diff --git a/resources/dashboard.js b/resources/dashboard.js
index aa987867..4d2ad475 100644
--- a/resources/dashboard.js
+++ b/resources/dashboard.js
@@ -1,3 +1,5 @@
+// SPDX-FileCopyrightText: 2026 Cesanta Software Limited
+// SPDX-License-Identifier: GPL-2.0-only or commercial
(function (global) {
"use strict";
diff --git a/tutorials/device-dashboard b/tutorials/device-dashboard
deleted file mode 120000
index dc77ff52..00000000
--- a/tutorials/device-dashboard
+++ /dev/null
@@ -1 +0,0 @@
-http/device-dashboard
\ No newline at end of file
diff --git a/tutorials/device-dashboard/full-dashboard/Makefile b/tutorials/device-dashboard/full-dashboard/Makefile
new file mode 100644
index 00000000..94495976
--- /dev/null
+++ b/tutorials/device-dashboard/full-dashboard/Makefile
@@ -0,0 +1,32 @@
+# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/
+
+PROG ?= server
+MGDIR ?= ../../..
+SOURCES = server.c dashboard.html.c $(MGDIR)/mongoose.c
+CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -g3 -O0
+PFLAGS = -I$(MGDIR) -DMG_DATA_SIZE=64 -DMG_TLS=MG_TLS_BUILTIN
+AFLAGS ?= -fsanitize=signed-integer-overflow,address,undefined,alignment
+
+all: $(PROG)
+ ./$(PROG)
+
+# Rebuild the program
+$(PROG): $(SOURCES)
+ $(CC) $(SOURCES) $(CFLAGS) $(PFLAGS) $(AFLAGS) -o $@
+
+# Generate a single, self-contained dashboard.html from the UI in web_root/
+dashboard.html: $(wildcard web_root/*)
+ curl https://purge.jsdelivr.net/gh/cesanta/mongoose@master/resources/dashboard.js -s -o /dev/null
+ monolith web_root/index.html > $@
+
+# Create an embedded filesystem containing compressed dashboard.html
+dashboard.html.c: dashboard.html
+ node $(MGDIR)/resources/pack.js dashboard.html::gzip > $@
+ @echo "On-flash size: `grep -oE '[0-9]+' $@ | wc -l`"
+
+# For development: rebuild and restart if any of the sources change
+run: $(SOURCES)
+ watchexec -r -w server.c -w web_root -w ../../glue -e c,h,html,css,js -- make
+
+clean:
+ rm -rf $(PROG) *.exe *.obj *.dSYM mongoose dashboard.*
diff --git a/tutorials/device-dashboard/full-dashboard/server.c b/tutorials/device-dashboard/full-dashboard/server.c
new file mode 100644
index 00000000..d0f23c0f
--- /dev/null
+++ b/tutorials/device-dashboard/full-dashboard/server.c
@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText: 2026 Cesanta Software Limited
+// SPDX-License-Identifier: GPL-2.0-only or commercial
+
+#include "mongoose.h"
+
+#if MG_ARCH == MG_ARCH_UNIX || MG_ARCH == MG_ARCH_WIN32
+#define HTTP_ADDR "http://0.0.0.0:8000"
+#else
+#define HTTP_ADDR "http://0.0.0.0:80"
+#endif
+
+static bool s_led;
+
+static void get_led(union mg_val *val) {
+ val->b = s_led;
+}
+
+static void set_led(const union mg_val *val) {
+ s_led = val->b;
+}
+
+// Modify this. This represents device's state to the dashboard
+static struct mg_field fields[] = {
+ {"led", MG_VAL_BOOL, get_led, set_led},
+ {NULL, 0, 0, 0},
+};
+
+void run_mongoose(void) {
+ struct mg_mgr mgr;
+ struct mg_dash dash = {fields};
+ mg_mgr_init(&mgr);
+ mg_http_listen(&mgr, HTTP_ADDR, mg_dash_ev_handler, &dash);
+ for (;;) {
+ mg_mgr_poll(&mgr, 10);
+ }
+}
+
+int main(void) {
+ run_mongoose();
+ return 0;
+}
diff --git a/tutorials/device-dashboard/full-dashboard/web_root/index.html b/tutorials/device-dashboard/full-dashboard/web_root/index.html
new file mode 100644
index 00000000..18ececa5
--- /dev/null
+++ b/tutorials/device-dashboard/full-dashboard/web_root/index.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+ Graph example
+
+
+
+
+
+
In server.c, we generate "change" notifications periodically,
+ reporting 512 data points:
+ {"method":"change","params":{"points":[[0,83],[1,99],...
+
+
In main.js, we create a uPlot chart instance bound to the div
+ inside the panel
+
In main.js, we call Dashboard.on('change', function() {...}) to intercept all change notifications, get the points, and then calling chart.setData() to plot received values.
+
+
+
+
diff --git a/tutorials/device-dashboard/realtime-graph/web_root/main.js b/tutorials/device-dashboard/realtime-graph/web_root/main.js
new file mode 100644
index 00000000..166cc4db
--- /dev/null
+++ b/tutorials/device-dashboard/realtime-graph/web_root/main.js
@@ -0,0 +1,36 @@
+document.addEventListener("DOMContentLoaded", function() {
+
+ const el = document.getElementById("graph");
+ const rect = el.getBoundingClientRect();
+
+ const options = {
+ width: rect.width,
+ height: rect.height,
+ tzDate: (ts) => uPlot.tzDate(new Date(ts * 1e3), "Europe/London"),
+ plugins: [],
+ legend: { show: false },
+ axes: [
+ { values: "{MMM} {DD}", size: 25 },
+ { size: 50, xvalues: (u, vals, space) => vals.map(v => (+v / 1000).toFixed(1) + 'k') },
+ ],
+ series: [
+ {},
+ {stroke: 'rgba(5, 141, 199, 1)', fill: 'rgba(5, 141, 199, 0.1)'},
+ {stroke: 'rgba(237, 126, 23, 1)', fill: 'rgba(237, 126, 23, 0.1)'},
+ ],
+ };
+
+ // Create chart instance
+ const chart = new uPlot(options, [], el);
+
+ // Intercept change notifications
+ Dashboard.on('change', function(args) {
+ const data = [
+ args.points.map(x => x[0]),
+ args.points.map(x => x[1]),
+ args.points.map(x => x[2]),
+ ];
+ //console.log(123, args.points);
+ chart.setData(data);
+ });
+});
diff --git a/tutorials/device-dashboard/realtime-graph/web_root/style.css b/tutorials/device-dashboard/realtime-graph/web_root/style.css
new file mode 100644
index 00000000..58969b4d
--- /dev/null
+++ b/tutorials/device-dashboard/realtime-graph/web_root/style.css
@@ -0,0 +1,108 @@
+:root {
+ --btn-color: white;
+ --btn-disabled-color: #d1d5db;
+ --bg-color: '#d8dcdf';
+}
+
+*, *::before, *::after {
+ box-sizing: border-box; margin: 0; padding: 0;
+ font-family: Arial, sans-serif;
+}
+
+body { background: #0004;}
+h1 {font-size: 1.25rem;}
+
+.main {
+ margin: 2rem auto; width: 640px; padding: 1em 2em;
+ border-radius:0.3rem; background: #fff5;
+}
+
+.panel {
+ display: flex; flex-direction: column; gap: 0.5rem;
+ background: #fffe;
+ border: 1px solid #0002;
+ border-radius: 0.3rem;
+ overflow: hidden;
+ padding: 0.5rem 0.75rem;
+ font-size: 0.875rem;
+}
+.panel-title {
+ margin: -0.5rem -0.75rem 0 -0.75rem;
+ padding: 0.5rem 0.75rem 0.3rem 0.75rem;
+ border-bottom: 1px solid #0003;
+ border-radius: 0.25rem 0.25rem 0 0;
+ background: #0001;
+ font-weight: 600;
+ color: #000c;
+}
+
+.input, .dropdown {
+ display:inline-flex;
+ border-radius: 5px;
+ background: #fff;
+ color: #475569;
+ border: 1px solid #ccc;
+ border-width: 1px;
+ outline: none;
+ box-sizing: border-box;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ margin:0;
+ font-size: 14px;
+ font-weight: normal;
+ transition: all .2s ease;
+}
+
+.button {
+ padding: 0.25rem 1rem;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ background: #2563eb;
+ color: var(--btn-color);
+ font-weight: 600;
+ cursor: pointer;
+ position: relative;
+ transition: all .2s ease;
+}
+
+.button:hover {
+ background: #3b82f6;
+}
+
+.button.loading {
+ color: transparent;
+ text-shadow: none;
+}
+
+.button:disabled,.button:hover:disabled,.button.disabled,.button:hover.disabled {
+ background: var(--btn-disabled-color) !important;
+ border-color: var(--btn-disabled-color);
+ cursor: not-allowed;
+}
+
+.input {
+ padding: 0.25rem 0.5rem;
+}
+
+.panel-row {
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+ gap: 0.5rem;
+}
+
+.input:disabled,.select:disabled,.input.disabled,.select.disabled,.slider.disabled {
+ background: var(--bg-color) !important;
+ cursor: not-allowed;
+}
+
+.input.edited, .select.edited, .slider.edited>* {
+ border-color: #50500040;
+ background: #ffff0020;
+}
+
+.input.error, .select.error, .slider.error>* {
+ border-color: #50000040;
+ background: #ff000020;
+}
diff --git a/tutorials/device-dashboard/realtime-graph/web_root/uPlot.iife.min.js b/tutorials/device-dashboard/realtime-graph/web_root/uPlot.iife.min.js
new file mode 100644
index 00000000..047f29b6
--- /dev/null
+++ b/tutorials/device-dashboard/realtime-graph/web_root/uPlot.iife.min.js
@@ -0,0 +1,2 @@
+/*! https://github.com/leeoniya/uPlot (v1.6.32) */
+var uPlot=function(){"use strict";const l="u-off",e="u-label",t="width",n="height",i="top",o="bottom",s="left",r="right",u="#000",a=u+"0",f="mousemove",c="mousedown",h="mouseup",d="mouseenter",p="mouseleave",m="dblclick",g="change",x="dppxchange",w="--",_="undefined"!=typeof window,b=_?document:null,v=_?window:null,k=_?navigator:null;let y,M;function S(l,e){if(null!=e){let t=l.classList;!t.contains(e)&&t.add(e)}}function T(l,e){let t=l.classList;t.contains(e)&&t.remove(e)}function E(l,e,t){l.style[e]=t+"px"}function z(l,e,t,n){let i=b.createElement(l);return null!=e&&S(i,e),null!=t&&t.insertBefore(i,n),i}function D(l,e){return z("div",l,e)}const P=new WeakMap;function A(e,t,n,i,o){let s="translate("+t+"px,"+n+"px)";s!=P.get(e)&&(e.style.transform=s,P.set(e,s),0>t||0>n||t>i||n>o?S(e,l):T(e,l))}const W=new WeakMap;function Y(l,e,t){let n=e+t;n!=W.get(l)&&(W.set(l,n),l.style.background=e,l.style.borderColor=t)}const C=new WeakMap;function H(l,e,t,n){let i=e+""+t;i!=C.get(l)&&(C.set(l,i),l.style.height=t+"px",l.style.width=e+"px",l.style.marginLeft=n?-e/2+"px":0,l.style.marginTop=n?-t/2+"px":0)}const F={passive:!0},R={...F,capture:!0};function G(l,e,t,n){e.addEventListener(l,t,n?R:F)}function I(l,e,t){e.removeEventListener(l,t,F)}function L(l,e,t,n){let i;t=t||0;let o=2147483647>=(n=n||e.length-1);for(;n-t>1;)i=o?t+n>>1:sl((t+n)/2),l>e[i]?t=i:n=i;return l-e[t]>e[n]-l?n:t}function O(l){return(e,t,n)=>{let i=-1,o=-1;for(let o=t;n>=o;o++)if(l(e[o])){i=o;break}for(let i=n;i>=t;i--)if(l(e[i])){o=i;break}return[i,o]}}_&&function l(){let e=devicePixelRatio;y!=e&&(y=e,M&&I(g,M,l),M=matchMedia(`(min-resolution: ${y-.001}dppx) and (max-resolution: ${y+.001}dppx)`),G(g,M,l),v.dispatchEvent(new CustomEvent(x)))}();const N=l=>null!=l,j=l=>null!=l&&l>0,U=O(N),V=O(j);function B(l,e,t,n){let i=hl(l),o=hl(e);l==e&&(-1==i?(l*=t,e/=t):(l/=t,e*=t));let s=10==t?dl:pl,r=1==o?ul:sl,u=(1==i?sl:ul)(s(ol(l))),a=r(s(ol(e))),f=cl(t,u),c=cl(t,a);return 10==t&&(0>u&&(f=Al(f,-u)),0>a&&(c=Al(c,-a))),n||2==t?(l=f*i,e=c*o):(l=Pl(l,f),e=Dl(e,c)),[l,e]}function $(l,e,t,n){let i=B(l,e,t,n);return 0==l&&(i[0]=0),0==e&&(i[1]=0),i}const J=.1,q={mode:3,pad:J},K={pad:0,soft:null,mode:0},X={min:K,max:K};function Z(l,e,t,n){return Ol(t)?ll(l,e,t):(K.pad=t,K.soft=n?0:null,K.mode=n?3:0,ll(l,e,X))}function Q(l,e){return null==l?e:l}function ll(l,e,t){let n=t.min,i=t.max,o=Q(n.pad,0),s=Q(i.pad,0),r=Q(n.hard,-gl),u=Q(i.hard,gl),a=Q(n.soft,gl),f=Q(i.soft,-gl),c=Q(n.mode,0),h=Q(i.mode,0),d=e-l,p=dl(d),m=fl(ol(l),ol(e)),g=dl(m),x=ol(g-p);(1e-24>d||x>10)&&(d=0,0!=l&&0!=e||(d=1e-24,2==c&&a!=gl&&(o=0),2==h&&f!=-gl&&(s=0)));let w=d||m||1e3,_=dl(w),b=cl(10,sl(_)),v=Al(Pl(l-w*(0==d?0==l?.1:1:o),b/10),24),k=a>l||1!=c&&(3!=c||v>a)&&(2!=c||a>v)?gl:a,y=fl(r,k>v&&l>=k?k:al(k,v)),M=Al(Dl(e+w*(0==d?0==e?.1:1:s),b/10),24),S=e>f||1!=h&&(3!=h||f>M)&&(2!=h||M>f)?-gl:f,T=al(u,M>S&&S>=e?S:fl(S,M));return y==T&&0==y&&(T=100),[y,T]}const el=new Intl.NumberFormat(_?k.language:"en-US"),tl=l=>el.format(l),nl=Math,il=nl.PI,ol=nl.abs,sl=nl.floor,rl=nl.round,ul=nl.ceil,al=nl.min,fl=nl.max,cl=nl.pow,hl=nl.sign,dl=nl.log10,pl=nl.log2,ml=(l,e=1)=>nl.asinh(l/e),gl=1/0;function xl(l){return 1+(0|dl((l^l>>31)-(l>>31)))}function wl(l,e,t){return al(fl(l,e),t)}function _l(l){return"function"==typeof l}function bl(l){return _l(l)?l:()=>l}const vl=l=>l,kl=(l,e)=>e,yl=()=>null,Ml=()=>!0,Sl=(l,e)=>l==e,Tl=/\.\d*?(?=9{6,}|0{6,})/gm,El=l=>{if(Il(l)||Wl.has(l))return l;const e=""+l,t=e.match(Tl);if(null==t)return l;let n=t[0].length-1;if(-1!=e.indexOf("e-")){let[l,t]=e.split("e");return+`${El(l)}e${t}`}return Al(l,n)};function zl(l,e){return El(Al(El(l/e))*e)}function Dl(l,e){return El(ul(El(l/e))*e)}function Pl(l,e){return El(sl(El(l/e))*e)}function Al(l,e=0){if(Il(l))return l;let t=10**e;return rl(l*t*(1+Number.EPSILON))/t}const Wl=new Map;function Yl(l){return((""+l).split(".")[1]||"").length}function Cl(l,e,t,n){let i=[],o=n.map(Yl);for(let s=e;t>s;s++){let e=ol(s),t=Al(cl(l,s),e);for(let r=0;n.length>r;r++){let u=10==l?+`${n[r]}e${s}`:n[r]*t,a=(0>s?e:0)+(o[r]>s?o[r]:0),f=10==l?u:Al(u,a);i.push(f),Wl.set(f,a)}}return i}const Hl={},Fl=[],Rl=[null,null],Gl=Array.isArray,Il=Number.isInteger;function Ll(l){return"string"==typeof l}function Ol(l){let e=!1;if(null!=l){let t=l.constructor;e=null==t||t==Object}return e}function Nl(l){return null!=l&&"object"==typeof l}const jl=Object.getPrototypeOf(Uint8Array),Ul="__proto__";function Vl(l,e=Ol){let t;if(Gl(l)){let n=l.find((l=>null!=l));if(Gl(n)||e(n)){t=Array(l.length);for(let n=0;l.length>n;n++)t[n]=Vl(l[n],e)}else t=l.slice()}else if(l instanceof jl)t=l.slice();else if(e(l)){t={};for(let n in l)n!=Ul&&(t[n]=Vl(l[n],e))}else t=l;return t}function Bl(l){let e=arguments;for(let t=1;e.length>t;t++){let n=e[t];for(let e in n)e!=Ul&&(Ol(l[e])?Bl(l[e],Vl(n[e])):l[e]=Vl(n[e]))}return l}function $l(l,e,t){for(let n,i=0,o=-1;e.length>i;i++){let s=e[i];if(s>o){for(n=s-1;n>=0&&null==l[n];)l[n--]=null;for(n=s+1;t>n&&null==l[n];)l[o=n++]=null}}}const Jl="undefined"==typeof queueMicrotask?l=>Promise.resolve().then(l):queueMicrotask,ql=["January","February","March","April","May","June","July","August","September","October","November","December"],Kl=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];function Xl(l){return l.slice(0,3)}const Zl=Kl.map(Xl),Ql=ql.map(Xl),le={MMMM:ql,MMM:Ql,WWWW:Kl,WWW:Zl};function ee(l){return(10>l?"0":"")+l}const te={YYYY:l=>l.getFullYear(),YY:l=>(l.getFullYear()+"").slice(2),MMMM:(l,e)=>e.MMMM[l.getMonth()],MMM:(l,e)=>e.MMM[l.getMonth()],MM:l=>ee(l.getMonth()+1),M:l=>l.getMonth()+1,DD:l=>ee(l.getDate()),D:l=>l.getDate(),WWWW:(l,e)=>e.WWWW[l.getDay()],WWW:(l,e)=>e.WWW[l.getDay()],HH:l=>ee(l.getHours()),H:l=>l.getHours(),h:l=>{let e=l.getHours();return 0==e?12:e>12?e-12:e},AA:l=>12>l.getHours()?"AM":"PM",aa:l=>12>l.getHours()?"am":"pm",a:l=>12>l.getHours()?"a":"p",mm:l=>ee(l.getMinutes()),m:l=>l.getMinutes(),ss:l=>ee(l.getSeconds()),s:l=>l.getSeconds(),fff:l=>function(l){return(10>l?"00":100>l?"0":"")+l}(l.getMilliseconds())};function ne(l,e){e=e||le;let t,n=[],i=/\{([a-z]+)\}|[^{]+/gi;for(;t=i.exec(l);)n.push("{"==t[0][0]?te[t[1]]:t[0]);return l=>{let t="";for(let i=0;n.length>i;i++)t+="string"==typeof n[i]?n[i]:n[i](l,e);return t}}const ie=(new Intl.DateTimeFormat).resolvedOptions().timeZone,oe=l=>l%1==0,se=[1,2,2.5,5],re=Cl(10,-32,0,se),ue=Cl(10,0,32,se),ae=ue.filter(oe),fe=re.concat(ue),ce="{YYYY}",he="\n"+ce,de="{M}/{D}",pe="\n"+de,me=pe+"/{YY}",ge="{aa}",xe="{h}:{mm}"+ge,we="\n"+xe,_e=":{ss}",be=null;function ve(l){let e=1e3*l,t=60*e,n=60*t,i=24*n,o=30*i,s=365*i;return[(1==l?Cl(10,0,3,se).filter(oe):Cl(10,-3,0,se)).concat([e,5*e,10*e,15*e,30*e,t,5*t,10*t,15*t,30*t,n,2*n,3*n,4*n,6*n,8*n,12*n,i,2*i,3*i,4*i,5*i,6*i,7*i,8*i,9*i,10*i,15*i,o,2*o,3*o,4*o,6*o,s,2*s,5*s,10*s,25*s,50*s,100*s]),[[s,ce,be,be,be,be,be,be,1],[28*i,"{MMM}",he,be,be,be,be,be,1],[i,de,he,be,be,be,be,be,1],[n,"{h}"+ge,me,be,pe,be,be,be,1],[t,xe,me,be,pe,be,be,be,1],[e,_e,me+" "+xe,be,pe+" "+xe,be,we,be,1],[l,_e+".{fff}",me+" "+xe,be,pe+" "+xe,be,we,be,1]],function(e){return(r,u,a,f,c,h)=>{let d=[],p=c>=s,m=c>=o&&s>c,g=e(a),x=Al(g*l,3),w=Pe(g.getFullYear(),p?0:g.getMonth(),m||p?1:g.getDate()),_=Al(w*l,3);if(m||p){let t=m?c/o:0,n=p?c/s:0,i=x==_?x:Al(Pe(w.getFullYear()+n,w.getMonth()+t,1)*l,3),r=new Date(rl(i/l)),u=r.getFullYear(),a=r.getMonth();for(let o=0;f>=i;o++){let s=Pe(u+n*o,a+t*o,1),r=s-e(Al(s*l,3));i=Al((+s+r)*l,3),i>f||d.push(i)}}else{let o=i>c?c:i,s=_+(sl(a)-sl(x))+Dl(x-_,o);d.push(s);let p=e(s),m=p.getHours()+p.getMinutes()/t+p.getSeconds()/n,g=c/n,w=h/r.axes[u]._space;for(;s=Al(s+c,1==l?0:3),f>=s;)if(g>1){let l=sl(Al(m+g,6))%24,t=e(s).getHours()-l;t>1&&(t=-1),s-=t*n,m=(m+g)%24,.7>Al((s-d[d.length-1])/c,3)*w||d.push(s)}else d.push(s)}return d}}]}const[ke,ye,Me]=ve(1),[Se,Te,Ee]=ve(.001);function ze(l,e){return l.map((l=>l.map(((t,n)=>0==n||8==n||null==t?t:e(1==n||0==l[8]?t:l[1]+t)))))}function De(l,e){return(t,n,i,o,s)=>{let r,u,a,f,c,h,d=e.find((l=>s>=l[0]))||e[e.length-1];return n.map((e=>{let t=l(e),n=t.getFullYear(),i=t.getMonth(),o=t.getDate(),s=t.getHours(),p=t.getMinutes(),m=t.getSeconds(),g=n!=r&&d[2]||i!=u&&d[3]||o!=a&&d[4]||s!=f&&d[5]||p!=c&&d[6]||m!=h&&d[7]||d[1];return r=n,u=i,a=o,f=s,c=p,h=m,g(t)}))}}function Pe(l,e,t){return new Date(l,e,t)}function Ae(l,e){return e(l)}function We(l,e){return(t,n,i,o)=>null==o?w:e(l(n))}Cl(2,-53,53,[1]);const Ye={show:!0,live:!0,isolate:!1,mount:()=>{},markers:{show:!0,width:2,stroke:function(l,e){let t=l.series[e];return t.width?t.stroke(l,e):t.points.width?t.points.stroke(l,e):null},fill:function(l,e){return l.series[e].fill(l,e)},dash:"solid"},idx:null,idxs:null,values:[]},Ce=[0,0];function He(l,e,t,n=!0){return l=>{0==l.button&&(!n||l.target==e)&&t(l)}}function Fe(l,e,t,n=!0){return l=>{(!n||l.target==e)&&t(l)}}const Re={show:!0,x:!0,y:!0,lock:!1,move:function(l,e,t){return Ce[0]=e,Ce[1]=t,Ce},points:{one:!1,show:function(l,e){let i=l.cursor.points,o=D(),s=i.size(l,e);E(o,t,s),E(o,n,s);let r=s/-2;E(o,"marginLeft",r),E(o,"marginTop",r);let u=i.width(l,e,s);return u&&E(o,"borderWidth",u),o},size:function(l,e){return l.series[e].points.size},width:0,stroke:function(l,e){let t=l.series[e].points;return t._stroke||t._fill},fill:function(l,e){let t=l.series[e].points;return t._fill||t._stroke}},bind:{mousedown:He,mouseup:He,click:He,dblclick:He,mousemove:Fe,mouseleave:Fe,mouseenter:Fe},drag:{setScale:!0,x:!0,y:!1,dist:0,uni:null,click:(l,e)=>{e.stopPropagation(),e.stopImmediatePropagation()},_x:!1,_y:!1},focus:{dist:(l,e,t,n,i)=>n-i,prox:-1,bias:0},hover:{skip:[void 0],prox:null,bias:0},left:-10,top:-10,idx:null,dataIdx:null,idxs:null,event:null},Ge={show:!0,stroke:"rgba(0,0,0,0.07)",width:2},Ie=Bl({},Ge,{filter:kl}),Le=Bl({},Ie,{size:10}),Oe=Bl({},Ge,{show:!1}),Ne='12px system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',je="bold "+Ne,Ue={show:!0,scale:"x",stroke:u,space:50,gap:5,alignTo:1,size:50,labelGap:0,labelSize:30,labelFont:je,side:2,grid:Ie,ticks:Le,border:Oe,font:Ne,lineGap:1.5,rotate:0},Ve={show:!0,scale:"x",auto:!1,sorted:1,min:gl,max:-gl,idxs:[]};function Be(l,e){return e.map((l=>null==l?"":tl(l)))}function $e(l,e,t,n,i,o,s){let r=[],u=Wl.get(i)||0;for(let l=t=s?t:Al(Dl(t,i),u);n>=l;l=Al(l+i,u))r.push(Object.is(l,-0)?0:l);return r}function Je(l,e,t,n,i){const o=[],s=l.scales[l.axes[e].scale].log,r=sl((10==s?dl:pl)(t));i=cl(s,r),10==s&&(i=fe[L(i,fe)]);let u=t,a=i*s;10==s&&(a=fe[L(a,fe)]);do{o.push(u),u+=i,10!=s||Wl.has(u)||(u=Al(u,Wl.get(i))),a>u||(a=(i=u)*s,10==s&&(a=fe[L(a,fe)]))}while(n>=u);return o}function qe(l,e,t,n,i){let o=l.scales[l.axes[e].scale].asinh,s=n>o?Je(l,e,fl(o,t),n,i):[o],r=0>n||t>0?[]:[0];return(-o>t?Je(l,e,fl(o,-n),-t,i):[o]).reverse().map((l=>-l)).concat(r,s)}const Ke=/./,Xe=/[12357]/,Ze=/[125]/,Qe=/1/,lt=(l,e,t,n)=>l.map(((l,i)=>4==e&&0==l||i%n==0&&t.test(l.toExponential()[0>l?1:0])?l:null));function et(l,e,t){let n=l.axes[t],i=n.scale,o=l.scales[i],s=l.valToPos,r=n._space,u=s(10,i),a=s(9,i)-u