Visx: Scale axis with zoom

Created on 4 Feb 2019  路  6Comments  路  Source: airbnb/visx

When using the zoom component I would like to apply the transform matrix to my axis so that they represent the new visible domain. How would I go about this using vx?

  // Scales aren't necessarily linear and time
  const xScale = scaleTime({
    range: [0, xMax],
    domain: extent(data, x)
  });

  const yScale = scaleLinear({
    range: [yMax, 0],
    domain: [0, max(data, y)]
  });

  <Zoom
      width={width}
      height={height}
      scaleXMin={1}
      scaleXMax={4}
      scaleYMin={1}
      scaleYMax={4}
      transformMatrix={initialTransform}
    >
      {zoom =>
        <svg width={width} height={height}>
          <Group>
            <Group transform={zoom.toString()}>
               {renderLine()} // Code rendering actual graph that can be zoomed
            </Group>
            // Axis live outside group with zoom transform
            <AxisLeft
              scale={???} // What goes here?
              top={0}
              left={0}
            />
            <AxisBottom
              scale={???} // What goes here?
              top={yMax}      
             />
         </Group>
       }
    </Zoom>
馃惎example

Most helpful comment

Correction, this is working for me for both linear and time. The trick was just to convert everything to pixel values, apply the transforms, then convert back to the domain.

const xScaleTransformed = scaleTime({
  range: [0, xMax],
  domain: [
    xScale.invert((xScale(extent(data, x)[0]) - zoom.transformMatrix.translateX) / zoom.transformMatrix.scaleX),
    xScale.invert((xScale(extent(data, x)[1]) - zoom.transformMatrix.translateX) / zoom.transformMatrix.scaleX),
  ],
});

const yScaleTransformed = scaleLinear({
  range: [yMax, 0],
  domain: [
    yScale.invert((yScale(0) - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY),
    yScale.invert((yScale(max(data, y)) - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY),
  ],
});

All 6 comments

Anyone made progress on this?

@s-hood I also could not think of a way to do this with zoom, so instead I used drag to draw a rectangle
over a part of my chart, subset the data to that part and then re-rendered. It's less dynamic than zooming but is good enough for my use case.

I have managed to do this with a linear scale, but struggling with time scale:

const yScale = scaleLinear({
  range: [yMax, 0],
  domain: [0, max(data, y)]
 });
<AxisLeft
  scale={scaleLinear({
    range: [yMax, 0],
    domain: [
      yScale.invert((yMax - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY), (max(data, y) / zoom.transformMatrix.scaleY) + yScale.invert((yMax - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY),
    ],
  })}
  top={0}
  left={0}
/>

Correction, this is working for me for both linear and time. The trick was just to convert everything to pixel values, apply the transforms, then convert back to the domain.

const xScaleTransformed = scaleTime({
  range: [0, xMax],
  domain: [
    xScale.invert((xScale(extent(data, x)[0]) - zoom.transformMatrix.translateX) / zoom.transformMatrix.scaleX),
    xScale.invert((xScale(extent(data, x)[1]) - zoom.transformMatrix.translateX) / zoom.transformMatrix.scaleX),
  ],
});

const yScaleTransformed = scaleLinear({
  range: [yMax, 0],
  domain: [
    yScale.invert((yScale(0) - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY),
    yScale.invert((yScale(max(data, y)) - zoom.transformMatrix.translateY) / zoom.transformMatrix.scaleY),
  ],
});

Yup, here is a method I'm using to scale my Axis based on the zoom.
Its all about updating the domain to what is now visible due to the zoom area.

const rescaleYAxis = (scale, zoom) => {
  let newDomain = scale.range().map((r) => {
    return scale.invert((r - zoom.transformMatrix.translateY)/zoom.transformMatrix.scaleY)
  })
  return scale.copy().domain(newDomain)
}

@sseira Trying to figure this stuff out myself now. Where would you call rescaleYAxis from?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

esetnik picture esetnik  路  3Comments

roxanagirdu picture roxanagirdu  路  4Comments

ghost picture ghost  路  5Comments

BrianRosamilia picture BrianRosamilia  路  3Comments

sabarnix picture sabarnix  路  4Comments