visx icon indicating copy to clipboard operation
visx copied to clipboard

Applying visx-zoom to a XYChart - issue moving graph outside grid and on top of axises

Open nilsgoksor opened this issue 3 years ago • 3 comments

Discussed in https://github.com/airbnb/visx/discussions/1243

Originally posted by nilsgoksor June 18, 2021 I'm struggling to find examples of visx-zoom other than the official one: https://airbnb.io/visx/zoom-i and right now I'm totally stuck on one issue.

When I apply it to my XYChart it's not behaving the desired way. I obviously don't want to be able to move the graph on top of the axises or even outside the graph (as in the picture) but no matter what I try I can't seem to get both the XYChart-axises and a movable graph at the same time.

Do you guys have any example I can follow or any idea what might cause the issue?

Screenshot 2021-06-18 at 08 30 12

nilsgoksor avatar Jun 21 '21 08:06 nilsgoksor

@nilsgoksor Do you have a gist of your xychart component that I can take a look? 👀

gazcn007 avatar Jun 21 '21 13:06 gazcn007

Sure, here you go https://codesandbox.io/embed/charming-cookies-ik7ps?fontsize=14&hidenavigation=1&theme=dark 🤙

nilsgoksor avatar Jun 22 '21 07:06 nilsgoksor

@nilsgoksor sorry for the late reply. Interesting problem. I believe this is normal if you directly apply transform={zoom.toString()} here:

<Group>
    <LineSeries
      transform={zoom.toString()} // <-- here
      data={reScaledData}
      {...otherProps}
      {...accessors}
    />
</Group>

Because that just takes whichever how much x and y movements you dragged and apply to the path svg (chart) with transform: matrix(...variables) or transform: translate(x, y) attributes.

This is a viz from Mike Bostock himself, same issue. https://observablehq.com/@d3/zoomable-bar-chart

So transform={zoom.toString()} is causing the problem for what you want to achieve with charts and axis. If you want to keep it simple with zoom.toString(), I would expand and axis and grid to cover the full svg space: chart

<Group>
   <Axis left hideZero orientation="right" />
   <Axis top hideZero orientation="bottom" />
   <Grid top left width={width + margin} height={height + margin} />
</Group>

If what you want to achieve is something like this: Line chart with zoom

Then you need to remove transform={zoom.toString()}, and do more math in getScaledData() function, calculate the new extent with x and y movement after dragging and remap your values onto the chart with new extent, something like this:

let extent = [[0, width], [0, height]];
function getScaledData(transformMatrix) {
   // ... get xMovement and yMovement after multiplying scaleX, scaleY
   // set extent
   extent = [[extent[0][0] + xMovement, extent[0][1] + xMovement], [extent[1][0] + yMovement, extent[1][1] + yMovement]];
   // 
const xScale = scaleLinear({
      domain: [Math.min(...XVals), Math.max(...XVals)],
      range: [extent[0][0], extent[0][1]]
    });
    const yScale = scaleLinear({
      domain: [Math.min(...YVals), Math.max(...YVals)],
      range: [extent[1][0], extent[1][1]]
    });

gazcn007 avatar Jul 01 '21 21:07 gazcn007