feat(interaction): add zoomToPinch prop
This commit is contained in:
@@ -27,6 +27,7 @@ const InteractionFlow = () => {
|
|||||||
const [isDraggable, setIsDraggable] = useState(false);
|
const [isDraggable, setIsDraggable] = useState(false);
|
||||||
const [isConnectable, setIsConnectable] = useState(false);
|
const [isConnectable, setIsConnectable] = useState(false);
|
||||||
const [zoomOnScroll, setZoomOnScroll] = useState(false);
|
const [zoomOnScroll, setZoomOnScroll] = useState(false);
|
||||||
|
const [zoomOnPinch, setZoomOnPinch] = useState(false);
|
||||||
const [panOnScroll, setPanOnScroll] = useState(false);
|
const [panOnScroll, setPanOnScroll] = useState(false);
|
||||||
const [panOnScrollMode, setPanOnScrollMode] = useState('free');
|
const [panOnScrollMode, setPanOnScrollMode] = useState('free');
|
||||||
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(false);
|
const [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(false);
|
||||||
@@ -42,6 +43,7 @@ const InteractionFlow = () => {
|
|||||||
nodesConnectable={isConnectable}
|
nodesConnectable={isConnectable}
|
||||||
nodesDraggable={isDraggable}
|
nodesDraggable={isDraggable}
|
||||||
zoomOnScroll={zoomOnScroll}
|
zoomOnScroll={zoomOnScroll}
|
||||||
|
zoomOnPinch={zoomOnPinch}
|
||||||
panOnScroll={panOnScroll}
|
panOnScroll={panOnScroll}
|
||||||
panOnScrollMode={panOnScrollMode}
|
panOnScrollMode={panOnScrollMode}
|
||||||
zoomOnDoubleClick={zoomOnDoubleClick}
|
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||||
@@ -107,6 +109,18 @@ const InteractionFlow = () => {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="zoomonpinch">
|
||||||
|
zoomOnPinch
|
||||||
|
<input
|
||||||
|
id="zoomonpinch"
|
||||||
|
type="checkbox"
|
||||||
|
checked={zoomOnPinch}
|
||||||
|
onChange={(event) => setZoomOnPinch(event.target.checked)}
|
||||||
|
className="react-flow__zoomonpinch"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="panonscroll">
|
<label htmlFor="panonscroll">
|
||||||
panOnScroll
|
panOnScroll
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const FlowRenderer = ({
|
|||||||
zoomActivationKeyCode,
|
zoomActivationKeyCode,
|
||||||
elementsSelectable,
|
elementsSelectable,
|
||||||
zoomOnScroll,
|
zoomOnScroll,
|
||||||
|
zoomOnPinch,
|
||||||
panOnScroll,
|
panOnScroll,
|
||||||
panOnScrollSpeed,
|
panOnScrollSpeed,
|
||||||
panOnScrollMode,
|
panOnScrollMode,
|
||||||
@@ -92,6 +93,7 @@ const FlowRenderer = ({
|
|||||||
selectionKeyPressed={selectionKeyPressed}
|
selectionKeyPressed={selectionKeyPressed}
|
||||||
elementsSelectable={elementsSelectable}
|
elementsSelectable={elementsSelectable}
|
||||||
zoomOnScroll={zoomOnScroll}
|
zoomOnScroll={zoomOnScroll}
|
||||||
|
zoomOnPinch={zoomOnPinch}
|
||||||
panOnScroll={panOnScroll}
|
panOnScroll={panOnScroll}
|
||||||
panOnScrollSpeed={panOnScrollSpeed}
|
panOnScrollSpeed={panOnScrollSpeed}
|
||||||
panOnScrollMode={panOnScrollMode}
|
panOnScrollMode={panOnScrollMode}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ const GraphView = ({
|
|||||||
arrowHeadColor,
|
arrowHeadColor,
|
||||||
markerEndId,
|
markerEndId,
|
||||||
zoomOnScroll,
|
zoomOnScroll,
|
||||||
|
zoomOnPinch,
|
||||||
panOnScroll,
|
panOnScroll,
|
||||||
panOnScrollSpeed,
|
panOnScrollSpeed,
|
||||||
panOnScrollMode,
|
panOnScrollMode,
|
||||||
@@ -212,6 +213,7 @@ const GraphView = ({
|
|||||||
onMoveStart={onMoveStart}
|
onMoveStart={onMoveStart}
|
||||||
onMoveEnd={onMoveEnd}
|
onMoveEnd={onMoveEnd}
|
||||||
zoomOnScroll={zoomOnScroll}
|
zoomOnScroll={zoomOnScroll}
|
||||||
|
zoomOnPinch={zoomOnPinch}
|
||||||
zoomOnDoubleClick={zoomOnDoubleClick}
|
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||||
panOnScroll={panOnScroll}
|
panOnScroll={panOnScroll}
|
||||||
panOnScrollSpeed={panOnScrollSpeed}
|
panOnScrollSpeed={panOnScrollSpeed}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
|||||||
arrowHeadColor?: string;
|
arrowHeadColor?: string;
|
||||||
markerEndId?: string;
|
markerEndId?: string;
|
||||||
zoomOnScroll?: boolean;
|
zoomOnScroll?: boolean;
|
||||||
|
zoomOnPinch?: boolean;
|
||||||
panOnScroll?: boolean;
|
panOnScroll?: boolean;
|
||||||
panOnScrollSpeed?: number;
|
panOnScrollSpeed?: number;
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
@@ -156,6 +157,7 @@ const ReactFlow = ({
|
|||||||
arrowHeadColor = '#b1b1b7',
|
arrowHeadColor = '#b1b1b7',
|
||||||
markerEndId,
|
markerEndId,
|
||||||
zoomOnScroll = true,
|
zoomOnScroll = true,
|
||||||
|
zoomOnPinch = true,
|
||||||
panOnScroll = false,
|
panOnScroll = false,
|
||||||
panOnScrollSpeed = 0.5,
|
panOnScrollSpeed = 0.5,
|
||||||
panOnScrollMode = PanOnScrollMode.Free,
|
panOnScrollMode = PanOnScrollMode.Free,
|
||||||
@@ -217,6 +219,7 @@ const ReactFlow = ({
|
|||||||
arrowHeadColor={arrowHeadColor}
|
arrowHeadColor={arrowHeadColor}
|
||||||
markerEndId={markerEndId}
|
markerEndId={markerEndId}
|
||||||
zoomOnScroll={zoomOnScroll}
|
zoomOnScroll={zoomOnScroll}
|
||||||
|
zoomOnPinch={zoomOnPinch}
|
||||||
zoomOnDoubleClick={zoomOnDoubleClick}
|
zoomOnDoubleClick={zoomOnDoubleClick}
|
||||||
panOnScroll={panOnScroll}
|
panOnScroll={panOnScroll}
|
||||||
panOnScrollSpeed={panOnScrollSpeed}
|
panOnScrollSpeed={panOnScrollSpeed}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useRef, ReactNode } from 'react';
|
import React, { useEffect, useRef, ReactNode } from 'react';
|
||||||
import { zoom, zoomIdentity } from 'd3-zoom';
|
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||||
import { select } from 'd3-selection';
|
import { select, pointer } from 'd3-selection';
|
||||||
|
|
||||||
import { clamp } from '../../utils';
|
import { clamp } from '../../utils';
|
||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
@@ -12,6 +12,7 @@ interface ZoomPaneProps {
|
|||||||
selectionKeyPressed: boolean;
|
selectionKeyPressed: boolean;
|
||||||
elementsSelectable?: boolean;
|
elementsSelectable?: boolean;
|
||||||
zoomOnScroll?: boolean;
|
zoomOnScroll?: boolean;
|
||||||
|
zoomOnPinch?: boolean;
|
||||||
panOnScroll?: boolean;
|
panOnScroll?: boolean;
|
||||||
panOnScrollSpeed?: number;
|
panOnScrollSpeed?: number;
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
@@ -43,6 +44,7 @@ const ZoomPane = ({
|
|||||||
onMoveStart,
|
onMoveStart,
|
||||||
onMoveEnd,
|
onMoveEnd,
|
||||||
zoomOnScroll = true,
|
zoomOnScroll = true,
|
||||||
|
zoomOnPinch = true,
|
||||||
panOnScroll = false,
|
panOnScroll = false,
|
||||||
panOnScrollSpeed = 0.5,
|
panOnScrollSpeed = 0.5,
|
||||||
panOnScrollMode = PanOnScrollMode.Free,
|
panOnScrollMode = PanOnScrollMode.Free,
|
||||||
@@ -104,6 +106,17 @@ const ZoomPane = ({
|
|||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
const currentZoom = d3Selection.property('__zoom').k || 1;
|
const currentZoom = d3Selection.property('__zoom').k || 1;
|
||||||
|
|
||||||
|
if (event.ctrlKey && zoomOnPinch) {
|
||||||
|
const point = pointer(event);
|
||||||
|
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
|
||||||
|
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10;
|
||||||
|
const zoom = currentZoom * Math.pow(2, pinchDelta);
|
||||||
|
d3Zoom.scaleTo(d3Selection, zoom, point);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// increase scroll speed in firefox
|
// increase scroll speed in firefox
|
||||||
// firefox: deltaMode === 1; chrome: deltaMode === 0
|
// firefox: deltaMode === 1; chrome: deltaMode === 0
|
||||||
const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
|
const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
|
||||||
@@ -121,7 +134,7 @@ const ZoomPane = ({
|
|||||||
d3Selection.on('wheel', null).on('wheel.zoom', d3ZoomHandler);
|
d3Selection.on('wheel', null).on('wheel.zoom', d3ZoomHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [panOnScroll, panOnScrollMode, d3Selection, d3Zoom, d3ZoomHandler, zoomActivationKeyPressed]);
|
}, [panOnScroll, panOnScrollMode, d3Selection, d3Zoom, d3ZoomHandler, zoomActivationKeyPressed, zoomOnPinch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (d3Zoom) {
|
if (d3Zoom) {
|
||||||
@@ -178,8 +191,10 @@ const ZoomPane = ({
|
|||||||
if (d3Zoom) {
|
if (d3Zoom) {
|
||||||
d3Zoom.filter((event: any) => {
|
d3Zoom.filter((event: any) => {
|
||||||
const zoomScroll = zoomActivationKeyPressed || zoomOnScroll;
|
const zoomScroll = zoomActivationKeyPressed || zoomOnScroll;
|
||||||
|
const pinchZoom = zoomOnPinch && event.ctrlKey;
|
||||||
|
|
||||||
// if all interactions are disabled, we prevent all zoom events
|
// if all interactions are disabled, we prevent all zoom events
|
||||||
if (!paneMoveable && !zoomScroll && !panOnScroll && !zoomOnDoubleClick) {
|
if (!paneMoveable && !zoomScroll && !panOnScroll && !zoomOnDoubleClick && !zoomOnPinch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,8 +225,12 @@ const ZoomPane = ({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!zoomOnPinch && event.ctrlKey && event.type === 'wheel') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// when there is no scroll handling enabled, we prevent all wheel events
|
// when there is no scroll handling enabled, we prevent all wheel events
|
||||||
if (!zoomScroll && !panOnScroll && event.type === 'wheel') {
|
if (!zoomScroll && !panOnScroll && !pinchZoom && event.type === 'wheel') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +246,7 @@ const ZoomPane = ({
|
|||||||
}, [
|
}, [
|
||||||
d3Zoom,
|
d3Zoom,
|
||||||
zoomOnScroll,
|
zoomOnScroll,
|
||||||
|
zoomOnPinch,
|
||||||
panOnScroll,
|
panOnScroll,
|
||||||
zoomOnDoubleClick,
|
zoomOnDoubleClick,
|
||||||
paneMoveable,
|
paneMoveable,
|
||||||
|
|||||||
Reference in New Issue
Block a user