简体   繁体   中英

d3 zoom consumes event and prevents mouseover

I'm attempting to make a stream graph in d3 that is both zoomable and the paths are hoverable.

From reading around I see that as of v4 d3 zoom consumes the event and therefore may be why my mouseover event no longer fires, however no amount of reordering or pointer-events: all I set seems to have an effect.

Is anybody able to help me understand what I have to do to get both my zoom and hover working in the following example? (There's also a codesandbox with the example )

const width = 500;
const height = 500;

let numberOfDataPoints = 5;
const numberOfLayers = 3;

let data = [];

for (let i = 0; i < numberOfDataPoints; i++) {
  let point = [];
  for (let j = 0; j < numberOfLayers; j++) {
    point.push(Math.floor(Math.random() * Math.floor(120)));
  }

  data.push(point);
}

const x = d3
  .scaleLinear()
  .domain([0, numberOfDataPoints - 1])
  .range([0, width]);
const y = d3.scaleLinear().range([height, 0]);

const area = d3
  .area()
  .x((d, i) => x(i))
  .y0(d => y(d[0]))
  .y1(d => y(d[1]));

const stack = d3
  .stack()
  .keys(d3.range(numberOfLayers))
  .offset(d3.stackOffsetWiggle)
  .order(d3.stackOrderNone);

let layers = stack(data);
y.domain([
  d3.min(layers, l => d3.min(l, d => d[0])),
  d3.max(layers, l => d3.max(l, d => d[1]))
]);

update();

const zoomContainer = d3
  .select('svg')
  .append('rect')
  .attr('width', width)
  .attr('height', height)
  .attr('fill', 'none')
  .style('pointer-events', 'all');

const zoom = d3
  .zoom()
  .scaleExtent([1, 8])
  .on('zoom', zoomed);

zoomContainer.call(zoom);

function update() {
  let path = d3
    .select('svg')
    .selectAll('path')
    .data(layers);

  path
    .enter()
    .append('path')
    .attr('fill', 'red')
    .merge(path)
    .attr('d', d => area(d))
    .on('mouseover', () => {
      d3.select('svg')
        .selectAll('path')
        .attr('fill', 'red');
      d3.select(d3.event.target).attr('fill', 'green');
    });
}

function zoomed() {
  let transform = d3.event.transform;

  transform.y = 0;

  let updatedScale = transform.rescaleX(x);
  d3.select('svg')
    .selectAll('path')
    .attr('d', area.x((d, i) => updatedScale(i)));
}

The hypothesis for why this didn't work was correct (the zoom container consumes the event), and the fix is to just remove the zoomContainer and apply the zoom to the svg instead ie

const zoom = d3
  .zoom()
  .on('zoom', zoomed);

d3.select('svg').call(zoom);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM