UNPKG

openalgo-charts

Version:

From-scratch, dependency-free canvas charting engine for OpenAlgo: professional-grade interactive rendering, advanced on-chart trading, and a one-call widget tier that adds the toolbar, drawing rail, dialogs and shortcuts.

3 lines (2 loc) • 6.9 kB
import{getSeriesTransform as e,chartSettingsSchema as t,readChartSettings as r,applyChartSettings as n}from"./openalgo-charts.mjs";import{w as o,x as s,widgetText as i,controlsFromInputs as a,m as l,n as c,renderForm as d,o as u,p,y as m,z as f}from"./openalgo-charts.widget.mjs";import"./openalgo-charts.draw.mjs";const b={"point-figure":[.05,.1,.15,.25,.5,1,2,3],renko:[.05,.1,.25,.5,1,2,3,5]},h={"point-figure":["symbol.body"],renko:["symbol.body","symbol.borders"]},g=["fixed","percent","atr","atrPercent"],y={fixed:"boxSize",percent:"percent",atr:"atrMultiplier",atrPercent:"percent"},v=e=>`${e<1?e.toFixed(2):String(e)}%`;let k=0;function x(e,t,r,n,o,s){const i=()=>o.mode,a=new Map,l=(t,n)=>{const o=c(e,"input","oac-input--num");return o.type="text",o.inputMode=n,o.id=`${r}-${t}`,o},d=l("size","decimal"),p=l("atr","numeric"),f=c(e,"span","oac-ctset__unit"),{wrap:h,select:k}=m(e);k.setAttribute("aria-label",t("method","Sizing method"));const x={fixed:t("mode.fixed","Absolute"),percent:t("mode.percent","Percent"),atr:t("mode.atr","ATR"),atrPercent:t("mode.atrPercent","ATR %")};for(const t of g)k.appendChild(Object.assign(c(e,"option",void 0,x[t]),{value:t}));const z=c(e,"span","oac-ctset__size");z.append(d,f,h);const P=c(e,"div","oac-ctset__presets");P.setAttribute("role","group"),P.setAttribute("aria-label",t("presets","Percent presets"));const S=b[n].map(t=>{const r=u(e,{label:v(t),onClick:()=>{o.mode="percent",o.percent=t,a.delete("size"),s()}});return r.classList.add("oac-ctset__preset"),r.dataset.percent=String(t),P.appendChild(r),{b:r,p:t}}),C=e=>{const r=(e=>{const r=("size"===e?d:p).value.trim(),n=""===r?"size"===e&&"fixed"===i()?0:NaN:Number(r);if("atrPeriod"===e){if(!Number.isInteger(n)||n<1)return t("error.length","Enter a whole number, 1 or more");o.atrPeriod=n}else{if(!Number.isFinite(n)||("fixed"===i()?n<0:n<=0))return"fixed"===i()?t("error.fixed","Enter 0 or a positive number"):t("error.positive","Enter a number above 0");o[y[i()]]=n}return null})(e);null===r?a.delete(e):a.set(e,r),s()};d.addEventListener("input",()=>C("size")),p.addEventListener("input",()=>C("atrPeriod")),k.addEventListener("change",()=>{o.mode=k.value,a.delete("size"),s()});const A=new Map;return{presets:P,size:z,atrPeriod:p,attach:t=>{for(const[r,n]of[["size",d],["atrPeriod",p]]){const o=t.querySelector(`[data-key="${r}"]`),s=o?.querySelector("label");s&&(s.htmlFor=n.id);const i=c(e,"div","oac-input-error");i.id=`${n.id}-error`,i.setAttribute("role","status"),n.setAttribute("aria-describedby",i.id),o?.appendChild(i),A.set(r,i)}},paint:()=>{const e=i();k.value=e,a.has("size")||(d.value="fixed"===e&&0===o.boxSize?"":String(o[y[e]]??"")),a.has("atrPeriod")||(p.value=String(o.atrPeriod??14)),d.placeholder="fixed"===e?t("auto","Auto"):"",d.title="fixed"===e?t("autoHint","Blank or 0 sizes it from the loaded history"):"",f.textContent="percent"===e||"atrPercent"===e?"%":"atr"===e?t("unit.atr","x ATR"):"",f.hidden=""===f.textContent;for(const{b:t,p:r}of S)t.setAttribute("aria-pressed",String("percent"===e&&o.percent===r&&!a.has("size")));for(const[e,t]of A){const r=a.get(e)??null;("size"===e?d:p).setAttribute("aria-invalid",String(null!==r)),t.textContent=r??"",t.hidden=null===r}},invalid:()=>a.has("size")?d:a.has("atrPeriod")&&(e=>"atr"===e||"atrPercent"===e)(i())?p:null,refuse:e=>{a.set("size",e),s()}}}function z(m,b){const{chart:y}=m,v=m.document,z=(e,t,r={})=>i(m,`schema.ui.chartTypeSettings.${e}`,r,t),P=o(y),S=y.primarySeries(),C=null===S?null:y.seriesTransform(S);if(null===P||null===C)return s(m,z("unavailable","This chart type has no box settings"));const A=P,_=e(A),O=z("title","{name} settings",{name:i(m,`schema.chartType.${A}`,{},_.name)}),E={};for(const e of _.inputs)E[e.key]=C.options?.[e.key]??e.default;g.includes(E.mode)||(E.mode="fixed");const T={},w="oac-ctset-"+ ++k,N=x(v,z,w,A,E,()=>W()),L=function(e,t,r,n,o){const s=c(e,"div","oac-ctset__radios");s.setAttribute("role","radiogroup"),s.setAttribute("aria-label",t("prices","Prices"));const i=["close","hl"].map(i=>{const a=c(e,"label","oac-ctset__radio"),l=Object.assign(c(e,"input"),{type:"radio",name:`${r}-method`,value:i});return l.addEventListener("change",()=>{l.checked&&(n.method=i,o())}),a.append(l,c(e,"span",void 0,"close"===i?t("method.close","Close only"):t("method.hl","High and low"))),s.appendChild(a),l});return{el:s,paint:()=>{for(const e of i)e.checked=n.method===e.value}}}(v,z,w,E,()=>W()),$="renko"===A?z("group.brick","Brick size"):z("group.box","Box size"),j=z("group.construction","Construction"),M=t(y).find(e=>"price"===e.id)?.inputs??[],R=h[A].flatMap(e=>M.filter(t=>t.key===e)),B=[...a(R,{translate:m.translate,scope:"settings"}).map(e=>({...e,group:z("group.colors","Colors")})),{key:"presets",kind:"custom",label:z("presetsLabel","Presets"),group:$},{key:"size",kind:"custom",label:z("size","Size"),group:$},{key:"atrPeriod",kind:"custom",label:z("atrPeriod","ATR length"),group:$,visibleWhen:{key:"mode",is:["atr","atrPercent"]}},..."renko"===A?[]:[{key:"reversal",kind:"select",label:z("reversal","Reversal"),group:j,options:Array.from({length:10},(e,t)=>({value:String(t+1),label:0===t?z("box","1 box"):z("boxes","{count} boxes",{count:String(t+1)})}))}],{key:"method",kind:"custom",label:z("prices","Prices"),group:j}],F={presets:N.presets,size:N.size,atrPeriod:N.atrPeriod,method:L.el};let q=!1,H=null;const J=l(v,{translate:m.translate,title:O,className:"oac-ctset",onClose:D}),I=c(v,"div","oac-ctset__form");J.body.appendChild(I);const K=d(I,B,{idPrefix:w,translate:m.translate,openOverlay:m.openOverlay,values:{...r(y),mode:E.mode,reversal:String(E.reversal??3)},onChange:(e,t)=>{"reversal"===e?E.reversal=Number(t):T[e]=t},custom:e=>F[e.key]??null});function W(){N.paint(),L.paint(),K.sync({mode:E.mode})}function D(){q||(q=!0,Q(),K.destroy(),H?.close())}function G(){if(q)return;const t=N.invalid();if(null!==t)return void t.focus();const r=function(t,r,o,s,i){const{chart:a}=t,l=a.primarySeries(),c=null===l?null:a.seriesTransform(l);if(null===l||c?.type!==r)return null;const d={...c.options};for(const t of e(r).inputs){const e=o[t.key];void 0!==e&&(e===t.default?delete d[t.key]:d[t.key]=e)}const u=Object.keys(d).length>0?{type:r,options:d}:{type:r};try{f(t,i,()=>{JSON.stringify(u)!==JSON.stringify(c)&&a.setSeriesTransform(l,u),Object.keys(s).length>0&&n(a,s)})}catch(e){return e instanceof Error?e.message:String(e)}return null}(m,A,E,T,O);null===r?D():N.refuse(r)}N.attach(I),J.actions.append(u(v,{label:i(m,"Cancel"),onClick:D}),u(v,{label:i(m,"OK"),variant:"primary",onClick:G})),I.addEventListener("keydown",e=>{"Enter"===e.key&&e.target.classList.contains("oac-input--num")&&G()});const Q=y.on("destroy",D);return W(),H=p(m,J.el,{anchor:b,modal:!0,placement:"center"},D),{el:J.el,close:D,isOpen:()=>!q&&H.isOpen()}}export{z as openChartTypeSettings}; //# sourceMappingURL=openalgo-charts.widget.chart-type-settings-Bu7g-LFB.mjs.map