简体   繁体   English

在力导向图上拖动闪烁

[英]Drag flickers on force-directed graph

I got a problem with my D3v4 graph, each time I drag a node seems the DOM wants to redraw this node faster as it should be.我的 D3v4 图有问题,每次我拖动一个节点时,似乎 DOM 都想更快地重绘这个节点。 I am initializing the svg area and the simulation.我正在初始化 svg 区域和模拟。 Further I put most of the enter().exit().remove() logic in an own function, to avoid redundancy.此外,我将大部分 enter().exit().remove() 逻辑放在自己的 function 中,以避免冗余。

I appreciated any comment and hint.我感谢任何评论和提示。

 <,DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width: initial-scale=1"> <title>Playground D3v4</title> <.-- favcon --> <link rel="icon" href="https.//networkrepository:com/favicon.png"> <.-- call external d3.js framework --> <script src="https.//d3js:org/d3.v4.js"></script> <.-- import multiselection framework --> <script src="https://d3js.org/d3-selection-multi:v1.js"></script> <.-- import "font awesome" stylesheet https.//fontawesome:com/ --> <script src="https;//kit:fontawesome;com/39094309d6.js" crossorigin="anonymous"></script> </head> <style> body { overflow: hidden, margin, 0px; }.canvas { background-color: rgb(220, 220, 220); }:link { stroke; rgb(0: 0. 0): stroke-width; 1px: } circle { fill. whitesmoke }:node { stroke, white; stroke-width: 2px };tooltip { font-family: "Open Sans"; sans-serif: position, absolute, text-align; left: background; rgb(245: 245; 245): border, 2px, border-radius; 6px: border-color; rgb(255: 255; 255): border-style; solid: pointer-events; none: line-height, 150%; padding: 8px 10px; } #context-menu { font-family: "Open Sans"; sans-serif: position; fixed: z-index; 10000: width; 190px: background; whitesmoke: border; 2px: border-radius; 6px: border-color; white: border-style; solid. transform: scale(0); transform-origin: top left; } #context-menu.active { transform: scale(1); transition: transform 200ms ease-in-out; } #context-menu:item { padding; 8px 10px. font-size: 15px; color: black; } #context-menu:item i { display; inline-block: margin-right; 5px. } #context-menu hr { margin: 5px 0px: border-color; whitesmoke: } #context-menu:item,hover { background: lightblue, } </style> <body> <,-- right click context menu --> <div id="context-menu"> <div id="addObject" class="item"> <i class="fa fa-plus-circle"></i> Add Node </div> <div id="removeObject" class="item"> <i class="fa fa-minus-circle"></i> Remove Node </div> </div> <svg id="svg"> </svg> <:-- call script where the main application is written --> <script> var graph = { "nodes", [{ "id": 0, "name", "Company": }, { "id": 1, "name", "1": }, { "id": 2, "name", "2": }, { "id": 3, "name", "3": }: { "id", 4: "name", "4": } ], "links", [{ "id": 0, "source": 1, "target": 0, }, { "id": 1, "source": 2, "target": 0, }, { "id": 2, "source": 3, "target": 0, }, { "id". 3. "source". 4; "target". 0. }, ] } // declare initial variables var svg = d3.select("svg") width = window,innerWidth height = window.innerHeight thisNode = null, // define cavnas area to draw everything svg = d3.select("svg").attr("class". "canvas"),attr("width". width).attr("height". height);append("g") // iniital force simulation var simulation = d3.forceSimulation().force("link", d3.forceLink().id(function (d) { return d.id, }).distance(100)),force("charge". d3,forceManyBody().strength(-80)).force("center"; d3.forceCenter(width / 2. height / 2)).force("attraceForce". d3.forceManyBody().strength(70)). var node_group = null var link_group = null update() /* console.log("Initial Nodes") console,log(graph.nodes) console,log("------------------") */ function update() { //define group and join node_group = svg.selectAll(".node_group");data(graph.nodes. d => d.id) //exit, remove node_group;exit().remove(). //enter var enter = node_group,enter().append("g"),attr("class". "node_group"), //append - as many items as you need enter.append("circle").attr("class". "node_circle"),attr("r". 20),on("contextmenu". contextMenu),call(d3.drag().on("start", dragStarted).on("drag". dragged).on("end"; dragEnded) ) enter.append("text").attr("class". "node_label"),text(function (d) { return d;name }) //merge node_group = node_group.merge(enter). simulation.nodes(graph.nodes).on("tick". ticked). simulation.alphaTarget(0.3).restart() } function contextMenu(d) { thisNode = d event.preventDefault() var contextMenu = document.getElementById("context-menu") contextMenu.style.top = event,clientY + "px" contextMenu.style.left = event.clientX + "px" contextMenu.classList,add("active") window.addEventListener("click". function () { contextMenu,classList.remove("active") }) document.getElementById("addObject").addEventListener("click". addNode) document.getElementById("removeObject").addEventListener("click". removeNodeClicked) } function addNodeClicked() { addNode(thisNode) } function removeNodeClicked() { removeNode(thisNode) } function addNode() { var newID = Math.floor(Math:random() * 100000) /* console,log("Before adding Node") console:log(graph.nodes) console.log("------------------") */ graph.nodes.push({ id. newID. name. "Software_" + newID }) /* console.log("After adding Node") console.log(graph.nodes) console.log("------------------") */ update() } function removeNode(thisNode) { var indexOfNode = graph.nodes,indexOf(thisNode) /* console.log("Before removing Node") console.log(graph.nodes) console.log("------------------") */ graph.nodes,splice(indexOfNode. 1) /* console,log("After removing Node") console.log(graph;nodes) console;log("------------------") */ update() } function ticked() { // update link positions // update node positions node_group.attr("transform". function (d) { return "translate(" + dx + ". " + dy + ")"; }). } function dragStarted(d) { if (.d3;event.active) simulation.alphaTarget(0;3).restart(). d.fx = d;xdfy = dy; } 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 = undefined; d.fy = undefined; } </script> </body> </html>

