Performance 调用Canvas.scale后D3强制布局(画布)性能退出

Performance 调用Canvas.scale后D3强制布局(画布)性能退出,performance,canvas,visualization,scale,d3-force-directed,Performance,Canvas,Visualization,Scale,D3 Force Directed,我遇到了非常奇怪的性能问题。 我使用d3力图可视化网络中的一些关系,为了实现缩放,我使用d3缩放。 当d3.zoomIdentity.k>1时,性能会显著下降,我不知道为什么!:( 正如您在性能配置文件的屏幕截图中所看到的,在滚动(紫色线)(放大,k变为>1)之后,帧渲染时间和任务(灰色线)时间立即增加 您可以这样复制它: 1.打开Index.html 2.拖动一些节点并检查fps(目视) 3.放大,现在可以看到病态绩效下降 4.缩小镜头,一切又恢复正常:耸耸肩: 以下是代码(index.ht

我遇到了非常奇怪的性能问题。 我使用d3力图可视化网络中的一些关系,为了实现缩放,我使用d3缩放。 当d3.zoomIdentity.k>1时,性能会显著下降,我不知道为什么!:(

正如您在性能配置文件的屏幕截图中所看到的,在滚动(紫色线)(放大,k变为>1)之后,帧渲染时间和任务(灰色线)时间立即增加

您可以这样复制它: 1.打开Index.html 2.拖动一些节点并检查fps(目视) 3.放大,现在可以看到病态绩效下降 4.缩小镜头,一切又恢复正常:耸耸肩:

以下是代码(index.html):


.边缘{
笔画:白色;
笔画宽度:1;
}
.graphSVG{
背景色:黑色;
}
分区集装箱{
宽度:100%;
边框:1px纯色灰色;
}
分区工具提示{
位置:绝对位置;
文本对齐:居中;
宽度:180px;
填充:2px;
字体:12px无衬线;
背景:淡蓝色;
边界:0px;
边界半径:8px;
指针事件:无;
}
var半径=5;
var defaultNodeCol=“白色”,
highlightCol=“黄色”;
var height=window.innerHeight;
var graphWidth=window.innerWidth;
var graphCanvas=d3.select(“#graphDiv”).append('canvas'))
.attr('width',graphWidth)
.attr('height',height)
.node();
var context=graphCanvas.getContext('2d');
graphCanvas.style.backgroundColor=“白色”;
var div=d3.选择(“主体”).追加(“div”)
.attr(“类”、“工具提示”)
.样式(“不透明度”,0);
var simulation=d3.forceSimulation()
.force(“link”,d3.forceLink().id(函数(d){return d.id;}))
.力(“中心”,d3.力中心(图canvas.width/2,图canvas.height/2))
.力(“x”,d3.力x(图宽/2).强度(0.2))
.力(“y”,d3.力(图形Canvas.height/2).强度(0.2))
.力(“电荷”,d3.力人体().力(-50))
var transform=d3.zoomIdentity;
d3.json(“https://jsonstorage.net/api/items/7a90797a-6abe-4795-bf5c-20b08644fe1e)然后(data=>initGraph(data));
函数initGraph(tempData){
函数缩放(){
transform=d3.event.transform;
模拟更新();
}
d3.选择(图形Canvas)
.call(d3.drag().subject(dragsubject).on(“开始”,拖动开始).on(“拖动”,拖动).on(“结束,拖动))
.call(d3.zoom().scaleExtent([1/10,8])。打开(“缩放”,缩放))
函数dragsubject(){
var i,
x=transform.invertX(d3.event.x),
y=变换.inversy(d3.event.y),
dx,
dy;
对于(i=tempData.nodes.length-1;i>=0;--i){
node=tempData.nodes[i];
dx=x-节点x;
dy=y-node.y;
if(dx*dx+dy*dy
AFK现在,您是否可以在其他浏览器或其他版本的Chrome(如canary)上重新编程?听起来像是一个浏览器错误。不过解决方法很简单:手动将所有坐标和线宽乘以k。同样,在金丝雀上,Safari根本不会启动。我在循环结束时进行的笔划调用是否会导致moveTo/lineTo出现问题?(最后回到计算机上)我试图编辑你的问题以包含一个实时片段,但无法在那里复制。首先我认为这是因为画布大小很重要。你这边的
graphWidth
height
值是什么?我开始看到延迟,当我达到3000x3000时,但之前不是真的…此外,手动缩放坐标的结果是速度更慢…图形宽度:1920高度:1080
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
  .edge {
    stroke: white;
    stroke-width: 1;
  }

  .graphSVG {
    background-color: black;
  }

  div.container {
    width: 100%;
    border: 1px solid gray;
  }

  div.tooltip {
    position: absolute;
    text-align: center;
    width: 180px;
    padding: 2px;
    font: 12px sans-serif;
    background: lightsteelblue;
    border: 0px;
    border-radius: 8px;
    pointer-events: none;
  }
</style>

<body>
  <div id="graphDiv"></div>

  <script>
    var radius = 5;

    var defaultNodeCol = "white",
      highlightCol = "yellow";

    var height = window.innerHeight;
    var graphWidth = window.innerWidth;

    var graphCanvas = d3.select('#graphDiv').append('canvas')
      .attr('width', graphWidth)
      .attr('height', height)
      .node();

    var context = graphCanvas.getContext('2d');
    graphCanvas.style.backgroundColor = "white";

    var div = d3.select("body").append("div")
      .attr("class", "tooltip")
      .style("opacity", 0);

    var simulation = d3.forceSimulation()
      .force("link", d3.forceLink().id(function (d) { return d.id; }))
      .force("center", d3.forceCenter(graphCanvas.width / 2, graphCanvas.height / 2))
      .force("x", d3.forceX(graphCanvas.width / 2).strength(0.2))
      .force("y", d3.forceY(graphCanvas.height / 2).strength(0.2))
      .force("charge", d3.forceManyBody().strength(-50))


    var transform = d3.zoomIdentity;

    d3.json("https://jsonstorage.net/api/items/7a90797a-6abe-4795-bf5c-20b08644fe1e").then(data => initGraph(data));

    function initGraph(tempData) {
      function zoomed() {
        transform = d3.event.transform;
        simulationUpdate();
      }

      d3.select(graphCanvas)
        .call(d3.drag().subject(dragsubject).on("start", dragstarted).on("drag", dragged).on("end", dragended))
        .call(d3.zoom().scaleExtent([1 / 10, 8]).on("zoom", zoomed))



      function dragsubject() {
        var i,
          x = transform.invertX(d3.event.x),
          y = transform.invertY(d3.event.y),
          dx,
          dy;
        for (i = tempData.nodes.length - 1; i >= 0; --i) {
          node = tempData.nodes[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);

      }

      function dragended() {
        if (!d3.event.active) simulation.alphaTarget(0);
        d3.event.subject.fx = null;
        d3.event.subject.fy = null;
      }

      simulation.nodes(tempData.nodes)
        .on("tick", simulationUpdate);

      simulation.force("link")
        .links(tempData.edges);



      function render() {

      }

      function simulationUpdate() {
        context.save();
        context.clearRect(0, 0, graphWidth, height);
        context.translate(transform.x, transform.y);
        context.scale(transform.k, transform.k);

        context.beginPath();
        context.strokeStyle = 'rgba(255, 0, 0, 1)';
        tempData.edges.forEach(function (d) {
          context.moveTo(d.source.x, d.source.y);
          context.lineTo(d.target.x, d.target.y);
        });
        context.stroke();
        context.closePath();

        const part1 = tempData.nodes.slice(0, tempData.nodes.length / 2);
        const part2 = tempData.nodes.slice(tempData.nodes.length / 2);

        context.fillStyle = 'black';
        context.beginPath();
        part1.forEach(function (d, i) {
          context.moveTo(d.x, d.y);
          context.arc(d.x, d.y, radius, 0, 2 * Math.PI, true);
        });
        context.fill();
        context.closePath();

        context.fillStyle = 'orange';
        context.beginPath();
        part2.forEach(function (d, i) {
          context.moveTo(d.x, d.y);
          context.arc(d.x, d.y, radius, 0, 2 * Math.PI, true);
        });
        context.fill();
        context.closePath();

        context.restore();
      }
    };


  </script>
</body>```