繁体   English   中英

D3js将圆附加到力导向的布局

[英]D3js append circle to force-directed layout

我显然对javascript以及D3js都是新的...

在弄清楚如何将“点”转换为附加到节点/路径的“圆”时我一头雾水?

我猜想它与tick()函数有关,但是我找不到启发性的文档:(

var node = svg.selectAll("path.node")
.data(dataset.nodes)
.enter().append("path").attr("class", "node")
.style("cursor","pointer")
.style("fill", function(d) {
        if (d.color) {return d.color;}
        else  { return "#fff" }
    ;})
.call(force.drag);

// add the nodes
node.append("circle")
    .attr("r", 35);

function tick() {
  node.attr("d", function(d) { var p = path({"type":"Feature","geometry":{"type":"Point","coordinates":[d.x, d.y]}}); return p ? p : 'M 0 0' });
  link.attr("d", function(d) { var p = path({"type":"Feature","geometry":{"type":"LineString","coordinates":[[d.source.x, d.source.y],[d.target.x, d.target.y]]}}); return p ? p : 'M 0 0' });
}

我在这里做了一个codepen https://codepen.io/unit60/pen/KqLEPe

朝着正确方向的方向将不胜感激...帮助:)

我想我明白您的要求。 在当前代码段中,您将在path元素下嵌套一个circletext 这是无效的,因为path无效子代无效。 而是将它们放在g (组)中:

var node = svg.selectAll(".node")
    .data(dataset.nodes)
    .enter()
    .append("g")
    .attr("class", "node")
    .style("cursor","pointer")
    .call(force.drag);

// add the nodes
node.append("circle")
    .attr("r", 35)
    .style("fill", function(d) {
      if (d.color) {return d.color;}
      else  { return "#fff"; }
   });


// add the text 
node.append("text")
    .attr("x", 12)
    .attr("dy", ".35em")
    .text(function(d) { return d.name; });

然后,我们需要更新tick功能以正确放置组(而不是像绘制路径那样):

function tick() {
  node.attr("transform", function(d) {   
    // change this to centroid 
    var p = path.centroid({"type":"Feature","geometry":{"type":"Point","coordinates":[d.x, d.y]}});    
    return "translate(" + p + ")";
  });  

  link.attr("d", function(d) { 
    var p = path({"type":"Feature","geometry":{"type":"LineString","coordinates":[[d.source.x, d.source.y],[d.target.x, d.target.y]]}}); return p ? p : 'M 0 0' });
  }
}

