diff --git a/README.md b/README.md index f303ac8b..fc9baf64 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Get the latest `pts.js` or `pts.min.js` (in [dist](https://github.com/williamnga ```html ``` -Pts is pretty lightweight. Currently at ~90kb minified and 26kb gzipped. +Pts is pretty lightweight. Currently at ~100kb minified and 30kb gzipped. **Option 2:** @@ -62,12 +62,6 @@ If you prefer to generate default typedocs, run this: typedoc --readme none --out typedocs src --name Pts ``` -#### Generate typescript declaration files and minify -```bash -npm run typings -npm run minify -``` - --- ### Contributing diff --git a/dist/index.js b/dist/index.js index d5b87b92..c9a92a19 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3939,10 +3939,7 @@ var CanvasForm = class extends VisualForm { vals.push([t, v]); } return (area1, area2) => { - area1 = area1.map((a) => a.abs()); - if (area2) - area2.map((a) => a.abs()); - let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], area1[1][0], area2[0][0], area2[0][1], area2[1][0]) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); + let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], Math.abs(area1[1][0]), area2[0][0], area2[0][1], Math.abs(area2[1][0])) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); for (let i = 0, len = vals.length; i < len; i++) { grad.addColorStop(vals[i][0], vals[i][1]); } diff --git a/dist/index.mjs b/dist/index.mjs index 09e5e954..bb4433a2 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -3870,10 +3870,7 @@ var CanvasForm = class extends VisualForm { vals.push([t, v]); } return (area1, area2) => { - area1 = area1.map((a) => a.abs()); - if (area2) - area2.map((a) => a.abs()); - let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], area1[1][0], area2[0][0], area2[0][1], area2[1][0]) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); + let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], Math.abs(area1[1][0]), area2[0][0], area2[0][1], Math.abs(area2[1][0])) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); for (let i = 0, len = vals.length; i < len; i++) { grad.addColorStop(vals[i][0], vals[i][1]); } diff --git a/dist/pts.js b/dist/pts.js index 07527fa6..3f076c96 100644 --- a/dist/pts.js +++ b/dist/pts.js @@ -3956,10 +3956,7 @@ See https://github.com/williamngan/pts for details. */ vals.push([t, v]); } return (area1, area2) => { - area1 = area1.map((a) => a.abs()); - if (area2) - area2.map((a) => a.abs()); - let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], area1[1][0], area2[0][0], area2[0][1], area2[1][0]) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); + let grad = area2 ? this._ctx.createRadialGradient(area1[0][0], area1[0][1], Math.abs(area1[1][0]), area2[0][0], area2[0][1], Math.abs(area2[1][0])) : this._ctx.createLinearGradient(area1[0][0], area1[0][1], area1[1][0], area1[1][1]); for (let i = 0, len = vals.length; i < len; i++) { grad.addColorStop(vals[i][0], vals[i][1]); } diff --git a/dist/pts.min.js b/dist/pts.min.js index dd878bcf..510e3dbd 100644 --- a/dist/pts.min.js +++ b/dist/pts.min.js @@ -1,8 +1,8 @@ /* Copyright © 2017-2022 William Ngan and contributors. Licensed under Apache 2.0 License. See https://github.com/williamngan/pts for details. */ -(()=>{var qt=Object.defineProperty;var z=(x,n)=>{for(var t in n)qt(x,t,{get:n[t],enumerable:!0})};var At={};z(At,{CanvasForm:()=>E,CanvasSpace:()=>ot});var It={};z(It,{MultiTouchSpace:()=>Q,Space:()=>ct});var kt={};z(kt,{Bound:()=>G,Group:()=>c,Pt:()=>a});var xt={};z(xt,{Const:()=>L,Util:()=>m});var wt={};z(wt,{Geom:()=>g,Num:()=>v,Range:()=>Pt,Shaping:()=>Y});var yt={};z(yt,{Circle:()=>O,Curve:()=>D,Line:()=>M,Polygon:()=>C,Rectangle:()=>k,Triangle:()=>R});var _t={};z(_t,{Mat:()=>y,Vec:()=>w});var w=class{static add(n,t){if(typeof t=="number")for(let e=0,r=n.length;eMath.max(s,o.length),0):n[0].length;for(let s=0;sm.warn("Group's length is less than "+n,x),Ht=(x,n="")=>m.warn(`Index ${n} is out of bound in Group`,x),M=class{static fromAngle(n,t,e){let r=new c(new a(n),new a(n));return r[1].toAngle(t,e,!0),r}static slope(n,t){return t[0]-n[0]===0?void 0:(t[1]-n[1])/(t[0]-n[0])}static intercept(n,t){if(t[0]-n[0]!==0){let e=(t[1]-n[1])/(t[0]-n[0]),r=n[1]-e*n[0];return{slope:e,yi:r,xi:e===0?void 0:-r/e}}}static sideOfPt2D(n,t){let e=m.iterToArray(n);return(e[1][0]-e[0][0])*(t[1]-e[0][1])-(t[0]-e[0][0])*(e[1][1]-e[0][1])}static collinear(n,t,e,r=.01){let i=new a(0,0,0).to(n).$subtract(t),s=new a(0,0,0).to(n).$subtract(e);return i.$cross(s).divide(1e3).equals(new a(0,0,0),r)}static magnitude(n){let t=m.iterToArray(n);return t.length>=2?t[1].$subtract(t[0]).magnitude():0}static magnitudeSq(n){let t=m.iterToArray(n);return t.length>=2?t[1].$subtract(t[0]).magnitudeSq():0}static perpendicularFromPt(n,t,e=!1){let r=m.iterToArray(n);if(r[0].equals(r[1]))return;let i=r[0].$subtract(r[1]),s=r[1].$subtract(t),o=s.$subtract(i.$project(s));return e?o:o.$add(t)}static distanceFromPt(n,t){let e=m.iterToArray(n),r=M.perpendicularFromPt(e,t,!0);return r?r.magnitude():e[0].$subtract(t).magnitude()}static intersectRay2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=M.intercept(e[0],e[1]),s=M.intercept(r[0],r[1]),o=e[0],l=r[0];if(i==null){if(s==null)return;let u=-s.slope*(l[0]-o[0])+l[1];return new a(o[0],u)}else if(s==null){let u=-i.slope*(o[0]-l[0])+o[1];return new a(l[0],u)}else if(s.slope!=i.slope){let u=(i.slope*o[0]-s.slope*l[0]+l[1]-o[1])/(i.slope-s.slope),h=i.slope*(u-o[0])+o[1];return new a(u,h)}else return i.yi==s.yi?new a(o[0],o[1]):void 0}static intersectLine2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=M.intersectRay2D(e,r);return i&&g.withinBound(i,e[0],e[1])&&g.withinBound(i,r[0],r[1])?i:void 0}static intersectLineWithRay2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=M.intersectRay2D(e,r);return i&&g.withinBound(i,e[0],e[1])?i:void 0}static intersectPolygon2D(n,t,e=!1){let r=m.iterToArray(n),i=m.iterToArray(t),s=e?M.intersectLineWithRay2D:M.intersectLine2D,o=new c;for(let l=0,u=i.length;l0?o:void 0}static intersectLines2D(n,t,e=!1){let r=new c,i=e?M.intersectLineWithRay2D:M.intersectLine2D;for(let s of n)for(let o of t){let l=i(s,o);l&&r.push(l)}return r}static intersectGridWithRay2D(n,t){let e=m.iterToArray(n),r=M.intercept(new a(e[0]).subtract(t),new a(e[1]).subtract(t)),i=new c;return r&&r.xi&&i.push(new a(t[0]+r.xi,t[1])),r&&r.yi&&i.push(new a(t[0],t[1]+r.yi)),i}static intersectGridWithLine2D(n,t){let e=m.iterToArray(n),r=M.intersectGridWithRay2D(e,t),i=new c;for(let s=0,o=r.length;sMath.abs(t[1]/t[0])?h=o[1]<0?0:2:h=o[0]<0?3:1,M.intersectRay2D(u[h],i)}}static marker(n,t,e="arrow",r=!0){let i=m.iterToArray(n),s=r?0:1,o=r?1:0,l=i[s].$subtract(i[o]);if(l.magnitudeSq()===0)return new c;l.unit();let u=g.perpendicular(l).multiply(t[0]).add(i[o]);return e=="arrow"?(u.add(l.$multiply(t[1])),new c(i[o],u[0],u[1])):new c(u[0],u[1])}static toRect(n){let t=m.iterToArray(n);return new c(t[0].$min(t[1]),t[0].$max(t[1]))}},k=class{static from(n,t,e){return k.fromTopLeft(n,t,e)}static fromTopLeft(n,t,e){let r=typeof t=="number"?[t,e||t]:t;return new c(new a(n),new a(n).add(r))}static fromCenter(n,t,e){let r=typeof t=="number"?[t/2,(e||t)/2]:new a(t).divide(2);return new c(new a(n).subtract(r),new a(n).add(r))}static toCircle(n,t=!0){return O.fromRect(n,t)}static toSquare(n,t=!1){let e=m.iterToArray(n),r=k.size(e),i=t?r.maxValue().value:r.minValue().value;return k.fromCenter(k.center(e),i,i)}static size(n){let t=m.iterToArray(n);return t[0].$max(t[1]).subtract(t[0].$min(t[1]))}static center(n){let t=m.iterToArray(n),e=t[0].$min(t[1]),r=t[0].$max(t[1]);return e.add(r.$subtract(e).divide(2))}static corners(n){let t=m.iterToArray(n),e=t[0].$min(t[1]),r=t[0].$max(t[1]);return new c(e,new a(r.x,e.y),r,new a(e.x,r.y))}static sides(n){let[t,e,r,i]=k.corners(n);return[new c(t,e),new c(e,r),new c(r,i),new c(i,t)]}static boundingBox(n){let t=m.iterToArray(n),e=m.flatten(t,!1),r=a.make(2,Number.MAX_VALUE),i=a.make(2,Number.MIN_VALUE);for(let s=0,o=e.length;s=2)break}return new c(r,i)}static polygon(n){return k.corners(n)}static quadrants(n,t){let e=m.iterToArray(n),r=k.corners(e),i=t!=null?new a(t):k.center(e);return r.map(s=>new c(s,i).boundingBox())}static halves(n,t=.5,e=!1){let r=m.iterToArray(n),i=r[0].$min(r[1]),s=r[0].$max(r[1]),o=e?v.lerp(i[1],s[1],t):v.lerp(i[0],s[0],t);return e?[new c(i,new a(s[0],o)),new c(new a(i[0],o),s)]:[new c(i,new a(o,s[1])),new c(new a(o,i[1]),s)]}static withinBound(n,t){let e=m.iterToArray(n);return g.withinBound(t,e[0],e[1])}static hasIntersectRect2D(n,t,e=!1){let r=m.iterToArray(n),i=m.iterToArray(t);return e&&(r=g.boundingBox(r),i=g.boundingBox(i)),!(r[0][0]>i[1][0]||i[0][0]>r[1][0]||r[0][1]>i[1][1]||i[0][1]>r[1][1])}static intersectRect2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t);return k.hasIntersectRect2D(e,r)?M.intersectLines2D(k.sides(e),k.sides(r)):new c}},O=class{static fromRect(n,t=!1){let e=m.iterToArray(n),r=0,i=r=k.size(e).minValue().value/2;if(t){let s=k.size(e).maxValue().value/2;r=Math.sqrt(i*i+s*s)}else r=i;return new c(k.center(e),new a(r,r))}static fromTriangle(n,t=!1){return t?R.circumcircle(n):R.incircle(n)}static fromCenter(n,t){return new c(new a(n),new a(t,t))}static withinBound(n,t,e=0){let r=m.iterToArray(n),i=r[0].$subtract(t);return i.dot(i)+e0)for(let o=0,l=i.length;ol+u)return new c;if(o0&&s.push(u)}return m.flatten(s)}static toRect(n,t=!1){let e=m.iterToArray(n),r=e[1][0];if(t){let i=Math.sqrt(r*r)/2;return new c(e[0].$subtract(i),e[0].$add(i))}else return new c(e[0].$subtract(r),e[0].$add(r))}static toTriangle(n,t=!0){let e=m.iterToArray(n);if(t){let r=-Math.PI/2,i=Math.PI*2/3,s=new c;for(let o=0;o<3;o++)s.push(e[0].clone().toAngle(r,e[1][0],!0)),r+=i;return s}else return R.fromCenter(e[0],e[1][0])}},R=class{static fromRect(n){let t=m.iterToArray(n),e=t[0].$add(t[1]).divide(2);e.y=t[0][1];let r=t[1].clone();return r.x=t[0][0],new c(e,t[1].clone(),r)}static fromCircle(n){return O.toTriangle(n,!0)}static fromCenter(n,t){return R.fromCircle(O.fromCenter(n,t))}static medial(n){let t=m.iterToArray(n);return t.length<3?X(new c,3):C.midpoints(t,!0)}static oppositeSide(n,t){let e=m.iterToArray(n);return e.length<3?X(new c,3):t===0?c.fromPtArray([e[1],e[2]]):t===1?c.fromPtArray([e[0],e[2]]):c.fromPtArray([e[0],e[1]])}static altitude(n,t){let e=m.iterToArray(n),r=R.oppositeSide(e,t);return r.length>1?new c(e[t],M.perpendicularFromPt(r,e[t])):new c}static orthocenter(n){let t=m.iterToArray(n);if(t.length<3)return X(void 0,3);let e=R.altitude(t,0),r=R.altitude(t,1);return M.intersectRay2D(e,r)}static incenter(n){let t=m.iterToArray(n);if(t.length<3)return X(void 0,3);let e=C.bisector(t,0).add(t[0]),r=C.bisector(t,1).add(t[1]);return M.intersectRay2D(new c(t[0],e),new c(t[1],r))}static incircle(n,t){let e=m.iterToArray(n),r=t||R.incenter(e),i=C.area(e),s=C.perimeter(e,!0),o=2*i/s.total;return O.fromCenter(r,o)}static circumcenter(n){let t=m.iterToArray(n),e=R.medial(t),r=[e[0],g.perpendicular(t[0].$subtract(e[0])).p1.$add(e[0])],i=[e[1],g.perpendicular(t[1].$subtract(e[1])).p1.$add(e[1])];return M.intersectRay2D(r,i)}static circumcircle(n,t){let e=m.iterToArray(n),r=t||R.circumcenter(e),i=e[0].$subtract(r).magnitude();return O.fromCenter(r,i)}},C=class{static centroid(n){return g.centroid(n)}static rectangle(n,t,e){return k.corners(k.fromCenter(n,t,e))}static fromCenter(n,t,e){let r=new c;for(let i=0;i=e.length)throw new Error("index out of the Polygon's range");return new c(e[t],t===e.length-1?e[0]:e[t+1])}static lines(n,t=!0){let e=m.iterToArray(n);if(e.length<2)return X(new c,2);let r=m.split(e,2,1);return t&&r.push(new c(e[e.length-1],e[0])),r.map(i=>i)}static midpoints(n,t=!1,e=.5){return C.lines(n,t).map(s=>g.interpolate(s[0],s[1],e))}static adjacentSides(n,t,e=!1){let r=m.iterToArray(n);if(r.length<2)return X(new c,2);if(t<0||t>=r.length)return Ht(new c,t);let i=[],s=t-1;e&&s<0&&(s=r.length-1),s>=0&&i.push(new c(r[t],r[s]));let o=t+1;return e&&o>r.length-1&&(o=0),o<=r.length-1&&i.push(new c(r[t],r[o])),i}static bisector(n,t){let e=C.adjacentSides(n,t,!0);if(e.length>=2){let r=e[0][1].$subtract(e[0][0]).unit(),i=e[1][1].$subtract(e[1][0]).unit();return r.add(i).divide(2)}else return}static perimeter(n,t=!1){let e=C.lines(n,t),r=0,i=a.make(e.length,0);for(let s=0,o=e.length;si[0]*s[1]-i[1]*s[0],r=0;for(let i=0,s=t.length;iu[0]-h[0]));let r=(u,h,p)=>(h[0]-u[0])*(p[1]-u[1])-(p[0]-u[0])*(h[1]-u[1])>0,i=[],s=e.length-2,o=s+3;i[s]=e[2],i[o]=e[2],r(e[0],e[1],e[2])?(i[s+1]=e[0],i[s+2]=e[1]):(i[s+1]=e[1],i[s+2]=e[0]);for(let u=3,h=e.length;ut[1]!=o[1][1]>t[1]&&t[0]<(o[1][0]-o[0][0])*(t[1]-o[0][1])/(o[1][1]-o[0][1])+o[0][0]&&(r=!r)}return r}static hasIntersectCircle(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i={which:-1,dist:0,normal:null,edge:null,vertex:null},s=r[0],o=r[1][0],l=Number.MAX_SAFE_INTEGER;for(let h=0,p=e.length;h0)return null;Math.abs(_)0)&&(i.edge=d,i.normal=f,l=Math.abs(_),i.which=h)}return i.edge?(s.$subtract(C.centroid(e)).dot(i.normal)<0&&i.normal.multiply(-1),i.dist=l,i.vertex=s,i):null}static hasIntersectPolygon(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i={which:-1,dist:0,normal:new a,edge:new c,vertex:new a},s=Number.MAX_SAFE_INTEGER;for(let f=0,P=e.length+r.length;f0)return null;Math.abs(S)r.length-1)return new c;let i=o=>oi+s.x*t[o],0),r=n.reduce((i,s,o)=>i+s.y*t[o],0);if(n[0].length>2){let i=n.reduce((s,o,l)=>s+o.z*t[l],0);return new a(e,r,i)}return new a(e,r)}static catmullRom(n,t=10){let e=m.iterToArray(n);if(e.length<2)return new c;let r=new c,i=D.getSteps(t),s=D.controlPoints(e,0,!0);for(let l=0;l<=t;l++)r.push(D.catmullRomStep(i[l],s));let o=0;for(;o0){for(let u=0;u<=t;u++)r.push(D.catmullRomStep(i[u],l));o++}}return r}static catmullRomStep(n,t){let e=new c(new a(-.5,1,-.5,0),new a(1.5,-2.5,0,1),new a(-1.5,2,.5,0),new a(.5,-.5,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static cardinal(n,t=10,e=.5){let r=m.iterToArray(n);if(r.length<2)return new c;let i=new c,s=D.getSteps(t),o=D.controlPoints(r,0,!0);for(let u=0;u<=t;u++)i.push(D.cardinalStep(s[u],o,e));let l=0;for(;l0){for(let h=0;h<=t;h++)i.push(D.cardinalStep(s[h],u,e));l++}}return i}static cardinalStep(n,t,e=.5){let r=new c(new a(-1,2,-1,0),new a(-1,1,0,0),new a(1,-2,1,0),new a(1,-1,0,0)),i=y.multiply([n],r,!0)[0].multiply(e),s=2*n[0]-3*n[1]+1,o=-2*n[0]+3*n[1],l=D._calcPt(t,i);return l.x+=s*t[1].x+o*t[2].x,l.y+=s*t[1].y+o*t[2].y,l.length>2&&(l.z+=s*t[1].z+o*t[2].z),l}static bezier(n,t=10){let e=m.iterToArray(n);if(e.length<4)return new c;let r=new c,i=D.getSteps(t),s=0;for(;s0){for(let l=0;l<=t;l++)r.push(D.bezierStep(i[l],o));s+=3}}return r}static bezierStep(n,t){let e=new c(new a(-1,3,-3,1),new a(3,-6,3,0),new a(-3,3,0,0),new a(1,0,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static bspline(n,t=10,e=1){let r=m.iterToArray(n);if(r.length<2)return new c;let i=new c,s=D.getSteps(t),o=0;for(;o0){if(e!==1)for(let u=0;u<=t;u++)i.push(D.bsplineTensionStep(s[u],l,e));else for(let u=0;u<=t;u++)i.push(D.bsplineStep(s[u],l));o++}}return i}static bsplineStep(n,t){let e=new c(new a(-.16666666666666666,.5,-.5,.16666666666666666),new a(.5,-1,0,.6666666666666666),new a(-.5,.5,.5,.16666666666666666),new a(.16666666666666666,0,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static bsplineTensionStep(n,t,e=1){let r=new c(new a(-.16666666666666666,.5,-.5,.16666666666666666),new a(-1.5,2,0,-.3333333333333333),new a(1.5,-2.5,.5,.16666666666666666),new a(.16666666666666666,0,0,0)),i=y.multiply([n],r,!0)[0].multiply(e),s=2*n[0]-3*n[1]+1,o=-2*n[0]+3*n[1],l=D._calcPt(t,i);return l.x+=s*t[1].x+o*t[2].x,l.y+=s*t[1].y+o*t[2].y,l.length>2&&(l.z+=s*t[1].z+o*t[2].z),l}};function Ut(){var x=4022871197,n=function(t){if(t){t=t.toString();for(var e=0;e>>0,r-=x,r*=x,x=r>>>0,r-=x,x+=r*4294967296}return(x>>>0)*23283064365386963e-26}else x=4022871197};return n}function Rt(x){var n=48,t=1,e=n,r=new Array(n),i,s,o=0,l=Ut();for(i=0;i=n&&(e=0);var d=1768863*r[e]+t*23283064365386963e-26;return r[e]=d-(t=d|0)}}}var v=class{static equals(n,t,e=1e-5){return Math.abs(n-t)e?i-=r:i=Math.min(t,e)&&n<=Math.max(t,e)}static randomRange(n,t=0){let e=n>t?n-t:t-n;return n+v.random()*e}static randomPt(n,t){let e=new a(n.length),r=t?w.subtract(t,n):n,i=t?n:new a(n.length).fill(0);for(let s=0,o=e.length;s.5?2-n*2:n*2)}static mapToRange(n,t,e,r,i){if(t==e)throw new Error("[currMin, currMax] must define a range that is not zero");let s=Math.min(r,i),o=Math.max(r,i);return v.normalizeValue(n,t,e)*(o-s)+s}static seed(n){this.generator=Rt(n)}static random(){return this.generator?this.generator.random():Math.random()}},g=class{static boundAngle(n){return v.boundValue(n,0,360)}static boundRadian(n){return v.boundValue(n,0,L.two_pi)}static toRadian(n){return n*L.deg_to_rad}static toDegree(n){return n*L.rad_to_deg}static boundingBox(n){let t,e;for(let r of n)t==null?(t=r.clone(),e=r.clone()):(t=t.$min(r),e=e.$max(r));return new c(t,e)}static centroid(n){return v.average(n)}static anchor(n,t=0,e="to"){let r=e=="to"?"subtract":"add",i=0;for(let s of n)typeof t=="number"?t!==i&&s[r](n[t]):s[r](t),i++}static interpolate(n,t,e=.5){let r=Math.min(n.length,t.length),i=a.make(r);for(let s=0;s{if(s.length<2||o.length<2)throw new Error("Pt dimension cannot be less than 2");let l=s.$subtract(r),u=o.$subtract(r);if(l[0]>=0&&u[0]<0)return 1;if(l[0]<0&&u[0]>=0)return-1;if(l[0]==0&&u[0]==0)return l[1]>=0||u[1]>=0?l[1]>u[1]?1:-1:u[1]>l[1]?1:-1;let h=l.$cross2D(u);return h<0?1:h>0?-1:l[0]*l[0]+l[1]*l[1]>u[0]*u[0]+u[1]*u[1]?1:-1};return t.sort(i)}static scale(n,t,e){let r=m.iterToArray(n[0]!==void 0&&typeof n[0]=="number"?[n]:n),i=typeof t=="number"?a.make(r[0].length,t):t;e||(e=a.make(r[0].length,0));for(let s=0,o=r.length;sn[Math.floor(g.boundAngle(g.toDegree(e)))]}}static sinTable(){let n=new Float64Array(360);for(let e=0;e<360;e++)n[e]=Math.sin(e*Math.PI/180);return{table:n,sin:e=>n[Math.floor(g.boundAngle(g.toDegree(e)))]}}},Y=class{static linear(n,t=1){return t*n}static quadraticIn(n,t=1){return t*n*n}static quadraticOut(n,t=1){return-t*n*(n-2)}static quadraticInOut(n,t=1){let e=n*2;return n<.5?t/2*n*n*4:-t/2*((e-1)*(e-3)-1)}static cubicIn(n,t=1){return t*n*n*n}static cubicOut(n,t=1){let e=n-1;return t*(e*e*e+1)}static cubicInOut(n,t=1){let e=n*2;return n<.5?t/2*e*e*e:t/2*((e-2)*(e-2)*(e-2)+2)}static exponentialIn(n,t=1,e=.25){return t*Math.pow(n,1/e)}static exponentialOut(n,t=1,e=.25){return t*Math.pow(n,e)}static sineIn(n,t=1){return-t*Math.cos(n*L.half_pi)+t}static sineOut(n,t=1){return t*Math.sin(n*L.half_pi)}static sineInOut(n,t=1){return-t/2*(Math.cos(Math.PI*n)-1)}static cosineApprox(n,t=1){let e=n*n,r=e*e,i=r*e;return t*(4*i/9-17*r/9+22*e/9)}static circularIn(n,t=1){return-t*(Math.sqrt(1-n*n)-1)}static circularOut(n,t=1){let e=n-1;return t*Math.sqrt(1-e*e)}static circularInOut(n,t=1){let e=n*2;return n<.5?-t/2*(Math.sqrt(1-e*e)-1):t/2*(Math.sqrt(1-(e-2)*(e-2))+1)}static elasticIn(n,t=1,e=.7){let r=n-1,i=e/L.two_pi*1.5707963267948966;return t*(-Math.pow(2,10*r)*Math.sin((r-i)*L.two_pi/e))}static elasticOut(n,t=1,e=.7){let r=e/L.two_pi*1.5707963267948966;return t*(Math.pow(2,-10*n)*Math.sin((n-r)*L.two_pi/e))+t}static elasticInOut(n,t=1,e=.6){let r=n*2,i=e/L.two_pi*1.5707963267948966;return n<.5?(r-=1,t*(-.5*(Math.pow(2,10*r)*Math.sin((r-i)*L.two_pi/e)))):(r-=1,t*(.5*(Math.pow(2,-10*r)*Math.sin((r-i)*L.two_pi/e)))+t)}static bounceIn(n,t=1){return t-Y.bounceOut(1-n,t)}static bounceOut(n,t=1){return n<1/2.75?t*(7.5625*n*n):n<2/2.75?(n-=1.5/2.75,t*(7.5625*n*n+.75)):n<2.5/2.75?(n-=2.25/2.75,t*(7.5625*n*n+.9375)):(n-=2.625/2.75,t*(7.5625*n*n+.984375))}static bounceInOut(n,t=1){return n<.5?Y.bounceIn(n*2,t)/2:Y.bounceOut(n*2-1,t)/2+t/2}static sigmoid(n,t=1,e=10){let r=e*(n-.5);return t/(1+Math.exp(-r))}static logSigmoid(n,t=1,e=.7){e=Math.max(L.epsilon,Math.min(1-L.epsilon,e)),e=1/(1-e);let r=1/(1+Math.exp((n-.5)*e*-2)),i=1/(1+Math.exp(e)),s=1/(1+Math.exp(-e));return t*(r-i)/(s-i)}static seat(n,t=1,e=.5){return n<.5?t*Math.pow(2*n,1-e)/2:t*(1-Math.pow(2*(1-n),1-e)/2)}static quadraticBezier(n,t=1,e=[.05,.95]){let r=typeof e!="number"?e[0]:e,i=typeof e!="number"?e[1]:.5,s=1-2*r;s===0&&(s=L.epsilon);let o=(Math.sqrt(r*r+s*n)-r)/s;return t*((1-2*i)*(o*o)+2*i*o)}static cubicBezier(n,t=1,e=[.1,.7],r=[.9,.2]){let i=new c(new a(0,0),new a(e),new a(r),new a(1,1));return t*D.bezierStep(new a(n*n*n,n*n,n,1),D.controlPoints(i)).y}static quadraticTarget(n,t=1,e=[.2,.35]){let r=Math.min(1-L.epsilon,Math.max(L.epsilon,e[0])),i=Math.min(1,Math.max(0,e[1])),s=(1-i)/(1-r)-i/r,o=(s*(r*r)-i)/r,l=s*(n*n)-o*n;return t*Math.min(1,Math.max(0,l))}static cliff(n,t=1,e=.5){return n>e?t:0}static step(n,t,e,r,...i){let s=1/t,o=Math.floor(e/s)*s;return n(o,r,...i)}},Pt=class{constructor(n){this._dims=0;this._source=c.fromPtArray(n),this.calc()}get max(){return this._max.clone()}get min(){return this._min.clone()}get magnitude(){return this._mag.clone()}calc(){if(!this._source)return;let n=this._source[0].length;this._dims=n;let t=new a(n),e=new a(n),r=new a(n);for(let i=0;i=i.length||!(r[s]in i));s++)t.push(i[r[s]])}else e&&(t=[].slice.call(n[0]));return t}static warn(n="error",t=void 0){if(K.warnLevel()=="error")throw new Error(n);return K.warnLevel()=="warn"&&console.warn(n),t}static randomInt(n,t=0){return K.warn("Util.randomInt is deprecated. Please use `Num.randomRange`"),Math.floor(v.random()*n)+t}static split(n,t,e,r=!1,i=!0){let s=[],o=[],l=e||t,u=0;if(n.length<=0||l<=0)return[];for(;u=n.length)break;o.push(n[u+h])}u+=l,(!i||i&&o.length===t)&&s.push(o)}return s}static flatten(n,t=!0){let e=t?new c:new Array;return e.concat.apply(e,n)}static combine(n,t,e){let r=[];for(let i=0,s=n.length;i=n&&(i=t+(i-n)),r&&r(i),i}}static forRange(n,t,e=0,r=1){let i=[];for(let s=e,o=t;s=200&&e.status<400?t(e.responseText,!0):t(`Server error (${e.status}) when loading "${n}"`,!1)},e.onerror=function(){t("Unknown network error",!1)},e.send()}static download(n,t="pts_canvas_image",e="png",r=1){let i=e==="jpg"?"jpeg":e;n.element.toBlob(function(s){let o=document.createElement("a"),l=URL.createObjectURL(s);o.href=l,o.download=`${t}.${e}`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(l)},`image/${i}`,r)}static performance(n=10){let t=Date.now(),e=[];return function(){let r=Date.now();return e.push(r-t),e.length>=n&&e.shift(),t=r,Math.floor(e.reduce((i,s)=>i+s,0)/e.length)}}static arrayCheck(n,t=2){return Array.isArray(n)&&n.length{super(...args)};t.length===1&&typeof t[0]=="number"?n(t[0]):n(t.length>0?m.getArgs(t):[0,0])}static make(t,e=0,r=!1){let i=new Float32Array(t);if(e&&i.fill(e),r)for(let s=0,o=i.length;se)return!1;return!0}to(...t){let e=m.getArgs(t);for(let r=0,i=Math.min(this.length,e.length);rt(e,...r)}ops(t){let e=[];for(let r=0,i=t.length;rt(e,...r)}ops(t){let e=[];for(let r=0,i=t.length;re?i[t]-r[t]:r[t]-i[t])}forEachPt(t,...e){if(!this[0][t])return m.warn(`${t} is not a function of Pt`),this;for(let r=0,i=this.length;rt+e.toString()+" ","")+" ]"}},G=class extends c{constructor(...t){super(...t);this._center=new a;this._size=new a;this._topLeft=new a;this._bottomRight=new a;this._inited=!1;this.init()}static fromBoundingRect(t){let e=new G(new a(t.left||0,t.top||0),new a(t.right||0,t.bottom||0));return t.width&&t.height&&(e.size=new a(t.width,t.height)),e}static fromGroup(t){let e=m.iterToArray(t);if(e.length<2)throw new Error("Cannot create a Bound from a group that has less than 2 Pt");return new G(e[0],e[e.length-1])}init(){if(this.p1&&(this._size=this.p1.clone(),this._inited=!0),this.p1&&this.p2){let t=this.p1,e=this.p2;this.topLeft=t.$min(e),this._bottomRight=t.$max(e),this._updateSize(),this._inited=!0}}clone(){return new G(this._topLeft.clone(),this._bottomRight.clone())}_updateSize(){this._size=this._bottomRight.$subtract(this._topLeft).abs(),this._updateCenter()}_updateCenter(){this._center=this._size.$multiply(.5).add(this._topLeft)}_updatePosFromTop(){this._bottomRight=this._topLeft.$add(this._size),this._updateCenter()}_updatePosFromBottom(){this._topLeft=this._bottomRight.$subtract(this._size),this._updateCenter()}_updatePosFromCenter(){let t=this._size.$multiply(.5);this._topLeft=this._center.$subtract(t),this._bottomRight=this._center.$add(t)}get size(){return new a(this._size)}set size(t){this._size=new a(t),this._updatePosFromTop()}get center(){return new a(this._center)}set center(t){this._center=new a(t),this._updatePosFromCenter()}get topLeft(){return new a(this._topLeft)}set topLeft(t){this._topLeft=new a(t),this[0]=this._topLeft,this._updateSize()}get bottomRight(){return new a(this._bottomRight)}set bottomRight(t){this._bottomRight=new a(t),this[1]=this._bottomRight,this._updateSize()}get width(){return this._size.length>0?this._size.x:0}set width(t){this._size.x=t,this._updatePosFromTop()}get height(){return this._size.length>1?this._size.y:0}set height(t){this._size.y=t,this._updatePosFromTop()}get depth(){return this._size.length>2?this._size.z:0}set depth(t){this._size.z=t,this._updatePosFromTop()}get x(){return this.topLeft.x}get y(){return this.topLeft.y}get z(){return this.topLeft.z}get inited(){return this._inited}update(){return this._topLeft=this[0],this._bottomRight=this[1],this._updateSize(),this}};var Lt={};z(Lt,{UI:()=>N,UIButton:()=>ht,UIDragger:()=>vt,UIPointerActions:()=>A,UIShape:()=>Z});var Z={rectangle:"rectangle",circle:"circle",polygon:"polygon",polyline:"polyline",line:"line"},A={up:"up",down:"down",move:"move",drag:"drag",uidrag:"uidrag",drop:"drop",uidrop:"uidrop",over:"over",out:"out",enter:"enter",leave:"leave",click:"click",keydown:"keydown",keyup:"keyup",contextmenu:"contextmenu",all:"all"},J=class{constructor(n,t,e={},r){this._holds=new Map;this._group=c.fromArray(n),this._shape=t,this._id=r===void 0?`ui_${J._counter++}`:r,this._states=e,this._actions={}}static fromRectangle(n,t,e){return new this(n,Z.rectangle,t,e)}static fromCircle(n,t,e){return new this(n,Z.circle,t,e)}static fromPolygon(n,t,e){return new this(n,Z.polygon,t,e)}static fromUI(n,t,e){return new this(n.group,n.shape,t||n._states,e)}get id(){return this._id}set id(n){this._id=n}get group(){return this._group}set group(n){this._group=n}get shape(){return this._shape}set shape(n){this._shape=n}state(n,t){return n?t!==void 0?(this._states[n]=t,this):this._states[n]:null}on(n,t){return this._actions[n]||(this._actions[n]=[]),J._addHandler(this._actions[n],t)}off(n,t){return this._actions[n]?t===void 0?(delete this._actions[n],!0):J._removeHandler(this._actions[n],t):!1}listen(n,t,e){if(this._actions[n]!==void 0){if(this._within(t)||Array.from(this._holds.values()).indexOf(n)>=0)return J._trigger(this._actions[n],this,t,n,e),!0;if(this._actions.all)return J._trigger(this._actions.all,this,t,n,e),!0}return!1}hold(n){let t=Math.max(0,...Array.from(this._holds.keys()))+1;return this._holds.set(t,n),t}unhold(n){n!==void 0?this._holds.delete(n):this._holds.clear()}static track(n,t,e,r){for(let i=0,s=n.length;i=0&&tn.length}else return!1}},N=J;N._counter=0;var ht=class extends N{constructor(t,e,r={},i){super(t,e,r,i);this._hoverID=-1;r.hover===void 0&&(this._states.hover=!1),r.clicks===void 0&&(this._states.clicks=0);let s=A;this.on(s.up,(o,l,u,h)=>{this.state("clicks",this._states.clicks+1)}),this.on(s.move,(o,l,u,h)=>{if(this._within(l)&&!this._states.hover){this.state("hover",!0),N._trigger(this._actions[s.enter],this,l,s.enter,h);var d=this.hold(s.move);this._hoverID=this.on(s.move,(f,P)=>{!this._within(P)&&!this.state("dragging")&&(this.state("hover",!1),N._trigger(this._actions[s.leave],this,l,s.leave,h),this.off(s.move,this._hoverID),this.unhold(d))})}})}onClick(t){return this.on(A.up,t)}offClick(t){return this.off(A.up,t)}onContextMenu(t){return this.on(A.contextmenu,t)}offContextMenu(t){return this.off(A.contextmenu,t)}onHover(t,e){var r=[void 0,void 0];return t&&(r[0]=this.on(A.enter,t)),e&&(r[1]=this.on(A.leave,e)),r}offHover(t,e){var r=[!1,!1];return(t===void 0||t>=0)&&(r[0]=this.off(A.enter,t)),(e===void 0||e>=0)&&(r[1]=this.off(A.leave,e)),r}},vt=class extends ht{constructor(t,e,r={},i){super(t,e,r,i);this._draggingID=-1;this._moveHoldID=-1;this._dropHoldID=-1;this._upHoldID=-1;r.dragging===void 0&&(this._states.dragging=!1),r.moved===void 0&&(this._states.moved=!1),r.offset===void 0&&(this._states.offset=new a);let s=A;this.on(s.down,(l,u,h,p)=>{this._moveHoldID===-1&&(this.state("dragging",!0),this.state("offset",new a(u).subtract(l.group[0])),this._moveHoldID=this.hold(s.move)),this._dropHoldID===-1&&(this._dropHoldID=this.hold(s.drop)),this._upHoldID===-1&&(this._upHoldID=this.hold(s.up)),this._draggingID===-1&&(this._draggingID=this.on(s.move,(d,f)=>{this.state("dragging")&&(N._trigger(this._actions[s.uidrag],d,f,s.uidrag,p),this.state("moved",!0))}))});let o=(l,u,h,p)=>{this.state("dragging",!1),this.off(s.move,this._draggingID),this._draggingID=-1,this.unhold(this._moveHoldID),this._moveHoldID=-1,this.unhold(this._dropHoldID),this._dropHoldID=-1,this.unhold(this._upHoldID),this._upHoldID=-1,this.state("moved")&&(N._trigger(this._actions[s.uidrop],l,u,s.uidrop,p),this.state("moved",!1))};this.on(s.drop,o),this.on(s.up,o),this.on(s.out,o)}onDrag(t){return this.on(A.uidrag,t)}offDrag(t){return this.off(A.uidrag,t)}onDrop(t){return this.on(A.uidrop,t)}offDrop(t){return this.off(A.uidrop,t)}};var ct=class{constructor(){this.id="space";this.bound=new G;this._time={prev:0,diff:0,end:-1,min:0};this.players={};this.playerCount=0;this._animID=-1;this._pause=!1;this._refresh=void 0;this._pointer=new a;this._isReady=!1;this._playing=!1}refresh(n){return this._refresh=n,this}minFrameTime(n=0){this._time.min=n}add(n){let t=typeof n=="function"?{animate:n}:n,e=this.playerCount++,r=this.id+e;return this.players[r]=t,t.animateID=r,t.resize&&this.bound.inited&&t.resize(this.bound),this._refresh===void 0&&(this._refresh=!0),this}remove(n){return delete this.players[n.animateID],this}removeAll(){return this.players={},this}play(n=0){if(!(n===0&&this._animID!==-1)){if(this._animID=requestAnimationFrame(this.play.bind(this)),this._pause)return this;if(this._time.diff=n-this._time.prev,this._time.diff=0&&n>this._time.end&&(cancelAnimationFrame(this._animID),this._animID=-1,this._playing=!1)}pause(n=!1){return this._pause=n?!this._pause:!0,this}resume(){return this._pause=!1,this}stop(n=0){return this._time.end=n,this}playOnce(n=0){return this.play(),this.stop(n),this}render(n){return this._renderFunc&&this._renderFunc(n,this),this}set customRendering(n){this._renderFunc=n}get customRendering(){return this._renderFunc}get isPlaying(){return this._playing}get outerBound(){return this.bound.clone()}get innerBound(){return new G(a.make(this.size.length,0),this.size.clone())}get size(){return this.bound.size.clone()}get center(){return this.size.divide(2)}get width(){return this.bound.width}get height(){return this.bound.height}},Q=class extends ct{constructor(){super(...arguments);this._pressed=!1;this._dragged=!1;this._hasMouse=!1;this._hasTouch=!1;this._hasKeyboard=!1}get pointer(){let t=this._pointer.clone();return t.id=this._pointer.id,t}bindCanvas(t,e,r={},i){(i||this._canvas).addEventListener(t,e,r)}unbindCanvas(t,e,r={},i){(i||this._canvas).removeEventListener(t,e,r)}bindDoc(t,e,r={}){document&&document.addEventListener(t,e,r)}unbindDoc(t,e,r={}){document&&document.removeEventListener(t,e,r)}bindMouse(t=!0,e){return t?(this._mouseDown=this._mouseDown.bind(this),this._mouseUp=this._mouseUp.bind(this),this._mouseOver=this._mouseOver.bind(this),this._mouseOut=this._mouseOut.bind(this),this._mouseMove=this._mouseMove.bind(this),this._mouseClick=this._mouseClick.bind(this),this._contextMenu=this._contextMenu.bind(this),this.bindCanvas("mousedown",this._mouseDown,{},e),this.bindCanvas("mouseup",this._mouseUp,{},e),this.bindCanvas("mouseover",this._mouseOver,{},e),this.bindCanvas("mouseout",this._mouseOut,{},e),this.bindCanvas("mousemove",this._mouseMove,{},e),this.bindCanvas("click",this._mouseClick,{},e),this.bindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!0):(this.unbindCanvas("mousedown",this._mouseDown,{},e),this.unbindCanvas("mouseup",this._mouseUp,{},e),this.unbindCanvas("mouseover",this._mouseOver,{},e),this.unbindCanvas("mouseout",this._mouseOut,{},e),this.unbindCanvas("mousemove",this._mouseMove,{},e),this.unbindCanvas("click",this._mouseClick,{},e),this.unbindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!1),this}bindTouch(t=!0,e=!1,r){return t?(this.bindCanvas("touchstart",this._touchStart.bind(this),{passive:e},r),this.bindCanvas("touchend",this._mouseUp.bind(this),{},r),this.bindCanvas("touchmove",this._touchMove.bind(this),{passive:e},r),this.bindCanvas("touchcancel",this._mouseOut.bind(this),{},r),this._hasTouch=!0):(this.unbindCanvas("touchstart",this._touchStart.bind(this),{passive:e},r),this.unbindCanvas("touchend",this._mouseUp.bind(this),{},r),this.unbindCanvas("touchmove",this._touchMove.bind(this),{passive:e},r),this.unbindCanvas("touchcancel",this._mouseOut.bind(this),{},r),this._hasTouch=!1),this}bindKeyboard(t=!0){return t?(this._keyDownBind=this._keyDown.bind(this),this._keyUpBind=this._keyUp.bind(this),this.bindDoc("keydown",this._keyDownBind,{}),this.bindDoc("keyup",this._keyUpBind,{}),this._hasKeyboard=!0):(this.unbindDoc("keydown",this._keyDownBind,{}),this.unbindDoc("keyup",this._keyUpBind,{}),this._hasKeyboard=!1),this}touchesToPoints(t,e="touches"){if(!t||!t[e])return[];let r=[];for(var i=0;i0,u=e.changedTouches.item(0);r=l?u.pageX-this.outerBound.x:0,i=l?u.pageY-this.outerBound.y:0,o.action&&o.action(t,r,i,e)}t&&(this._pointer.to(r,i),this._pointer.id=t)}_mouseDown(t){return this._mouseAction(A.down,t),this._pressed=!0,!1}_mouseUp(t){return this._dragged?this._mouseAction(A.drop,t):this._mouseAction(A.up,t),this._pressed=!1,this._dragged=!1,!1}_mouseMove(t){return this._mouseAction(A.move,t),this._pressed&&(this._dragged=!0,this._mouseAction(A.drag,t)),!1}_mouseOver(t){return this._mouseAction(A.over,t),!1}_mouseOut(t){return this._mouseAction(A.out,t),this._dragged&&this._mouseAction(A.drop,t),this._dragged=!1,!1}_mouseClick(t){return this._mouseAction(A.click,t),this._pressed=!1,this._dragged=!1,!1}_contextMenu(t){return this._mouseAction(A.contextmenu,t),!1}_touchMove(t){return this._mouseMove(t),t.preventDefault(),!1}_touchStart(t){return this._mouseDown(t),t.preventDefault(),!1}_keyDown(t){return this._keyboardAction(A.keydown,t),!1}_keyUp(t){return this._keyboardAction(A.keyup,t),!1}_keyboardAction(t,e){if(!!this.isPlaying){for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.action&&i.action(t,e.shiftKey?1:0,e.altKey?1:0,e)}}}};var Ct={};z(Ct,{Font:()=>F,Form:()=>mt,VisualForm:()=>j});var mt=class{constructor(){this._ready=!1}get ready(){return this._ready}},j=class extends mt{constructor(){super(...arguments);this._filled=!0;this._stroked=!0;this._font=new F(14,"sans-serif")}get filled(){return this._filled}set filled(t){this._filled=t}get stroked(){return this._stroked}set stroked(t){this._stroked=t}get currentFont(){return this._font}_multiple(t,e,...r){if(!t)return this;for(let i=0,s=t.length;iit});var it=class{static textWidthEstimator(n,t=["M","n","."],e=[.06,.8,.14]){let r=t.map(n),i=new a(e).dot(r);return s=>s.length*i}static truncate(n,t,e,r=""){let i=Math.floor(t.length*Math.min(1,e/n(t)));return i0?Math.max(i,e):i}}};var Dt={};z(Dt,{Img:()=>q});var q=class{constructor(n=!1,t,e){this._scale=1;this._loaded=!1;this._editable=n,this._space=t,this._scale=this._space?this._space.pixelScale:1,this._img=new Image,e&&(this._img.crossOrigin="Anonymous")}static load(n,t=!1,e,r){let i=new q(t,e);return i.load(n).then(s=>{r&&r(s)}),i}static async loadAsync(n,t=!1,e){return await new q(t,e).load(n)}static async loadPattern(n,t,e="repeat",r=!1){return(await q.loadAsync(n,r,t)).pattern(e)}static blank(n,t,e){let r=new q(!0,t),i=e||t.pixelScale;return r.initCanvas(n[0],n[1],i),r}load(n){return new Promise((t,e)=>{this._editable&&!document&&e("Cannot create html canvas element. document not found."),this._img.src=n,this._img.onload=()=>{this._editable&&(this._cv||(this._cv=document.createElement("canvas")),this._drawToScale(this._scale,this._img),this._data=this._ctx.getImageData(0,0,this._cv.width,this._cv.height)),this._loaded=!0,t(this)},this._img.onerror=r=>{e(r)}})}_drawToScale(n,t){let e=t.width,r=t.height;this.initCanvas(e,r,n),t&&this._ctx.drawImage(t,0,0,e,r,0,0,this._cv.width,this._cv.height)}initCanvas(n,t,e=1){if(!this._editable){console.error("Cannot initiate canvas because this Img is not set to be editable");return}this._cv||(this._cv=document.createElement("canvas"));let r=typeof e=="number"?[e,e]:e;this._cv.width=n*r[0],this._cv.height=t*r[1],this._ctx=this._cv.getContext("2d"),this._loaded=!0}bitmap(n){let t=n?n[0]:this._cv.width,e=n?n[1]:this._cv.height;return createImageBitmap(this._cv,0,0,t,e)}pattern(n="repeat",t=!1){if(!this._space)throw"Cannot find CanvasSpace ctx to create image pattern";return this._space.ctx.createPattern(t?this._cv:this._img,n)}sync(){this._scale!==1?this.bitmap().then(n=>{this._drawToScale(1/this._scale,n),this.load(this.toBase64())}):this._img.src=this.toBase64()}pixel(n,t=!0){let e=typeof t=="number"?t:t?this._scale:1;return q.getPixel(this._data,[n[0]*e,n[1]*e])}static getPixel(n,t){let e=new a(0,0,0,0);if(t[0]>=n.width||t[1]>=n.height)return e;let r=Math.floor(t[1])*(n.width*4)+Math.floor(t[0])*4,i=n.data;return r>=i.length-4?e:new a(i[r],i[r+1],i[r+2],i[r+3])}resize(n,t=!1){let e=t?n:[n[0]/this._img.naturalWidth,n[1]/this._img.naturalHeight];return this._drawToScale(e,this._img),this._data=this._ctx.getImageData(0,0,this._cv.width,this._cv.height),this}crop(n){let t=n.topLeft.scale(this._scale),e=n.size.scale(this._scale);return this._ctx.getImageData(t.x,t.y,e.x,e.y)}filter(n){return this._ctx.filter=n,this._ctx.drawImage(this._cv,0,0),this._ctx.filter="none",this}cleanup(){this._cv&&this._cv.remove(),this._img&&this._img.remove(),this._data=null}static fromBlob(n,t=!1,e){let r=URL.createObjectURL(n);return new q(t,e).load(r)}static imageDataToBlob(n){return new Promise(function(t,e){document||e("Cannot create html canvas element. document not found.");let r=document.createElement("canvas");r.width=n.width,r.height=n.height,r.getContext("2d").putImageData(n,0,0),r.toBlob(i=>{t(i),r.remove()})})}toBase64(){return this._cv.toDataURL()}toBlob(){return new Promise(n=>{this._cv.toBlob(t=>n(t))})}getForm(){return this._editable||console.error("Cannot get a CanvasForm because this Img is not editable"),this._ctx?new E(this._ctx):void 0}get current(){return this._editable?this._cv:this._img}get image(){return this._img}get canvas(){return this._cv}get data(){return this._data}get ctx(){return this._ctx}get loaded(){return this._loaded}get pixelScale(){return this._scale}get imageSize(){return!this._img.width||!this._img.height?this.canvasSize.$divide(this._scale):new a(this._img.width,this._img.height)}get canvasSize(){return new a(this._cv.width,this._cv.height)}get scaledMatrix(){let n=1/this._scale;return new y().scale2D([n,n])}};var ot=class extends Q{constructor(t,e){super();this._pixelScale=1;this._autoResize=!0;this._bgcolor="#e1e9f0";this._offscreen=!1;this._initialResize=!1;var r=null,i=!1;if(this.id="pt",t instanceof Element)r=t,this.id="pts_existing_space";else{let s=t;s=t[0]==="#"||t[0]==="."?t:"#"+t,r=document.querySelector(s),i=!0,this.id=s.substr(1)}r?r.nodeName.toLowerCase()!="canvas"?(this._container=r,this._canvas=this._createElement("canvas",this.id+"_canvas"),this._container.appendChild(this._canvas),this._initialResize=!0):(this._canvas=r,this._container=r.parentElement,this._autoResize=!1):(this._container=this._createElement("div",this.id+"_container"),this._canvas=this._createElement("canvas",this.id),this._container.appendChild(this._canvas),document.body.appendChild(this._container),i=!1),setTimeout(this._ready.bind(this,e),100),this._ctx=this._canvas.getContext("2d")}_createElement(t="div",e){let r=document.createElement(t);return r.setAttribute("id",e),r}_ready(t){if(!this._container)throw new Error(`Cannot initiate #${this.id} element`);this._isReady=!0,this._resizeHandler(null),this.clear(this._bgcolor),this._canvas.dispatchEvent(new Event("ready"));for(let e in this.players)this.players.hasOwnProperty(e)&&this.players[e].start&&this.players[e].start(this.bound.clone(),this);this._pointer=this.center,this._initialResize=!1,t&&t(this.bound,this._canvas)}setup(t){if(this._bgcolor=t.bgcolor?t.bgcolor:"transparent",this.autoResize=t.resize!=null?t.resize:!1,t.retina!==!1){let e=window&&window.devicePixelRatio||1,r=this._ctx.webkitBackingStorePixelRatio||this._ctx.mozBackingStorePixelRatio||this._ctx.msBackingStorePixelRatio||this._ctx.oBackingStorePixelRatio||this._ctx.backingStorePixelRatio||1;this._pixelScale=Math.max(1,e/r)}return t.offscreen?(this._offscreen=!0,this._offCanvas=this._createElement("canvas",this.id+"_offscreen"),this._offCtx=this._offCanvas.getContext("2d")):this._offscreen=!1,t.pixelDensity&&(this._pixelScale=t.pixelDensity),this}set autoResize(t){!window||(this._autoResize=t,t?window.addEventListener("resize",this._resizeHandler.bind(this)):window.removeEventListener("resize",this._resizeHandler.bind(this)))}get autoResize(){return this._autoResize}resize(t,e){this.bound=t,this._canvas.width=Math.ceil(this.bound.size.x)*this._pixelScale,this._canvas.height=Math.ceil(this.bound.size.y)*this._pixelScale,this._canvas.style.width=Math.ceil(this.bound.size.x)+"px",this._canvas.style.height=Math.ceil(this.bound.size.y)+"px",this._offscreen&&(this._offCanvas.width=Math.ceil(this.bound.size.x)*this._pixelScale,this._offCanvas.height=Math.ceil(this.bound.size.y)*this._pixelScale),this._pixelScale!=1&&(this._ctx.scale(this._pixelScale,this._pixelScale),this._offscreen&&this._offCtx.scale(this._pixelScale,this._pixelScale));for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.resize&&i.resize(this.bound,e)}return this.render(this._ctx),e&&!this.isPlaying&&this.playOnce(0),this}_resizeHandler(t){if(!window)return;let e=this._autoResize||this._initialResize?this._container.getBoundingClientRect():this._canvas.getBoundingClientRect();if(e){let r=G.fromBoundingRect(e);r.center=r.center.add(window.pageXOffset,window.pageYOffset),this.resize(r,t)}}set background(t){this._bgcolor=t}get background(){return this._bgcolor}get pixelScale(){return this._pixelScale}get hasOffscreen(){return this._offscreen}get offscreenCtx(){return this._offCtx}get offscreenCanvas(){return this._offCanvas}getForm(){return new E(this)}get element(){return this._canvas}get parent(){return this._container}get ready(){return this._isReady}get ctx(){return this._ctx}clear(t){t&&(this._bgcolor=t);let e=this._ctx.fillStyle,r=Math.ceil(this.pixelScale);return!this._bgcolor||this._bgcolor==="transparent"?this._ctx.clearRect(-r,-r,this._canvas.width+r,this._canvas.height+r):((this._bgcolor.indexOf("rgba")===0||this._bgcolor.length===9&&this._bgcolor.indexOf("#")===0)&&this._ctx.clearRect(-r,-r,this._canvas.width+r,this._canvas.height+r),this._ctx.fillStyle=this._bgcolor,this._ctx.fillRect(-r,-r,this._canvas.width+r,this._canvas.height+r)),this._ctx.fillStyle=e,this}clearOffscreen(t){if(this._offscreen){let e=Math.ceil(this.pixelScale);t?(this._offCtx.fillStyle=t,this._offCtx.fillRect(-e,-e,this._canvas.width+e,this._canvas.height+e)):this._offCtx.clearRect(-e,-e,this._offCanvas.width+e,this._offCanvas.height+e)}return this}playItems(t){this._isReady&&(this._ctx.save(),this._offscreen&&this._offCtx.save(),super.playItems(t),this._ctx.restore(),this._offscreen&&this._offCtx.restore(),this.render(this._ctx))}dispose(){if(!!window)return window.removeEventListener("resize",this._resizeHandler.bind(this)),this.stop(),this.removeAll(),this}recorder(t,e="webm",r=15e6){let i=this._canvas.captureStream(),s=new MediaRecorder(i,{mimeType:`video/${e}`,bitsPerSecond:r});return s.ondataavailable=function(o){let l=URL.createObjectURL(new Blob([o.data],{type:`video/${e}`}));if(typeof t=="function")t(l);else if(t){let u=document.createElement("a");u.href=l,u.download=`canvas_video.${e}`,u.click(),u.remove()}},s}},E=class extends j{constructor(t){super();this._style={fillStyle:"#f03",strokeStyle:"#fff",lineWidth:1,lineJoin:"bevel",lineCap:"butt",globalAlpha:1};if(!t)return this;let e=r=>{this._ctx=r,this._ctx.fillStyle=this._style.fillStyle,this._ctx.strokeStyle=this._style.strokeStyle,this._ctx.lineJoin="bevel",this._ctx.font=this._font.value,this._ready=!0};t instanceof CanvasRenderingContext2D?e(t):(this._space=t,this._space.add({start:()=>{e(this._space.ctx)}}))}get space(){return this._space}get ctx(){return this._ctx}useOffscreen(t=!0,e=!1){return e&&this._space.clearOffscreen(typeof e=="string"?e:null),this._ctx=this._space.hasOffscreen&&t?this._space.offscreenCtx:this._space.ctx,this}renderOffscreen(t=[0,0]){this._space.hasOffscreen&&this._space.ctx.drawImage(this._space.offscreenCanvas,t[0],t[1],this._space.width,this._space.height)}alpha(t){return this._ctx.globalAlpha=t,this._style.globalAlpha=t,this}fill(t){return typeof t=="boolean"?this.filled=t:(this.filled=!0,this._style.fillStyle=t,this._ctx.fillStyle=t),this}stroke(t,e,r,i){return typeof t=="boolean"?this.stroked=t:(this.stroked=!0,this._style.strokeStyle=t,this._ctx.strokeStyle=t,e&&(this._ctx.lineWidth=e,this._style.lineWidth=e),r&&(this._ctx.lineJoin=r,this._style.lineJoin=r),i&&(this._ctx.lineCap=i,this._style.lineCap=i)),this}applyFillStroke(t=!0,e=!0,r=1){return t&&(typeof t=="string"&&this.fill(t),this._ctx.fill()),e&&(typeof e=="string"&&this.stroke(e,r),this._ctx.stroke()),this}gradient(t){let e=[];t.length<2&&t.push([.99,"#000"],[1,"#000"]);for(let r=0,i=t.length;r{r=r.map(o=>o.abs()),i&&i.map(o=>o.abs());let s=i?this._ctx.createRadialGradient(r[0][0],r[0][1],r[1][0],i[0][0],i[0][1],i[1][0]):this._ctx.createLinearGradient(r[0][0],r[0][1],r[1][0],r[1][1]);for(let o=0,l=e.length;othis._ctx.measureText(e).width):void 0,this}getTextWidth(t){return this._estimateTextWidth?this._estimateTextWidth(t):this._ctx.measureText(t+" .").width}_textTruncate(t,e,r=""){return it.truncate(this.getTextWidth.bind(this),t,e,r)}_textAlign(t,e,r,i){let s=m.iterToArray(t);if(!!m.arrayCheck(s)){i||(i=k.center(s));var o=s[0][0];this._ctx.textAlign=="end"||this._ctx.textAlign=="right"?o=s[1][0]:(this._ctx.textAlign=="center"||this._ctx.textAlign=="middle")&&(o=i[0]);var l=i[1];return e=="top"||e=="start"?l=s[0][1]:(e=="end"||e=="bottom")&&(l=s[1][1]),r?new a(o+r[0],l+r[1]):new a(o,l)}}reset(){for(let t in this._style)this._style.hasOwnProperty(t)&&(this._ctx[t]=this._style[t]);return this._font=new F,this._ctx.font=this._font.value,this}_paint(){this._filled&&this._ctx.fill(),this._stroked&&this._ctx.stroke()}static point(t,e,r=5,i="square"){if(!!e){if(!E[i])throw new Error(`${i} is not a static function of CanvasForm`);E[i](t,e,r)}}point(t,e=5,r="square"){return E.point(this._ctx,t,e,r),this._paint(),this}static circle(t,e,r=10){!e||(t.beginPath(),t.arc(e[0],e[1],r,0,L.two_pi,!1),t.closePath())}circle(t){let e=m.iterToArray(t);return E.circle(this._ctx,e[0],e[1][0]),this._paint(),this}static ellipse(t,e,r,i=0,s=0,o=L.two_pi,l=!1){!e||!r||(t.beginPath(),t.ellipse(e[0],e[1],r[0],r[1],i,s,o,l))}ellipse(t,e,r=0,i=0,s=L.two_pi,o=!1){return E.ellipse(this._ctx,t,e,r,i,s,o),this._paint(),this}static arc(t,e,r,i,s,o){!e||(t.beginPath(),t.arc(e[0],e[1],r,i,s,o))}arc(t,e,r,i,s){return E.arc(this._ctx,t,e,r,i,s),this._paint(),this}static square(t,e,r){if(!e)return;let i=e[0]-r,s=e[1]-r,o=e[0]+r,l=e[1]+r;t.beginPath(),t.moveTo(i,s),t.lineTo(i,l),t.lineTo(o,l),t.lineTo(o,s),t.closePath()}square(t,e){return E.square(this._ctx,t,e),this._paint(),this}static line(t,e){if(!m.arrayCheck(e))return;let r=0;t.beginPath();for(let i of e)i&&(r++>0?t.lineTo(i[0],i[1]):t.moveTo(i[0],i[1]))}line(t){return E.line(this._ctx,t),this._paint(),this}static polygon(t,e){!m.arrayCheck(e)||(E.line(t,e),t.closePath())}polygon(t){return E.polygon(this._ctx,t),this._paint(),this}static rect(t,e){let r=m.iterToArray(e);!m.arrayCheck(r)||(t.beginPath(),t.moveTo(r[0][0],r[0][1]),t.lineTo(r[0][0],r[1][1]),t.lineTo(r[1][0],r[1][1]),t.lineTo(r[1][0],r[0][1]),t.closePath())}rect(t){return E.rect(this._ctx,t),this._paint(),this}static image(t,e,r,i){let s=m.iterToArray(e),o;if(typeof s[0]=="number")o=s;else if(i){let l=m.iterToArray(i);o=[l[0][0],l[0][1],l[1][0]-l[0][0],l[1][1]-l[0][1],s[0][0],s[0][1],s[1][0]-s[0][0],s[1][1]-s[0][1]]}else o=[s[0][0],s[0][1],s[1][0]-s[0][0],s[1][1]-s[0][1]];r instanceof q?r.loaded&&t.drawImage(r.image,...o):t.drawImage(r,...o)}image(t,e,r){return e instanceof q?e.loaded&&E.image(this._ctx,t,e.image,r):E.image(this._ctx,t,e,r),this}static imageData(t,e,r){let i=m.iterToArray(e);typeof i[0]=="number"?t.putImageData(r,i[0],i[1]):t.putImageData(r,i[0][0],i[0][1],i[0][0],i[0][1],i[1][0],i[1][1])}imageData(t,e){return E.imageData(this._ctx,t,e),this}static text(t,e,r,i){!e||t.fillText(r,e[0],e[1],i)}text(t,e,r){return E.text(this._ctx,t,e,r),this}textBox(t,e,r="middle",i="",s=!0){s&&(this._ctx.textBaseline=r);let o=k.size(t),l=this._textTruncate(e,o[0],i);return this.text(this._textAlign(t,r),l[0]),this}paragraphBox(t,e,r=1.2,i="top",s=!0){let o=m.iterToArray(t),l=k.size(o);this._ctx.textBaseline="top";let u=this._font.size*r,h=(_,T=[],S=0)=>{if(!_||s&&S*u>l[1]-u*2)return T;if(S>1e4)throw new Error("max recursion reached (10000)");let W=this._textTruncate(_,l[0],""),gt=W[0].indexOf(` -`);if(gt>=0)return T.push(W[0].substr(0,gt)),h(_.substr(gt+1),T,S+1);let ut=W[0].lastIndexOf(" ")+1;(ut<=0||W[1]===_.length)&&(ut=void 0);let Ot=W[0].substr(0,ut);return T.push(Ot),W[1]<=0||W[1]===_.length?T:h(_.substr(ut||W[1]),T,S+1)},p=h(e),d=p.length*u,f=o;if(i=="middle"||i=="center"){let _=(l[1]-d)/2;s&&(_=Math.max(0,_)),f=new c(o[0].$add(0,_),o[1].$subtract(0,_))}else i=="bottom"?f=new c(o[0].$add(0,l[1]-d),o[1]):f=new c(o[0],o[0].$add(l[0],d));let P=k.center(f);for(let _=0,T=p.length;_$t,Delaunay:()=>nt,Noise:()=>ft});var $t=class{static distributeRandom(n,t,e=2){let r=new c;for(let i=0;i1&&s.push(n.y+v.random()*n.height),e>2&&s.push(n.z+v.random()*n.depth),r.push(new a(s))}return r}static distributeLinear(n,t){let e=m.iterToArray(n),r=M.subpoints(e,t-2);return r.unshift(e[0]),r.push(e[e.length-1]),r}static gridPts(n,t,e,r=[.5,.5]){if(t===0||e===0)throw new Error("grid columns and rows cannot be 0");let i=n.size.$subtract(1).$divide(t,e),s=i.$multiply(r),o=new c;for(let l=0;l0?Math.floor(l/r):l,d=i&&i>0?l%i:l;h.initNoise(t*d,e*p),h.seed(s),o.push(h),l++}return o}static delaunay(n){return nt.from(n)}},dt=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],pt=[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,9,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180],ft=class extends a{constructor(...t){super(...t);this.perm=[];this._n=new a(.01,.01);this.perm=pt.concat(pt)}initNoise(...t){return this._n=new a(...t),this}step(t=0,e=0){return this._n.add(t,e),this}seed(t){t>0&&t<1&&(t*=65536),t=Math.floor(t),t<256&&(t|=t<<8);for(let e=0;e<255;e++){let r=e&1?pt[e]^t&255:pt[e]^t>>8&255;this.perm[e]=this.perm[e+256]=r}return this}noise2D(){let t=Math.max(0,Math.floor(this._n[0]))%255,e=Math.max(0,Math.floor(this._n[1]))%255,r=this._n[0]%255-t,i=this._n[1]%255-e,s=w.dot(dt[(t+this.perm[e])%12],[r,i,0]),o=w.dot(dt[(t+this.perm[e+1])%12],[r,i-1,0]),l=w.dot(dt[(t+1+this.perm[e])%12],[r-1,i,0]),u=w.dot(dt[(t+1+this.perm[e+1])%12],[r-1,i-1,0]),h=d=>d*d*d*(d*(d*6-15)+10),p=h(r);return v.lerp(v.lerp(s,l,p),v.lerp(o,u,p),h(i))}},nt=class extends c{constructor(){super(...arguments);this._mesh=[]}delaunay(t=!0){if(this.length<3)return[];this._mesh=[];let e=this.length,r=[];for(let h=0;hthis[p][0]-this[h][0]);let i=this.slice(),s=this._superTriangle();i=i.concat(s);let o=[this._circum(e,e+1,e+2,s)],l=[],u=[];for(let h=0,p=r.length;h0&&S[0]*S[0]>T*T){l.push(_),u.push(_.triangle),o.splice(P,1);continue}S[0]*S[0]+S[1]*S[1]-T*T>L.epsilon||(f.push(_.i,_.j,_.j,_.k,_.k,_.i),o.splice(P,1))}for(nt._dedupe(f),P=f.length;P>1;)o.push(this._circum(f[--P],f[--P],d,!1,i))}for(let h=0,p=o.length;h1;){let r=t[--e],i=t[--e],s=e;for(;s>1;){let o=t[--s],l=t[--s];if(i==l&&r==o||i==o&&r==l){t.splice(e,2),t.splice(s,2);break}}}return t}};var Et={};z(Et,{Color:()=>lt});var b=class extends a{constructor(...t){super(...t);this._mode="rgb";this._isNorm=!1}static from(...t){let e=[1,1,1,1],r=m.getArgs(t);for(let i=0,s=e.length;it[s]||"F";t=`${i(0)}${i(0)}${i(1)}${i(1)}${i(2)}${i(2)}`}let e=1;t.length===8&&(e=t.substr(6)&&255/255,t=t.substring(0,6));let r=parseInt(t,16);return new b(r>>16,r>>8&255,r&255,e)}static rgb(...t){return b.from(...t).toMode("rgb")}static hsl(...t){return b.from(...t).toMode("hsl")}static hsb(...t){return b.from(...t).toMode("hsb")}static lab(...t){return b.from(...t).toMode("lab")}static lch(...t){return b.from(...t).toMode("lch")}static luv(...t){return b.from(...t).toMode("luv")}static xyz(...t){return b.from(...t).toMode("xyz")}static maxValues(t){return b.ranges[t].zipSlice(1).$take([0,1,2])}get hex(){return this.toString("hex")}get rgb(){return this.toString("rgb")}get rgba(){return this.toString("rgba")}clone(){let t=new b(this);return t.toMode(this._mode),t}toMode(t,e=!1){if(e){let r=this._mode.toUpperCase()+"to"+t.toUpperCase();if(b[r])this.to(b[r](this,this._isNorm,this._isNorm));else throw new Error("Cannot convert color with "+r)}return this._mode=t,this}get mode(){return this._mode}get r(){return this[0]}set r(t){this[0]=t}get g(){return this[1]}set g(t){this[1]=t}get b(){return this[2]}set b(t){this[2]=t}get h(){return this._mode=="lch"?this[2]:this[0]}set h(t){let e=this._mode=="lch"?2:0;this[e]=t}get s(){return this[1]}set s(t){this[1]=t}get l(){return this._mode=="hsl"?this[2]:this[0]}set l(t){let e=this._mode=="hsl"?2:0;this[e]=t}get a(){return this[1]}set a(t){this[1]=t}get c(){return this[1]}set c(t){this[1]=t}get u(){return this[1]}set u(t){this[1]=t}get v(){return this[2]}set v(t){this[2]=t}set alpha(t){this.length>3&&(this[3]=t)}get alpha(){return this.length>3?this[3]:1}get normalized(){return this._isNorm}set normalized(t){this._isNorm=t}normalize(t=!0){if(this._isNorm==t)return this;let e=b.ranges[this._mode];for(let r=0;r<3;r++)this[r]=t?v.mapToRange(this[r],e[r][0],e[r][1],0,1):v.mapToRange(this[r],0,1,e[r][0],e[r][1]);return this._isNorm=t,this}$normalize(t=!0){return this.clone().normalize(t)}toString(t="mode"){if(t=="hex"){let e=r=>{let i=Math.floor(r).toString(16);return i.length<2?"0"+i:i};return`#${e(this[0])}${e(this[1])}${e(this[2])}`}else return t=="rgba"?`rgba(${Math.floor(this[0])},${Math.floor(this[1])},${Math.floor(this[2])},${this.alpha})`:t=="rgb"?`rgb(${Math.floor(this[0])},${Math.floor(this[1])},${Math.floor(this[2])})`:`${this._mode}(${this[0]},${this[1]},${this[2]},${this.alpha})`}static RGBtoHSL(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=Math.max(i,s,o),u=Math.min(i,s,o),h=(l+u)/2,p=h,d=h;if(l==u)h=0,p=0;else{let f=l-u;p=d>.5?f/(2-l-u):f/(l+u),h=0,l===i?h=(s-o)/f+(s(d=d<0?d+1:d>1?d-1:d,d*6<1?u+(l-u)*d*6:d*2<1?l:d*3<2?u+(l-u)*(2/3-d)*6:u),p=r?1:255;return b.rgb(p*h(i+1/3),p*h(i),p*h(i-1/3),t.alpha)}static RGBtoHSB(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=Math.max(i,s,o),u=Math.min(i,s,o),h=l-u,p=0,d=l===0?0:h/l,f=l;return l!=u&&(l===i?p=(s-o)/h+(s.04045?Math.pow((i[o]+.055)/1.055,2.4):i[o]/12.92,r||(i[o]=i[o]*100);let s=b.xyz(i[0]*.4124564+i[1]*.3575761+i[2]*.1804375,i[0]*.2126729+i[1]*.7151522+i[2]*.072175,i[0]*.0193339+i[1]*.119192+i[2]*.9503041,t.alpha);return r?s.normalize():s}static XYZtoRGB(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=[i*3.2406254773200533+s*-1.5372079722103187+o*-.4986285986982479,i*-.9689307147293197+s*1.8757560608852415+o*.041517523842953964,i*.055710120445510616+s*-.2040210505984867+o*1.0569959422543882];for(let h=0;h<3;h++)l[h]=l[h]>.0031308?1.055*Math.pow(l[h],1/2.4)-.055:12.92*l[h],l[h]=Math.max(0,Math.min(1,l[h])),r||(l[h]=Math.round(l[h]*255));let u=b.rgb(l[0],l[1],l[2],t.alpha);return r?u.normalize():u}static XYZtoLAB(t,e=!1,r=!1){let i=e?t.$normalize(!1):t.clone(),s=.00885645167,o=903.296296296;i.divide(b.D65);let l=p=>p>s?Math.pow(p,1/3):(o*p+16)/116,u=l(i[1]),h=b.lab(116*u-16,500*(l(i[0])-u),200*(u-l(i[2])),t.alpha);return r?h.normalize():h}static LABtoXYZ(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=(i[0]+16)/116,o=i[1]/500+s,l=s-i[2]/200,u=.00885645167,h=903.296296296,p=b.D65,d=Math.pow(o,3),f=Math.pow(l,3),P=b.xyz(p[0]*(d>u?d:(116*o-16)/h),p[1]*(i[0]>h*u?Math.pow((i[0]+16)/116,3):i[0]/h),p[2]*(f>u?f:(116*l-16)/h),t.alpha);return r?P.normalize():P}static XYZtoLUV(t,e=!1,r=!1){let[i,s,o]=e?t.$normalize(!1):t,l=4*i/(i+15*s+3*o),u=9*s/(i+15*s+3*o);s=s/100,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116;let h=4*b.D65[0]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),p=9*b.D65[1]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),d=116*s-16;return b.luv(d,13*d*(l-h),13*d*(u-p),t.alpha)}static LUVtoXYZ(t,e=!1,r=!1){let[i,s,o]=e?t.$normalize(!1):t,l=(i+16)/116,u=l*l*l;l=u>.008856?u:(l-16/116)/7.787;let h=4*b.D65[0]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),p=9*b.D65[1]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]);s=s/(13*i)+h,o=o/(13*i)+p,l=l*100;let d=-1*(9*l*s)/((s-4)*o-s*o),f=(9*l-15*o*l-o*d)/(3*o);return b.xyz(d,l,f,t.alpha)}static LABtoLCH(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=g.toDegree(g.boundRadian(Math.atan2(i[2],i[1])));return b.lch(i[0],Math.sqrt(i[1]*i[1]+i[2]*i[2]),s,t.alpha)}static LCHtoLAB(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=g.toRadian(i[2]);return b.lab(i[0],Math.cos(s)*i[1],Math.sin(s)*i[1],t.alpha)}},lt=b;lt.D65=new a(95.047,100,108.883,1),lt.ranges={rgb:new c(new a(0,255),new a(0,255),new a(0,255)),hsl:new c(new a(0,360),new a(0,1),new a(0,1)),hsb:new c(new a(0,360),new a(0,1),new a(0,1)),lab:new c(new a(0,100),new a(-128,127),new a(-128,127)),lch:new c(new a(0,100),new a(0,100),new a(0,360)),luv:new c(new a(0,100),new a(-134,220),new a(-140,122)),xyz:new c(new a(0,100),new a(0,100),new a(0,100))};var Gt={};z(Gt,{DOMSpace:()=>B,HTMLForm:()=>tt,HTMLSpace:()=>U});var B=class extends Q{constructor(t,e){super();this.id="domspace";this._autoResize=!0;this._bgcolor="#e1e9f0";this._css={};var r=null,i=!1;this.id="pts",t instanceof Element?(r=t,this.id="pts_existing_space"):(r=document.querySelector(t),i=!0,this.id=t.substr(1)),r?(this._canvas=r,this._container=r.parentElement):(this._container=B.createElement("div","pts_container"),this._canvas=B.createElement("div","pts_element"),this._container.appendChild(this._canvas),document.body.appendChild(this._container),i=!1),setTimeout(this._ready.bind(this,e),50)}static createElement(t="div",e,r){let i=document.createElement(t);return e&&i.setAttribute("id",e),r&&r.appendChild&&r.appendChild(i),i}_ready(t){if(!this._container)throw new Error(`Cannot initiate #${this.id} element`);this._isReady=!0,this._resizeHandler(null),this.clear(this._bgcolor),this._canvas.dispatchEvent(new Event("ready"));for(let e in this.players)this.players.hasOwnProperty(e)&&this.players[e].start&&this.players[e].start(this.bound.clone(),this);this._pointer=this.center,this.refresh(!1),t&&t(this.bound,this._canvas)}setup(t){return t.bgcolor&&(this._bgcolor=t.bgcolor),this.autoResize=t.resize!=null?t.resize:!1,this}getForm(){return null}set autoResize(t){this._autoResize=t,t?window.addEventListener("resize",this._resizeHandler.bind(this)):(delete this._css.width,delete this._css.height,window.removeEventListener("resize",this._resizeHandler.bind(this)))}get autoResize(){return this._autoResize}resize(t,e){this.bound=t,this.styles({width:`${t.width}px`,height:`${t.height}px`},!0);for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.resize&&i.resize(this.bound,e)}return this}_resizeHandler(t){let e=G.fromBoundingRect(this._container.getBoundingClientRect());this._autoResize?this.styles({width:"100%",height:"100%"},!0):this.styles({width:`${e.width}px`,height:`${e.height}px`},!0),this.resize(e,t)}get element(){return this._canvas}get parent(){return this._container}get ready(){return this._isReady}clear(t){return t&&(this.background=t),this._canvas.innerHTML="",this}set background(t){this._bgcolor=t,this._container.style.backgroundColor=this._bgcolor}get background(){return this._bgcolor}style(t,e,r=!1){return this._css[t]=e,r&&(this._canvas.style[t]=e),this}styles(t,e=!1){for(let r in t)t.hasOwnProperty(r)&&this.style(r,t[r],e);return this}static setAttr(t,e){for(let r in e)e.hasOwnProperty(r)&&t.setAttribute(r,e[r]);return t}static getInlineStyles(t){let e="";for(let r in t)t.hasOwnProperty(r)&&t[r]&&(e+=`${r}: ${t[r]}; `);return e}dispose(){return window.removeEventListener("resize",this._resizeHandler.bind(this)),this.stop(),this.removeAll(),this}},U=class extends B{getForm(){return new tt(this)}static htmlElement(n,t,e,r=!0){if(!n||!n.appendChild)throw new Error("parent is not a valid DOM element");let i=document.querySelector(`#${e}`);return i||(i=document.createElement(t),i.setAttribute("id",e),r&&i.setAttribute("class",e.substring(0,e.indexOf("-"))),n.appendChild(i)),i}remove(n){return this._container.querySelectorAll("."+tt.scopeID(n)).forEach(e=>{e.parentNode.removeChild(e)}),super.remove(n)}removeAll(){return this._container.innerHTML="",super.removeAll()}},$=class extends j{constructor(t){super();this._style={filled:!0,stroked:!0,background:"#f03","border-color":"#fff",color:"#000","border-width":"1px","border-radius":"0","border-style":"solid",opacity:1,position:"absolute",top:0,left:0,width:0,height:0};this._ctx={group:null,groupID:"pts",groupCount:0,currentID:"pts0",currentClass:"",style:{}};this._ready=!1;this._space=t,this._space.add({start:()=>{this._ctx.group=this._space.element,this._ctx.groupID="pts_dom_"+$.groupID++,this._ctx.style=Object.assign({},this._style),this._ready=!0}})}get space(){return this._space}styleTo(t,e,r=""){if(this._ctx.style[t]===void 0)throw new Error(`${t} style property doesn't exist`);this._ctx.style[t]=`${e}${r}`}alpha(t){return this.styleTo("opacity",t),this}fill(t){return typeof t=="boolean"?(this.styleTo("filled",t),t||this.styleTo("background","transparent")):(this.styleTo("filled",!0),this.styleTo("background",t)),this}stroke(t,e,r,i){return typeof t=="boolean"?(this.styleTo("stroked",t),t||this.styleTo("border-width",0)):(this.styleTo("stroked",!0),this.styleTo("border-color",t),this.styleTo("border-width",(e||1)+"px")),this}fillText(t){return this.styleTo("color",t),this}cls(t){return typeof t=="boolean"?this._ctx.currentClass="":this._ctx.currentClass=t,this}font(t,e,r,i,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),r&&(this._font.style=r),i&&(this._font.lineHeight=i)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new F(10,"sans-serif"),this._ctx.style.font=this._font.value,this}updateScope(t,e){return this._ctx.group=e,this._ctx.groupID=t,this._ctx.groupCount=0,this.nextID(),this._ctx}scope(t){if(!t||t.animateID==null)throw new Error("item not defined or not yet added to Space");return this.updateScope($.scopeID(t),this.space.element)}nextID(){return this._ctx.groupCount++,this._ctx.currentID=`${this._ctx.groupID}-${this._ctx.groupCount}`,this._ctx.currentID}static getID(t){return t.currentID||`p-${$.domID++}`}static scopeID(t){return`item-${t.animateID}`}static style(t,e){let r=[];e.filled||r.push("background: none"),e.stroked||r.push("border: none");for(let i in e)if(e.hasOwnProperty(i)&&i!="filled"&&i!="stroked"){let s=e[i];if(s){if(!e.filled&&i.indexOf("background")===0)continue;if(!e.stroked&&i.indexOf("border-width")===0)continue;r.push(`${i}: ${s}`)}}return U.setAttr(t,{style:r.join(";")})}static rectStyle(t,e,r){return t.style.left=e[0]+"px",t.style.top=e[1]+"px",t.style.width=r[0]+"px",t.style.height=r[1]+"px",t}static textStyle(t,e){return t.style.left=e[0]+"px",t.style.top=e[1]+"px",t}static point(t,e,r=5,i="square"){return i==="circle"?$.circle(t,e,r):$.square(t,e,r)}point(t,e=5,r="square"){return this.nextID(),r=="circle"&&this.styleTo("border-radius","100%"),$.point(this._ctx,t,e,r),this}static circle(t,e,r=10){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-circle ${t.currentClass}`}),$.rectStyle(t,new a(e).$subtract(r),new a(r*2,r*2)),$.style(i,t.style),i}circle(t){return this.nextID(),this.styleTo("border-radius","100%"),$.circle(this._ctx,t[0],t[1][0]),this}static square(t,e,r){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-square ${t.currentClass}`}),$.rectStyle(t,new a(e).$subtract(r),new a(r*2,r*2)),$.style(i,t.style),i}square(t,e){return this.nextID(),$.square(this._ctx,t,e),this}static rect(t,e){let r=m.iterToArray(e);if(!m.arrayCheck(r))return;let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-rect ${t.currentClass}`}),$.rectStyle(t,r[0],r[1]),$.style(i,t.style),i}rect(t){return this.nextID(),this.styleTo("border-radius","0"),$.rect(this._ctx,t),this}static text(t,e,r){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-text ${t.currentClass}`}),i.textContent=r,$.textStyle(t,e),$.style(i,t.style),i}text(t,e){return this.nextID(),$.text(this._ctx,t,e),this}log(t){return this.fill("#000").stroke("#fff",.5).text([10,14],t),this}arc(t,e,r,i,s){return m.warn("arc is not implemented in HTMLForm"),this}line(t){return m.warn("line is not implemented in HTMLForm"),this}polygon(t){return m.warn("polygon is not implemented in HTMLForm"),this}},tt=$;tt.groupID=0,tt.domID=0;var St={};z(St,{SVGForm:()=>et,SVGSpace:()=>H});var H=class extends B{constructor(t,e){super(t,e);this._bgcolor="#999";if(this._canvas.nodeName.toLowerCase()!="svg"){let r=H.svgElement(this._canvas,"svg",`${this.id}_svg`);this._container=this._canvas,this._canvas=r}}getForm(){return new et(this)}get element(){return this._canvas}resize(t,e){return super.resize(t,e),H.setAttr(this.element,{viewBox:`0 0 ${this.bound.width} ${this.bound.height}`,width:`${this.bound.width}`,height:`${this.bound.height}`,xmlns:"http://www.w3.org/2000/svg",version:"1.1"}),this}static svgElement(t,e,r){if(!t||!t.appendChild)throw new Error("parent is not a valid DOM element");let i=document.querySelector(`#${r}`);return i||(i=document.createElementNS("http://www.w3.org/2000/svg",e),i.setAttribute("id",r),t.appendChild(i)),i}remove(t){return this._container.querySelectorAll("."+et.scopeID(t)).forEach(r=>{r.parentNode.removeChild(r)}),super.remove(t)}removeAll(){return this._container.innerHTML="",super.removeAll()}},I=class extends j{constructor(t){super();this._style={filled:!0,stroked:!0,fill:"#f03",stroke:"#fff","stroke-width":1,"stroke-linejoin":"bevel","stroke-linecap":"sqaure",opacity:1};this._ctx={group:null,groupID:"pts",groupCount:0,currentID:"pts0",currentClass:"",style:{}};this._ready=!1;this._space=t,this._space.add({start:()=>{this._ctx.group=this._space.element,this._ctx.groupID="pts_svg_"+I.groupID++,this._ctx.style=Object.assign({},this._style),this._ready=!0}})}get space(){return this._space}styleTo(t,e){if(this._ctx.style[t]===void 0)throw new Error(`${t} style property doesn't exist`);this._ctx.style[t]=e}alpha(t){return this.styleTo("opacity",t),this}fill(t){return typeof t=="boolean"?this.styleTo("filled",t):(this.styleTo("filled",!0),this.styleTo("fill",t)),this}stroke(t,e,r,i){return typeof t=="boolean"?this.styleTo("stroked",t):(this.styleTo("stroked",!0),this.styleTo("stroke",t),e&&this.styleTo("stroke-width",e),r&&this.styleTo("stroke-linejoin",r),i&&this.styleTo("stroke-linecap",i)),this}cls(t){return typeof t=="boolean"?this._ctx.currentClass="":this._ctx.currentClass=t,this}font(t,e,r,i,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),r&&(this._font.style=r),i&&(this._font.lineHeight=i)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new F(10,"sans-serif"),this._ctx.style.font=this._font.value,this}updateScope(t,e){return this._ctx.group=e,this._ctx.groupID=t,this._ctx.groupCount=0,this.nextID(),this._ctx}scope(t){if(!t||t.animateID==null)throw new Error("item not defined or not yet added to Space");return this.updateScope(I.scopeID(t),this.space.element)}nextID(){return this._ctx.groupCount++,this._ctx.currentID=`${this._ctx.groupID}-${this._ctx.groupCount}`,this._ctx.currentID}static getID(t){return t.currentID||`p-${I.domID++}`}static scopeID(t){return`item-${t.animateID}`}static style(t,e){let r=[];e.filled||r.push("fill: none"),e.stroked||r.push("stroke: none");for(let i in e)if(e.hasOwnProperty(i)&&i!="filled"&&i!="stroked"){let s=e[i];if(s){if(!e.filled&&i.indexOf("fill")===0)continue;if(!e.stroked&&i.indexOf("stroke")===0)continue;r.push(`${i}: ${s}`)}}return B.setAttr(t,{style:r.join(";")})}static point(t,e,r=5,i="square"){return i==="circle"?I.circle(t,e,r):I.square(t,e,r)}point(t,e=5,r="square"){return this.nextID(),I.point(this._ctx,t,e,r),this}static circle(t,e,r=10){let i=H.svgElement(t.group,"circle",I.getID(t));return B.setAttr(i,{cx:e[0],cy:e[1],r,class:`pts-svgform pts-circle ${t.currentClass}`}),I.style(i,t.style),i}circle(t){this.nextID();let e=m.iterToArray(t);return I.circle(this._ctx,e[0],e[1][0]),this}static arc(t,e,r,i,s,o){let l=H.svgElement(t.group,"path",I.getID(t)),u=new a(e).toAngle(i,r,!0),h=new a(e).toAngle(s,r,!0),d=g.boundAngle(s)-g.boundAngle(i)>L.pi;o&&(d=!d);let f=o?"0":"1",P=`M ${u[0]} ${u[1]} A ${r} ${r} 0 ${d?"1":"0"} ${f} ${h[0]} ${h[1]}`;return B.setAttr(l,{d:P,class:`pts-svgform pts-arc ${t.currentClass}`}),I.style(l,t.style),l}arc(t,e,r,i,s){return this.nextID(),I.arc(this._ctx,t,e,r,i,s),this}static square(t,e,r){let i=H.svgElement(t.group,"rect",I.getID(t));return B.setAttr(i,{x:e[0]-r,y:e[1]-r,width:r*2,height:r*2,class:`pts-svgform pts-square ${t.currentClass}`}),I.style(i,t.style),i}square(t,e){return this.nextID(),I.square(this._ctx,t,e),this}static line(t,e){let r=I.pointsString(e);if(r.count<2)return;if(r.count>2)return I._poly(t,r.string,!1);let i=H.svgElement(t.group,"line",I.getID(t)),s=m.iterToArray(e);return B.setAttr(i,{x1:s[0][0],y1:s[0][1],x2:s[1][0],y2:s[1][1],class:`pts-svgform pts-line ${t.currentClass}`}),I.style(i,t.style),i}line(t){return this.nextID(),I.line(this._ctx,t),this}static _poly(t,e,r=!0){let i=H.svgElement(t.group,r?"polygon":"polyline",I.getID(t));return B.setAttr(i,{points:e,class:`pts-svgform pts-polygon ${t.currentClass}`}),I.style(i,t.style),i}static pointsString(t){let e="",r=0;for(let i of t)e+=`${i[0]},${i[1]} `,r++;return{string:e,count:r}}static polygon(t,e){let r=I.pointsString(e);return I._poly(t,r.string,!0)}polygon(t){return this.nextID(),I.polygon(this._ctx,t),this}static rect(t,e){if(!m.arrayCheck(e))return;let r=H.svgElement(t.group,"rect",I.getID(t)),i=c.fromArray(e).boundingBox(),s=k.size(i);return B.setAttr(r,{x:i[0][0],y:i[0][1],width:s[0],height:s[1],class:`pts-svgform pts-rect ${t.currentClass}`}),I.style(r,t.style),r}rect(t){return this.nextID(),I.rect(this._ctx,t),this}static text(t,e,r){let i=H.svgElement(t.group,"text",I.getID(t));return B.setAttr(i,{"pointer-events":"none",x:e[0],y:e[1],dx:0,dy:0,class:`pts-svgform pts-text ${t.currentClass}`}),i.textContent=r,I.style(i,t.style),i}text(t,e){return this.nextID(),I.text(this._ctx,t,e),this}log(t){return this.fill("#000").stroke("#fff",.5).text([10,14],t),this}},et=I;et.groupID=0,et.domID=0;var zt={};z(zt,{Body:()=>st,Particle:()=>bt,World:()=>rt});var rt=class{constructor(n,t=1,e=0){this._lastTime=null;this._gravity=new a;this._friction=1;this._damping=.75;this._particles=[];this._bodies=[];this._pnames=[];this._bnames=[];return this._bound=G.fromGroup(n),this._friction=t,this._gravity=typeof e=="number"?new a(0,e):new a(e),this}get bound(){return this._bound}set bound(n){this._bound=n}get gravity(){return this._gravity}set gravity(n){this._gravity=n}get friction(){return this._friction}set friction(n){this._friction=n}get damping(){return this._damping}set damping(n){this._damping=n}get bodyCount(){return this._bodies.length}get particleCount(){return this._particles.length}body(n){let t=n;if(typeof n=="string"&&n.length>0&&(t=this._bnames.indexOf(n)),t>=0)return this._bodies[t]}particle(n){let t=n;if(typeof n=="string"&&n.length>0&&(t=this._pnames.indexOf(n)),t>=0)return this._particles[t]}bodyIndex(n){return this._bnames.indexOf(n)}particleIndex(n){return this._pnames.indexOf(n)}update(n){let t=n/1e3;this._updateParticles(t),this._updateBodies(t)}drawParticles(n){this._drawParticles=n}drawBodies(n){this._drawBodies=n}add(n,t=""){return n instanceof st?(this._bodies.push(n),this._bnames.push(t)):(this._particles.push(n),this._pnames.push(t)),this}_index(n,t){let e=0;if(typeof t=="string"){if(e=n(t),e<0)throw new Error(`Cannot find index of ${t}. You can use particleIndex() or bodyIndex() function to check existence by name.`)}else e=t;return e}removeBody(n,t=1){let e=this._index(this.bodyIndex.bind(this),n),r=e<0?[e*-1-1,t]:[e,t];return this._bodies.splice(r[0],r[1]),this._bnames.splice(r[0],r[1]),this}removeParticle(n,t=1){let e=this._index(this.particleIndex.bind(this),n),r=e<0?[e*-1-1,t]:[e,t];return this._particles.splice(r[0],r[1]),this._pnames.splice(r[0],r[1]),this}static edgeConstraint(n,t,e,r=1,i=!1){let s=1/(n.mass||1),o=1/(t.mass||1),l=s+o,u=t.$subtract(n),h=e*e,p=i?e/u.magnitude()-1:h/(u.dot(u)+h)-.5,d=u.$multiply(p*r);return n.subtract(d.$multiply(s/l)),t.add(d.$multiply(o/l)),n}static boundConstraint(n,t,e=.75){let r=g.boundingBox(t),i=n.$min(r[1].subtract(n.radius)).$max(r[0].add(n.radius));if(i[0]===r[0][0]||i[0]===r[1][0]){let s=n.changed.$multiply(e);n.previous=i.$subtract(new a(-s[0],s[1]))}else if(i[1]===r[0][1]||i[1]===r[1][1]){let s=n.changed.$multiply(e);n.previous=i.$subtract(new a(s[0],-s[1]))}n.to(i)}integrate(n,t,e){return n.addForce(this._gravity),n.verlet(t,this._friction,e),n}_updateParticles(n){for(let t=0,e=this._particles.length;t=this.length)throw new Error("index1 is not in the Group's indices");if(e<0||e>=this.length)throw new Error("index1 is not in the Group's indices");let i=this[t].$subtract(this[e]).magnitude();return this._cs.push([t,e,i,r||this._stiff]),this}linkAll(t){let e=this.length/2;for(let r=0,i=this.length;r=i-1?0:r+1;if(this.link(r,s,t),i>4){let o=Math.floor(e/2)+1,l=r>=i-o?r%i:r+o;this.link(r,l,t)}r<=e-1&&this.link(r,Math.min(this.length-1,r+Math.floor(e)))}}linksToLines(){let t=[];for(let e=0,r=this._cs.length;eMath.abs(l[0][1]-l[1][1])?o=(i.vertex[0]-s[0]-l[0][0])/(l[1][0]-l[0][0]):o=(i.vertex[1]-s[1]-l[0][1])/(l[1][1]-l[0][1]);let u=1/(o*o+(1-o)*(1-o)),h=i.vertex.body.mass||1,p=i.edge[0].body.mass||1,d=h/(h+p),f=p/(h+p);l[0].subtract(s.$multiply(d*(1-o)*u/2)),l[1].subtract(s.$multiply(d*o*u/2)),i.vertex.add(s.$multiply(f))}}processParticle(t){let e=this,r=t,i=C.hasIntersectCircle(e,O.fromCenter(t,t.radius));if(i){let s=i.normal.$multiply(i.dist),o,l=i.edge;Math.abs(l[0][0]-l[1][0])>Math.abs(l[0][1]-l[1][1])?o=(i.vertex[0]-s[0]-l[0][0])/(l[1][0]-l[0][0]):o=(i.vertex[1]-s[1]-l[0][1])/(l[1][1]-l[0][1]);let u=1/(o*o+(1-o)*(1-o)),h=i.vertex.mass||r.mass||1,p=i.edge[0].body.mass||1,d=h/(h+p),f=p/(h+p);l[0].subtract(s.$multiply(d*(1-o)*u/2)),l[1].subtract(s.$multiply(d*o*u/2));let P=t.changed.add(s.$multiply(f));t.previous=t.$subtract(P)}}};var Bt={};z(Bt,{Sound:()=>V,Tempo:()=>at});var at=class{constructor(n){this._listeners={};this._listenerInc=0;this.bpm=n}static fromBeat(n){return new at(6e4/n)}get bpm(){return this._bpm}set bpm(n){this._bpm=n,this._ms=6e4/this._bpm}get ms(){return this._ms}set ms(n){this._bpm=Math.floor(6e4/n),this._ms=6e4/this._bpm}_createID(n){let t="";return typeof n=="function"?t="_b"+this._listenerInc++:t=n.name||"_b"+this._listenerInc++,t}every(n){let t=this,e=Array.isArray(n)?n[0]:n;return{start:function(r,i=0,s){let o=s||t._createID(r);return t._listeners[o]={name:o,beats:n,period:e,index:0,offset:i,duration:-1,continuous:!1,fn:r},this},progress:function(r,i=0,s){let o=s||t._createID(r);return t._listeners[o]={name:o,beats:n,period:e,index:0,offset:i,duration:-1,continuous:!0,fn:r},this}}}track(n){for(let t in this._listeners)if(this._listeners.hasOwnProperty(t)){let e=this._listeners[t],r=e.offset?n+e.offset:n,i=e.period*this._ms,s=!1;r>e.duration+i&&(e.duration=r-r%this._ms,Array.isArray(e.beats)&&(e.index=(e.index+1)%e.beats.length,e.period=e.beats[e.index]),s=!0);let o=Math.max(0,Math.ceil(Math.floor(e.duration/this._ms)/e.period)),l=e.continuous?[o,v.clamp((r-e.duration)/i,0,1),r,s]:[o];(e.continuous||s)&&e.fn.apply(e,l)&&delete this._listeners[e.name]}}stop(n){this._listeners[n]&&delete this._listeners[n]}animate(n,t){this.track(n)}resize(n,t){}action(n,t,e,r){}},V=class{constructor(n){this._playing=!1;this._type=n;let t=window.AudioContext||window.webkitAudioContext||!1;if(!t)throw new Error("Your browser doesn't support Web Audio. (No AudioContext)");this._ctx=t?new t:void 0}static from(n,t,e="gen",r){let i=new V(e);return i._node=n,i._ctx=t,r&&(i._stream=r),i}static load(n,t="anonymous"){return new Promise((e,r)=>{let i=new V("file");i._source=typeof n=="string"?new Audio(n):n,i._source.autoplay=!1,i._source.crossOrigin=t,i._source.addEventListener("ended",function(){i._playing=!1}),i._source.addEventListener("error",function(){r("Error loading sound")}),i._source.addEventListener("canplaythrough",function(){i._node=i._ctx.createMediaElementSource(i._source),e(i)})})}static loadAsBuffer(n){return new Promise((t,e)=>{let r=new XMLHttpRequest;r.open("GET",n,!0),r.responseType="arraybuffer";let i=new V("file");r.onload=function(){i._ctx.decodeAudioData(r.response,function(s){i.createBuffer(s),t(i)},s=>e("Error decoding audio"))},r.send()})}createBuffer(n){return this._node=this._ctx.createBufferSource(),n!==void 0&&(this._buffer=n),this._node.buffer=this._buffer,this._node.onended=()=>{this._playing=!1},this}static generate(n,t){return new V("gen")._gen(n,t)}_gen(n,t){this._node=this._ctx.createOscillator();let e=this._node;return e.type=n,n==="custom"?e.setPeriodicWave(t):e.frequency.value=t,this}static async input(n){try{let t=new V("input");if(!t)return;let e=n||{audio:!0,video:!1};return t._stream=await navigator.mediaDevices.getUserMedia(e),t._node=t._ctx.createMediaStreamSource(t._stream),t}catch{return console.error("Cannot get audio from input device."),Promise.resolve(null)}}get ctx(){return this._ctx}get node(){return this._node}get outputNode(){return this._outputNode}get stream(){return this._stream}get source(){return this._source}get buffer(){return this._buffer}set buffer(n){this._buffer=n}get type(){return this._type}get playing(){return this._playing}get progress(){let n=0,t=0;return this._buffer?(n=this._buffer.duration,t=this._timestamp?this._ctx.currentTime-this._timestamp:0):(n=this._source.duration,t=this._source.currentTime),t/n}get playable(){return this._type==="input"?this._node!==void 0:!!this._buffer||this._source.readyState===4}get binSize(){return this.analyzer.size}get sampleRate(){return this._ctx.sampleRate}get frequency(){return this._type==="gen"?this._node.frequency.value:0}set frequency(n){this._type==="gen"&&(this._node.frequency.value=n)}connect(n){return this._node.connect(n),this}setOutputNode(n){return this._outputNode=n,this}removeOutputNode(){return this._outputNode=null,this}analyze(n=256,t=-100,e=-30,r=.8){let i=this._ctx.createAnalyser();return i.fftSize=n*2,i.minDecibels=t,i.maxDecibels=e,i.smoothingTimeConstant=r,this.analyzer={node:i,size:i.frequencyBinCount,data:new Uint8Array(i.frequencyBinCount)},this._node.connect(this.analyzer.node),this}_domain(n){return this.analyzer?(n?this.analyzer.node.getByteTimeDomainData(this.analyzer.data):this.analyzer.node.getByteFrequencyData(this.analyzer.data),this.analyzer.data):new Uint8Array(0)}_domainTo(n,t,e=[0,0],r=[0,0]){let i=n?this.timeDomain():this.freqDomain(),s=new c;for(let o=r[0],l=i.length-r[1];o0&&(this._source.currentTime=n)):this._type==="gen"&&(this._gen(this._node.type,this._node.frequency.value),this._node.start(),this.analyzer&&this._node.connect(this.analyzer.node)),(this._outputNode||this._node).connect(this._ctx.destination),this._playing=!0,this}stop(){return this._playing&&(this._outputNode||this._node).disconnect(this._ctx.destination),this._type==="file"?this._buffer?this.progress<1&&this._node.stop():this._source.pause():this._type==="gen"?this._node.stop():this._type==="input"&&this._stream.getAudioTracks().forEach(n=>n.stop()),this._playing=!1,this}toggle(){return this._playing?this.stop():this.start(),this}};globalThis.Pts={...At,...Tt,...Ct,..._t,...wt,...yt,...kt,...It,...Et,...xt,...Gt,...St,...Mt,...zt,...Lt,...Bt,...Dt};globalThis.Pts.namespace=x=>{let n=globalThis.Pts;for(let t in n)t!="namespace"&&(x[t]=n[t])};globalThis.Pts.quickStart=(x,n="#9ab")=>{if(!window)return;let t=globalThis;return globalThis.Pts.namespace(t),t.space=new ot(x).setup({bgcolor:n,resize:!0,retina:!0}),t.form=t.space.getForm(),function(e=null,r=null,i=null,s=null){t.space.add({start:r,animate:e,resize:s,action:i}),t.space.bindMouse().bindTouch().play()}};})(); +(()=>{var qt=Object.defineProperty;var z=(x,n)=>{for(var t in n)qt(x,t,{get:n[t],enumerable:!0})};var At={};z(At,{CanvasForm:()=>E,CanvasSpace:()=>ot});var It={};z(It,{MultiTouchSpace:()=>Q,Space:()=>ct});var kt={};z(kt,{Bound:()=>G,Group:()=>c,Pt:()=>a});var xt={};z(xt,{Const:()=>L,Util:()=>m});var wt={};z(wt,{Geom:()=>g,Num:()=>v,Range:()=>Pt,Shaping:()=>Y});var yt={};z(yt,{Circle:()=>O,Curve:()=>D,Line:()=>C,Polygon:()=>M,Rectangle:()=>k,Triangle:()=>R});var _t={};z(_t,{Mat:()=>y,Vec:()=>w});var w=class{static add(n,t){if(typeof t=="number")for(let e=0,r=n.length;eMath.max(s,o.length),0):n[0].length;for(let s=0;sm.warn("Group's length is less than "+n,x),Ht=(x,n="")=>m.warn(`Index ${n} is out of bound in Group`,x),C=class{static fromAngle(n,t,e){let r=new c(new a(n),new a(n));return r[1].toAngle(t,e,!0),r}static slope(n,t){return t[0]-n[0]===0?void 0:(t[1]-n[1])/(t[0]-n[0])}static intercept(n,t){if(t[0]-n[0]!==0){let e=(t[1]-n[1])/(t[0]-n[0]),r=n[1]-e*n[0];return{slope:e,yi:r,xi:e===0?void 0:-r/e}}}static sideOfPt2D(n,t){let e=m.iterToArray(n);return(e[1][0]-e[0][0])*(t[1]-e[0][1])-(t[0]-e[0][0])*(e[1][1]-e[0][1])}static collinear(n,t,e,r=.01){let i=new a(0,0,0).to(n).$subtract(t),s=new a(0,0,0).to(n).$subtract(e);return i.$cross(s).divide(1e3).equals(new a(0,0,0),r)}static magnitude(n){let t=m.iterToArray(n);return t.length>=2?t[1].$subtract(t[0]).magnitude():0}static magnitudeSq(n){let t=m.iterToArray(n);return t.length>=2?t[1].$subtract(t[0]).magnitudeSq():0}static perpendicularFromPt(n,t,e=!1){let r=m.iterToArray(n);if(r[0].equals(r[1]))return;let i=r[0].$subtract(r[1]),s=r[1].$subtract(t),o=s.$subtract(i.$project(s));return e?o:o.$add(t)}static distanceFromPt(n,t){let e=m.iterToArray(n),r=C.perpendicularFromPt(e,t,!0);return r?r.magnitude():e[0].$subtract(t).magnitude()}static intersectRay2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=C.intercept(e[0],e[1]),s=C.intercept(r[0],r[1]),o=e[0],l=r[0];if(i==null){if(s==null)return;let u=-s.slope*(l[0]-o[0])+l[1];return new a(o[0],u)}else if(s==null){let u=-i.slope*(o[0]-l[0])+o[1];return new a(l[0],u)}else if(s.slope!=i.slope){let u=(i.slope*o[0]-s.slope*l[0]+l[1]-o[1])/(i.slope-s.slope),h=i.slope*(u-o[0])+o[1];return new a(u,h)}else return i.yi==s.yi?new a(o[0],o[1]):void 0}static intersectLine2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=C.intersectRay2D(e,r);return i&&g.withinBound(i,e[0],e[1])&&g.withinBound(i,r[0],r[1])?i:void 0}static intersectLineWithRay2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i=C.intersectRay2D(e,r);return i&&g.withinBound(i,e[0],e[1])?i:void 0}static intersectPolygon2D(n,t,e=!1){let r=m.iterToArray(n),i=m.iterToArray(t),s=e?C.intersectLineWithRay2D:C.intersectLine2D,o=new c;for(let l=0,u=i.length;l0?o:void 0}static intersectLines2D(n,t,e=!1){let r=new c,i=e?C.intersectLineWithRay2D:C.intersectLine2D;for(let s of n)for(let o of t){let l=i(s,o);l&&r.push(l)}return r}static intersectGridWithRay2D(n,t){let e=m.iterToArray(n),r=C.intercept(new a(e[0]).subtract(t),new a(e[1]).subtract(t)),i=new c;return r&&r.xi&&i.push(new a(t[0]+r.xi,t[1])),r&&r.yi&&i.push(new a(t[0],t[1]+r.yi)),i}static intersectGridWithLine2D(n,t){let e=m.iterToArray(n),r=C.intersectGridWithRay2D(e,t),i=new c;for(let s=0,o=r.length;sMath.abs(t[1]/t[0])?h=o[1]<0?0:2:h=o[0]<0?3:1,C.intersectRay2D(u[h],i)}}static marker(n,t,e="arrow",r=!0){let i=m.iterToArray(n),s=r?0:1,o=r?1:0,l=i[s].$subtract(i[o]);if(l.magnitudeSq()===0)return new c;l.unit();let u=g.perpendicular(l).multiply(t[0]).add(i[o]);return e=="arrow"?(u.add(l.$multiply(t[1])),new c(i[o],u[0],u[1])):new c(u[0],u[1])}static toRect(n){let t=m.iterToArray(n);return new c(t[0].$min(t[1]),t[0].$max(t[1]))}},k=class{static from(n,t,e){return k.fromTopLeft(n,t,e)}static fromTopLeft(n,t,e){let r=typeof t=="number"?[t,e||t]:t;return new c(new a(n),new a(n).add(r))}static fromCenter(n,t,e){let r=typeof t=="number"?[t/2,(e||t)/2]:new a(t).divide(2);return new c(new a(n).subtract(r),new a(n).add(r))}static toCircle(n,t=!0){return O.fromRect(n,t)}static toSquare(n,t=!1){let e=m.iterToArray(n),r=k.size(e),i=t?r.maxValue().value:r.minValue().value;return k.fromCenter(k.center(e),i,i)}static size(n){let t=m.iterToArray(n);return t[0].$max(t[1]).subtract(t[0].$min(t[1]))}static center(n){let t=m.iterToArray(n),e=t[0].$min(t[1]),r=t[0].$max(t[1]);return e.add(r.$subtract(e).divide(2))}static corners(n){let t=m.iterToArray(n),e=t[0].$min(t[1]),r=t[0].$max(t[1]);return new c(e,new a(r.x,e.y),r,new a(e.x,r.y))}static sides(n){let[t,e,r,i]=k.corners(n);return[new c(t,e),new c(e,r),new c(r,i),new c(i,t)]}static boundingBox(n){let t=m.iterToArray(n),e=m.flatten(t,!1),r=a.make(2,Number.MAX_VALUE),i=a.make(2,Number.MIN_VALUE);for(let s=0,o=e.length;s=2)break}return new c(r,i)}static polygon(n){return k.corners(n)}static quadrants(n,t){let e=m.iterToArray(n),r=k.corners(e),i=t!=null?new a(t):k.center(e);return r.map(s=>new c(s,i).boundingBox())}static halves(n,t=.5,e=!1){let r=m.iterToArray(n),i=r[0].$min(r[1]),s=r[0].$max(r[1]),o=e?v.lerp(i[1],s[1],t):v.lerp(i[0],s[0],t);return e?[new c(i,new a(s[0],o)),new c(new a(i[0],o),s)]:[new c(i,new a(o,s[1])),new c(new a(o,i[1]),s)]}static withinBound(n,t){let e=m.iterToArray(n);return g.withinBound(t,e[0],e[1])}static hasIntersectRect2D(n,t,e=!1){let r=m.iterToArray(n),i=m.iterToArray(t);return e&&(r=g.boundingBox(r),i=g.boundingBox(i)),!(r[0][0]>i[1][0]||i[0][0]>r[1][0]||r[0][1]>i[1][1]||i[0][1]>r[1][1])}static intersectRect2D(n,t){let e=m.iterToArray(n),r=m.iterToArray(t);return k.hasIntersectRect2D(e,r)?C.intersectLines2D(k.sides(e),k.sides(r)):new c}},O=class{static fromRect(n,t=!1){let e=m.iterToArray(n),r=0,i=r=k.size(e).minValue().value/2;if(t){let s=k.size(e).maxValue().value/2;r=Math.sqrt(i*i+s*s)}else r=i;return new c(k.center(e),new a(r,r))}static fromTriangle(n,t=!1){return t?R.circumcircle(n):R.incircle(n)}static fromCenter(n,t){return new c(new a(n),new a(t,t))}static withinBound(n,t,e=0){let r=m.iterToArray(n),i=r[0].$subtract(t);return i.dot(i)+e0)for(let o=0,l=i.length;ol+u)return new c;if(o0&&s.push(u)}return m.flatten(s)}static toRect(n,t=!1){let e=m.iterToArray(n),r=e[1][0];if(t){let i=Math.sqrt(r*r)/2;return new c(e[0].$subtract(i),e[0].$add(i))}else return new c(e[0].$subtract(r),e[0].$add(r))}static toTriangle(n,t=!0){let e=m.iterToArray(n);if(t){let r=-Math.PI/2,i=Math.PI*2/3,s=new c;for(let o=0;o<3;o++)s.push(e[0].clone().toAngle(r,e[1][0],!0)),r+=i;return s}else return R.fromCenter(e[0],e[1][0])}},R=class{static fromRect(n){let t=m.iterToArray(n),e=t[0].$add(t[1]).divide(2);e.y=t[0][1];let r=t[1].clone();return r.x=t[0][0],new c(e,t[1].clone(),r)}static fromCircle(n){return O.toTriangle(n,!0)}static fromCenter(n,t){return R.fromCircle(O.fromCenter(n,t))}static medial(n){let t=m.iterToArray(n);return t.length<3?X(new c,3):M.midpoints(t,!0)}static oppositeSide(n,t){let e=m.iterToArray(n);return e.length<3?X(new c,3):t===0?c.fromPtArray([e[1],e[2]]):t===1?c.fromPtArray([e[0],e[2]]):c.fromPtArray([e[0],e[1]])}static altitude(n,t){let e=m.iterToArray(n),r=R.oppositeSide(e,t);return r.length>1?new c(e[t],C.perpendicularFromPt(r,e[t])):new c}static orthocenter(n){let t=m.iterToArray(n);if(t.length<3)return X(void 0,3);let e=R.altitude(t,0),r=R.altitude(t,1);return C.intersectRay2D(e,r)}static incenter(n){let t=m.iterToArray(n);if(t.length<3)return X(void 0,3);let e=M.bisector(t,0).add(t[0]),r=M.bisector(t,1).add(t[1]);return C.intersectRay2D(new c(t[0],e),new c(t[1],r))}static incircle(n,t){let e=m.iterToArray(n),r=t||R.incenter(e),i=M.area(e),s=M.perimeter(e,!0),o=2*i/s.total;return O.fromCenter(r,o)}static circumcenter(n){let t=m.iterToArray(n),e=R.medial(t),r=[e[0],g.perpendicular(t[0].$subtract(e[0])).p1.$add(e[0])],i=[e[1],g.perpendicular(t[1].$subtract(e[1])).p1.$add(e[1])];return C.intersectRay2D(r,i)}static circumcircle(n,t){let e=m.iterToArray(n),r=t||R.circumcenter(e),i=e[0].$subtract(r).magnitude();return O.fromCenter(r,i)}},M=class{static centroid(n){return g.centroid(n)}static rectangle(n,t,e){return k.corners(k.fromCenter(n,t,e))}static fromCenter(n,t,e){let r=new c;for(let i=0;i=e.length)throw new Error("index out of the Polygon's range");return new c(e[t],t===e.length-1?e[0]:e[t+1])}static lines(n,t=!0){let e=m.iterToArray(n);if(e.length<2)return X(new c,2);let r=m.split(e,2,1);return t&&r.push(new c(e[e.length-1],e[0])),r.map(i=>i)}static midpoints(n,t=!1,e=.5){return M.lines(n,t).map(s=>g.interpolate(s[0],s[1],e))}static adjacentSides(n,t,e=!1){let r=m.iterToArray(n);if(r.length<2)return X(new c,2);if(t<0||t>=r.length)return Ht(new c,t);let i=[],s=t-1;e&&s<0&&(s=r.length-1),s>=0&&i.push(new c(r[t],r[s]));let o=t+1;return e&&o>r.length-1&&(o=0),o<=r.length-1&&i.push(new c(r[t],r[o])),i}static bisector(n,t){let e=M.adjacentSides(n,t,!0);if(e.length>=2){let r=e[0][1].$subtract(e[0][0]).unit(),i=e[1][1].$subtract(e[1][0]).unit();return r.add(i).divide(2)}else return}static perimeter(n,t=!1){let e=M.lines(n,t),r=0,i=a.make(e.length,0);for(let s=0,o=e.length;si[0]*s[1]-i[1]*s[0],r=0;for(let i=0,s=t.length;iu[0]-h[0]));let r=(u,h,p)=>(h[0]-u[0])*(p[1]-u[1])-(p[0]-u[0])*(h[1]-u[1])>0,i=[],s=e.length-2,o=s+3;i[s]=e[2],i[o]=e[2],r(e[0],e[1],e[2])?(i[s+1]=e[0],i[s+2]=e[1]):(i[s+1]=e[1],i[s+2]=e[0]);for(let u=3,h=e.length;ut[1]!=o[1][1]>t[1]&&t[0]<(o[1][0]-o[0][0])*(t[1]-o[0][1])/(o[1][1]-o[0][1])+o[0][0]&&(r=!r)}return r}static hasIntersectCircle(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i={which:-1,dist:0,normal:null,edge:null,vertex:null},s=r[0],o=r[1][0],l=Number.MAX_SAFE_INTEGER;for(let h=0,p=e.length;h0)return null;Math.abs(_)0)&&(i.edge=d,i.normal=f,l=Math.abs(_),i.which=h)}return i.edge?(s.$subtract(M.centroid(e)).dot(i.normal)<0&&i.normal.multiply(-1),i.dist=l,i.vertex=s,i):null}static hasIntersectPolygon(n,t){let e=m.iterToArray(n),r=m.iterToArray(t),i={which:-1,dist:0,normal:new a,edge:new c,vertex:new a},s=Number.MAX_SAFE_INTEGER;for(let f=0,P=e.length+r.length;f0)return null;Math.abs(S)r.length-1)return new c;let i=o=>oi+s.x*t[o],0),r=n.reduce((i,s,o)=>i+s.y*t[o],0);if(n[0].length>2){let i=n.reduce((s,o,l)=>s+o.z*t[l],0);return new a(e,r,i)}return new a(e,r)}static catmullRom(n,t=10){let e=m.iterToArray(n);if(e.length<2)return new c;let r=new c,i=D.getSteps(t),s=D.controlPoints(e,0,!0);for(let l=0;l<=t;l++)r.push(D.catmullRomStep(i[l],s));let o=0;for(;o0){for(let u=0;u<=t;u++)r.push(D.catmullRomStep(i[u],l));o++}}return r}static catmullRomStep(n,t){let e=new c(new a(-.5,1,-.5,0),new a(1.5,-2.5,0,1),new a(-1.5,2,.5,0),new a(.5,-.5,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static cardinal(n,t=10,e=.5){let r=m.iterToArray(n);if(r.length<2)return new c;let i=new c,s=D.getSteps(t),o=D.controlPoints(r,0,!0);for(let u=0;u<=t;u++)i.push(D.cardinalStep(s[u],o,e));let l=0;for(;l0){for(let h=0;h<=t;h++)i.push(D.cardinalStep(s[h],u,e));l++}}return i}static cardinalStep(n,t,e=.5){let r=new c(new a(-1,2,-1,0),new a(-1,1,0,0),new a(1,-2,1,0),new a(1,-1,0,0)),i=y.multiply([n],r,!0)[0].multiply(e),s=2*n[0]-3*n[1]+1,o=-2*n[0]+3*n[1],l=D._calcPt(t,i);return l.x+=s*t[1].x+o*t[2].x,l.y+=s*t[1].y+o*t[2].y,l.length>2&&(l.z+=s*t[1].z+o*t[2].z),l}static bezier(n,t=10){let e=m.iterToArray(n);if(e.length<4)return new c;let r=new c,i=D.getSteps(t),s=0;for(;s0){for(let l=0;l<=t;l++)r.push(D.bezierStep(i[l],o));s+=3}}return r}static bezierStep(n,t){let e=new c(new a(-1,3,-3,1),new a(3,-6,3,0),new a(-3,3,0,0),new a(1,0,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static bspline(n,t=10,e=1){let r=m.iterToArray(n);if(r.length<2)return new c;let i=new c,s=D.getSteps(t),o=0;for(;o0){if(e!==1)for(let u=0;u<=t;u++)i.push(D.bsplineTensionStep(s[u],l,e));else for(let u=0;u<=t;u++)i.push(D.bsplineStep(s[u],l));o++}}return i}static bsplineStep(n,t){let e=new c(new a(-.16666666666666666,.5,-.5,.16666666666666666),new a(.5,-1,0,.6666666666666666),new a(-.5,.5,.5,.16666666666666666),new a(.16666666666666666,0,0,0));return D._calcPt(t,y.multiply([n],e,!0)[0])}static bsplineTensionStep(n,t,e=1){let r=new c(new a(-.16666666666666666,.5,-.5,.16666666666666666),new a(-1.5,2,0,-.3333333333333333),new a(1.5,-2.5,.5,.16666666666666666),new a(.16666666666666666,0,0,0)),i=y.multiply([n],r,!0)[0].multiply(e),s=2*n[0]-3*n[1]+1,o=-2*n[0]+3*n[1],l=D._calcPt(t,i);return l.x+=s*t[1].x+o*t[2].x,l.y+=s*t[1].y+o*t[2].y,l.length>2&&(l.z+=s*t[1].z+o*t[2].z),l}};function Ut(){var x=4022871197,n=function(t){if(t){t=t.toString();for(var e=0;e>>0,r-=x,r*=x,x=r>>>0,r-=x,x+=r*4294967296}return(x>>>0)*23283064365386963e-26}else x=4022871197};return n}function Rt(x){var n=48,t=1,e=n,r=new Array(n),i,s,o=0,l=Ut();for(i=0;i=n&&(e=0);var d=1768863*r[e]+t*23283064365386963e-26;return r[e]=d-(t=d|0)}}}var v=class{static equals(n,t,e=1e-5){return Math.abs(n-t)e?i-=r:i=Math.min(t,e)&&n<=Math.max(t,e)}static randomRange(n,t=0){let e=n>t?n-t:t-n;return n+v.random()*e}static randomPt(n,t){let e=new a(n.length),r=t?w.subtract(t,n):n,i=t?n:new a(n.length).fill(0);for(let s=0,o=e.length;s.5?2-n*2:n*2)}static mapToRange(n,t,e,r,i){if(t==e)throw new Error("[currMin, currMax] must define a range that is not zero");let s=Math.min(r,i),o=Math.max(r,i);return v.normalizeValue(n,t,e)*(o-s)+s}static seed(n){this.generator=Rt(n)}static random(){return this.generator?this.generator.random():Math.random()}},g=class{static boundAngle(n){return v.boundValue(n,0,360)}static boundRadian(n){return v.boundValue(n,0,L.two_pi)}static toRadian(n){return n*L.deg_to_rad}static toDegree(n){return n*L.rad_to_deg}static boundingBox(n){let t,e;for(let r of n)t==null?(t=r.clone(),e=r.clone()):(t=t.$min(r),e=e.$max(r));return new c(t,e)}static centroid(n){return v.average(n)}static anchor(n,t=0,e="to"){let r=e=="to"?"subtract":"add",i=0;for(let s of n)typeof t=="number"?t!==i&&s[r](n[t]):s[r](t),i++}static interpolate(n,t,e=.5){let r=Math.min(n.length,t.length),i=a.make(r);for(let s=0;s{if(s.length<2||o.length<2)throw new Error("Pt dimension cannot be less than 2");let l=s.$subtract(r),u=o.$subtract(r);if(l[0]>=0&&u[0]<0)return 1;if(l[0]<0&&u[0]>=0)return-1;if(l[0]==0&&u[0]==0)return l[1]>=0||u[1]>=0?l[1]>u[1]?1:-1:u[1]>l[1]?1:-1;let h=l.$cross2D(u);return h<0?1:h>0?-1:l[0]*l[0]+l[1]*l[1]>u[0]*u[0]+u[1]*u[1]?1:-1};return t.sort(i)}static scale(n,t,e){let r=m.iterToArray(n[0]!==void 0&&typeof n[0]=="number"?[n]:n),i=typeof t=="number"?a.make(r[0].length,t):t;e||(e=a.make(r[0].length,0));for(let s=0,o=r.length;sn[Math.floor(g.boundAngle(g.toDegree(e)))]}}static sinTable(){let n=new Float64Array(360);for(let e=0;e<360;e++)n[e]=Math.sin(e*Math.PI/180);return{table:n,sin:e=>n[Math.floor(g.boundAngle(g.toDegree(e)))]}}},Y=class{static linear(n,t=1){return t*n}static quadraticIn(n,t=1){return t*n*n}static quadraticOut(n,t=1){return-t*n*(n-2)}static quadraticInOut(n,t=1){let e=n*2;return n<.5?t/2*n*n*4:-t/2*((e-1)*(e-3)-1)}static cubicIn(n,t=1){return t*n*n*n}static cubicOut(n,t=1){let e=n-1;return t*(e*e*e+1)}static cubicInOut(n,t=1){let e=n*2;return n<.5?t/2*e*e*e:t/2*((e-2)*(e-2)*(e-2)+2)}static exponentialIn(n,t=1,e=.25){return t*Math.pow(n,1/e)}static exponentialOut(n,t=1,e=.25){return t*Math.pow(n,e)}static sineIn(n,t=1){return-t*Math.cos(n*L.half_pi)+t}static sineOut(n,t=1){return t*Math.sin(n*L.half_pi)}static sineInOut(n,t=1){return-t/2*(Math.cos(Math.PI*n)-1)}static cosineApprox(n,t=1){let e=n*n,r=e*e,i=r*e;return t*(4*i/9-17*r/9+22*e/9)}static circularIn(n,t=1){return-t*(Math.sqrt(1-n*n)-1)}static circularOut(n,t=1){let e=n-1;return t*Math.sqrt(1-e*e)}static circularInOut(n,t=1){let e=n*2;return n<.5?-t/2*(Math.sqrt(1-e*e)-1):t/2*(Math.sqrt(1-(e-2)*(e-2))+1)}static elasticIn(n,t=1,e=.7){let r=n-1,i=e/L.two_pi*1.5707963267948966;return t*(-Math.pow(2,10*r)*Math.sin((r-i)*L.two_pi/e))}static elasticOut(n,t=1,e=.7){let r=e/L.two_pi*1.5707963267948966;return t*(Math.pow(2,-10*n)*Math.sin((n-r)*L.two_pi/e))+t}static elasticInOut(n,t=1,e=.6){let r=n*2,i=e/L.two_pi*1.5707963267948966;return n<.5?(r-=1,t*(-.5*(Math.pow(2,10*r)*Math.sin((r-i)*L.two_pi/e)))):(r-=1,t*(.5*(Math.pow(2,-10*r)*Math.sin((r-i)*L.two_pi/e)))+t)}static bounceIn(n,t=1){return t-Y.bounceOut(1-n,t)}static bounceOut(n,t=1){return n<1/2.75?t*(7.5625*n*n):n<2/2.75?(n-=1.5/2.75,t*(7.5625*n*n+.75)):n<2.5/2.75?(n-=2.25/2.75,t*(7.5625*n*n+.9375)):(n-=2.625/2.75,t*(7.5625*n*n+.984375))}static bounceInOut(n,t=1){return n<.5?Y.bounceIn(n*2,t)/2:Y.bounceOut(n*2-1,t)/2+t/2}static sigmoid(n,t=1,e=10){let r=e*(n-.5);return t/(1+Math.exp(-r))}static logSigmoid(n,t=1,e=.7){e=Math.max(L.epsilon,Math.min(1-L.epsilon,e)),e=1/(1-e);let r=1/(1+Math.exp((n-.5)*e*-2)),i=1/(1+Math.exp(e)),s=1/(1+Math.exp(-e));return t*(r-i)/(s-i)}static seat(n,t=1,e=.5){return n<.5?t*Math.pow(2*n,1-e)/2:t*(1-Math.pow(2*(1-n),1-e)/2)}static quadraticBezier(n,t=1,e=[.05,.95]){let r=typeof e!="number"?e[0]:e,i=typeof e!="number"?e[1]:.5,s=1-2*r;s===0&&(s=L.epsilon);let o=(Math.sqrt(r*r+s*n)-r)/s;return t*((1-2*i)*(o*o)+2*i*o)}static cubicBezier(n,t=1,e=[.1,.7],r=[.9,.2]){let i=new c(new a(0,0),new a(e),new a(r),new a(1,1));return t*D.bezierStep(new a(n*n*n,n*n,n,1),D.controlPoints(i)).y}static quadraticTarget(n,t=1,e=[.2,.35]){let r=Math.min(1-L.epsilon,Math.max(L.epsilon,e[0])),i=Math.min(1,Math.max(0,e[1])),s=(1-i)/(1-r)-i/r,o=(s*(r*r)-i)/r,l=s*(n*n)-o*n;return t*Math.min(1,Math.max(0,l))}static cliff(n,t=1,e=.5){return n>e?t:0}static step(n,t,e,r,...i){let s=1/t,o=Math.floor(e/s)*s;return n(o,r,...i)}},Pt=class{constructor(n){this._dims=0;this._source=c.fromPtArray(n),this.calc()}get max(){return this._max.clone()}get min(){return this._min.clone()}get magnitude(){return this._mag.clone()}calc(){if(!this._source)return;let n=this._source[0].length;this._dims=n;let t=new a(n),e=new a(n),r=new a(n);for(let i=0;i=i.length||!(r[s]in i));s++)t.push(i[r[s]])}else e&&(t=[].slice.call(n[0]));return t}static warn(n="error",t=void 0){if(K.warnLevel()=="error")throw new Error(n);return K.warnLevel()=="warn"&&console.warn(n),t}static randomInt(n,t=0){return K.warn("Util.randomInt is deprecated. Please use `Num.randomRange`"),Math.floor(v.random()*n)+t}static split(n,t,e,r=!1,i=!0){let s=[],o=[],l=e||t,u=0;if(n.length<=0||l<=0)return[];for(;u=n.length)break;o.push(n[u+h])}u+=l,(!i||i&&o.length===t)&&s.push(o)}return s}static flatten(n,t=!0){let e=t?new c:new Array;return e.concat.apply(e,n)}static combine(n,t,e){let r=[];for(let i=0,s=n.length;i=n&&(i=t+(i-n)),r&&r(i),i}}static forRange(n,t,e=0,r=1){let i=[];for(let s=e,o=t;s=200&&e.status<400?t(e.responseText,!0):t(`Server error (${e.status}) when loading "${n}"`,!1)},e.onerror=function(){t("Unknown network error",!1)},e.send()}static download(n,t="pts_canvas_image",e="png",r=1){let i=e==="jpg"?"jpeg":e;n.element.toBlob(function(s){let o=document.createElement("a"),l=URL.createObjectURL(s);o.href=l,o.download=`${t}.${e}`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(l)},`image/${i}`,r)}static performance(n=10){let t=Date.now(),e=[];return function(){let r=Date.now();return e.push(r-t),e.length>=n&&e.shift(),t=r,Math.floor(e.reduce((i,s)=>i+s,0)/e.length)}}static arrayCheck(n,t=2){return Array.isArray(n)&&n.length{super(...args)};t.length===1&&typeof t[0]=="number"?n(t[0]):n(t.length>0?m.getArgs(t):[0,0])}static make(t,e=0,r=!1){let i=new Float32Array(t);if(e&&i.fill(e),r)for(let s=0,o=i.length;se)return!1;return!0}to(...t){let e=m.getArgs(t);for(let r=0,i=Math.min(this.length,e.length);rt(e,...r)}ops(t){let e=[];for(let r=0,i=t.length;rt(e,...r)}ops(t){let e=[];for(let r=0,i=t.length;re?i[t]-r[t]:r[t]-i[t])}forEachPt(t,...e){if(!this[0][t])return m.warn(`${t} is not a function of Pt`),this;for(let r=0,i=this.length;rt+e.toString()+" ","")+" ]"}},G=class extends c{constructor(...t){super(...t);this._center=new a;this._size=new a;this._topLeft=new a;this._bottomRight=new a;this._inited=!1;this.init()}static fromBoundingRect(t){let e=new G(new a(t.left||0,t.top||0),new a(t.right||0,t.bottom||0));return t.width&&t.height&&(e.size=new a(t.width,t.height)),e}static fromGroup(t){let e=m.iterToArray(t);if(e.length<2)throw new Error("Cannot create a Bound from a group that has less than 2 Pt");return new G(e[0],e[e.length-1])}init(){if(this.p1&&(this._size=this.p1.clone(),this._inited=!0),this.p1&&this.p2){let t=this.p1,e=this.p2;this.topLeft=t.$min(e),this._bottomRight=t.$max(e),this._updateSize(),this._inited=!0}}clone(){return new G(this._topLeft.clone(),this._bottomRight.clone())}_updateSize(){this._size=this._bottomRight.$subtract(this._topLeft).abs(),this._updateCenter()}_updateCenter(){this._center=this._size.$multiply(.5).add(this._topLeft)}_updatePosFromTop(){this._bottomRight=this._topLeft.$add(this._size),this._updateCenter()}_updatePosFromBottom(){this._topLeft=this._bottomRight.$subtract(this._size),this._updateCenter()}_updatePosFromCenter(){let t=this._size.$multiply(.5);this._topLeft=this._center.$subtract(t),this._bottomRight=this._center.$add(t)}get size(){return new a(this._size)}set size(t){this._size=new a(t),this._updatePosFromTop()}get center(){return new a(this._center)}set center(t){this._center=new a(t),this._updatePosFromCenter()}get topLeft(){return new a(this._topLeft)}set topLeft(t){this._topLeft=new a(t),this[0]=this._topLeft,this._updateSize()}get bottomRight(){return new a(this._bottomRight)}set bottomRight(t){this._bottomRight=new a(t),this[1]=this._bottomRight,this._updateSize()}get width(){return this._size.length>0?this._size.x:0}set width(t){this._size.x=t,this._updatePosFromTop()}get height(){return this._size.length>1?this._size.y:0}set height(t){this._size.y=t,this._updatePosFromTop()}get depth(){return this._size.length>2?this._size.z:0}set depth(t){this._size.z=t,this._updatePosFromTop()}get x(){return this.topLeft.x}get y(){return this.topLeft.y}get z(){return this.topLeft.z}get inited(){return this._inited}update(){return this._topLeft=this[0],this._bottomRight=this[1],this._updateSize(),this}};var Lt={};z(Lt,{UI:()=>N,UIButton:()=>ht,UIDragger:()=>vt,UIPointerActions:()=>A,UIShape:()=>Z});var Z={rectangle:"rectangle",circle:"circle",polygon:"polygon",polyline:"polyline",line:"line"},A={up:"up",down:"down",move:"move",drag:"drag",uidrag:"uidrag",drop:"drop",uidrop:"uidrop",over:"over",out:"out",enter:"enter",leave:"leave",click:"click",keydown:"keydown",keyup:"keyup",contextmenu:"contextmenu",all:"all"},J=class{constructor(n,t,e={},r){this._holds=new Map;this._group=c.fromArray(n),this._shape=t,this._id=r===void 0?`ui_${J._counter++}`:r,this._states=e,this._actions={}}static fromRectangle(n,t,e){return new this(n,Z.rectangle,t,e)}static fromCircle(n,t,e){return new this(n,Z.circle,t,e)}static fromPolygon(n,t,e){return new this(n,Z.polygon,t,e)}static fromUI(n,t,e){return new this(n.group,n.shape,t||n._states,e)}get id(){return this._id}set id(n){this._id=n}get group(){return this._group}set group(n){this._group=n}get shape(){return this._shape}set shape(n){this._shape=n}state(n,t){return n?t!==void 0?(this._states[n]=t,this):this._states[n]:null}on(n,t){return this._actions[n]||(this._actions[n]=[]),J._addHandler(this._actions[n],t)}off(n,t){return this._actions[n]?t===void 0?(delete this._actions[n],!0):J._removeHandler(this._actions[n],t):!1}listen(n,t,e){if(this._actions[n]!==void 0){if(this._within(t)||Array.from(this._holds.values()).indexOf(n)>=0)return J._trigger(this._actions[n],this,t,n,e),!0;if(this._actions.all)return J._trigger(this._actions.all,this,t,n,e),!0}return!1}hold(n){let t=Math.max(0,...Array.from(this._holds.keys()))+1;return this._holds.set(t,n),t}unhold(n){n!==void 0?this._holds.delete(n):this._holds.clear()}static track(n,t,e,r){for(let i=0,s=n.length;i=0&&tn.length}else return!1}},N=J;N._counter=0;var ht=class extends N{constructor(t,e,r={},i){super(t,e,r,i);this._hoverID=-1;r.hover===void 0&&(this._states.hover=!1),r.clicks===void 0&&(this._states.clicks=0);let s=A;this.on(s.up,(o,l,u,h)=>{this.state("clicks",this._states.clicks+1)}),this.on(s.move,(o,l,u,h)=>{if(this._within(l)&&!this._states.hover){this.state("hover",!0),N._trigger(this._actions[s.enter],this,l,s.enter,h);var d=this.hold(s.move);this._hoverID=this.on(s.move,(f,P)=>{!this._within(P)&&!this.state("dragging")&&(this.state("hover",!1),N._trigger(this._actions[s.leave],this,l,s.leave,h),this.off(s.move,this._hoverID),this.unhold(d))})}})}onClick(t){return this.on(A.up,t)}offClick(t){return this.off(A.up,t)}onContextMenu(t){return this.on(A.contextmenu,t)}offContextMenu(t){return this.off(A.contextmenu,t)}onHover(t,e){var r=[void 0,void 0];return t&&(r[0]=this.on(A.enter,t)),e&&(r[1]=this.on(A.leave,e)),r}offHover(t,e){var r=[!1,!1];return(t===void 0||t>=0)&&(r[0]=this.off(A.enter,t)),(e===void 0||e>=0)&&(r[1]=this.off(A.leave,e)),r}},vt=class extends ht{constructor(t,e,r={},i){super(t,e,r,i);this._draggingID=-1;this._moveHoldID=-1;this._dropHoldID=-1;this._upHoldID=-1;r.dragging===void 0&&(this._states.dragging=!1),r.moved===void 0&&(this._states.moved=!1),r.offset===void 0&&(this._states.offset=new a);let s=A;this.on(s.down,(l,u,h,p)=>{this._moveHoldID===-1&&(this.state("dragging",!0),this.state("offset",new a(u).subtract(l.group[0])),this._moveHoldID=this.hold(s.move)),this._dropHoldID===-1&&(this._dropHoldID=this.hold(s.drop)),this._upHoldID===-1&&(this._upHoldID=this.hold(s.up)),this._draggingID===-1&&(this._draggingID=this.on(s.move,(d,f)=>{this.state("dragging")&&(N._trigger(this._actions[s.uidrag],d,f,s.uidrag,p),this.state("moved",!0))}))});let o=(l,u,h,p)=>{this.state("dragging",!1),this.off(s.move,this._draggingID),this._draggingID=-1,this.unhold(this._moveHoldID),this._moveHoldID=-1,this.unhold(this._dropHoldID),this._dropHoldID=-1,this.unhold(this._upHoldID),this._upHoldID=-1,this.state("moved")&&(N._trigger(this._actions[s.uidrop],l,u,s.uidrop,p),this.state("moved",!1))};this.on(s.drop,o),this.on(s.up,o),this.on(s.out,o)}onDrag(t){return this.on(A.uidrag,t)}offDrag(t){return this.off(A.uidrag,t)}onDrop(t){return this.on(A.uidrop,t)}offDrop(t){return this.off(A.uidrop,t)}};var ct=class{constructor(){this.id="space";this.bound=new G;this._time={prev:0,diff:0,end:-1,min:0};this.players={};this.playerCount=0;this._animID=-1;this._pause=!1;this._refresh=void 0;this._pointer=new a;this._isReady=!1;this._playing=!1}refresh(n){return this._refresh=n,this}minFrameTime(n=0){this._time.min=n}add(n){let t=typeof n=="function"?{animate:n}:n,e=this.playerCount++,r=this.id+e;return this.players[r]=t,t.animateID=r,t.resize&&this.bound.inited&&t.resize(this.bound),this._refresh===void 0&&(this._refresh=!0),this}remove(n){return delete this.players[n.animateID],this}removeAll(){return this.players={},this}play(n=0){if(!(n===0&&this._animID!==-1)){if(this._animID=requestAnimationFrame(this.play.bind(this)),this._pause)return this;if(this._time.diff=n-this._time.prev,this._time.diff=0&&n>this._time.end&&(cancelAnimationFrame(this._animID),this._animID=-1,this._playing=!1)}pause(n=!1){return this._pause=n?!this._pause:!0,this}resume(){return this._pause=!1,this}stop(n=0){return this._time.end=n,this}playOnce(n=0){return this.play(),this.stop(n),this}render(n){return this._renderFunc&&this._renderFunc(n,this),this}set customRendering(n){this._renderFunc=n}get customRendering(){return this._renderFunc}get isPlaying(){return this._playing}get outerBound(){return this.bound.clone()}get innerBound(){return new G(a.make(this.size.length,0),this.size.clone())}get size(){return this.bound.size.clone()}get center(){return this.size.divide(2)}get width(){return this.bound.width}get height(){return this.bound.height}},Q=class extends ct{constructor(){super(...arguments);this._pressed=!1;this._dragged=!1;this._hasMouse=!1;this._hasTouch=!1;this._hasKeyboard=!1}get pointer(){let t=this._pointer.clone();return t.id=this._pointer.id,t}bindCanvas(t,e,r={},i){(i||this._canvas).addEventListener(t,e,r)}unbindCanvas(t,e,r={},i){(i||this._canvas).removeEventListener(t,e,r)}bindDoc(t,e,r={}){document&&document.addEventListener(t,e,r)}unbindDoc(t,e,r={}){document&&document.removeEventListener(t,e,r)}bindMouse(t=!0,e){return t?(this._mouseDown=this._mouseDown.bind(this),this._mouseUp=this._mouseUp.bind(this),this._mouseOver=this._mouseOver.bind(this),this._mouseOut=this._mouseOut.bind(this),this._mouseMove=this._mouseMove.bind(this),this._mouseClick=this._mouseClick.bind(this),this._contextMenu=this._contextMenu.bind(this),this.bindCanvas("mousedown",this._mouseDown,{},e),this.bindCanvas("mouseup",this._mouseUp,{},e),this.bindCanvas("mouseover",this._mouseOver,{},e),this.bindCanvas("mouseout",this._mouseOut,{},e),this.bindCanvas("mousemove",this._mouseMove,{},e),this.bindCanvas("click",this._mouseClick,{},e),this.bindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!0):(this.unbindCanvas("mousedown",this._mouseDown,{},e),this.unbindCanvas("mouseup",this._mouseUp,{},e),this.unbindCanvas("mouseover",this._mouseOver,{},e),this.unbindCanvas("mouseout",this._mouseOut,{},e),this.unbindCanvas("mousemove",this._mouseMove,{},e),this.unbindCanvas("click",this._mouseClick,{},e),this.unbindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!1),this}bindTouch(t=!0,e=!1,r){return t?(this.bindCanvas("touchstart",this._touchStart.bind(this),{passive:e},r),this.bindCanvas("touchend",this._mouseUp.bind(this),{},r),this.bindCanvas("touchmove",this._touchMove.bind(this),{passive:e},r),this.bindCanvas("touchcancel",this._mouseOut.bind(this),{},r),this._hasTouch=!0):(this.unbindCanvas("touchstart",this._touchStart.bind(this),{passive:e},r),this.unbindCanvas("touchend",this._mouseUp.bind(this),{},r),this.unbindCanvas("touchmove",this._touchMove.bind(this),{passive:e},r),this.unbindCanvas("touchcancel",this._mouseOut.bind(this),{},r),this._hasTouch=!1),this}bindKeyboard(t=!0){return t?(this._keyDownBind=this._keyDown.bind(this),this._keyUpBind=this._keyUp.bind(this),this.bindDoc("keydown",this._keyDownBind,{}),this.bindDoc("keyup",this._keyUpBind,{}),this._hasKeyboard=!0):(this.unbindDoc("keydown",this._keyDownBind,{}),this.unbindDoc("keyup",this._keyUpBind,{}),this._hasKeyboard=!1),this}touchesToPoints(t,e="touches"){if(!t||!t[e])return[];let r=[];for(var i=0;i0,u=e.changedTouches.item(0);r=l?u.pageX-this.outerBound.x:0,i=l?u.pageY-this.outerBound.y:0,o.action&&o.action(t,r,i,e)}t&&(this._pointer.to(r,i),this._pointer.id=t)}_mouseDown(t){return this._mouseAction(A.down,t),this._pressed=!0,!1}_mouseUp(t){return this._dragged?this._mouseAction(A.drop,t):this._mouseAction(A.up,t),this._pressed=!1,this._dragged=!1,!1}_mouseMove(t){return this._mouseAction(A.move,t),this._pressed&&(this._dragged=!0,this._mouseAction(A.drag,t)),!1}_mouseOver(t){return this._mouseAction(A.over,t),!1}_mouseOut(t){return this._mouseAction(A.out,t),this._dragged&&this._mouseAction(A.drop,t),this._dragged=!1,!1}_mouseClick(t){return this._mouseAction(A.click,t),this._pressed=!1,this._dragged=!1,!1}_contextMenu(t){return this._mouseAction(A.contextmenu,t),!1}_touchMove(t){return this._mouseMove(t),t.preventDefault(),!1}_touchStart(t){return this._mouseDown(t),t.preventDefault(),!1}_keyDown(t){return this._keyboardAction(A.keydown,t),!1}_keyUp(t){return this._keyboardAction(A.keyup,t),!1}_keyboardAction(t,e){if(!!this.isPlaying){for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.action&&i.action(t,e.shiftKey?1:0,e.altKey?1:0,e)}}}};var Mt={};z(Mt,{Font:()=>F,Form:()=>mt,VisualForm:()=>j});var mt=class{constructor(){this._ready=!1}get ready(){return this._ready}},j=class extends mt{constructor(){super(...arguments);this._filled=!0;this._stroked=!0;this._font=new F(14,"sans-serif")}get filled(){return this._filled}set filled(t){this._filled=t}get stroked(){return this._stroked}set stroked(t){this._stroked=t}get currentFont(){return this._font}_multiple(t,e,...r){if(!t)return this;for(let i=0,s=t.length;iit});var it=class{static textWidthEstimator(n,t=["M","n","."],e=[.06,.8,.14]){let r=t.map(n),i=new a(e).dot(r);return s=>s.length*i}static truncate(n,t,e,r=""){let i=Math.floor(t.length*Math.min(1,e/n(t)));return i0?Math.max(i,e):i}}};var Dt={};z(Dt,{Img:()=>q});var q=class{constructor(n=!1,t,e){this._scale=1;this._loaded=!1;this._editable=n,this._space=t,this._scale=this._space?this._space.pixelScale:1,this._img=new Image,e&&(this._img.crossOrigin="Anonymous")}static load(n,t=!1,e,r){let i=new q(t,e);return i.load(n).then(s=>{r&&r(s)}),i}static async loadAsync(n,t=!1,e){return await new q(t,e).load(n)}static async loadPattern(n,t,e="repeat",r=!1){return(await q.loadAsync(n,r,t)).pattern(e)}static blank(n,t,e){let r=new q(!0,t),i=e||t.pixelScale;return r.initCanvas(n[0],n[1],i),r}load(n){return new Promise((t,e)=>{this._editable&&!document&&e("Cannot create html canvas element. document not found."),this._img.src=n,this._img.onload=()=>{this._editable&&(this._cv||(this._cv=document.createElement("canvas")),this._drawToScale(this._scale,this._img),this._data=this._ctx.getImageData(0,0,this._cv.width,this._cv.height)),this._loaded=!0,t(this)},this._img.onerror=r=>{e(r)}})}_drawToScale(n,t){let e=t.width,r=t.height;this.initCanvas(e,r,n),t&&this._ctx.drawImage(t,0,0,e,r,0,0,this._cv.width,this._cv.height)}initCanvas(n,t,e=1){if(!this._editable){console.error("Cannot initiate canvas because this Img is not set to be editable");return}this._cv||(this._cv=document.createElement("canvas"));let r=typeof e=="number"?[e,e]:e;this._cv.width=n*r[0],this._cv.height=t*r[1],this._ctx=this._cv.getContext("2d"),this._loaded=!0}bitmap(n){let t=n?n[0]:this._cv.width,e=n?n[1]:this._cv.height;return createImageBitmap(this._cv,0,0,t,e)}pattern(n="repeat",t=!1){if(!this._space)throw"Cannot find CanvasSpace ctx to create image pattern";return this._space.ctx.createPattern(t?this._cv:this._img,n)}sync(){this._scale!==1?this.bitmap().then(n=>{this._drawToScale(1/this._scale,n),this.load(this.toBase64())}):this._img.src=this.toBase64()}pixel(n,t=!0){let e=typeof t=="number"?t:t?this._scale:1;return q.getPixel(this._data,[n[0]*e,n[1]*e])}static getPixel(n,t){let e=new a(0,0,0,0);if(t[0]>=n.width||t[1]>=n.height)return e;let r=Math.floor(t[1])*(n.width*4)+Math.floor(t[0])*4,i=n.data;return r>=i.length-4?e:new a(i[r],i[r+1],i[r+2],i[r+3])}resize(n,t=!1){let e=t?n:[n[0]/this._img.naturalWidth,n[1]/this._img.naturalHeight];return this._drawToScale(e,this._img),this._data=this._ctx.getImageData(0,0,this._cv.width,this._cv.height),this}crop(n){let t=n.topLeft.scale(this._scale),e=n.size.scale(this._scale);return this._ctx.getImageData(t.x,t.y,e.x,e.y)}filter(n){return this._ctx.filter=n,this._ctx.drawImage(this._cv,0,0),this._ctx.filter="none",this}cleanup(){this._cv&&this._cv.remove(),this._img&&this._img.remove(),this._data=null}static fromBlob(n,t=!1,e){let r=URL.createObjectURL(n);return new q(t,e).load(r)}static imageDataToBlob(n){return new Promise(function(t,e){document||e("Cannot create html canvas element. document not found.");let r=document.createElement("canvas");r.width=n.width,r.height=n.height,r.getContext("2d").putImageData(n,0,0),r.toBlob(i=>{t(i),r.remove()})})}toBase64(){return this._cv.toDataURL()}toBlob(){return new Promise(n=>{this._cv.toBlob(t=>n(t))})}getForm(){return this._editable||console.error("Cannot get a CanvasForm because this Img is not editable"),this._ctx?new E(this._ctx):void 0}get current(){return this._editable?this._cv:this._img}get image(){return this._img}get canvas(){return this._cv}get data(){return this._data}get ctx(){return this._ctx}get loaded(){return this._loaded}get pixelScale(){return this._scale}get imageSize(){return!this._img.width||!this._img.height?this.canvasSize.$divide(this._scale):new a(this._img.width,this._img.height)}get canvasSize(){return new a(this._cv.width,this._cv.height)}get scaledMatrix(){let n=1/this._scale;return new y().scale2D([n,n])}};var ot=class extends Q{constructor(t,e){super();this._pixelScale=1;this._autoResize=!0;this._bgcolor="#e1e9f0";this._offscreen=!1;this._initialResize=!1;var r=null,i=!1;if(this.id="pt",t instanceof Element)r=t,this.id="pts_existing_space";else{let s=t;s=t[0]==="#"||t[0]==="."?t:"#"+t,r=document.querySelector(s),i=!0,this.id=s.substr(1)}r?r.nodeName.toLowerCase()!="canvas"?(this._container=r,this._canvas=this._createElement("canvas",this.id+"_canvas"),this._container.appendChild(this._canvas),this._initialResize=!0):(this._canvas=r,this._container=r.parentElement,this._autoResize=!1):(this._container=this._createElement("div",this.id+"_container"),this._canvas=this._createElement("canvas",this.id),this._container.appendChild(this._canvas),document.body.appendChild(this._container),i=!1),setTimeout(this._ready.bind(this,e),100),this._ctx=this._canvas.getContext("2d")}_createElement(t="div",e){let r=document.createElement(t);return r.setAttribute("id",e),r}_ready(t){if(!this._container)throw new Error(`Cannot initiate #${this.id} element`);this._isReady=!0,this._resizeHandler(null),this.clear(this._bgcolor),this._canvas.dispatchEvent(new Event("ready"));for(let e in this.players)this.players.hasOwnProperty(e)&&this.players[e].start&&this.players[e].start(this.bound.clone(),this);this._pointer=this.center,this._initialResize=!1,t&&t(this.bound,this._canvas)}setup(t){if(this._bgcolor=t.bgcolor?t.bgcolor:"transparent",this.autoResize=t.resize!=null?t.resize:!1,t.retina!==!1){let e=window&&window.devicePixelRatio||1,r=this._ctx.webkitBackingStorePixelRatio||this._ctx.mozBackingStorePixelRatio||this._ctx.msBackingStorePixelRatio||this._ctx.oBackingStorePixelRatio||this._ctx.backingStorePixelRatio||1;this._pixelScale=Math.max(1,e/r)}return t.offscreen?(this._offscreen=!0,this._offCanvas=this._createElement("canvas",this.id+"_offscreen"),this._offCtx=this._offCanvas.getContext("2d")):this._offscreen=!1,t.pixelDensity&&(this._pixelScale=t.pixelDensity),this}set autoResize(t){!window||(this._autoResize=t,t?window.addEventListener("resize",this._resizeHandler.bind(this)):window.removeEventListener("resize",this._resizeHandler.bind(this)))}get autoResize(){return this._autoResize}resize(t,e){this.bound=t,this._canvas.width=Math.ceil(this.bound.size.x)*this._pixelScale,this._canvas.height=Math.ceil(this.bound.size.y)*this._pixelScale,this._canvas.style.width=Math.ceil(this.bound.size.x)+"px",this._canvas.style.height=Math.ceil(this.bound.size.y)+"px",this._offscreen&&(this._offCanvas.width=Math.ceil(this.bound.size.x)*this._pixelScale,this._offCanvas.height=Math.ceil(this.bound.size.y)*this._pixelScale),this._pixelScale!=1&&(this._ctx.scale(this._pixelScale,this._pixelScale),this._offscreen&&this._offCtx.scale(this._pixelScale,this._pixelScale));for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.resize&&i.resize(this.bound,e)}return this.render(this._ctx),e&&!this.isPlaying&&this.playOnce(0),this}_resizeHandler(t){if(!window)return;let e=this._autoResize||this._initialResize?this._container.getBoundingClientRect():this._canvas.getBoundingClientRect();if(e){let r=G.fromBoundingRect(e);r.center=r.center.add(window.pageXOffset,window.pageYOffset),this.resize(r,t)}}set background(t){this._bgcolor=t}get background(){return this._bgcolor}get pixelScale(){return this._pixelScale}get hasOffscreen(){return this._offscreen}get offscreenCtx(){return this._offCtx}get offscreenCanvas(){return this._offCanvas}getForm(){return new E(this)}get element(){return this._canvas}get parent(){return this._container}get ready(){return this._isReady}get ctx(){return this._ctx}clear(t){t&&(this._bgcolor=t);let e=this._ctx.fillStyle,r=Math.ceil(this.pixelScale);return!this._bgcolor||this._bgcolor==="transparent"?this._ctx.clearRect(-r,-r,this._canvas.width+r,this._canvas.height+r):((this._bgcolor.indexOf("rgba")===0||this._bgcolor.length===9&&this._bgcolor.indexOf("#")===0)&&this._ctx.clearRect(-r,-r,this._canvas.width+r,this._canvas.height+r),this._ctx.fillStyle=this._bgcolor,this._ctx.fillRect(-r,-r,this._canvas.width+r,this._canvas.height+r)),this._ctx.fillStyle=e,this}clearOffscreen(t){if(this._offscreen){let e=Math.ceil(this.pixelScale);t?(this._offCtx.fillStyle=t,this._offCtx.fillRect(-e,-e,this._canvas.width+e,this._canvas.height+e)):this._offCtx.clearRect(-e,-e,this._offCanvas.width+e,this._offCanvas.height+e)}return this}playItems(t){this._isReady&&(this._ctx.save(),this._offscreen&&this._offCtx.save(),super.playItems(t),this._ctx.restore(),this._offscreen&&this._offCtx.restore(),this.render(this._ctx))}dispose(){if(!!window)return window.removeEventListener("resize",this._resizeHandler.bind(this)),this.stop(),this.removeAll(),this}recorder(t,e="webm",r=15e6){let i=this._canvas.captureStream(),s=new MediaRecorder(i,{mimeType:`video/${e}`,bitsPerSecond:r});return s.ondataavailable=function(o){let l=URL.createObjectURL(new Blob([o.data],{type:`video/${e}`}));if(typeof t=="function")t(l);else if(t){let u=document.createElement("a");u.href=l,u.download=`canvas_video.${e}`,u.click(),u.remove()}},s}},E=class extends j{constructor(t){super();this._style={fillStyle:"#f03",strokeStyle:"#fff",lineWidth:1,lineJoin:"bevel",lineCap:"butt",globalAlpha:1};if(!t)return this;let e=r=>{this._ctx=r,this._ctx.fillStyle=this._style.fillStyle,this._ctx.strokeStyle=this._style.strokeStyle,this._ctx.lineJoin="bevel",this._ctx.font=this._font.value,this._ready=!0};t instanceof CanvasRenderingContext2D?e(t):(this._space=t,this._space.add({start:()=>{e(this._space.ctx)}}))}get space(){return this._space}get ctx(){return this._ctx}useOffscreen(t=!0,e=!1){return e&&this._space.clearOffscreen(typeof e=="string"?e:null),this._ctx=this._space.hasOffscreen&&t?this._space.offscreenCtx:this._space.ctx,this}renderOffscreen(t=[0,0]){this._space.hasOffscreen&&this._space.ctx.drawImage(this._space.offscreenCanvas,t[0],t[1],this._space.width,this._space.height)}alpha(t){return this._ctx.globalAlpha=t,this._style.globalAlpha=t,this}fill(t){return typeof t=="boolean"?this.filled=t:(this.filled=!0,this._style.fillStyle=t,this._ctx.fillStyle=t),this}stroke(t,e,r,i){return typeof t=="boolean"?this.stroked=t:(this.stroked=!0,this._style.strokeStyle=t,this._ctx.strokeStyle=t,e&&(this._ctx.lineWidth=e,this._style.lineWidth=e),r&&(this._ctx.lineJoin=r,this._style.lineJoin=r),i&&(this._ctx.lineCap=i,this._style.lineCap=i)),this}applyFillStroke(t=!0,e=!0,r=1){return t&&(typeof t=="string"&&this.fill(t),this._ctx.fill()),e&&(typeof e=="string"&&this.stroke(e,r),this._ctx.stroke()),this}gradient(t){let e=[];t.length<2&&t.push([.99,"#000"],[1,"#000"]);for(let r=0,i=t.length;r{let s=i?this._ctx.createRadialGradient(r[0][0],r[0][1],Math.abs(r[1][0]),i[0][0],i[0][1],Math.abs(i[1][0])):this._ctx.createLinearGradient(r[0][0],r[0][1],r[1][0],r[1][1]);for(let o=0,l=e.length;othis._ctx.measureText(e).width):void 0,this}getTextWidth(t){return this._estimateTextWidth?this._estimateTextWidth(t):this._ctx.measureText(t+" .").width}_textTruncate(t,e,r=""){return it.truncate(this.getTextWidth.bind(this),t,e,r)}_textAlign(t,e,r,i){let s=m.iterToArray(t);if(!!m.arrayCheck(s)){i||(i=k.center(s));var o=s[0][0];this._ctx.textAlign=="end"||this._ctx.textAlign=="right"?o=s[1][0]:(this._ctx.textAlign=="center"||this._ctx.textAlign=="middle")&&(o=i[0]);var l=i[1];return e=="top"||e=="start"?l=s[0][1]:(e=="end"||e=="bottom")&&(l=s[1][1]),r?new a(o+r[0],l+r[1]):new a(o,l)}}reset(){for(let t in this._style)this._style.hasOwnProperty(t)&&(this._ctx[t]=this._style[t]);return this._font=new F,this._ctx.font=this._font.value,this}_paint(){this._filled&&this._ctx.fill(),this._stroked&&this._ctx.stroke()}static point(t,e,r=5,i="square"){if(!!e){if(!E[i])throw new Error(`${i} is not a static function of CanvasForm`);E[i](t,e,r)}}point(t,e=5,r="square"){return E.point(this._ctx,t,e,r),this._paint(),this}static circle(t,e,r=10){!e||(t.beginPath(),t.arc(e[0],e[1],r,0,L.two_pi,!1),t.closePath())}circle(t){let e=m.iterToArray(t);return E.circle(this._ctx,e[0],e[1][0]),this._paint(),this}static ellipse(t,e,r,i=0,s=0,o=L.two_pi,l=!1){!e||!r||(t.beginPath(),t.ellipse(e[0],e[1],r[0],r[1],i,s,o,l))}ellipse(t,e,r=0,i=0,s=L.two_pi,o=!1){return E.ellipse(this._ctx,t,e,r,i,s,o),this._paint(),this}static arc(t,e,r,i,s,o){!e||(t.beginPath(),t.arc(e[0],e[1],r,i,s,o))}arc(t,e,r,i,s){return E.arc(this._ctx,t,e,r,i,s),this._paint(),this}static square(t,e,r){if(!e)return;let i=e[0]-r,s=e[1]-r,o=e[0]+r,l=e[1]+r;t.beginPath(),t.moveTo(i,s),t.lineTo(i,l),t.lineTo(o,l),t.lineTo(o,s),t.closePath()}square(t,e){return E.square(this._ctx,t,e),this._paint(),this}static line(t,e){if(!m.arrayCheck(e))return;let r=0;t.beginPath();for(let i of e)i&&(r++>0?t.lineTo(i[0],i[1]):t.moveTo(i[0],i[1]))}line(t){return E.line(this._ctx,t),this._paint(),this}static polygon(t,e){!m.arrayCheck(e)||(E.line(t,e),t.closePath())}polygon(t){return E.polygon(this._ctx,t),this._paint(),this}static rect(t,e){let r=m.iterToArray(e);!m.arrayCheck(r)||(t.beginPath(),t.moveTo(r[0][0],r[0][1]),t.lineTo(r[0][0],r[1][1]),t.lineTo(r[1][0],r[1][1]),t.lineTo(r[1][0],r[0][1]),t.closePath())}rect(t){return E.rect(this._ctx,t),this._paint(),this}static image(t,e,r,i){let s=m.iterToArray(e),o;if(typeof s[0]=="number")o=s;else if(i){let l=m.iterToArray(i);o=[l[0][0],l[0][1],l[1][0]-l[0][0],l[1][1]-l[0][1],s[0][0],s[0][1],s[1][0]-s[0][0],s[1][1]-s[0][1]]}else o=[s[0][0],s[0][1],s[1][0]-s[0][0],s[1][1]-s[0][1]];r instanceof q?r.loaded&&t.drawImage(r.image,...o):t.drawImage(r,...o)}image(t,e,r){return e instanceof q?e.loaded&&E.image(this._ctx,t,e.image,r):E.image(this._ctx,t,e,r),this}static imageData(t,e,r){let i=m.iterToArray(e);typeof i[0]=="number"?t.putImageData(r,i[0],i[1]):t.putImageData(r,i[0][0],i[0][1],i[0][0],i[0][1],i[1][0],i[1][1])}imageData(t,e){return E.imageData(this._ctx,t,e),this}static text(t,e,r,i){!e||t.fillText(r,e[0],e[1],i)}text(t,e,r){return E.text(this._ctx,t,e,r),this}textBox(t,e,r="middle",i="",s=!0){s&&(this._ctx.textBaseline=r);let o=k.size(t),l=this._textTruncate(e,o[0],i);return this.text(this._textAlign(t,r),l[0]),this}paragraphBox(t,e,r=1.2,i="top",s=!0){let o=m.iterToArray(t),l=k.size(o);this._ctx.textBaseline="top";let u=this._font.size*r,h=(_,T=[],S=0)=>{if(!_||s&&S*u>l[1]-u*2)return T;if(S>1e4)throw new Error("max recursion reached (10000)");let W=this._textTruncate(_,l[0],""),gt=W[0].indexOf(` +`);if(gt>=0)return T.push(W[0].substr(0,gt)),h(_.substr(gt+1),T,S+1);let ut=W[0].lastIndexOf(" ")+1;(ut<=0||W[1]===_.length)&&(ut=void 0);let Ot=W[0].substr(0,ut);return T.push(Ot),W[1]<=0||W[1]===_.length?T:h(_.substr(ut||W[1]),T,S+1)},p=h(e),d=p.length*u,f=o;if(i=="middle"||i=="center"){let _=(l[1]-d)/2;s&&(_=Math.max(0,_)),f=new c(o[0].$add(0,_),o[1].$subtract(0,_))}else i=="bottom"?f=new c(o[0].$add(0,l[1]-d),o[1]):f=new c(o[0],o[0].$add(l[0],d));let P=k.center(f);for(let _=0,T=p.length;_$t,Delaunay:()=>nt,Noise:()=>ft});var $t=class{static distributeRandom(n,t,e=2){let r=new c;for(let i=0;i1&&s.push(n.y+v.random()*n.height),e>2&&s.push(n.z+v.random()*n.depth),r.push(new a(s))}return r}static distributeLinear(n,t){let e=m.iterToArray(n),r=C.subpoints(e,t-2);return r.unshift(e[0]),r.push(e[e.length-1]),r}static gridPts(n,t,e,r=[.5,.5]){if(t===0||e===0)throw new Error("grid columns and rows cannot be 0");let i=n.size.$subtract(1).$divide(t,e),s=i.$multiply(r),o=new c;for(let l=0;l0?Math.floor(l/r):l,d=i&&i>0?l%i:l;h.initNoise(t*d,e*p),h.seed(s),o.push(h),l++}return o}static delaunay(n){return nt.from(n)}},dt=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],pt=[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,9,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180],ft=class extends a{constructor(...t){super(...t);this.perm=[];this._n=new a(.01,.01);this.perm=pt.concat(pt)}initNoise(...t){return this._n=new a(...t),this}step(t=0,e=0){return this._n.add(t,e),this}seed(t){t>0&&t<1&&(t*=65536),t=Math.floor(t),t<256&&(t|=t<<8);for(let e=0;e<255;e++){let r=e&1?pt[e]^t&255:pt[e]^t>>8&255;this.perm[e]=this.perm[e+256]=r}return this}noise2D(){let t=Math.max(0,Math.floor(this._n[0]))%255,e=Math.max(0,Math.floor(this._n[1]))%255,r=this._n[0]%255-t,i=this._n[1]%255-e,s=w.dot(dt[(t+this.perm[e])%12],[r,i,0]),o=w.dot(dt[(t+this.perm[e+1])%12],[r,i-1,0]),l=w.dot(dt[(t+1+this.perm[e])%12],[r-1,i,0]),u=w.dot(dt[(t+1+this.perm[e+1])%12],[r-1,i-1,0]),h=d=>d*d*d*(d*(d*6-15)+10),p=h(r);return v.lerp(v.lerp(s,l,p),v.lerp(o,u,p),h(i))}},nt=class extends c{constructor(){super(...arguments);this._mesh=[]}delaunay(t=!0){if(this.length<3)return[];this._mesh=[];let e=this.length,r=[];for(let h=0;hthis[p][0]-this[h][0]);let i=this.slice(),s=this._superTriangle();i=i.concat(s);let o=[this._circum(e,e+1,e+2,s)],l=[],u=[];for(let h=0,p=r.length;h0&&S[0]*S[0]>T*T){l.push(_),u.push(_.triangle),o.splice(P,1);continue}S[0]*S[0]+S[1]*S[1]-T*T>L.epsilon||(f.push(_.i,_.j,_.j,_.k,_.k,_.i),o.splice(P,1))}for(nt._dedupe(f),P=f.length;P>1;)o.push(this._circum(f[--P],f[--P],d,!1,i))}for(let h=0,p=o.length;h1;){let r=t[--e],i=t[--e],s=e;for(;s>1;){let o=t[--s],l=t[--s];if(i==l&&r==o||i==o&&r==l){t.splice(e,2),t.splice(s,2);break}}}return t}};var Et={};z(Et,{Color:()=>lt});var b=class extends a{constructor(...t){super(...t);this._mode="rgb";this._isNorm=!1}static from(...t){let e=[1,1,1,1],r=m.getArgs(t);for(let i=0,s=e.length;it[s]||"F";t=`${i(0)}${i(0)}${i(1)}${i(1)}${i(2)}${i(2)}`}let e=1;t.length===8&&(e=t.substr(6)&&255/255,t=t.substring(0,6));let r=parseInt(t,16);return new b(r>>16,r>>8&255,r&255,e)}static rgb(...t){return b.from(...t).toMode("rgb")}static hsl(...t){return b.from(...t).toMode("hsl")}static hsb(...t){return b.from(...t).toMode("hsb")}static lab(...t){return b.from(...t).toMode("lab")}static lch(...t){return b.from(...t).toMode("lch")}static luv(...t){return b.from(...t).toMode("luv")}static xyz(...t){return b.from(...t).toMode("xyz")}static maxValues(t){return b.ranges[t].zipSlice(1).$take([0,1,2])}get hex(){return this.toString("hex")}get rgb(){return this.toString("rgb")}get rgba(){return this.toString("rgba")}clone(){let t=new b(this);return t.toMode(this._mode),t}toMode(t,e=!1){if(e){let r=this._mode.toUpperCase()+"to"+t.toUpperCase();if(b[r])this.to(b[r](this,this._isNorm,this._isNorm));else throw new Error("Cannot convert color with "+r)}return this._mode=t,this}get mode(){return this._mode}get r(){return this[0]}set r(t){this[0]=t}get g(){return this[1]}set g(t){this[1]=t}get b(){return this[2]}set b(t){this[2]=t}get h(){return this._mode=="lch"?this[2]:this[0]}set h(t){let e=this._mode=="lch"?2:0;this[e]=t}get s(){return this[1]}set s(t){this[1]=t}get l(){return this._mode=="hsl"?this[2]:this[0]}set l(t){let e=this._mode=="hsl"?2:0;this[e]=t}get a(){return this[1]}set a(t){this[1]=t}get c(){return this[1]}set c(t){this[1]=t}get u(){return this[1]}set u(t){this[1]=t}get v(){return this[2]}set v(t){this[2]=t}set alpha(t){this.length>3&&(this[3]=t)}get alpha(){return this.length>3?this[3]:1}get normalized(){return this._isNorm}set normalized(t){this._isNorm=t}normalize(t=!0){if(this._isNorm==t)return this;let e=b.ranges[this._mode];for(let r=0;r<3;r++)this[r]=t?v.mapToRange(this[r],e[r][0],e[r][1],0,1):v.mapToRange(this[r],0,1,e[r][0],e[r][1]);return this._isNorm=t,this}$normalize(t=!0){return this.clone().normalize(t)}toString(t="mode"){if(t=="hex"){let e=r=>{let i=Math.floor(r).toString(16);return i.length<2?"0"+i:i};return`#${e(this[0])}${e(this[1])}${e(this[2])}`}else return t=="rgba"?`rgba(${Math.floor(this[0])},${Math.floor(this[1])},${Math.floor(this[2])},${this.alpha})`:t=="rgb"?`rgb(${Math.floor(this[0])},${Math.floor(this[1])},${Math.floor(this[2])})`:`${this._mode}(${this[0]},${this[1]},${this[2]},${this.alpha})`}static RGBtoHSL(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=Math.max(i,s,o),u=Math.min(i,s,o),h=(l+u)/2,p=h,d=h;if(l==u)h=0,p=0;else{let f=l-u;p=d>.5?f/(2-l-u):f/(l+u),h=0,l===i?h=(s-o)/f+(s(d=d<0?d+1:d>1?d-1:d,d*6<1?u+(l-u)*d*6:d*2<1?l:d*3<2?u+(l-u)*(2/3-d)*6:u),p=r?1:255;return b.rgb(p*h(i+1/3),p*h(i),p*h(i-1/3),t.alpha)}static RGBtoHSB(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=Math.max(i,s,o),u=Math.min(i,s,o),h=l-u,p=0,d=l===0?0:h/l,f=l;return l!=u&&(l===i?p=(s-o)/h+(s.04045?Math.pow((i[o]+.055)/1.055,2.4):i[o]/12.92,r||(i[o]=i[o]*100);let s=b.xyz(i[0]*.4124564+i[1]*.3575761+i[2]*.1804375,i[0]*.2126729+i[1]*.7151522+i[2]*.072175,i[0]*.0193339+i[1]*.119192+i[2]*.9503041,t.alpha);return r?s.normalize():s}static XYZtoRGB(t,e=!1,r=!1){let[i,s,o]=e?t:t.$normalize(),l=[i*3.2406254773200533+s*-1.5372079722103187+o*-.4986285986982479,i*-.9689307147293197+s*1.8757560608852415+o*.041517523842953964,i*.055710120445510616+s*-.2040210505984867+o*1.0569959422543882];for(let h=0;h<3;h++)l[h]=l[h]>.0031308?1.055*Math.pow(l[h],1/2.4)-.055:12.92*l[h],l[h]=Math.max(0,Math.min(1,l[h])),r||(l[h]=Math.round(l[h]*255));let u=b.rgb(l[0],l[1],l[2],t.alpha);return r?u.normalize():u}static XYZtoLAB(t,e=!1,r=!1){let i=e?t.$normalize(!1):t.clone(),s=.00885645167,o=903.296296296;i.divide(b.D65);let l=p=>p>s?Math.pow(p,1/3):(o*p+16)/116,u=l(i[1]),h=b.lab(116*u-16,500*(l(i[0])-u),200*(u-l(i[2])),t.alpha);return r?h.normalize():h}static LABtoXYZ(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=(i[0]+16)/116,o=i[1]/500+s,l=s-i[2]/200,u=.00885645167,h=903.296296296,p=b.D65,d=Math.pow(o,3),f=Math.pow(l,3),P=b.xyz(p[0]*(d>u?d:(116*o-16)/h),p[1]*(i[0]>h*u?Math.pow((i[0]+16)/116,3):i[0]/h),p[2]*(f>u?f:(116*l-16)/h),t.alpha);return r?P.normalize():P}static XYZtoLUV(t,e=!1,r=!1){let[i,s,o]=e?t.$normalize(!1):t,l=4*i/(i+15*s+3*o),u=9*s/(i+15*s+3*o);s=s/100,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116;let h=4*b.D65[0]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),p=9*b.D65[1]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),d=116*s-16;return b.luv(d,13*d*(l-h),13*d*(u-p),t.alpha)}static LUVtoXYZ(t,e=!1,r=!1){let[i,s,o]=e?t.$normalize(!1):t,l=(i+16)/116,u=l*l*l;l=u>.008856?u:(l-16/116)/7.787;let h=4*b.D65[0]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]),p=9*b.D65[1]/(b.D65[0]+15*b.D65[1]+3*b.D65[2]);s=s/(13*i)+h,o=o/(13*i)+p,l=l*100;let d=-1*(9*l*s)/((s-4)*o-s*o),f=(9*l-15*o*l-o*d)/(3*o);return b.xyz(d,l,f,t.alpha)}static LABtoLCH(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=g.toDegree(g.boundRadian(Math.atan2(i[2],i[1])));return b.lch(i[0],Math.sqrt(i[1]*i[1]+i[2]*i[2]),s,t.alpha)}static LCHtoLAB(t,e=!1,r=!1){let i=e?t.$normalize(!1):t,s=g.toRadian(i[2]);return b.lab(i[0],Math.cos(s)*i[1],Math.sin(s)*i[1],t.alpha)}},lt=b;lt.D65=new a(95.047,100,108.883,1),lt.ranges={rgb:new c(new a(0,255),new a(0,255),new a(0,255)),hsl:new c(new a(0,360),new a(0,1),new a(0,1)),hsb:new c(new a(0,360),new a(0,1),new a(0,1)),lab:new c(new a(0,100),new a(-128,127),new a(-128,127)),lch:new c(new a(0,100),new a(0,100),new a(0,360)),luv:new c(new a(0,100),new a(-134,220),new a(-140,122)),xyz:new c(new a(0,100),new a(0,100),new a(0,100))};var Gt={};z(Gt,{DOMSpace:()=>B,HTMLForm:()=>tt,HTMLSpace:()=>U});var B=class extends Q{constructor(t,e){super();this.id="domspace";this._autoResize=!0;this._bgcolor="#e1e9f0";this._css={};var r=null,i=!1;this.id="pts",t instanceof Element?(r=t,this.id="pts_existing_space"):(r=document.querySelector(t),i=!0,this.id=t.substr(1)),r?(this._canvas=r,this._container=r.parentElement):(this._container=B.createElement("div","pts_container"),this._canvas=B.createElement("div","pts_element"),this._container.appendChild(this._canvas),document.body.appendChild(this._container),i=!1),setTimeout(this._ready.bind(this,e),50)}static createElement(t="div",e,r){let i=document.createElement(t);return e&&i.setAttribute("id",e),r&&r.appendChild&&r.appendChild(i),i}_ready(t){if(!this._container)throw new Error(`Cannot initiate #${this.id} element`);this._isReady=!0,this._resizeHandler(null),this.clear(this._bgcolor),this._canvas.dispatchEvent(new Event("ready"));for(let e in this.players)this.players.hasOwnProperty(e)&&this.players[e].start&&this.players[e].start(this.bound.clone(),this);this._pointer=this.center,this.refresh(!1),t&&t(this.bound,this._canvas)}setup(t){return t.bgcolor&&(this._bgcolor=t.bgcolor),this.autoResize=t.resize!=null?t.resize:!1,this}getForm(){return null}set autoResize(t){this._autoResize=t,t?window.addEventListener("resize",this._resizeHandler.bind(this)):(delete this._css.width,delete this._css.height,window.removeEventListener("resize",this._resizeHandler.bind(this)))}get autoResize(){return this._autoResize}resize(t,e){this.bound=t,this.styles({width:`${t.width}px`,height:`${t.height}px`},!0);for(let r in this.players)if(this.players.hasOwnProperty(r)){let i=this.players[r];i.resize&&i.resize(this.bound,e)}return this}_resizeHandler(t){let e=G.fromBoundingRect(this._container.getBoundingClientRect());this._autoResize?this.styles({width:"100%",height:"100%"},!0):this.styles({width:`${e.width}px`,height:`${e.height}px`},!0),this.resize(e,t)}get element(){return this._canvas}get parent(){return this._container}get ready(){return this._isReady}clear(t){return t&&(this.background=t),this._canvas.innerHTML="",this}set background(t){this._bgcolor=t,this._container.style.backgroundColor=this._bgcolor}get background(){return this._bgcolor}style(t,e,r=!1){return this._css[t]=e,r&&(this._canvas.style[t]=e),this}styles(t,e=!1){for(let r in t)t.hasOwnProperty(r)&&this.style(r,t[r],e);return this}static setAttr(t,e){for(let r in e)e.hasOwnProperty(r)&&t.setAttribute(r,e[r]);return t}static getInlineStyles(t){let e="";for(let r in t)t.hasOwnProperty(r)&&t[r]&&(e+=`${r}: ${t[r]}; `);return e}dispose(){return window.removeEventListener("resize",this._resizeHandler.bind(this)),this.stop(),this.removeAll(),this}},U=class extends B{getForm(){return new tt(this)}static htmlElement(n,t,e,r=!0){if(!n||!n.appendChild)throw new Error("parent is not a valid DOM element");let i=document.querySelector(`#${e}`);return i||(i=document.createElement(t),i.setAttribute("id",e),r&&i.setAttribute("class",e.substring(0,e.indexOf("-"))),n.appendChild(i)),i}remove(n){return this._container.querySelectorAll("."+tt.scopeID(n)).forEach(e=>{e.parentNode.removeChild(e)}),super.remove(n)}removeAll(){return this._container.innerHTML="",super.removeAll()}},$=class extends j{constructor(t){super();this._style={filled:!0,stroked:!0,background:"#f03","border-color":"#fff",color:"#000","border-width":"1px","border-radius":"0","border-style":"solid",opacity:1,position:"absolute",top:0,left:0,width:0,height:0};this._ctx={group:null,groupID:"pts",groupCount:0,currentID:"pts0",currentClass:"",style:{}};this._ready=!1;this._space=t,this._space.add({start:()=>{this._ctx.group=this._space.element,this._ctx.groupID="pts_dom_"+$.groupID++,this._ctx.style=Object.assign({},this._style),this._ready=!0}})}get space(){return this._space}styleTo(t,e,r=""){if(this._ctx.style[t]===void 0)throw new Error(`${t} style property doesn't exist`);this._ctx.style[t]=`${e}${r}`}alpha(t){return this.styleTo("opacity",t),this}fill(t){return typeof t=="boolean"?(this.styleTo("filled",t),t||this.styleTo("background","transparent")):(this.styleTo("filled",!0),this.styleTo("background",t)),this}stroke(t,e,r,i){return typeof t=="boolean"?(this.styleTo("stroked",t),t||this.styleTo("border-width",0)):(this.styleTo("stroked",!0),this.styleTo("border-color",t),this.styleTo("border-width",(e||1)+"px")),this}fillText(t){return this.styleTo("color",t),this}cls(t){return typeof t=="boolean"?this._ctx.currentClass="":this._ctx.currentClass=t,this}font(t,e,r,i,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),r&&(this._font.style=r),i&&(this._font.lineHeight=i)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new F(10,"sans-serif"),this._ctx.style.font=this._font.value,this}updateScope(t,e){return this._ctx.group=e,this._ctx.groupID=t,this._ctx.groupCount=0,this.nextID(),this._ctx}scope(t){if(!t||t.animateID==null)throw new Error("item not defined or not yet added to Space");return this.updateScope($.scopeID(t),this.space.element)}nextID(){return this._ctx.groupCount++,this._ctx.currentID=`${this._ctx.groupID}-${this._ctx.groupCount}`,this._ctx.currentID}static getID(t){return t.currentID||`p-${$.domID++}`}static scopeID(t){return`item-${t.animateID}`}static style(t,e){let r=[];e.filled||r.push("background: none"),e.stroked||r.push("border: none");for(let i in e)if(e.hasOwnProperty(i)&&i!="filled"&&i!="stroked"){let s=e[i];if(s){if(!e.filled&&i.indexOf("background")===0)continue;if(!e.stroked&&i.indexOf("border-width")===0)continue;r.push(`${i}: ${s}`)}}return U.setAttr(t,{style:r.join(";")})}static rectStyle(t,e,r){return t.style.left=e[0]+"px",t.style.top=e[1]+"px",t.style.width=r[0]+"px",t.style.height=r[1]+"px",t}static textStyle(t,e){return t.style.left=e[0]+"px",t.style.top=e[1]+"px",t}static point(t,e,r=5,i="square"){return i==="circle"?$.circle(t,e,r):$.square(t,e,r)}point(t,e=5,r="square"){return this.nextID(),r=="circle"&&this.styleTo("border-radius","100%"),$.point(this._ctx,t,e,r),this}static circle(t,e,r=10){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-circle ${t.currentClass}`}),$.rectStyle(t,new a(e).$subtract(r),new a(r*2,r*2)),$.style(i,t.style),i}circle(t){return this.nextID(),this.styleTo("border-radius","100%"),$.circle(this._ctx,t[0],t[1][0]),this}static square(t,e,r){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-square ${t.currentClass}`}),$.rectStyle(t,new a(e).$subtract(r),new a(r*2,r*2)),$.style(i,t.style),i}square(t,e){return this.nextID(),$.square(this._ctx,t,e),this}static rect(t,e){let r=m.iterToArray(e);if(!m.arrayCheck(r))return;let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-rect ${t.currentClass}`}),$.rectStyle(t,r[0],r[1]),$.style(i,t.style),i}rect(t){return this.nextID(),this.styleTo("border-radius","0"),$.rect(this._ctx,t),this}static text(t,e,r){let i=U.htmlElement(t.group,"div",$.getID(t));return U.setAttr(i,{class:`pts-form pts-text ${t.currentClass}`}),i.textContent=r,$.textStyle(t,e),$.style(i,t.style),i}text(t,e){return this.nextID(),$.text(this._ctx,t,e),this}log(t){return this.fill("#000").stroke("#fff",.5).text([10,14],t),this}arc(t,e,r,i,s){return m.warn("arc is not implemented in HTMLForm"),this}line(t){return m.warn("line is not implemented in HTMLForm"),this}polygon(t){return m.warn("polygon is not implemented in HTMLForm"),this}},tt=$;tt.groupID=0,tt.domID=0;var St={};z(St,{SVGForm:()=>et,SVGSpace:()=>H});var H=class extends B{constructor(t,e){super(t,e);this._bgcolor="#999";if(this._canvas.nodeName.toLowerCase()!="svg"){let r=H.svgElement(this._canvas,"svg",`${this.id}_svg`);this._container=this._canvas,this._canvas=r}}getForm(){return new et(this)}get element(){return this._canvas}resize(t,e){return super.resize(t,e),H.setAttr(this.element,{viewBox:`0 0 ${this.bound.width} ${this.bound.height}`,width:`${this.bound.width}`,height:`${this.bound.height}`,xmlns:"http://www.w3.org/2000/svg",version:"1.1"}),this}static svgElement(t,e,r){if(!t||!t.appendChild)throw new Error("parent is not a valid DOM element");let i=document.querySelector(`#${r}`);return i||(i=document.createElementNS("http://www.w3.org/2000/svg",e),i.setAttribute("id",r),t.appendChild(i)),i}remove(t){return this._container.querySelectorAll("."+et.scopeID(t)).forEach(r=>{r.parentNode.removeChild(r)}),super.remove(t)}removeAll(){return this._container.innerHTML="",super.removeAll()}},I=class extends j{constructor(t){super();this._style={filled:!0,stroked:!0,fill:"#f03",stroke:"#fff","stroke-width":1,"stroke-linejoin":"bevel","stroke-linecap":"sqaure",opacity:1};this._ctx={group:null,groupID:"pts",groupCount:0,currentID:"pts0",currentClass:"",style:{}};this._ready=!1;this._space=t,this._space.add({start:()=>{this._ctx.group=this._space.element,this._ctx.groupID="pts_svg_"+I.groupID++,this._ctx.style=Object.assign({},this._style),this._ready=!0}})}get space(){return this._space}styleTo(t,e){if(this._ctx.style[t]===void 0)throw new Error(`${t} style property doesn't exist`);this._ctx.style[t]=e}alpha(t){return this.styleTo("opacity",t),this}fill(t){return typeof t=="boolean"?this.styleTo("filled",t):(this.styleTo("filled",!0),this.styleTo("fill",t)),this}stroke(t,e,r,i){return typeof t=="boolean"?this.styleTo("stroked",t):(this.styleTo("stroked",!0),this.styleTo("stroke",t),e&&this.styleTo("stroke-width",e),r&&this.styleTo("stroke-linejoin",r),i&&this.styleTo("stroke-linecap",i)),this}cls(t){return typeof t=="boolean"?this._ctx.currentClass="":this._ctx.currentClass=t,this}font(t,e,r,i,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),r&&(this._font.style=r),i&&(this._font.lineHeight=i)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new F(10,"sans-serif"),this._ctx.style.font=this._font.value,this}updateScope(t,e){return this._ctx.group=e,this._ctx.groupID=t,this._ctx.groupCount=0,this.nextID(),this._ctx}scope(t){if(!t||t.animateID==null)throw new Error("item not defined or not yet added to Space");return this.updateScope(I.scopeID(t),this.space.element)}nextID(){return this._ctx.groupCount++,this._ctx.currentID=`${this._ctx.groupID}-${this._ctx.groupCount}`,this._ctx.currentID}static getID(t){return t.currentID||`p-${I.domID++}`}static scopeID(t){return`item-${t.animateID}`}static style(t,e){let r=[];e.filled||r.push("fill: none"),e.stroked||r.push("stroke: none");for(let i in e)if(e.hasOwnProperty(i)&&i!="filled"&&i!="stroked"){let s=e[i];if(s){if(!e.filled&&i.indexOf("fill")===0)continue;if(!e.stroked&&i.indexOf("stroke")===0)continue;r.push(`${i}: ${s}`)}}return B.setAttr(t,{style:r.join(";")})}static point(t,e,r=5,i="square"){return i==="circle"?I.circle(t,e,r):I.square(t,e,r)}point(t,e=5,r="square"){return this.nextID(),I.point(this._ctx,t,e,r),this}static circle(t,e,r=10){let i=H.svgElement(t.group,"circle",I.getID(t));return B.setAttr(i,{cx:e[0],cy:e[1],r,class:`pts-svgform pts-circle ${t.currentClass}`}),I.style(i,t.style),i}circle(t){this.nextID();let e=m.iterToArray(t);return I.circle(this._ctx,e[0],e[1][0]),this}static arc(t,e,r,i,s,o){let l=H.svgElement(t.group,"path",I.getID(t)),u=new a(e).toAngle(i,r,!0),h=new a(e).toAngle(s,r,!0),d=g.boundAngle(s)-g.boundAngle(i)>L.pi;o&&(d=!d);let f=o?"0":"1",P=`M ${u[0]} ${u[1]} A ${r} ${r} 0 ${d?"1":"0"} ${f} ${h[0]} ${h[1]}`;return B.setAttr(l,{d:P,class:`pts-svgform pts-arc ${t.currentClass}`}),I.style(l,t.style),l}arc(t,e,r,i,s){return this.nextID(),I.arc(this._ctx,t,e,r,i,s),this}static square(t,e,r){let i=H.svgElement(t.group,"rect",I.getID(t));return B.setAttr(i,{x:e[0]-r,y:e[1]-r,width:r*2,height:r*2,class:`pts-svgform pts-square ${t.currentClass}`}),I.style(i,t.style),i}square(t,e){return this.nextID(),I.square(this._ctx,t,e),this}static line(t,e){let r=I.pointsString(e);if(r.count<2)return;if(r.count>2)return I._poly(t,r.string,!1);let i=H.svgElement(t.group,"line",I.getID(t)),s=m.iterToArray(e);return B.setAttr(i,{x1:s[0][0],y1:s[0][1],x2:s[1][0],y2:s[1][1],class:`pts-svgform pts-line ${t.currentClass}`}),I.style(i,t.style),i}line(t){return this.nextID(),I.line(this._ctx,t),this}static _poly(t,e,r=!0){let i=H.svgElement(t.group,r?"polygon":"polyline",I.getID(t));return B.setAttr(i,{points:e,class:`pts-svgform pts-polygon ${t.currentClass}`}),I.style(i,t.style),i}static pointsString(t){let e="",r=0;for(let i of t)e+=`${i[0]},${i[1]} `,r++;return{string:e,count:r}}static polygon(t,e){let r=I.pointsString(e);return I._poly(t,r.string,!0)}polygon(t){return this.nextID(),I.polygon(this._ctx,t),this}static rect(t,e){if(!m.arrayCheck(e))return;let r=H.svgElement(t.group,"rect",I.getID(t)),i=c.fromArray(e).boundingBox(),s=k.size(i);return B.setAttr(r,{x:i[0][0],y:i[0][1],width:s[0],height:s[1],class:`pts-svgform pts-rect ${t.currentClass}`}),I.style(r,t.style),r}rect(t){return this.nextID(),I.rect(this._ctx,t),this}static text(t,e,r){let i=H.svgElement(t.group,"text",I.getID(t));return B.setAttr(i,{"pointer-events":"none",x:e[0],y:e[1],dx:0,dy:0,class:`pts-svgform pts-text ${t.currentClass}`}),i.textContent=r,I.style(i,t.style),i}text(t,e){return this.nextID(),I.text(this._ctx,t,e),this}log(t){return this.fill("#000").stroke("#fff",.5).text([10,14],t),this}},et=I;et.groupID=0,et.domID=0;var zt={};z(zt,{Body:()=>st,Particle:()=>bt,World:()=>rt});var rt=class{constructor(n,t=1,e=0){this._lastTime=null;this._gravity=new a;this._friction=1;this._damping=.75;this._particles=[];this._bodies=[];this._pnames=[];this._bnames=[];return this._bound=G.fromGroup(n),this._friction=t,this._gravity=typeof e=="number"?new a(0,e):new a(e),this}get bound(){return this._bound}set bound(n){this._bound=n}get gravity(){return this._gravity}set gravity(n){this._gravity=n}get friction(){return this._friction}set friction(n){this._friction=n}get damping(){return this._damping}set damping(n){this._damping=n}get bodyCount(){return this._bodies.length}get particleCount(){return this._particles.length}body(n){let t=n;if(typeof n=="string"&&n.length>0&&(t=this._bnames.indexOf(n)),t>=0)return this._bodies[t]}particle(n){let t=n;if(typeof n=="string"&&n.length>0&&(t=this._pnames.indexOf(n)),t>=0)return this._particles[t]}bodyIndex(n){return this._bnames.indexOf(n)}particleIndex(n){return this._pnames.indexOf(n)}update(n){let t=n/1e3;this._updateParticles(t),this._updateBodies(t)}drawParticles(n){this._drawParticles=n}drawBodies(n){this._drawBodies=n}add(n,t=""){return n instanceof st?(this._bodies.push(n),this._bnames.push(t)):(this._particles.push(n),this._pnames.push(t)),this}_index(n,t){let e=0;if(typeof t=="string"){if(e=n(t),e<0)throw new Error(`Cannot find index of ${t}. You can use particleIndex() or bodyIndex() function to check existence by name.`)}else e=t;return e}removeBody(n,t=1){let e=this._index(this.bodyIndex.bind(this),n),r=e<0?[e*-1-1,t]:[e,t];return this._bodies.splice(r[0],r[1]),this._bnames.splice(r[0],r[1]),this}removeParticle(n,t=1){let e=this._index(this.particleIndex.bind(this),n),r=e<0?[e*-1-1,t]:[e,t];return this._particles.splice(r[0],r[1]),this._pnames.splice(r[0],r[1]),this}static edgeConstraint(n,t,e,r=1,i=!1){let s=1/(n.mass||1),o=1/(t.mass||1),l=s+o,u=t.$subtract(n),h=e*e,p=i?e/u.magnitude()-1:h/(u.dot(u)+h)-.5,d=u.$multiply(p*r);return n.subtract(d.$multiply(s/l)),t.add(d.$multiply(o/l)),n}static boundConstraint(n,t,e=.75){let r=g.boundingBox(t),i=n.$min(r[1].subtract(n.radius)).$max(r[0].add(n.radius));if(i[0]===r[0][0]||i[0]===r[1][0]){let s=n.changed.$multiply(e);n.previous=i.$subtract(new a(-s[0],s[1]))}else if(i[1]===r[0][1]||i[1]===r[1][1]){let s=n.changed.$multiply(e);n.previous=i.$subtract(new a(s[0],-s[1]))}n.to(i)}integrate(n,t,e){return n.addForce(this._gravity),n.verlet(t,this._friction,e),n}_updateParticles(n){for(let t=0,e=this._particles.length;t=this.length)throw new Error("index1 is not in the Group's indices");if(e<0||e>=this.length)throw new Error("index1 is not in the Group's indices");let i=this[t].$subtract(this[e]).magnitude();return this._cs.push([t,e,i,r||this._stiff]),this}linkAll(t){let e=this.length/2;for(let r=0,i=this.length;r=i-1?0:r+1;if(this.link(r,s,t),i>4){let o=Math.floor(e/2)+1,l=r>=i-o?r%i:r+o;this.link(r,l,t)}r<=e-1&&this.link(r,Math.min(this.length-1,r+Math.floor(e)))}}linksToLines(){let t=[];for(let e=0,r=this._cs.length;eMath.abs(l[0][1]-l[1][1])?o=(i.vertex[0]-s[0]-l[0][0])/(l[1][0]-l[0][0]):o=(i.vertex[1]-s[1]-l[0][1])/(l[1][1]-l[0][1]);let u=1/(o*o+(1-o)*(1-o)),h=i.vertex.body.mass||1,p=i.edge[0].body.mass||1,d=h/(h+p),f=p/(h+p);l[0].subtract(s.$multiply(d*(1-o)*u/2)),l[1].subtract(s.$multiply(d*o*u/2)),i.vertex.add(s.$multiply(f))}}processParticle(t){let e=this,r=t,i=M.hasIntersectCircle(e,O.fromCenter(t,t.radius));if(i){let s=i.normal.$multiply(i.dist),o,l=i.edge;Math.abs(l[0][0]-l[1][0])>Math.abs(l[0][1]-l[1][1])?o=(i.vertex[0]-s[0]-l[0][0])/(l[1][0]-l[0][0]):o=(i.vertex[1]-s[1]-l[0][1])/(l[1][1]-l[0][1]);let u=1/(o*o+(1-o)*(1-o)),h=i.vertex.mass||r.mass||1,p=i.edge[0].body.mass||1,d=h/(h+p),f=p/(h+p);l[0].subtract(s.$multiply(d*(1-o)*u/2)),l[1].subtract(s.$multiply(d*o*u/2));let P=t.changed.add(s.$multiply(f));t.previous=t.$subtract(P)}}};var Bt={};z(Bt,{Sound:()=>V,Tempo:()=>at});var at=class{constructor(n){this._listeners={};this._listenerInc=0;this.bpm=n}static fromBeat(n){return new at(6e4/n)}get bpm(){return this._bpm}set bpm(n){this._bpm=n,this._ms=6e4/this._bpm}get ms(){return this._ms}set ms(n){this._bpm=Math.floor(6e4/n),this._ms=6e4/this._bpm}_createID(n){let t="";return typeof n=="function"?t="_b"+this._listenerInc++:t=n.name||"_b"+this._listenerInc++,t}every(n){let t=this,e=Array.isArray(n)?n[0]:n;return{start:function(r,i=0,s){let o=s||t._createID(r);return t._listeners[o]={name:o,beats:n,period:e,index:0,offset:i,duration:-1,continuous:!1,fn:r},this},progress:function(r,i=0,s){let o=s||t._createID(r);return t._listeners[o]={name:o,beats:n,period:e,index:0,offset:i,duration:-1,continuous:!0,fn:r},this}}}track(n){for(let t in this._listeners)if(this._listeners.hasOwnProperty(t)){let e=this._listeners[t],r=e.offset?n+e.offset:n,i=e.period*this._ms,s=!1;r>e.duration+i&&(e.duration=r-r%this._ms,Array.isArray(e.beats)&&(e.index=(e.index+1)%e.beats.length,e.period=e.beats[e.index]),s=!0);let o=Math.max(0,Math.ceil(Math.floor(e.duration/this._ms)/e.period)),l=e.continuous?[o,v.clamp((r-e.duration)/i,0,1),r,s]:[o];(e.continuous||s)&&e.fn.apply(e,l)&&delete this._listeners[e.name]}}stop(n){this._listeners[n]&&delete this._listeners[n]}animate(n,t){this.track(n)}resize(n,t){}action(n,t,e,r){}},V=class{constructor(n){this._playing=!1;this._type=n;let t=window.AudioContext||window.webkitAudioContext||!1;if(!t)throw new Error("Your browser doesn't support Web Audio. (No AudioContext)");this._ctx=t?new t:void 0}static from(n,t,e="gen",r){let i=new V(e);return i._node=n,i._ctx=t,r&&(i._stream=r),i}static load(n,t="anonymous"){return new Promise((e,r)=>{let i=new V("file");i._source=typeof n=="string"?new Audio(n):n,i._source.autoplay=!1,i._source.crossOrigin=t,i._source.addEventListener("ended",function(){i._playing=!1}),i._source.addEventListener("error",function(){r("Error loading sound")}),i._source.addEventListener("canplaythrough",function(){i._node=i._ctx.createMediaElementSource(i._source),e(i)})})}static loadAsBuffer(n){return new Promise((t,e)=>{let r=new XMLHttpRequest;r.open("GET",n,!0),r.responseType="arraybuffer";let i=new V("file");r.onload=function(){i._ctx.decodeAudioData(r.response,function(s){i.createBuffer(s),t(i)},s=>e("Error decoding audio"))},r.send()})}createBuffer(n){return this._node=this._ctx.createBufferSource(),n!==void 0&&(this._buffer=n),this._node.buffer=this._buffer,this._node.onended=()=>{this._playing=!1},this}static generate(n,t){return new V("gen")._gen(n,t)}_gen(n,t){this._node=this._ctx.createOscillator();let e=this._node;return e.type=n,n==="custom"?e.setPeriodicWave(t):e.frequency.value=t,this}static async input(n){try{let t=new V("input");if(!t)return;let e=n||{audio:!0,video:!1};return t._stream=await navigator.mediaDevices.getUserMedia(e),t._node=t._ctx.createMediaStreamSource(t._stream),t}catch{return console.error("Cannot get audio from input device."),Promise.resolve(null)}}get ctx(){return this._ctx}get node(){return this._node}get outputNode(){return this._outputNode}get stream(){return this._stream}get source(){return this._source}get buffer(){return this._buffer}set buffer(n){this._buffer=n}get type(){return this._type}get playing(){return this._playing}get progress(){let n=0,t=0;return this._buffer?(n=this._buffer.duration,t=this._timestamp?this._ctx.currentTime-this._timestamp:0):(n=this._source.duration,t=this._source.currentTime),t/n}get playable(){return this._type==="input"?this._node!==void 0:!!this._buffer||this._source.readyState===4}get binSize(){return this.analyzer.size}get sampleRate(){return this._ctx.sampleRate}get frequency(){return this._type==="gen"?this._node.frequency.value:0}set frequency(n){this._type==="gen"&&(this._node.frequency.value=n)}connect(n){return this._node.connect(n),this}setOutputNode(n){return this._outputNode=n,this}removeOutputNode(){return this._outputNode=null,this}analyze(n=256,t=-100,e=-30,r=.8){let i=this._ctx.createAnalyser();return i.fftSize=n*2,i.minDecibels=t,i.maxDecibels=e,i.smoothingTimeConstant=r,this.analyzer={node:i,size:i.frequencyBinCount,data:new Uint8Array(i.frequencyBinCount)},this._node.connect(this.analyzer.node),this}_domain(n){return this.analyzer?(n?this.analyzer.node.getByteTimeDomainData(this.analyzer.data):this.analyzer.node.getByteFrequencyData(this.analyzer.data),this.analyzer.data):new Uint8Array(0)}_domainTo(n,t,e=[0,0],r=[0,0]){let i=n?this.timeDomain():this.freqDomain(),s=new c;for(let o=r[0],l=i.length-r[1];o0&&(this._source.currentTime=n)):this._type==="gen"&&(this._gen(this._node.type,this._node.frequency.value),this._node.start(),this.analyzer&&this._node.connect(this.analyzer.node)),(this._outputNode||this._node).connect(this._ctx.destination),this._playing=!0,this}stop(){return this._playing&&(this._outputNode||this._node).disconnect(this._ctx.destination),this._type==="file"?this._buffer?this.progress<1&&this._node.stop():this._source.pause():this._type==="gen"?this._node.stop():this._type==="input"&&this._stream.getAudioTracks().forEach(n=>n.stop()),this._playing=!1,this}toggle(){return this._playing?this.stop():this.start(),this}};globalThis.Pts={...At,...Tt,...Mt,..._t,...wt,...yt,...kt,...It,...Et,...xt,...Gt,...St,...Ct,...zt,...Lt,...Bt,...Dt};globalThis.Pts.namespace=x=>{let n=globalThis.Pts;for(let t in n)t!="namespace"&&(x[t]=n[t])};globalThis.Pts.quickStart=(x,n="#9ab")=>{if(!window)return;let t=globalThis;return globalThis.Pts.namespace(t),t.space=new ot(x).setup({bgcolor:n,resize:!0,retina:!0}),t.form=t.space.getForm(),function(e=null,r=null,i=null,s=null){t.space.add({start:r,animate:e,resize:s,action:i}),t.space.bindMouse().bindTouch().play()}};})(); /*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */ //# sourceMappingURL=pts.min.js.map \ No newline at end of file diff --git a/dist/pts.min.js.map b/dist/pts.min.js.map index 43b61845..df7cf46b 100644 --- a/dist/pts.min.js.map +++ b/dist/pts.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/Canvas.ts","../src/Space.ts","../src/Pt.ts","../src/Util.ts","../src/Num.ts","../src/Op.ts","../src/LinearAlgebra.ts","../src/uheprng.ts","../src/UI.ts","../src/Form.ts","../src/Typography.ts","../src/Image.ts","../src/Create.ts","../src/Color.ts","../src/Dom.ts","../src/Svg.ts","../src/Physics.ts","../src/Play.ts","../src/_script.ts"],"sourcesContent":["/*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */\r\n\r\nimport {MultiTouchSpace} from './Space';\r\nimport {VisualForm, Font} from \"./Form\";\r\nimport {Pt, Group, Bound} from \"./Pt\";\r\nimport {Const, Util} from \"./Util\";\r\nimport {Typography as Typo} from \"./Typography\";\r\nimport { Rectangle } from './Op';\r\nimport {Img} from './Image';\r\nimport {PtLike, GroupLike, PtsCanvasRenderingContext2D, DefaultFormStyle, PtLikeIterable, PtIterable, CanvasSpaceOptions} from \"./Types\";\r\n\r\n\r\n\r\n\r\n/**\r\n* CanvasSpace is an implementation of the abstract class [`Space`](#link). It represents a space for HTML Canvas.\r\n* Learn more about the concept of Space in [this guide](../guide/Space-0500.html).\r\n*/\r\nexport class CanvasSpace extends MultiTouchSpace {\r\n \r\n protected _canvas:HTMLCanvasElement;\r\n protected _container:Element;\r\n\r\n protected _pixelScale = 1;\r\n protected _autoResize = true;\r\n protected _bgcolor = \"#e1e9f0\";\r\n protected _ctx:PtsCanvasRenderingContext2D;\r\n \r\n protected _offscreen = false;\r\n protected _offCanvas:HTMLCanvasElement;\r\n protected _offCtx:PtsCanvasRenderingContext2D;\r\n\r\n protected _initialResize = false;\r\n \r\n\r\n \r\n /**\r\n * Create a CanvasSpace which represents a HTML Canvas Space\r\n * @param elem Specify an element by its \"id\" attribute as string, or by the element object itself. An element can be an existing ``, or a `
` container in which a new `` will be created. If left empty, a `
` will be added to DOM. Use css to customize its appearance if needed.\r\n * @param callback an optional callback `function(boundingBox, spaceElement)` to be called when canvas is appended and ready. Alternatively, a \"ready\" event will also be fired from the `` element when it's appended, which can be traced with `spaceInstance.canvas.addEventListener(\"ready\")`\r\n * @example `new CanvasSpace( \"#myElementID\" )`\r\n */\r\n constructor( elem:string|Element, callback?:Function) {\r\n super();\r\n \r\n var _selector:Element = null;\r\n var _existed = false;\r\n this.id = \"pt\";\r\n \r\n // check element or element id string\r\n if ( elem instanceof Element ) {\r\n _selector = elem;\r\n this.id = \"pts_existing_space\";\r\n } else {\r\n let id = elem;\r\n id = (elem[0] === \"#\" || elem[0] === \".\") ? elem : \"#\"+elem;\r\n _selector = document.querySelector( id );\r\n _existed = true;\r\n this.id = id.substr(1);\r\n }\r\n \r\n // if selector is not defined, create a canvas\r\n if (!_selector) { \r\n this._container = this._createElement( \"div\", this.id+\"_container\" );\r\n this._canvas = this._createElement( \"canvas\", this.id ) as HTMLCanvasElement;\r\n this._container.appendChild( this._canvas );\r\n document.body.appendChild( this._container );\r\n _existed = false;\r\n \r\n // if selector is element but not canvas, create a canvas inside it\r\n } else if (_selector.nodeName.toLowerCase() != \"canvas\") { \r\n this._container = _selector;\r\n this._canvas = this._createElement( \"canvas\", this.id+\"_canvas\" ) as HTMLCanvasElement;\r\n this._container.appendChild( this._canvas );\r\n this._initialResize = true;\r\n \r\n // if selector is an existing canvas\r\n } else {\r\n this._canvas = _selector as HTMLCanvasElement;\r\n this._container = _selector.parentElement;\r\n this._autoResize = false;\r\n }\r\n \r\n // if size is known then set it immediately\r\n // if (_existed) {\r\n // let b = this._container.getBoundingClientRect();\r\n // this.resize( Bound.fromBoundingRect(b) );\r\n // }\r\n \r\n // no mutation observer, so we set a timeout for ready event\r\n setTimeout( this._ready.bind( this, callback ), 100 );\r\n \r\n // store canvas 2d rendering context\r\n this._ctx = this._canvas.getContext('2d');\r\n \r\n }\r\n \r\n \r\n /**\r\n * Helper function to create a DOM element\r\n * @param elem element tag name\r\n * @param id element id attribute\r\n */\r\n protected _createElement( elem=\"div\", id ) {\r\n let d = document.createElement( elem );\r\n d.setAttribute(\"id\", id);\r\n return d;\r\n }\r\n \r\n \r\n /**\r\n * Handle callbacks after element is mounted in DOM\r\n * @param callback \r\n */\r\n private _ready( callback:Function ) {\r\n if (!this._container) throw new Error(`Cannot initiate #${this.id} element`);\r\n \r\n this._isReady = true;\r\n \r\n this._resizeHandler( null );\r\n\r\n this.clear( this._bgcolor );\r\n this._canvas.dispatchEvent( new Event(\"ready\") );\r\n \r\n for (let k in this.players) {\r\n if (this.players.hasOwnProperty(k)) {\r\n if (this.players[k].start) this.players[k].start( this.bound.clone(), this );\r\n }\r\n }\r\n \r\n this._pointer = this.center;\r\n this._initialResize = false; // unset\r\n \r\n if (callback) callback( this.bound, this._canvas );\r\n }\r\n \r\n \r\n /**\r\n * Set up various options for CanvasSpace. The `opt` parameter is an object with the following fields. This is usually set during instantiation, eg `new CanvasSpace(...).setup( { opt } )`\r\n * @param opt a [`CanvasSpaceOptions`](#link) object with optional settings, ie `{ bgcolor:string, resize:boolean, retina:boolean, offscreen:boolean, pixelDensity:number }`. \r\n * @example `space.setup({ bgcolor: \"#f00\", retina: true, resize: true })`\r\n */\r\n setup( opt:CanvasSpaceOptions ):this {\r\n this._bgcolor = opt.bgcolor ? opt.bgcolor : \"transparent\";\r\n \r\n this.autoResize = (opt.resize != undefined) ? opt.resize : false;\r\n \r\n if (opt.retina !== false) {\r\n let r1 = window ? window.devicePixelRatio || 1 : 1;\r\n let r2 = this._ctx.webkitBackingStorePixelRatio || this._ctx.mozBackingStorePixelRatio || this._ctx.msBackingStorePixelRatio || this._ctx.oBackingStorePixelRatio || this._ctx.backingStorePixelRatio || 1; \r\n this._pixelScale = Math.max(1, r1/r2);\r\n }\r\n \r\n if (opt.offscreen) {\r\n this._offscreen = true;\r\n this._offCanvas = this._createElement( \"canvas\", this.id+\"_offscreen\" ) as HTMLCanvasElement;\r\n this._offCtx = this._offCanvas.getContext('2d');\r\n } else {\r\n this._offscreen = false;\r\n }\r\n\r\n if (opt.pixelDensity) {\r\n this._pixelScale = opt.pixelDensity;\r\n }\r\n \r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Set whether the canvas element should resize when its container is resized. \r\n * @param auto a boolean value indicating if auto size is set\r\n */\r\n set autoResize( auto ) {\r\n if (!window) return;\r\n this._autoResize = auto;\r\n if (auto) {\r\n window.addEventListener( 'resize', this._resizeHandler.bind(this) );\r\n } else {\r\n window.removeEventListener( 'resize', this._resizeHandler.bind(this) );\r\n }\r\n }\r\n get autoResize(): boolean { return this._autoResize; }\r\n \r\n \r\n /**\r\n * This overrides Space's `resize` function. It's used as a callback function for window's resize event and not usually called directly. You can keep track of resize events with `resize: (bound ,evt)` callback in your player objects. \r\n * @param b a Bound object to resize to\r\n * @param evt Optionally pass a resize event\r\n * @see Space.add\r\n */\r\n resize( b:Bound, evt?:Event):this {\r\n \r\n this.bound = b;\r\n\r\n this._canvas.width = Math.ceil(this.bound.size.x) * this._pixelScale;\r\n this._canvas.height = Math.ceil(this.bound.size.y) * this._pixelScale;\r\n this._canvas.style.width = Math.ceil(this.bound.size.x) + \"px\";\r\n this._canvas.style.height = Math.ceil(this.bound.size.y) + \"px\";\r\n \r\n if (this._offscreen) {\r\n this._offCanvas.width = Math.ceil(this.bound.size.x) * this._pixelScale;\r\n this._offCanvas.height = Math.ceil(this.bound.size.y) * this._pixelScale;\r\n // this._offCanvas.style.width = Math.floor(this.bound.size.x) + \"px\";\r\n // this._offCanvas.style.height = Math.floor(this.bound.size.y) + \"px\";\r\n }\r\n \r\n if (this._pixelScale != 1) {\r\n this._ctx.scale( this._pixelScale, this._pixelScale );\r\n \r\n if (this._offscreen) {\r\n this._offCtx.scale( this._pixelScale, this._pixelScale );\r\n }\r\n }\r\n \r\n for (let k in this.players) {\r\n if (this.players.hasOwnProperty(k)) {\r\n let p = this.players[k];\r\n if (p.resize) p.resize( this.bound, evt);\r\n }\r\n }\r\n \r\n this.render( this._ctx );\r\n\r\n // if it's a valid resize event and space is not playing, repaint the canvas once\r\n if (evt && !this.isPlaying) this.playOnce( 0 ); \r\n \r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Window resize handling\r\n * @param evt \r\n */\r\n protected _resizeHandler( evt:Event ) {\r\n if (!window) return;\r\n let b = (this._autoResize || this._initialResize) ? this._container.getBoundingClientRect() : this._canvas.getBoundingClientRect();\r\n\r\n if (b) {\r\n let box = Bound.fromBoundingRect(b);\r\n \r\n // Need to compute offset from window scroll. See outerBound calculation in Space's _mouseAction \r\n box.center = box.center.add( window.pageXOffset, window.pageYOffset ); \r\n this.resize( box, evt );\r\n }\r\n }\r\n \r\n\r\n /**\r\n * Set a background color for this canvas. Alternatively, you may use `clear()` function.\r\n @param bg background color as hex or rgba string\r\n */\r\n set background( bg:string ) { this._bgcolor = bg; }\r\n get background():string { return this._bgcolor; }\r\n\r\n \r\n /**\r\n * `pixelScale` property returns a number that let you determine if the screen is \"retina\" (when value >= 2)\r\n */\r\n public get pixelScale():number {\r\n return this._pixelScale;\r\n }\r\n \r\n \r\n /**\r\n * Check if an offscreen canvas is created\r\n */\r\n public get hasOffscreen():boolean {\r\n return this._offscreen;\r\n }\r\n \r\n \r\n /**\r\n * Get the rendering context of offscreen canvas (if created via `setup()`)\r\n */\r\n public get offscreenCtx():PtsCanvasRenderingContext2D { return this._offCtx; }\r\n \r\n \r\n /**\r\n * Get the offscreen canvas element\r\n */\r\n public get offscreenCanvas():HTMLCanvasElement { return this._offCanvas; }\r\n \r\n \r\n\r\n \r\n /**\r\n * Get a new `CanvasForm` for drawing\r\n * @see `CanvasForm`\r\n */\r\n public getForm():CanvasForm { return new CanvasForm(this); }\r\n \r\n \r\n /**\r\n * Get the html canvas element\r\n */\r\n get element():HTMLCanvasElement {\r\n return this._canvas;\r\n }\r\n \r\n \r\n /**\r\n * Get the parent element that contains the canvas element\r\n */\r\n get parent():Element {\r\n return this._container;\r\n }\r\n\r\n\r\n /**\r\n * A property to indicate if the Space is ready\r\n */\r\n get ready():boolean { \r\n return this._isReady; \r\n }\r\n \r\n \r\n /**\r\n * Get the rendering context of canvas\r\n * @example `form.ctx.clip()`\r\n */\r\n public get ctx():PtsCanvasRenderingContext2D { return this._ctx; }\r\n \r\n \r\n \r\n /**\r\n * Clear the canvas with its background color. Overrides Space's `clear` function.\r\n * @param bg Optionally specify a custom background color in hex or rgba string, or \"transparent\". If not defined, it will use its `bgcolor` property as background color to clear the canvas.\r\n */\r\n clear( bg?:string ):this {\r\n \r\n if (bg) this._bgcolor = bg;\r\n const lastColor = this._ctx.fillStyle;\r\n const px = Math.ceil(this.pixelScale);\r\n \r\n if (!this._bgcolor || this._bgcolor === \"transparent\") {\r\n this._ctx.clearRect( -px, -px, this._canvas.width+px, this._canvas.height+px );\r\n } else { \r\n // semi-transparent bg needs to be cleared first\r\n if (this._bgcolor.indexOf(\"rgba\") === 0 || (this._bgcolor.length === 9 && this._bgcolor.indexOf(\"#\") === 0) ) { \r\n this._ctx.clearRect( -px, -px, this._canvas.width+px, this._canvas.height+px );\r\n }\r\n this._ctx.fillStyle = this._bgcolor;\r\n this._ctx.fillRect( -px, -px, this._canvas.width+px, this._canvas.height+px );\r\n }\r\n \r\n this._ctx.fillStyle = lastColor;\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Similiar to `clear()` but clear the offscreen canvas instead\r\n * @param bg Optionally specify a custom background color in hex or rgba string, or \"transparent\". If not defined, it will use its `bgcolor` property as background color to clear the canvas.\r\n */\r\n clearOffscreen( bg?:string ):this {\r\n if (this._offscreen) {\r\n const px = Math.ceil(this.pixelScale);\r\n if (bg) {\r\n this._offCtx.fillStyle = bg;\r\n this._offCtx.fillRect( -px, -px, this._canvas.width+px, this._canvas.height+px );\r\n } else {\r\n this._offCtx.clearRect( -px, -px, this._offCanvas.width+px, this._offCanvas.height+px );\r\n }\r\n }\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Main animation function.\r\n * @param time current time\r\n */\r\n protected playItems( time: number ) {\r\n if (this._isReady) {\r\n this._ctx.save();\r\n if (this._offscreen) this._offCtx.save();\r\n super.playItems( time );\r\n this._ctx.restore();\r\n if (this._offscreen) this._offCtx.restore();\r\n this.render( this._ctx );\r\n }\r\n }\r\n \r\n \r\n /**\r\n * Dispose of browser resources held by this space and remove all players. Call this before unmounting the canvas.\r\n */\r\n dispose():this {\r\n if (!window) return;\r\n // remove event listeners\r\n window.removeEventListener( 'resize', this._resizeHandler.bind(this) );\r\n // stop animation loop\r\n this.stop();\r\n // remove players from space\r\n this.removeAll();\r\n\r\n return this;\r\n }\r\n \r\n\r\n /**\r\n * Get a [`MediaRecorder`](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) to record the current CanvasSpace. You can then call its `start()` function to start recording, and `stop()` to either download the video file or handle the blob data in the callback function you provided.\r\n * @param downloadOrCallback Either `true` to download the video, or provide a callback function to handle the Blob data, when recording is completed.\r\n * @param filetype video format. Default is \"webm\".\r\n * @param bitrate bitrate per second\r\n * @example `let rec = space.recorder(true); rec.start(); setTimeout( () => rec.stop(), 5000); // record 5s of video and download the file`\r\n */\r\n recorder( downloadOrCallback: boolean | ((blobURL:string) => {}), filetype:string = \"webm\", bitrate:number = 15000000 ): MediaRecorder {\r\n // @ts-ignore\r\n let stream = this._canvas.captureStream();\r\n const recorder = new MediaRecorder(stream, { mimeType: `video/${filetype}`, bitsPerSecond: bitrate } );\r\n \r\n recorder.ondataavailable = function(d) {\r\n let url = URL.createObjectURL( new Blob( [d.data], { type: `video/${filetype}` } ) );\r\n\r\n if (typeof downloadOrCallback === \"function\") {\r\n downloadOrCallback( url );\r\n\r\n } else if (downloadOrCallback) {\r\n let a = document.createElement(\"a\");\r\n a.href = url;\r\n a.download = `canvas_video.${filetype}`;\r\n a.click();\r\n a.remove();\r\n }\r\n };\r\n\r\n return recorder;\r\n }\r\n\r\n}\r\n\r\n\r\n\r\n\r\n\r\n/**\r\n* CanvasForm is an implementation of abstract class [`VisualForm`](#link). It provide methods to express Pts on [`CanvasSpace`](#link). \r\n* You may extend CanvasForm to implement your own expressions for CanvasSpace.\r\n*/\r\nexport class CanvasForm extends VisualForm {\r\n \r\n protected _space:CanvasSpace;\r\n protected _ctx:CanvasRenderingContext2D; \r\n protected _estimateTextWidth:(string) => number;\r\n\r\n /** \r\n * store common styles so that they can be restored to canvas context when using multiple forms. See `reset()`.\r\n */\r\n protected _style:DefaultFormStyle = {\r\n fillStyle: \"#f03\", strokeStyle:\"#fff\", \r\n lineWidth: 1, lineJoin: \"bevel\", lineCap: \"butt\",\r\n globalAlpha: 1\r\n };\r\n \r\n \r\n /**\r\n * Create a new CanvasForm. You may also use [`CanvasSpace.getForm()`](#link) to get the default form.\r\n * @param space an instance of CanvasSpace\r\n */\r\n constructor( space:CanvasSpace|CanvasRenderingContext2D ) {\r\n super();\r\n\r\n // allow for undefined context to support custom contexts via subclassing. \r\n if (!space) return this; \r\n \r\n const _setup = (ctx) => {\r\n this._ctx = ctx;\r\n this._ctx.fillStyle = this._style.fillStyle;\r\n this._ctx.strokeStyle = this._style.strokeStyle; \r\n this._ctx.lineJoin = \"bevel\";\r\n this._ctx.font = this._font.value;\r\n this._ready = true;\r\n };\r\n\r\n if (space instanceof CanvasRenderingContext2D) {\r\n _setup( space );\r\n } else {\r\n this._space = space;\r\n this._space.add( { start: () => {\r\n _setup( this._space.ctx );\r\n }} );\r\n }\r\n }\r\n \r\n \r\n /**\r\n * get the CanvasSpace instance that this form is associated with\r\n */\r\n get space():CanvasSpace { return this._space; }\r\n \r\n\r\n /**\r\n * Get the rendering context of canvas to perform other canvas functions.\r\n * @example `form.ctx.clip()`\r\n */\r\n get ctx():PtsCanvasRenderingContext2D { return this._ctx; }\r\n\r\n\r\n /**\r\n * Toggle whether to draw on offscreen canvas (if offscreen is set in CanvasSpace)\r\n * @param off if `true`, draw on offscreen canvas instead of the visible canvas. Default is `true`\r\n * @param clear optionally provide a valid color string to fill a bg color. see CanvasSpace's `clearOffscreen` function.\r\n */\r\n useOffscreen( off:boolean=true, clear:boolean|string=false ) {\r\n if (clear) this._space.clearOffscreen( (typeof clear == \"string\") ? clear : null );\r\n this._ctx = (this._space.hasOffscreen && off) ? this._space.offscreenCtx : this._space.ctx;\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Render the offscreen canvas's content on the visible canvas\r\n * @param offset Optional offset on the top-left position when drawing on the visible canvas\r\n */\r\n renderOffscreen( offset:PtLike=[0,0] ) {\r\n if (this._space.hasOffscreen) {\r\n this._space.ctx.drawImage( \r\n this._space.offscreenCanvas, offset[0], offset[1], this._space.width, this._space.height );\r\n }\r\n }\r\n \r\n \r\n /**\r\n * Set current alpha value.\r\n * @example `form.alpha(0.6)`\r\n * @param a alpha value between 0 and 1\r\n */\r\n alpha( a:number ):this {\r\n this._ctx.globalAlpha = a;\r\n this._style.globalAlpha = a;\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Set current fill style. Provide a valid color string such as `\"#FFF\"` or `\"rgba(255,0,100,0.5)\"` or `false` to specify no fill color.\r\n * @example `form.fill(\"#F90\")`, `form.fill(\"rgba(0,0,0,.5\")`, `form.fill(false)`\r\n * @param c fill color which can be as color, gradient, or pattern. (See [canvas documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle))\r\n */\r\n fill( c:string|boolean|CanvasGradient|CanvasPattern ):this {\r\n if (typeof c == \"boolean\") {\r\n this.filled = c;\r\n } else {\r\n this.filled = true;\r\n this._style.fillStyle = c;\r\n this._ctx.fillStyle = c;\r\n }\r\n return this;\r\n }\r\n \r\n \r\n \r\n /**\r\n * Set current stroke style. Provide a valid color string or `false` to specify no stroke color.\r\n * @example `form.stroke(\"#F90\")`, `form.stroke(\"rgba(0,0,0,.5\")`, `form.stroke(false)`, `form.stroke(\"#000\", 0.5, 'round', 'square')`\r\n * @param c stroke color which can be as color, gradient, or pattern. (See [canvas documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle))\r\n * @param width Optional value (can be floating point) to set line width\r\n * @param linejoin Optional string to set line joint style. Can be \"miter\", \"bevel\", or \"round\".\r\n * @param linecap Optional string to set line cap style. Can be \"butt\", \"round\", or \"square\".\r\n */\r\n stroke( c:string|boolean|CanvasGradient|CanvasPattern, width?:number, linejoin?:CanvasLineJoin, linecap?:CanvasLineCap ):this {\r\n if (typeof c == \"boolean\") {\r\n this.stroked = c;\r\n } else {\r\n this.stroked = true;\r\n this._style.strokeStyle = c;\r\n this._ctx.strokeStyle = c;\r\n if (width) {\r\n this._ctx.lineWidth = width;\r\n this._style.lineWidth = width;\r\n }\r\n if (linejoin) {\r\n this._ctx.lineJoin = linejoin;\r\n this._style.lineJoin = linejoin;\r\n }\r\n if (linecap) {\r\n this._ctx.lineCap = linecap;\r\n this._style.lineCap = linecap;\r\n }\r\n }\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * A convenient function to apply fill and/or stroke after custom drawings using canvas context (eg, `form.ctx.ellipse(...)`). \r\n * You don't need to call this function if you're using Pts' drawing functions like `form.point` or `form.rect`\r\n * @param filled apply fill when set to `true`\r\n * @param stroked apply stroke when set to `true`\r\n * @param strokeWidth optionally set a stroke width\r\n * @example `form.ctx.beginPath(); form.ctx.ellipse(...); form.applyFillStroke();`\r\n */\r\n applyFillStroke( filled:boolean|string = true, stroked:boolean|string = true, strokeWidth:number = 1 ) {\r\n if (filled) {\r\n if (typeof filled === 'string') this.fill( filled );\r\n this._ctx.fill();\r\n }\r\n\r\n if (stroked) {\r\n if (typeof stroked === 'string') this.stroke( stroked, strokeWidth );\r\n this._ctx.stroke();\r\n }\r\n\r\n return this;\r\n }\r\n \r\n\r\n /**\r\n * This function takes an array of gradient colors, and returns a function to define the areas of the gradient fill. See demo code in [CanvasForm.gradient](https://ptsjs.org/demo/?name=canvasform.textBox).\r\n * @param stops an array of gradient stops. This can be an array of colors `[\"#f00\", \"#0f0\", ...]` for evenly distributed gradient, or an array of [stop, color] like `[[0.1, \"#f00\"], [0.7, \"#0f0\"]]`\r\n * @returns a function that takes 1 or 2 `Group` as parameters. Use a single `Group` to specify a rectangular area for linear gradient, or use 2 `Groups` to specify 2 `Circles` for radial gradient.\r\n * @example `c1 = Circle.fromCenter(...); grad = form.gradient([\"#f00\", \"#00f\"]); form.fill( grad( c1, c2 ) ).circle( c1 )`\r\n */\r\n gradient( stops:[number, string][]|string[] ):((area1:GroupLike, area2?:GroupLike) => CanvasGradient) {\r\n let vals:[number, string][] = [];\r\n if (stops.length < 2) (stops as [number, string][]).push( [0.99, \"#000\"], [1,\"#000\"] );\r\n\r\n for (let i=0, len=stops.length; i {\r\n area1 = area1.map( a => a.abs() );\r\n if (area2) area2.map( a => a.abs() );\r\n\r\n let grad = area2 \r\n ? this._ctx.createRadialGradient( area1[0][0], area1[0][1], area1[1][0], area2[0][0], area2[0][1], area2[1][0] )\r\n : this._ctx.createLinearGradient( area1[0][0], area1[0][1], area1[1][0], area1[1][1] );\r\n\r\n for (let i=0, len=vals.length; i this._ctx.measureText(c).width) ) : undefined;\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * Get the width of this text. It will return an actual measurement or an estimate based on [`fontWidthEstimate`](#link) setting. Default is an actual measurement using canvas context's measureText.\r\n * @param c a string of text contents\r\n */\r\n getTextWidth( c:string ):number {\r\n return (!this._estimateTextWidth) ? this._ctx.measureText(c+\" .\").width : this._estimateTextWidth( c );\r\n }\r\n\r\n\r\n /**\r\n * Truncate text to fit width.\r\n * @param str text to truncate\r\n * @param width width to fit\r\n * @param tail text to indicate overflow such as \"...\". Default is empty \"\".\r\n */\r\n protected _textTruncate( str:string, width:number, tail:string=\"\" ):[string, number] {\r\n return Typo.truncate( this.getTextWidth.bind(this), str, width, tail );\r\n }\r\n\r\n\r\n /**\r\n * Align text within a rectangle box.\r\n * @param box a Group or an Iterable that defines a rectangular box\r\n * @param vertical a string that specifies the vertical alignment in the box: \"top\", \"bottom\", \"middle\", \"start\", \"end\"\r\n * @param offset Optional offset from the edge (like padding)\r\n * @param center Optional center position \r\n */\r\n protected _textAlign( box:PtLikeIterable, vertical:string, offset?:PtLike, center?:Pt ):Pt {\r\n let _box = Util.iterToArray( box );\r\n if ( !Util.arrayCheck(_box) ) return;\r\n\r\n if (!center) center = Rectangle.center( _box );\r\n\r\n var px = _box[0][0];\r\n if (this._ctx.textAlign == \"end\" || this._ctx.textAlign == \"right\") {\r\n px = _box[1][0];\r\n // @ts-ignore\r\n } else if (this._ctx.textAlign == \"center\" || this._ctx.textAlign == \"middle\") {\r\n px = center[0];\r\n }\r\n\r\n var py = center[1];\r\n if (vertical == \"top\" || vertical == \"start\") {\r\n py = _box[0][1];\r\n } else if (vertical == \"end\" || vertical == \"bottom\") {\r\n py = _box[1][1];\r\n }\r\n\r\n return (offset) ? new Pt( px+offset[0], py+offset[1] ) : new Pt(px, py);\r\n }\r\n \r\n \r\n /**\r\n * Reset the rendering context's common styles to this form's styles. This supports using multiple forms on the same canvas context.\r\n */\r\n reset():this {\r\n for (let k in this._style) {\r\n if (this._style.hasOwnProperty(k)) {\r\n this._ctx[k] = this._style[k];\r\n }\r\n }\r\n this._font = new Font();\r\n this._ctx.font = this._font.value;\r\n return this;\r\n }\r\n \r\n \r\n protected _paint() {\r\n if (this._filled) this._ctx.fill();\r\n if (this._stroked) this._ctx.stroke();\r\n }\r\n \r\n\r\n /**\r\n * A static function to draw a point.\r\n * @param ctx canvas rendering context\r\n * @param p a Pt object\r\n * @param radius radius of the point. Default is 5.\r\n * @param shape The shape of the point. Defaults to \"square\", but it can be \"circle\" or a custom shape function in your own implementation.\r\n * @example `form.point( p )`, `form.point( p, 10, \"circle\" )`\r\n */\r\n static point( ctx:CanvasRenderingContext2D, p:PtLike, radius:number=5, shape:string=\"square\" ) {\r\n if (!p) return;\r\n if (!CanvasForm[shape]) throw new Error(`${shape} is not a static function of CanvasForm`);\r\n CanvasForm[shape]( ctx, p, radius );\r\n }\r\n \r\n\r\n /**\r\n * Draws a point.\r\n * @param p a Pt object\r\n * @param radius radius of the point. Default is 5.\r\n * @param shape The shape of the point. Defaults to \"square\", but it can be \"circle\" or a custom shape function in your own implementation.\r\n * @example `form.point( p )`, `form.point( p, 10, \"circle\" )`\r\n */\r\n point( p:PtLike, radius:number=5, shape:string=\"square\" ):this {\r\n CanvasForm.point( this._ctx, p, radius, shape );\r\n this._paint();\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * A static function to draw a circle.\r\n * @param ctx canvas rendering context\r\n * @param pt center position of the circle\r\n * @param radius radius of the circle\r\n */\r\n static circle( ctx:CanvasRenderingContext2D, pt:PtLike, radius:number=10 ) {\r\n if (!pt) return;\r\n ctx.beginPath();\r\n ctx.arc( pt[0], pt[1], radius, 0, Const.two_pi, false );\r\n ctx.closePath();\r\n }\r\n \r\n \r\n /**\r\n * Draw a circle. See also [`Circle.fromCenter`](#link)\r\n * @param pts usually a Group or an Iterable with 2 Pt, but it can also take an array of two numeric arrays [ [position], [size] ]\r\n */\r\n circle( pts:PtLikeIterable ):this {\r\n let p = Util.iterToArray( pts );\r\n CanvasForm.circle( this._ctx, p[0], p[1][0] );\r\n this._paint();\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * A static function to draw an ellipse.\r\n * @param ctx canvas rendering context\r\n * @param pt center position \r\n * @param radius radius [x, y] of the ellipse\r\n * @param rotation rotation of the ellipse in radian. Default is 0.\r\n * @param startAngle start angle of the ellipse. Default is 0.\r\n * @param endAngle end angle of the ellipse. Default is 2 PI.\r\n * @param cc an optional boolean value to specify if it should be drawn clockwise (`false`) or counter-clockwise (`true`). Default is clockwise.\r\n */\r\n static ellipse( ctx:CanvasRenderingContext2D, pt:PtLike, radius:PtLike, rotation:number=0, startAngle:number=0, endAngle:number=Const.two_pi, cc:boolean=false ) {\r\n if (!pt || !radius) return;\r\n ctx.beginPath();\r\n ctx.ellipse( pt[0], pt[1], radius[0], radius[1], rotation, startAngle, endAngle, cc );\r\n }\r\n\r\n\r\n /**\r\n * Draw an ellipse.\r\n * @param pt center position \r\n * @param radius radius [x, y] of the ellipse\r\n * @param rotation rotation of the ellipse in radian. Default is 0.\r\n * @param startAngle start angle of the ellipse. Default is 0.\r\n * @param endAngle end angle of the ellipse. Default is 2 PI.\r\n * @param cc an optional boolean value to specify if it should be drawn clockwise (`false`) or counter-clockwise (`true`). Default is clockwise.\r\n */\r\n ellipse( pt:PtLike, radius:PtLike, rotation:number=0, startAngle:number=0, endAngle:number=Const.two_pi, cc:boolean=false ) {\r\n CanvasForm.ellipse( this._ctx, pt, radius, rotation, startAngle, endAngle, cc );\r\n this._paint();\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * A static function to draw an arc.\r\n * @param ctx canvas rendering context\r\n * @param pt center position \r\n * @param radius radius of the arc circle\r\n * @param startAngle start angle of the arc\r\n * @param endAngle end angle of the arc\r\n * @param cc an optional boolean value to specify if it should be drawn clockwise (`false`) or counter-clockwise (`true`). Default is clockwise.\r\n */\r\n static arc( ctx:CanvasRenderingContext2D, pt:PtLike, radius:number, startAngle:number, endAngle:number, cc?:boolean ) {\r\n if (!pt) return;\r\n ctx.beginPath();\r\n ctx.arc( pt[0], pt[1], radius, startAngle, endAngle, cc );\r\n }\r\n\r\n\r\n /**\r\n * Draw an arc.\r\n * @param pt center position\r\n * @param radius radius of the arc circle\r\n * @param startAngle start angle of the arc\r\n * @param endAngle end angle of the arc\r\n * @param cc an optional boolean value to specify if it should be drawn clockwise (`false`) or counter-clockwise (`true`). Default is clockwise.\r\n */\r\n arc( pt:PtLike, radius:number, startAngle:number, endAngle:number, cc?:boolean ):this {\r\n CanvasForm.arc( this._ctx, pt, radius, startAngle, endAngle, cc );\r\n this._paint();\r\n return this;\r\n }\r\n\r\n \r\n /**\r\n * A static function to draw a square.\r\n * @param ctx canvas rendering context\r\n * @param pt center position of the square\r\n * @param halfsize half size of the square\r\n */\r\n static square( ctx:CanvasRenderingContext2D, pt:PtLike, halfsize:number ) {\r\n if (!pt) return;\r\n let x1 = pt[0]-halfsize;\r\n let y1 = pt[1]-halfsize;\r\n let x2 = pt[0]+halfsize;\r\n let y2 = pt[1]+halfsize;\r\n \r\n // faster than using `rect`\r\n ctx.beginPath();\r\n ctx.moveTo( x1, y1 );\r\n ctx.lineTo( x1, y2 );\r\n ctx.lineTo( x2, y2 );\r\n ctx.lineTo( x2, y1 );\r\n ctx.closePath();\r\n }\r\n \r\n \r\n /**\r\n * Draw a square, given a center and its half-size.\r\n * @param pt center Pt\r\n * @param halfsize half-size\r\n */\r\n square( pt:PtLike, halfsize:number ) {\r\n CanvasForm.square( this._ctx, pt, halfsize );\r\n this._paint();\r\n return this;\r\n }\r\n\r\n \r\n /**\r\n * A static function to draw a line or polyline.\r\n * @param ctx canvas rendering context\r\n * @param pts a Group or an Iterable representing a line\r\n */\r\n static line( ctx:CanvasRenderingContext2D, pts:PtLikeIterable ) {\r\n if ( !Util.arrayCheck(pts) ) return;\r\n let i = 0;\r\n ctx.beginPath();\r\n for (let it of pts) {\r\n if (it) {\r\n if (i++ > 0) {\r\n ctx.lineTo(it[0], it[1]);\r\n } else {\r\n ctx.moveTo(it[0], it[1]);\r\n }\r\n }\r\n }\r\n }\r\n \r\n \r\n /**\r\n * Draw a line or polyline.\r\n * @param pts a Group or an Iterable representing a line\r\n */\r\n line( pts:PtLikeIterable ):this {\r\n CanvasForm.line( this._ctx, pts );\r\n this._paint();\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * A static function to draw a polygon.\r\n * @param ctx canvas rendering context\r\n * @param pts a Group or an Iterable representing a polygon\r\n */\r\n static polygon( ctx:CanvasRenderingContext2D, pts:PtLikeIterable ) {\r\n if ( !Util.arrayCheck(pts) ) return;\r\n CanvasForm.line( ctx, pts );\r\n ctx.closePath();\r\n }\r\n \r\n \r\n /**\r\n * Draw a polygon.\r\n * @param pts a Group or an Iterable representingg a polygon\r\n */\r\n polygon( pts:PtLikeIterable ):this {\r\n CanvasForm.polygon( this._ctx, pts );\r\n this._paint();\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * A static function to draw a rectangle.\r\n * @param ctx canvas rendering context\r\n * @param pts a Group or an Iterable with 2 Pt specifying the top-left and bottom-right positions.\r\n */\r\n static rect( ctx:CanvasRenderingContext2D, pts:PtLikeIterable ) {\r\n let p = Util.iterToArray( pts );\r\n if ( !Util.arrayCheck(p) ) return;\r\n ctx.beginPath();\r\n ctx.moveTo( p[0][0], p[0][1] );\r\n ctx.lineTo( p[0][0], p[1][1] );\r\n ctx.lineTo( p[1][0], p[1][1] );\r\n ctx.lineTo( p[1][0], p[0][1] );\r\n ctx.closePath();\r\n \r\n }\r\n \r\n \r\n /**\r\n * Draw a rectangle.\r\n * @param pts a Group or an Iterable with 2 Pt specifying the top-left and bottom-right positions.\r\n */\r\n rect( pts:PtLikeIterable ):this {\r\n CanvasForm.rect( this._ctx, pts );\r\n this._paint();\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * A static function to draw an image.\r\n * @param ctx canvas rendering context\r\n * @param img either an [Img](#link) instance or an [`CanvasImageSource`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasImageSource) instance (eg the image from ``, `