emberwick 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emberwick",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Smooth flowing candlestick charts for the web — canvas-rendered, zero-dependency, pluggable data feeds.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,2 +1,2 @@
1
- (function(w,C){typeof exports=="object"&&typeof module!="undefined"?C(exports):typeof define=="function"&&define.amd?define(["exports"],C):(w=typeof globalThis!="undefined"?globalThis:w||self,C(w.Emberwick={}))})(this,function(w){"use strict";class C{constructor(t,e){this.container=t,this.names=e,this.canvas={},this.ctx={},this.width=0,this.height=0,this.dpr=0,this.onResize=null,getComputedStyle(t).position==="static"&&(t.style.position="relative"),e.forEach((s,n)=>{const o=document.createElement("canvas");Object.assign(o.style,{position:"absolute",left:"0",top:"0",width:"100%",height:"100%",pointerEvents:"none",zIndex:String(n+1)}),t.appendChild(o),this.canvas[s]=o,this.ctx[s]=o.getContext("2d")}),this._ro=new ResizeObserver(()=>this.measure()),this._ro.observe(t),this.measure()}measure(){const t=this.container.getBoundingClientRect(),e=Math.max(1,Math.floor(t.width)),s=Math.max(1,Math.floor(t.height)),n=Math.min(window.devicePixelRatio||1,2);if(!(e===this.width&&s===this.height&&n===this.dpr)){this.width=e,this.height=s,this.dpr=n;for(const o of this.names){const h=this.canvas[o];h.width=Math.floor(e*n),h.height=Math.floor(s*n),this.ctx[o].setTransform(n,0,0,n,0,0)}this.onResize&&this.onResize(e,s)}}composite(){const t=document.createElement("canvas");t.width=Math.floor(this.width*this.dpr),t.height=Math.floor(this.height*this.dpr);const e=t.getContext("2d");for(const s of this.names)e.drawImage(this.canvas[s],0,0);return t}destroy(){this._ro.disconnect();for(const t of this.names)this.canvas[t].remove();this.canvas={},this.ctx={}}}class J{constructor(t){this.onFrame=t,this.fps=0,this._raf=0,this._dirty=new Set,this._last=0,this._running=!1,this._frames=0,this._fpsAt=0,this._tick=this._tick.bind(this)}invalidate(...t){if(!t.length)this._dirty.add("all");else for(const e of t)this._dirty.add(e);this._schedule()}start(){this._running||(this._running=!0,this._last=performance.now(),this._fpsAt=this._last,this.invalidate("all"))}stop(){this._running=!1,this._raf&&cancelAnimationFrame(this._raf),this._raf=0}_schedule(){this._raf||!this._running||(this._raf=requestAnimationFrame(this._tick))}_tick(t){if(this._raf=0,!this._running)return;const e=Math.min(Math.max(t-this._last,1),64);this._last=t,this._frames++,t-this._fpsAt>=500&&(this.fps=Math.round(this._frames*1e3/(t-this._fpsAt)),this._frames=0,this._fpsAt=t);const s=this._dirty;this._dirty=new Set;let n=!1;try{n=this.onFrame(s,e,t)===!0}catch(o){console.error("[Emberwick] frame error",o)}(n||this._dirty.size)&&this._schedule()}}const F=i=>1-Math.pow(1-i,3),Q=i=>i<.5?4*i*i*i:1-Math.pow(-2*i+2,3)/2;class S{constructor(t=0,e=90){this.value=t,this.target=t,this.tau=e}set(t){this.target=t}jump(t){this.value=t,this.target=t}get settled(){const t=1e-9+Math.abs(this.target)*1e-6;return Math.abs(this.target-this.value)<=t}tick(t){return this.settled?(this.value=this.target,!1):(this.value+=(this.target-this.value)*(1-Math.exp(-t/this.tau)),!0)}}class I{constructor(t=200,e=F){this.duration=t,this.ease=e,this.t=t}restart(){this.t=0}get done(){return this.t>=this.duration}get progress(){return this.ease(Math.min(1,this.t/this.duration))}tick(t){return this.done?!1:(this.t+=t,!0)}}const L=(i,t,e)=>i<t?t:i>e?e:i;class H{constructor({spacing:t=9,minSpacing:e=.8,maxSpacing:s=160,rightOffset:n=12}={}){this.minSpacing=e,this.maxSpacing=s,this.rightOffset=n,this.width=0,this.barCount=0,this.follow=!0,this.timeframeMs=6e4,this._spacing=new S(t,65),this._right=new S(n,65),this._initial=t}get spacing(){return this._spacing.value}get right(){return this._right.value}resize(t){this.width=Math.max(1,t)}setBarCount(t){const e=t>this.barCount;if(this.barCount=t,this.follow){const s=t-1+this.rightOffset;e?this._right.set(s):this._right.jump(s)}}x(t){return this.width-(this._right.value-t)*this._spacing.value}index(t){return this._right.value-(this.width-t)/this._spacing.value}barWidth(){const t=this._spacing.value;return Math.max(1,Math.floor(t*.72))}visibleRange(){const t=Math.floor(this.index(0))-1,e=Math.ceil(this.index(this.width))+1;return{from:L(t,0,Math.max(0,this.barCount-1)),to:L(e,0,Math.max(0,this.barCount-1))}}_clampRight(t){const e=this.barCount-1+this.rightOffset+this.width/this._spacing.target,s=Math.min(4,this.barCount-1+this.rightOffset);return L(t,s,e)}panBy(t){if(!t)return!1;const e=this._clampRight(this._right.value-t/this._spacing.value);return this._right.jump(e),this.follow=!1,!0}zoomAt(t,e){const s=this._spacing.target,n=L(s*e,this.minSpacing,this.maxSpacing);if(Math.abs(n-s)<1e-9)return!1;const o=this.follow?this.width:t,a=this._right.target-(this.width-o)/s+(this.width-o)/n;return this._spacing.set(n),this._right.set(this._clampRight(a)),!0}snapToRealtime(){this.follow=!0,this._right.set(this.barCount-1+this.rightOffset)}reset(){this._spacing.set(this._initial),this.snapToRealtime()}tick(t){const e=this._spacing.tick(t),s=this._right.tick(t);return e||s}get settled(){return this._spacing.settled&&this._right.settled}}const x=(i,t,e)=>i<t?t:i>e?e:i;class O{constructor({mode:t="linear",tau:e=120,marginTop:s=.12,marginBottom:n=.12}={}){this.mode=t,this.marginTop=s,this.marginBottom=n,this.auto=!0,this.top=0,this.height=1,this._lo=new S(0,e),this._hi=new S(1,e),this._primed=!1}_fwd(t){return this.mode==="log"?Math.log(Math.max(t,1e-9)):t}_inv(t){return this.mode==="log"?Math.exp(t):t}setMode(t){if(t===this.mode)return;const e=this._inv(this._lo.value),s=this._inv(this._hi.value);this.mode=t,this._lo.jump(this._fwd(e)),this._hi.jump(this._fwd(s))}layout(t,e){this.top=t,this.height=Math.max(1,e)}get lo(){return this._inv(this._lo.value)}get hi(){return this._inv(this._hi.value)}y(t){const e=this._lo.value,s=this._hi.value,n=(this._fwd(t)-e)/(s-e||1);return this.top+this.height*(1-n)}price(t){const e=this._lo.value,s=this._hi.value,n=1-(t-this.top)/this.height;return this._inv(e+n*(s-e))}fit(t,e,s,n){if(!this.auto||!t.length)return;let o=1/0,h=-1/0;for(let m=e;m<=s;m++){const r=t[m];r&&(r.low<o&&(o=r.low),r.high>h&&(h=r.high))}if(n&&(n.low<o&&(o=n.low),n.high>h&&(h=n.high)),!isFinite(o)||!isFinite(h))return;let f=this._fwd(o),a=this._fwd(h),l=(a-f)*this.marginTop;l>0||(l=Math.abs(a)*.01||1),f-=l,a+=(a-f)*0+l,this._lo.set(f),this._hi.set(a),this._primed||(this._lo.jump(f),this._hi.jump(a),this._primed=!0)}scaleBy(t){this.auto=!1;const e=this._lo.target,s=this._hi.target,n=(e+s)/2,o=(s-e)/2*x(t,.2,5);this._lo.set(n-o),this._hi.set(n+o)}resetAuto(){this.auto=!0}tick(t){const e=this._lo.tick(t),s=this._hi.tick(t);return e||s}}const B={background:"#0b0e14",grid:"rgba(255,255,255,0.045)",axisLine:"rgba(255,255,255,0.10)",text:"#8b93a7",textStrong:"#e6e9ef",up:"#26a69a",down:"#ef5350",upFill:"#26a69a",downFill:"#ef5350",wickUp:"#26a69a",wickDown:"#ef5350",volumeUp:"rgba(38,166,154,0.30)",volumeDown:"rgba(239,83,80,0.30)",crosshair:"rgba(255,255,255,0.32)",labelBg:"#2a3040",labelText:"#e6e9ef",tagText:"#06080d",font:'11px ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif',priceAxisWidth:68,timeAxisHeight:26},tt={...B,background:"#ffffff",grid:"rgba(0,0,0,0.06)",axisLine:"rgba(0,0,0,0.14)",text:"#6b7280",textStrong:"#111827",labelBg:"#374151",volumeUp:"rgba(38,166,154,0.25)",volumeDown:"rgba(239,83,80,0.25)",crosshair:"rgba(0,0,0,0.35)",tagText:"#ffffff"};class U{constructor(t=55){this.enabled=!0,this.o=new S(0,t),this.h=new S(0,t),this.l=new S(0,t),this.c=new S(0,t),this.vol=new S(0,t*2),this.spawn=new I(240),this._has=!1,this._time=null}setTarget(t){if(!t){this._has=!1;return}(!this._has||t.time!==this._time)&&(this.o.jump(t.open),this.h.jump(t.open),this.l.jump(t.open),this.c.jump(t.open),this.vol.jump(0),this.spawn.restart(),this._time=t.time,this._has=!0),this.o.set(t.open),this.h.set(t.high),this.l.set(t.low),this.c.set(t.close),this.vol.set(t.volume||0)}reset(){this._has=!1,this._time=null}tick(t){if(!this._has)return!1;let e=!1;return this.o.tick(t)&&(e=!0),this.h.tick(t)&&(e=!0),this.l.tick(t)&&(e=!0),this.c.tick(t)&&(e=!0),this.vol.tick(t)&&(e=!0),this.spawn.tick(t)&&(e=!0),e}read(t){if(!this._has||!this.enabled||t.time!==this._time)return t;const e=this.o.value,s=this.c.value;return{time:t.time,open:e,close:s,high:Math.max(this.h.value,e,s),low:Math.min(this.l.value,e,s),volume:this.vol.value,_spawn:this.spawn.progress}}}class ${constructor({friction:t=.92,min:e=.015}={}){this.friction=t,this.min=e,this.v=0,this.active=!1}sample(t,e){if(e<=0)return;const s=t/e;this.v=this.v*.6+s*.4,this.active=!1}release(){Math.abs(this.v)>this.min&&(this.active=!0)}stop(){this.v=0,this.active=!1}tick(t){if(!this.active)return 0;const e=this.v*t;return this.v*=Math.pow(this.friction,t/16.6667),Math.abs(this.v)<this.min&&this.stop(),e}}function et(i,t){const e=i/Math.max(1,t);if(!(e>0)||!isFinite(e))return 1;const s=Math.pow(10,Math.floor(Math.log10(e))),n=e/s;return(n<1.5?1:n<3?2:n<7?5:10)*s}function R(i,t,e){const s=et(t-i,e),n=[],o=Math.ceil(i/s)*s;for(let h=o;h<=t+s*1e-9;h+=s)n.push(h);return{ticks:n,step:s}}function D(i){return!isFinite(i)||i<=0?2:i>=100?0:i>=1?2:Math.min(8,Math.ceil(-Math.log10(i))+1)}function it(i){const t=[1,2,5,10,15,20,30,60,120,240,480,960,1920,3840,7680];for(const e of t)if(e>=i)return e;return Math.ceil(i/1e3)*1e3}const A=i=>String(i).padStart(2,"0");function st(i,t){const e=new Date(i);return t>=864e5?`${e.getDate()} ${e.toLocaleString("en",{month:"short"})}`:e.getHours()===0&&e.getMinutes()===0?`${e.getDate()} ${e.toLocaleString("en",{month:"short"})}`:`${A(e.getHours())}:${A(e.getMinutes())}`}function nt(i){const t=new Date(i);return`${t.getFullYear()}-${A(t.getMonth()+1)}-${A(t.getDate())} ${A(t.getHours())}:${A(t.getMinutes())}`}function ot(i,t){const{theme:e,ts:s,ps:n,plot:o,bars:h,width:f,height:a}=t;i.clearRect(0,0,f,a),i.fillStyle=e.background,i.fillRect(0,0,f,a),i.font=e.font,i.textBaseline="middle";const l=Math.max(2,Math.floor(o.h/58)),{ticks:m,step:r}=R(n.lo,n.hi,l),c=D(r);i.strokeStyle=e.grid,i.lineWidth=1,i.beginPath();for(const p of m){const u=Math.round(n.y(p))+.5;u<o.y||u>o.y+o.h||(i.moveTo(0,u),i.lineTo(o.w,u))}i.stroke(),i.fillStyle=e.text,i.textAlign="left";for(const p of m){const u=Math.round(n.y(p));u<o.y+6||u>o.y+o.h-6||i.fillText(p.toFixed(c),o.w+8,u)}if(h.length){const p=Math.ceil(74/Math.max(1e-4,s.spacing)),u=it(p),{from:v,to:b}=s.visibleRange(),M=Math.ceil(v/u)*u;i.strokeStyle=e.grid,i.beginPath();for(let g=M;g<=b;g+=u){const d=Math.round(s.x(g))+.5;d<0||d>o.w||(i.moveTo(d,0),i.lineTo(d,o.h))}i.stroke(),i.fillStyle=e.text,i.textAlign="center";const y=o.h+e.timeAxisHeight/2;for(let g=M;g<=b;g+=u){const d=h[g];if(!d)continue;const _=Math.round(s.x(g));_<28||_>o.w-28||i.fillText(st(d.time,s.timeframeMs),_,y)}}i.strokeStyle=e.axisLine,i.beginPath(),i.moveTo(o.w+.5,0),i.lineTo(o.w+.5,o.h),i.moveTo(0,o.h+.5),i.lineTo(f,o.h+.5),i.stroke()}function ht(i,t){const{theme:e,ts:s,ps:n,plot:o,bars:h,width:f,height:a,live:l,volumeRatio:m}=t;if(i.clearRect(0,0,f,a),!h.length)return;const{from:r,to:c}=s.visibleRange(),p=s.barWidth(),u=p/2,v=p<=2,b=o.h*m,M=o.y+o.h-b;let y=0;for(let d=r;d<=c;d++){const _=h[d];_&&_.volume>y&&(y=_.volume)}if(y>0)for(let d=r;d<=c;d++){let _=h[d];if(!_)continue;l&&d===h.length-1&&(_=l);const k=s.x(d);if(k<-p||k>o.w+p)continue;const T=_.volume/y*b*.9;i.fillStyle=_.close>=_.open?e.volumeUp:e.volumeDown,i.fillRect(Math.round(k-u),M+(b-T),Math.max(1,p),T)}for(let d=r;d<=c;d++){let _=h[d];if(!_)continue;const k=d===h.length-1;l&&k&&(_=l);const T=s.x(d);if(T<-p||T>o.w+p)continue;const P=_.close>=_.open,Tt=P?e.up:e.down,Y=n.y(_.open),N=n.y(_.close),St=n.y(_.high),At=n.y(_.low);let V=1;l&&k&&typeof _._spawn=="number"&&(V=.35+.65*_._spawn);const Z=Math.round(T)+(p%2?.5:0);if(i.strokeStyle=P?e.wickUp:e.wickDown,i.lineWidth=Math.max(1,Math.min(2,p*.16)),i.beginPath(),i.moveTo(Z,St),i.lineTo(Z,At),i.stroke(),v)continue;const Ct=Math.min(Y,N),Lt=Math.max(1,Math.abs(N-Y)),G=Math.max(1,p*V);i.fillStyle=Tt,i.fillRect(Math.round(T-G/2),Math.round(Ct),Math.round(G),Math.round(Lt))}const g=l||h[h.length-1];if(g){const d=Math.round(n.y(g.close))+.5;if(d>o.y&&d<o.y+o.h){const _=g.close>=g.open;i.save(),i.setLineDash([3,3]),i.strokeStyle=_?e.up:e.down,i.lineWidth=1,i.globalAlpha=.7,i.beginPath(),i.moveTo(0,d),i.lineTo(o.w,d),i.stroke(),i.restore();const{step:k}=R(n.lo,n.hi,Math.max(2,Math.floor(o.h/58))),T=g.close.toFixed(D(k));i.font=e.font,i.textBaseline="middle",i.textAlign="left";const P=i.measureText(T).width;i.fillStyle=_?e.up:e.down,i.fillRect(o.w+1,d-9,P+14,18),i.fillStyle=e.tagText,i.fillText(T,o.w+8,d)}}}function at(i,t){const{theme:e,ts:s,ps:n,plot:o,bars:h,width:f,height:a,cursor:l,magnet:m}=t;if(i.clearRect(0,0,f,a),!l||!h.length||l.x<0||l.x>o.w||l.y<0||l.y>o.h)return;const r=Math.round(s.index(l.x)),c=h[r];let p=l.x,u=l.y;if(c&&(p=s.x(r),m)){const y=[c.open,c.high,c.low,c.close];let g=null,d=1/0;for(const _ of y){const k=n.y(_),T=Math.abs(k-l.y);T<d&&(d=T,g=k)}d<22&&(u=g)}i.save(),i.setLineDash([4,4]),i.strokeStyle=e.crosshair,i.lineWidth=1,i.beginPath(),i.moveTo(Math.round(p)+.5,0),i.lineTo(Math.round(p)+.5,o.h),i.moveTo(0,Math.round(u)+.5),i.lineTo(o.w,Math.round(u)+.5),i.stroke(),i.restore(),i.font=e.font,i.textBaseline="middle";const{step:v}=R(n.lo,n.hi,Math.max(2,Math.floor(o.h/58))),b=n.price(u).toFixed(D(v));i.textAlign="left";const M=i.measureText(b).width;if(i.fillStyle=e.labelBg,i.fillRect(o.w+1,u-9,M+14,18),i.fillStyle=e.labelText,i.fillText(b,o.w+8,u),c){const y=nt(c.time);i.textAlign="center";const g=i.measureText(y).width,d=Math.min(Math.max(p,g/2+6),o.w-g/2-6);i.fillStyle=e.labelBg,i.fillRect(d-g/2-7,o.h+3,g+14,18),i.fillStyle=e.labelText,i.fillText(y,d,o.h+12)}}const rt=["arrowUp","arrowDown","triangleUp","triangleDown","circle","square","diamond","flag","label"],lt=new Set(rt),ft={arrowUp:"belowBar",triangleUp:"belowBar",arrowDown:"aboveBar",triangleDown:"aboveBar"},ct=new Set(["aboveBar","belowBar","inBar","atPrice"]);function ut(i,t){if(!i||!isFinite(i.time))return null;const e=lt.has(i.shape)?i.shape:"circle",s=ct.has(i.position)?i.position:ft[e]||"aboveBar";return{id:i.id!=null?String(i.id):`mk${t}`,time:+i.time,price:isFinite(i.price)?+i.price:null,shape:e,position:s,color:i.color||null,textColor:i.textColor||null,text:i.text!=null?String(i.text):"",size:isFinite(i.size)&&i.size>0?+i.size:1,data:i.data,index:-1}}function j(i){if(!Array.isArray(i))return[];const t=[];for(let e=0;e<i.length;e++){const s=ut(i[e],e);s&&t.push(s)}return t.sort((e,s)=>e.time-s.time),t}function z(i,t){const e=i.length;if(!e)return-1;if(t<=i[0].time)return 0;if(t>=i[e-1].time)return e-1;let s=0,n=e-1;for(;s<=n;){const f=s+n>>1,a=i[f].time;if(a===t)return f;a<t?s=f+1:n=f-1}const o=Math.max(0,n),h=Math.min(e-1,s);return Math.abs(i[o].time-t)<=Math.abs(i[h].time-t)?o:h}function dt(i,t){for(let e=0;e<i.length;e++)i[e].index=z(t,i[e].time);return i}function mt(i,t){const{ts:e,ps:s,plot:n,bars:o,live:h}=t;if(!i.length||!o.length)return[];const{from:f,to:a}=e.visibleRange(),l=o.length-1,m=e.barWidth()<=3,r=new Map,c=[];let p=-1/0;for(const u of i){const v=u.index;if(v<0||v<f-2||v>a+2)continue;const b=h&&v===l?h:o[v];if(!b)continue;const M=e.x(v);if(M<-48||M>n.w+48)continue;if(m){if(M-p<4)continue;p=M}const y=5*u.size;let g,d=0;if(u.position==="atPrice"&&u.price!=null?g=s.y(u.price):u.position==="inBar"?g=s.y((b.high+b.low)/2):u.position==="belowBar"?(g=s.y(b.low)+y+7,d=1):(g=s.y(b.high)-y-7,d=-1),d!==0){const _=v+u.position,k=r.get(_)||0;r.set(_,k+1),g+=d*k*(y*2+5)}c.push({m:u,x:M,y:g,r:y,dir:d})}return c}const W={solid:[],dashed:[6,4],dotted:[1,3]},pt=new Set(["arrowDown","triangleDown"]);function K(i,t,e,s,n,o){const h=Math.max(0,Math.min(o,n/2,s/2));i.beginPath(),i.moveTo(t+h,e),i.lineTo(t+s-h,e),i.quadraticCurveTo(t+s,e,t+s,e+h),i.lineTo(t+s,e+n-h),i.quadraticCurveTo(t+s,e+n,t+s-h,e+n),i.lineTo(t+h,e+n),i.quadraticCurveTo(t,e+n,t,e+n-h),i.lineTo(t,e+h),i.quadraticCurveTo(t,e,t+h,e),i.closePath()}function gt(i,t){const{zones:e,theme:s,ts:n,ps:o,plot:h,bars:f}=t;if(!(!e||!e.length)){i.save(),i.font=s.font,i.textBaseline="top",i.textAlign="left";for(const a of e){let l,m,r,c;if(isFinite(a.from)&&isFinite(a.to))m=o.y(Math.max(a.from,a.to)),c=Math.max(1,o.y(Math.min(a.from,a.to))-m),l=0,r=h.w;else if(isFinite(a.fromTime)&&isFinite(a.toTime)&&f.length){const p=n.x(z(f,Math.min(a.fromTime,a.toTime))),u=n.x(z(f,Math.max(a.fromTime,a.toTime)));l=p,r=Math.max(1,u-p),m=0,c=h.h}else continue;l>h.w||l+r<0||m>h.h||m+c<0||(i.fillStyle=a.color||"rgba(38,166,154,0.10)",i.fillRect(l,m,r,c),a.border&&(i.strokeStyle=a.border,i.lineWidth=1,i.strokeRect(Math.round(l)+.5,Math.round(m)+.5,Math.round(r),Math.round(c))),a.label&&(i.fillStyle=a.labelColor||s.text,i.fillText(a.label,Math.max(6,l+6),Math.max(4,m+4))))}i.restore()}}function _t(i,t){const{priceLines:e,theme:s,ps:n,plot:o}=t;if(!e||!e.length)return;const{step:h}=R(n.lo,n.hi,Math.max(2,Math.floor(o.h/58))),f=D(h);i.save(),i.font=s.font,i.textBaseline="middle";for(const a of e){if(!a||!isFinite(a.price))continue;const l=Math.round(n.y(a.price))+.5;if(l<0||l>o.h)continue;const m=a.color||s.textStrong;if(i.setLineDash(W[a.lineStyle]||W.dashed),i.strokeStyle=m,i.lineWidth=a.lineWidth||1,i.beginPath(),i.moveTo(0,l),i.lineTo(o.w,l),i.stroke(),i.setLineDash([]),a.title){i.textAlign="left";const r=i.measureText(a.title).width;i.fillStyle=m,K(i,6,l-9,r+12,18,4),i.fill(),i.fillStyle=a.titleColor||s.tagText,i.fillText(a.title,12,l)}if(a.axisLabel!==!1){const r=a.price.toFixed(f);i.textAlign="left";const c=i.measureText(r).width;i.fillStyle=m,i.fillRect(o.w+1,l-9,c+14,18),i.fillStyle=a.tagTextColor||s.tagText,i.fillText(r,o.w+8,l)}}i.restore()}function vt(i,t,e,s,n){switch(i.beginPath(),t){case"arrowUp":i.moveTo(e,s-n),i.lineTo(e+n,s),i.lineTo(e+n*.45,s),i.lineTo(e+n*.45,s+n),i.lineTo(e-n*.45,s+n),i.lineTo(e-n*.45,s),i.lineTo(e-n,s),i.closePath();break;case"arrowDown":i.moveTo(e,s+n),i.lineTo(e+n,s),i.lineTo(e+n*.45,s),i.lineTo(e+n*.45,s-n),i.lineTo(e-n*.45,s-n),i.lineTo(e-n*.45,s),i.lineTo(e-n,s),i.closePath();break;case"triangleUp":i.moveTo(e,s-n),i.lineTo(e+n,s+n),i.lineTo(e-n,s+n),i.closePath();break;case"triangleDown":i.moveTo(e,s+n),i.lineTo(e+n,s-n),i.lineTo(e-n,s-n),i.closePath();break;case"square":i.rect(e-n,s-n,n*2,n*2);break;case"diamond":i.moveTo(e,s-n),i.lineTo(e+n,s),i.lineTo(e,s+n),i.lineTo(e-n,s),i.closePath();break;default:i.arc(e,s,n,0,Math.PI*2)}}function bt(i,t,e,s,n){i.fillStyle=n,i.fillRect(t-s*.8,e-s,Math.max(1,s*.3),s*2),i.beginPath(),i.moveTo(t-s*.5,e-s),i.lineTo(t+s,e-s*.55),i.lineTo(t-s*.5,e-s*.1),i.closePath(),i.fill()}function wt(i,t,e,s){const n=[];if(!e||!e.length)return n;const{theme:o}=t;i.save(),i.font=o.font,i.textAlign="center",i.textBaseline="middle";for(const h of e){const{m:f,x:a,y:l,r:m,dir:r}=h,c=f.color||(pt.has(f.shape)?o.down:o.up),p=s!=null&&f.id===s;if(f.shape==="label"){const u=f.text||"•",v=i.measureText(u).width+14,b=18*f.size;K(i,a-v/2,l-b/2,v,b,4),i.fillStyle=c,i.fill(),p&&(i.strokeStyle=o.textStrong,i.lineWidth=1.5,i.stroke()),i.fillStyle=f.textColor||o.tagText,i.fillText(u,a,l+.5),n.push({id:f.id,marker:f,x:a,y:l,r:Math.max(v,b)/2});continue}p&&(i.beginPath(),i.arc(a,l,m+4,0,Math.PI*2),i.fillStyle="rgba(255,255,255,0.14)",i.fill()),f.shape==="flag"?bt(i,a,l,m,c):(vt(i,f.shape,a,l,m),i.fillStyle=c,i.fill()),f.text&&(i.fillStyle=f.textColor||o.text,i.fillText(f.text,a,r>=0?l+m+9:l-m-9)),n.push({id:f.id,marker:f,x:a,y:l,r:m+3})}return i.restore(),n}class q{constructor(t,e={}){if(!t)throw new Error("Chart: container element is required");this.container=t,this.theme={...B,...e.theme||{}},this.options={volumeRatio:.18,magnet:!0,animate:!0,...e},this.bars=[],this.feed=null,this._unsub=null,this._loadingHistory=!1,this._exhausted=!1,this._listeners={crosshair:new Set,visibleRange:new Set,markerClick:new Set,markerHover:new Set},this._markers=j(e.markers),this.priceLines=Array.isArray(e.priceLines)?e.priceLines.slice():[],this.zones=Array.isArray(e.zones)?e.zones.slice():[],this._markerHits=[],this._hoverMarkerId=null,this._resolveKey="",this.layers=new C(t,["base","main","overlay"]),this.ts=new H(e.timeScale),this.ps=new O(e.priceScale),this.live=new U,this.live.enabled=this.options.animate!==!1,this.inertia=new $,this.cursor=null,this.plot={x:0,y:0,w:1,h:1},this.loop=new J((s,n)=>this._frame(s,n)),this.layers.onResize=()=>{this._layout(),this.loop.invalidate("all")},this._layout(),this._bindEvents(),this.loop.start()}_layout(){const{width:t,height:e}=this.layers,s=Math.max(1,t-this.theme.priceAxisWidth),n=Math.max(1,e-this.theme.timeAxisHeight);this.plot={x:0,y:0,w:s,h:n},this.ts.resize(s),this.ps.layout(0,n)}setData(t){this.bars=Array.isArray(t)?t.slice():[],this._exhausted=!1,this.bars.length>1&&(this.ts.timeframeMs=this.bars[1].time-this.bars[0].time),this.ts.setBarCount(this.bars.length),this.ts.snapToRealtime(),this.live.reset(),this.ps._primed=!1,this.loop.invalidate("all")}update(t){if(!t)return;const e=this.bars.length;if(e&&this.bars[e-1].time===t.time)this.bars[e-1]=t;else{this.append(t);return}this.live.setTarget(t),this.loop.invalidate("main")}append(t){if(!t)return;const e=this.bars.length;e&&t.time<=this.bars[e-1].time?this.bars[e-1]=t:(this.bars.push(t),this.ts.setBarCount(this.bars.length)),this.live.setTarget(t),this.loop.invalidate("main")}async setFeed(t){if(this.detachFeed(),this.feed=t,!t)return;this.ts.timeframeMs=t.timeframe||this.ts.timeframeMs;const e=await t.getBars({symbol:t.symbol,timeframe:t.timeframe,to:null,limit:this.options.initialBars||1500});this.setData(e),typeof t.prime=="function"&&t.prime(e[e.length-1]),this._unsub=t.subscribe(s=>{!s||!s.bar||(s.type==="append"?this.append(s.bar):this.update(s.bar))})}detachFeed(){this._unsub&&this._unsub(),this._unsub=null,this.feed=null}async _maybeLoadHistory(){if(this._loadingHistory||this._exhausted||!this.feed)return;const{from:t}=this.ts.visibleRange();if(!(t>80||!this.bars.length)){this._loadingHistory=!0;try{const e=this.bars[0].time,s=await this.feed.getBars({symbol:this.feed.symbol,timeframe:this.feed.timeframe,to:e,limit:1e3});if(!s||!s.length)this._exhausted=!0;else{const n=s.filter(o=>o.time<e);if(!n.length)this._exhausted=!0;else{this.bars=n.concat(this.bars);const o=this.ts.follow;this.ts.barCount=this.bars.length,this.ts._right.jump(this.ts._right.value+n.length),this.ts._right.set(this.ts._right.target+n.length),this.ts.follow=o,this.loop.invalidate("all")}}}catch(e){console.error("[Emberwick] history load failed",e),this._exhausted=!0}finally{this._loadingHistory=!1}}}_bindEvents(){const t=this.container;t.style.touchAction="none",t.style.cursor="crosshair";let e=!1,s=null,n=0,o=0,h=0,f=!1;const a=new Map;let l=0;const m=r=>{const c=t.getBoundingClientRect();return{x:r.clientX-c.left,y:r.clientY-c.top}};this._onDown=r=>{if(a.set(r.pointerId,m(r)),a.size===2){const[p,u]=[...a.values()];l=Math.hypot(p.x-u.x,p.y-u.y),e=!1;return}const c=m(r);e=!0,f=!1,s=c.x>this.plot.w?"price":c.y>this.plot.h?"time":"pan",n=c.x,o=c.y,h=performance.now(),this.inertia.stop(),t.setPointerCapture(r.pointerId)},this._onMove=r=>{const c=m(r);if(a.has(r.pointerId)&&a.set(r.pointerId,c),a.size===2){const[M,y]=[...a.values()],g=Math.hypot(M.x-y.x,M.y-y.y);if(l>0&&g>0){const d=(M.x+y.x)/2;this.ts.zoomAt(d,g/l),this.loop.invalidate("all")}l=g;return}if(this.cursor=c,this._emitCrosshair(c),this.loop.invalidate("overlay"),!e)return;const p=performance.now(),u=p-h,v=c.x-n,b=c.y-o;(Math.abs(v)>1||Math.abs(b)>1)&&(f=!0),s==="pan"?(this.ts.panBy(v),this.inertia.sample(v,u),this.loop.invalidate("all"),this._maybeLoadHistory()):s==="price"?(this.ps.scaleBy(1+b/220),this.loop.invalidate("all")):s==="time"&&(this.ts.zoomAt(this.plot.w,1-v/260),this.loop.invalidate("all")),n=c.x,o=c.y,h=p},this._onUp=r=>{a.delete(r.pointerId),a.size<2&&(l=0),e&&s==="pan"&&f&&(this.inertia.release(),this.loop.invalidate("all")),e=!1,s=null;try{t.releasePointerCapture(r.pointerId)}catch{}},this._onLeave=()=>{this.cursor=null,this._emitCrosshair(null),this.loop.invalidate("overlay")},this._onWheel=r=>{r.preventDefault();const c=t.getBoundingClientRect(),p=r.clientX-c.left,u=Math.pow(.999,r.deltaY);this.ts.zoomAt(p,u),this.loop.invalidate("all"),this._maybeLoadHistory()},this._onDbl=()=>{this.ts.reset(),this.ps.resetAuto(),this.loop.invalidate("all")},this._onKey=r=>{const c=r.shiftKey?120:40;if(r.key==="ArrowLeft")this.ts.panBy(c),this.loop.invalidate("all"),this._maybeLoadHistory();else if(r.key==="ArrowRight")this.ts.panBy(-c),this.loop.invalidate("all");else if(r.key==="+"||r.key==="=")this.ts.zoomAt(this.plot.w/2,1.2),this.loop.invalidate("all");else if(r.key==="-"||r.key==="_")this.ts.zoomAt(this.plot.w/2,.8),this.loop.invalidate("all");else return;r.preventDefault()},this._onClick=r=>{if(f||!this._listeners.markerClick.size)return;const c=m(r),p=this.markerAt(c.x,c.y);if(p)for(const u of this._listeners.markerClick)u(p)},t.addEventListener("click",this._onClick),t.addEventListener("pointerdown",this._onDown),t.addEventListener("pointermove",this._onMove),t.addEventListener("pointerup",this._onUp),t.addEventListener("pointercancel",this._onUp),t.addEventListener("pointerleave",this._onLeave),t.addEventListener("wheel",this._onWheel,{passive:!1}),t.addEventListener("dblclick",this._onDbl),t.addEventListener("keydown",this._onKey),t.hasAttribute("tabindex")||t.setAttribute("tabindex","0")}_emitCrosshair(t){if(this._listeners.crosshair.size){let e=null;if(t&&this.bars.length&&t.x<=this.plot.w&&t.y<=this.plot.h){const s=Math.round(this.ts.index(t.x)),n=this.bars[s];n&&(e={index:s,bar:n,price:this.ps.price(t.y)})}for(const s of this._listeners.crosshair)s(e)}this._updateHover(t)}markerAt(t,e){const s=this._markerHits;for(let n=s.length-1;n>=0;n--){const o=s[n],h=t-o.x,f=e-o.y;if(h*h+f*f<=o.r*o.r)return o.marker}return null}_updateHover(t){const e=t?this.markerAt(t.x,t.y):null,s=e?e.id:null;if(s!==this._hoverMarkerId){this._hoverMarkerId=s,this.container.style.cursor=e?"pointer":"crosshair",this.loop.invalidate("main");for(const n of this._listeners.markerHover)n(e)}}subscribe(t,e){const s=this._listeners[t];if(!s)throw new Error(`Chart: unknown event "${t}"`);if(s.add(e),t==="visibleRange"){const n=this.visibleRange();this._rangeKey=this._rangeIdentity(n),e(n)}return()=>s.delete(e)}visibleRange(){const{from:t,to:e}=this.ts.visibleRange();return this._rangePayload(t,e)}_rangePayload(t,e){const s=this.bars.length;return{from:t,to:e,fromTime:s?this.bars[t].time:null,toTime:s?this.bars[e].time:null,barCount:s,spacing:this.ts.spacing,settled:this.ts.settled}}_rangeIdentity(t){return`${t.from}:${t.to}:${t.fromTime}:${t.toTime}:${t.settled?1:0}`}_emitVisibleRange(t,e){const s=this._listeners.visibleRange;if(!s.size)return;const n=this._rangePayload(t,e),o=this._rangeIdentity(n);if(o!==this._rangeKey){this._rangeKey=o;for(const h of s)h(n)}}setMarkers(t){this._markers=j(t),this._resolveKey="",this.loop.invalidate("main")}getMarkers(){return this._markers.slice()}addMarker(t){this.setMarkers(this._markers.concat([t]))}removeMarker(t){const e=String(t);this.setMarkers(this._markers.filter(s=>s.id!==e))}clearMarkers(){this.setMarkers([])}setPriceLines(t){this.priceLines=Array.isArray(t)?t.slice():[],this.loop.invalidate("main")}setZones(t){this.zones=Array.isArray(t)?t.slice():[],this.loop.invalidate("all")}_frame(t,e){let s=!1;this.ts.tick(e)&&(s=!0);const n=this.inertia.tick(e);n&&(this.ts.panBy(n),s=!0,this._maybeLoadHistory()),this.live.tick(e)&&(s=!0);const{from:o,to:h}=this.ts.visibleRange(),f=this.bars.length-1,a=this.bars.length?this.live.read(this.bars[f]):null,l=a&&h>=f?a:null;this.ps.fit(this.bars,o,h,l),this.ps.tick(e)&&(s=!0);const m=s||t.has("all")||t.has("base")||t.has("main"),r={theme:this.theme,ts:this.ts,ps:this.ps,plot:this.plot,bars:this.bars,width:this.layers.width,height:this.layers.height,live:l,volumeRatio:this.options.volumeRatio,cursor:this.cursor,magnet:this.options.magnet,priceLines:this.priceLines,zones:this.zones};if(this._markers.length){const c=this.bars.length+":"+(this.bars.length?this.bars[0].time:0);c!==this._resolveKey&&(dt(this._markers,this.bars),this._resolveKey=c)}return m&&(ot(this.layers.ctx.base,r),gt(this.layers.ctx.base,r),ht(this.layers.ctx.main,r),_t(this.layers.ctx.main,r),this._markerHits=wt(this.layers.ctx.main,r,mt(this._markers,r),this._hoverMarkerId)),(m||t.has("overlay"))&&at(this.layers.ctx.overlay,r),this._emitVisibleRange(o,h),s}get fps(){return this.loop.fps}setTheme(t){this.theme={...this.theme,...t},this._layout(),this.loop.invalidate("all")}setPriceMode(t){this.ps.setMode(t),this.loop.invalidate("all")}setAnimate(t){this.live.enabled=!!t,this.loop.invalidate("all")}setMagnet(t){this.options.magnet=!!t,this.loop.invalidate("overlay")}snapToRealtime(){this.ts.snapToRealtime(),this.ps.resetAuto(),this.loop.invalidate("all")}toImage(){return this.layers.composite().toDataURL("image/png")}destroy(){const t=this.container;t.removeEventListener("pointerdown",this._onDown),t.removeEventListener("pointermove",this._onMove),t.removeEventListener("pointerup",this._onUp),t.removeEventListener("pointercancel",this._onUp),t.removeEventListener("pointerleave",this._onLeave),t.removeEventListener("wheel",this._onWheel),t.removeEventListener("dblclick",this._onDbl),t.removeEventListener("keydown",this._onKey),t.removeEventListener("click",this._onClick),this.detachFeed(),this.loop.stop(),this.layers.destroy();for(const e of Object.values(this._listeners))e.clear();this._markers=[],this._markerHits=[],this.priceLines=[],this.zones=[],this.bars=[]}}class X{constructor({symbol:t="DEMO",timeframe:e=6e4}={}){this.symbol=t,this.timeframe=e}async getBars({symbol:t,timeframe:e,to:s,limit:n}){throw new Error("DataFeed.getBars() not implemented")}subscribe(t){return()=>{}}destroy(){}}function E(i){let t=i>>>0;return function(){t=t+1831565813|0;let e=Math.imul(t^t>>>15,1|t);return e=e+Math.imul(e^e>>>7,61|e)^e,((e^e>>>14)>>>0)/4294967296}}class yt extends X{constructor({symbol:t="EMBR",timeframe:e=6e4,seed:s=7,start:n=100,volatility:o=.0022,drift:h=2e-5,ticksPerSecond:f=8,speed:a=1}={}){super({symbol:t,timeframe:e}),this.seed=s,this.start=n,this.volatility=o,this.drift=h,this.ticksPerSecond=f,this.speed=a,this._rnd=E(s),this._handlers=new Set,this._timer=null,this._forming=null,this._last=n,this._vol=o,this._anchorTime=Math.floor(Date.now()/e)*e}_gauss(){let t=0,e=0;for(;t===0;)t=this._rnd();for(;e===0;)e=this._rnd();return Math.sqrt(-2*Math.log(t))*Math.cos(2*Math.PI*e)}_step(t){const e=this._gauss();return this._vol+=(this.volatility-this._vol)*.02+Math.abs(e)*this.volatility*.015,this._vol=Math.min(this._vol,this.volatility*6),Math.max(.01,t*(1+this.drift+e*this._vol))}_makeBar(t,e){let s=e;const n=14;let o=e,h=e;for(let l=0;l<n;l++)s=this._step(s),s>o&&(o=s),s<h&&(h=s);const f=Math.max(1e-9,o-h),a=Math.round((300+this._rnd()*900)*(1+f/e*260));return{time:t,open:e,high:o,low:h,close:s,volume:a}}async getBars({to:t,limit:e=1500,timeframe:s=this.timeframe}={}){const n=t==null?this._anchorTime:t,o=[],h=n-e*s,f=E(this.seed^Math.floor(h/s)),a=this._rnd;this._rnd=f;let l=this.start*(1+(f()-.5)*.04);for(let m=0;m<e;m++){const r=h+m*s,c=this._makeBar(r,l);l=c.close,o.push(c)}return this._rnd=a,t==null&&(this._last=o.length?o[o.length-1].close:this.start),o}subscribe(t){return this._handlers.add(t),this._timer||this._start(),()=>{this._handlers.delete(t),this._handlers.size||this.stop()}}_emit(t){for(const e of this._handlers)e(t)}_start(){const t=Math.max(16,1e3/this.ticksPerSecond);this._timer=setInterval(()=>this._tick(),t)}prime(t){t&&(this._last=t.close,this._forming={...t})}_tick(){const t=this.timeframe/this.speed,e=Date.now(),s=Math.floor(e/t)*t;if(!this._forming||this._forming.time!==s){const h=this._last;this._forming={time:s,open:h,high:h,low:h,close:h,volume:0},this._emit({type:"append",bar:{...this._forming}});return}const n=this._step(this._last);this._last=n;const o=this._forming;o.close=n,n>o.high&&(o.high=n),n<o.low&&(o.low=n),o.volume+=Math.round(20+this._rnd()*120),this._emit({type:"update",bar:{...o}})}setSpeed(t){this.speed=t}setTicksPerSecond(t){this.ticksPerSecond=t,this._timer&&(this.stop(),this._start())}setPaused(t){t?this.stop():!this._timer&&this._handlers.size&&this._start()}get paused(){return!this._timer}stop(){this._timer&&clearInterval(this._timer),this._timer=null}destroy(){this.stop(),this._handlers.clear()}}function Mt(i,t){return new q(i,t)}const kt="0.2.0";w.Chart=q,w.DataFeed=X,w.Inertia=$,w.LiveCandle=U,w.PriceScale=O,w.RandomFeed=yt,w.Smoothed=S,w.TimeScale=H,w.Tween=I,w.createChart=Mt,w.defaultTheme=B,w.easeInOutCubic=Q,w.easeOutCubic=F,w.lightTheme=tt,w.mulberry32=E,w.version=kt,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
1
+ (function(y,R){typeof exports=="object"&&typeof module!="undefined"?R(exports):typeof define=="function"&&define.amd?define(["exports"],R):(y=typeof globalThis!="undefined"?globalThis:y||self,R(y.Emberwick={}))})(this,function(y){"use strict";class R{constructor(t,e){this.container=t,this.names=e,this.canvas={},this.ctx={},this.width=0,this.height=0,this.dpr=0,this.onResize=null,getComputedStyle(t).position==="static"&&(t.style.position="relative"),e.forEach((s,n)=>{const h=document.createElement("canvas");Object.assign(h.style,{position:"absolute",left:"0",top:"0",width:"100%",height:"100%",pointerEvents:"none",zIndex:String(n+1)}),t.appendChild(h),this.canvas[s]=h,this.ctx[s]=h.getContext("2d")}),this._ro=new ResizeObserver(()=>this.measure()),this._ro.observe(t),this.measure()}measure(){const t=this.container.getBoundingClientRect(),e=Math.max(1,Math.floor(t.width)),s=Math.max(1,Math.floor(t.height)),n=Math.min(window.devicePixelRatio||1,2);if(!(e===this.width&&s===this.height&&n===this.dpr)){this.width=e,this.height=s,this.dpr=n;for(const h of this.names){const a=this.canvas[h];a.width=Math.floor(e*n),a.height=Math.floor(s*n),this.ctx[h].setTransform(n,0,0,n,0,0)}this.onResize&&this.onResize(e,s)}}composite(){const t=document.createElement("canvas");t.width=Math.floor(this.width*this.dpr),t.height=Math.floor(this.height*this.dpr);const e=t.getContext("2d");for(const s of this.names)e.drawImage(this.canvas[s],0,0);return t}destroy(){this._ro.disconnect();for(const t of this.names)this.canvas[t].remove();this.canvas={},this.ctx={}}}class et{constructor(t){this.onFrame=t,this.fps=0,this._raf=0,this._dirty=new Set,this._last=0,this._running=!1,this._frames=0,this._fpsAt=0,this._tick=this._tick.bind(this)}invalidate(...t){if(!t.length)this._dirty.add("all");else for(const e of t)this._dirty.add(e);this._schedule()}start(){this._running||(this._running=!0,this._last=performance.now(),this._fpsAt=this._last,this.invalidate("all"))}stop(){this._running=!1,this._raf&&cancelAnimationFrame(this._raf),this._raf=0}_schedule(){this._raf||!this._running||(this._raf=requestAnimationFrame(this._tick))}_tick(t){if(this._raf=0,!this._running)return;const e=Math.min(Math.max(t-this._last,1),64);this._last=t,this._frames++,t-this._fpsAt>=500&&(this.fps=Math.round(this._frames*1e3/(t-this._fpsAt)),this._frames=0,this._fpsAt=t);const s=this._dirty;this._dirty=new Set;let n=!1;try{n=this.onFrame(s,e,t)===!0}catch(h){console.error("[Emberwick] frame error",h)}(n||this._dirty.size)&&this._schedule()}}const $=i=>1-Math.pow(1-i,3),it=i=>i<.5?4*i*i*i:1-Math.pow(-2*i+2,3)/2;class S{constructor(t=0,e=90){this.value=t,this.target=t,this.tau=e}set(t){this.target=t}jump(t){this.value=t,this.target=t}get settled(){const t=1e-9+Math.abs(this.target)*1e-6;return Math.abs(this.target-this.value)<=t}tick(t){return this.settled?(this.value=this.target,!1):(this.value+=(this.target-this.value)*(1-Math.exp(-t/this.tau)),!0)}}class j{constructor(t=200,e=$){this.duration=t,this.ease=e,this.t=t}restart(){this.t=0}get done(){return this.t>=this.duration}get progress(){return this.ease(Math.min(1,this.t/this.duration))}tick(t){return this.done?!1:(this.t+=t,!0)}}const I=(i,t,e)=>i<t?t:i>e?e:i;class K{constructor({spacing:t=9,minSpacing:e=.8,maxSpacing:s=160,rightOffset:n=12}={}){this.minSpacing=e,this.maxSpacing=s,this.rightOffset=n,this.width=0,this.barCount=0,this.follow=!0,this.timeframeMs=6e4,this._spacing=new S(t,65),this._right=new S(n,65),this._initial=t}get spacing(){return this._spacing.value}get right(){return this._right.value}resize(t){this.width=Math.max(1,t)}setBarCount(t){const e=t>this.barCount;if(this.barCount=t,this.follow){const s=t-1+this.rightOffset;e?this._right.set(s):this._right.jump(s)}}x(t){return this.width-(this._right.value-t)*this._spacing.value}index(t){return this._right.value-(this.width-t)/this._spacing.value}barWidth(){const t=this._spacing.value;return Math.max(1,Math.floor(t*.72))}visibleRange(){const t=Math.floor(this.index(0))-1,e=Math.ceil(this.index(this.width))+1;return{from:I(t,0,Math.max(0,this.barCount-1)),to:I(e,0,Math.max(0,this.barCount-1))}}_clampRight(t){const e=this.barCount-1+this.rightOffset+this.width/this._spacing.target,s=Math.min(4,this.barCount-1+this.rightOffset);return I(t,s,e)}panBy(t){if(!t)return!1;const e=this._clampRight(this._right.value-t/this._spacing.value);return this._right.jump(e),this.follow=!1,!0}zoomAt(t,e){const s=this._spacing.target,n=I(s*e,this.minSpacing,this.maxSpacing);if(Math.abs(n-s)<1e-9)return!1;const h=this.follow?this.width:t,r=this._right.target-(this.width-h)/s+(this.width-h)/n;return this._spacing.set(n),this._right.set(this._clampRight(r)),!0}snapToRealtime(){this.follow=!0,this._right.set(this.barCount-1+this.rightOffset)}jumpToRealtime(){this.follow=!0,this._right.jump(this.barCount-1+this.rightOffset)}reset(){this._spacing.set(this._initial),this.snapToRealtime()}tick(t){const e=this._spacing.tick(t),s=this._right.tick(t);return e||s}get settled(){return this._spacing.settled&&this._right.settled}}const st=(i,t,e)=>i<t?t:i>e?e:i;class O{constructor({mode:t="linear",tau:e=120,marginTop:s=.12,marginBottom:n=.12}={}){this.mode=t,this.marginTop=s,this.marginBottom=n,this.auto=!0,this.top=0,this.height=1,this._lo=new S(0,e),this._hi=new S(1,e),this._primed=!1}_fwd(t){return this.mode==="log"?Math.log(Math.max(t,1e-9)):t}_inv(t){return this.mode==="log"?Math.exp(t):t}setMode(t){if(t===this.mode)return;const e=this._inv(this._lo.value),s=this._inv(this._hi.value);this.mode=t,this._lo.jump(this._fwd(e)),this._hi.jump(this._fwd(s))}layout(t,e){this.top=t,this.height=Math.max(1,e)}get lo(){return this._inv(this._lo.value)}get hi(){return this._inv(this._hi.value)}y(t){const e=this._lo.value,s=this._hi.value,n=(this._fwd(t)-e)/(s-e||1);return this.top+this.height*(1-n)}price(t){const e=this._lo.value,s=this._hi.value,n=1-(t-this.top)/this.height;return this._inv(e+n*(s-e))}fit(t,e,s,n){if(!this.auto||!t.length)return;let h=1/0,a=-1/0;for(let p=e;p<=s;p++){const o=t[p];o&&(o.low<h&&(h=o.low),o.high>a&&(a=o.high))}if(n&&(n.low<h&&(h=n.low),n.high>a&&(a=n.high)),!isFinite(h)||!isFinite(a))return;let u=this._fwd(h),r=this._fwd(a),l=(r-u)*this.marginTop;l>0||(l=Math.abs(r)*.01||1),u-=l,r+=(r-u)*0+l,this._lo.set(u),this._hi.set(r),this._primed||(this._lo.jump(u),this._hi.jump(r),this._primed=!0)}scaleBy(t){this.auto=!1;const e=this._lo.target,s=this._hi.target,n=(e+s)/2,h=(s-e)/2*st(t,.2,5);this._lo.set(n-h),this._hi.set(n+h)}resetAuto(){this.auto=!0}tick(t){const e=this._lo.tick(t),s=this._hi.tick(t);return e||s}}const D={background:"#0b0e14",grid:"rgba(255,255,255,0.045)",axisLine:"rgba(255,255,255,0.10)",text:"#8b93a7",textStrong:"#e6e9ef",up:"#26a69a",down:"#ef5350",upFill:"#26a69a",downFill:"#ef5350",wickUp:"#26a69a",wickDown:"#ef5350",volumeUp:"rgba(38,166,154,0.30)",volumeDown:"rgba(239,83,80,0.30)",crosshair:"rgba(255,255,255,0.32)",labelBg:"#2a3040",labelText:"#e6e9ef",tagText:"#06080d",font:'11px ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif',priceAxisWidth:68,timeAxisHeight:26},nt={...D,background:"#ffffff",grid:"rgba(0,0,0,0.06)",axisLine:"rgba(0,0,0,0.14)",text:"#6b7280",textStrong:"#111827",labelBg:"#374151",volumeUp:"rgba(38,166,154,0.25)",volumeDown:"rgba(239,83,80,0.25)",crosshair:"rgba(0,0,0,0.35)",tagText:"#ffffff"};class U{constructor(t=55){this.enabled=!0,this.o=new S(0,t),this.h=new S(0,t),this.l=new S(0,t),this.c=new S(0,t),this.vol=new S(0,t*2),this.spawn=new j(240),this._has=!1,this._time=null}setTarget(t){if(!t){this._has=!1;return}(!this._has||t.time!==this._time)&&(this.o.jump(t.open),this.h.jump(t.open),this.l.jump(t.open),this.c.jump(t.open),this.vol.jump(0),this.spawn.restart(),this._time=t.time,this._has=!0),this.o.set(t.open),this.h.set(t.high),this.l.set(t.low),this.c.set(t.close),this.vol.set(t.volume||0)}reset(){this._has=!1,this._time=null}tick(t){if(!this._has)return!1;let e=!1;return this.o.tick(t)&&(e=!0),this.h.tick(t)&&(e=!0),this.l.tick(t)&&(e=!0),this.c.tick(t)&&(e=!0),this.vol.tick(t)&&(e=!0),this.spawn.tick(t)&&(e=!0),e}read(t){if(!this._has||!this.enabled||t.time!==this._time)return t;const e=this.o.value,s=this.c.value;return{time:t.time,open:e,close:s,high:Math.max(this.h.value,e,s),low:Math.min(this.l.value,e,s),volume:this.vol.value,_spawn:this.spawn.progress}}}class W{constructor({friction:t=.92,min:e=.015}={}){this.friction=t,this.min=e,this.v=0,this.active=!1}sample(t,e){if(e<=0)return;const s=t/e;this.v=this.v*.6+s*.4,this.active=!1}release(){Math.abs(this.v)>this.min&&(this.active=!0)}stop(){this.v=0,this.active=!1}tick(t){if(!this.active)return 0;const e=this.v*t;return this.v*=Math.pow(this.friction,t/16.6667),Math.abs(this.v)<this.min&&this.stop(),e}}const C=(i,t,e)=>i<t?t:i>e?e:i,B=.25,z=500,ht=240;class q{constructor(t,e={}){const s=Array.isArray(e.bars)?e.bars:[];this.chart=t,this.source=s.slice(),this.baseInterval=Math.max(16,+e.baseInterval||1e3),this.speed=C(+e.speed||1,B,z),this.looping=e.loop===!0,this.follow=e.follow!==!1,this.playing=!1,this._acc=0,this._markerKey="",this._markerView=null,this.minIndex=Math.min(1,this.lastIndex);const n=+e.from;this.index=C(Number.isFinite(n)?Math.round(n):Math.floor(this.lastIndex/2),this.minIndex,this.lastIndex),this._apply("seek")}get length(){return this.source.length}get lastIndex(){return Math.max(0,this.source.length-1)}get atEnd(){return this.index>=this.lastIndex}get bar(){return this.source[this.index]||null}get time(){return this.bar?this.bar.time:null}get progress(){const t=this.lastIndex-this.minIndex;return t>0?(this.index-this.minIndex)/t:1}get interval(){return this.baseInterval/this.speed}state(){return{active:!0,playing:this.playing,index:this.index,length:this.length,progress:this.progress,speed:this.speed,time:this.time,bar:this.bar,atEnd:this.atEnd}}play(){return this.playing||this.length<2?this:(this.atEnd&&(this.index=this.minIndex,this._apply("seek")),this.playing=!0,this._acc=0,this._changed(),this)}pause(){return this.playing?(this.playing=!1,this._acc=0,this._changed(),this):this}toggle(){return this.playing?this.pause():this.play()}setSpeed(t){const e=C(+t||1,B,z);return e===this.speed?this:(this.speed=e,this._acc=0,this._changed(),this)}setLoop(t){return this.looping=!!t,this._changed(),this}seek(t){const e=C(Math.round(+t),this.minIndex,this.lastIndex);return e===this.index?this:(this.index=e,this._acc=0,this._apply("seek"),this._changed(),this)}step(t=1){return this.seek(this.index+(t||0))}toStart(){return this.seek(this.minIndex)}toEnd(){return this.seek(this.lastIndex)}tick(t){if(!this.playing||this.length<2)return!1;this._acc+=t*this.speed;const e=Math.floor(this._acc/this.baseInterval);if(e<=0)return!0;this._acc-=e*this.baseInterval;const s=this.lastIndex;let n=this.index+Math.min(e,ht);if(n>s){if(this.looping)return this.index=this.minIndex,this._apply("seek"),this._changed(),!0;n=s}const h=n===this.index+1;return this.index=n,this._apply(h?"step":"seek"),this.atEnd&&!this.looping&&(this.playing=!1,this._acc=0),this._changed(),this.playing}markerFilter(t){const e=this.time;if(e==null)return t;const s=this.index+":"+t.length;if(s!==this._markerKey||!this._markerView){const n=e+(this.chart.ts.timeframeMs||0)/2;this._markerView=t.filter(h=>h.time<=n),this._markerKey=s}return this._markerView}invalidateMarkers(){this._markerKey="",this._markerView=null}_apply(t){const e=this.chart;if(t==="step"&&e.bars.length===this.index){e.append(this.source[this.index]);return}e._swapBars(this.source.slice(0,this.index+1)),this.follow&&e.ts.jumpToRealtime()}_changed(){this.chart.loop.invalidate("main")}}function at(i,t){const e=i/Math.max(1,t);if(!(e>0)||!isFinite(e))return 1;const s=Math.pow(10,Math.floor(Math.log10(e))),n=e/s;return(n<1.5?1:n<3?2:n<7?5:10)*s}function L(i,t,e){const s=at(t-i,e),n=[],h=Math.ceil(i/s)*s;for(let a=h;a<=t+s*1e-9;a+=s)n.push(a);return{ticks:n,step:s}}function E(i){return!isFinite(i)||i<=0?2:i>=100?0:i>=1?2:Math.min(8,Math.ceil(-Math.log10(i))+1)}function rt(i){const t=[1,2,5,10,15,20,30,60,120,240,480,960,1920,3840,7680];for(const e of t)if(e>=i)return e;return Math.ceil(i/1e3)*1e3}const A=i=>String(i).padStart(2,"0");function ot(i,t){const e=new Date(i);return t>=864e5?`${e.getDate()} ${e.toLocaleString("en",{month:"short"})}`:e.getHours()===0&&e.getMinutes()===0?`${e.getDate()} ${e.toLocaleString("en",{month:"short"})}`:`${A(e.getHours())}:${A(e.getMinutes())}`}function lt(i){const t=new Date(i);return`${t.getFullYear()}-${A(t.getMonth()+1)}-${A(t.getDate())} ${A(t.getHours())}:${A(t.getMinutes())}`}function ct(i,t){const{theme:e,ts:s,ps:n,plot:h,bars:a,width:u,height:r}=t;i.clearRect(0,0,u,r),i.fillStyle=e.background,i.fillRect(0,0,u,r),i.font=e.font,i.textBaseline="middle";const l=Math.max(2,Math.floor(h.h/58)),{ticks:p,step:o}=L(n.lo,n.hi,l),c=E(o);i.strokeStyle=e.grid,i.lineWidth=1,i.beginPath();for(const d of p){const f=Math.round(n.y(d))+.5;f<h.y||f>h.y+h.h||(i.moveTo(0,f),i.lineTo(h.w,f))}i.stroke(),i.fillStyle=e.text,i.textAlign="left";for(const d of p){const f=Math.round(n.y(d));f<h.y+6||f>h.y+h.h-6||i.fillText(d.toFixed(c),h.w+8,f)}if(a.length){const d=Math.ceil(74/Math.max(1e-4,s.spacing)),f=rt(d),{from:v,to:b}=s.visibleRange(),M=Math.ceil(v/f)*f;i.strokeStyle=e.grid,i.beginPath();for(let g=M;g<=b;g+=f){const m=Math.round(s.x(g))+.5;m<0||m>h.w||(i.moveTo(m,0),i.lineTo(m,h.h))}i.stroke(),i.fillStyle=e.text,i.textAlign="center";const w=h.h+e.timeAxisHeight/2;for(let g=M;g<=b;g+=f){const m=a[g];if(!m)continue;const _=Math.round(s.x(g));_<28||_>h.w-28||i.fillText(ot(m.time,s.timeframeMs),_,w)}}i.strokeStyle=e.axisLine,i.beginPath(),i.moveTo(h.w+.5,0),i.lineTo(h.w+.5,h.h),i.moveTo(0,h.h+.5),i.lineTo(u,h.h+.5),i.stroke()}function ut(i,t){const{theme:e,ts:s,ps:n,plot:h,bars:a,width:u,height:r,live:l,volumeRatio:p}=t;if(i.clearRect(0,0,u,r),!a.length)return;const{from:o,to:c}=s.visibleRange(),d=s.barWidth(),f=d/2,v=d<=2,b=h.h*p,M=h.y+h.h-b;let w=0;for(let m=o;m<=c;m++){const _=a[m];_&&_.volume>w&&(w=_.volume)}if(w>0)for(let m=o;m<=c;m++){let _=a[m];if(!_)continue;l&&m===a.length-1&&(_=l);const k=s.x(m);if(k<-d||k>h.w+d)continue;const T=_.volume/w*b*.9;i.fillStyle=_.close>=_.open?e.volumeUp:e.volumeDown,i.fillRect(Math.round(k-f),M+(b-T),Math.max(1,d),T)}for(let m=o;m<=c;m++){let _=a[m];if(!_)continue;const k=m===a.length-1;l&&k&&(_=l);const T=s.x(m);if(T<-d||T>h.w+d)continue;const P=_.close>=_.open,Lt=P?e.up:e.down,G=n.y(_.open),J=n.y(_.close),Et=n.y(_.high),Pt=n.y(_.low);let Q=1;l&&k&&typeof _._spawn=="number"&&(Q=.35+.65*_._spawn);const x=Math.round(T)+(d%2?.5:0);if(i.strokeStyle=P?e.wickUp:e.wickDown,i.lineWidth=Math.max(1,Math.min(2,d*.16)),i.beginPath(),i.moveTo(x,Et),i.lineTo(x,Pt),i.stroke(),v)continue;const Dt=Math.min(G,J),Bt=Math.max(1,Math.abs(J-G)),tt=Math.max(1,d*Q);i.fillStyle=Lt,i.fillRect(Math.round(T-tt/2),Math.round(Dt),Math.round(tt),Math.round(Bt))}const g=l||a[a.length-1];if(g){const m=Math.round(n.y(g.close))+.5;if(m>h.y&&m<h.y+h.h){const _=g.close>=g.open;i.save(),i.setLineDash([3,3]),i.strokeStyle=_?e.up:e.down,i.lineWidth=1,i.globalAlpha=.7,i.beginPath(),i.moveTo(0,m),i.lineTo(h.w,m),i.stroke(),i.restore();const{step:k}=L(n.lo,n.hi,Math.max(2,Math.floor(h.h/58))),T=g.close.toFixed(E(k));i.font=e.font,i.textBaseline="middle",i.textAlign="left";const P=i.measureText(T).width;i.fillStyle=_?e.up:e.down,i.fillRect(h.w+1,m-9,P+14,18),i.fillStyle=e.tagText,i.fillText(T,h.w+8,m)}}}function ft(i,t){const{theme:e,ts:s,ps:n,plot:h,bars:a,width:u,height:r,cursor:l,magnet:p}=t;if(i.clearRect(0,0,u,r),!l||!a.length||l.x<0||l.x>h.w||l.y<0||l.y>h.h)return;const o=Math.round(s.index(l.x)),c=a[o];let d=l.x,f=l.y;if(c&&(d=s.x(o),p)){const w=[c.open,c.high,c.low,c.close];let g=null,m=1/0;for(const _ of w){const k=n.y(_),T=Math.abs(k-l.y);T<m&&(m=T,g=k)}m<22&&(f=g)}i.save(),i.setLineDash([4,4]),i.strokeStyle=e.crosshair,i.lineWidth=1,i.beginPath(),i.moveTo(Math.round(d)+.5,0),i.lineTo(Math.round(d)+.5,h.h),i.moveTo(0,Math.round(f)+.5),i.lineTo(h.w,Math.round(f)+.5),i.stroke(),i.restore(),i.font=e.font,i.textBaseline="middle";const{step:v}=L(n.lo,n.hi,Math.max(2,Math.floor(h.h/58))),b=n.price(f).toFixed(E(v));i.textAlign="left";const M=i.measureText(b).width;if(i.fillStyle=e.labelBg,i.fillRect(h.w+1,f-9,M+14,18),i.fillStyle=e.labelText,i.fillText(b,h.w+8,f),c){const w=lt(c.time);i.textAlign="center";const g=i.measureText(w).width,m=Math.min(Math.max(d,g/2+6),h.w-g/2-6);i.fillStyle=e.labelBg,i.fillRect(m-g/2-7,h.h+3,g+14,18),i.fillStyle=e.labelText,i.fillText(w,m,h.h+12)}}const dt=["arrowUp","arrowDown","triangleUp","triangleDown","circle","square","diamond","flag","label"],mt=new Set(dt),pt={arrowUp:"belowBar",triangleUp:"belowBar",arrowDown:"aboveBar",triangleDown:"aboveBar"},gt=new Set(["aboveBar","belowBar","inBar","atPrice"]);function _t(i,t){if(!i||!isFinite(i.time))return null;const e=mt.has(i.shape)?i.shape:"circle",s=gt.has(i.position)?i.position:pt[e]||"aboveBar";return{id:i.id!=null?String(i.id):`mk${t}`,time:+i.time,price:isFinite(i.price)?+i.price:null,shape:e,position:s,color:i.color||null,textColor:i.textColor||null,text:i.text!=null?String(i.text):"",size:isFinite(i.size)&&i.size>0?+i.size:1,data:i.data,index:-1}}function V(i){if(!Array.isArray(i))return[];const t=[];for(let e=0;e<i.length;e++){const s=_t(i[e],e);s&&t.push(s)}return t.sort((e,s)=>e.time-s.time),t}function F(i,t){const e=i.length;if(!e)return-1;if(t<=i[0].time)return 0;if(t>=i[e-1].time)return e-1;let s=0,n=e-1;for(;s<=n;){const u=s+n>>1,r=i[u].time;if(r===t)return u;r<t?s=u+1:n=u-1}const h=Math.max(0,n),a=Math.min(e-1,s);return Math.abs(i[h].time-t)<=Math.abs(i[a].time-t)?h:a}function yt(i,t){for(let e=0;e<i.length;e++)i[e].index=F(t,i[e].time);return i}function vt(i,t){const{ts:e,ps:s,plot:n,bars:h,live:a}=t;if(!i.length||!h.length)return[];const{from:u,to:r}=e.visibleRange(),l=h.length-1,p=e.barWidth()<=3,o=new Map,c=[];let d=-1/0;for(const f of i){const v=f.index;if(v<0||v<u-2||v>r+2)continue;const b=a&&v===l?a:h[v];if(!b)continue;const M=e.x(v);if(M<-48||M>n.w+48)continue;if(p){if(M-d<4)continue;d=M}const w=5*f.size;let g,m=0;if(f.position==="atPrice"&&f.price!=null?g=s.y(f.price):f.position==="inBar"?g=s.y((b.high+b.low)/2):f.position==="belowBar"?(g=s.y(b.low)+w+7,m=1):(g=s.y(b.high)-w-7,m=-1),m!==0){const _=v+f.position,k=o.get(_)||0;o.set(_,k+1),g+=m*k*(w*2+5)}c.push({m:f,x:M,y:g,r:w,dir:m})}return c}const X={solid:[],dashed:[6,4],dotted:[1,3]},bt=new Set(["arrowDown","triangleDown"]);function N(i,t,e,s,n,h){const a=Math.max(0,Math.min(h,n/2,s/2));i.beginPath(),i.moveTo(t+a,e),i.lineTo(t+s-a,e),i.quadraticCurveTo(t+s,e,t+s,e+a),i.lineTo(t+s,e+n-a),i.quadraticCurveTo(t+s,e+n,t+s-a,e+n),i.lineTo(t+a,e+n),i.quadraticCurveTo(t,e+n,t,e+n-a),i.lineTo(t,e+a),i.quadraticCurveTo(t,e,t+a,e),i.closePath()}function wt(i,t){const{zones:e,theme:s,ts:n,ps:h,plot:a,bars:u}=t;if(!(!e||!e.length)){i.save(),i.font=s.font,i.textBaseline="top",i.textAlign="left";for(const r of e){let l,p,o,c;if(isFinite(r.from)&&isFinite(r.to))p=h.y(Math.max(r.from,r.to)),c=Math.max(1,h.y(Math.min(r.from,r.to))-p),l=0,o=a.w;else if(isFinite(r.fromTime)&&isFinite(r.toTime)&&u.length){const d=n.x(F(u,Math.min(r.fromTime,r.toTime))),f=n.x(F(u,Math.max(r.fromTime,r.toTime)));l=d,o=Math.max(1,f-d),p=0,c=a.h}else continue;l>a.w||l+o<0||p>a.h||p+c<0||(i.fillStyle=r.color||"rgba(38,166,154,0.10)",i.fillRect(l,p,o,c),r.border&&(i.strokeStyle=r.border,i.lineWidth=1,i.strokeRect(Math.round(l)+.5,Math.round(p)+.5,Math.round(o),Math.round(c))),r.label&&(i.fillStyle=r.labelColor||s.text,i.fillText(r.label,Math.max(6,l+6),Math.max(4,p+4))))}i.restore()}}function Mt(i,t){const{priceLines:e,theme:s,ps:n,plot:h}=t;if(!e||!e.length)return;const{step:a}=L(n.lo,n.hi,Math.max(2,Math.floor(h.h/58))),u=E(a);i.save(),i.font=s.font,i.textBaseline="middle";for(const r of e){if(!r||!isFinite(r.price))continue;const l=Math.round(n.y(r.price))+.5;if(l<0||l>h.h)continue;const p=r.color||s.textStrong;if(i.setLineDash(X[r.lineStyle]||X.dashed),i.strokeStyle=p,i.lineWidth=r.lineWidth||1,i.beginPath(),i.moveTo(0,l),i.lineTo(h.w,l),i.stroke(),i.setLineDash([]),r.title){i.textAlign="left";const o=i.measureText(r.title).width;i.fillStyle=p,N(i,6,l-9,o+12,18,4),i.fill(),i.fillStyle=r.titleColor||s.tagText,i.fillText(r.title,12,l)}if(r.axisLabel!==!1){const o=r.price.toFixed(u);i.textAlign="left";const c=i.measureText(o).width;i.fillStyle=p,i.fillRect(h.w+1,l-9,c+14,18),i.fillStyle=r.tagTextColor||s.tagText,i.fillText(o,h.w+8,l)}}i.restore()}function kt(i,t,e,s,n){switch(i.beginPath(),t){case"arrowUp":i.moveTo(e,s-n),i.lineTo(e+n,s),i.lineTo(e+n*.45,s),i.lineTo(e+n*.45,s+n),i.lineTo(e-n*.45,s+n),i.lineTo(e-n*.45,s),i.lineTo(e-n,s),i.closePath();break;case"arrowDown":i.moveTo(e,s+n),i.lineTo(e+n,s),i.lineTo(e+n*.45,s),i.lineTo(e+n*.45,s-n),i.lineTo(e-n*.45,s-n),i.lineTo(e-n*.45,s),i.lineTo(e-n,s),i.closePath();break;case"triangleUp":i.moveTo(e,s-n),i.lineTo(e+n,s+n),i.lineTo(e-n,s+n),i.closePath();break;case"triangleDown":i.moveTo(e,s+n),i.lineTo(e+n,s-n),i.lineTo(e-n,s-n),i.closePath();break;case"square":i.rect(e-n,s-n,n*2,n*2);break;case"diamond":i.moveTo(e,s-n),i.lineTo(e+n,s),i.lineTo(e,s+n),i.lineTo(e-n,s),i.closePath();break;default:i.arc(e,s,n,0,Math.PI*2)}}function Tt(i,t,e,s,n){i.fillStyle=n,i.fillRect(t-s*.8,e-s,Math.max(1,s*.3),s*2),i.beginPath(),i.moveTo(t-s*.5,e-s),i.lineTo(t+s,e-s*.55),i.lineTo(t-s*.5,e-s*.1),i.closePath(),i.fill()}function St(i,t,e,s){const n=[];if(!e||!e.length)return n;const{theme:h}=t;i.save(),i.font=h.font,i.textAlign="center",i.textBaseline="middle";for(const a of e){const{m:u,x:r,y:l,r:p,dir:o}=a,c=u.color||(bt.has(u.shape)?h.down:h.up),d=s!=null&&u.id===s;if(u.shape==="label"){const f=u.text||"•",v=i.measureText(f).width+14,b=18*u.size;N(i,r-v/2,l-b/2,v,b,4),i.fillStyle=c,i.fill(),d&&(i.strokeStyle=h.textStrong,i.lineWidth=1.5,i.stroke()),i.fillStyle=u.textColor||h.tagText,i.fillText(f,r,l+.5),n.push({id:u.id,marker:u,x:r,y:l,r:Math.max(v,b)/2});continue}d&&(i.beginPath(),i.arc(r,l,p+4,0,Math.PI*2),i.fillStyle="rgba(255,255,255,0.14)",i.fill()),u.shape==="flag"?Tt(i,r,l,p,c):(kt(i,u.shape,r,l,p),i.fillStyle=c,i.fill()),u.text&&(i.fillStyle=u.textColor||h.text,i.fillText(u.text,r,o>=0?l+p+9:l-p-9)),n.push({id:u.id,marker:u,x:r,y:l,r:p+3})}return i.restore(),n}const At=()=>({active:!1,playing:!1,index:-1,length:0,progress:0,speed:1,time:null,bar:null,atEnd:!1});class Y{constructor(t,e={}){if(!t)throw new Error("Chart: container element is required");this.container=t,this.theme={...D,...e.theme||{}},this.options={volumeRatio:.18,magnet:!0,animate:!0,...e},this.bars=[],this.feed=null,this._unsub=null,this._loadingHistory=!1,this._exhausted=!1,this._replay=null,this._listeners={crosshair:new Set,visibleRange:new Set,markerClick:new Set,markerHover:new Set,replay:new Set},this._markers=V(e.markers),this.priceLines=Array.isArray(e.priceLines)?e.priceLines.slice():[],this.zones=Array.isArray(e.zones)?e.zones.slice():[],this._markerHits=[],this._hoverMarkerId=null,this._resolveKey="",this.layers=new R(t,["base","main","overlay"]),this.ts=new K(e.timeScale),this.ps=new O(e.priceScale),this.live=new U,this.live.enabled=this.options.animate!==!1,this.inertia=new W,this.cursor=null,this.plot={x:0,y:0,w:1,h:1},this.loop=new et((s,n)=>this._frame(s,n)),this.layers.onResize=()=>{this._layout(),this.loop.invalidate("all")},this._layout(),this._bindEvents(),this.loop.start()}_layout(){const{width:t,height:e}=this.layers,s=Math.max(1,t-this.theme.priceAxisWidth),n=Math.max(1,e-this.theme.timeAxisHeight);this.plot={x:0,y:0,w:s,h:n},this.ts.resize(s),this.ps.layout(0,n)}setData(t){this._replay&&(this._replay=null),this.bars=Array.isArray(t)?t.slice():[],this._exhausted=!1,this.bars.length>1&&(this.ts.timeframeMs=this.bars[1].time-this.bars[0].time),this.ts.setBarCount(this.bars.length),this.ts.snapToRealtime(),this.live.reset(),this.ps._primed=!1,this.loop.invalidate("all")}_swapBars(t){this.bars=Array.isArray(t)?t:[],this.bars.length>1&&(this.ts.timeframeMs=this.bars[1].time-this.bars[0].time),this.ts.setBarCount(this.bars.length),this.live.reset(),this._resolveKey="",this.loop.invalidate("all")}update(t){if(!t)return;const e=this.bars.length;if(e&&this.bars[e-1].time===t.time)this.bars[e-1]=t;else{this.append(t);return}this.live.setTarget(t),this.loop.invalidate("main")}append(t){if(!t)return;const e=this.bars.length;e&&t.time<=this.bars[e-1].time?this.bars[e-1]=t:(this.bars.push(t),this.ts.setBarCount(this.bars.length)),this.live.setTarget(t),this.loop.invalidate("main")}async setFeed(t){if(this.detachFeed(),this.feed=t,!t)return;this.ts.timeframeMs=t.timeframe||this.ts.timeframeMs;const e=await t.getBars({symbol:t.symbol,timeframe:t.timeframe,to:null,limit:this.options.initialBars||1500});this.setData(e),typeof t.prime=="function"&&t.prime(e[e.length-1]),this._unsub=t.subscribe(s=>{!s||!s.bar||this._replay||(s.type==="append"?this.append(s.bar):this.update(s.bar))})}detachFeed(){this._unsub&&this._unsub(),this._unsub=null,this.feed=null}async _maybeLoadHistory(){if(this._replay||this._loadingHistory||this._exhausted||!this.feed)return;const{from:t}=this.ts.visibleRange();if(!(t>80||!this.bars.length)){this._loadingHistory=!0;try{const e=this.bars[0].time,s=await this.feed.getBars({symbol:this.feed.symbol,timeframe:this.feed.timeframe,to:e,limit:1e3});if(!s||!s.length)this._exhausted=!0;else{const n=s.filter(h=>h.time<e);if(!n.length)this._exhausted=!0;else{this.bars=n.concat(this.bars);const h=this.ts.follow;this.ts.barCount=this.bars.length,this.ts._right.jump(this.ts._right.value+n.length),this.ts._right.set(this.ts._right.target+n.length),this.ts.follow=h,this.loop.invalidate("all")}}}catch(e){console.error("[Emberwick] history load failed",e),this._exhausted=!0}finally{this._loadingHistory=!1}}}_bindEvents(){const t=this.container;t.style.touchAction="none",t.style.cursor="crosshair";let e=!1,s=null,n=0,h=0,a=0,u=!1;const r=new Map;let l=0;const p=o=>{const c=t.getBoundingClientRect();return{x:o.clientX-c.left,y:o.clientY-c.top}};this._onDown=o=>{if(r.set(o.pointerId,p(o)),r.size===2){const[d,f]=[...r.values()];l=Math.hypot(d.x-f.x,d.y-f.y),e=!1;return}const c=p(o);e=!0,u=!1,s=c.x>this.plot.w?"price":c.y>this.plot.h?"time":"pan",n=c.x,h=c.y,a=performance.now(),this.inertia.stop(),t.setPointerCapture(o.pointerId)},this._onMove=o=>{const c=p(o);if(r.has(o.pointerId)&&r.set(o.pointerId,c),r.size===2){const[M,w]=[...r.values()],g=Math.hypot(M.x-w.x,M.y-w.y);if(l>0&&g>0){const m=(M.x+w.x)/2;this.ts.zoomAt(m,g/l),this.loop.invalidate("all")}l=g;return}if(this.cursor=c,this._emitCrosshair(c),this.loop.invalidate("overlay"),!e)return;const d=performance.now(),f=d-a,v=c.x-n,b=c.y-h;(Math.abs(v)>1||Math.abs(b)>1)&&(u=!0),s==="pan"?(this.ts.panBy(v),this.inertia.sample(v,f),this.loop.invalidate("all"),this._maybeLoadHistory()):s==="price"?(this.ps.scaleBy(1+b/220),this.loop.invalidate("all")):s==="time"&&(this.ts.zoomAt(this.plot.w,1-v/260),this.loop.invalidate("all")),n=c.x,h=c.y,a=d},this._onUp=o=>{r.delete(o.pointerId),r.size<2&&(l=0),e&&s==="pan"&&u&&(this.inertia.release(),this.loop.invalidate("all")),e=!1,s=null;try{t.releasePointerCapture(o.pointerId)}catch{}},this._onLeave=()=>{this.cursor=null,this._emitCrosshair(null),this.loop.invalidate("overlay")},this._onWheel=o=>{o.preventDefault();const c=t.getBoundingClientRect(),d=o.clientX-c.left,f=Math.pow(.999,o.deltaY);this.ts.zoomAt(d,f),this.loop.invalidate("all"),this._maybeLoadHistory()},this._onDbl=()=>{this.ts.reset(),this.ps.resetAuto(),this.loop.invalidate("all")},this._onKey=o=>{const c=o.shiftKey?120:40;if(o.key==="ArrowLeft")this.ts.panBy(c),this.loop.invalidate("all"),this._maybeLoadHistory();else if(o.key==="ArrowRight")this.ts.panBy(-c),this.loop.invalidate("all");else if(o.key==="+"||o.key==="=")this.ts.zoomAt(this.plot.w/2,1.2),this.loop.invalidate("all");else if(o.key==="-"||o.key==="_")this.ts.zoomAt(this.plot.w/2,.8),this.loop.invalidate("all");else return;o.preventDefault()},this._onClick=o=>{if(u||!this._listeners.markerClick.size)return;const c=p(o),d=this.markerAt(c.x,c.y);if(d)for(const f of this._listeners.markerClick)f(d)},t.addEventListener("click",this._onClick),t.addEventListener("pointerdown",this._onDown),t.addEventListener("pointermove",this._onMove),t.addEventListener("pointerup",this._onUp),t.addEventListener("pointercancel",this._onUp),t.addEventListener("pointerleave",this._onLeave),t.addEventListener("wheel",this._onWheel,{passive:!1}),t.addEventListener("dblclick",this._onDbl),t.addEventListener("keydown",this._onKey),t.hasAttribute("tabindex")||t.setAttribute("tabindex","0")}_emitCrosshair(t){if(this._listeners.crosshair.size){let e=null;if(t&&this.bars.length&&t.x<=this.plot.w&&t.y<=this.plot.h){const s=Math.round(this.ts.index(t.x)),n=this.bars[s];n&&(e={index:s,bar:n,price:this.ps.price(t.y)})}for(const s of this._listeners.crosshair)s(e)}this._updateHover(t)}markerAt(t,e){const s=this._markerHits;for(let n=s.length-1;n>=0;n--){const h=s[n],a=t-h.x,u=e-h.y;if(a*a+u*u<=h.r*h.r)return h.marker}return null}_updateHover(t){const e=t?this.markerAt(t.x,t.y):null,s=e?e.id:null;if(s!==this._hoverMarkerId){this._hoverMarkerId=s,this.container.style.cursor=e?"pointer":"crosshair",this.loop.invalidate("main");for(const n of this._listeners.markerHover)n(e)}}subscribe(t,e){const s=this._listeners[t];if(!s)throw new Error(`Chart: unknown event "${t}"`);if(s.add(e),t==="visibleRange"){const n=this.visibleRange();this._rangeKey=this._rangeIdentity(n),e(n)}if(t==="replay"){const n=this.replayState();this._replayKey=this._replayIdentity(n),e(n)}return()=>s.delete(e)}visibleRange(){const{from:t,to:e}=this.ts.visibleRange();return this._rangePayload(t,e)}_rangePayload(t,e){const s=this.bars.length;return{from:t,to:e,fromTime:s?this.bars[t].time:null,toTime:s?this.bars[e].time:null,barCount:s,spacing:this.ts.spacing,settled:this.ts.settled}}_rangeIdentity(t){return`${t.from}:${t.to}:${t.fromTime}:${t.toTime}:${t.settled?1:0}`}_emitVisibleRange(t,e){const s=this._listeners.visibleRange;if(!s.size)return;const n=this._rangePayload(t,e),h=this._rangeIdentity(n);if(h!==this._rangeKey){this._rangeKey=h;for(const a of s)a(n)}}startReplay(t={}){const e=Array.isArray(t.bars)&&t.bars.length?t.bars:this._replay?this._replay.source:this.bars;if(!e||e.length<2)return null;const s=e.slice();return this._replay=new q(this,{...t,bars:s}),this._replay}stopReplay(){if(!this._replay)return;const t=this._replay.source;this._replay=null,this.setData(t)}get replay(){return this._replay}replayState(){return this._replay?this._replay.state():At()}_replayIdentity(t){return`${t.active?1:0}:${t.playing?1:0}:${t.index}:${t.length}:${t.speed}`}_emitReplay(){const t=this._listeners.replay;if(!t.size)return;const e=this.replayState(),s=this._replayIdentity(e);if(s!==this._replayKey){this._replayKey=s;for(const n of t)n(e)}}setMarkers(t){this._markers=V(t),this._resolveKey="",this._replay&&this._replay.invalidateMarkers(),this.loop.invalidate("main")}getMarkers(){return this._markers.slice()}addMarker(t){this.setMarkers(this._markers.concat([t]))}removeMarker(t){const e=String(t);this.setMarkers(this._markers.filter(s=>s.id!==e))}clearMarkers(){this.setMarkers([])}setPriceLines(t){this.priceLines=Array.isArray(t)?t.slice():[],this.loop.invalidate("main")}setZones(t){this.zones=Array.isArray(t)?t.slice():[],this.loop.invalidate("all")}_frame(t,e){let s=!1;this._replay&&this._replay.tick(e)&&(s=!0),this.ts.tick(e)&&(s=!0);const n=this.inertia.tick(e);n&&(this.ts.panBy(n),s=!0,this._maybeLoadHistory()),this.live.tick(e)&&(s=!0);const{from:h,to:a}=this.ts.visibleRange(),u=this.bars.length-1,r=this.bars.length?this.live.read(this.bars[u]):null,l=r&&a>=u?r:null;this.ps.fit(this.bars,h,a,l),this.ps.tick(e)&&(s=!0);const p=s||t.has("all")||t.has("base")||t.has("main"),o={theme:this.theme,ts:this.ts,ps:this.ps,plot:this.plot,bars:this.bars,width:this.layers.width,height:this.layers.height,live:l,volumeRatio:this.options.volumeRatio,cursor:this.cursor,magnet:this.options.magnet,priceLines:this.priceLines,zones:this.zones};let c=this._markers;if(this._replay&&c.length&&(c=this._replay.markerFilter(c)),c.length){const d=c.length+":"+this.bars.length+":"+(this.bars.length?this.bars[0].time:0);d!==this._resolveKey&&(yt(c,this.bars),this._resolveKey=d)}return p&&(ct(this.layers.ctx.base,o),wt(this.layers.ctx.base,o),ut(this.layers.ctx.main,o),Mt(this.layers.ctx.main,o),this._markerHits=St(this.layers.ctx.main,o,vt(c,o),this._hoverMarkerId)),(p||t.has("overlay"))&&ft(this.layers.ctx.overlay,o),this._emitVisibleRange(h,a),this._emitReplay(),s}get fps(){return this.loop.fps}setTheme(t){this.theme={...this.theme,...t},this._layout(),this.loop.invalidate("all")}setPriceMode(t){this.ps.setMode(t),this.loop.invalidate("all")}setAnimate(t){this.live.enabled=!!t,this.loop.invalidate("all")}setMagnet(t){this.options.magnet=!!t,this.loop.invalidate("overlay")}snapToRealtime(){this.ts.snapToRealtime(),this.ps.resetAuto(),this.loop.invalidate("all")}toImage(){return this.layers.composite().toDataURL("image/png")}destroy(){const t=this.container;t.removeEventListener("pointerdown",this._onDown),t.removeEventListener("pointermove",this._onMove),t.removeEventListener("pointerup",this._onUp),t.removeEventListener("pointercancel",this._onUp),t.removeEventListener("pointerleave",this._onLeave),t.removeEventListener("wheel",this._onWheel),t.removeEventListener("dblclick",this._onDbl),t.removeEventListener("keydown",this._onKey),t.removeEventListener("click",this._onClick),this.detachFeed(),this.loop.stop(),this.layers.destroy();for(const e of Object.values(this._listeners))e.clear();this._replay=null,this._markers=[],this._markerHits=[],this.priceLines=[],this.zones=[],this.bars=[]}}class Z{constructor({symbol:t="DEMO",timeframe:e=6e4}={}){this.symbol=t,this.timeframe=e}async getBars({symbol:t,timeframe:e,to:s,limit:n}){throw new Error("DataFeed.getBars() not implemented")}subscribe(t){return()=>{}}destroy(){}}function H(i){let t=i>>>0;return function(){t=t+1831565813|0;let e=Math.imul(t^t>>>15,1|t);return e=e+Math.imul(e^e>>>7,61|e)^e,((e^e>>>14)>>>0)/4294967296}}class Rt extends Z{constructor({symbol:t="EMBR",timeframe:e=6e4,seed:s=7,start:n=100,volatility:h=.0022,drift:a=2e-5,ticksPerSecond:u=8,speed:r=1}={}){super({symbol:t,timeframe:e}),this.seed=s,this.start=n,this.volatility=h,this.drift=a,this.ticksPerSecond=u,this.speed=r,this._rnd=H(s),this._handlers=new Set,this._timer=null,this._forming=null,this._last=n,this._vol=h,this._anchorTime=Math.floor(Date.now()/e)*e}_gauss(){let t=0,e=0;for(;t===0;)t=this._rnd();for(;e===0;)e=this._rnd();return Math.sqrt(-2*Math.log(t))*Math.cos(2*Math.PI*e)}_step(t){const e=this._gauss();return this._vol+=(this.volatility-this._vol)*.02+Math.abs(e)*this.volatility*.015,this._vol=Math.min(this._vol,this.volatility*6),Math.max(.01,t*(1+this.drift+e*this._vol))}_makeBar(t,e){let s=e;const n=14;let h=e,a=e;for(let l=0;l<n;l++)s=this._step(s),s>h&&(h=s),s<a&&(a=s);const u=Math.max(1e-9,h-a),r=Math.round((300+this._rnd()*900)*(1+u/e*260));return{time:t,open:e,high:h,low:a,close:s,volume:r}}async getBars({to:t,limit:e=1500,timeframe:s=this.timeframe}={}){const n=t==null?this._anchorTime:t,h=[],a=n-e*s,u=H(this.seed^Math.floor(a/s)),r=this._rnd;this._rnd=u;let l=this.start*(1+(u()-.5)*.04);for(let p=0;p<e;p++){const o=a+p*s,c=this._makeBar(o,l);l=c.close,h.push(c)}return this._rnd=r,t==null&&(this._last=h.length?h[h.length-1].close:this.start),h}subscribe(t){return this._handlers.add(t),this._timer||this._start(),()=>{this._handlers.delete(t),this._handlers.size||this.stop()}}_emit(t){for(const e of this._handlers)e(t)}_start(){const t=Math.max(16,1e3/this.ticksPerSecond);this._timer=setInterval(()=>this._tick(),t)}prime(t){t&&(this._last=t.close,this._forming={...t})}_tick(){const t=this.timeframe/this.speed,e=Date.now(),s=Math.floor(e/t)*t;if(!this._forming||this._forming.time!==s){const a=this._last;this._forming={time:s,open:a,high:a,low:a,close:a,volume:0},this._emit({type:"append",bar:{...this._forming}});return}const n=this._step(this._last);this._last=n;const h=this._forming;h.close=n,n>h.high&&(h.high=n),n<h.low&&(h.low=n),h.volume+=Math.round(20+this._rnd()*120),this._emit({type:"update",bar:{...h}})}setSpeed(t){this.speed=t}setTicksPerSecond(t){this.ticksPerSecond=t,this._timer&&(this.stop(),this._start())}setPaused(t){t?this.stop():!this._timer&&this._handlers.size&&this._start()}get paused(){return!this._timer}stop(){this._timer&&clearInterval(this._timer),this._timer=null}destroy(){this.stop(),this._handlers.clear()}}function It(i,t){return new Y(i,t)}const Ct="0.4.0";y.Chart=Y,y.DataFeed=Z,y.Inertia=W,y.LiveCandle=U,y.MAX_SPEED=z,y.MIN_SPEED=B,y.PriceScale=O,y.RandomFeed=Rt,y.Replay=q,y.Smoothed=S,y.TimeScale=K,y.Tween=j,y.createChart=It,y.defaultTheme=D,y.easeInOutCubic=it,y.easeOutCubic=$,y.lightTheme=nt,y.mulberry32=H,y.version=Ct,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
2
2
  //# sourceMappingURL=emberwick.umd.js.map