How to catch pinch and stretch gesture events in d3.zoom (d3v4/v5)

Viewed 2080

Background

I'm building multiple interactions into my d3v5 visualization. Clicking and dragging should let the user pan the svg container. The scroll wheel should translate vertically. Both of those work.

svg.call(d3.zoom().on("zoom", zoomed)).on("wheel.zoom", wheeled);

function zoomed() {
    current_transform = d3.zoomTransform(g);
    current_transform.x += d3.event.sourceEvent.movementX;
    current_transform.y += d3.event.sourceEvent.movementY;
    g.attr("transform", current_transform);
}

function wheeled() {
    current_transform = d3.zoomTransform(g);
    current_transform.y = current_transform.y - d3.event.deltaY;
    g.attr("transform", current_transform);
}

Question

I'd like to permit the user to use pinch and stretch touch gestures to zoom the svg in the classical sense. What is the analog of "wheel.zoom" is for touch gestures? How do I register a callback on the user pinching and stretching on their trackpad or phone?

Notes

Updates

It seems like it might be the case that the pinch gesture is being caught by "wheel.zoom" and d3.event.type == "wheel" on pinch and stretch. Furthermore, d3.event.deltaZ == 0 for all these events.

1 Answers

Turns out trackpad pinch is emitted as a wheel.zoom with d3.event.ctrlKey set to True. That's what browsers have agreed to:

https://medium.com/@auchenberg/detecting-multi-touch-trackpad-gestures-in-javascript-a2505babb10e

Pretty unintuitive, but there you have it.

Here's my final code:

svg.call(d3.zoom().on("zoom", zoomed)).on("wheel.zoom", wheeled);

transform = d3.zoomTransform(g);
transform.x += margin.left;
transform.y += margin.top;
g.attr("transform", transform);

function zoomed() {
    current_transform = d3.zoomTransform(g);
    current_transform.x += d3.event.sourceEvent.movementX;
    current_transform.y += d3.event.sourceEvent.movementY;
    g.attr("transform", current_transform);
}

function wheeled() {
    current_transform = d3.zoomTransform(g);
    if (d3.event.ctrlKey) {
        current_transform.k = current_transform.k - d3.event.deltaY * 0.01;
    } else {
        current_transform.y = current_transform.y - d3.event.deltaY;
    }
    g.attr("transform", current_transform);
}
Related