JSFiddle - React, Tailwind, and code Playground

by Chris Lindeman

HTML

<button id="reflect">
  reflect
</button>
<div id="container"></div>

CSS

svg {
  background: lightgrey;
  margin: 50px;
  overflow: visible;
}

JavaScript

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());