为了账号安全,请及时绑定邮箱和手机立即绑定

分层边缘集群组名

分层边缘集群组名

互换的青春 2023-05-19 16:14:21
我有以下聚类图,它大部分工作正常。我猜这与我如何将东西打包在一起有关?function packageImports(nodes) {  var map = {},    imports = [];  // Compute a map from name to node.  nodes.forEach(function(d) {    map[d.data.name] = d;  });  // For each import, construct a link from the source to target node.  nodes.forEach(function(d) {    if (d.data.imports) d.data.imports.forEach(function(i) {      imports.push(map[d.data.name].path(map[i]));    });  });  return imports;}.node {  font: 300 11px "Helvetica Neue", Helvetica, Arial, sans-serif;  fill: #444;}.node:hover {  fill: #000;}.link {  stroke: steelblue;  stroke-opacity: 0.5;  fill: none;  pointer-events: none;  stroke-width: 1px;  stroke-linecap: round;}.node:hover,.node--source,.node--target {  font-weight: 700;}/* text color */.node--source {  fill: red;}/* text color */.node--target {  fill: red;}.link--source,.link--target {  stroke-opacity: 1;  stroke-width: 2px;}/* line color */.link--source {  stroke: red;}/* line color */.link--target {  stroke: red;}<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>我所追求的是两件事我需要每个组都显示一个标题。EG 数据库说它们是数据库3 条颜色线(我目前有 2 条颜色相同),1 条用于依赖,1 条用于依赖,1 条用于两者D3 的新手不确定如何实现这些?
查看完整描述

1 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

我认为您遇到的问题是度数和弧度之间的转换。这就是为什么你必须在例程中使用聪明的解决方案rotate - translate - rotate

我已将集群更改为以弧度输出,然后groups作为文本添加为节点的父节点。我还更改了链接类,使传入和传出链接的颜色不同。如果一个链接有两个类,那么它是绿色的。

你把类link--sourcelink--target类颠倒了,我把它颠倒了。

var diameter = 900,

  radius = diameter / 2,

  innerRadius = radius - 180;


var cluster = d3.cluster()

  .size([2 * Math.PI, innerRadius]);


var line = d3.radialLine()

  .curve(d3.curveBundle.beta(0.2))

  .radius(function(d) {

    return d.y;

  })

  .angle(function(d) {

    return d.x;

  });


var svg = d3.select("body").append("svg")

  .attr("width", diameter)

  .attr("height", diameter)

  .append("g")

  .attr("transform", "translate(" + radius + "," + radius + ")");


var link = svg.append("g").selectAll(".link"),

  node = svg.append("g").selectAll(".node"),

  group = svg.append("g").selectAll(".group");


let samlDeps = [

  'dsi.backend.SAML-ASSERTIONS',

  'dsi.frontend.OIDC'

];


var arc = d3.arc()

  .innerRadius(10)

  .outerRadius(15);


var classes = [{

    'name': 'dsi.frontend.HELP',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.PROFILE',

      'dsi.frontend.INTERACTIONS',

      'dsi.frontend.SERVICES',

      'dsi.frontend.SUPPORT',

      'dsi.backend.APPLICATIONS',

      'dsi.cache.REDIS',

      'dsi.frontend.CDN',

    ]

  },

  {

    'name': 'dsi.frontend.INTERACTIONS',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.PROFILE',

      'dsi.frontend.HELP',

      'dsi.frontend.SERVICES',

      'dsi.frontend.SUPPORT',

      'dsi.db.DIRECTORIES',

      'dsi.frontend.OIDC',

      'dsi.backend.DEVICES',

      'dsi.backend.ORGANISATIONS',

      'dsi.backend.APPLICATIONS',

      'dsi.backend.ACCESS',

      'dsi.cache.REDIS',

      'dsi.frontend.CDN',

    ]

  },

  {

    'name': 'dsi.frontend.MANAGE',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.INTERACTIONS',

      'dsi.frontend.HELP',

      'dsi.frontend.SERVICES',

      'dsi.frontend.PROFILE',

      'dsi.backend.ACCESS',

      'dsi.backend.APPLICATIONS',

      'dsi.backend.DIRECTORIES',

      'dsi.db.ORGANISATION',

      'dsi.cache.SEARCH',

      'dsi.cache.REDIS',

      'dsi.frontend.CDN',

      'dsi.frontend.OIDC',

    ]

  },

  {

    'name': 'dsi.frontend.OIDC',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.backend.DIRECTORIES',

      'dsi.cache.REDIS',

      'dsi.frontend.HELP',

      'dsi.db.DIRECTORIES',

      'dsi.db.ORGANISATION',

      'dsi.backend.APPLICATIONS',

      'dsi.frontend.CDN',

      'dsi.frontend.INTERACTIONS',

    ]

  },

  {

    'name': 'dsi.frontend.PUBLIC-API',

    'size': 1000,

    'imports': [

      'dsi.cache.REDIS',

      'dsi.backend.DIRECTORIES',

      'dsi.backend.APPLICATIONS',

      'dsi.backend.ACCESS',

      'dsi.backend.ORGANISATIONS',

    ]

  },

  {

    'name': 'dsi.frontend.PROFILE',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.INTERACTIONS',

      'dsi.frontend.HELP',

      'dsi.frontend.SERVICES',

      'dsi.frontend.SUPPORT',

      'dsi.backend.DIRECTORIES',

      'dsi.backend.ORGANISATIONS',

      'dsi.backend.APPLICATIONS',

      'dsi.backend.ACCESS',

      'dsi.cache.SEARCH',

      'dsi.frontend.CDN',

      'dsi.frontend.OIDC',

    ]

  },

  {

    'name': 'dsi.frontend.SUPPORT',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.PROFILE',

      'dsi.frontend.INTERACTIONS',

      'dsi.frontend.HELP',

      'dsi.frontend.SERVICES',

      'dsi.frontend.OIDC',

      'dsi.cache.SEARCH',

      'dsi.cache.REDIS',

      'dsi.backend.DIRECTORIES',

      'dsi.backend.ORGANISATIONS',

      'dsi.backend.DEVICES',

      'dsi.backend.APPLICATIONS',

      'dsi.backend.ACCESS',

      'dsi.frontend.CDN',

    ]

  },

  {

    'name': 'dsi.frontend.SERVICES',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.PROFILE',

      'dsi.frontend.INTERACTIONS',

      'dsi.frontend.HELP',

      'dsi.frontend.SUPPORT',

      'dsi.backend.DIRECTORIES',

      'dsi.backend.ORGANISATIONS',

      'dsi.backend.ACCESS',

      'dsi.backend.APPLICATIONS',

      'dsi.cache.SEARCH',

      'dsi.db.ORGANISATION',

      'dsi.frontend.OIDC',

      'dsi.cache.REDIS',

      'dsi.db.DIRECTORIES',

      'dsi.db.ORGANISATION',

      'dsi.frontend.CDN',

    ]

  },

  {

    'name': 'dsi.frontend.CDN',

    'size': 1000,

    'imports': []

  },


  {

    'name': 'dsi.backend.ACCESS',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.db.ORGANISATION',

      'dsi.cache.REDIS',

    ]

  },

  {

    'name': 'dsi.backend.APPLICATIONS',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.db.ORGANISATION',

      'dsi.db.ORGANISATION',

    ]

  },

  {

    'name': 'dsi.backend.SAML-ASSERTIONS',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.backend.DIRECTORIES',

      'dsi.backend.ACCESS',

      'dsi.backend.APPLICATIONS',

    ]

  },

  {

    'name': 'dsi.backend.DEVICES',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.frontend.CDN',

      'dsi.db.DEVICES',

    ]

  },

  {

    'name': 'dsi.backend.DIRECTORIES',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.db.DIRECTORIES',

      'dsi.backend.APPLICATIONS',

      'dsi.cache.REDIS',

    ]

  },

  {

    'name': 'dsi.backend.ORGANISATIONS',

    'size': 1000,

    'imports': [

      'dsi.db.AUDIT',

      'dsi.db.ORGANISATION',

      'dsi.backend.DIRECTORIES',

      'dsi.cache.REDIS',

    ]

  },

  {

    'name': 'dsi.backend.sa',

    'size': 1000,

    'imports': [

      'dsi.backend.APPLICATIONS',

    ]

  },


  {

    'name': 'dsi.saml.A-FORMS',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.ASP',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.COLLECT',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.DQT',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.GIAS',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.INFORMATION-EXCHANGE',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.KEY-TO-SUCCESS',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.KEY-TO-SUCCESS_SECURE-ACCESS',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.psp',

    'size': 1000,

    'imports': samlDeps

  },

  {

    'name': 'dsi.saml.SCHOOL-2-SCHOOL',

    'size': 1000,

    'imports': samlDeps

  },


  {

    'name': 'dsi.db.AUDIT',

    'size': 1000,

    'imports': []

  },

  {

    'name': 'dsi.db.DIRECTORIES',

    'size': 1000,

    'imports': []

  },

  {

    'name': 'dsi.db.ORGANISATION',

    'size': 1000,

    'imports': []

  },

  {

    'name': 'dsi.db.DEVICES',

    'size': 1000,

    'imports': []

  },


  {

    'name': 'dsi.cache.REDIS',

    'size': 1000,

    'imports': []

  },

  {

    'name': 'dsi.cache.SEARCH',

    'size': 1000,

    'imports': []

  },

];