更新的Codepen ; 运行示例:

 var dataset = { nodes: [{ name: "Location 01", class: "overlay01-link", color: "red" }, { name: "Location 02", class: "overlay02-link", color: "orange" }, { name: "Location 03" }, { name: "Location 04" }, { name: "Location 05" }, { name: "Location 06" }, { name: "Location 07" }, { name: "Location 08" }, { name: "Location 09" }, { name: "Location 10" }], edges: [{ source: 0, target: 1 }, { source: 0, target: 2 }, { source: 0, target: 3 }, { source: 0, target: 4 }, { source: 1, target: 5 }, { source: 2, target: 5 }, { source: 2, target: 5 }, { source: 3, target: 4 }, { source: 5, target: 8 }, { source: 5, target: 9 }, { source: 6, target: 7 }, { source: 7, target: 8 }, { source: 8, target: 9 }] }; var projections = { "Albers": d3.geo.albers(), "Azimuthal Equal Area": d3.geo.azimuthalEqualArea(), "Azimuthal Eqidistant": d3.geo.azimuthalEquidistant(), "Conic Conformal": d3.geo.conicConformal(), "Conic Equal Area": d3.geo.conicEqualArea(), "Conic Equidistant": d3.geo.conicEquidistant(), "Eqirectangular": d3.geo.equirectangular(), "Gnomonic": d3.geo.gnomonic(), "Mercator": d3.geo.mercator(), "Orthographic": d3.geo.orthographic(), "Stereographic": d3.geo.stereographic(), "Transverse Mercator": d3.geo.transverseMercator(), }; var config = { "projection": "Orthographic", "clip": false, "friction": .45, "linkStrength": 1, "linkDistance": 320, "charge": 3, "gravity": .1, "theta": .1 }; var gui = new dat.GUI(); //var projectionChanger = gui.add(config, "projection", ['equalarea', 'equidistant', 'gnomonic', 'orthographic', 'stereographic', 'rectangular']); var projectionChanger = gui.add(config, "projection", Object.keys(projections)); //http://stackoverflow.com/a/3417242 function wrapIndex(i, i_max) { return ((i % i_max) + i_max) % i_max; } projectionChanger.onChange(function(value) { projection = projections[value] .scale(height/2) .translate([(width/2)-125, height/2]) .clipAngle(config["clip"] ? 90 : null) path.projection(projections[value]) return if(value == 'rectangular') { path = d3.geo.path().projection(function(coordinates){ console.log(coordinates[0], coordinates[1]) return [ wrapIndex(coordinates[0], width), wrapIndex(coordinates[1], height), ]; }); config['clip'] = false } else { projection.mode(value) path = d3.geo.path().projection(projection) } force.start() }); var clipChanger = gui.add(config, "clip").listen(); clipChanger.onChange(function(value) { projection.clipAngle(value ? 90 : null) force.start() }); var fl = gui.addFolder('Force Layout'); fl.open() var frictionChanger = fl.add(config, "friction", 0, 1); frictionChanger.onChange(function(value) { force.friction(value) force.start() }); var linkDistanceChanger = fl.add(config, "linkDistance", 0, 400); linkDistanceChanger.onChange(function(value) { force.linkDistance(value) force.start() }); var linkStrengthChanger = fl.add(config, "linkStrength", 0, 1); linkStrengthChanger.onChange(function(value) { force.linkStrength(value) force.start() }); var chargeChanger = fl.add(config,"charge", 0, 500); chargeChanger.onChange(function(value) { force.charge(-value) force.start() }); var gravityChanger = fl.add(config,"gravity", 0, 1); gravityChanger.onChange(function(value) { force.gravity(value) force.start() }); var thetaChanger = fl.add(config,"theta", 0, 1); thetaChanger.onChange(function(value) { force.theta(value) force.start() }); var width = window.innerWidth, height = window.innerHeight - 5, fill = d3.scale.category20(), nodes = [{x: width/2, y: height/2}], links = []; var projection = projections[config["projection"]] .scale(height/2) .translate([(width/2)-125, height/2]) .clipAngle(config["clip"] ? 90 : null) var path = d3.geo.path() .projection(projection) var force = d3.layout.force() .linkDistance(config["linkDistance"]) .linkStrength(config["linkStrength"]) .gravity(config["gravity"]) .size([width, height]) .charge(-config["charge"]); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .call(d3.behavior.drag() .origin(function() { var r = projection.rotate(); return {x: 2 * r[0], y: -2 * r[1]}; }) .on("drag", function() { force.start(); var r = [d3.event.x / 2, -d3.event.y / 2, projection.rotate()[2]]; t0 = Date.now(); origin = r; projection.rotate(r); })) for(x=0;x<100;x++){ source = nodes[~~(Math.random() * nodes.length)] target = {x: source.x + Math.random(), y: source.y + Math.random(), group: Math.random()} links.push({source: source, target: target}) nodes.push(target) } var link = svg.selectAll(".link") .data(dataset.edges) .enter().append("path").attr("class", "link") var node = svg.selectAll(".node") .data(dataset.nodes) .enter() .append("g") .attr("class", "node") .style("cursor","pointer") .call(force.drag); // add the nodes node.append("circle") .attr("r", 35) .style("fill", function(d) { if (d.color) {return d.color;} else { return "#fff"; } }); // add the text node.append("text") .attr("x", 12) .attr("dy", ".35em") .text(function(d) { return d.name; }); force .nodes(dataset.nodes) .links(dataset.edges) .on("tick", tick) .start(); function tick() { node.attr("transform", function(d) { var p = path.centroid({"type":"Feature","geometry":{"type":"Point","coordinates":[dx, dy]}}); return "translate(" + p + ")"; }); link.attr("d", function(d) { var p = path({"type":"Feature","geometry":{"type":"LineString","coordinates":[[d.source.x, d.source.y],[d.target.x, d.target.y]]}}); return p ? p : 'M 0 0' }); } // action to take on mouse click function click() { d3.select(this).select("text").transition() .duration(750) .attr("x", 22) .style("fill", "steelblue") .style("stroke", "lightsteelblue") .style("stroke-width", ".5px") .style("font", "20px sans-serif"); d3.select(this).select("circle").transition() .duration(750) .attr("r", 16) .style("fill", "lightsteelblue"); } // action to take on mouse double click function dblclick() { d3.select(this).select("circle").transition() .duration(750) .attr("r", 6) .style("fill", "#ccc"); d3.select(this).select("text").transition() .duration(750) .attr("x", 12) .style("stroke", "none") .style("fill", "black") .style("stroke", "none") .style("font", "10px sans-serif"); } 
 body { padding: 0; margin: 0; background:#222; } .node { stroke-width: 2.5px; width:100px; fill:#fff; } text { fill: #fff; font: 10px sans-serif; pointer-events: none; } circle { fill: #ccc; stroke: #fff; stroke-width: 1.5px; } path.link { stroke: #fff; fill-opacity: 0 } svg { height:100%; width:100%; display:block; } 
 <script src="//d3js.org/d3.v3.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM