gpt4 book ai didi

javascript - 在 Canvas 上放大 d3js 力模拟

转载 作者:行者123 更新时间:2023-11-29 21:15:00 24 4
gpt4 key购买 nike

我已经使用 svg 使用 d3.js 设置了力导向图,但最终该图变得很大并且出现了性能问题。我决定尝试在 Canvas 上做这件事,因为我读到它可以更好更快地渲染东西。但是现在我遇到了缩放问题。我已经正确地实现了缩放行为(我猜),但我只能在图形处于静止状态时进行缩放。在模拟找到平衡点之前缩放行为不起作用。知道为什么吗?或者关于我应该做什么的任何提示?

var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) { return i; }))
.force("charge", d3.forceManyBody().strength( -5 ))
.force("center", d3.forceCenter(width / 2, height / 2));

force.nodes(data.nodes)
.on("tick", ticked)

force.force("link")
.links(data.links);

function ticked(){
context.clearRect(0, 0, width, height);

// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI, true);
context.fill();
});
};

// now the zooming part
canvas.call( d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed) )

function zoomed(d) {
context.save();
context.clearRect(0, 0, width, height);
context.translate(d3.event.transform.x, d3.event.transform.y);
context.scale(d3.event.transform.k, d3.event.transform.k);

// Draw the links ...
data.links.forEach(function(d) {
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes ...
data.nodes.forEach(function(d, i) {
context.beginPath();
context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI, true);
context.fill();
});
context.restore();
}

最佳答案

您的tick 函数不知道缩放创建的任何转换。最好的方法是始终在刻度中应用变换(在任何缩放之前是 identity transform )。这允许您重用 tick 方法来完成所有绘图。

var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(width / 2, height / 2));

force.nodes(data.nodes)
.on("tick", ticked);

force.force("link")
.links(data.links)

var trans = d3.zoomIdentity; //<-- identity transform
function ticked() {
context.save();
context.clearRect(0, 0, width, height);
context.translate(trans.x, trans.y); //<-- this always applies a transform
context.scale(trans.k, trans.k);

// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, 5, 0, 2 * Math.PI, true);
context.fill();
});

context.restore();
};

// now the zooming part
canvas.call(d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed))

function zoomed(d) {
trans = d3.event.transform; //<-- set to current transform
ticked(); //<-- use tick to redraw regardless of event
}

完整运行代码:

<!DOCTYPE html>
<html>

<head>
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>

<canvas width="500" height="500"></canvas>

<script>

var width = 500,
height = 500
canvas = document.querySelector("canvas"),
context = canvas.getContext("2d");

canvas = d3.select(canvas);

