UNPKG

@magnetman103/react-native-sketch-canvas

Version:

A fork of react native sketch canvas from sourcetoad for modification.

280 lines (262 loc) 9.15 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeGestureHandler = require("react-native-gesture-handler"); var _DrawCanvas = _interopRequireDefault(require("./DrawCanvas.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const SketchContainer = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => { const { strokeColor, strokeWidth, style, user, onStrokeStart, onStrokeChanged, onStrokeEnd, onPathsChange, onSketchSaved, onGenerateBase64, onCanvasReady, touchEnabled, scrollY, eraserOn } = props; // Use refs instead of state for path data (similar to original implementation) const pathsRef = (0, _react.useRef)([]); const pathsToProcessRef = (0, _react.useRef)([]); const currentPathRef = (0, _react.useRef)(null); // We'll use a single state for size and to trigger redraws when needed const [size, setSize] = (0, _react.useState)({ width: 0, height: 0 }); const [, setForceUpdate] = (0, _react.useState)(0); // For forcing re-renders when needed // Reference to the DrawCanvas component const canvasRef = (0, _react.useRef)(null); // Force component to update when paths change const triggerUpdate = () => { setForceUpdate(prev => prev + 1); }; const lastYAmount = (0, _react.useRef)(0); // Create the pan gesture const panGesture = _reactNativeGestureHandler.Gesture.Pan().onStart(event => { if (!event.stylusData && !touchEnabled || eraserOn) { return; } const newPath = { id: parseInt(String(Math.random() * 100000000), 10), color: strokeColor, width: strokeWidth, data: [] }; const x = parseFloat(event.x.toFixed(2)); const y = parseFloat(event.y.toFixed(2)); newPath.data.push(`${x},${y}`); currentPathRef.current = newPath; // Start path in the DrawCanvas if (canvasRef.current) { canvasRef.current.newPath(newPath.id, newPath.color, newPath.width); canvasRef.current.addPoint(x, y); } onStrokeStart?.(x, y); triggerUpdate(); // Force update to render current path }).onUpdate(event => { const x = parseFloat(event.x.toFixed(2)); const y = parseFloat(event.y.toFixed(2)); if (eraserOn && (event.stylusData || touchEnabled)) { // only fire if stylus is used and eraser is on onStrokeChanged?.(x, y); return; } // handle case when touch is enabled and eraser is on? (future) if (!event.stylusData && !touchEnabled || !currentPathRef.current) { if (scrollY) { // If scrollY is provided, call it with the current scroll position scrollY(lastYAmount.current - event.translationY); lastYAmount.current = event.translationY; } return; } // Add point to current path if (currentPathRef.current) { currentPathRef.current.data.push(`${x},${y}`); // Add point directly to the canvas if (canvasRef.current) { canvasRef.current.addPoint(x, y); } } onStrokeChanged?.(x, y); }).onEnd(event => { if (eraserOn && (event.stylusData || touchEnabled)) { onStrokeEnd?.({ path: { id: -1, color: strokeColor, width: strokeWidth, data: [] }, size: { width: 0, height: 0 }, drawer: null }); return; } if (!event.stylusData && !touchEnabled || !currentPathRef.current) { if (scrollY) { scrollY(0, event.velocityY); lastYAmount.current = 0; } return; } if (currentPathRef.current) { // Create path for internal tracking const newPath = { path: currentPathRef.current, size, drawer: user }; // Add to paths array pathsRef.current = [...pathsRef.current, newPath]; // Create properly typed object for the callback const strokeEndData = { path: currentPathRef.current, size, drawer: user || null }; // End the path in the canvas if (canvasRef.current) { canvasRef.current.endPath(); } onStrokeEnd?.(strokeEndData); } currentPathRef.current = null; triggerUpdate(); // Force update after completing the path }).minDistance(1).runOnJS(true); // Methods that can be called from outside const clear = () => { pathsRef.current = []; pathsToProcessRef.current = []; currentPathRef.current = null; if (canvasRef.current) { canvasRef.current.clear(); } triggerUpdate(); }; const undo = () => { let lastId = -1; pathsRef.current.forEach(d => lastId = d.drawer === user ? d.path.id : lastId); if (lastId >= 0) { pathsRef.current = pathsRef.current.filter(p => p.path.id !== lastId); if (canvasRef.current) { canvasRef.current.deletePath(lastId); } triggerUpdate(); } return lastId; }; const addPath = data => { // Check if path already exists if (pathsRef.current.filter(p => p.path.id === data.path.id).length === 0) { // Add to paths array pathsRef.current = [...pathsRef.current, data]; // Add to processing queue pathsToProcessRef.current = [...pathsToProcessRef.current, data]; // Process the path directly if (canvasRef.current && size.width > 0 && size.height > 0) { canvasRef.current.addPath(data); } triggerUpdate(); } }; const deletePath = id => { pathsRef.current = pathsRef.current.filter(p => p.path.id !== id); pathsToProcessRef.current = pathsToProcessRef.current.filter(p => p.path.id !== id); if (canvasRef.current) { canvasRef.current.deletePath(id); } triggerUpdate(); }; const save = (imageType, transparent, folder, filename, includeImage, includeText, cropToImageSize) => { if (canvasRef.current) { canvasRef.current.save(imageType, transparent, folder, filename, includeImage, includeText, cropToImageSize); } }; const getBase64 = (imageType, transparent, includeImage, includeText, cropToImageSize) => { if (canvasRef.current) { canvasRef.current.getBase64(imageType, transparent, includeImage, includeText, cropToImageSize); } }; const getPaths = () => { return pathsRef.current; }; // Process any paths that need processing after layout (0, _react.useEffect)(() => { if (size.width > 0 && size.height > 0 && pathsToProcessRef.current.length > 0 && canvasRef.current) { pathsToProcessRef.current.forEach(path => { canvasRef.current?.addPath(path); }); // Clear the processing queue pathsToProcessRef.current = []; } }, [size]); // Expose methods to parent components (0, _react.useImperativeHandle)(ref, () => ({ clear, undo, addPath, deletePath, getPaths, save, getBase64 })); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureHandlerRootView, { style: styles.container, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, { gesture: panGesture, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: [styles.container, style], onLayout: e => { setSize({ width: e.nativeEvent.layout.width, height: e.nativeEvent.layout.height }); }, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_DrawCanvas.default, { ref: canvasRef, style: styles.canvas, strokeColor: strokeColor, strokeWidth: strokeWidth, paths: pathsRef.current, pathsToProcess: pathsToProcessRef.current, currentPath: currentPathRef.current, onPathsChange: onPathsChange, onStrokeStart: onStrokeStart, onStrokeChanged: onStrokeChanged, onStrokeEnd: onStrokeEnd, onSketchSaved: onSketchSaved, onGenerateBase64: onGenerateBase64, onCanvasReady: onCanvasReady, user: user }) }) }) }); }); const styles = _reactNative.StyleSheet.create({ container: { flex: 1 }, canvas: { flex: 1 } }); var _default = exports.default = SketchContainer; //# sourceMappingURL=SketchContainer.js.map