|
1 | | -import React from 'react'; |
2 | | -import './styles/index.less'; |
| 1 | +import React, { useEffect, useRef } from 'react'; |
| 2 | +import { getStroke, type StrokeOptions } from 'perfect-freehand'; |
| 3 | +import { getSvgPathFromStroke, getBoundingClientRect, getClinetXY, defaultOptions, defaultStyle } from './utils'; |
3 | 4 |
|
4 | | -export interface MonorepoTemplateProps extends React.AllHTMLAttributes<HTMLDivElement> { |
| 5 | +export interface SignatureProps extends React.SVGProps<SVGSVGElement> { |
5 | 6 | prefixCls?: string; |
| 7 | + options?: StrokeOptions; |
6 | 8 | } |
7 | 9 |
|
8 | | -export default function MonorepoTemplate(props: MonorepoTemplateProps = {}) { |
9 | | - const { className, prefixCls = 'w-template', children, ...others } = props; |
| 10 | +let points: number[][] = []; |
| 11 | +export default function Signature(props: SignatureProps = {}) { |
| 12 | + const { className, prefixCls = 'w-signature', style, options, ...others } = props; |
10 | 13 | const cls = [className, prefixCls].filter(Boolean).join(' '); |
| 14 | + const $svg = useRef<SVGSVGElement>(null); |
| 15 | + const $path = useRef<SVGPathElement>(); |
| 16 | + |
| 17 | + const handleMouseDown = (e: React.MouseEvent<SVGSVGElement, MouseEvent>) => { |
| 18 | + const { offsetY, offsetX } = getBoundingClientRect($svg.current); |
| 19 | + const clientX = e.clientX || e.nativeEvent.clientX; |
| 20 | + const clientY = e.clientY || e.nativeEvent.clientY; |
| 21 | + points = [[clientX - offsetX, clientY - offsetY]]; |
| 22 | + const pathElm = document.createElementNS('http://www.w3.org/2000/svg', 'path'); |
| 23 | + $path.current = pathElm; |
| 24 | + $svg.current!.appendChild(pathElm); |
| 25 | + }; |
| 26 | + |
| 27 | + const handleMouseMove = (e: MouseEvent | TouchEvent) => { |
| 28 | + if ($path.current) { |
| 29 | + const { offsetY, offsetX } = getBoundingClientRect($svg.current); |
| 30 | + const { clientX, clientY } = getClinetXY(e); |
| 31 | + points = [...points, [clientX - offsetX, clientY - offsetY]]; |
| 32 | + const stroke = getStroke(points, { ...defaultOptions, ...options }); |
| 33 | + const pathData = getSvgPathFromStroke(stroke); |
| 34 | + $path.current?.setAttribute('d', pathData); |
| 35 | + } |
| 36 | + }; |
| 37 | + |
| 38 | + const handleMouseUp = () => { |
| 39 | + points = []; |
| 40 | + $path.current = undefined; |
| 41 | + }; |
| 42 | + |
| 43 | + useEffect(() => { |
| 44 | + document.addEventListener('mousemove', handleMouseMove); |
| 45 | + document.addEventListener('mouseup', handleMouseUp); |
| 46 | + document.addEventListener('touchmove', handleMouseMove); |
| 47 | + document.addEventListener('touchend', handleMouseUp); |
| 48 | + return () => { |
| 49 | + document.removeEventListener('mousemove', handleMouseMove); |
| 50 | + document.removeEventListener('mouseup', handleMouseUp); |
| 51 | + document.removeEventListener('touchmove', handleMouseMove); |
| 52 | + document.removeEventListener('touchend', handleMouseUp); |
| 53 | + }; |
| 54 | + }, []); |
| 55 | + |
11 | 56 | return ( |
12 | | - <div {...others} className={cls}> |
13 | | - {children && |
14 | | - React.Children.map(children, (child) => { |
15 | | - if (React.isValidElement(child)) return child; |
16 | | - return <span> {child} </span>; |
17 | | - })} |
18 | | - </div> |
| 57 | + <svg |
| 58 | + {...others} |
| 59 | + ref={$svg} |
| 60 | + className={cls} |
| 61 | + onPointerDown={handleMouseDown} |
| 62 | + // onPointerMove={handlePointerMove} |
| 63 | + style={{ ...defaultStyle, ...style }} |
| 64 | + /> |
19 | 65 | ); |
20 | 66 | } |
0 commit comments