var data = {
"nodes": [{
"id": "Myriel",
"group": 1
}, {
"id": "Napoleon",
"group": 1
}, {
"id": "Mlle.Baptistine",
"group": 1
}, {
"id": "Mme.Magloire",
"group": 1
}, {
"id": "CountessdeLo",
"group": 1
}, {
"id": "Geborand",
"group": 1
}, {
"id": "Champtercier",
"group": 1
}, {
"id": "Cravatte",
"group": 1
}, {
"id": "Count",
"group": 1
}, {
"id": "OldMan",
"group": 1
}, {
"id": "Labarre",
"group": 2
}, {
"id": "Valjean",
"group": 2
}, {
"id": "Marguerite",
"group": 3
}, {
"id": "Mme.deR",
"group": 2
}, {
"id": "Isabeau",
"group": 2
}, {
"id": "Gervais",
"group": 2
}, {
"id": "Tholomyes",
"group": 3
}, {
"id": "Listolier",
"group": 3
}, {
"id": "Fameuil",
"group": 3
}, {
"id": "Blacheville",
"group": 3
}, {
"id": "Favourite",
"group": 3
}, {
"id": "Dahlia",
"group": 3
}, {
"id": "Zephine",
"group": 3
}, {
"id": "Fantine",
"group": 3
}, {
"id": "Mme.Thenardier",
"group": 4
}, {
"id": "Thenardier",
"group": 4
}, {
"id": "Cosette",
"group": 5
}, {
"id": "Javert",
"group": 4
}, {
"id": "Fauchelevent",
"group": 0
}],
"links": [{
"source": "Napoleon",
"target": "Myriel",
"value": 1
}, {
"source": "Mlle.Baptistine",
"target": "Myriel",
"value": 8
}, {
"source": "Mme.Magloire",
"target": "Myriel",
"value": 10
}, {
"source": "Mme.Magloire",
"target": "Mlle.Baptistine",
"value": 6
}, {
"source": "CountessdeLo",
"target": "Myriel",
"value": 1
}, {
"source": "Geborand",
"target": "Myriel",
"value": 1
}, {
"source": "Champtercier",
"target": "Myriel",
"value": 1
}, {
"source": "Cravatte",
"target": "Myriel",
"value": 1
}, {
"source": "Count",
"target": "Myriel",
"value": 2
}, {
"source": "OldMan",
"target": "Myriel",
"value": 1
}, {
"source": "Valjean",
"target": "Labarre",
"value": 1
}, {
"source": "Valjean",
"target": "Mme.Magloire",
"value": 3
}, {
"source": "Valjean",
"target": "Mlle.Baptistine",
"value": 3
}, {
"source": "Valjean",
"target": "Myriel",
"value": 5
}, {
"source": "Marguerite",
"target": "Valjean",
"value": 1
}, {
"source": "Mme.deR",
"target": "Valjean",
"value": 1
}, {
"source": "Isabeau",
"target": "Valjean",
"value": 1
}, {
"source": "Gervais",
"target": "Valjean",
"value": 1
}, {
"source": "Listolier",
"target": "Tholomyes",
"value": 4
}, {
"source": "Fameuil",
"target": "Tholomyes",
"value": 4
}, {
"source": "Fameuil",
"target": "Listolier",
"value": 4
}, {
"source": "Blacheville",
"target": "Tholomyes",
"value": 4
}, {
"source": "Blacheville",
"target": "Listolier",
"value": 4
}, {
"source": "Blacheville",
"target": "Fameuil",
"value": 4
}, {
"source": "Favourite",
"target": "Tholomyes",
"value": 3
}, {
"source": "Favourite",
"target": "Listolier",
"value": 3
}, {
"source": "Favourite",
"target": "Fameuil",
"value": 3
}, {
"source": "Favourite",
"target": "Blacheville",
"value": 4
}, {
"source": "Dahlia",
"target": "Tholomyes",
"value": 3
}, {
"source": "Dahlia",
"target": "Listolier",
"value": 3
}, {
"source": "Dahlia",
"target": "Fameuil",
"value": 3
}, {
"source": "Dahlia",
"target": "Blacheville",
"value": 3
}, {
"source": "Dahlia",
"target": "Favourite",
"value": 5
}, {
"source": "Zephine",
"target": "Tholomyes",
"value": 3
}, {
"source": "Zephine",
"target": "Listolier",
"value": 3
}, {
"source": "Zephine",
"target": "Fameuil",
"value": 3
}, {
"source": "Zephine",
"target": "Blacheville",
"value": 3
}, {
"source": "Zephine",
"target": "Favourite",
"value": 4
}, {
"source": "Zephine",
"target": "Dahlia",
"value": 4
}, {
"source": "Fantine",
"target": "Tholomyes",
"value": 3
}, {
"source": "Fantine",
"target": "Listolier",
"value": 3
}, {
"source": "Fantine",
"target": "Fameuil",
"value": 3
}, {
"source": "Fantine",
"target": "Blacheville",
"value": 3
}, {
"source": "Fantine",
"target": "Favourite",
"value": 4
}, {
"source": "Fantine",
"target": "Dahlia",
"value": 4
}, {
"source": "Fantine",
"target": "Zephine",
"value": 4
}, {
"source": "Fantine",
"target": "Marguerite",
"value": 2
}]
}

var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(width / 2, height / 2));

force.nodes(data.nodes)
.on("tick", ticked);

force.force("link")
.links(data.links)

var trans = d3.zoomIdentity;
function ticked() {
context.save();
context.clearRect(0, 0, width, height);
context.translate(trans.x, trans.y);
context.scale(trans.k, trans.k);

// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, 5, 0, 2 * Math.PI, true);
context.fill();
});

context.restore();
};

// now the zooming part
canvas.call(d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed))

function zoomed(d) {
trans = d3.event.transform;
ticked();
}
</script>
</body>

</html>

关于javascript - 在 Canvas 上放大 d3js 力模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39807094/

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