d3 - "не удается создать свойство 'vx' на номере '65'"
Поэтому я пытаюсь использовать этот замечательный пример силового Графа для некоторых очень простых json: https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json
Моя работа здесь: codepen
Я получаю бесконечный поток ошибок от d3 без ошибки в начале, чтобы предположить, что что-то не так с моим кодом. Она начинается так:
XHR finished loading: GET "https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json".
[...]
d3.min.js:2 Uncaught Error: missing: 0
at ar (d3.min.js:2)
at r (d3.min.js:5)
at Function.e.links (d3.min.js:5)
at pen.js:46
at Object.<anonymous> (d3.min.js:7)
at d.call (d3.min.js:4)
at XMLHttpRequest.e (d3.min.js:7)
ar @ d3.min.js:2
r @ d3.min.js:5
e.links @ d3.min.js:5
(anonymous) @ pen.js:46
(anonymous) @ d3.min.js:7
call @ d3.min.js:4
e @ d3.min.js:7
d3.min.js:5 Uncaught TypeError: Cannot create property 'vx' on number '66'
at e (d3.min.js:5)
at d3.min.js:5
at Fe.each (d3.min.js:5)
at e (d3.min.js:5)
at n (d3.min.js:5)
at yn (d3.min.js:2)
at gn (d3.min.js:2)
e @ d3.min.js:5
(anonymous) @ d3.min.js:5
each @ d3.min.js:5
e @ d3.min.js:5
n @ d3.min.js:5
yn @ d3.min.js:2
gn @ d3.min.js:2
d3.min.js:5 Uncaught TypeError: Cannot create property 'vx' on number '66'
at e (d3.min.js:5)
at d3.min.js:5
at Fe.each (d3.min.js:5)
at e (d3.min.js:5)
at n (d3.min.js:5)
at yn (d3.min.js:2)
at gn (d3.min.js:2)
e @ d3.min.js:5
(anonymous) @ d3.min.js:5
each @ d3.min.js:5
e @ d3.min.js:5
n @ d3.min.js:5
yn @ d3.min.js:2
gn @ d3.min.js:2
На самом деле я не могу найти хороший вводный ресурс по графам силы в d3 v4+, поэтому я надо просто взломать его.
Html
<main>
<section class="d3">
</section>
</main>
Код
const api = 'https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json'
let root = d3.select(".d3"),
width = +root.attr("width"),
height = +root.attr("height")
let svg = root.append('svg')
.attr("width", width)
.attr("height", height)
let color = d3.scaleOrdinal(d3.schemeCategory20);
let simulation = d3.forceSimulation()
.force("link", d3.forceLink().id((d) => d.country))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json(api, function(error, graph) {
if (error)
throw error
let link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", () => 4);
let node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", d => color(1))
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
simulation
.nodes(graph.nodes)
.on("tick", ticked)
simulation.force("link")
.links(graph.links)
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
})
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
1 ответ:
Взгляните на свой массив
links
:Теперь взгляните на вашу функцию[ { "target": 66, "source": 0 }, { "target": 3, "source": 1 }, { "target": 100, "source": 2 }, ... ]
id
:.id((d) => d.country)
Как вы можете видеть, в вашем массиве
Поэтому, поскольку вы используете для ссылок числовой индекс , Просто отбросьте функциюlinks
нетcountry
.id()
. Согласно API:Если указан id, устанавливает метод доступа node id в указанную функцию и возвращает эту силу. Если id не указан, возвращает текущий идентификатор узла доступа, по умолчанию используется числовой узел.индекс
Вот ваш рабочий код:
const api = 'https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json' var width = 500, height = 500; let svg = d3.select("body").append('svg') .attr("width", width) .attr("height", height) let color = d3.scaleOrdinal(d3.schemeCategory20); let simulation = d3.forceSimulation() .force("link", d3.forceLink()) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); d3.json(api, function(error, graph) { if (error) throw error let link = svg.append("g") .attr("class", "links") .selectAll("line") .data(graph.links) .enter().append("line") .attr("stroke", "black") .attr("stroke-width", 4); let node = svg.append("g") .attr("class", "nodes") .selectAll("circle") .data(graph.nodes) .enter().append("circle") .attr("r", 5) .attr("fill", d => color(1)) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)) simulation .nodes(graph.nodes) .on("tick", ticked) simulation.force("link") .links(graph.links) function ticked() { link .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); } }) function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; }
<script src="https://d3js.org/d3.v4.min.js"></script>