在 d3.js 中更新剪辑路径?

Posted

技术标签:

【中文标题】在 d3.js 中更新剪辑路径?【英文标题】:Updating a clip-path in d3.js? 【发布时间】:2022-01-20 09:35:39 【问题描述】:

在我最近的项目中,我有兴趣创建一个随鼠标移动而移动的剪辑路径。我最初的想法是使用鼠标移动坐标选择并重新定位省略号及其属性cxcy,然后选择矩形并重新初始化其clip-path 属性。

但是,这似乎不起作用。到目前为止,我发现的唯一可行的解​​决方案是删除矩形和剪辑路径,然后在新坐标处重新初始化它们。这适用于下面的简单测试用例,但在我的实际实验中,我将尝试剪辑的对象是外部加载的 svg,并且每次鼠标悬停时都必须重新加载它可能会非常昂贵。

您对如何在不重新初始化所有内容的情况下达到我下面显示的相同效果有什么建议吗?

<!DOCTYPE html>
<html>

  <head>
    <script src="https://unpkg.com/mathjs/lib/browser/math.js"></script>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    
    <style>

    </style>
  </head>

<!-- Create a div where the graph will take place -->
<div id="my_datavisualization">
  <svg id="click" xmlns="http://www.w3.org/2000/svg">
      <defs>
          <g id="pointer" transform="scale(0.5)">
              <circle cx="0" cy="0" r="20" id="dragcircle" />
          </g>
      </defs>
  </svg>
</div>



  <body style='overflow:hidden'>
  
    
    <script>
    
        // Get the viewport height and width
      const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
      const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
      
      // Fit to viewport
      var height            = vw*0.7;
      var width             = vw;
      
      // Create the canvas. We will use only part of it for the main plot
      var svg = d3.select("#click") // This selects the div
          .attr("width", width) // This defines the canvas' width
          .attr("height", height) // This defines the canvas' height
      
      
        
      
      // define the clipPath
      svg.append("clipPath")       // define a clip path
          .attr("id", "ellipse-clip") // give the clipPath an ID
        .append("ellipse")          // shape it as an ellipse
          .attr("cx", 175)         // position the x-centre
          .attr("cy", 100)         // position the y-centre
          .attr("rx", 100)         // set the x radius
          .attr("ry", 50);         // set the y radius

      // draw clipped path on the screen
      svg.append("rect")        // attach a rectangle
          .attr("id","cliprect")
          .attr("x", 125)        // position the left of the rectangle
          .attr("y", 75)         // position the top of the rectangle
          .attr("clip-path", "url(#ellipse-clip)") // clip the rectangle
          .style("fill", "lightgrey")   // fill the clipped path with grey
          .attr("height", 100)    // set the height
          .attr("width", 200);    // set the width
      
      
      // Shift the marker around on mouseover; restrict it to the contour
      var movex
      var movey

      svg
        .on("mousemove", function () 
        
            // Get the current mouseover coordinates
            movex = d3.event.x;
            movey = d3.event.y;

          // The only way I get this to work right now is by removing the previous clipped shape, then re-adding it
          d3.select("#cliprect").remove()
          d3.select("#ellipse-clip").remove()
          
          // define the clipPath
          svg.append("clipPath")       // define a clip path
              .attr("id", "ellipse-clip") // give the clipPath an ID
            .append("ellipse")          // shape it as an ellipse
              .attr("cx", movex)         // position the x-centre
              .attr("cy", movey)         // position the y-centre
              .attr("rx", 100)         // set the x radius
              .attr("ry", 50);         // set the y radius
            
          // draw clipped path on the screen
          svg.append("rect")        // attach a rectangle
              .attr("id","cliprect")
              .attr("x", 125)        // position the left of the rectangle
              .attr("y", 75)         // position the top of the rectangle
              .attr("clip-path", "url(#ellipse-clip)") // clip the rectangle
              .style("fill", "lightgrey")   // fill the clipped path with grey
              .attr("height", 100)    // set the height
              .attr("width", 200);    // set the width
          
          
            
          );

      
  
    </script>
  </body>

</html>

【问题讨论】:

【参考方案1】:

用它代替你的 mousemove 回调

function() 
        
            // Get the current mouseover coordinates
            movex = d3.event.x;
            movey = d3.event.y;

  
          // move the clipPath
          d3.select("#ellipse-clip") // selects the clipPath
            .select("ellipse")          // selects the ellipse
              .attr("cx", movex)         // position the x-centre
              .attr("cy", movey)         // position the y-centre
            
          // move clipped path on the screen
          svg.select("rect")        // attach a rectangle
              .attr("x", movex)        // position the left of the rectangle
              .attr("y", movey)         // position the top of the rectangle

          
          
            

【讨论】:

以上是关于在 d3.js 中更新剪辑路径?的主要内容,如果未能解决你的问题,请参考以下文章

d3.js - v3 和 v4 - 输入和更新差异

在鼠标悬停事件上更新 D3.js 图

D3.js 和 Knockout Force Diagram API 更新

D3.js饼图动态更新转换未按预期工作

更新SVG元素的转换时,Firefox会移动剪辑路径,而Chromium则不会 - 这是正确的,什么是便携式解决方案?

d3.js 封装一个方法更新柱状图,运用数据模板