diff --git a/dist/index.d.mts b/dist/index.d.mts index e4f0133e..e779ea60 100644 --- a/dist/index.d.mts +++ b/dist/index.d.mts @@ -1033,6 +1033,7 @@ declare class Util { static arrayCheck(pts: PtLikeIterable, minRequired?: number): boolean; static iterToArray(it: Iterable): any[]; static isMobile(): boolean; + static uniqueId(useCrypto?: boolean): string; } /*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */ diff --git a/dist/index.d.ts b/dist/index.d.ts index e4f0133e..e779ea60 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1033,6 +1033,7 @@ declare class Util { static arrayCheck(pts: PtLikeIterable, minRequired?: number): boolean; static iterToArray(it: Iterable): any[]; static isMobile(): boolean; + static uniqueId(useCrypto?: boolean): string; } /*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */ diff --git a/dist/index.js b/dist/index.js index 3858b393..a2274d80 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3250,6 +3250,13 @@ var _Util = class _Util { static isMobile() { return /iPhone|iPad|Android/i.test(navigator.userAgent); } + /** + * Generate a time-based unique ID or a crypto-based ID. + * @returns + */ + static uniqueId(useCrypto = false) { + return useCrypto && crypto ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).substring(2); + } }; _Util._warnLevel = "mute"; var Util = _Util; @@ -5862,34 +5869,49 @@ var CanvasSpace2 = class extends MultiTouchSpace { this._initialResize = false; let _selector = null; let _existed = false; - this.id = "pt"; + this.id = Util.uniqueId(); if (elem instanceof Element) { _selector = elem; - this.id = "pts_existing_space"; + this.id = _selector.id || this.id; } else { let id = elem; id = elem[0] === "#" || elem[0] === "." ? elem : "#" + elem; _selector = document.querySelector(id); - _existed = true; this.id = id.substr(1); } if (!_selector) { 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); - _existed = false; } else if (_selector.nodeName.toLowerCase() != "canvas") { this._container = _selector; this._canvas = this._createElement("canvas", this.id + "_canvas"); - this._container.appendChild(this._canvas); this._initialResize = true; } else { this._canvas = _selector; this._container = _selector.parentElement; this._autoResize = false; + _existed = true; + } + if (!_existed) { + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === "childList" && mutation.addedNodes.length) { + for (let node of mutation.addedNodes) { + if (node === this._canvas) { + this._ready(callback); + observer.disconnect(); + return; + } + } + } + }); + }); + observer.observe(this._container, { childList: true }); + this._container.appendChild(this._canvas); + } else { + this._ready(callback); } - setTimeout(this._ready.bind(this, callback), 100); this._ctx = this._canvas.getContext("2d"); } /** diff --git a/dist/index.mjs b/dist/index.mjs index c0e8a386..e806d7b1 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -3182,6 +3182,13 @@ var _Util = class _Util { static isMobile() { return /iPhone|iPad|Android/i.test(navigator.userAgent); } + /** + * Generate a time-based unique ID or a crypto-based ID. + * @returns + */ + static uniqueId(useCrypto = false) { + return useCrypto && crypto ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).substring(2); + } }; _Util._warnLevel = "mute"; var Util = _Util; @@ -5794,34 +5801,49 @@ var CanvasSpace2 = class extends MultiTouchSpace { this._initialResize = false; let _selector = null; let _existed = false; - this.id = "pt"; + this.id = Util.uniqueId(); if (elem instanceof Element) { _selector = elem; - this.id = "pts_existing_space"; + this.id = _selector.id || this.id; } else { let id = elem; id = elem[0] === "#" || elem[0] === "." ? elem : "#" + elem; _selector = document.querySelector(id); - _existed = true; this.id = id.substr(1); } if (!_selector) { 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); - _existed = false; } else if (_selector.nodeName.toLowerCase() != "canvas") { this._container = _selector; this._canvas = this._createElement("canvas", this.id + "_canvas"); - this._container.appendChild(this._canvas); this._initialResize = true; } else { this._canvas = _selector; this._container = _selector.parentElement; this._autoResize = false; + _existed = true; + } + if (!_existed) { + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === "childList" && mutation.addedNodes.length) { + for (let node of mutation.addedNodes) { + if (node === this._canvas) { + this._ready(callback); + observer.disconnect(); + return; + } + } + } + }); + }); + observer.observe(this._container, { childList: true }); + this._container.appendChild(this._canvas); + } else { + this._ready(callback); } - setTimeout(this._ready.bind(this, callback), 100); this._ctx = this._canvas.getContext("2d"); } /** diff --git a/dist/pts.js b/dist/pts.js index be0be471..ad0fb666 100644 --- a/dist/pts.js +++ b/dist/pts.js @@ -3260,6 +3260,13 @@ See https://github.com/williamngan/pts for details. */ static isMobile() { return /iPhone|iPad|Android/i.test(navigator.userAgent); } + /** + * Generate a time-based unique ID or a crypto-based ID. + * @returns + */ + static uniqueId(useCrypto = false) { + return useCrypto && crypto ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).substring(2); + } }; _Util._warnLevel = "mute"; var Util = _Util; @@ -5894,34 +5901,49 @@ See https://github.com/williamngan/pts for details. */ this._initialResize = false; let _selector = null; let _existed = false; - this.id = "pt"; + this.id = Util.uniqueId(); if (elem instanceof Element) { _selector = elem; - this.id = "pts_existing_space"; + this.id = _selector.id || this.id; } else { let id = elem; id = elem[0] === "#" || elem[0] === "." ? elem : "#" + elem; _selector = document.querySelector(id); - _existed = true; this.id = id.substr(1); } if (!_selector) { 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); - _existed = false; } else if (_selector.nodeName.toLowerCase() != "canvas") { this._container = _selector; this._canvas = this._createElement("canvas", this.id + "_canvas"); - this._container.appendChild(this._canvas); this._initialResize = true; } else { this._canvas = _selector; this._container = _selector.parentElement; this._autoResize = false; + _existed = true; + } + if (!_existed) { + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === "childList" && mutation.addedNodes.length) { + for (let node of mutation.addedNodes) { + if (node === this._canvas) { + this._ready(callback); + observer.disconnect(); + return; + } + } + } + }); + }); + observer.observe(this._container, { childList: true }); + this._container.appendChild(this._canvas); + } else { + this._ready(callback); } - setTimeout(this._ready.bind(this, callback), 100); this._ctx = this._canvas.getContext("2d"); } /** diff --git a/dist/pts.min.js b/dist/pts.min.js index 31275aaa..0746eb43 100644 --- a/dist/pts.min.js +++ b/dist/pts.min.js @@ -2,7 +2,7 @@ Licensed under Apache 2.0 License. See https://github.com/williamngan/pts for details. */ (()=>{var qt=Object.defineProperty;var Ft=Object.getOwnPropertySymbols;var jt=Object.prototype.hasOwnProperty,Vt=Object.prototype.propertyIsEnumerable;var Ht=(l,r,t)=>r in l?qt(l,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[r]=t,$=(l,r)=>{for(var t in r||(r={}))jt.call(r,t)&&Ht(l,t,r[t]);if(Ft)for(var t of Ft(r))Vt.call(r,t)&&Ht(l,t,r[t]);return l};var T=(l,r)=>{for(var t in r)qt(l,t,{get:r[t],enumerable:!0})};var et=(l,r,t)=>new Promise((e,i)=>{var n=a=>{try{o(t.next(a))}catch(u){i(u)}},s=a=>{try{o(t.throw(a))}catch(u){i(u)}},o=a=>a.done?e(a.value):Promise.resolve(a.value).then(n,s);o((t=t.apply(l,r)).next())});var Dt={};T(Dt,{CanvasForm:()=>Q,CanvasSpace:()=>tt});var Lt={};T(Lt,{MultiTouchSpace:()=>Y,Space:()=>at});var xt={};T(xt,{Bound:()=>G,Group:()=>d,Pt:()=>h});var wt={};T(wt,{Const:()=>w,Util:()=>m});var Pt={};T(Pt,{Geom:()=>y,Num:()=>L,Range:()=>yt,Shaping:()=>st});var _t={};T(_t,{Circle:()=>B,Curve:()=>K,Line:()=>E,Polygon:()=>S,Rectangle:()=>M,Triangle:()=>j});var gt={};T(gt,{Mat:()=>C,Vec:()=>k});var k=class l{static add(r,t){if(typeof t=="number")for(let e=0,i=r.length;eMath.max(s,o.length),0):r[0].length;for(let s=0;sm.warn("Group's length is less than "+r,l),Wt=(l,r="")=>m.warn(`Index ${r} is out of bound in Group`,l),E=class l{static fromAngle(r,t,e){let i=new d(new h(r),new h(r));return i[1].toAngle(t,e,!0),i}static slope(r,t){return t[0]-r[0]===0?void 0:(t[1]-r[1])/(t[0]-r[0])}static intercept(r,t){if(t[0]-r[0]!==0){let e=(t[1]-r[1])/(t[0]-r[0]),i=r[1]-e*r[0];return{slope:e,yi:i,xi:e===0?void 0:-i/e}}}static sideOfPt2D(r,t){let e=m.iterToArray(r);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(r,t,e,i=.01){let n=new h(0,0,0).to(r).$subtract(t),s=new h(0,0,0).to(r).$subtract(e);return n.$cross(s).divide(1e3).equals(new h(0,0,0),i)}static magnitude(r){let t=m.iterToArray(r);return t.length>=2?t[1].$subtract(t[0]).magnitude():0}static magnitudeSq(r){let t=m.iterToArray(r);return t.length>=2?t[1].$subtract(t[0]).magnitudeSq():0}static perpendicularFromPt(r,t,e=!1){let i=m.iterToArray(r);if(i[0].equals(i[1]))return;let n=i[0].$subtract(i[1]),s=i[1].$subtract(t),o=s.$subtract(n.$project(s));return e?o:o.$add(t)}static distanceFromPt(r,t){let e=m.iterToArray(r),i=l.perpendicularFromPt(e,t,!0);return i?i.magnitude():e[0].$subtract(t).magnitude()}static intersectRay2D(r,t){let e=m.iterToArray(r),i=m.iterToArray(t),n=l.intercept(e[0],e[1]),s=l.intercept(i[0],i[1]),o=e[0],a=i[0];if(n==null){if(s==null)return;let u=-s.slope*(a[0]-o[0])+a[1];return new h(o[0],u)}else if(s==null){let u=-n.slope*(o[0]-a[0])+o[1];return new h(a[0],u)}else if(s.slope!=n.slope){let u=(n.slope*o[0]-s.slope*a[0]+a[1]-o[1])/(n.slope-s.slope),c=n.slope*(u-o[0])+o[1];return new h(u,c)}else return n.yi==s.yi?new h(o[0],o[1]):void 0}static intersectLine2D(r,t){let e=m.iterToArray(r),i=m.iterToArray(t),n=l.intersectRay2D(e,i);return n&&y.withinBound(n,e[0],e[1])&&y.withinBound(n,i[0],i[1])?n:void 0}static intersectLineWithRay2D(r,t){let e=m.iterToArray(r),i=m.iterToArray(t),n=l.intersectRay2D(e,i);return n&&y.withinBound(n,e[0],e[1])?n:void 0}static intersectPolygon2D(r,t,e=!1){let i=m.iterToArray(r),n=m.iterToArray(t),s=e?l.intersectLineWithRay2D:l.intersectLine2D,o=new d;for(let a=0,u=n.length;a0?o:void 0}static intersectLines2D(r,t,e=!1){let i=new d,n=e?l.intersectLineWithRay2D:l.intersectLine2D;for(let s of r)for(let o of t){let a=n(s,o);a&&i.push(a)}return i}static intersectGridWithRay2D(r,t){let e=m.iterToArray(r),i=l.intercept(new h(e[0]).subtract(t),new h(e[1]).subtract(t)),n=new d;return i&&i.xi&&n.push(new h(t[0]+i.xi,t[1])),i&&i.yi&&n.push(new h(t[0],t[1]+i.yi)),n}static intersectGridWithLine2D(r,t){let e=m.iterToArray(r),i=l.intersectGridWithRay2D(e,t),n=new d;for(let s=0,o=i.length;sMath.abs(t[1]/t[0])?c=o[1]<0?0:2:c=o[0]<0?3:1,l.intersectRay2D(u[c],n)}}static marker(r,t,e="arrow",i=!0){let n=m.iterToArray(r),s=i?0:1,o=i?1:0,a=n[s].$subtract(n[o]);if(a.magnitudeSq()===0)return new d;a.unit();let u=y.perpendicular(a).multiply(t[0]).add(n[o]);return e=="arrow"?(u.add(a.$multiply(t[1])),new d(n[o],u[0],u[1])):new d(u[0],u[1])}static toRect(r){let t=m.iterToArray(r);return new d(t[0].$min(t[1]),t[0].$max(t[1]))}},M=class l{static from(r,t,e){return l.fromTopLeft(r,t,e)}static fromTopLeft(r,t,e){let i=typeof t=="number"?[t,e||t]:t;return new d(new h(r),new h(r).add(i))}static fromCenter(r,t,e){let i=typeof t=="number"?[t/2,(e||t)/2]:new h(t).divide(2);return new d(new h(r).subtract(i),new h(r).add(i))}static toCircle(r,t=!0){return B.fromRect(r,t)}static toSquare(r,t=!1){let e=m.iterToArray(r),i=l.size(e),n=t?i.maxValue().value:i.minValue().value;return l.fromCenter(l.center(e),n,n)}static size(r){let t=m.iterToArray(r);return t[0].$max(t[1]).subtract(t[0].$min(t[1]))}static center(r){let t=m.iterToArray(r),e=t[0].$min(t[1]),i=t[0].$max(t[1]);return e.add(i.$subtract(e).divide(2))}static corners(r){let t=m.iterToArray(r),e=t[0].$min(t[1]),i=t[0].$max(t[1]);return new d(e,new h(i.x,e.y),i,new h(e.x,i.y))}static sides(r){let[t,e,i,n]=l.corners(r);return[new d(t,e),new d(e,i),new d(i,n),new d(n,t)]}static boundingBox(r){let t=m.iterToArray(r),e=m.flatten(t,!1),i=h.make(2,Number.MAX_VALUE),n=h.make(2,Number.MIN_VALUE);for(let s=0,o=e.length;s=2)break}return new d(i,n)}static polygon(r){return l.corners(r)}static quadrants(r,t){let e=m.iterToArray(r),i=l.corners(e),n=t!=null?new h(t):l.center(e);return i.map(s=>new d(s,n).boundingBox())}static halves(r,t=.5,e=!1){let i=m.iterToArray(r),n=i[0].$min(i[1]),s=i[0].$max(i[1]),o=e?L.lerp(n[1],s[1],t):L.lerp(n[0],s[0],t);return e?[new d(n,new h(s[0],o)),new d(new h(n[0],o),s)]:[new d(n,new h(o,s[1])),new d(new h(o,n[1]),s)]}static withinBound(r,t){let e=m.iterToArray(r);return y.withinBound(t,e[0],e[1])}static hasIntersectRect2D(r,t,e=!1){let i=m.iterToArray(r),n=m.iterToArray(t);return e&&(i=y.boundingBox(i),n=y.boundingBox(n)),!(i[0][0]>n[1][0]||n[0][0]>i[1][0]||i[0][1]>n[1][1]||n[0][1]>i[1][1])}static intersectRect2D(r,t){let e=m.iterToArray(r),i=m.iterToArray(t);return l.hasIntersectRect2D(e,i)?E.intersectLines2D(l.sides(e),l.sides(i)):new d}},B=class l{static fromRect(r,t=!1){let e=m.iterToArray(r),i=0,n=i=M.size(e).minValue().value/2;if(t){let s=M.size(e).maxValue().value/2;i=Math.sqrt(n*n+s*s)}else i=n;return new d(M.center(e),new h(i,i))}static fromTriangle(r,t=!1){return t?j.circumcircle(r):j.incircle(r)}static fromCenter(r,t){return new d(new h(r),new h(t,t))}static withinBound(r,t,e=0){let i=m.iterToArray(r),n=i[0].$subtract(t);return n.dot(n)+e0)for(let o=0,a=n.length;oa+u)return new d;if(o0&&s.push(u)}return m.flatten(s)}static toRect(r,t=!1){let e=m.iterToArray(r),i=e[1][0];if(t){let n=Math.sqrt(i*i)/2;return new d(e[0].$subtract(n),e[0].$add(n))}else return new d(e[0].$subtract(i),e[0].$add(i))}static toTriangle(r,t=!0){let e=m.iterToArray(r);if(t){let i=-Math.PI/2,n=Math.PI*2/3,s=new d;for(let o=0;o<3;o++)s.push(e[0].clone().toAngle(i,e[1][0],!0)),i+=n;return s}else return j.fromCenter(e[0],e[1][0])}},j=class l{static fromRect(r){let t=m.iterToArray(r),e=t[0].$add(t[1]).divide(2);e.y=t[0][1];let i=t[1].clone();return i.x=t[0][0],new d(e,t[1].clone(),i)}static fromCircle(r){return B.toTriangle(r,!0)}static fromCenter(r,t){return l.fromCircle(B.fromCenter(r,t))}static medial(r){let t=m.iterToArray(r);return t.length<3?N(new d,3):S.midpoints(t,!0)}static oppositeSide(r,t){let e=m.iterToArray(r);return e.length<3?N(new d,3):t===0?d.fromPtArray([e[1],e[2]]):t===1?d.fromPtArray([e[0],e[2]]):d.fromPtArray([e[0],e[1]])}static altitude(r,t){let e=m.iterToArray(r),i=l.oppositeSide(e,t);return i.length>1?new d(e[t],E.perpendicularFromPt(i,e[t])):new d}static orthocenter(r){let t=m.iterToArray(r);if(t.length<3)return N(void 0,3);let e=l.altitude(t,0),i=l.altitude(t,1);return E.intersectRay2D(e,i)}static incenter(r){let t=m.iterToArray(r);if(t.length<3)return N(void 0,3);let e=S.bisector(t,0).add(t[0]),i=S.bisector(t,1).add(t[1]);return E.intersectRay2D(new d(t[0],e),new d(t[1],i))}static incircle(r,t){let e=m.iterToArray(r),i=t||l.incenter(e),n=S.area(e),s=S.perimeter(e,!0),o=2*n/s.total;return B.fromCenter(i,o)}static circumcenter(r){let t=m.iterToArray(r),e=l.medial(t),i=[e[0],y.perpendicular(t[0].$subtract(e[0])).p1.$add(e[0])],n=[e[1],y.perpendicular(t[1].$subtract(e[1])).p1.$add(e[1])];return E.intersectRay2D(i,n)}static circumcircle(r,t){let e=m.iterToArray(r),i=t||l.circumcenter(e),n=e[0].$subtract(i).magnitude();return B.fromCenter(i,n)}},S=class l{static centroid(r){return y.centroid(r)}static rectangle(r,t,e){return M.corners(M.fromCenter(r,t,e))}static fromCenter(r,t,e){let i=new d;for(let n=0;n=e.length)throw new Error("index out of the Polygon's range");return new d(e[t],t===e.length-1?e[0]:e[t+1])}static lines(r,t=!0){let e=m.iterToArray(r);if(e.length<2)return N(new d,2);let i=m.split(e,2,1);return t&&i.push(new d(e[e.length-1],e[0])),i.map(n=>n)}static midpoints(r,t=!1,e=.5){return l.lines(r,t).map(s=>y.interpolate(s[0],s[1],e))}static adjacentSides(r,t,e=!1){let i=m.iterToArray(r);if(i.length<2)return N(new d,2);if(t<0||t>=i.length)return Wt(new d,t);let n=[],s=t-1;e&&s<0&&(s=i.length-1),s>=0&&n.push(new d(i[t],i[s]));let o=t+1;return e&&o>i.length-1&&(o=0),o<=i.length-1&&n.push(new d(i[t],i[o])),n}static bisector(r,t){let e=l.adjacentSides(r,t,!0);if(e.length>=2){let i=e[0][1].$subtract(e[0][0]).unit(),n=e[1][1].$subtract(e[1][0]).unit();return i.add(n).divide(2)}else return}static perimeter(r,t=!1){let e=l.lines(r,t),i=0,n=h.make(e.length,0);for(let s=0,o=e.length;sn[0]*s[1]-n[1]*s[0],i=0;for(let n=0,s=t.length;nu[0]-c[0]));let i=(u,c,f)=>(c[0]-u[0])*(f[1]-u[1])-(f[0]-u[0])*(c[1]-u[1])>0,n=[],s=e.length-2,o=s+3;n[s]=e[2],n[o]=e[2],i(e[0],e[1],e[2])?(n[s+1]=e[0],n[s+2]=e[1]):(n[s+1]=e[1],n[s+2]=e[0]);for(let u=3,c=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]&&(i=!i)}return i}static hasIntersectCircle(r,t){let e=m.iterToArray(r),i=m.iterToArray(t),n={which:-1,dist:0,normal:null,edge:null,vertex:null},s=i[0],o=i[1][0],a=Number.MAX_SAFE_INTEGER;for(let c=0,f=e.length;c0)return null;Math.abs(_)0)&&(n.edge=p,n.normal=b,a=Math.abs(_),n.which=c)}return n.edge?(s.$subtract(l.centroid(e)).dot(n.normal)<0&&n.normal.multiply(-1),n.dist=a,n.vertex=s,n):null}static hasIntersectPolygon(r,t){let e=m.iterToArray(r),i=m.iterToArray(t),n={which:-1,dist:0,normal:new h,edge:new d,vertex:new h},s=Number.MAX_SAFE_INTEGER;for(let b=0,P=e.length+i.length;b0)return null;Math.abs(A)i.length-1)return new d;let n=o=>on+s.x*t[o],0),i=r.reduce((n,s,o)=>n+s.y*t[o],0);if(r[0].length>2){let n=r.reduce((s,o,a)=>s+o.z*t[a],0);return new h(e,i,n)}return new h(e,i)}static catmullRom(r,t=10){let e=m.iterToArray(r);if(e.length<2)return new d;let i=new d,n=l.getSteps(t),s=l.controlPoints(e,0,!0);for(let a=0;a<=t;a++)i.push(l.catmullRomStep(n[a],s));let o=0;for(;o0){for(let u=0;u<=t;u++)i.push(l.catmullRomStep(n[u],a));o++}}return i}static catmullRomStep(r,t){let e=new d(new h(-.5,1,-.5,0),new h(1.5,-2.5,0,1),new h(-1.5,2,.5,0),new h(.5,-.5,0,0));return l._calcPt(t,C.multiply([r],e,!0)[0])}static cardinal(r,t=10,e=.5){let i=m.iterToArray(r);if(i.length<2)return new d;let n=new d,s=l.getSteps(t),o=l.controlPoints(i,0,!0);for(let u=0;u<=t;u++)n.push(l.cardinalStep(s[u],o,e));let a=0;for(;a0){for(let c=0;c<=t;c++)n.push(l.cardinalStep(s[c],u,e));a++}}return n}static cardinalStep(r,t,e=.5){let i=new d(new h(-1,2,-1,0),new h(-1,1,0,0),new h(1,-2,1,0),new h(1,-1,0,0)),n=C.multiply([r],i,!0)[0].multiply(e),s=2*r[0]-3*r[1]+1,o=-2*r[0]+3*r[1],a=l._calcPt(t,n);return a.x+=s*t[1].x+o*t[2].x,a.y+=s*t[1].y+o*t[2].y,a.length>2&&(a.z+=s*t[1].z+o*t[2].z),a}static bezier(r,t=10){let e=m.iterToArray(r);if(e.length<4)return new d;let i=new d,n=l.getSteps(t),s=0;for(;s0){for(let a=0;a<=t;a++)i.push(l.bezierStep(n[a],o));s+=3}}return i}static bezierStep(r,t){let e=new d(new h(-1,3,-3,1),new h(3,-6,3,0),new h(-3,3,0,0),new h(1,0,0,0));return l._calcPt(t,C.multiply([r],e,!0)[0])}static bspline(r,t=10,e=1){let i=m.iterToArray(r);if(i.length<2)return new d;let n=new d,s=l.getSteps(t),o=0;for(;o0){if(e!==1)for(let u=0;u<=t;u++)n.push(l.bsplineTensionStep(s[u],a,e));else for(let u=0;u<=t;u++)n.push(l.bsplineStep(s[u],a));o++}}return n}static bsplineStep(r,t){let e=new d(new h(-.16666666666666666,.5,-.5,.16666666666666666),new h(.5,-1,0,.6666666666666666),new h(-.5,.5,.5,.16666666666666666),new h(.16666666666666666,0,0,0));return l._calcPt(t,C.multiply([r],e,!0)[0])}static bsplineTensionStep(r,t,e=1){let i=new d(new h(-.16666666666666666,.5,-.5,.16666666666666666),new h(-1.5,2,0,-.3333333333333333),new h(1.5,-2.5,.5,.16666666666666666),new h(.16666666666666666,0,0,0)),n=C.multiply([r],i,!0)[0].multiply(e),s=2*r[0]-3*r[1]+1,o=-2*r[0]+3*r[1],a=l._calcPt(t,n);return a.x+=s*t[1].x+o*t[2].x,a.y+=s*t[1].y+o*t[2].y,a.length>2&&(a.z+=s*t[1].z+o*t[2].z),a}};function Xt(){let l=4022871197;return function(t){if(t){t=t.toString();for(let e=0;e>>0,i-=l,i*=l,l=i>>>0,i-=l,l+=i*4294967296}return(l>>>0)*23283064365386963e-26}else l=4022871197}}function Ut(l){let r=48,t=1,e=r,i=new Array(r),n,s,o=0,a=Xt();for(n=0;n=r&&(e=0);let p=1768863*i[e]+t*23283064365386963e-26;return i[e]=p-(t=p|0)}}}var L=class l{static equals(r,t,e=1e-5){return Math.abs(r-t)e?n-=i:n=Math.min(t,e)&&r<=Math.max(t,e)}static randomRange(r,t=0){let e=r>t?r-t:t-r;return r+l.random()*e}static randomPt(r,t){let e=new h(r.length),i=t?k.subtract(t.slice(),r):r,n=t?r:new h(r.length).fill(0);for(let s=0,o=e.length;s.5?2-r*2:r*2)}static mapToRange(r,t,e,i,n){if(t==e)throw new Error("[currMin, currMax] must define a range that is not zero");let s=Math.min(i,n),o=Math.max(i,n);return l.normalizeValue(r,t,e)*(o-s)+s}static seed(r){this.generator=Ut(r)}static random(){return this.generator?this.generator.random():Math.random()}},y=class l{static boundAngle(r){return L.boundValue(r,0,360)}static boundRadian(r){return L.boundValue(r,0,w.two_pi)}static toRadian(r){return r*w.deg_to_rad}static toDegree(r){return r*w.rad_to_deg}static boundingBox(r){let t,e;for(let i of r)t==null?(t=i.clone(),e=i.clone()):(t=t.$min(i),e=e.$max(i));return new d(t,e)}static centroid(r){return L.average(r)}static anchor(r,t=0,e="to"){let i=e=="to"?"subtract":"add",n=0;for(let s of r)typeof t=="number"?t!==n&&s[i](r[t]):s[i](t),n++}static interpolate(r,t,e=.5){let i=Math.min(r.length,t.length),n=h.make(i);for(let s=0;s{if(s.length<2||o.length<2)throw new Error("Pt dimension cannot be less than 2");let a=s.$subtract(i),u=o.$subtract(i);if(a[0]>=0&&u[0]<0)return 1;if(a[0]<0&&u[0]>=0)return-1;if(a[0]==0&&u[0]==0)return a[1]>=0||u[1]>=0?a[1]>u[1]?1:-1:u[1]>a[1]?1:-1;let c=a.$cross2D(u);return c<0?1:c>0?-1:a[0]*a[0]+a[1]*a[1]>u[0]*u[0]+u[1]*u[1]?1:-1};return t.sort(n)}static scale(r,t,e){let i=m.iterToArray(r[0]!==void 0&&typeof r[0]=="number"?[r]:r),n=typeof t=="number"?h.make(i[0].length,t):t;e||(e=h.make(i[0].length,0));for(let s=0,o=i.length;sr[Math.floor(l.boundAngle(l.toDegree(e)))]}}static sinTable(){let r=new Float64Array(360);for(let e=0;e<360;e++)r[e]=Math.sin(e*Math.PI/180);return{table:r,sin:e=>r[Math.floor(l.boundAngle(l.toDegree(e)))]}}},st=class l{static linear(r,t=1){return t*r}static quadraticIn(r,t=1){return t*r*r}static quadraticOut(r,t=1){return-t*r*(r-2)}static quadraticInOut(r,t=1){let e=r*2;return r<.5?t/2*r*r*4:-t/2*((e-1)*(e-3)-1)}static cubicIn(r,t=1){return t*r*r*r}static cubicOut(r,t=1){let e=r-1;return t*(e*e*e+1)}static cubicInOut(r,t=1){let e=r*2;return r<.5?t/2*e*e*e:t/2*((e-2)*(e-2)*(e-2)+2)}static exponentialIn(r,t=1,e=.25){return t*Math.pow(r,1/e)}static exponentialOut(r,t=1,e=.25){return t*Math.pow(r,e)}static sineIn(r,t=1){return-t*Math.cos(r*w.half_pi)+t}static sineOut(r,t=1){return t*Math.sin(r*w.half_pi)}static sineInOut(r,t=1){return-t/2*(Math.cos(Math.PI*r)-1)}static cosineApprox(r,t=1){let e=r*r,i=e*e,n=i*e;return t*(4*n/9-17*i/9+22*e/9)}static circularIn(r,t=1){return-t*(Math.sqrt(1-r*r)-1)}static circularOut(r,t=1){let e=r-1;return t*Math.sqrt(1-e*e)}static circularInOut(r,t=1){let e=r*2;return r<.5?-t/2*(Math.sqrt(1-e*e)-1):t/2*(Math.sqrt(1-(e-2)*(e-2))+1)}static elasticIn(r,t=1,e=.7){let i=r-1,n=e/w.two_pi*1.5707963267948966;return t*(-Math.pow(2,10*i)*Math.sin((i-n)*w.two_pi/e))}static elasticOut(r,t=1,e=.7){let i=e/w.two_pi*1.5707963267948966;return t*(Math.pow(2,-10*r)*Math.sin((r-i)*w.two_pi/e))+t}static elasticInOut(r,t=1,e=.6){let i=r*2,n=e/w.two_pi*1.5707963267948966;return r<.5?(i-=1,t*(-.5*(Math.pow(2,10*i)*Math.sin((i-n)*w.two_pi/e)))):(i-=1,t*(.5*(Math.pow(2,-10*i)*Math.sin((i-n)*w.two_pi/e)))+t)}static bounceIn(r,t=1){return t-l.bounceOut(1-r,t)}static bounceOut(r,t=1){return r<1/2.75?t*(7.5625*r*r):r<2/2.75?(r-=1.5/2.75,t*(7.5625*r*r+.75)):r<2.5/2.75?(r-=2.25/2.75,t*(7.5625*r*r+.9375)):(r-=2.625/2.75,t*(7.5625*r*r+.984375))}static bounceInOut(r,t=1){return r<.5?l.bounceIn(r*2,t)/2:l.bounceOut(r*2-1,t)/2+t/2}static sigmoid(r,t=1,e=10){let i=e*(r-.5);return t/(1+Math.exp(-i))}static logSigmoid(r,t=1,e=.7){e=Math.max(w.epsilon,Math.min(1-w.epsilon,e)),e=1/(1-e);let i=1/(1+Math.exp((r-.5)*e*-2)),n=1/(1+Math.exp(e)),s=1/(1+Math.exp(-e));return t*(i-n)/(s-n)}static seat(r,t=1,e=.5){return r<.5?t*Math.pow(2*r,1-e)/2:t*(1-Math.pow(2*(1-r),1-e)/2)}static quadraticBezier(r,t=1,e=[.05,.95]){let i=typeof e!="number"?e[0]:e,n=typeof e!="number"?e[1]:.5,s=1-2*i;s===0&&(s=w.epsilon);let o=(Math.sqrt(i*i+s*r)-i)/s;return t*((1-2*n)*(o*o)+2*n*o)}static cubicBezier(r,t=1,e=[.1,.7],i=[.9,.2]){let n=new d(new h(0,0),new h(e),new h(i),new h(1,1));return t*K.bezierStep(new h(r*r*r,r*r,r,1),K.controlPoints(n)).y}static quadraticTarget(r,t=1,e=[.2,.35]){let i=Math.min(1-w.epsilon,Math.max(w.epsilon,e[0])),n=Math.min(1,Math.max(0,e[1])),s=(1-n)/(1-i)-n/i,o=(s*(i*i)-n)/i,a=s*(r*r)-o*r;return t*Math.min(1,Math.max(0,a))}static cliff(r,t=1,e=.5){return r>e?t:0}static step(r,t,e,i,...n){let s=1/t,o=Math.floor(e/s)*s;return r(o,i,...n)}},yt=class{constructor(r){this._dims=0;this._source=d.fromPtArray(r),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 r=this._source[0].length;this._dims=r;let t=new h(r),e=new h(r),i=new h(r);for(let n=0;n=n.length||!(i[s]in n));s++)t.push(n[i[s]])}else e&&(t=[].slice.call(r[0]));return t}static warn(r="error",t=void 0){if(H.warnLevel()=="error")throw new Error(r);return H.warnLevel()=="warn"&&console.warn(r),t}static randomInt(r,t=0){return H.warn("Util.randomInt is deprecated. Please use `Num.randomRange`"),Math.floor(L.random()*r)+t}static split(r,t,e,i=!1,n=!0){let s=[],o=[],a=e||t,u=0;if(r.length<=0||a<=0)return[];for(;u=r.length)break;o.push(r[u+c])}u+=a,(!n||n&&o.length===t)&&s.push(o)}return s}static flatten(r,t=!0){let e=t?new d:[];return e.concat.apply(e,r)}static combine(r,t,e){let i=[];for(let n=0,s=r.length;n=r&&(n=t+(n-r)),i&&i(n),n}}static forRange(r,t,e=0,i=1){let n=[];for(let s=e,o=t;s=200&&e.status<400?t(e.responseText,!0):t(`Server error (${e.status}) when loading "${r}"`,!1)},e.onerror=function(){t("Unknown network error",!1)},e.send()}static download(r,t="pts_canvas_image",e="png",i=1){let n=e==="jpg"?"jpeg":e;r.element.toBlob(function(s){let o=document.createElement("a"),a=URL.createObjectURL(s);o.href=a,o.download=`${t}.${e}`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(a)},`image/${n}`,i)}static performance(r=10){let t=Date.now(),e=[];return function(){let i=Date.now();return e.push(i-t),e.length>=r&&e.shift(),t=i,Math.floor(e.reduce((n,s)=>n+s,0)/e.length)}}static arrayCheck(r,t=2){return Array.isArray(r)&&r.length0?m.getArgs(r):[0,0],super(t)}static make(r,t=0,e=!1){let i=new Float32Array(r);if(t&&i.fill(t),e)for(let n=0,s=i.length;nt)return!1;return!0}to(...r){let t=m.getArgs(r);for(let e=0,i=Math.min(this.length,t.length);er(t,...e)}ops(r){let t=[];for(let e=0,i=r.length;er(t,...e)}ops(r){let t=[];for(let e=0,i=r.length;et?i[r]-e[r]:e[r]-i[r])}forEachPt(r,...t){if(!this[0][r])return m.warn(`${r} is not a function of Pt`),this;for(let e=0,i=this.length;er+t.toString()+" ","")+" ]"}},G=class l extends d{constructor(...t){super(...t);this._center=new h;this._size=new h;this._topLeft=new h;this._bottomRight=new h;this._inited=!1;this.init()}static fromBoundingRect(t){let e=new l(new h(t.left||0,t.top||0),new h(t.right||0,t.bottom||0));return t.width&&t.height&&(e.size=new h(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 l(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 l(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 h(this._size)}set size(t){this._size=new h(t),this._updatePosFromTop()}get center(){return new h(this._center)}set center(t){this._center=new h(t),this._updatePosFromCenter()}get topLeft(){return new h(this._topLeft)}set topLeft(t){this._topLeft=new h(t),this[0]=this._topLeft,this._updateSize()}get bottomRight(){return new h(this._bottomRight)}set bottomRight(t){this._bottomRight=new h(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 vt={};T(vt,{UI:()=>W,UIButton:()=>ot,UIDragger:()=>kt,UIPointerActions:()=>v,UIShape:()=>X});var X={rectangle:"rectangle",circle:"circle",polygon:"polygon",polyline:"polyline",line:"line"},v={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",pointerdown:"pointerdown",pointerup:"pointerup",contextmenu:"contextmenu",all:"all"},V=class V{constructor(r,t,e={},i){this._holds=new Map;this._group=d.fromArray(r),this._shape=t,this._id=i===void 0?`ui_${V._counter++}`:i,this._states=e,this._actions={}}static fromRectangle(r,t,e){return new this(r,X.rectangle,t,e)}static fromCircle(r,t,e){return new this(r,X.circle,t,e)}static fromPolygon(r,t,e){return new this(r,X.polygon,t,e)}static fromUI(r,t,e){return new this(r.group,r.shape,t||r._states,e)}get id(){return this._id}set id(r){this._id=r}get group(){return this._group}set group(r){this._group=r}get shape(){return this._shape}set shape(r){this._shape=r}state(r,t){return r?t!==void 0?(this._states[r]=t,this):this._states[r]:null}on(r,t){return this._actions[r]||(this._actions[r]=[]),V._addHandler(this._actions[r],t)}off(r,t){return this._actions[r]?t===void 0?(delete this._actions[r],!0):V._removeHandler(this._actions[r],t):!1}listen(r,t,e){if(this._actions[r]!==void 0){if(this._within(t)||Array.from(this._holds.values()).indexOf(r)>=0)return V._trigger(this._actions[r],this,t,r,e),!0;if(this._actions.all)return V._trigger(this._actions.all,this,t,r,e),!0}return!1}hold(r){let t=Math.max(0,...Array.from(this._holds.keys()))+1;return this._holds.set(t,r),t}unhold(r){r!==void 0?this._holds.delete(r):this._holds.clear()}static track(r,t,e,i){for(let n=0,s=r.length;n=0&&tr.length}else return!1}};V._counter=0;var W=V,ot=class extends W{constructor(t,e,i={},n){super(t,e,i,n);this._hoverID=-1;i.hover===void 0&&(this._states.hover=!1),i.clicks===void 0&&(this._states.clicks=0);let s=v;this.on(s.up,(o,a,u,c)=>{this.state("clicks",this._states.clicks+1)}),this.on(s.move,(o,a,u,c)=>{if(this._within(a)&&!this._states.hover){this.state("hover",!0),W._trigger(this._actions[s.enter],this,a,s.enter,c);let p=this.hold(s.move);this._hoverID=this.on(s.move,(b,P)=>{!this._within(P)&&!this.state("dragging")&&(this.state("hover",!1),W._trigger(this._actions[s.leave],this,a,s.leave,c),this.off(s.move,this._hoverID),this.unhold(p))})}})}onClick(t){return this.on(v.up,t)}offClick(t){return this.off(v.up,t)}onContextMenu(t){return this.on(v.contextmenu,t)}offContextMenu(t){return this.off(v.contextmenu,t)}onHover(t,e){let i=[void 0,void 0];return t&&(i[0]=this.on(v.enter,t)),e&&(i[1]=this.on(v.leave,e)),i}offHover(t,e){let i=[!1,!1];return(t===void 0||t>=0)&&(i[0]=this.off(v.enter,t)),(e===void 0||e>=0)&&(i[1]=this.off(v.leave,e)),i}},kt=class extends ot{constructor(t,e,i={},n){super(t,e,i,n);this._draggingID=-1;this._moveHoldID=-1;this._dropHoldID=-1;this._upHoldID=-1;i.dragging===void 0&&(this._states.dragging=!1),i.moved===void 0&&(this._states.moved=!1),i.offset===void 0&&(this._states.offset=new h);let s=v;this.on(s.down,(a,u,c,f)=>{this._moveHoldID===-1&&(this.state("dragging",!0),this.state("offset",new h(u).subtract(a.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,(p,b)=>{this.state("dragging")&&(W._trigger(this._actions[s.uidrag],p,b,s.uidrag,f),this.state("moved",!0))}))});let o=(a,u,c,f)=>{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")&&(W._trigger(this._actions[s.uidrop],a,u,s.uidrop,f),this.state("moved",!1))};this.on(s.drop,o),this.on(s.up,o),this.on(s.out,o)}onDrag(t){return this.on(v.uidrag,t)}offDrag(t){return this.off(v.uidrag,t)}onDrop(t){return this.on(v.uidrop,t)}offDrop(t){return this.off(v.uidrop,t)}};var at=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 h;this._isReady=!1;this._playing=!1}refresh(r){return this._refresh=r,this}minFrameTime(r=0){this._time.min=r}add(r){let t=typeof r=="function"?{animate:r}:r,e=this.playerCount++,i=t.animateID||this.id+e;return this.players[i]=t,t.animateID=i,t.resize&&this.bound.inited&&t.resize(this.bound),this._refresh===void 0&&(this._refresh=!0),this}remove(r){return delete this.players[r.animateID],this}removeAll(){return this.players={},this}play(r=0){if(!(r===0&&this._animID!==-1)){if(this._animID=requestAnimationFrame(this.play.bind(this)),this._pause)return this;if(this._time.diff=r-this._time.prev,this._time.diff=0&&r>this._time.end&&(cancelAnimationFrame(this._animID),this._animID=-1,this._playing=!1)}pause(r=!1){return this._pause=r?!this._pause:!0,this}resume(){return this._pause=!1,this}stop(r=0){return this._time.end=r,this}playOnce(r=0){return this.play(),this.stop(r),this}render(r){return this._renderFunc&&this._renderFunc(r,this),this}set customRendering(r){this._renderFunc=r}get customRendering(){return this._renderFunc}get isPlaying(){return this._playing}get outerBound(){return this.bound.clone()}get innerBound(){return new G(h.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}},Y=class extends at{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,i={},n){(n||this._canvas).addEventListener(t,e,i)}unbindCanvas(t,e,i={},n){(n||this._canvas).removeEventListener(t,e,i)}bindDoc(t,e,i={}){document&&document.addEventListener(t,e,i)}unbindDoc(t,e,i={}){document&&document.removeEventListener(t,e,i)}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("pointerdown",this._mouseDown,{},e),this.bindCanvas("pointerup",this._mouseUp,{},e),this.bindCanvas("pointerover",this._mouseOver,{},e),this.bindCanvas("pointerout",this._mouseOut,{},e),this.bindCanvas("pointermove",this._mouseMove,{},e),this.bindCanvas("click",this._mouseClick,{},e),this.bindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!0):(this.unbindCanvas("pointerdown",this._mouseDown,{},e),this.unbindCanvas("pointerup",this._mouseUp,{},e),this.unbindCanvas("pointerover",this._mouseOver,{},e),this.unbindCanvas("pointerout",this._mouseOut,{},e),this.unbindCanvas("pointermove",this._mouseMove,{},e),this.unbindCanvas("click",this._mouseClick,{},e),this.unbindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!1),this}bindTouch(t=!0,e=!1,i){return t?(this.bindCanvas("touchstart",this._touchStart.bind(this),{passive:e},i),this.bindCanvas("touchend",this._mouseUp.bind(this),{},i),this.bindCanvas("touchmove",this._touchMove.bind(this),{passive:e},i),this.bindCanvas("touchcancel",this._mouseOut.bind(this),{},i),this._hasTouch=!0):(this.unbindCanvas("touchstart",this._touchStart.bind(this),{passive:e},i),this.unbindCanvas("touchend",this._mouseUp.bind(this),{},i),this.unbindCanvas("touchmove",this._touchMove.bind(this),{passive:e},i),this.unbindCanvas("touchcancel",this._mouseOut.bind(this),{},i),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 i=[];for(let n=0;n0,u=e.changedTouches.item(0);i=a?u.pageX-this.outerBound.x:0,n=a?u.pageY-this.outerBound.y:0,o.action&&o.action(t,i,n,e)}t&&(this._pointer.to(i,n),this._pointer.id=t)}_mouseDown(t){return this._mouseAction(v.down,t),this._mouseAction(v.pointerdown,t),this._pressed=!0,t.target instanceof Element&&t.target.setPointerCapture(t.pointerId),!1}_mouseUp(t){return this._mouseAction(v.pointerup,t),this._dragged?this._mouseAction(v.drop,t):this._mouseAction(v.up,t),this._pressed=!1,this._dragged=!1,t.target instanceof Element&&t.target.releasePointerCapture(t.pointerId),!1}_mouseMove(t){return this._pressed?(this._dragged=!0,this._mouseAction(v.drag,t)):this._mouseAction(v.move,t),!1}_mouseOver(t){return this._mouseAction(v.over,t),!1}_mouseOut(t){return this._mouseAction(v.out,t),this._dragged&&this._mouseAction(v.drop,t),this._dragged=!1,!1}_mouseClick(t){return this._mouseAction(v.click,t),this._pressed=!1,this._dragged=!1,!1}_contextMenu(t){return this._mouseAction(v.contextmenu,t),!1}_touchMove(t){return this._mouseAction(v.move,t),this._pressed&&(this._dragged=!0,this._mouseAction(v.drag,t)),t.preventDefault(),!1}_touchStart(t){return this._mouseAction(v.down,t),this._pressed=!0,!1;return t.preventDefault(),!1}_keyDown(t){return this._keyboardAction(v.keydown,t),!1}_keyUp(t){return this._keyboardAction(v.keyup,t),!1}_keyboardAction(t,e){if(this.isPlaying){for(let i in this.players)if(this.players.hasOwnProperty(i)){let n=this.players[i];n.action&&n.action(t,e.shiftKey?1:0,e.altKey?1:0,e)}}}};var It={};T(It,{Font:()=>O,Form:()=>lt,VisualForm:()=>q});var lt=class{constructor(){this._ready=!1}get ready(){return this._ready}},q=class extends lt{constructor(){super(...arguments);this._filled=!0;this._stroked=!0;this._font=new O(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,...i){if(!t)return this;for(let n=0,s=t.length;nZ});var Z=class{static textWidthEstimator(r,t=["M","n","."],e=[.06,.8,.14]){let i=t.map(r),n=new h(e).dot(i);return s=>s.length*n}static truncate(r,t,e,i=""){let n=Math.floor(t.length*Math.min(1,e/r(t)));return n0?Math.max(n,e):n}}};var Mt={};T(Mt,{Img:()=>J});var J=class l{constructor(r=!1,t,e){this._scale=1;this._loaded=!1;this._editable=r,this._space=t,this._scale=this._space?this._space.pixelScale:1,this._img=new Image,e&&(this._img.crossOrigin="Anonymous")}static load(r,t=!1,e,i){let n=new l(t,e);return n.load(r).then(s=>{i&&i(s)}),n}static loadAsync(r,t=!1,e){return et(this,null,function*(){return yield new l(t,e).load(r)})}static loadPattern(r,t,e="repeat",i=!1){return et(this,null,function*(){return(yield l.loadAsync(r,i,t)).pattern(e)})}static blank(r,t,e){let i=new l(!0,t),n=e||(t?t.pixelScale:1);return i.initCanvas(r[0],r[1],n),i}load(r){return new Promise((t,e)=>{this._editable&&!document&&e("Cannot create html canvas element. document not found."),this._img.src=r,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=i=>{e(i)}})}_drawToScale(r,t){let e=t.width,i=t.height;this.initCanvas(e,i,r),t&&this._ctx.drawImage(t,0,0,e,i,0,0,this._cv.width,this._cv.height)}initCanvas(r,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 i=typeof e=="number"?[e,e]:e;this._cv.width=r*i[0],this._cv.height=t*i[1],this._ctx=this._cv.getContext("2d"),this._loaded=!0}bitmap(r){let t=r?r[0]:this._cv.width,e=r?r[1]:this._cv.height;return createImageBitmap(this._cv,0,0,t,e)}pattern(r="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,r)}sync(){this._scale!==1?this.bitmap().then(r=>{this._drawToScale(1/this._scale,r),this.load(this.toBase64())}):this._img.src=this.toBase64()}pixel(r,t=!0){let e=typeof t=="number"?t:t?this._scale:1;return l.getPixel(this._data,[r[0]*e,r[1]*e])}static getPixel(r,t){let e=new h(0,0,0,0);if(t[0]>=r.width||t[1]>=r.height)return e;let i=Math.floor(t[1])*(r.width*4)+Math.floor(t[0])*4,n=r.data;return i>=n.length-4?e:new h(n[i],n[i+1],n[i+2],n[i+3])}resize(r,t=!1){let e=t?r:[r[0]/this._img.naturalWidth,r[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(r){let t=r.topLeft.scale(this._scale),e=r.size.scale(this._scale);return this._ctx.getImageData(t.x,t.y,e.x,e.y)}filter(r){return this._ctx.filter=r,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(r,t=!1,e){let i=URL.createObjectURL(r);return new l(t,e).load(i)}static imageDataToBlob(r){return new Promise(function(t,e){document||e("Cannot create html canvas element. document not found.");let i=document.createElement("canvas");i.width=r.width,i.height=r.height,i.getContext("2d").putImageData(r,0,0),i.toBlob(n=>{t(n),i.remove()})})}toBase64(){return this._cv.toDataURL()}toBlob(){return new Promise(r=>{this._cv.toBlob(t=>r(t))})}getForm(){return this._editable||console.error("Cannot get a CanvasForm because this Img is not editable"),this._ctx?new Q(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 h(this._img.width,this._img.height)}get canvasSize(){return new h(this._cv.width,this._cv.height)}get scaledMatrix(){let r=1/this._scale;return new C().scale2D([r,r])}};var tt=class extends Y{constructor(t,e){super();this._pixelScale=1;this._autoResize=!0;this._bgcolor="#e1e9f0";this._offscreen=!1;this._initialResize=!1;let i=null,n=!1;if(this.id="pt",t instanceof Element)i=t,this.id="pts_existing_space";else{let s=t;s=t[0]==="#"||t[0]==="."?t:"#"+t,i=document.querySelector(s),n=!0,this.id=s.substr(1)}i?i.nodeName.toLowerCase()!="canvas"?(this._container=i,this._canvas=this._createElement("canvas",this.id+"_canvas"),this._container.appendChild(this._canvas),this._initialResize=!0):(this._canvas=i,this._container=i.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),n=!1),setTimeout(this._ready.bind(this,e),100),this._ctx=this._canvas.getContext("2d")}_createElement(t="div",e){let i=document.createElement(t);return i.setAttribute("id",e),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._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,i=this._ctx.webkitBackingStorePixelRatio||this._ctx.mozBackingStorePixelRatio||this._ctx.msBackingStorePixelRatio||this._ctx.oBackingStorePixelRatio||this._ctx.backingStorePixelRatio||1;this._pixelScale=Math.max(1,e/i)}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 i in this.players)if(this.players.hasOwnProperty(i)){let n=this.players[i];n.resize&&n.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 i=G.fromBoundingRect(e);i.center=i.center.add(window.pageXOffset,window.pageYOffset),this.resize(i,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 Q(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,i=Math.ceil(this.pixelScale);return!this._bgcolor||this._bgcolor==="transparent"?this._ctx.clearRect(-i,-i,this._canvas.width+i,this._canvas.height+i):((this._bgcolor.indexOf("rgba")===0||this._bgcolor.length===9&&this._bgcolor.indexOf("#")===0)&&this._ctx.clearRect(-i,-i,this._canvas.width+i,this._canvas.height+i),this._ctx.fillStyle=this._bgcolor,this._ctx.fillRect(-i,-i,this._canvas.width+i,this._canvas.height+i)),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",i=15e6){let n=this._canvas.captureStream(),s=new MediaRecorder(n,{mimeType:`video/${e}`,bitsPerSecond:i});return s.ondataavailable=function(o){let a=URL.createObjectURL(new Blob([o.data],{type:`video/${e}`}));if(typeof t=="function")t(a);else if(t){let u=document.createElement("a");u.href=a,u.download=`canvas_video.${e}`,u.click(),u.remove()}},s}},Q=class l extends q{constructor(t){super();this._style={fillStyle:"#f03",strokeStyle:"#fff",lineWidth:1,lineJoin:"bevel",lineCap:"butt",globalAlpha:1};if(!t)return this;let e=i=>{this._ctx=i,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 tt?(this._space=t,this._space.ready&&this._space.ctx?e(this._space.ctx):this._space.add({start:()=>{e(this._space.ctx)}})):e(t)}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}fillOnly(t){return this.stroke(!1),this.fill(t)}stroke(t,e,i,n){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),i&&(this._ctx.lineJoin=i,this._style.lineJoin=i),n&&(this._ctx.lineCap=n,this._style.lineCap=n)),this}strokeOnly(t,e,i,n){return this.fill(!1),this.stroke(t,e,i,n)}applyFillStroke(t=!0,e=!0,i=1){return t&&(typeof t=="string"&&this.fill(t),this._ctx.fill()),e&&(typeof e=="string"&&this.stroke(e,i),this._ctx.stroke()),this}gradient(t){let e=[];t.length<2&&t.push([.99,"#000"],[1,"#000"]);for(let i=0,n=t.length;i{let s=n?this._ctx.createRadialGradient(i[0][0],i[0][1],Math.abs(i[1][0]),n[0][0],n[0][1],Math.abs(n[1][0])):this._ctx.createLinearGradient(i[0][0],i[0][1],i[1][0],i[1][1]);for(let o=0,a=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,i=""){return Z.truncate(this.getTextWidth.bind(this),t,e,i)}_textAlign(t,e,i,n){let s=m.iterToArray(t);if(!m.arrayCheck(s))return;n||(n=M.center(s));let 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=n[0]);let a=n[1];return e=="top"||e=="start"?a=s[0][1]:(e=="end"||e=="bottom")&&(a=s[1][1]),i?new h(o+i[0],a+i[1]):new h(o,a)}reset(){for(let t in this._style)this._style.hasOwnProperty(t)&&(this._ctx[t]=this._style[t]);return this._font=new O,this._ctx.font=this._font.value,this}_paint(){this._filled&&this._ctx.fill(),this._stroked&&this._ctx.stroke()}static point(t,e,i=5,n="square"){if(e){if(!l[n])throw new Error(`${n} is not a static function of CanvasForm`);l[n](t,e,i)}}point(t,e=5,i="square"){return l.point(this._ctx,t,e,i),this._paint(),this}static circle(t,e,i=10){e&&(t.beginPath(),t.arc(e[0],e[1],i,0,w.two_pi,!1),t.closePath())}circle(t){let e=m.iterToArray(t);return l.circle(this._ctx,e[0],e[1][0]),this._paint(),this}static ellipse(t,e,i,n=0,s=0,o=w.two_pi,a=!1){!e||!i||(t.beginPath(),t.ellipse(e[0],e[1],i[0],i[1],n,s,o,a))}ellipse(t,e,i=0,n=0,s=w.two_pi,o=!1){return l.ellipse(this._ctx,t,e,i,n,s,o),this._paint(),this}static arc(t,e,i,n,s,o){e&&(t.beginPath(),t.arc(e[0],e[1],i,n,s,o))}arc(t,e,i,n,s){return l.arc(this._ctx,t,e,i,n,s),this._paint(),this}static square(t,e,i){if(!e)return;let n=e[0]-i,s=e[1]-i,o=e[0]+i,a=e[1]+i;t.beginPath(),t.moveTo(n,s),t.lineTo(n,a),t.lineTo(o,a),t.lineTo(o,s),t.closePath()}square(t,e){return l.square(this._ctx,t,e),this._paint(),this}static line(t,e){if(!m.arrayCheck(e))return;let i=0;t.beginPath();for(let n of e)n&&(i++>0?t.lineTo(n[0],n[1]):t.moveTo(n[0],n[1]))}line(t){return l.line(this._ctx,t),this._paint(),this}static polygon(t,e){m.arrayCheck(e)&&(l.line(t,e),t.closePath())}polygon(t){return l.polygon(this._ctx,t),this._paint(),this}static rect(t,e){let i=m.iterToArray(e);m.arrayCheck(i)&&(t.beginPath(),t.moveTo(i[0][0],i[0][1]),t.lineTo(i[0][0],i[1][1]),t.lineTo(i[1][0],i[1][1]),t.lineTo(i[1][0],i[0][1]),t.closePath())}rect(t){return l.rect(this._ctx,t),this._paint(),this}static image(t,e,i,n){let s=m.iterToArray(e),o;if(typeof s[0]=="number")o=s;else if(n){let a=m.iterToArray(n);o=[a[0][0],a[0][1],a[1][0]-a[0][0],a[1][1]-a[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]];i instanceof J?i.loaded&&t.drawImage(i.image,...o):t.drawImage(i,...o)}image(t,e,i){return e instanceof J?e.loaded&&l.image(this._ctx,t,e.image,i):l.image(this._ctx,t,e,i),this}static imageData(t,e,i){let n=m.iterToArray(e);typeof n[0]=="number"?t.putImageData(i,n[0],n[1]):t.putImageData(i,n[0][0],n[0][1],n[0][0],n[0][1],n[1][0],n[1][1])}imageData(t,e){return l.imageData(this._ctx,t,e),this}static text(t,e,i,n){e&&t.fillText(i,e[0],e[1],n)}text(t,e,i){return l.text(this._ctx,t,e,i),this}textBox(t,e,i="middle",n="",s=!0){s&&(this._ctx.textBaseline=i);let o=M.size(t),a=this._textTruncate(e,o[0],n);return this.text(this._textAlign(t,i),a[0]),this}paragraphBox(t,e,i=1.2,n="top",s=!0){let o=m.iterToArray(t),a=M.size(o);this._ctx.textBaseline="top";let u=this._font.size*i,c=(_,D=[],A=0)=>{if(!_||s&&A*u>a[1]-u*2)return D;if(A>1e4)throw new Error("max recursion reached (10000)");let U=this._textTruncate(_,a[0],""),bt=U[0].indexOf(` +`),p}function f(p){for(p=c(p),a(p),n=0;n=r&&(e=0);let p=1768863*i[e]+t*23283064365386963e-26;return i[e]=p-(t=p|0)}}}var L=class l{static equals(r,t,e=1e-5){return Math.abs(r-t)e?n-=i:n=Math.min(t,e)&&r<=Math.max(t,e)}static randomRange(r,t=0){let e=r>t?r-t:t-r;return r+l.random()*e}static randomPt(r,t){let e=new h(r.length),i=t?k.subtract(t.slice(),r):r,n=t?r:new h(r.length).fill(0);for(let s=0,o=e.length;s.5?2-r*2:r*2)}static mapToRange(r,t,e,i,n){if(t==e)throw new Error("[currMin, currMax] must define a range that is not zero");let s=Math.min(i,n),o=Math.max(i,n);return l.normalizeValue(r,t,e)*(o-s)+s}static seed(r){this.generator=Ut(r)}static random(){return this.generator?this.generator.random():Math.random()}},y=class l{static boundAngle(r){return L.boundValue(r,0,360)}static boundRadian(r){return L.boundValue(r,0,w.two_pi)}static toRadian(r){return r*w.deg_to_rad}static toDegree(r){return r*w.rad_to_deg}static boundingBox(r){let t,e;for(let i of r)t==null?(t=i.clone(),e=i.clone()):(t=t.$min(i),e=e.$max(i));return new d(t,e)}static centroid(r){return L.average(r)}static anchor(r,t=0,e="to"){let i=e=="to"?"subtract":"add",n=0;for(let s of r)typeof t=="number"?t!==n&&s[i](r[t]):s[i](t),n++}static interpolate(r,t,e=.5){let i=Math.min(r.length,t.length),n=h.make(i);for(let s=0;s{if(s.length<2||o.length<2)throw new Error("Pt dimension cannot be less than 2");let a=s.$subtract(i),u=o.$subtract(i);if(a[0]>=0&&u[0]<0)return 1;if(a[0]<0&&u[0]>=0)return-1;if(a[0]==0&&u[0]==0)return a[1]>=0||u[1]>=0?a[1]>u[1]?1:-1:u[1]>a[1]?1:-1;let c=a.$cross2D(u);return c<0?1:c>0?-1:a[0]*a[0]+a[1]*a[1]>u[0]*u[0]+u[1]*u[1]?1:-1};return t.sort(n)}static scale(r,t,e){let i=m.iterToArray(r[0]!==void 0&&typeof r[0]=="number"?[r]:r),n=typeof t=="number"?h.make(i[0].length,t):t;e||(e=h.make(i[0].length,0));for(let s=0,o=i.length;sr[Math.floor(l.boundAngle(l.toDegree(e)))]}}static sinTable(){let r=new Float64Array(360);for(let e=0;e<360;e++)r[e]=Math.sin(e*Math.PI/180);return{table:r,sin:e=>r[Math.floor(l.boundAngle(l.toDegree(e)))]}}},st=class l{static linear(r,t=1){return t*r}static quadraticIn(r,t=1){return t*r*r}static quadraticOut(r,t=1){return-t*r*(r-2)}static quadraticInOut(r,t=1){let e=r*2;return r<.5?t/2*r*r*4:-t/2*((e-1)*(e-3)-1)}static cubicIn(r,t=1){return t*r*r*r}static cubicOut(r,t=1){let e=r-1;return t*(e*e*e+1)}static cubicInOut(r,t=1){let e=r*2;return r<.5?t/2*e*e*e:t/2*((e-2)*(e-2)*(e-2)+2)}static exponentialIn(r,t=1,e=.25){return t*Math.pow(r,1/e)}static exponentialOut(r,t=1,e=.25){return t*Math.pow(r,e)}static sineIn(r,t=1){return-t*Math.cos(r*w.half_pi)+t}static sineOut(r,t=1){return t*Math.sin(r*w.half_pi)}static sineInOut(r,t=1){return-t/2*(Math.cos(Math.PI*r)-1)}static cosineApprox(r,t=1){let e=r*r,i=e*e,n=i*e;return t*(4*n/9-17*i/9+22*e/9)}static circularIn(r,t=1){return-t*(Math.sqrt(1-r*r)-1)}static circularOut(r,t=1){let e=r-1;return t*Math.sqrt(1-e*e)}static circularInOut(r,t=1){let e=r*2;return r<.5?-t/2*(Math.sqrt(1-e*e)-1):t/2*(Math.sqrt(1-(e-2)*(e-2))+1)}static elasticIn(r,t=1,e=.7){let i=r-1,n=e/w.two_pi*1.5707963267948966;return t*(-Math.pow(2,10*i)*Math.sin((i-n)*w.two_pi/e))}static elasticOut(r,t=1,e=.7){let i=e/w.two_pi*1.5707963267948966;return t*(Math.pow(2,-10*r)*Math.sin((r-i)*w.two_pi/e))+t}static elasticInOut(r,t=1,e=.6){let i=r*2,n=e/w.two_pi*1.5707963267948966;return r<.5?(i-=1,t*(-.5*(Math.pow(2,10*i)*Math.sin((i-n)*w.two_pi/e)))):(i-=1,t*(.5*(Math.pow(2,-10*i)*Math.sin((i-n)*w.two_pi/e)))+t)}static bounceIn(r,t=1){return t-l.bounceOut(1-r,t)}static bounceOut(r,t=1){return r<1/2.75?t*(7.5625*r*r):r<2/2.75?(r-=1.5/2.75,t*(7.5625*r*r+.75)):r<2.5/2.75?(r-=2.25/2.75,t*(7.5625*r*r+.9375)):(r-=2.625/2.75,t*(7.5625*r*r+.984375))}static bounceInOut(r,t=1){return r<.5?l.bounceIn(r*2,t)/2:l.bounceOut(r*2-1,t)/2+t/2}static sigmoid(r,t=1,e=10){let i=e*(r-.5);return t/(1+Math.exp(-i))}static logSigmoid(r,t=1,e=.7){e=Math.max(w.epsilon,Math.min(1-w.epsilon,e)),e=1/(1-e);let i=1/(1+Math.exp((r-.5)*e*-2)),n=1/(1+Math.exp(e)),s=1/(1+Math.exp(-e));return t*(i-n)/(s-n)}static seat(r,t=1,e=.5){return r<.5?t*Math.pow(2*r,1-e)/2:t*(1-Math.pow(2*(1-r),1-e)/2)}static quadraticBezier(r,t=1,e=[.05,.95]){let i=typeof e!="number"?e[0]:e,n=typeof e!="number"?e[1]:.5,s=1-2*i;s===0&&(s=w.epsilon);let o=(Math.sqrt(i*i+s*r)-i)/s;return t*((1-2*n)*(o*o)+2*n*o)}static cubicBezier(r,t=1,e=[.1,.7],i=[.9,.2]){let n=new d(new h(0,0),new h(e),new h(i),new h(1,1));return t*K.bezierStep(new h(r*r*r,r*r,r,1),K.controlPoints(n)).y}static quadraticTarget(r,t=1,e=[.2,.35]){let i=Math.min(1-w.epsilon,Math.max(w.epsilon,e[0])),n=Math.min(1,Math.max(0,e[1])),s=(1-n)/(1-i)-n/i,o=(s*(i*i)-n)/i,a=s*(r*r)-o*r;return t*Math.min(1,Math.max(0,a))}static cliff(r,t=1,e=.5){return r>e?t:0}static step(r,t,e,i,...n){let s=1/t,o=Math.floor(e/s)*s;return r(o,i,...n)}},yt=class{constructor(r){this._dims=0;this._source=d.fromPtArray(r),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 r=this._source[0].length;this._dims=r;let t=new h(r),e=new h(r),i=new h(r);for(let n=0;n=n.length||!(i[s]in n));s++)t.push(n[i[s]])}else e&&(t=[].slice.call(r[0]));return t}static warn(r="error",t=void 0){if(H.warnLevel()=="error")throw new Error(r);return H.warnLevel()=="warn"&&console.warn(r),t}static randomInt(r,t=0){return H.warn("Util.randomInt is deprecated. Please use `Num.randomRange`"),Math.floor(L.random()*r)+t}static split(r,t,e,i=!1,n=!0){let s=[],o=[],a=e||t,u=0;if(r.length<=0||a<=0)return[];for(;u=r.length)break;o.push(r[u+c])}u+=a,(!n||n&&o.length===t)&&s.push(o)}return s}static flatten(r,t=!0){let e=t?new d:[];return e.concat.apply(e,r)}static combine(r,t,e){let i=[];for(let n=0,s=r.length;n=r&&(n=t+(n-r)),i&&i(n),n}}static forRange(r,t,e=0,i=1){let n=[];for(let s=e,o=t;s=200&&e.status<400?t(e.responseText,!0):t(`Server error (${e.status}) when loading "${r}"`,!1)},e.onerror=function(){t("Unknown network error",!1)},e.send()}static download(r,t="pts_canvas_image",e="png",i=1){let n=e==="jpg"?"jpeg":e;r.element.toBlob(function(s){let o=document.createElement("a"),a=URL.createObjectURL(s);o.href=a,o.download=`${t}.${e}`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(a)},`image/${n}`,i)}static performance(r=10){let t=Date.now(),e=[];return function(){let i=Date.now();return e.push(i-t),e.length>=r&&e.shift(),t=i,Math.floor(e.reduce((n,s)=>n+s,0)/e.length)}}static arrayCheck(r,t=2){return Array.isArray(r)&&r.length0?m.getArgs(r):[0,0],super(t)}static make(r,t=0,e=!1){let i=new Float32Array(r);if(t&&i.fill(t),e)for(let n=0,s=i.length;nt)return!1;return!0}to(...r){let t=m.getArgs(r);for(let e=0,i=Math.min(this.length,t.length);er(t,...e)}ops(r){let t=[];for(let e=0,i=r.length;er(t,...e)}ops(r){let t=[];for(let e=0,i=r.length;et?i[r]-e[r]:e[r]-i[r])}forEachPt(r,...t){if(!this[0][r])return m.warn(`${r} is not a function of Pt`),this;for(let e=0,i=this.length;er+t.toString()+" ","")+" ]"}},G=class l extends d{constructor(...t){super(...t);this._center=new h;this._size=new h;this._topLeft=new h;this._bottomRight=new h;this._inited=!1;this.init()}static fromBoundingRect(t){let e=new l(new h(t.left||0,t.top||0),new h(t.right||0,t.bottom||0));return t.width&&t.height&&(e.size=new h(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 l(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 l(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 h(this._size)}set size(t){this._size=new h(t),this._updatePosFromTop()}get center(){return new h(this._center)}set center(t){this._center=new h(t),this._updatePosFromCenter()}get topLeft(){return new h(this._topLeft)}set topLeft(t){this._topLeft=new h(t),this[0]=this._topLeft,this._updateSize()}get bottomRight(){return new h(this._bottomRight)}set bottomRight(t){this._bottomRight=new h(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 vt={};T(vt,{UI:()=>W,UIButton:()=>ot,UIDragger:()=>kt,UIPointerActions:()=>v,UIShape:()=>X});var X={rectangle:"rectangle",circle:"circle",polygon:"polygon",polyline:"polyline",line:"line"},v={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",pointerdown:"pointerdown",pointerup:"pointerup",contextmenu:"contextmenu",all:"all"},V=class V{constructor(r,t,e={},i){this._holds=new Map;this._group=d.fromArray(r),this._shape=t,this._id=i===void 0?`ui_${V._counter++}`:i,this._states=e,this._actions={}}static fromRectangle(r,t,e){return new this(r,X.rectangle,t,e)}static fromCircle(r,t,e){return new this(r,X.circle,t,e)}static fromPolygon(r,t,e){return new this(r,X.polygon,t,e)}static fromUI(r,t,e){return new this(r.group,r.shape,t||r._states,e)}get id(){return this._id}set id(r){this._id=r}get group(){return this._group}set group(r){this._group=r}get shape(){return this._shape}set shape(r){this._shape=r}state(r,t){return r?t!==void 0?(this._states[r]=t,this):this._states[r]:null}on(r,t){return this._actions[r]||(this._actions[r]=[]),V._addHandler(this._actions[r],t)}off(r,t){return this._actions[r]?t===void 0?(delete this._actions[r],!0):V._removeHandler(this._actions[r],t):!1}listen(r,t,e){if(this._actions[r]!==void 0){if(this._within(t)||Array.from(this._holds.values()).indexOf(r)>=0)return V._trigger(this._actions[r],this,t,r,e),!0;if(this._actions.all)return V._trigger(this._actions.all,this,t,r,e),!0}return!1}hold(r){let t=Math.max(0,...Array.from(this._holds.keys()))+1;return this._holds.set(t,r),t}unhold(r){r!==void 0?this._holds.delete(r):this._holds.clear()}static track(r,t,e,i){for(let n=0,s=r.length;n=0&&tr.length}else return!1}};V._counter=0;var W=V,ot=class extends W{constructor(t,e,i={},n){super(t,e,i,n);this._hoverID=-1;i.hover===void 0&&(this._states.hover=!1),i.clicks===void 0&&(this._states.clicks=0);let s=v;this.on(s.up,(o,a,u,c)=>{this.state("clicks",this._states.clicks+1)}),this.on(s.move,(o,a,u,c)=>{if(this._within(a)&&!this._states.hover){this.state("hover",!0),W._trigger(this._actions[s.enter],this,a,s.enter,c);let p=this.hold(s.move);this._hoverID=this.on(s.move,(b,P)=>{!this._within(P)&&!this.state("dragging")&&(this.state("hover",!1),W._trigger(this._actions[s.leave],this,a,s.leave,c),this.off(s.move,this._hoverID),this.unhold(p))})}})}onClick(t){return this.on(v.up,t)}offClick(t){return this.off(v.up,t)}onContextMenu(t){return this.on(v.contextmenu,t)}offContextMenu(t){return this.off(v.contextmenu,t)}onHover(t,e){let i=[void 0,void 0];return t&&(i[0]=this.on(v.enter,t)),e&&(i[1]=this.on(v.leave,e)),i}offHover(t,e){let i=[!1,!1];return(t===void 0||t>=0)&&(i[0]=this.off(v.enter,t)),(e===void 0||e>=0)&&(i[1]=this.off(v.leave,e)),i}},kt=class extends ot{constructor(t,e,i={},n){super(t,e,i,n);this._draggingID=-1;this._moveHoldID=-1;this._dropHoldID=-1;this._upHoldID=-1;i.dragging===void 0&&(this._states.dragging=!1),i.moved===void 0&&(this._states.moved=!1),i.offset===void 0&&(this._states.offset=new h);let s=v;this.on(s.down,(a,u,c,f)=>{this._moveHoldID===-1&&(this.state("dragging",!0),this.state("offset",new h(u).subtract(a.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,(p,b)=>{this.state("dragging")&&(W._trigger(this._actions[s.uidrag],p,b,s.uidrag,f),this.state("moved",!0))}))});let o=(a,u,c,f)=>{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")&&(W._trigger(this._actions[s.uidrop],a,u,s.uidrop,f),this.state("moved",!1))};this.on(s.drop,o),this.on(s.up,o),this.on(s.out,o)}onDrag(t){return this.on(v.uidrag,t)}offDrag(t){return this.off(v.uidrag,t)}onDrop(t){return this.on(v.uidrop,t)}offDrop(t){return this.off(v.uidrop,t)}};var at=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 h;this._isReady=!1;this._playing=!1}refresh(r){return this._refresh=r,this}minFrameTime(r=0){this._time.min=r}add(r){let t=typeof r=="function"?{animate:r}:r,e=this.playerCount++,i=t.animateID||this.id+e;return this.players[i]=t,t.animateID=i,t.resize&&this.bound.inited&&t.resize(this.bound),this._refresh===void 0&&(this._refresh=!0),this}remove(r){return delete this.players[r.animateID],this}removeAll(){return this.players={},this}play(r=0){if(!(r===0&&this._animID!==-1)){if(this._animID=requestAnimationFrame(this.play.bind(this)),this._pause)return this;if(this._time.diff=r-this._time.prev,this._time.diff=0&&r>this._time.end&&(cancelAnimationFrame(this._animID),this._animID=-1,this._playing=!1)}pause(r=!1){return this._pause=r?!this._pause:!0,this}resume(){return this._pause=!1,this}stop(r=0){return this._time.end=r,this}playOnce(r=0){return this.play(),this.stop(r),this}render(r){return this._renderFunc&&this._renderFunc(r,this),this}set customRendering(r){this._renderFunc=r}get customRendering(){return this._renderFunc}get isPlaying(){return this._playing}get outerBound(){return this.bound.clone()}get innerBound(){return new G(h.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}},Y=class extends at{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,i={},n){(n||this._canvas).addEventListener(t,e,i)}unbindCanvas(t,e,i={},n){(n||this._canvas).removeEventListener(t,e,i)}bindDoc(t,e,i={}){document&&document.addEventListener(t,e,i)}unbindDoc(t,e,i={}){document&&document.removeEventListener(t,e,i)}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("pointerdown",this._mouseDown,{},e),this.bindCanvas("pointerup",this._mouseUp,{},e),this.bindCanvas("pointerover",this._mouseOver,{},e),this.bindCanvas("pointerout",this._mouseOut,{},e),this.bindCanvas("pointermove",this._mouseMove,{},e),this.bindCanvas("click",this._mouseClick,{},e),this.bindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!0):(this.unbindCanvas("pointerdown",this._mouseDown,{},e),this.unbindCanvas("pointerup",this._mouseUp,{},e),this.unbindCanvas("pointerover",this._mouseOver,{},e),this.unbindCanvas("pointerout",this._mouseOut,{},e),this.unbindCanvas("pointermove",this._mouseMove,{},e),this.unbindCanvas("click",this._mouseClick,{},e),this.unbindCanvas("contextmenu",this._contextMenu,{},e),this._hasMouse=!1),this}bindTouch(t=!0,e=!1,i){return t?(this.bindCanvas("touchstart",this._touchStart.bind(this),{passive:e},i),this.bindCanvas("touchend",this._mouseUp.bind(this),{},i),this.bindCanvas("touchmove",this._touchMove.bind(this),{passive:e},i),this.bindCanvas("touchcancel",this._mouseOut.bind(this),{},i),this._hasTouch=!0):(this.unbindCanvas("touchstart",this._touchStart.bind(this),{passive:e},i),this.unbindCanvas("touchend",this._mouseUp.bind(this),{},i),this.unbindCanvas("touchmove",this._touchMove.bind(this),{passive:e},i),this.unbindCanvas("touchcancel",this._mouseOut.bind(this),{},i),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 i=[];for(let n=0;n0,u=e.changedTouches.item(0);i=a?u.pageX-this.outerBound.x:0,n=a?u.pageY-this.outerBound.y:0,o.action&&o.action(t,i,n,e)}t&&(this._pointer.to(i,n),this._pointer.id=t)}_mouseDown(t){return this._mouseAction(v.down,t),this._mouseAction(v.pointerdown,t),this._pressed=!0,t.target instanceof Element&&t.target.setPointerCapture(t.pointerId),!1}_mouseUp(t){return this._mouseAction(v.pointerup,t),this._dragged?this._mouseAction(v.drop,t):this._mouseAction(v.up,t),this._pressed=!1,this._dragged=!1,t.target instanceof Element&&t.target.releasePointerCapture(t.pointerId),!1}_mouseMove(t){return this._pressed?(this._dragged=!0,this._mouseAction(v.drag,t)):this._mouseAction(v.move,t),!1}_mouseOver(t){return this._mouseAction(v.over,t),!1}_mouseOut(t){return this._mouseAction(v.out,t),this._dragged&&this._mouseAction(v.drop,t),this._dragged=!1,!1}_mouseClick(t){return this._mouseAction(v.click,t),this._pressed=!1,this._dragged=!1,!1}_contextMenu(t){return this._mouseAction(v.contextmenu,t),!1}_touchMove(t){return this._mouseAction(v.move,t),this._pressed&&(this._dragged=!0,this._mouseAction(v.drag,t)),t.preventDefault(),!1}_touchStart(t){return this._mouseAction(v.down,t),this._pressed=!0,!1;return t.preventDefault(),!1}_keyDown(t){return this._keyboardAction(v.keydown,t),!1}_keyUp(t){return this._keyboardAction(v.keyup,t),!1}_keyboardAction(t,e){if(this.isPlaying){for(let i in this.players)if(this.players.hasOwnProperty(i)){let n=this.players[i];n.action&&n.action(t,e.shiftKey?1:0,e.altKey?1:0,e)}}}};var It={};T(It,{Font:()=>O,Form:()=>lt,VisualForm:()=>q});var lt=class{constructor(){this._ready=!1}get ready(){return this._ready}},q=class extends lt{constructor(){super(...arguments);this._filled=!0;this._stroked=!0;this._font=new O(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,...i){if(!t)return this;for(let n=0,s=t.length;nZ});var Z=class{static textWidthEstimator(r,t=["M","n","."],e=[.06,.8,.14]){let i=t.map(r),n=new h(e).dot(i);return s=>s.length*n}static truncate(r,t,e,i=""){let n=Math.floor(t.length*Math.min(1,e/r(t)));return n0?Math.max(n,e):n}}};var Mt={};T(Mt,{Img:()=>J});var J=class l{constructor(r=!1,t,e){this._scale=1;this._loaded=!1;this._editable=r,this._space=t,this._scale=this._space?this._space.pixelScale:1,this._img=new Image,e&&(this._img.crossOrigin="Anonymous")}static load(r,t=!1,e,i){let n=new l(t,e);return n.load(r).then(s=>{i&&i(s)}),n}static loadAsync(r,t=!1,e){return et(this,null,function*(){return yield new l(t,e).load(r)})}static loadPattern(r,t,e="repeat",i=!1){return et(this,null,function*(){return(yield l.loadAsync(r,i,t)).pattern(e)})}static blank(r,t,e){let i=new l(!0,t),n=e||(t?t.pixelScale:1);return i.initCanvas(r[0],r[1],n),i}load(r){return new Promise((t,e)=>{this._editable&&!document&&e("Cannot create html canvas element. document not found."),this._img.src=r,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=i=>{e(i)}})}_drawToScale(r,t){let e=t.width,i=t.height;this.initCanvas(e,i,r),t&&this._ctx.drawImage(t,0,0,e,i,0,0,this._cv.width,this._cv.height)}initCanvas(r,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 i=typeof e=="number"?[e,e]:e;this._cv.width=r*i[0],this._cv.height=t*i[1],this._ctx=this._cv.getContext("2d"),this._loaded=!0}bitmap(r){let t=r?r[0]:this._cv.width,e=r?r[1]:this._cv.height;return createImageBitmap(this._cv,0,0,t,e)}pattern(r="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,r)}sync(){this._scale!==1?this.bitmap().then(r=>{this._drawToScale(1/this._scale,r),this.load(this.toBase64())}):this._img.src=this.toBase64()}pixel(r,t=!0){let e=typeof t=="number"?t:t?this._scale:1;return l.getPixel(this._data,[r[0]*e,r[1]*e])}static getPixel(r,t){let e=new h(0,0,0,0);if(t[0]>=r.width||t[1]>=r.height)return e;let i=Math.floor(t[1])*(r.width*4)+Math.floor(t[0])*4,n=r.data;return i>=n.length-4?e:new h(n[i],n[i+1],n[i+2],n[i+3])}resize(r,t=!1){let e=t?r:[r[0]/this._img.naturalWidth,r[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(r){let t=r.topLeft.scale(this._scale),e=r.size.scale(this._scale);return this._ctx.getImageData(t.x,t.y,e.x,e.y)}filter(r){return this._ctx.filter=r,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(r,t=!1,e){let i=URL.createObjectURL(r);return new l(t,e).load(i)}static imageDataToBlob(r){return new Promise(function(t,e){document||e("Cannot create html canvas element. document not found.");let i=document.createElement("canvas");i.width=r.width,i.height=r.height,i.getContext("2d").putImageData(r,0,0),i.toBlob(n=>{t(n),i.remove()})})}toBase64(){return this._cv.toDataURL()}toBlob(){return new Promise(r=>{this._cv.toBlob(t=>r(t))})}getForm(){return this._editable||console.error("Cannot get a CanvasForm because this Img is not editable"),this._ctx?new Q(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 h(this._img.width,this._img.height)}get canvasSize(){return new h(this._cv.width,this._cv.height)}get scaledMatrix(){let r=1/this._scale;return new C().scale2D([r,r])}};var tt=class extends Y{constructor(t,e){super();this._pixelScale=1;this._autoResize=!0;this._bgcolor="#e1e9f0";this._offscreen=!1;this._initialResize=!1;let i=null,n=!1;if(this.id=m.uniqueId(),t instanceof Element)i=t,this.id=i.id||this.id;else{let s=t;s=t[0]==="#"||t[0]==="."?t:"#"+t,i=document.querySelector(s),this.id=s.substr(1)}if(i?i.nodeName.toLowerCase()!="canvas"?(this._container=i,this._canvas=this._createElement("canvas",this.id+"_canvas"),this._initialResize=!0):(this._canvas=i,this._container=i.parentElement,this._autoResize=!1,n=!0):(this._container=this._createElement("div",this.id+"_container"),this._canvas=this._createElement("canvas",this.id),document.body.appendChild(this._container)),n)this._ready(e);else{let s=new MutationObserver(o=>{o.forEach(a=>{if(a.type==="childList"&&a.addedNodes.length){for(let u of a.addedNodes)if(u===this._canvas){this._ready(e),s.disconnect();return}}})});s.observe(this._container,{childList:!0}),this._container.appendChild(this._canvas)}this._ctx=this._canvas.getContext("2d")}_createElement(t="div",e){let i=document.createElement(t);return i.setAttribute("id",e),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._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,i=this._ctx.webkitBackingStorePixelRatio||this._ctx.mozBackingStorePixelRatio||this._ctx.msBackingStorePixelRatio||this._ctx.oBackingStorePixelRatio||this._ctx.backingStorePixelRatio||1;this._pixelScale=Math.max(1,e/i)}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 i in this.players)if(this.players.hasOwnProperty(i)){let n=this.players[i];n.resize&&n.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 i=G.fromBoundingRect(e);i.center=i.center.add(window.pageXOffset,window.pageYOffset),this.resize(i,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 Q(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,i=Math.ceil(this.pixelScale);return!this._bgcolor||this._bgcolor==="transparent"?this._ctx.clearRect(-i,-i,this._canvas.width+i,this._canvas.height+i):((this._bgcolor.indexOf("rgba")===0||this._bgcolor.length===9&&this._bgcolor.indexOf("#")===0)&&this._ctx.clearRect(-i,-i,this._canvas.width+i,this._canvas.height+i),this._ctx.fillStyle=this._bgcolor,this._ctx.fillRect(-i,-i,this._canvas.width+i,this._canvas.height+i)),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",i=15e6){let n=this._canvas.captureStream(),s=new MediaRecorder(n,{mimeType:`video/${e}`,bitsPerSecond:i});return s.ondataavailable=function(o){let a=URL.createObjectURL(new Blob([o.data],{type:`video/${e}`}));if(typeof t=="function")t(a);else if(t){let u=document.createElement("a");u.href=a,u.download=`canvas_video.${e}`,u.click(),u.remove()}},s}},Q=class l extends q{constructor(t){super();this._style={fillStyle:"#f03",strokeStyle:"#fff",lineWidth:1,lineJoin:"bevel",lineCap:"butt",globalAlpha:1};if(!t)return this;let e=i=>{this._ctx=i,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 tt?(this._space=t,this._space.ready&&this._space.ctx?e(this._space.ctx):this._space.add({start:()=>{e(this._space.ctx)}})):e(t)}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}fillOnly(t){return this.stroke(!1),this.fill(t)}stroke(t,e,i,n){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),i&&(this._ctx.lineJoin=i,this._style.lineJoin=i),n&&(this._ctx.lineCap=n,this._style.lineCap=n)),this}strokeOnly(t,e,i,n){return this.fill(!1),this.stroke(t,e,i,n)}applyFillStroke(t=!0,e=!0,i=1){return t&&(typeof t=="string"&&this.fill(t),this._ctx.fill()),e&&(typeof e=="string"&&this.stroke(e,i),this._ctx.stroke()),this}gradient(t){let e=[];t.length<2&&t.push([.99,"#000"],[1,"#000"]);for(let i=0,n=t.length;i{let s=n?this._ctx.createRadialGradient(i[0][0],i[0][1],Math.abs(i[1][0]),n[0][0],n[0][1],Math.abs(n[1][0])):this._ctx.createLinearGradient(i[0][0],i[0][1],i[1][0],i[1][1]);for(let o=0,a=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,i=""){return Z.truncate(this.getTextWidth.bind(this),t,e,i)}_textAlign(t,e,i,n){let s=m.iterToArray(t);if(!m.arrayCheck(s))return;n||(n=M.center(s));let 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=n[0]);let a=n[1];return e=="top"||e=="start"?a=s[0][1]:(e=="end"||e=="bottom")&&(a=s[1][1]),i?new h(o+i[0],a+i[1]):new h(o,a)}reset(){for(let t in this._style)this._style.hasOwnProperty(t)&&(this._ctx[t]=this._style[t]);return this._font=new O,this._ctx.font=this._font.value,this}_paint(){this._filled&&this._ctx.fill(),this._stroked&&this._ctx.stroke()}static point(t,e,i=5,n="square"){if(e){if(!l[n])throw new Error(`${n} is not a static function of CanvasForm`);l[n](t,e,i)}}point(t,e=5,i="square"){return l.point(this._ctx,t,e,i),this._paint(),this}static circle(t,e,i=10){e&&(t.beginPath(),t.arc(e[0],e[1],i,0,w.two_pi,!1),t.closePath())}circle(t){let e=m.iterToArray(t);return l.circle(this._ctx,e[0],e[1][0]),this._paint(),this}static ellipse(t,e,i,n=0,s=0,o=w.two_pi,a=!1){!e||!i||(t.beginPath(),t.ellipse(e[0],e[1],i[0],i[1],n,s,o,a))}ellipse(t,e,i=0,n=0,s=w.two_pi,o=!1){return l.ellipse(this._ctx,t,e,i,n,s,o),this._paint(),this}static arc(t,e,i,n,s,o){e&&(t.beginPath(),t.arc(e[0],e[1],i,n,s,o))}arc(t,e,i,n,s){return l.arc(this._ctx,t,e,i,n,s),this._paint(),this}static square(t,e,i){if(!e)return;let n=e[0]-i,s=e[1]-i,o=e[0]+i,a=e[1]+i;t.beginPath(),t.moveTo(n,s),t.lineTo(n,a),t.lineTo(o,a),t.lineTo(o,s),t.closePath()}square(t,e){return l.square(this._ctx,t,e),this._paint(),this}static line(t,e){if(!m.arrayCheck(e))return;let i=0;t.beginPath();for(let n of e)n&&(i++>0?t.lineTo(n[0],n[1]):t.moveTo(n[0],n[1]))}line(t){return l.line(this._ctx,t),this._paint(),this}static polygon(t,e){m.arrayCheck(e)&&(l.line(t,e),t.closePath())}polygon(t){return l.polygon(this._ctx,t),this._paint(),this}static rect(t,e){let i=m.iterToArray(e);m.arrayCheck(i)&&(t.beginPath(),t.moveTo(i[0][0],i[0][1]),t.lineTo(i[0][0],i[1][1]),t.lineTo(i[1][0],i[1][1]),t.lineTo(i[1][0],i[0][1]),t.closePath())}rect(t){return l.rect(this._ctx,t),this._paint(),this}static image(t,e,i,n){let s=m.iterToArray(e),o;if(typeof s[0]=="number")o=s;else if(n){let a=m.iterToArray(n);o=[a[0][0],a[0][1],a[1][0]-a[0][0],a[1][1]-a[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]];i instanceof J?i.loaded&&t.drawImage(i.image,...o):t.drawImage(i,...o)}image(t,e,i){return e instanceof J?e.loaded&&l.image(this._ctx,t,e.image,i):l.image(this._ctx,t,e,i),this}static imageData(t,e,i){let n=m.iterToArray(e);typeof n[0]=="number"?t.putImageData(i,n[0],n[1]):t.putImageData(i,n[0][0],n[0][1],n[0][0],n[0][1],n[1][0],n[1][1])}imageData(t,e){return l.imageData(this._ctx,t,e),this}static text(t,e,i,n){e&&t.fillText(i,e[0],e[1],n)}text(t,e,i){return l.text(this._ctx,t,e,i),this}textBox(t,e,i="middle",n="",s=!0){s&&(this._ctx.textBaseline=i);let o=M.size(t),a=this._textTruncate(e,o[0],n);return this.text(this._textAlign(t,i),a[0]),this}paragraphBox(t,e,i=1.2,n="top",s=!0){let o=m.iterToArray(t),a=M.size(o);this._ctx.textBaseline="top";let u=this._font.size*i,c=(_,D=[],A=0)=>{if(!_||s&&A*u>a[1]-u*2)return D;if(A>1e4)throw new Error("max recursion reached (10000)");let U=this._textTruncate(_,a[0],""),bt=U[0].indexOf(` `);if(bt>=0)return D.push(U[0].substr(0,bt)),c(_.substr(bt+1),D,A+1);let nt=U[0].lastIndexOf(" ")+1;(nt<=0||U[1]===_.length)&&(nt=void 0);let Nt=U[0].substr(0,nt);return D.push(Nt),U[1]<=0||U[1]===_.length?D:c(_.substr(nt||U[1]),D,A+1)},f=c(e),p=f.length*u,b=o;if(n=="middle"||n=="center"){let _=(a[1]-p)/2;s&&(_=Math.max(0,_)),b=new d(o[0].$add(0,_),o[1].$subtract(0,_))}else n=="bottom"?b=new d(o[0].$add(0,a[1]-p),o[1]):b=new d(o[0],o[0].$add(a[0],p));let P=M.center(b);for(let _=0,D=f.length;_At,Delaunay:()=>mt,Noise:()=>ct});var At=class{static distributeRandom(r,t,e=2){let i=new d;for(let n=0;n1&&s.push(r.y+L.random()*r.height),e>2&&s.push(r.z+L.random()*r.depth),i.push(new h(s))}return i}static distributeLinear(r,t){let e=m.iterToArray(r),i=E.subpoints(e,t-2);return i.unshift(e[0]),i.push(e[e.length-1]),i}static gridPts(r,t,e,i=[.5,.5]){if(t===0||e===0)throw new Error("grid columns and rows cannot be 0");let n=r.size.$subtract(1).$divide(t,e),s=n.$multiply(i),o=new d;for(let a=0;a0?Math.floor(a/i):a,p=n&&n>0?a%n:a;c.initNoise(t*p,e*f),c.seed(s),o.push(c),a++}return o}static delaunay(r){return mt.from(r)}},ut=[[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]],ht=[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],ct=class extends h{constructor(...t){super(...t);this.perm=[];this._n=new h(.01,.01);this.perm=ht.concat(ht)}initNoise(...t){return this._n=new h(...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 i=e&1?ht[e]^t&255:ht[e]^t>>8&255;this.perm[e]=this.perm[e+256]=i}return this}noise2D(){let t=Math.max(0,Math.floor(this._n[0]))%255,e=Math.max(0,Math.floor(this._n[1]))%255,i=this._n[0]%255-t,n=this._n[1]%255-e,s=k.dot(ut[(t+this.perm[e])%12],[i,n,0]),o=k.dot(ut[(t+this.perm[e+1])%12],[i,n-1,0]),a=k.dot(ut[(t+1+this.perm[e])%12],[i-1,n,0]),u=k.dot(ut[(t+1+this.perm[e+1])%12],[i-1,n-1,0]),c=p=>p*p*p*(p*(p*6-15)+10),f=c(i);return L.lerp(L.lerp(s,a,f),L.lerp(o,u,f),c(n))}},mt=class l extends d{constructor(){super(...arguments);this._mesh=[]}delaunay(t=!0){if(this.length<3)return[];this._mesh=[];let e=this.length,i=[];for(let c=0;cthis[f][0]-this[c][0]);let n=this.slice(),s=this._superTriangle();n=n.concat(s);let o=[this._circum(e,e+1,e+2,s)],a=[],u=[];for(let c=0,f=i.length;c0&&A[0]*A[0]>D*D){a.push(_),u.push(_.triangle),o.splice(P,1);continue}A[0]*A[0]+A[1]*A[1]-D*D>w.epsilon||(b.push(_.i,_.j,_.j,_.k,_.k,_.i),o.splice(P,1))}for(l._dedupe(b),P=b.length;P>1;)o.push(this._circum(b[--P],b[--P],p,!1,n))}for(let c=0,f=o.length;c1;){let i=t[--e],n=t[--e],s=e;for(;s>1;){let o=t[--s],a=t[--s];if(n==a&&i==o||n==o&&i==a){t.splice(e,2),t.splice(s,2);break}}}return t}};var Gt={};T(Gt,{Color:()=>Tt});var g=class g extends h{constructor(...t){super(...t);this._mode="rgb";this._isNorm=!1}static from(...t){let e=[1,1,1,1],i=m.getArgs(t);for(let n=0,s=e.length;nt[s]||"F";t=`${n(0)}${n(0)}${n(1)}${n(1)}${n(2)}${n(2)}`}let e=1;t.length===8&&(e=t.substr(6)&&255/255,t=t.substring(0,6));let i=parseInt(t,16);return new g(i>>16,i>>8&255,i&255,e)}static rgb(...t){return g.from(...t).toMode("rgb")}static hsl(...t){return g.from(...t).toMode("hsl")}static hsb(...t){return g.from(...t).toMode("hsb")}static lab(...t){return g.from(...t).toMode("lab")}static lch(...t){return g.from(...t).toMode("lch")}static luv(...t){return g.from(...t).toMode("luv")}static xyz(...t){return g.from(...t).toMode("xyz")}static maxValues(t){return g.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 g(this);return t.toMode(this._mode),t}toMode(t,e=!1){if(e){let i=this._mode.toUpperCase()+"to"+t.toUpperCase();if(g[i])this.to(g[i](this,this._isNorm,this._isNorm));else throw new Error("Cannot convert color with "+i)}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=g.ranges[this._mode];for(let i=0;i<3;i++)this[i]=t?L.mapToRange(this[i],e[i][0],e[i][1],0,1):L.mapToRange(this[i],0,1,e[i][0],e[i][1]);return this._isNorm=t,this}$normalize(t=!0){return this.clone().normalize(t)}toString(t="mode"){if(t=="hex"){let e=i=>{let n=Math.floor(i).toString(16);return n.length<2?"0"+n:n};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,i=!1){let[n,s,o]=e?t:t.$normalize(),a=Math.max(n,s,o),u=Math.min(n,s,o),c=(a+u)/2,f=c,p=c;if(a==u)c=0,f=0;else{let b=a-u;f=p>.5?b/(2-a-u):b/(a+u),c=0,a===n?c=(s-o)/b+(s(p=p<0?p+1:p>1?p-1:p,p*6<1?u+(a-u)*p*6:p*2<1?a:p*3<2?u+(a-u)*(2/3-p)*6:u),f=i?1:255;return g.rgb(f*c(n+1/3),f*c(n),f*c(n-1/3),t.alpha)}static RGBtoHSB(t,e=!1,i=!1){let[n,s,o]=e?t:t.$normalize(),a=Math.max(n,s,o),u=Math.min(n,s,o),c=a-u,f=0,p=a===0?0:c/a,b=a;return a!=u&&(a===n?f=(s-o)/c+(s.04045?Math.pow((n[o]+.055)/1.055,2.4):n[o]/12.92,i||(n[o]=n[o]*100);let s=g.xyz(n[0]*.4124564+n[1]*.3575761+n[2]*.1804375,n[0]*.2126729+n[1]*.7151522+n[2]*.072175,n[0]*.0193339+n[1]*.119192+n[2]*.9503041,t.alpha);return i?s.normalize():s}static XYZtoRGB(t,e=!1,i=!1){let[n,s,o]=e?t:t.$normalize(),a=[n*3.2406254773200533+s*-1.5372079722103187+o*-.4986285986982479,n*-.9689307147293197+s*1.8757560608852415+o*.041517523842953964,n*.055710120445510616+s*-.2040210505984867+o*1.0569959422543882];for(let c=0;c<3;c++)a[c]=a[c]>.0031308?1.055*Math.pow(a[c],1/2.4)-.055:12.92*a[c],a[c]=Math.max(0,Math.min(1,a[c])),i||(a[c]=Math.round(a[c]*255));let u=g.rgb(a[0],a[1],a[2],t.alpha);return i?u.normalize():u}static XYZtoLAB(t,e=!1,i=!1){let n=e?t.$normalize(!1):t.clone(),s=.00885645167,o=903.296296296;n.divide(g.D65);let a=f=>f>s?Math.pow(f,1/3):(o*f+16)/116,u=a(n[1]),c=g.lab(116*u-16,500*(a(n[0])-u),200*(u-a(n[2])),t.alpha);return i?c.normalize():c}static LABtoXYZ(t,e=!1,i=!1){let n=e?t.$normalize(!1):t,s=(n[0]+16)/116,o=n[1]/500+s,a=s-n[2]/200,u=.00885645167,c=903.296296296,f=g.D65,p=Math.pow(o,3),b=Math.pow(a,3),P=g.xyz(f[0]*(p>u?p:(116*o-16)/c),f[1]*(n[0]>c*u?Math.pow((n[0]+16)/116,3):n[0]/c),f[2]*(b>u?b:(116*a-16)/c),t.alpha);return i?P.normalize():P}static XYZtoLUV(t,e=!1,i=!1){let[n,s,o]=e?t.$normalize(!1):t,a=4*n/(n+15*s+3*o),u=9*s/(n+15*s+3*o);s=s/100,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116;let c=4*g.D65[0]/(g.D65[0]+15*g.D65[1]+3*g.D65[2]),f=9*g.D65[1]/(g.D65[0]+15*g.D65[1]+3*g.D65[2]),p=116*s-16;return g.luv(p,13*p*(a-c),13*p*(u-f),t.alpha)}static LUVtoXYZ(t,e=!1,i=!1){let[n,s,o]=e?t.$normalize(!1):t,a=(n+16)/116,u=a*a*a;a=u>.008856?u:(a-16/116)/7.787;let c=4*g.D65[0]/(g.D65[0]+15*g.D65[1]+3*g.D65[2]),f=9*g.D65[1]/(g.D65[0]+15*g.D65[1]+3*g.D65[2]);s=s/(13*n)+c,o=o/(13*n)+f,a=a*100;let p=-1*(9*a*s)/((s-4)*o-s*o),b=(9*a-15*o*a-o*p)/(3*o);return g.xyz(p,a,b,t.alpha)}static LABtoLCH(t,e=!1,i=!1){let n=e?t.$normalize(!1):t,s=y.toDegree(y.boundRadian(Math.atan2(n[2],n[1])));return g.lch(n[0],Math.sqrt(n[1]*n[1]+n[2]*n[2]),s,t.alpha)}static LCHtoLAB(t,e=!1,i=!1){let n=e?t.$normalize(!1):t,s=y.toRadian(n[2]);return g.lab(n[0],Math.cos(s)*n[1],Math.sin(s)*n[1],t.alpha)}};g.D65=new h(95.047,100,108.883,1),g.ranges={rgb:new d(new h(0,255),new h(0,255),new h(0,255)),hsl:new d(new h(0,360),new h(0,1),new h(0,1)),hsb:new d(new h(0,360),new h(0,1),new h(0,1)),lab:new d(new h(0,100),new h(-128,127),new h(-128,127)),lch:new d(new h(0,100),new h(0,100),new h(0,360)),luv:new d(new h(0,100),new h(-134,220),new h(-140,122)),xyz:new d(new h(0,100),new h(0,100),new h(0,100))};var Tt=g;var Et={};T(Et,{DOMSpace:()=>z,HTMLForm:()=>rt,HTMLSpace:()=>R});var z=class l extends Y{constructor(t,e){super();this.id="domspace";this._autoResize=!0;this._bgcolor="#e1e9f0";this._css={};let i=null,n=!1;this.id="pts",t instanceof Element?(i=t,this.id="pts_existing_space"):(i=document.querySelector(t),n=!0,this.id=t.substr(1)),i?(this._canvas=i,this._container=i.parentElement):(this._container=l.createElement("div","pts_container"),this._canvas=l.createElement("div","pts_element"),this._container.appendChild(this._canvas),document.body.appendChild(this._container),n=!1),setTimeout(this._ready.bind(this,e),50)}static createElement(t="div",e,i){let n=document.createElement(t);return e&&n.setAttribute("id",e),i&&i.appendChild&&i.appendChild(n),n}_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 i in this.players)if(this.players.hasOwnProperty(i)){let n=this.players[i];n.resize&&n.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,i=!1){return this._css[t]=e,i&&(this._canvas.style[t]=e),this}styles(t,e=!1){for(let i in t)t.hasOwnProperty(i)&&this.style(i,t[i],e);return this}static setAttr(t,e){for(let i in e)e.hasOwnProperty(i)&&t.setAttribute(i,e[i]);return t}static getInlineStyles(t){let e="";for(let i in t)t.hasOwnProperty(i)&&t[i]&&(e+=`${i}: ${t[i]}; `);return e}dispose(){return window.removeEventListener("resize",this._resizeHandler.bind(this)),this.stop(),this.removeAll(),this}},R=class extends z{getForm(){return new rt(this)}static htmlElement(r,t,e,i=!0){if(!r||!r.appendChild)throw new Error("parent is not a valid DOM element");let n=document.querySelector(`#${e}`);return n||(n=document.createElement(t),n.setAttribute("id",e),i&&n.setAttribute("class",e.substring(0,e.indexOf("-"))),r.appendChild(n)),n}remove(r){return this._container.querySelectorAll("."+rt.scopeID(r)).forEach(e=>{e.parentNode.removeChild(e)}),super.remove(r)}removeAll(){return this._container.innerHTML="",super.removeAll()}},I=class I extends q{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_"+I.groupID++,this._ctx.style=Object.assign({},this._style),this._ready=!0}})}get space(){return this._space}styleTo(t,e,i=""){if(this._ctx.style[t]===void 0)throw new Error(`${t} style property doesn't exist`);this._ctx.style[t]=`${e}${i}`}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,i,n){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,i,n,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),i&&(this._font.style=i),n&&(this._font.lineHeight=n)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new O(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 i=[];e.filled||i.push("background: none"),e.stroked||i.push("border: none");for(let n in e)if(e.hasOwnProperty(n)&&n!="filled"&&n!="stroked"){let s=e[n];if(s){if(!e.filled&&n.indexOf("background")===0)continue;if(!e.stroked&&n.indexOf("border-width")===0)continue;i.push(`${n}: ${s}`)}}return R.setAttr(t,{style:i.join(";")})}static rectStyle(t,e,i){return t.style.left=e[0]+"px",t.style.top=e[1]+"px",t.style.width=i[0]+"px",t.style.height=i[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,i=5,n="square"){return n==="circle"?I.circle(t,e,i):I.square(t,e,i)}point(t,e=5,i="square"){return this.nextID(),i=="circle"&&this.styleTo("border-radius","100%"),I.point(this._ctx,t,e,i),this}static circle(t,e,i=10){let n=R.htmlElement(t.group,"div",I.getID(t));return R.setAttr(n,{class:`pts-form pts-circle ${t.currentClass}`}),I.rectStyle(t,new h(e).$subtract(i),new h(i*2,i*2)),I.style(n,t.style),n}circle(t){return this.nextID(),this.styleTo("border-radius","100%"),I.circle(this._ctx,t[0],t[1][0]),this}static square(t,e,i){let n=R.htmlElement(t.group,"div",I.getID(t));return R.setAttr(n,{class:`pts-form pts-square ${t.currentClass}`}),I.rectStyle(t,new h(e).$subtract(i),new h(i*2,i*2)),I.style(n,t.style),n}square(t,e){return this.nextID(),I.square(this._ctx,t,e),this}static rect(t,e){let i=m.iterToArray(e);if(!m.arrayCheck(i))return;let n=R.htmlElement(t.group,"div",I.getID(t));return R.setAttr(n,{class:`pts-form pts-rect ${t.currentClass}`}),I.rectStyle(t,i[0],i[1]),I.style(n,t.style),n}rect(t){return this.nextID(),this.styleTo("border-radius","0"),I.rect(this._ctx,t),this}static text(t,e,i){let n=R.htmlElement(t.group,"div",I.getID(t));return R.setAttr(n,{class:`pts-form pts-text ${t.currentClass}`}),n.textContent=i,I.textStyle(t,e),I.style(n,t.style),n}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}arc(t,e,i,n,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}};I.groupID=0,I.domID=0;var rt=I;var St={};T(St,{SVGForm:()=>it,SVGSpace:()=>F});var F=class l extends z{constructor(t,e){super(t,e);this._bgcolor="#999";if(this._canvas.nodeName.toLowerCase()!="svg"){let i=l.svgElement(this._canvas,"svg",`${this.id}_svg`);this._container=this._canvas,this._canvas=i}}getForm(){return new it(this)}get element(){return this._canvas}resize(t,e){return super.resize(t,e),l.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,i){if(!t||!t.appendChild)throw new Error("parent is not a valid DOM element");let n=document.querySelector(`#${i}`);return n||(n=document.createElementNS("http://www.w3.org/2000/svg",e),n.setAttribute("id",i),t.appendChild(n)),n}remove(t){return this._container.querySelectorAll("."+it.scopeID(t)).forEach(i=>{i.parentNode.removeChild(i)}),super.remove(t)}removeAll(){return this._container.innerHTML="",super.removeAll()}},x=class x extends q{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_"+x.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,i,n){return typeof t=="boolean"?this.styleTo("stroked",t):(this.styleTo("stroked",!0),this.styleTo("stroke",t),e&&this.styleTo("stroke-width",e),i&&this.styleTo("stroke-linejoin",i),n&&this.styleTo("stroke-linecap",n)),this}cls(t){return typeof t=="boolean"?this._ctx.currentClass="":this._ctx.currentClass=t,this}font(t,e,i,n,s){return typeof t=="number"?(this._font.size=t,s&&(this._font.face=s),e&&(this._font.weight=e),i&&(this._font.style=i),n&&(this._font.lineHeight=n)):this._font=t,this._ctx.style.font=this._font.value,this}reset(){return this._ctx.style=Object.assign({},this._style),this._font=new O(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(x.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-${x.domID++}`}static scopeID(t){return`item-${t.animateID}`}static style(t,e){let i=[];e.filled||i.push("fill: none"),e.stroked||i.push("stroke: none");for(let n in e)if(e.hasOwnProperty(n)&&n!="filled"&&n!="stroked"){let s=e[n];if(s){if(!e.filled&&n.indexOf("fill")===0)continue;if(!e.stroked&&n.indexOf("stroke")===0)continue;i.push(`${n}: ${s}`)}}return z.setAttr(t,{style:i.join(";")})}static point(t,e,i=5,n="square"){return n==="circle"?x.circle(t,e,i):x.square(t,e,i)}point(t,e=5,i="square"){return this.nextID(),x.point(this._ctx,t,e,i),this}static circle(t,e,i=10){let n=F.svgElement(t.group,"circle",x.getID(t));return z.setAttr(n,{cx:e[0],cy:e[1],r:i,class:`pts-svgform pts-circle ${t.currentClass}`}),x.style(n,t.style),n}circle(t){this.nextID();let e=m.iterToArray(t);return x.circle(this._ctx,e[0],e[1][0]),this}static arc(t,e,i,n,s,o){let a=F.svgElement(t.group,"path",x.getID(t)),u=new h(e).toAngle(n,i,!0),c=new h(e).toAngle(s,i,!0),p=y.boundAngle(s)-y.boundAngle(n)>w.pi;o&&(p=!p);let b=o?"0":"1",P=`M ${u[0]} ${u[1]} A ${i} ${i} 0 ${p?"1":"0"} ${b} ${c[0]} ${c[1]}`;return z.setAttr(a,{d:P,class:`pts-svgform pts-arc ${t.currentClass}`}),x.style(a,t.style),a}arc(t,e,i,n,s){return this.nextID(),x.arc(this._ctx,t,e,i,n,s),this}static square(t,e,i){let n=F.svgElement(t.group,"rect",x.getID(t));return z.setAttr(n,{x:e[0]-i,y:e[1]-i,width:i*2,height:i*2,class:`pts-svgform pts-square ${t.currentClass}`}),x.style(n,t.style),n}square(t,e){return this.nextID(),x.square(this._ctx,t,e),this}static line(t,e){let i=x.pointsString(e);if(i.count<2)return;if(i.count>2)return x._poly(t,i.string,!1);let n=F.svgElement(t.group,"line",x.getID(t)),s=m.iterToArray(e);return z.setAttr(n,{x1:s[0][0],y1:s[0][1],x2:s[1][0],y2:s[1][1],class:`pts-svgform pts-line ${t.currentClass}`}),x.style(n,t.style),n}line(t){return this.nextID(),x.line(this._ctx,t),this}static _poly(t,e,i=!0){let n=F.svgElement(t.group,i?"polygon":"polyline",x.getID(t));return z.setAttr(n,{points:e,class:`pts-svgform pts-polygon ${t.currentClass}`}),x.style(n,t.style),n}static pointsString(t){let e="",i=0;for(let n of t)e+=`${n[0]},${n[1]} `,i++;return{string:e,count:i}}static polygon(t,e){let i=x.pointsString(e);return x._poly(t,i.string,!0)}polygon(t){return this.nextID(),x.polygon(this._ctx,t),this}static rect(t,e){if(!m.arrayCheck(e))return;let i=F.svgElement(t.group,"rect",x.getID(t)),n=d.fromArray(e).boundingBox(),s=M.size(n);return z.setAttr(i,{x:n[0][0],y:n[0][1],width:s[0],height:s[1],class:`pts-svgform pts-rect ${t.currentClass}`}),x.style(i,t.style),i}rect(t){return this.nextID(),x.rect(this._ctx,t),this}static text(t,e,i){let n=F.svgElement(t.group,"text",x.getID(t));return z.setAttr(n,{"pointer-events":"none",x:e[0],y:e[1],dx:0,dy:0,class:`pts-svgform pts-text ${t.currentClass}`}),n.textContent=i,x.style(n,t.style),n}text(t,e){return this.nextID(),x.text(this._ctx,t,e),this}log(t){return this.fill("#000").stroke("#fff",.5).text([10,14],t),this}};x.groupID=0,x.domID=0;var it=x;var zt={};T(zt,{Body:()=>ft,Particle:()=>pt,World:()=>dt});var dt=class l{constructor(r,t=1,e=0){this._lastTime=null;this._gravity=new h;this._friction=1;this._damping=.75;this._iterations=1;this._particles=[];this._bodies=[];this._pnames=[];this._bnames=[];return this._bound=G.fromGroup(r),this._friction=t,this._gravity=typeof e=="number"?new h(0,e):new h(e),this}get bound(){return this._bound}set bound(r){this._bound=r}get gravity(){return this._gravity}set gravity(r){this._gravity=r}get friction(){return this._friction}set friction(r){this._friction=r}get damping(){return this._damping}set damping(r){this._damping=r}get iterations(){return this._iterations}set iterations(r){this._iterations=r}get bodyCount(){return this._bodies.length}get particleCount(){return this._particles.length}body(r){return typeof r=="string"&&r.length>0?this._bodies[this._bnames.indexOf(r)]:typeof r=="number"&&r>=0?this._bodies[r]:void 0}particle(r){return typeof r=="string"&&r.length>0?this._particles[this._pnames.indexOf(r)]:typeof r=="number"&&r>=0?this._particles[r]:void 0}bodyIndex(r){return this._bnames.indexOf(r)}particleIndex(r){return this._pnames.indexOf(r)}update(r){let t=r/1e3;this._updateParticles(t),this._updateBodies(t)}drawParticles(r){this._drawParticles=r}drawBodies(r){this._drawBodies=r}add(r,t=""){return r instanceof ft?(this._bodies.push(r),this._bnames.push(t)):(this._particles.push(r),this._pnames.push(t)),this}_index(r,t){let e=0;if(typeof t=="string"){if(e=r(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(r,t=1){let e=this._index(this.bodyIndex.bind(this),r),i=e<0?[e*-1-1,t]:[e,t];return this._bodies.splice(i[0],i[1]),this._bnames.splice(i[0],i[1]),this}removeParticle(r,t=1){let e=this._index(this.particleIndex.bind(this),r),i=e<0?[e*-1-1,t]:[e,t];return this._particles.splice(i[0],i[1]),this._pnames.splice(i[0],i[1]),this}static edgeConstraint(r,t,e,i=1,n=!1){let s=1/(r.mass||1),o=1/(t.mass||1),a=s+o,u=t.$subtract(r),c=e*e,f=n?e/u.magnitude()-1:c/(u.dot(u)+c)-.5,p=u.$multiply(f*i);return r.subtract(p.$multiply(s/a)),t.add(p.$multiply(o/a)),r}static boundConstraint(r,t,e=.75){let i=y.boundingBox(t),n=r.$min(i[1].subtract(r.radius)).$max(i[0].add(r.radius));if(n[0]===i[0][0]||n[0]===i[1][0]){let s=r.changed.$multiply(e);r.previous=n.$subtract(new h(-s[0],s[1]))}else if(n[1]===i[0][1]||n[1]===i[1][1]){let s=r.changed.$multiply(e);r.previous=n.$subtract(new h(s[0],-s[1]))}r.to(n)}integrate(r,t,e){return r.addForce(this._gravity),r.verlet(t,this._friction,e),r}_updateParticles(r){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 n=this[t].$subtract(this[e]).magnitude();return this._cs.push([t,e,n,i||this._stiff]),this}linkAll(t){let e=this.length/2;for(let i=0,n=this.length;i=n-1?0:i+1;if(this.link(i,s,t),n>4){let o=Math.floor(e/2)+1,a=i>=n-o?i%n:i+o;this.link(i,a,t)}i<=e-1&&this.link(i,Math.min(this.length-1,i+Math.floor(e)))}}linksToLines(){let t=[];for(let e=0,i=this._cs.length;eMath.abs(a[0][1]-a[1][1])?o=(n.vertex[0]-s[0]-a[0][0])/(a[1][0]-a[0][0]):o=(n.vertex[1]-s[1]-a[0][1])/(a[1][1]-a[0][1]);let u=1/(o*o+(1-o)*(1-o)),c=n.vertex.body.mass||1,f=n.edge[0].body.mass||1,p=c/(c+f),b=f/(c+f);a[0].subtract(s.$multiply(p*(1-o)*u/2)),a[1].subtract(s.$multiply(p*o*u/2)),n.vertex.add(s.$multiply(b))}}processParticle(t){let e=this,i=t,n=S.hasIntersectCircle(e,B.fromCenter(t,t.radius));if(n){let s=n.normal.$multiply(n.dist),o,a=n.edge;Math.abs(a[0][0]-a[1][0])>Math.abs(a[0][1]-a[1][1])?o=(n.vertex[0]-s[0]-a[0][0])/(a[1][0]-a[0][0]):o=(n.vertex[1]-s[1]-a[0][1])/(a[1][1]-a[0][1]);let u=1/(o*o+(1-o)*(1-o)),c=n.vertex.mass||i.mass||1,f=n.edge[0].body.mass||1,p=c/(c+f),b=f/(c+f);a[0].subtract(s.$multiply(p*(1-o)*u/2)),a[1].subtract(s.$multiply(p*o*u/2));let P=t.changed.add(s.$multiply(b));t.previous=t.$subtract(P)}}};var Ot={};T(Ot,{Sound:()=>Rt,Tempo:()=>Bt});var Bt=class l{constructor(r){this._listeners={};this._listenerInc=0;this.bpm=r}static fromBeat(r){return new l(6e4/r)}get bpm(){return this._bpm}set bpm(r){this._bpm=r,this._ms=6e4/this._bpm}get ms(){return this._ms}set ms(r){this._bpm=Math.floor(6e4/r),this._ms=6e4/this._bpm}_createID(r){let t="";return typeof r=="function"?t="_b"+this._listenerInc++:t=r.name||"_b"+this._listenerInc++,t}every(r){let t=this,e=Array.isArray(r)?r[0]:r;return{start:function(i,n=0,s){let o=s||t._createID(i);return t._listeners[o]={name:o,beats:r,period:e,index:0,offset:n,duration:-1,continuous:!1,fn:i},this},progress:function(i,n=0,s){let o=s||t._createID(i);return t._listeners[o]={name:o,beats:r,period:e,index:0,offset:n,duration:-1,continuous:!0,fn:i},this}}}track(r){for(let t in this._listeners)if(this._listeners.hasOwnProperty(t)){let e=this._listeners[t],i=e.offset?r+e.offset:r,n=e.period*this._ms,s=!1;i>e.duration+n&&(e.duration=i-i%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)),a=e.continuous?[o,L.clamp((i-e.duration)/n,0,1),i,s]:[o];(e.continuous||s)&&e.fn.apply(e,a)&&delete this._listeners[e.name]}}stop(r){this._listeners[r]&&delete this._listeners[r]}animate(r,t){this.track(r)}resize(r,t){}action(r,t,e,i){}},Rt=class l{constructor(r){this._playing=!1;this._type=r,this._createAudioContext()}_createAudioContext(){let r=window.AudioContext;if(!r)throw new Error("Your browser doesn't support Web Audio. (No AudioContext)");this._ctx=r?new r:void 0}static from(r,t,e="gen",i){let n=new l(e);return n._node=r,n._ctx=t,i&&(n._stream=i),n}static load(r,t="anonymous"){return new Promise((e,i)=>{let n=new l("file");n._source=typeof r=="string"?new Audio(r):r,n._source.autoplay=!1,n._source.crossOrigin=t,n._source.addEventListener("ended",function(){n._playing=!1}),n._source.addEventListener("error",function(){i("Error loading sound")}),n._source.addEventListener("canplaythrough",function(){n._node||(n._node=n._ctx.createMediaElementSource(n._source)),e(n)})})}static loadAsBuffer(r){return new Promise((t,e)=>{let i=new XMLHttpRequest;i.open("GET",r,!0),i.responseType="arraybuffer";let n=new l("file");i.onload=function(){n._ctx.decodeAudioData(i.response,function(s){n.createBuffer(s),t(n)},s=>e("Error decoding audio"))},i.send()})}createBuffer(r){return this._node=this._ctx.createBufferSource(),r!==void 0&&(this._buffer=r),this._node.buffer=this._buffer,this._node.onended=()=>{this._playing=!1},this}static generate(r,t){return new l("gen")._gen(r,t)}_gen(r,t){this._node=this._ctx.createOscillator();let e=this._node;return e.type=r,r==="custom"?e.setPeriodicWave(t):e.frequency.value=t,this}static input(r){return et(this,null,function*(){try{let t=new l("input");if(!t)return;let e=r||{audio:!0,video:!1};return t._stream=yield navigator.mediaDevices.getUserMedia(e),t._node=t._ctx.createMediaStreamSource(t._stream),t}catch(t){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(r){this._buffer=r}get type(){return this._type}get playing(){return this._playing}get progress(){let r=0,t=0;return this._buffer?(r=this._buffer.duration,t=this._timestamp?this._ctx.currentTime-this._timestamp:0):(r=this._source.duration,t=this._source.currentTime),t/r}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(r){this._type==="gen"&&(this._node.frequency.value=r)}connect(r){return this._node.connect(r),this}setOutputNode(r){return this._outputNode=r,this}removeOutputNode(){return this._outputNode=null,this}analyze(r=256,t=-100,e=-30,i=.8){let n=this._ctx.createAnalyser();return n.fftSize=r*2,n.minDecibels=t,n.maxDecibels=e,n.smoothingTimeConstant=i,this.analyzer={node:n,size:n.frequencyBinCount,data:new Uint8Array(n.frequencyBinCount)},this._node.connect(this.analyzer.node),this}_domain(r){return this.analyzer?(r?this.analyzer.node.getByteTimeDomainData(this.analyzer.data):this.analyzer.node.getByteFrequencyData(this.analyzer.data),this.analyzer.data):new Uint8Array(0)}_domainTo(r,t,e=[0,0],i=[0,0]){let n=r?this.timeDomain():this.freqDomain(),s=new d;for(let o=i[0],a=n.length-i[1];o0&&(this._source.currentTime=r)):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(r=>r.stop()),this._playing=!1,this}toggle(){return this._playing?this.stop():this.start(),this}};globalThis.Pts=$($($($($($($($($($($($($($($($($({},Dt),$t),It),gt),Pt),_t),xt),Lt),Gt),wt),Et),St),Ct),zt),vt),Ot),Mt);globalThis.Pts.namespace=l=>{let r=globalThis.Pts;for(let t in r)t!="namespace"&&(l[t]=r[t])};globalThis.Pts.quickStart=(l,r="#9ab")=>{if(!window)return;let t=globalThis;return globalThis.Pts.namespace(t),t.space=new tt(l).setup({bgcolor:r,resize:!0,retina:!0}),t.form=t.space.getForm(),function(e=null,i=null,n=null,s=null){t.space.add({start:i,animate:e,resize:s,action:n}),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 a41d19d1..41433bc0 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 let _selector:Element = null;\r\n let _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 const 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 ( const 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 const r1 = window ? window.devicePixelRatio || 1 : 1;\r\n const 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 ( const k in this.players ) {\r\n if ( this.players.hasOwnProperty( k ) ) {\r\n const 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 const b = ( this._autoResize || this._initialResize ) ? this._container.getBoundingClientRect() : this._canvas.getBoundingClientRect();\r\n\r\n if ( b ) {\r\n const 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 const 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 const 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 const 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 | OffscreenCanvasRenderingContext2D ) {\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 CanvasSpace ) { \r\n this._space = space;\r\n if ( this._space.ready && this._space.ctx ) {\r\n _setup( this._space.ctx );\r\n } else {\r\n this._space.add( { start: () => {\r\n _setup( this._space.ctx );\r\n }} );\r\n }\r\n } else {\r\n _setup( space );\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 * Set current fill style and remove stroke style.\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 fillOnly( c:string | boolean | CanvasGradient | CanvasPattern ):this {\r\n this.stroke( false );\r\n return this.fill( c );\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 * Set stroke style and remove fill style.\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 strokeOnly( c:string | boolean | CanvasGradient | CanvasPattern, width?:number, linejoin?:CanvasLineJoin, linecap?:CanvasLineCap ):this {\r\n this.fill( false );\r\n return this.stroke( c, width, linejoin, linecap );\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 const 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 < len; i++ ) {\r\n const t:number = typeof stops[i] === 'string' ? i * ( 1 / ( stops.length - 1 ) ) : stops[i][0] as number;\r\n const v: string = typeof stops[i] === 'string' ? stops[i] as string : stops[i][1] as string;\r\n vals.push( [t, v] );\r\n }\r\n\r\n return ( area1:GroupLike, area2?:GroupLike ) => {\r\n const grad = area2 \r\n ? 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] ) )\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 < len; i++ ) {\r\n grad.addColorStop( vals[i][0], vals[i][1] );\r\n }\r\n\r\n return grad;\r\n };\r\n }\r\n\r\n\r\n /**\r\n * Set composite operation (also known as blend mode). You can also call this function without parameters to get back to default 'source-over' mode. See [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation) for the full list of operations you can use.\r\n * @param mode a composite operation such as 'lighten', 'multiply', 'overlay', and 'color-burn'.\r\n */\r\n composite( mode:GlobalCompositeOperation = 'source-over' ):this {\r\n this._ctx.globalCompositeOperation = mode;\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * Create a clipping mask from the current path. See [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip) for details.\r\n */\r\n clip():this {\r\n this._ctx.clip();\r\n return this;\r\n }\r\n \r\n \r\n /**\r\n * Activate dashed stroke and set dash style. You can customize the segments and offset.\r\n * @example `form.dash()`, `form.dash([5, 10])`, `form.dash([5, 5], 5)`, `form.dash(false)`\r\n * @param segments Dash segments. Defaults to `true` which corresponds to `[5, 5]`. Pass `false` to deactivate dashes. (See [canvas documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash))\r\n * @param offset Dash offset. Defaults to 0. (See [canvas documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)\r\n */\r\n dash( segments:PtLike | boolean = true, offset:number = 0 ):this {\r\n if ( !segments ) {\r\n // false or [], deactivate dashed strokes\r\n this._ctx.setLineDash( [] );\r\n this._ctx.lineDashOffset = 0;\r\n } else {\r\n if ( segments === true ) {\r\n segments = [5, 5];\r\n }\r\n this._ctx.setLineDash( [segments[0], segments[1]] );\r\n this._ctx.lineDashOffset = offset;\r\n }\r\n return this;\r\n }\r\n \r\n \r\n \r\n /**\r\n * Set the current font.\r\n * @param sizeOrFont either a number to specify font-size, or a `Font` object to specify all font properties\r\n * @param weight Optional font-weight string such as \"bold\"\r\n * @param style Optional font-style string such as \"italic\"\r\n * @param lineHeight Optional line-height number suchas 1.5\r\n * @param family Optional font-family such as \"Helvetica, sans-serif\"\r\n * @example `form.font( myFont )`, `form.font(14, \"bold\")`\r\n */\r\n font( sizeOrFont:number | Font, weight?:string, style?:string, lineHeight?:number, family?:string ):this {\r\n if ( typeof sizeOrFont == \"number\" ) {\r\n \r\n this._font.size = sizeOrFont;\r\n if ( family ) this._font.face = family;\r\n if ( weight ) this._font.weight = weight;\r\n if ( style ) this._font.style = style;\r\n if ( lineHeight ) this._font.lineHeight = lineHeight;\r\n \r\n } else {\r\n this._font = sizeOrFont;\r\n }\r\n\r\n this._ctx.font = this._font.value;\r\n\r\n // If using estimate, reapply it when font changes.\r\n if ( this._estimateTextWidth ) this.fontWidthEstimate( true );\r\n\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * Set whether to use html canvas' [`measureText`](#link) function, or a faster but less accurate heuristic function.\r\n * @param estimate `true` to use heuristic function, or `false` to use ctx.measureText\r\n */\r\n fontWidthEstimate( estimate:boolean = true ):this {\r\n this._estimateTextWidth = ( estimate ) ? Typo.textWidthEstimator( ( ( c:string ) => 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 const _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 let 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 let 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 ( const 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 const 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 const x1 = pt[0] - halfsize;\r\n const y1 = pt[1] - halfsize;\r\n const x2 = pt[0] + halfsize;\r\n const 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 ( const 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 const 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 ``, `