0

I have made a graph using d3 in JavaScript. The code allows the user to scale the x and y axes separately using pinch gestures within a certain degree from the desired axis. This works well.

Unfortunately, I have an issue where the domains of the axes 'snap' to match each other when any gesture transform is applied like a pinch zoom away from a single axis or a single finger gesture pan. I'd like some help figuring out how to stop this 'snapping' domain behavior. Thanks. Here is the code:

const staticBaseX = d3.scaleLinear().domain([-10, 10]).range([margin, svgWidth - margin]);
const staticBaseY = d3.scaleLinear().domain([-10, 10]).range([svgHeight - margin, margin]);

let baseX = staticBaseX.copy();
let baseY = staticBaseY.copy();

const ANGLE_TOLERANCE = 10;  // degrees

const zoomBehavior = d3.zoom()
  .filter((event) => {
    const t = event.type;
    return t === 'wheel'
        || t === 'mousedown'
        || t === 'mousemove'
        || t === 'touchstart'
        || t === 'touchmove';
  })
  .scaleExtent([1e-6, 1e6])
  .on('zoom', (event) => {
    const t  = event.transform;
    const se = event.sourceEvent;

    let newX = baseX.domain();
    let newY = baseY.domain();

    if (se?.touches && se.touches.length === 2) {
      // Two-finger pinch gesture — detect angle
      const [p1, p2] = se.touches;
      const dx = p2.clientX - p1.clientX;
      const dy = p2.clientY - p1.clientY;
      let angle = Math.abs(Math.atan2(dy, dx)) * 180 / Math.PI;
      if (angle > 180) angle -= 180;

      const nearH = angle <= ANGLE_TOLERANCE || angle >= 180 - ANGLE_TOLERANCE;
      const nearV = angle >= 90 - ANGLE_TOLERANCE && angle <= 90 + ANGLE_TOLERANCE;

      if (nearH) {
      // Only update X, keep Y fixed
      newX = t.rescaleX(staticBaseX).domain();
      
    } else if (nearV) {
      // Only update Y, keep X fixed
      newY = t.rescaleY(staticBaseY).domain();
      
    } else {
      // Diagonal: update both
      newX = t.rescaleX(staticBaseX).domain();
      newY = t.rescaleY(staticBaseY).domain();
    }
  } else {
    // Pan, wheel, or single-finger: update both
    newX = t.rescaleX(staticBaseX).domain();
    newY = t.rescaleY(staticBaseY).domain();
  }

  // Store the current domains
  currentXRange = newX;
  currentYRange = newY;
  baseX.domain(newX);
  baseY.domain(newY);

  plotGraph(currentExpr, currentXRange, currentYRange, true);
});

plotGraph is just a function to update the graph to the user.

3
  • Excuse me my curiosity: could you explain your typo in the title (!) So many people use the same wrong spelling, so — where it comes from? Also note, that syntax highlighting can be turned on by adding the word javascript (and appropriate names for other languages) to the opening fence line, for example: ~~~javascript. Commented Aug 22 at 13:16
  • @SergeyAKryukov, thank you for the edit. Apologies, but I think the typo is just a common misspelling. Commented Aug 22 at 13:42
  • You are welcome. No problem at all. The common is exactly the source of my curiosity: I see this exact spelling typo for years, it looks like people copy this bad habit from each other, and I am puzzled about where it comes from. Commented Aug 22 at 14:39

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.