在D3js中对外部svg图标的子元素进行动画处理?

时间:2020-09-14 22:56:45

标签: svg d3.js

我被要求创建一个仪表板,以可视化滑雪的机械原理。他要我做的第一件事是可视化滑雪中涉及的空气阻力。因此,我认为如果可以创建一个可以向不同方向移动的滑雪者的SVG图标,那就太好了。例如,为了可视化正确的手臂位置在滑雪中的效果,我希望能够将手臂更多地移动到滑雪者面前而不是垂下。简单的2D图形。

在D3中,喜欢附加这样的图像。

const skier = g
.append('image')
.attr('id', 'skier')
.datum(p3)
.attr('href', skierIconSvg)
.attr('width', 100)
.attr('height', 100)
.attr('transform', 'translate(-50, -40)')

但是使用这种方法,我发现仅在svg图标上仅制作一个元素(例如手臂)的动画非常棘手。所以我的问题是,有没有办法让D3.js中的外部svg图标的一个元素动画?

1 个答案:

答案 0 :(得分:1)

应该可以,我创建了这个展示柜,展示了如何做。 我将SVG解析为XML,并将其子级直接附加到我信任的XML文件中。然后,我可以选择手臂和棍子(它们具有可怕的自动生成的ID,您可以在SVG文件本身中更改它们)并旋转它们。

唯一真正令人讨厌的事情是旋转使元素大量移位。我用transform-origin修复了这个问题,我通过反复试验手动将其设置在肩关节附近。这样,手臂将绕着肩膀旋转,而不是围绕SVG的左上方旋转。

// The herokuapp is just a hack to make it work on SO, should be easier
// for you locally
d3.xml('https://cors-anywhere.herokuapp.com/https://cmagelssen.no/skier.svg')
  .then((xml) => {
    const svgEl = d3.select('#mySvg')
      .append('g')
      .attr('id', 'skier')
      .node();
    Array.from(xml.documentElement.children).forEach((el) => {
      svgEl.appendChild(el);
    });
    
    const skierG = d3.select("#skier > g > g");
    const skierArms = d3.select("#skier #ailpBmbkR")
       // Trial an error, but if you get this close to the skier's shoulder,
       // you don't have to do a transform and can easily vary rotation!
      .style("transform-origin", "322px 244px")
      .style("transform", "rotate(30deg)");

    const skierStick = d3.select("#skier #c4PTA7jJrE")
       // Same point as the skier arms!
      .style("transform-origin", "322px 244px")
      .style("transform", "rotate(30deg)");
  })
  .catch((e) => {
    console.error(e);
  })
  .finally(() => {
    console.log('done');
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg id="mySvg" width="500" height="500"></svg>