@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
JavaScript
'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