Получение ожидаемого значения атрибута при переходе 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);
}