Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x | import React, { useEffect, useRef, useId, forwardRef, useImperativeHandle } from 'react';
import { getBoundingClientRect, getClinetXY, useEvent } from '../utils';
import { SignatureCanvasRef, SignatureProps } from '.';
import { useDispatch } from '../store';
import { useOptionDispatch } from '../options';
export const defaultStyle: React.CSSProperties = {
'--w-signature-background': '#fff',
touchAction: 'none',
position: 'relative',
backgroundColor: 'var(--w-signature-background)',
} as React.CSSProperties;
export const Signature = forwardRef<SignatureCanvasRef, SignatureProps>((props, ref) => {
const {
className,
prefixCls = 'w-signature',
style,
readonly = false,
onPointer,
options,
children,
...others
} = props;
const cls = [className, prefixCls].filter(Boolean).join(' ');
const $canvas = useRef<HTMLCanvasElement>(null);
const $path = useRef<SVGPathElement>();
const pointsRef = useRef<number[][]>();
const pointCount = useRef<number>(0);
const pointId = useId();
const dispatch = useDispatch();
const dispatchOption = useOptionDispatch();
useImperativeHandle<SignatureCanvasRef, SignatureCanvasRef>(
ref,
() => ({
canvas: $canvas.current,
dispatch,
clear: () => {
dispatch({});
const ctx = $canvas.current?.getContext('2d');
ctx?.clearRect(0, 0, $canvas.current?.width || 0, $canvas.current?.height || 0);
},
}),
[$canvas.current, dispatch],
);
const handlePointerDown = useEvent((e: React.PointerEvent<HTMLCanvasElement>) => {
if (readonly) return;
pointCount.current += 1;
const { offsetY, offsetX } = getBoundingClientRect($canvas.current);
const clientX = e.clientX || e.nativeEvent.clientX;
const clientY = e.clientY || e.nativeEvent.clientY;
pointsRef.current = [[clientX - offsetX, clientY - offsetY]];
const pathElm = document.createElementNS('http://www.w3.org/2000/svg', 'path');
$path.current = pathElm;
$canvas.current!.appendChild(pathElm);
dispatch({
[pointId + pointCount.current]: pointsRef.current,
});
});
const handlePointerMove = useEvent((e: PointerEvent) => {
if ($path.current) {
const { offsetY, offsetX } = getBoundingClientRect($canvas.current);
const { clientX, clientY } = getClinetXY(e);
pointsRef.current = [...pointsRef.current!, [clientX - offsetX, clientY - offsetY]];
dispatch({
[pointId + pointCount.current]: pointsRef.current,
});
}
});
const handlePointerUp = useEvent(() => {
let result = pointsRef.current || [];
onPointer && props.onPointer!(result);
$path.current = undefined;
pointsRef.current = undefined;
});
useEffect(() => {
Eif ($canvas.current) {
dispatchOption({ container: $canvas.current });
}
Iif (readonly) return;
document.addEventListener('pointermove', handlePointerMove);
document.addEventListener('pointerup', handlePointerUp);
return () => {
Iif (readonly) return;
document.removeEventListener('pointermove', handlePointerMove);
document.removeEventListener('pointerup', handlePointerUp);
};
}, []);
return (
<canvas
{...others}
ref={$canvas}
className={cls}
onPointerDown={handlePointerDown}
style={{ ...defaultStyle, ...style }}
>
{children}
</canvas>
);
});
|