Commit b7a94aa2 authored by tom's avatar tom

chart selection for touch devices

parent 869d3a1c
...@@ -21,7 +21,6 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) => ...@@ -21,7 +21,6 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) =>
const isPressed = React.useRef(false); const isPressed = React.useRef(false);
const startX = React.useRef<number>(); const startX = React.useRef<number>();
const endX = React.useRef<number>(); const endX = React.useRef<number>();
const startIndex = React.useRef<number>(0);
const getIndexByX = React.useCallback((x: number) => { const getIndexByX = React.useCallback((x: number) => {
const xDate = scale.invert(x); const xDate = scale.invert(x);
...@@ -51,20 +50,33 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) => ...@@ -51,20 +50,33 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) =>
.attr('width', Math.abs(diffX)); .attr('width', Math.abs(diffX));
}, []); }, []);
const handelMouseUp = React.useCallback(() => { const handleSelect = React.useCallback((x0: number, x1: number) => {
const index0 = getIndexByX(x0);
const index1 = getIndexByX(x1);
if (Math.abs(index0 - index1) > SELECTION_THRESHOLD) {
onSelect([ Math.min(index0, index1), Math.max(index0, index1) ]);
}
}, [ getIndexByX, onSelect ]);
const cleanUp = React.useCallback(() => {
isPressed.current = false; isPressed.current = false;
startX.current = undefined; startX.current = undefined;
endX.current = undefined;
d3.select(ref.current).attr('opacity', 0); d3.select(ref.current).attr('opacity', 0);
}, [ ]);
if (!endX.current) { const handelMouseUp = React.useCallback(() => {
if (!isPressed.current) {
return; return;
} }
const index = getIndexByX(endX.current); if (startX.current && endX.current) {
if (Math.abs(index - startIndex.current) > SELECTION_THRESHOLD) { handleSelect(startX.current, endX.current);
onSelect([ Math.min(index, startIndex.current), Math.max(index, startIndex.current) ]);
} }
}, [ getIndexByX, onSelect ]);
cleanUp();
}, [ cleanUp, handleSelect ]);
React.useEffect(() => { React.useEffect(() => {
if (!anchorEl) { if (!anchorEl) {
...@@ -78,18 +90,32 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) => ...@@ -78,18 +90,32 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) =>
const [ x ] = d3.pointer(event, anchorEl); const [ x ] = d3.pointer(event, anchorEl);
isPressed.current = true; isPressed.current = true;
startX.current = x; startX.current = x;
const index = getIndexByX(x);
startIndex.current = index;
}) })
.on('mouseup.selectionX', handelMouseUp)
.on('mousemove.selectionX', (event: MouseEvent) => { .on('mousemove.selectionX', (event: MouseEvent) => {
if (isPressed.current) { if (isPressed.current) {
const [ x ] = d3.pointer(event, anchorEl); const [ x ] = d3.pointer(event, anchorEl);
startX.current && drawSelection(startX.current, x); startX.current && drawSelection(startX.current, x);
endX.current = x; endX.current = x;
} }
}); })
.on('mouseup.selectionX', handelMouseUp)
.on('touchstart.selectionX', (event: TouchEvent) => {
const pointers = d3.pointers(event, anchorEl);
isPressed.current = pointers.length === 2;
})
.on('touchmove.selectionX', (event: TouchEvent) => {
if (isPressed.current) {
const pointers = d3.pointers(event, anchorEl);
if (pointers.length === 2 && Math.abs(pointers[0][0] - pointers[1][0]) > 5) {
drawSelection(pointers[0][0], pointers[1][0]);
startX.current = pointers[0][0];
endX.current = pointers[1][0];
}
}
})
.on('touchend.selectionX', handelMouseUp);
d3.select('body').on('mouseup.selectionX', function(event) { d3.select('body').on('mouseup.selectionX', function(event) {
const isOutside = startX.current !== undefined && event.target !== anchorD3.node(); const isOutside = startX.current !== undefined && event.target !== anchorD3.node();
...@@ -99,10 +125,10 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) => ...@@ -99,10 +125,10 @@ const ChartSelectionX = ({ anchorEl, height, scale, data, onSelect }: Props) =>
}); });
return () => { return () => {
anchorD3.on('mousedown.selectionX mouseup.selectionX mousemove.selectionX', null); anchorD3.on('.selectionX', null);
d3.select('body').on('mouseup.selectionX', null); d3.select('body').on('.selectionX', null);
}; };
}, [ anchorEl, drawSelection, getIndexByX, handelMouseUp ]); }, [ anchorEl, cleanUp, drawSelection, getIndexByX, handelMouseUp, handleSelect ]);
return ( return (
<g className="ChartSelectionX" ref={ ref } opacity={ 0 }> <g className="ChartSelectionX" ref={ ref } opacity={ 0 }>
......
...@@ -26,16 +26,28 @@ export function trackPointer(event: PointerEvent, { start, move, out, end }: Poi ...@@ -26,16 +26,28 @@ export function trackPointer(event: PointerEvent, { start, move, out, end }: Poi
tracker.point = d3.pointer(event, target); tracker.point = d3.pointer(event, target);
target.setPointerCapture(id); target.setPointerCapture(id);
const untrack = (sourceEvent: PointerEvent) => {
tracker.sourceEvent = sourceEvent;
d3.select(target).on(`.${ id }`, null);
target.releasePointerCapture(id);
end?.(tracker);
};
d3.select(target) d3.select(target)
.on(`touchstart.${ id }`, (sourceEvent: PointerEvent) => {
const target = sourceEvent.target as Element;
const touches = d3.pointers(sourceEvent, target);
if (touches.length > 1) {
untrack(sourceEvent);
}
})
.on(`pointerup.${ id } pointercancel.${ id } lostpointercapture.${ id }`, (sourceEvent: PointerEvent) => { .on(`pointerup.${ id } pointercancel.${ id } lostpointercapture.${ id }`, (sourceEvent: PointerEvent) => {
if (sourceEvent.pointerId !== id) { if (sourceEvent.pointerId !== id) {
return; return;
} }
tracker.sourceEvent = sourceEvent; untrack(sourceEvent);
d3.select(target).on(`.${ id }`, null);
target.releasePointerCapture(id);
end?.(tracker);
}) })
.on(`pointermove.${ id }`, (sourceEvent) => { .on(`pointermove.${ id }`, (sourceEvent) => {
if (sourceEvent.pointerId !== id) { if (sourceEvent.pointerId !== id) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment