UNPKG

@shapeshop/react

Version:

A TS hook and component to capture user mouse/stylus inputs to generate svg shapes and paths

52 lines (46 loc) 5.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var react = require('react'); var e;exports.ShapeType = void 0;exports.CanvasState = void 0;!function(e){e.Create="CREATE",e.Set="SET";}(e||(e={}));class n{constructor(){this.db={},this.listeners=[];}set(t,s){const n=this.db[t];this.db=Object.assign(Object.assign({},this.db),{[t]:s}),Object.freeze(this.db),this._onChange(void 0===n?e.Create:e.Set,t,s,n);}get(e){return this.db[e]}listen(e){this.listeners.push(e);}_onChange(e,t,s,n){this.listeners.forEach((i=>{i({action:e,prop:t,val:s,previousVal:n});}));}}!function(e){e.Rect="RECT",e.Circle="CIRCLE",e.Line="LINE",e.Path="PATH",e._ellipse="ELLIPSE",e._polyline="POLYLINE",e._polygon="POLYGON";}(exports.ShapeType||(exports.ShapeType={})),function(e){e.Shapes="shapes",e.ShapeType="shapeType",e.IsDrawing="isDrawing";}(exports.CanvasState||(exports.CanvasState={}));class i{constructor(e){this._shapes=()=>this.store.get(exports.CanvasState.Shapes),this._setShapes=e=>this.store.set(exports.CanvasState.Shapes,e),this._isDrawing=()=>this.store.get(exports.CanvasState.IsDrawing),this._setDrawing=e=>this.store.set(exports.CanvasState.IsDrawing,e),this._shapeType=()=>this.store.get(exports.CanvasState.ShapeType),this._setShapeType=e=>this.store.set(exports.CanvasState.ShapeType,e),this.handleMouseDown=e=>{if(0===e.button)try{const t={points:[h(e,this.el)],type:this._shapeType()};this._setDrawing(!0),this._setShapes([...this._shapes(),t]);}catch(e){if(e instanceof Error&&"REF_IS_NULL"===e.message)return void console.warn("ref is null")}},this.handleMouseMove=e=>{if(this._isDrawing())try{const s=h(e,this.el),n=this._shapes(),i=n.length-1,o=Object.assign({},n[i]),a=this._shapeType();a===exports.ShapeType.Path&&(o.points=[...o.points,s]),a!==exports.ShapeType.Rect&&a!==exports.ShapeType.Line||(o.points=[o.points[0],s]);const r=[...n];r[i]=o,this._setShapes(r);}catch(e){if(e instanceof Error&&"REF_IS_NULL"===e.message)return void console.warn("ref is null")}},this.handleMouseUp=e=>{0===e.button&&this._setDrawing(!1);},this.setShapeType=e=>{this._setShapeType(e);},this.storeListener=({action:e,prop:t,val:s,previousVal:n})=>{var i;this.onCanvasUpdate&&(null===(i=this.onCanvasUpdate)||void 0===i||i.call(this,{action:e,prop:t,val:s,previousVal:n}));},this.destroy=()=>{console.log("Destroying"),this.el.removeEventListener("mousedown",this.handleMouseDown),this.el.removeEventListener("mousemove",this.handleMouseMove),document.removeEventListener("mouseup",this.handleMouseUp);},console.log("ShapeShop Engine is on");const{el:i,defaultShape:o}=e;this.el=i,this.el.addEventListener("mousedown",this.handleMouseDown),this.el.addEventListener("mousemove",this.handleMouseMove),document.addEventListener("mouseup",this.handleMouseUp),this.store=new n,this.store.listen(this.storeListener),this._setDrawing(!1),this._setShapes([]),this._setShapeType(o),this.onCanvasUpdate=e.onCanvasUpdate;}}function h(e,t){const s=t.getBoundingClientRect();return [e.clientX-s.left,e.clientY-s.top]}const o=(e,t)=>`${e.reduce(((e,s,n,i)=>0===n?`M ${s[0]},${s[1]}`:`${e} ${t(s,n,i)}`),"")}`;var a,r;const p=(e=>(t,s,n)=>{const[i,h]=e(n[s-1],n[s-2],t),[o,a]=e(t,n[s-1],n[s+1],!0);return `C ${i},${h} ${o},${a} ${t[0]},${t[1]}`})((a=(e,t)=>{const s=t[0]-e[0],n=t[1]-e[1];return {length:Math.sqrt(Math.pow(s,2)+Math.pow(n,2)),angle:Math.atan2(n,s)}},r=.2,(e,t,s,n)=>{const i=a(t||e,s||e),h=i.angle+(n?Math.PI:0),o=i.length*r;return [e[0]+Math.cos(h)*o,e[1]+Math.sin(h)*o]})),l=e=>o(e,p),c=e=>{const t=e[0][0],s=e[0][1],n=e[1][0]-t;let i=e[1][1]-s,h=n,o=s,a=t;return i<0&&(i=Math.abs(i),o=s-i),h<0&&(h=Math.abs(h),a=t-h),{x:a,y:o,width:h,height:i}},u=e=>({x1:e[0][0],y1:e[0][1],x2:e[1][0],y2:e[1][1]}); function useShapeShop(ref, shape, onCanvasUpdate) { const shapeshopRef = react.useRef(); react.useEffect(() => { return () => shapeshopRef.current.destroy(); }, []); react.useEffect(() => { if (!!shape && !!shapeshopRef.current) { shapeshopRef.current.setShapeType(shape); } }, [shape]); const _onCanvasUpdate = react.useCallback((update) => { if (onCanvasUpdate !== undefined) { onCanvasUpdate(update); } }, [onCanvasUpdate]); react.useEffect(() => { const element = ref.current; if (isHtmlElment(element)) { shapeshopRef.current = new i({ el: castToHtmlElement(ref.current), defaultShape: shape, onCanvasUpdate: _onCanvasUpdate }); } }, [ref, _onCanvasUpdate]); } function castToHtmlElement(obj) { if (isHtmlElment(obj)) { return obj; } throw new Error("NOT_HTML_ELEMENT"); } function isHtmlElment(obj) { return (obj === null || obj === void 0 ? void 0 : obj.onmousedown) !== undefined && (obj === null || obj === void 0 ? void 0 : obj.onmouseup) !== undefined && (obj === null || obj === void 0 ? void 0 : obj.onmousemove) !== undefined; } exports.Engine = i; exports.ShapeShop = i; exports.bezierCommandCalc = p; exports.generateLineData = u; exports.generatePathData = l; exports.generateRectData = c; exports.svgPath = o; exports.useShapeShop = useShapeShop; //# sourceMappingURL=index.js.map