Получение ожидаемого значения атрибута при переходе D3

Например у меня есть переход:

var sel = container.selectAll('div')
    .transition()
    .duration(1000)
    .attr('transform', 'translate(100,500)');

В какой-то момент мне нужно знать, куда приземляются некоторые элементы, например,

setTimeout(() => {
    var value = d3.select('div#target')
        .expectedAttr('transform');
    assertEqual(value, 'translate(100,500)');
}, 500);

Есть ли такая встроенная функция в D3? В противном случае мне придется написать свою собственную обертку d3.transition().attr() метод хранения переданных ему значений.

редактировать

Я узнал, что D3 создает __transition__ поле элементов, которое, кажется, содержит информацию о переходе, но я не вижу способа найти там значение целевого атрибута.

2 ответа

Решение

Сначала я подумал, что это будет невозможно, потому что целевое значение, казалось, было недоступно скрыто закрытием. Однако с небольшим фокусом это значение можно получить.

Вы должны иметь в виду, что при звонке transition.attr(), D3 сделает следующее:

Для каждого выбранного элемента создается атрибут анимации для атрибута с указанным именем и указанным целевым значением.

Доступ к этой автоматически созданной анимации можно получить, вызвав transition.attrTween(attrName),

Когда эта анимация вызывается D3, она возвращает интерполятор. Это, в свою очередь, имеет доступ к целевому значению, которое было закрыто при создании интерполятора. Когда вы читаете дальше документы, настоящая хитрость становится очевидной:

Возвращенный интерполятор затем вызывается для каждого кадра перехода, чтобы пройти прошедшее время t, обычно в диапазоне [0, 1].

Зная, что конечное значение для t - в конце перехода - будет 1, вы можете вызвать ранее полученный интерполятор с этим значением, которое даст целевое значение перехода.

var targetValue = transition 
  .attrTween("x2")            // Get the tween for the desired attribute
  .call(line.node())          // Call the tween to get the interpolator
  (1);                        // Call the interpolator with 1 to get the target value

Следующий пример показывает это, печатая целевое значение для уже запущенного перехода.

var line = d3.select("line");
line
  .transition()
  .duration(2000)
  .attr("x2", 100);
  
setTimeout(function() {
  var transition = d3.active(line.node())  // Get the active transition on the line
  var targetValue = transition 
    .attrTween("x2")                       // Get the tween for the desired attribute
    .call(line.node())                     // Call the tween to get the interpolator
    (1);                                   // Call the interpolator with 1 to get the target value
  console.log(targetValue);                // 100
}, 1000);
<script src="https://d3js.org/d3.v4.js"></script>

<svg><line x2="0" y2="100" stroke="black"></line></svg>

То же самое относится и к переходам стиля, где вы будете использовать transition.styleTween() чтобы получить подростка.

Заглянул сегодня в эту проблему и нашел очень полезным ответ высококучевых облаков . Однако я обнаружил, что (по крайней мере, для текущего d3-transition@2.0.0), если текущее значение уже равно целевому значению, .callв attrTween вернусь null вместо интерполятора.

Мое решение выглядело примерно так:

      const attrTargetValue = (selection, attr) => {
  const interpolator = selection
    .attrTween(attr)
    .call(selection.node());
  return interpolator === null
    ? selection.selection().attr(attr)
    : interpolator(1);
}
Другие вопросы по тегам