gpt4 book ai didi

javascript - D3js 将圆附加到强制导向布局

转载 作者:行者123 更新时间:2023-12-03 03:49:21 25 4
gpt4 key购买 nike

我显然对 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 。这不会起作用,因为路径的子项无效。相反,请将它们放在 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":[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' });
}

// 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>

关于javascript - D3js 将圆附加到强制导向布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45235309/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com