var root = packageHierarchy(classes)

  .sum(function(d) {

    return d.size;

  });


cluster(root);


group = group

  .data(root.descendants().filter(function(d) {

    return d.height === 1;

  }))

  .enter()

  .append('text')

  .each(function(d) {

    d.angle = (d3.sum(d.children, function(v) {

      return v.x;

    }) / d.children.length);

    d.radius = d3.max(d.children, function(v) {

      return v.y;

    }) + 140;

  })

  .classed("group", true)

  .attr('x', function(d) {

    return Math.sin(d.angle) * d.radius;

  })

  .attr('y', function(d) {

    return -Math.cos(d.angle) * d.radius;

  })

  .attr("text-anchor", function(d) {

    return d.angle < Math.PI ? "start" : "end";

  })

  .text(function(d) {

    return d.data.key.toUpperCase();

  });


link = link

  .data(packageImports(root.leaves()))

  .enter().append("path")

  .each(function(d) {

    d.source = d[0], d.target = d[d.length - 1];

  })

  .attr("class", "link")

  .attr("d", line);


node = node

  .data(root.leaves())

  .enter().append("text")

  .attr("class", "node")

  .attr("dy", "0.31em")

  .attr('x', function(d) {

    return Math.sin(d.x) * d.y;

  })

  .attr('y', function(d) {

    return -Math.cos(d.x) * d.y;

  })

  .attr("transform", function(d) {

    const angle = (d.x * 180 / Math.PI) - 90 + (d.x < Math.PI ? 0 : 180);

    const x = Math.sin(d.x) * d.y;

    const y = -Math.cos(d.x) * d.y

    return "rotate(" + angle + "," + x + "," + y + ")";

  })

  .attr("text-anchor", function(d) {

    return d.x < Math.PI ? "start" : "end";

  })

  .text(function(d) {

    return d.data.key;

  })

  .on("mouseover", mouseovered)

  .on("mouseout", mouseouted);


