Анимировать подэлементы внешнего значка svg в D3js?

#svg #d3.js

#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)')
  

Но при таком подходе мне сложно просто выполнить анимацию только одного элемента (например, arm) на значке svg. Итак, мой вопрос в том, есть ли способ анимировать только один элемент внешнего значка svg в D3.js ?

Комментарии:

1. изображения не поддерживают сценарии, так что это будет практически невозможно.

2. Ого .. так что, невозможно нарисовать внешний значок svg, обернуть некоторые его элементы элементом g, а затем иметь возможность выполнять анимацию только для этих элементов g?

3. Как вы планируете «обернуть некоторые элементы» изображения. Изображение непрозрачное, вы не можете получить доступ к его содержимому.

4. bl.ocks.org/mbostock/1014829 — Я подумал, что мог бы добавить элемент g в svg, возможно, с именем класса, а затем использовать d3 для выбора только этого элемента 🙊

5. Который использует iframe, а не элемент изображения.

Ответ №1:

Это должно быть возможно, я создал эту демонстрацию о том, как это сделать. Я анализирую SVG как XML и добавляю его дочерние элементы непосредственно в мой доверенный XML-файл. Затем я могу выбрать arm и stick (у которых ужасные автоматически сгенерированные идентификаторы — вы можете изменить их внутри самого файла 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>  

Комментарии:

1. Ваши знания о D3.js это действительно потрясающе, Рубен. Вы предоставляете решение всех моих проблем. Как вы нашли arm в моем svg? Это просто идентификационный тег в svg?

2. Я просто использовал инспектор элементов, чтобы найти соответствующий элемент path, идентификаторы на самом деле не описательные

3. Но в принципе. Я могу нарисовать свой значок в Adobe illustrator, сохранить его в svg. Тогда я могу зайти внутрь svg и добавить идентификационные теги к рукам, ногам, голове, телу?

4. Я не совсем уверен, но теоретически вы можете сделать именно это

5. Я попробую в эти выходные. Я пришлю вам обновленную информацию о том, как это происходит.