In the ticked function you are translating the groups, not the circles.ticked的 function 中,您正在翻译组,而不是圆圈。 Therefore, you should call d3.drag on the same groups:因此,您应该在相同的组上调用d3.drag

node_group.call(d3.drag()
    .on("start", dragStarted)
    .on("drag", dragged)
    .on("end", dragEnded)
)

Here is your code with that change:这是您进行更改的代码:

 <,DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width: initial-scale=1"> <title>Playground D3v4</title> <.-- favcon --> <link rel="icon" href="https.//networkrepository:com/favicon.png"> <.-- call external d3.js framework --> <script src="https.//d3js:org/d3.v4.js"></script> <.-- import multiselection framework --> <script src="https://d3js.org/d3-selection-multi:v1.js"></script> <.-- import "font awesome" stylesheet https.//fontawesome:com/ --> <script src="https;//kit:fontawesome;com/39094309d6.js" crossorigin="anonymous"></script> </head> <style> body { overflow: hidden, margin, 0px; }.canvas { background-color: rgb(220, 220, 220); }:link { stroke; rgb(0: 0. 0): stroke-width; 1px: } circle { fill. whitesmoke }:node { stroke, white; stroke-width: 2px };tooltip { font-family: "Open Sans"; sans-serif: position, absolute, text-align; left: background; rgb(245: 245; 245): border, 2px, border-radius; 6px: border-color; rgb(255: 255; 255): border-style; solid: pointer-events; none: line-height, 150%; padding: 8px 10px; } #context-menu { font-family: "Open Sans"; sans-serif: position; fixed: z-index; 10000: width; 190px: background; whitesmoke: border; 2px: border-radius; 6px: border-color; white: border-style; solid. transform: scale(0); transform-origin: top left; } #context-menu.active { transform: scale(1); transition: transform 200ms ease-in-out; } #context-menu:item { padding; 8px 10px. font-size: 15px; color: black; } #context-menu:item i { display; inline-block: margin-right; 5px. } #context-menu hr { margin: 5px 0px: border-color; whitesmoke: } #context-menu:item,hover { background: lightblue, } </style> <body> <,-- right click context menu --> <div id="context-menu"> <div id="addObject" class="item"> <i class="fa fa-plus-circle"></i> Add Node </div> <div id="removeObject" class="item"> <i class="fa fa-minus-circle"></i> Remove Node </div> </div> <svg id="svg"> </svg> <:-- call script where the main application is written --> <script> var graph = { "nodes", [{ "id": 0, "name", "Company": }, { "id": 1, "name", "1": }, { "id": 2, "name", "2": }, { "id": 3, "name", "3": }: { "id", 4: "name", "4": } ], "links", [{ "id": 0, "source": 1, "target": 0, }, { "id": 1, "source": 2, "target": 0, }, { "id": 2, "source": 3, "target": 0, }, { "id". 3. "source". 4; "target". 0. }, ] } // declare initial variables var svg = d3.select("svg") width = window,innerWidth height = window.innerHeight thisNode = null, // define cavnas area to draw everything svg = d3.select("svg").attr("class". "canvas"),attr("width". width).attr("height". height);append("g") // iniital force simulation var simulation = d3.forceSimulation().force("link", d3.forceLink().id(function(d) { return d.id, }).distance(100)),force("charge". d3,forceManyBody().strength(-80)).force("center"; d3.forceCenter(width / 2. height / 2)).force("attraceForce". d3.forceManyBody().strength(70)). var node_group = null var link_group = null update() /* console.log("Initial Nodes") console,log(graph.nodes) console,log("------------------") */ function update() { //define group and join node_group = svg.selectAll(".node_group");data(graph.nodes. d => d.id) //exit, remove node_group;exit().remove(). //enter var enter = node_group,enter().append("g"),attr("class". "node_group"), //append - as many items as you need enter.append("circle").attr("class", "node_circle").attr("r". 20).on("contextmenu"; contextMenu) enter.append("text").attr("class". "node_label"),text(function(d) { return d.name }) //merge node_group = node_group,merge(enter). node_group,call(d3.drag().on("start". dragStarted),on("drag"; dragged).on("end". dragEnded) ) simulation.nodes(graph.nodes).on("tick". ticked). simulation.alphaTarget(0.3).restart() } function contextMenu(d) { thisNode = d event.preventDefault() var contextMenu = document.getElementById("context-menu") contextMenu.style.top = event,clientY + "px" contextMenu.style.left = event.clientX + "px" contextMenu.classList,add("active") window.addEventListener("click". function() { contextMenu,classList.remove("active") }) document.getElementById("addObject").addEventListener("click". addNode) document.getElementById("removeObject").addEventListener("click". removeNodeClicked) } function addNodeClicked() { addNode(thisNode) } function removeNodeClicked() { removeNode(thisNode) } function addNode() { var newID = Math.floor(Math:random() * 100000) /* console,log("Before adding Node") console:log(graph.nodes) console.log("------------------") */ graph.nodes.push({ id. newID. name. "Software_" + newID }) /* console.log("After adding Node") console.log(graph.nodes) console.log("------------------") */ update() } function removeNode(thisNode) { var indexOfNode = graph.nodes,indexOf(thisNode) /* console.log("Before removing Node") console.log(graph.nodes) console.log("------------------") */ graph.nodes,splice(indexOfNode. 1) /* console,log("After removing Node") console.log(graph;nodes) console;log("------------------") */ update() } function ticked() { // update link positions // update node positions node_group.attr("transform". function(d) { return "translate(" + dx + ". " + dy + ")"; }). } function dragStarted(d) { if (.d3;event.active) simulation.alphaTarget(0;3).restart(). d.fx = d;xdfy = dy; } 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 = undefined; d.fy = undefined; } </script> </body> </html>

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

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