function mouseovered(d) {

  node

    .each(function(n) {

      n.target = n.source = false;

    });


  link

    .classed("link--source", function(l) {

      if (l.target === d) return l.source.source = true;

    })

    .classed("link--target", function(l) {

      if (l.source === d) return l.target.target = true;

    })

    .filter(function(l) {

      return l.target === d || l.source === d;

    })

    .raise();


  node

    .classed("node--target", function(n) {

      return n.target;

    })

    .classed("node--source", function(n) {

      return n.source;

    });

}


function mouseouted(d) {

  link

    .classed("link--target", false)

    .classed("link--source", false);


  node

    .classed("node--target", false)

    .classed("node--source", false);

}


// Lazily construct the package hierarchy from class names.

function packageHierarchy(classes) {

  var map = {};


  function find(name, data) {

    var node = map[name],

      i;

    if (!node) {

      node = map[name] = data || {

        name: name,

        children: []

      };

      if (name.length) {

        node.parent = find(name.substring(0, i = name.lastIndexOf(".")));

        node.parent.children.push(node);

        node.key = name.substring(i + 1);

      }

    }

    return node;

  }


  classes.forEach(function(d) {

    find(d.name, d);

  });


  return d3.hierarchy(map[""]);

}


// Return a list of imports for the given array of nodes.

function packageImports(nodes) {

  var map = {},

    imports = [];


  // Compute a map from name to node.

  nodes.forEach(function(d) {

    map[d.data.name] = d;

  });


  // For each import, construct a link from the source to target node.

  nodes.forEach(function(d) {

    if (d.data.imports) d.data.imports.forEach(function(i) {

      imports.push(map[d.data.name].path(map[i]));

    });

  });


  return imports;

}

.node,

.group {

  font: 300 11px "Helvetica Neue", Helvetica, Arial, sans-serif;

  fill: #444;

}


.group {

  font-size: 16px;

}


.node:hover {

  fill: #000;

}


.link {

  stroke: steelblue;

  stroke-opacity: 0.5;

  fill: none;

  pointer-events: none;

  stroke-width: 1px;

  stroke-linecap: round;

}


.node:hover,

.node--source,

.node--target {

  font-weight: 700;

}



/* text color */


.node--source {

  fill: red;

}


.node--target {

  fill: blue;

}


.node--target.node-source {

  fill: green;

}


.link--source,

.link--target {

  stroke-opacity: 1;

  stroke-width: 2px;

}



/* line color */


.link--source {

  stroke: red;

}


.link--target {

  stroke: blue;

}


.link--source.link--target {

  stroke: green;

}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>


查看完整回答
反对 回复 2023-05-19
  • 1 回答
  • 0 关注
  • 79 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信