d3.js на холсте, не может определить правильные координаты узла при использовании функции масштабирования и перетаскивания
Я пытаюсь визуализировать данные JSON, используя d3 v4 и холст. Я сталкиваюсь с некоторыми трудностями при реализации масштабирования, панорамирования и перетаскивания. Хотя код дает практически все желаемые результаты, после масштабирования при щелчке узла он отображается в другом месте. Я предполагаю, что это потому, что мне не удается определить правильные координаты для узла после преобразования.
Вот выдержки из кода:
var canvas=document.querySelector("canvas"),
context=canvas.getContext("2d"),
width=canvas.width,
height=canvas.height;
context.clearRect(0,0,width,height);
context.fillStyle=" #566573";
context.fillRect(0,0,width,height);
var color = d3.scaleOrdinal(d3.schemeCategory20);
d3.json('data.do', function(error,graph) {
var radius=3;
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.alpha(0.5)
.alphaDecay(0.03)
.velocityDecay(.4)
.force("y", d3.forceY(height/2).strength(.020))
.force("collision", d3.forceCollide().radius(function(d) { return radius+2; }))
var transform=d3.zoomIdentity;
d3.select(canvas)
.call(d3.drag().subject(dragsubject).on("start",dragstarted).on("drag", dragged))
.call(d3.zoom().scaleExtent([1 / 10, 8]).on("zoom", zoomed)).on("dblclick.zoom",null)
.on('click',function(){console.log("clicked");})
function zoomed() {
transform = d3.event.transform;
simulationUpdate();
}
function dragsubject() {
var i,
x = transform.invertX(d3.event.x),
y = transform.invertY(d3.event.y),
dx,
dy;
for (i = graph.points.length - 1; i >= 0; --i) {
node = graph.points[i];
dx = x - node.x;
dy = y - node.y;
if (dx * dx + dy * dy < radius * radius) {
node.x = transform.applyX(node.x);
node.y = transform.applyY(node.y);
return node;
}
}
}
function dragstarted() {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d3.event.subject.fx = transform.invertX(d3.event.x);
d3.event.subject.fy = transform.invertY(d3.event.y);
}
function dragged() {
d3.event.subject.fx = transform.invertX(d3.event.x);
d3.event.subject.fy = transform.invertY(d3.event.y);
}
simulation
.nodes(graph.points)
.on("tick", simulationUpdate);
simulation.force("link")
.links(graph.plinks);
function simulationUpdate(){
console.log("simulationupdate");
context.save();
context.clearRect(0, 0, width, height);
context.fillStyle=" #2a2c2d ";
context.fillRect(0,0,width,height);
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
graph.plinks.forEach(function(d) {
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.strokeStyle = "#335d6c";
context.stroke();
});
graph.points.forEach(function(d, i) {
context.beginPath();
context.moveTo(d.x+radius,d.y);
context.arc(d.x,d.y, radius, 0, 2 * Math.PI, true);
context.fillStyle=color(d.group);
context.fill();
context.strokeStyle = "#fff";
context.stroke();
});
context.restore();
}
});
JSON-объект 'graph' выглядит следующим образом:
{
"plinks":[
{"source":"source1","target":"target1","value":"1"},
{"source":"source2","target":"target2","value":"0"},
.
.
],
"points":[
{"group":0,"id":"source1"},
{"group":3,"id":"source2"},
.
.
]
}
Функции увеличения и уменьшения и перетаскивания работают нормально. Ведение журнала консоли сообщает мне, что при нажатии на узел вызываются методы dragsubject, dragstarted, clicked и Simulationupdate. Я не мог выяснить, что именно вызывает узел, чтобы иметь разные координаты после щелчка мышью.
Ссылка: https://bl.ocks.org/jodyphelan/5dc989637045a0f48418101423378fbd и многие другие Bl.ocks.
Оцените любую помощь заранее. Спасибо.