I have a path
element that I am updating with new data. It is then repositioned and also reflected. All of that is working correctly. The part that is not working correctly is the transition. Due to the way I am reflecting (using scale
and translate
), it moves past the correct position before returning.
How can I transition from the initial x-axis position to the new x-axis position without moving past the new position?
HTML:
<button id="reflect">reflect</button>
<div id="container"></div>
JS:
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
const width = 500;
const height = 200;
const x = d3.scaleLinear()
.domain([0, 100])
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, 50])
.range([height, 0]);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
svg.append("g")
.call(d3.axisLeft(y));
const data = [{
x: 60,
y: 20
}];
const reflectedData = [{
x: 30,
y: 20
}];
svg.selectAll('arrow')
.data(data)
.join('path')
.attr('class', 'arrow')
.attr('d', 'M0,0 L80,0 L80, 50z')
d3.select('#reflect')
.on('click', () => {
svg.selectAll('.arrow')
.data(reflectedData)
updateArrow(2000)
})
updateArrow(0);
function updateArrow(duration) {
const midpoint = x.domain()[1] / 2
svg.selectAll('.arrow')
.transition()
.duration(duration)
.style('scale', d => d.x < midpoint ? '-1 1' : '1 1')
.style('transform', d => {
const translateX = d.x < midpoint ? -x(d.x) : x(d.x);
return `translate(${translateX}px, ${y(d.y)}px)`;
})
}
container.append(svg.node());
Two problems:
transform
doesn't really play nice with other transform-like attributes like scale
. (At least, it's very hard to reason about.) Much easier to just do everything in transform
.d.x < midpoint
; only the scale should.function updateArrow(duration) {
const midpoint = x.domain()[1] / 2
svg.selectAll('.arrow')
.transition()
.duration(duration)
.style('transform', d =>
`translate(${x(d.x)}px, ${y(d.y)}px) scaleX(${d.x < midpoint ? -1 : 1})`
)
}
The triangle flips over the vertical as it moves from right to left.