@toclocoinc/lattice-grid 1.67.0 → 1.68.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/README.md +1 -1
- package/angular/package.json +1 -1
- package/docs/API.html +21 -16
- package/docs/api-detail.html +40 -5
- package/lattice-grid.d.ts +12 -2
- package/lattice-grid.esm.min.js +27 -7
- package/lattice-grid.min.cjs +27 -7
- package/lattice-grid.min.js +27 -7
- package/modules/ai.d.ts +1 -1
- package/modules/ai.esm.min.js +3 -3
- package/modules/ai.min.cjs +3 -3
- package/modules/ai.min.js +3 -3
- package/modules/angular.d.ts +1 -1
- package/modules/angular.esm.min.js +3 -3
- package/modules/angular.min.cjs +3 -3
- package/modules/angular.min.js +3 -3
- package/modules/chart-alluvial.d.ts +1 -1
- package/modules/chart-alluvial.esm.min.js +1 -1
- package/modules/chart-alluvial.min.cjs +1 -1
- package/modules/chart-alluvial.min.js +1 -1
- package/modules/chart-arc.d.ts +1 -1
- package/modules/chart-arc.esm.min.js +1 -1
- package/modules/chart-arc.min.cjs +1 -1
- package/modules/chart-arc.min.js +1 -1
- package/modules/chart-bubblemap.d.ts +1 -1
- package/modules/chart-bubblemap.esm.min.js +1 -1
- package/modules/chart-bubblemap.min.cjs +1 -1
- package/modules/chart-bubblemap.min.js +1 -1
- package/modules/chart-bump.d.ts +1 -1
- package/modules/chart-bump.esm.min.js +1 -1
- package/modules/chart-bump.min.cjs +1 -1
- package/modules/chart-bump.min.js +1 -1
- package/modules/chart-calendar.d.ts +1 -1
- package/modules/chart-calendar.esm.min.js +1 -1
- package/modules/chart-calendar.min.cjs +1 -1
- package/modules/chart-calendar.min.js +1 -1
- package/modules/chart-decomposition.d.ts +1 -1
- package/modules/chart-decomposition.esm.min.js +1 -1
- package/modules/chart-decomposition.min.cjs +1 -1
- package/modules/chart-decomposition.min.js +1 -1
- package/modules/chart-diverging.d.ts +1 -1
- package/modules/chart-diverging.esm.min.js +1 -1
- package/modules/chart-diverging.min.cjs +1 -1
- package/modules/chart-diverging.min.js +1 -1
- package/modules/chart-dumbbell.d.ts +1 -1
- package/modules/chart-dumbbell.esm.min.js +1 -1
- package/modules/chart-dumbbell.min.cjs +1 -1
- package/modules/chart-dumbbell.min.js +1 -1
- package/modules/chart-fan.d.ts +1 -1
- package/modules/chart-fan.esm.min.js +1 -1
- package/modules/chart-fan.min.cjs +1 -1
- package/modules/chart-fan.min.js +1 -1
- package/modules/chart-hexbin.d.ts +1 -1
- package/modules/chart-hexbin.esm.min.js +1 -1
- package/modules/chart-hexbin.min.cjs +1 -1
- package/modules/chart-hexbin.min.js +1 -1
- package/modules/chart-hexmap.d.ts +1 -1
- package/modules/chart-hexmap.esm.min.js +1 -1
- package/modules/chart-hexmap.min.cjs +1 -1
- package/modules/chart-hexmap.min.js +1 -1
- package/modules/chart-icicle.d.ts +1 -1
- package/modules/chart-icicle.esm.min.js +1 -1
- package/modules/chart-icicle.min.cjs +1 -1
- package/modules/chart-icicle.min.js +1 -1
- package/modules/chart-markermap.d.ts +1 -1
- package/modules/chart-markermap.esm.min.js +1 -1
- package/modules/chart-markermap.min.cjs +1 -1
- package/modules/chart-markermap.min.js +1 -1
- package/modules/chart-parallel.d.ts +1 -1
- package/modules/chart-parallel.esm.min.js +1 -1
- package/modules/chart-parallel.min.cjs +1 -1
- package/modules/chart-parallel.min.js +1 -1
- package/modules/chart-ridgeline.d.ts +1 -1
- package/modules/chart-ridgeline.esm.min.js +1 -1
- package/modules/chart-ridgeline.min.cjs +1 -1
- package/modules/chart-ridgeline.min.js +1 -1
- package/modules/chart-roc.d.ts +1 -1
- package/modules/chart-roc.esm.min.js +1 -1
- package/modules/chart-roc.min.cjs +1 -1
- package/modules/chart-roc.min.js +1 -1
- package/modules/chart-slope.d.ts +1 -1
- package/modules/chart-slope.esm.min.js +1 -1
- package/modules/chart-slope.min.cjs +1 -1
- package/modules/chart-slope.min.js +1 -1
- package/modules/chart-splom.d.ts +1 -1
- package/modules/chart-splom.esm.min.js +1 -1
- package/modules/chart-splom.min.cjs +1 -1
- package/modules/chart-splom.min.js +1 -1
- package/modules/chart-waffle.d.ts +1 -1
- package/modules/chart-waffle.esm.min.js +1 -1
- package/modules/chart-waffle.min.cjs +1 -1
- package/modules/chart-waffle.min.js +1 -1
- package/modules/charts.d.ts +1 -1
- package/modules/charts.esm.min.js +1376 -1249
- package/modules/charts.min.cjs +1376 -1249
- package/modules/charts.min.js +1376 -1249
- package/modules/data-router.d.ts +1 -1
- package/modules/data-router.esm.min.js +204 -8
- package/modules/data-router.min.cjs +204 -8
- package/modules/data-router.min.js +204 -8
- package/modules/devtools.d.ts +1 -1
- package/modules/devtools.esm.min.js +1 -1
- package/modules/devtools.min.cjs +1 -1
- package/modules/devtools.min.js +1 -1
- package/modules/dhtmlx-compat.d.ts +1 -1
- package/modules/dhtmlx-compat.esm.min.js +3 -3
- package/modules/dhtmlx-compat.min.cjs +3 -3
- package/modules/dhtmlx-compat.min.js +3 -3
- package/modules/gantt.d.ts +1 -1
- package/modules/gantt.esm.min.js +32 -7
- package/modules/gantt.min.cjs +32 -7
- package/modules/gantt.min.js +32 -7
- package/modules/geo-europe-nuts.d.ts +1 -1
- package/modules/geo-europe-nuts.esm.min.js +1 -1
- package/modules/geo-uk.d.ts +1 -1
- package/modules/geo-uk.esm.min.js +1 -1
- package/modules/geo-us-states.d.ts +1 -1
- package/modules/geo-us-states.esm.min.js +1 -1
- package/modules/geo-world-110m.d.ts +1 -1
- package/modules/geo-world-110m.esm.min.js +1 -1
- package/modules/geo-world-50m.d.ts +1 -1
- package/modules/geo-world-50m.esm.min.js +1 -1
- package/modules/htmx.d.ts +1 -1
- package/modules/htmx.esm.min.js +27 -7
- package/modules/htmx.min.cjs +27 -7
- package/modules/htmx.min.js +27 -7
- package/modules/kanban.d.ts +1 -1
- package/modules/kanban.esm.min.js +3 -3
- package/modules/kanban.min.cjs +3 -3
- package/modules/kanban.min.js +3 -3
- package/modules/kpi.d.ts +26 -8
- package/modules/kpi.esm.min.js +31 -6
- package/modules/kpi.min.cjs +31 -6
- package/modules/kpi.min.js +31 -6
- package/modules/layout.d.ts +1 -1
- package/modules/layout.esm.min.js +3 -3
- package/modules/layout.min.cjs +3 -3
- package/modules/layout.min.js +3 -3
- package/modules/mock-socket.d.ts +1 -1
- package/modules/mock-socket.esm.min.js +1 -1
- package/modules/mock-socket.min.cjs +1 -1
- package/modules/mock-socket.min.js +1 -1
- package/modules/react.d.ts +1 -1
- package/modules/react.esm.min.js +3 -3
- package/modules/react.min.cjs +3 -3
- package/modules/react.min.js +3 -3
- package/modules/svelte.d.ts +1 -1
- package/modules/svelte.esm.min.js +3 -3
- package/modules/svelte.min.cjs +3 -3
- package/modules/svelte.min.js +3 -3
- package/modules/tabs.d.ts +1 -1
- package/modules/tabs.esm.min.js +13 -14
- package/modules/tabs.min.cjs +13 -14
- package/modules/tabs.min.js +13 -14
- package/modules/vue.d.ts +1 -1
- package/modules/vue.esm.min.js +3 -3
- package/modules/vue.min.cjs +3 -3
- package/modules/vue.min.js +3 -3
- package/modules/webcomponent.d.ts +1 -1
- package/modules/webcomponent.esm.min.js +27 -7
- package/modules/webcomponent.min.cjs +27 -7
- package/modules/webcomponent.min.js +27 -7
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.68.0, charts module
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -996,6 +996,8 @@ const STEPS=[1,2,2.5,5,10];
|
|
|
996
996
|
const MINUTE=60000;
|
|
997
997
|
const HOUR=3600000;
|
|
998
998
|
const DAY=86400000;
|
|
999
|
+
const YEAR=365.25*DAY;
|
|
1000
|
+
const YEAR_COUNTS=[1,2,5,10,20,25,50,100];
|
|
999
1001
|
const TIME_STEPS=[
|
|
1000
1002
|
1,5,10,25,50,100,250,500,
|
|
1001
1003
|
1000,5000,15000,30000,
|
|
@@ -1003,7 +1005,7 @@ MINUTE,5*MINUTE,15*MINUTE,30*MINUTE,
|
|
|
1003
1005
|
HOUR,3*HOUR,6*HOUR,12*HOUR,
|
|
1004
1006
|
DAY,2*DAY,7*DAY,14*DAY,
|
|
1005
1007
|
30*DAY,90*DAY,180*DAY,
|
|
1006
|
-
|
|
1008
|
+
...YEAR_COUNTS.map((years)=>years*YEAR),
|
|
1007
1009
|
];
|
|
1008
1010
|
function isNumber(v){
|
|
1009
1011
|
return typeof v==='number'&&Number.isFinite(v);
|
|
@@ -1089,12 +1091,35 @@ out.push(Math.abs(v)<step/1e6?0:Number(v.toPrecision(12)));
|
|
|
1089
1091
|
return out;
|
|
1090
1092
|
}
|
|
1091
1093
|
function timeStepFor(span,count=5){
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1094
|
+
const wanted=Math.max(1,count);
|
|
1095
|
+
const target=span/wanted;
|
|
1096
|
+
let picked=TIME_STEPS[TIME_STEPS.length-1];
|
|
1097
|
+
for(const candidate of TIME_STEPS){
|
|
1098
|
+
if(candidate>=target){picked=candidate;break;}
|
|
1099
|
+
}
|
|
1100
|
+
if(picked<YEAR)return picked;
|
|
1101
|
+
let best=picked;
|
|
1102
|
+
let bestDiff=Math.abs(span/picked-wanted);
|
|
1103
|
+
for(const candidate of TIME_STEPS){
|
|
1104
|
+
if(candidate<YEAR)continue;
|
|
1105
|
+
const diff=Math.abs(span/candidate-wanted);
|
|
1106
|
+
if(diff<bestDiff){bestDiff=diff;best=candidate;}
|
|
1107
|
+
}
|
|
1108
|
+
return best;
|
|
1109
|
+
}
|
|
1110
|
+
function calendarYearTicks(domain,years){
|
|
1111
|
+
const minYear=new Date(domain.min).getUTCFullYear();
|
|
1112
|
+
let year=Math.ceil(minYear/years)*years;
|
|
1113
|
+
if(Date.UTC(year,0,1)<domain.min)year+=years;
|
|
1114
|
+
const out=[];
|
|
1115
|
+
for(;Date.UTC(year,0,1)<=domain.max;year+=years){
|
|
1116
|
+
out.push(Date.UTC(year,0,1));
|
|
1117
|
+
}
|
|
1118
|
+
return out;
|
|
1095
1119
|
}
|
|
1096
1120
|
function timeTicks(domain,count=5){
|
|
1097
1121
|
const step=timeStepFor(domain.max-domain.min,count);
|
|
1122
|
+
if(step>=YEAR)return calendarYearTicks(domain,Math.round(step/YEAR));
|
|
1098
1123
|
const out=[];
|
|
1099
1124
|
const first=Math.ceil(domain.min/step)*step;
|
|
1100
1125
|
for(let t=first;t<=domain.max;t+=step)out.push(t);
|
|
@@ -1545,1438 +1570,1540 @@ canvas.style.height=`${opts.height}px`;
|
|
|
1545
1570
|
return typeof canvas.getContext==='function'?canvas.getContext('2d'):null;
|
|
1546
1571
|
}
|
|
1547
1572
|
});
|
|
1548
|
-
__def("packages/
|
|
1573
|
+
__def("packages/core/src/internal/util.js",function(__exports,__req){
|
|
1549
1574
|
'use strict';
|
|
1550
|
-
Object.defineProperty(__exports,"
|
|
1551
|
-
Object.defineProperty(__exports,"
|
|
1552
|
-
Object.defineProperty(__exports,"
|
|
1553
|
-
Object.defineProperty(__exports,"
|
|
1554
|
-
Object.defineProperty(__exports,"
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
function
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1575
|
+
Object.defineProperty(__exports,"VERSION",{enumerable:true,get:function(){return VERSION;}});
|
|
1576
|
+
Object.defineProperty(__exports,"reportedWarnings",{enumerable:true,get:function(){return reportedWarnings;}});
|
|
1577
|
+
Object.defineProperty(__exports,"warnOnce",{enumerable:true,get:function(){return warnOnce;}});
|
|
1578
|
+
Object.defineProperty(__exports,"infoOnce",{enumerable:true,get:function(){return infoOnce;}});
|
|
1579
|
+
Object.defineProperty(__exports,"resetWarnings",{enumerable:true,get:function(){return resetWarnings;}});
|
|
1580
|
+
Object.defineProperty(__exports,"fail",{enumerable:true,get:function(){return fail;}});
|
|
1581
|
+
Object.defineProperty(__exports,"invariant",{enumerable:true,get:function(){return invariant;}});
|
|
1582
|
+
Object.defineProperty(__exports,"DEV",{enumerable:true,get:function(){return DEV;}});
|
|
1583
|
+
Object.defineProperty(__exports,"isObject",{enumerable:true,get:function(){return isObject;}});
|
|
1584
|
+
Object.defineProperty(__exports,"isFunction",{enumerable:true,get:function(){return isFunction;}});
|
|
1585
|
+
Object.defineProperty(__exports,"isNil",{enumerable:true,get:function(){return isNil;}});
|
|
1586
|
+
Object.defineProperty(__exports,"isBlank",{enumerable:true,get:function(){return isBlank;}});
|
|
1587
|
+
Object.defineProperty(__exports,"isCtor",{enumerable:true,get:function(){return isCtor;}});
|
|
1588
|
+
Object.defineProperty(__exports,"pathGetter",{enumerable:true,get:function(){return pathGetter;}});
|
|
1589
|
+
Object.defineProperty(__exports,"pathSetter",{enumerable:true,get:function(){return pathSetter;}});
|
|
1590
|
+
Object.defineProperty(__exports,"getPath",{enumerable:true,get:function(){return getPath;}});
|
|
1591
|
+
Object.defineProperty(__exports,"setPath",{enumerable:true,get:function(){return setPath;}});
|
|
1592
|
+
Object.defineProperty(__exports,"humanise",{enumerable:true,get:function(){return humanise;}});
|
|
1593
|
+
Object.defineProperty(__exports,"escapeHtml",{enumerable:true,get:function(){return escapeHtml;}});
|
|
1594
|
+
Object.defineProperty(__exports,"titleCase",{enumerable:true,get:function(){return titleCase;}});
|
|
1595
|
+
Object.defineProperty(__exports,"expand",{enumerable:true,get:function(){return expand;}});
|
|
1596
|
+
Object.defineProperty(__exports,"toArray",{enumerable:true,get:function(){return toArray;}});
|
|
1597
|
+
Object.defineProperty(__exports,"merge",{enumerable:true,get:function(){return merge;}});
|
|
1598
|
+
Object.defineProperty(__exports,"mergeRow",{enumerable:true,get:function(){return mergeRow;}});
|
|
1599
|
+
Object.defineProperty(__exports,"Lru",{enumerable:true,get:function(){return Lru;}});
|
|
1600
|
+
Object.defineProperty(__exports,"collator",{enumerable:true,get:function(){return collator;}});
|
|
1601
|
+
Object.defineProperty(__exports,"defaultCompare",{enumerable:true,get:function(){return defaultCompare;}});
|
|
1602
|
+
Object.defineProperty(__exports,"now",{enumerable:true,get:function(){return now;}});
|
|
1603
|
+
Object.defineProperty(__exports,"nextFrame",{enumerable:true,get:function(){return nextFrame;}});
|
|
1604
|
+
Object.defineProperty(__exports,"cancelFrame",{enumerable:true,get:function(){return cancelFrame;}});
|
|
1605
|
+
Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){return frameBatched;}});
|
|
1606
|
+
Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
|
|
1607
|
+
Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
|
|
1608
|
+
Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
|
|
1609
|
+
const STAMPED_VERSION="1.68.0";
|
|
1610
|
+
async function resolveVersion(){
|
|
1611
|
+
if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
|
|
1612
|
+
return STAMPED_VERSION;
|
|
1572
1613
|
}
|
|
1614
|
+
const VERSION="1.68.0";
|
|
1615
|
+
const warned=new Set();
|
|
1616
|
+
const WARNED_LIMIT=2000;
|
|
1617
|
+
function rememberWarned(key){
|
|
1618
|
+
warned.add(key);
|
|
1619
|
+
if(warned.size>WARNED_LIMIT){
|
|
1620
|
+
const oldest=warned.values().next().value;
|
|
1621
|
+
if(oldest!==undefined)warned.delete(oldest);
|
|
1573
1622
|
}
|
|
1574
|
-
const host=group.ownerDocument.createElementNS(SVG_NS,'g');
|
|
1575
|
-
host.setAttribute('class',className);
|
|
1576
|
-
group.appendChild(host);
|
|
1577
|
-
return host;
|
|
1578
1623
|
}
|
|
1579
|
-
const
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1624
|
+
const reported=[];
|
|
1625
|
+
const REPORT_LIMIT=500;
|
|
1626
|
+
function record(key,level,message){
|
|
1627
|
+
reported.push({
|
|
1628
|
+
key,
|
|
1629
|
+
level,
|
|
1630
|
+
message:message.map((m)=>(typeof m==='string'?m:safeString(m))).join(' '),
|
|
1631
|
+
at:Date.now(),
|
|
1632
|
+
});
|
|
1633
|
+
if(reported.length>REPORT_LIMIT)reported.shift();
|
|
1586
1634
|
}
|
|
1587
|
-
|
|
1635
|
+
function safeString(value){
|
|
1636
|
+
if(value instanceof Error)return value.message;
|
|
1637
|
+
try{return JSON.stringify(value);}catch{return String(value);}
|
|
1588
1638
|
}
|
|
1589
|
-
function
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1639
|
+
function reportedWarnings(){return reported.map((r)=>({...r}));}
|
|
1640
|
+
function warnOnce(key,...message){
|
|
1641
|
+
if(warned.has(key))return;
|
|
1642
|
+
rememberWarned(key);
|
|
1643
|
+
record(key,'warn',message);
|
|
1644
|
+
console.warn('[lattice]',...message);
|
|
1593
1645
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1646
|
+
function infoOnce(key,...message){
|
|
1647
|
+
if(warned.has(key))return;
|
|
1648
|
+
rememberWarned(key);
|
|
1649
|
+
record(key,'info',message);
|
|
1650
|
+
console.info('[lattice]',...message);
|
|
1597
1651
|
}
|
|
1598
|
-
function
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
const side=s.axis==='right'?'right':'left';
|
|
1602
|
-
if(side!==axis)continue;
|
|
1603
|
-
if(anno.series!==undefined&&s.key!==anno.series)continue;
|
|
1604
|
-
for(const p of s.points)if(isNumber(p.y))out.push(Number(p.y));
|
|
1652
|
+
function resetWarnings(){
|
|
1653
|
+
warned.clear();
|
|
1654
|
+
reported.length=0;
|
|
1605
1655
|
}
|
|
1606
|
-
|
|
1656
|
+
function fail(message,extra){
|
|
1657
|
+
const err=new Error(`[lattice] ${message}`);
|
|
1658
|
+
if(extra!==undefined)err.cause=extra;
|
|
1659
|
+
throw err;
|
|
1607
1660
|
}
|
|
1608
|
-
function
|
|
1609
|
-
if(!
|
|
1610
|
-
const sorted=[...values].sort((a,b)=>a-b);
|
|
1611
|
-
if(sorted.length===1)return sorted[0];
|
|
1612
|
-
const rank=(Math.min(100,Math.max(0,p))/100)*(sorted.length-1);
|
|
1613
|
-
const low=Math.floor(rank);
|
|
1614
|
-
const high=Math.ceil(rank);
|
|
1615
|
-
if(low===high)return sorted[low];
|
|
1616
|
-
return sorted[low]+(sorted[high]-sorted[low])*(rank-low);
|
|
1661
|
+
function invariant(condition,message){
|
|
1662
|
+
if(!condition)fail(message);
|
|
1617
1663
|
}
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
return
|
|
1664
|
+
const DEV=(()=>{
|
|
1665
|
+
try{
|
|
1666
|
+
return!(typeof process!=='undefined'&&process.env
|
|
1667
|
+
&&process.env.NODE_ENV==='production');
|
|
1668
|
+
}catch{
|
|
1669
|
+
return true;
|
|
1621
1670
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
if(compute==='mean'||compute==='avg'){
|
|
1626
|
-
return values.reduce((t,v)=>t+v,0)/values.length;
|
|
1671
|
+
})();
|
|
1672
|
+
function isObject(v){
|
|
1673
|
+
return v!==null&&typeof v==='object'&&!Array.isArray(v);
|
|
1627
1674
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
if(compute==='max')return Math.max(...values);
|
|
1631
|
-
const match=/^p(\d+(?:\.\d+)?)$/.exec(compute);
|
|
1632
|
-
if(match)return percentile(values,Number(match[1]));
|
|
1633
|
-
return null;
|
|
1675
|
+
function isFunction(v){
|
|
1676
|
+
return typeof v==='function';
|
|
1634
1677
|
}
|
|
1635
|
-
function
|
|
1636
|
-
return
|
|
1678
|
+
function isNil(v){
|
|
1679
|
+
return v===null||v===undefined;
|
|
1637
1680
|
}
|
|
1638
|
-
function
|
|
1639
|
-
|
|
1640
|
-
const axis=dual?` (${annotationAxis(anno)==='right'?'right axis':'left axis'})`:'';
|
|
1641
|
-
const kind=anno.kind||'line';
|
|
1642
|
-
if(kind==='band'){
|
|
1643
|
-
if(!Array.isArray(resolved)||resolved[0]===null||resolved[1]===null)return'';
|
|
1644
|
-
const[lo,hi]=resolved;
|
|
1645
|
-
return`${label||'Band: '}${fmt(Math.min(lo,hi))} to ${fmt(Math.max(lo,hi))}${axis}`;
|
|
1681
|
+
function isBlank(v){
|
|
1682
|
+
return v===null||v===undefined||v==='';
|
|
1646
1683
|
}
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1684
|
+
function isCtor(v){
|
|
1685
|
+
if(typeof v!=='function')return false;
|
|
1686
|
+
if(/^class[\s{]/.test(Function.prototype.toString.call(v)))return true;
|
|
1687
|
+
return!!(v.prototype&&Object.getOwnPropertyNames(v.prototype).length>1);
|
|
1650
1688
|
}
|
|
1651
|
-
|
|
1652
|
-
|
|
1689
|
+
const pathCache=new Map();
|
|
1690
|
+
function pathGetter(path){
|
|
1691
|
+
let fn=pathCache.get(path);
|
|
1692
|
+
if(fn)return fn;
|
|
1693
|
+
if(!path.includes('.')){
|
|
1694
|
+
fn=(o)=>(o==null?undefined:o[path]);
|
|
1695
|
+
}else{
|
|
1696
|
+
const parts=path.split('.');
|
|
1697
|
+
const n=parts.length;
|
|
1698
|
+
fn=(o)=>{
|
|
1699
|
+
let cur=o;
|
|
1700
|
+
for(let i=0;i<n;i++){
|
|
1701
|
+
if(cur==null)return undefined;
|
|
1702
|
+
cur=cur[parts[i]];
|
|
1653
1703
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
group,plot,xScale,yScale,rightScale,series,format,
|
|
1657
|
-
}=opts;
|
|
1658
|
-
const pool=new Pool(overlayLayer(group,`${NS}__annotations`));
|
|
1659
|
-
const described=[];
|
|
1660
|
-
const list=Array.isArray(opts.annotations)?opts.annotations:[];
|
|
1661
|
-
const ordered=[...list].sort((a,b)=>bandFirst(a)-bandFirst(b));
|
|
1662
|
-
for(const anno of ordered){
|
|
1663
|
-
const kind=anno.kind||'line';
|
|
1664
|
-
if(!KINDS.has(kind))continue;
|
|
1665
|
-
const axis=annotationAxis(anno);
|
|
1666
|
-
const scale=axis==='right'&&rightScale?rightScale:yScale;
|
|
1667
|
-
if(kind==='band'){
|
|
1668
|
-
if(anno.orient==='vertical'){
|
|
1669
|
-
const x1=xPixel(xScale,anno.from,'left');
|
|
1670
|
-
const x2=xPixel(xScale,anno.to,'right');
|
|
1671
|
-
if(Number.isNaN(x1)||Number.isNaN(x2))continue;
|
|
1672
|
-
const left=round(Math.min(x1,x2));
|
|
1673
|
-
const right=round(Math.max(x1,x2));
|
|
1674
|
-
attrs(pool.next('rect',`${NS}__annotation-band ${anno.className||''}`.trim()),{
|
|
1675
|
-
x:left,
|
|
1676
|
-
y:round(plot.top),
|
|
1677
|
-
width:Math.max(0,right-left),
|
|
1678
|
-
height:round(Math.max(0,plot.bottom-plot.top)),
|
|
1679
|
-
fill:anno.colour||'currentColor',
|
|
1680
|
-
'fill-opacity':anno.opacity===undefined?0.12:anno.opacity,
|
|
1681
|
-
});
|
|
1682
|
-
if(anno.label){
|
|
1683
|
-
const text=pool.next('text',`${NS}__annotation-label`);
|
|
1684
|
-
attrs(text,{x:left+4,y:round(plot.top+12),'text-anchor':'start'});
|
|
1685
|
-
setText(text,anno.label);
|
|
1704
|
+
return cur;
|
|
1705
|
+
};
|
|
1686
1706
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
continue;
|
|
1707
|
+
pathCache.set(path,fn);
|
|
1708
|
+
return fn;
|
|
1690
1709
|
}
|
|
1691
|
-
const
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
setText(text,anno.label);
|
|
1710
|
+
const setterCache=new Map();
|
|
1711
|
+
function pathSetter(path){
|
|
1712
|
+
let fn=setterCache.get(path);
|
|
1713
|
+
if(fn)return fn;
|
|
1714
|
+
if(!path.includes('.')){
|
|
1715
|
+
fn=(o,v)=>{if(o!=null)o[path]=v;};
|
|
1716
|
+
}else{
|
|
1717
|
+
const parts=path.split('.');
|
|
1718
|
+
const last=parts.length-1;
|
|
1719
|
+
fn=(o,v)=>{
|
|
1720
|
+
let cur=o;
|
|
1721
|
+
for(let i=0;i<last;i++){
|
|
1722
|
+
if(cur==null)return;
|
|
1723
|
+
const k=parts[i];
|
|
1724
|
+
if(cur[k]==null)cur[k]={};
|
|
1725
|
+
cur=cur[k];
|
|
1708
1726
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1727
|
+
if(cur!=null)cur[parts[last]]=v;
|
|
1728
|
+
};
|
|
1711
1729
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
const at=round(xPixel(xScale,raw,'left')+(xScale.kind==='band'?(Number(xScale.bandwidth)||0)/2:0));
|
|
1715
|
-
if(Number.isNaN(at))continue;
|
|
1716
|
-
attrs(pool.next('path',`${NS}__annotation-event`),{
|
|
1717
|
-
d:path(['M',at,round(plot.top),'L',at,round(plot.bottom)]),
|
|
1718
|
-
stroke:anno.colour||'currentColor',
|
|
1719
|
-
fill:'none',
|
|
1720
|
-
});
|
|
1721
|
-
attrs(pool.next('circle',`${NS}__annotation-event-flag`),{
|
|
1722
|
-
cx:at,cy:round(plot.top),r:3,fill:anno.colour||'currentColor',
|
|
1723
|
-
});
|
|
1724
|
-
if(anno.label){
|
|
1725
|
-
const text=pool.next('text',`${NS}__annotation-label`);
|
|
1726
|
-
attrs(text,{x:at+5,y:round(plot.top+10),'text-anchor':'start'});
|
|
1727
|
-
setText(text,anno.label);
|
|
1730
|
+
setterCache.set(path,fn);
|
|
1731
|
+
return fn;
|
|
1728
1732
|
}
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
continue;
|
|
1733
|
+
function getPath(obj,path){
|
|
1734
|
+
return pathGetter(path)(obj);
|
|
1732
1735
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
if(value===null)continue;
|
|
1736
|
-
const cx=anno.at!==undefined
|
|
1737
|
-
?round(xScale.kind==='band'?xScale.centre(anno.at):xScale.of(toNumber(anno.at)))
|
|
1738
|
-
:round(plot.right-4);
|
|
1739
|
-
const cy=round(scale.of(value));
|
|
1740
|
-
if(Number.isNaN(cx))continue;
|
|
1741
|
-
attrs(pool.next('circle',`${NS}__annotation-point`),{
|
|
1742
|
-
cx,cy,r:3.5,fill:anno.colour||'currentColor',
|
|
1743
|
-
});
|
|
1744
|
-
if(anno.label){
|
|
1745
|
-
const text=pool.next('text',`${NS}__annotation-label`);
|
|
1746
|
-
attrs(text,{x:cx+6,y:cy-6,'text-anchor':'start'});
|
|
1747
|
-
setText(text,anno.label);
|
|
1736
|
+
function setPath(obj,path,value){
|
|
1737
|
+
pathSetter(path)(obj,value);
|
|
1748
1738
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1739
|
+
function humanise(field){
|
|
1740
|
+
if(!field)return'';
|
|
1741
|
+
const leaf=field.includes('.')?field.slice(field.lastIndexOf('.')+1):field;
|
|
1742
|
+
return leaf
|
|
1743
|
+
.replace(/[_-]+/g,' ')
|
|
1744
|
+
.replace(/([a-z0-9])([A-Z])/g,'$1 $2')
|
|
1745
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g,'$1 $2')
|
|
1746
|
+
.replace(/\s+/g,' ')
|
|
1747
|
+
.trim()
|
|
1748
|
+
.replace(/^./,(c)=>c.toUpperCase());
|
|
1751
1749
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
const
|
|
1755
|
-
?
|
|
1756
|
-
:round(xScale.of(toNumber(raw)));
|
|
1757
|
-
if(Number.isNaN(at))continue;
|
|
1758
|
-
const cls=kind==='target'?`${NS}__annotation-target`:`${NS}__annotation-line`;
|
|
1759
|
-
attrs(pool.next('path',cls),{
|
|
1760
|
-
d:path(['M',at,round(plot.top),'L',at,round(plot.bottom)]),
|
|
1761
|
-
stroke:anno.colour||'currentColor',
|
|
1762
|
-
fill:'none',
|
|
1763
|
-
});
|
|
1764
|
-
if(anno.label){
|
|
1765
|
-
const text=pool.next('text',`${NS}__annotation-label`);
|
|
1766
|
-
attrs(text,{
|
|
1767
|
-
x:at+4,y:round(plot.top+10),'text-anchor':'start',
|
|
1768
|
-
});
|
|
1769
|
-
setText(text,anno.label);
|
|
1750
|
+
const ESCAPES={'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
|
1751
|
+
function escapeHtml(s){
|
|
1752
|
+
const str=s==null?'':String(s);
|
|
1753
|
+
return/[&<>"']/.test(str)?str.replace(/[&<>"']/g,(c)=>ESCAPES[c]):str;
|
|
1770
1754
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1755
|
+
function titleCase(s){
|
|
1756
|
+
return String(s).replace(/\w\S*/g,(t)=>t[0].toUpperCase()+t.slice(1).toLowerCase());
|
|
1773
1757
|
}
|
|
1774
|
-
|
|
1775
|
-
if(value===
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
stroke:anno.colour||'currentColor',
|
|
1781
|
-
fill:'none',
|
|
1782
|
-
});
|
|
1783
|
-
if(anno.label){
|
|
1784
|
-
const text=pool.next('text',`${NS}__annotation-label`);
|
|
1785
|
-
attrs(text,{x:round(plot.right-4),y:at-4,'text-anchor':'end'});
|
|
1786
|
-
setText(text,anno.label);
|
|
1758
|
+
function expand(value,key,whenTrue){
|
|
1759
|
+
if(value===undefined)return undefined;
|
|
1760
|
+
if(value===true)return{enabled:true,...whenTrue};
|
|
1761
|
+
if(value===false)return{enabled:false};
|
|
1762
|
+
if(isObject(value))return value;
|
|
1763
|
+
return{[key]:value,enabled:true};
|
|
1787
1764
|
}
|
|
1788
|
-
|
|
1765
|
+
function toArray(v){
|
|
1766
|
+
if(v===undefined||v===null)return[];
|
|
1767
|
+
return Array.isArray(v)?v:[v];
|
|
1789
1768
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1769
|
+
const MERGE_FORBIDDEN_KEYS=Object.freeze(new Set(['__proto__','constructor','prototype']));
|
|
1770
|
+
function merge(a,b){
|
|
1771
|
+
if(!isObject(a))return isObject(b)?{...b}:b;
|
|
1772
|
+
if(!isObject(b))return b===undefined?a:b;
|
|
1773
|
+
const out={...a};
|
|
1774
|
+
for(const k of Object.keys(b)){
|
|
1775
|
+
if(MERGE_FORBIDDEN_KEYS.has(k))continue;
|
|
1776
|
+
const bv=b[k];
|
|
1777
|
+
if(bv===undefined)continue;
|
|
1778
|
+
out[k]=isObject(bv)&&isObject(out[k])?merge(out[k],bv):bv;
|
|
1792
1779
|
}
|
|
1793
|
-
|
|
1794
|
-
__def("packages/modules/charts/combo.js",function(__exports,__req){
|
|
1795
|
-
'use strict';
|
|
1796
|
-
Object.defineProperty(__exports,"toPareto",{enumerable:true,get:function(){return toPareto;}});
|
|
1797
|
-
Object.defineProperty(__exports,"drawCombo",{enumerable:true,get:function(){return drawCombo;}});
|
|
1798
|
-
Object.defineProperty(__exports,"drawRightAxis",{enumerable:true,get:function(){return drawRightAxis;}});
|
|
1799
|
-
const __m0=__req("packages/modules/charts/axis.js");
|
|
1800
|
-
const drawAxisLines=__m0["drawAxisLines"];
|
|
1801
|
-
const drawCategoryAxis=__m0["drawCategoryAxis"];
|
|
1802
|
-
const drawMeasureAxis=__m0["drawMeasureAxis"];
|
|
1803
|
-
const overhangFor=__m0["overhangFor"];
|
|
1804
|
-
const setPlotClip=__m0["setPlotClip"];
|
|
1805
|
-
const __m1=__req("packages/modules/charts/frame.js");
|
|
1806
|
-
const Pool=__m1["Pool"];
|
|
1807
|
-
const shouldRotate=__m1["shouldRotate"];
|
|
1808
|
-
const __m2=__req("packages/modules/charts/format.js");
|
|
1809
|
-
const formatters=__m2["formatters"];
|
|
1810
|
-
const __m3=__req("packages/modules/charts/scale.js");
|
|
1811
|
-
const bandScale=__m3["bandScale"];
|
|
1812
|
-
const isNumber=__m3["isNumber"];
|
|
1813
|
-
const linearScale=__m3["linearScale"];
|
|
1814
|
-
const measureDomain=__m3["measureDomain"];
|
|
1815
|
-
const __m4=__req("packages/modules/charts/svg.js");
|
|
1816
|
-
const attrs=__m4["attrs"];
|
|
1817
|
-
const path=__m4["path"];
|
|
1818
|
-
const round=__m4["round"];
|
|
1819
|
-
const __m5=__req("packages/modules/charts/styles.js");
|
|
1820
|
-
const NS=__m5["NS"];
|
|
1821
|
-
const __m6=__req("packages/modules/charts/scheme.js");
|
|
1822
|
-
const resolveScheme=__m6["resolveScheme"];
|
|
1823
|
-
const __m7=__req("packages/modules/charts/labels.js");
|
|
1824
|
-
const drawDataLabels=__m7["drawDataLabels"];
|
|
1825
|
-
const __m8=__req("packages/modules/charts/annotations.js");
|
|
1826
|
-
const drawAnnotations=__m8["drawAnnotations"];
|
|
1827
|
-
function byAxis(series){
|
|
1828
|
-
return{
|
|
1829
|
-
left:series.filter((s)=>s.axis!=='right'),
|
|
1830
|
-
right:series.filter((s)=>s.axis==='right'),
|
|
1831
|
-
};
|
|
1780
|
+
return out;
|
|
1832
1781
|
}
|
|
1833
|
-
function
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1782
|
+
function mergeRow(previous,patch){
|
|
1783
|
+
if(!isObject(previous)||!isObject(patch)||previous===patch)return patch;
|
|
1784
|
+
const out=Object.create(Object.getPrototypeOf(previous));
|
|
1785
|
+
Object.assign(out,previous,patch);
|
|
1786
|
+
return out;
|
|
1837
1787
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
const total=ranked.reduce((t,entry)=>t+(entry.point.y),0);
|
|
1846
|
-
let running=0;
|
|
1847
|
-
const cumulative=ranked.map((entry)=>{
|
|
1848
|
-
running+=(entry.point.y);
|
|
1849
|
-
return total>0?(running/total)*100:0;
|
|
1850
|
-
});
|
|
1851
|
-
return{
|
|
1852
|
-
...bound,
|
|
1853
|
-
categories:ranked.map((entry)=>entry.category),
|
|
1854
|
-
labels:ranked.map((entry)=>entry.label),
|
|
1855
|
-
series:[
|
|
1856
|
-
{
|
|
1857
|
-
...source,
|
|
1858
|
-
index:0,
|
|
1859
|
-
mark:'bar',
|
|
1860
|
-
axis:'left',
|
|
1861
|
-
points:ranked.map((entry)=>entry.point),
|
|
1862
|
-
},
|
|
1863
|
-
{
|
|
1864
|
-
key:'cumulative',
|
|
1865
|
-
label:bound.cumulativeLabel||'%',
|
|
1866
|
-
index:1,
|
|
1867
|
-
mark:'line',
|
|
1868
|
-
axis:'right',
|
|
1869
|
-
points:ranked.map((entry,i)=>({
|
|
1870
|
-
x:entry.category,
|
|
1871
|
-
xKey:entry.point.xKey,
|
|
1872
|
-
label:entry.label,
|
|
1873
|
-
y:cumulative[i],
|
|
1874
|
-
rows:entry.point.rows,
|
|
1875
|
-
rowKey:entry.point.rowKey,
|
|
1876
|
-
})),
|
|
1877
|
-
},
|
|
1878
|
-
],
|
|
1879
|
-
};
|
|
1788
|
+
class Lru{
|
|
1789
|
+
#max;
|
|
1790
|
+
#map=new Map();
|
|
1791
|
+
#onEvict;
|
|
1792
|
+
constructor(max=256,onEvict=null){
|
|
1793
|
+
this.#max=max;
|
|
1794
|
+
this.#onEvict=onEvict;
|
|
1880
1795
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
const{plot}=ctx;
|
|
1884
|
-
const bound=ctx.pareto?toPareto(ctx.bound):ctx.bound;
|
|
1885
|
-
const visible=bound.series.filter((s)=>!ctx.hidden.has(s.key));
|
|
1886
|
-
const sides=byAxis(visible);
|
|
1887
|
-
const hasBars=sides.left.some((s)=>(s.mark||'bar')==='bar');
|
|
1888
|
-
const leftDomain=domainFor(sides.left,hasBars);
|
|
1889
|
-
const yScale=linearScale(leftDomain,[plot.bottom,plot.top]);
|
|
1890
|
-
const rightDomain=sides.right.length
|
|
1891
|
-
?(ctx.pareto?{min:0,max:100}:domainFor(sides.right,false))
|
|
1892
|
-
:null;
|
|
1893
|
-
const rightScale=rightDomain?linearScale(rightDomain,[plot.bottom,plot.top]):null;
|
|
1894
|
-
const xScale=bandScale(bound.categories,[plot.left,plot.right],0.2);
|
|
1895
|
-
drawMeasureAxis({
|
|
1896
|
-
gridGroup:ctx.groups.grid,
|
|
1897
|
-
axisGroup:ctx.groups.axis,
|
|
1898
|
-
plot,
|
|
1899
|
-
scale:yScale,
|
|
1900
|
-
format:formatters(ctx.grid,{
|
|
1901
|
-
kind:'linear',step:(leftDomain.max-leftDomain.min)/5,
|
|
1902
|
-
}),
|
|
1903
|
-
});
|
|
1904
|
-
drawCategoryAxis({
|
|
1905
|
-
group:ctx.groups.overlay,
|
|
1906
|
-
plot,
|
|
1907
|
-
scale:xScale,
|
|
1908
|
-
labels:bound.labels,
|
|
1909
|
-
fontSize:ctx.fontSize,
|
|
1910
|
-
rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize),
|
|
1911
|
-
});
|
|
1912
|
-
drawAxisLines({group:ctx.groups.rules,plot});
|
|
1913
|
-
if(rightScale){
|
|
1914
|
-
drawRightAxis({
|
|
1915
|
-
group:ctx.groups.axis,
|
|
1916
|
-
plot,
|
|
1917
|
-
scale:rightScale,
|
|
1918
|
-
colour:scheme.series(sides.right[0].index),
|
|
1919
|
-
format:formatters(ctx.grid,{
|
|
1920
|
-
kind:'linear',step:(rightDomain.max-rightDomain.min)/5,
|
|
1921
|
-
}),
|
|
1922
|
-
suffix:ctx.pareto?'%':'',
|
|
1923
|
-
});
|
|
1796
|
+
get size(){
|
|
1797
|
+
return this.#map.size;
|
|
1924
1798
|
}
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
const bars=visible.filter((s)=>(s.mark||'bar')==='bar');
|
|
1928
|
-
const slot=bars.length?xScale.bandwidth/bars.length:xScale.bandwidth;
|
|
1929
|
-
let barIndex=0;
|
|
1930
|
-
for(const series of visible){
|
|
1931
|
-
const mark=series.mark||'bar';
|
|
1932
|
-
const scale=series.axis==='right'&&rightScale?rightScale:yScale;
|
|
1933
|
-
const colour=scheme.series(series.index);
|
|
1934
|
-
if(mark==='bar'){
|
|
1935
|
-
const offset=barIndex*slot;
|
|
1936
|
-
barIndex++;
|
|
1937
|
-
const base=scale.of(Math.max(scale.domain.min,0));
|
|
1938
|
-
for(let i=0;i<series.points.length;i++){
|
|
1939
|
-
const point=series.points[i];
|
|
1940
|
-
if(!isNumber(point.y))continue;
|
|
1941
|
-
const start=xScale.of(point.x);
|
|
1942
|
-
if(Number.isNaN(start))continue;
|
|
1943
|
-
const top=scale.of((point.y));
|
|
1944
|
-
attrs(pool.next('rect',`${NS}__bar ${NS}__mark`),{
|
|
1945
|
-
x:round(start+offset),
|
|
1946
|
-
y:round(Math.min(top,base)),
|
|
1947
|
-
width:round(Math.max(0,slot)),
|
|
1948
|
-
height:round(Math.max(1,Math.abs(base-top))),
|
|
1949
|
-
fill:colour,
|
|
1950
|
-
'data-series':series.index,
|
|
1951
|
-
'data-point':i,
|
|
1952
|
-
});
|
|
1953
|
-
point.px=round(start+offset+slot/2);
|
|
1954
|
-
point.py=round(Math.min(top,base));
|
|
1799
|
+
get max(){
|
|
1800
|
+
return this.#max;
|
|
1955
1801
|
}
|
|
1956
|
-
|
|
1802
|
+
set max(v){
|
|
1803
|
+
this.#max=v;
|
|
1804
|
+
this.#trim();
|
|
1957
1805
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
for(const point of series.points){
|
|
1961
|
-
if(!isNumber(point.y)){open=false;continue;}
|
|
1962
|
-
const x=round(xScale.centre(point.x));
|
|
1963
|
-
if(Number.isNaN(x)){open=false;continue;}
|
|
1964
|
-
const y=round(scale.of((point.y)));
|
|
1965
|
-
commands.push(open?'L':'M',x,y);
|
|
1966
|
-
open=true;
|
|
1967
|
-
point.px=x;
|
|
1968
|
-
point.py=y;
|
|
1806
|
+
has(k){
|
|
1807
|
+
return this.#map.has(k);
|
|
1969
1808
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
attrs(pool.next('circle',`${NS}__point ${NS}__mark`),{
|
|
1978
|
-
cx:point.px,cy:point.py,r:3,fill:colour,
|
|
1979
|
-
});
|
|
1809
|
+
get(k){
|
|
1810
|
+
const m=this.#map;
|
|
1811
|
+
if(!m.has(k))return undefined;
|
|
1812
|
+
const v=m.get(k);
|
|
1813
|
+
m.delete(k);
|
|
1814
|
+
m.set(k,v);
|
|
1815
|
+
return v;
|
|
1980
1816
|
}
|
|
1817
|
+
peek(k){
|
|
1818
|
+
return this.#map.get(k);
|
|
1981
1819
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
options:ctx.labels,
|
|
1989
|
-
grid:ctx.grid,
|
|
1990
|
-
size:(ctx.typography&&ctx.typography.small)||ctx.fontSize,
|
|
1991
|
-
});
|
|
1820
|
+
set(k,v){
|
|
1821
|
+
const m=this.#map;
|
|
1822
|
+
if(m.has(k))m.delete(k);
|
|
1823
|
+
m.set(k,v);
|
|
1824
|
+
this.#trim();
|
|
1825
|
+
return v;
|
|
1992
1826
|
}
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
plot,
|
|
1998
|
-
xScale,
|
|
1999
|
-
yScale,
|
|
2000
|
-
rightScale,
|
|
2001
|
-
series:visible,
|
|
2002
|
-
annotations:ctx.annotations,
|
|
2003
|
-
dual:!!rightScale,
|
|
2004
|
-
format:formatters(ctx.grid,{
|
|
2005
|
-
kind:'linear',step:(leftDomain.max-leftDomain.min)/5,
|
|
2006
|
-
}).tick,
|
|
2007
|
-
});
|
|
1827
|
+
delete(k){
|
|
1828
|
+
const v=this.#map.get(k);
|
|
1829
|
+
if(this.#map.delete(k)&&this.#onEvict)this.#onEvict(v,k);
|
|
1830
|
+
return v;
|
|
2008
1831
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
1832
|
+
clear(){
|
|
1833
|
+
if(this.#onEvict)for(const[k,v]of this.#map)this.#onEvict(v,k);
|
|
1834
|
+
this.#map.clear();
|
|
1835
|
+
}
|
|
1836
|
+
keys(){
|
|
1837
|
+
return this.#map.keys();
|
|
1838
|
+
}
|
|
1839
|
+
values(){
|
|
1840
|
+
return this.#map.values();
|
|
1841
|
+
}
|
|
1842
|
+
#trim(){
|
|
1843
|
+
const m=this.#map;
|
|
1844
|
+
while(m.size>this.#max){
|
|
1845
|
+
const oldest=m.keys().next().value;
|
|
1846
|
+
const v=m.get(oldest);
|
|
1847
|
+
m.delete(oldest);
|
|
1848
|
+
if(this.#onEvict)this.#onEvict(v,oldest);
|
|
2012
1849
|
}
|
|
2013
|
-
function drawRightAxis(opts){
|
|
2014
|
-
const{group,plot,scale,format}=opts;
|
|
2015
|
-
const pool=new Pool(group);
|
|
2016
|
-
attrs(pool.next('line',`${NS}__axis-right`),{
|
|
2017
|
-
x1:round(plot.right),x2:round(plot.right),
|
|
2018
|
-
y1:round(plot.top),y2:round(plot.bottom),
|
|
2019
|
-
stroke:opts.colour,
|
|
2020
|
-
});
|
|
2021
|
-
for(const value of scale.ticks(5)){
|
|
2022
|
-
const at=round(scale.of(value));
|
|
2023
|
-
const label=pool.next('text',`${NS}__tick`);
|
|
2024
|
-
attrs(label,{
|
|
2025
|
-
x:round(plot.right+6),y:at,'text-anchor':'start',
|
|
2026
|
-
'dominant-baseline':'middle',fill:opts.colour,
|
|
2027
|
-
});
|
|
2028
|
-
label.textContent=`${format.tick(value)}${opts.suffix||''}`;
|
|
2029
1850
|
}
|
|
2030
|
-
pool.finish();
|
|
2031
1851
|
}
|
|
1852
|
+
const collators=new Map();
|
|
1853
|
+
function collator(locale,opts){
|
|
1854
|
+
const key=`${locale||''}|${opts?JSON.stringify(opts):''}`;
|
|
1855
|
+
let c=collators.get(key);
|
|
1856
|
+
if(!c){
|
|
1857
|
+
c=new Intl.Collator(locale||undefined,{
|
|
1858
|
+
numeric:true,sensitivity:'variant',...opts,
|
|
2032
1859
|
});
|
|
2033
|
-
|
|
2034
|
-
'use strict';
|
|
2035
|
-
Object.defineProperty(__exports,"normalQuantile",{enumerable:true,get:function(){return normalQuantile;}});
|
|
2036
|
-
Object.defineProperty(__exports,"studentTQuantile",{enumerable:true,get:function(){return studentTQuantile;}});
|
|
2037
|
-
const LANCZOS=Object.freeze([
|
|
2038
|
-
676.5203681218851,-1259.1392167224028,771.32342877765313,
|
|
2039
|
-
-176.61502916214059,12.507343278686905,-0.13857109526572012,
|
|
2040
|
-
9.9843695780195716e-6,1.5056327351493116e-7,
|
|
2041
|
-
]);
|
|
2042
|
-
const EPS=3e-12;
|
|
2043
|
-
const TINY=1e-300;
|
|
2044
|
-
function logGamma(x){
|
|
2045
|
-
if(x<0.5)return Math.log(Math.PI/Math.sin(Math.PI*x))-logGamma(1-x);
|
|
2046
|
-
const z=x-1;
|
|
2047
|
-
let a=0.99999999999980993;
|
|
2048
|
-
const t=z+7.5;
|
|
2049
|
-
for(let i=0;i<LANCZOS.length;i++)a+=LANCZOS[i]/(z+i+1);
|
|
2050
|
-
return 0.5*Math.log(2*Math.PI)+(z+0.5)*Math.log(t)-t+Math.log(a);
|
|
1860
|
+
collators.set(key,c);
|
|
2051
1861
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
if(
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
const m2=2*m;
|
|
2063
|
-
let aa=(m*(b-m)*x)/((qam+m2)*(a+m2));
|
|
2064
|
-
d=1+aa*d;
|
|
2065
|
-
if(Math.abs(d)<TINY)d=TINY;
|
|
2066
|
-
c=1+aa/c;
|
|
2067
|
-
if(Math.abs(c)<TINY)c=TINY;
|
|
2068
|
-
d=1/d;
|
|
2069
|
-
h*=d*c;
|
|
2070
|
-
aa=(-(a+m)*(qab+m)*x)/((a+m2)*(qap+m2));
|
|
2071
|
-
d=1+aa*d;
|
|
2072
|
-
if(Math.abs(d)<TINY)d=TINY;
|
|
2073
|
-
c=1+aa/c;
|
|
2074
|
-
if(Math.abs(c)<TINY)c=TINY;
|
|
2075
|
-
d=1/d;
|
|
2076
|
-
const step=d*c;
|
|
2077
|
-
h*=step;
|
|
2078
|
-
if(Math.abs(step-1)<EPS)break;
|
|
1862
|
+
return c;
|
|
1863
|
+
}
|
|
1864
|
+
function defaultCompare(a,b){
|
|
1865
|
+
if(a===b)return 0;
|
|
1866
|
+
if(a===null||a===undefined)return 1;
|
|
1867
|
+
if(b===null||b===undefined)return-1;
|
|
1868
|
+
if(typeof a==='number'&&typeof b==='number'){
|
|
1869
|
+
if(Number.isNaN(a))return Number.isNaN(b)?0:1;
|
|
1870
|
+
if(Number.isNaN(b))return-1;
|
|
1871
|
+
return a<b?-1:a>b?1:0;
|
|
2079
1872
|
}
|
|
2080
|
-
|
|
1873
|
+
const sa=String(a);
|
|
1874
|
+
const sb=String(b);
|
|
1875
|
+
return sa<sb?-1:sa>sb?1:0;
|
|
2081
1876
|
}
|
|
2082
|
-
function
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
const front=Math.exp(
|
|
2087
|
-
logGamma(a+b)-logGamma(a)-logGamma(b)+a*Math.log(x)+b*Math.log(1-x),
|
|
2088
|
-
);
|
|
2089
|
-
return x<(a+1)/(a+b+2)
|
|
2090
|
-
?(front*betaContinuedFraction(a,b,x))/a
|
|
2091
|
-
:1-(front*betaContinuedFraction(b,a,1-x))/b;
|
|
1877
|
+
function now(){
|
|
1878
|
+
return typeof performance!=='undefined'&&performance.now
|
|
1879
|
+
?performance.now()
|
|
1880
|
+
:Date.now();
|
|
2092
1881
|
}
|
|
2093
|
-
function
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
const cof=[-1.3026537197817094,6.4196979235649026e-1,1.9476473204185836e-2,
|
|
2098
|
-
-9.561514786808631e-3,-9.46595344482036e-4,3.66839497852761e-4,
|
|
2099
|
-
4.2523324806907e-5,-2.0278578112534e-5,-1.624290004647e-6,
|
|
2100
|
-
1.303655835580e-6,1.5626441722e-8,-8.5238095915e-8,6.529054439e-9,
|
|
2101
|
-
5.059343495e-9,-9.91364156e-10,-2.27365122e-10,9.6467911e-11,
|
|
2102
|
-
2.394038e-12,-6.886027e-12,8.94487e-13,3.13092e-13,-1.12708e-13,
|
|
2103
|
-
3.81e-16,7.106e-15];
|
|
2104
|
-
let dd=0;
|
|
2105
|
-
let dv=0;
|
|
2106
|
-
let tmp;
|
|
2107
|
-
for(let j=cof.length-1;j>0;j--){
|
|
2108
|
-
tmp=dv;
|
|
2109
|
-
dv=ty*dv-dd+cof[j];
|
|
2110
|
-
dd=tmp;
|
|
1882
|
+
const hasRaf=typeof requestAnimationFrame==='function';
|
|
1883
|
+
function nextFrame(fn){
|
|
1884
|
+
if(hasRaf)return requestAnimationFrame(fn);
|
|
1885
|
+
return setTimeout(()=>fn(now()),16);
|
|
2111
1886
|
}
|
|
2112
|
-
|
|
2113
|
-
return
|
|
1887
|
+
function cancelFrame(handle){
|
|
1888
|
+
if(handle==null)return;
|
|
1889
|
+
if(hasRaf)cancelAnimationFrame(handle);
|
|
1890
|
+
else clearTimeout(handle);
|
|
2114
1891
|
}
|
|
2115
|
-
function
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
1892
|
+
function frameBatched(fn){
|
|
1893
|
+
let handle=null;
|
|
1894
|
+
let lastArgs=null;
|
|
1895
|
+
const run=()=>{
|
|
1896
|
+
handle=null;
|
|
1897
|
+
const a=lastArgs;
|
|
1898
|
+
lastArgs=null;
|
|
1899
|
+
fn(...(a||[]));
|
|
1900
|
+
};
|
|
1901
|
+
const wrapped=(...args)=>{
|
|
1902
|
+
lastArgs=args;
|
|
1903
|
+
if(handle===null)handle=nextFrame(run);
|
|
1904
|
+
};
|
|
1905
|
+
wrapped.cancel=()=>{
|
|
1906
|
+
cancelFrame(handle);
|
|
1907
|
+
handle=null;
|
|
1908
|
+
lastArgs=null;
|
|
1909
|
+
};
|
|
1910
|
+
wrapped.flush=()=>{
|
|
1911
|
+
if(handle!==null){
|
|
1912
|
+
cancelFrame(handle);
|
|
1913
|
+
run();
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
return wrapped;
|
|
1917
|
+
}
|
|
1918
|
+
function settleDebounce(fn,waitMs){
|
|
1919
|
+
let timer=null;
|
|
1920
|
+
let held=null;
|
|
1921
|
+
const trailing=()=>{
|
|
1922
|
+
timer=null;
|
|
1923
|
+
if(held===null)return;
|
|
1924
|
+
const args=held;
|
|
1925
|
+
held=null;
|
|
1926
|
+
fn(...args);
|
|
1927
|
+
arm();
|
|
1928
|
+
};
|
|
1929
|
+
const arm=()=>{
|
|
1930
|
+
timer=setTimeout(trailing,waitMs);
|
|
1931
|
+
if(typeof timer?.unref==='function')timer.unref();
|
|
1932
|
+
};
|
|
1933
|
+
const wrapped=(...args)=>{
|
|
1934
|
+
if(timer===null){
|
|
1935
|
+
fn(...args);
|
|
1936
|
+
arm();
|
|
2138
1937
|
}else{
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
1938
|
+
held=args;
|
|
1939
|
+
clearTimeout(timer);
|
|
1940
|
+
arm();
|
|
2142
1941
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
1942
|
+
};
|
|
1943
|
+
wrapped.flush=()=>{
|
|
1944
|
+
if(timer!==null)clearTimeout(timer);
|
|
1945
|
+
timer=null;
|
|
1946
|
+
if(held===null)return;
|
|
1947
|
+
const args=held;
|
|
1948
|
+
held=null;
|
|
1949
|
+
fn(...args);
|
|
1950
|
+
};
|
|
1951
|
+
wrapped.cancel=()=>{
|
|
1952
|
+
if(timer!==null)clearTimeout(timer);
|
|
1953
|
+
timer=null;
|
|
1954
|
+
held=null;
|
|
1955
|
+
};
|
|
1956
|
+
wrapped.pending=()=>timer!==null||held!==null;
|
|
1957
|
+
return wrapped;
|
|
2146
1958
|
}
|
|
2147
|
-
function
|
|
2148
|
-
if(
|
|
2149
|
-
|
|
2150
|
-
return t>0?1-tail:tail;
|
|
1959
|
+
function whenIdle(fn,timeout=50){
|
|
1960
|
+
if(typeof requestIdleCallback==='function'){
|
|
1961
|
+
return requestIdleCallback(fn,{timeout});
|
|
2151
1962
|
}
|
|
2152
|
-
|
|
2153
|
-
if(!(p>0)||!(p<1)||!(df>0))return Number.NaN;
|
|
2154
|
-
if(df>1e7)return normalQuantile(p);
|
|
2155
|
-
let lo=-1e4;
|
|
2156
|
-
let hi=1e4;
|
|
2157
|
-
let x=normalQuantile(p);
|
|
2158
|
-
const logBeta=logGamma(df/2)+logGamma(0.5)-logGamma((df+1)/2);
|
|
2159
|
-
for(let i=0;i<60;i++){
|
|
2160
|
-
const cdf=studentT(x,df);
|
|
2161
|
-
if(cdf<p)lo=x;else hi=x;
|
|
2162
|
-
const pdf=Math.exp(-((df+1)/2)*Math.log(1+(x*x)/df)-logBeta)
|
|
2163
|
-
/ Math.sqrt(df);
|
|
2164
|
-
const step=pdf>0?(cdf-p)/pdf:0;
|
|
2165
|
-
if(Math.abs(step)<1e-12)break;
|
|
2166
|
-
const next=x-step;
|
|
2167
|
-
x=next>lo&&next<hi&&Number.isFinite(next)?next:(lo+hi)/2;
|
|
2168
|
-
if(hi-lo<1e-12)break;
|
|
1963
|
+
return setTimeout(()=>fn({timeRemaining:()=>0,didTimeout:true}),1);
|
|
2169
1964
|
}
|
|
2170
|
-
|
|
1965
|
+
let idSeq=0;
|
|
1966
|
+
function uid(prefix='l'){
|
|
1967
|
+
return`${prefix}${(++idSeq).toString(36)}`;
|
|
2171
1968
|
}
|
|
2172
1969
|
});
|
|
2173
|
-
__def("packages/modules/charts/
|
|
1970
|
+
__def("packages/modules/charts/annotations.js",function(__exports,__req){
|
|
2174
1971
|
'use strict';
|
|
2175
|
-
Object.defineProperty(__exports,"
|
|
2176
|
-
Object.defineProperty(__exports,"
|
|
2177
|
-
Object.defineProperty(__exports,"
|
|
2178
|
-
Object.defineProperty(__exports,"
|
|
2179
|
-
Object.defineProperty(__exports,"
|
|
2180
|
-
Object.defineProperty(__exports,"trendText",{enumerable:true,get:function(){return trendText;}});
|
|
2181
|
-
Object.defineProperty(__exports,"drawTrendlines",{enumerable:true,get:function(){return drawTrendlines;}});
|
|
1972
|
+
Object.defineProperty(__exports,"overlayLayer",{enumerable:true,get:function(){return overlayLayer;}});
|
|
1973
|
+
Object.defineProperty(__exports,"annotationValue",{enumerable:true,get:function(){return annotationValue;}});
|
|
1974
|
+
Object.defineProperty(__exports,"annotationAxis",{enumerable:true,get:function(){return annotationAxis;}});
|
|
1975
|
+
Object.defineProperty(__exports,"annotationText",{enumerable:true,get:function(){return annotationText;}});
|
|
1976
|
+
Object.defineProperty(__exports,"drawAnnotations",{enumerable:true,get:function(){return drawAnnotations;}});
|
|
2182
1977
|
const __m0=__req("packages/modules/charts/frame.js");
|
|
2183
1978
|
const Pool=__m0["Pool"];
|
|
2184
|
-
const __m1=__req("packages/modules/charts/
|
|
2185
|
-
const
|
|
2186
|
-
const
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2189
|
-
const
|
|
2190
|
-
const
|
|
2191
|
-
const __m2
|
|
2192
|
-
const
|
|
1979
|
+
const __m1=__req("packages/modules/charts/scale.js");
|
|
1980
|
+
const isNumber=__m1["isNumber"];
|
|
1981
|
+
const toNumber=__m1["toNumber"];
|
|
1982
|
+
const toTime=__m1["toTime"];
|
|
1983
|
+
const __m2=__req("packages/modules/charts/svg.js");
|
|
1984
|
+
const attrs=__m2["attrs"];
|
|
1985
|
+
const path=__m2["path"];
|
|
1986
|
+
const round=__m2["round"];
|
|
1987
|
+
const setText=__m2["setText"];
|
|
1988
|
+
const SVG_NS=__m2["SVG_NS"];
|
|
2193
1989
|
const __m3=__req("packages/modules/charts/styles.js");
|
|
2194
1990
|
const NS=__m3["NS"];
|
|
2195
|
-
const __m4=__req("packages/
|
|
2196
|
-
const
|
|
2197
|
-
|
|
2198
|
-
const
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
linear:new Set(['linear','lr','ols','regression','least-squares']),
|
|
2202
|
-
movingAverage:new Set(['movingaverage','moving-average','ma','sma','rolling']),
|
|
2203
|
-
exponential:new Set(['exponential','exp','ewma','ses','holt','smoothing']),
|
|
2204
|
-
};
|
|
2205
|
-
const SMOOTH_LO=1e-4;
|
|
2206
|
-
const SMOOTH_HI=1-1e-4;
|
|
2207
|
-
function methodOf(name){
|
|
2208
|
-
const key=String(name||'linear').toLowerCase();
|
|
2209
|
-
if(METHODS.linear.has(key))return'linear';
|
|
2210
|
-
if(METHODS.movingAverage.has(key))return'movingAverage';
|
|
2211
|
-
if(METHODS.exponential.has(key))return'exponential';
|
|
2212
|
-
return null;
|
|
1991
|
+
const __m4=__req("packages/core/src/internal/util.js");
|
|
1992
|
+
const warnOnce=__m4["warnOnce"];
|
|
1993
|
+
function overlayLayer(group,className){
|
|
1994
|
+
for(const child of group.childNodes||[]){
|
|
1995
|
+
if(child&&String(child.getAttribute&&child.getAttribute('class'))===className){
|
|
1996
|
+
return(child);
|
|
2213
1997
|
}
|
|
2214
|
-
function normaliseTrends(trend){
|
|
2215
|
-
if(!trend)return[];
|
|
2216
|
-
const raw=Array.isArray(trend)?trend:[trend];
|
|
2217
|
-
const out=[];
|
|
2218
|
-
for(const entry of raw){
|
|
2219
|
-
if(entry===true){out.push({method:'linear'});continue;}
|
|
2220
|
-
if(typeof entry==='string'){
|
|
2221
|
-
const method=methodOf(entry);
|
|
2222
|
-
if(method)out.push({method});
|
|
2223
|
-
continue;
|
|
2224
1998
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
1999
|
+
const host=group.ownerDocument.createElementNS(SVG_NS,'g');
|
|
2000
|
+
host.setAttribute('class',className);
|
|
2001
|
+
group.appendChild(host);
|
|
2002
|
+
return host;
|
|
2003
|
+
}
|
|
2004
|
+
const KINDS=new Set(['line','target','band','callout','event']);
|
|
2005
|
+
function xNumber(scale,raw){
|
|
2006
|
+
return scale.kind==='time'?toTime(raw):toNumber(raw);
|
|
2007
|
+
}
|
|
2008
|
+
function xPixel(xScale,raw,edge){
|
|
2009
|
+
if(xScale.kind==='band'){
|
|
2010
|
+
const left=xScale.of(raw);
|
|
2011
|
+
if(!Number.isFinite(left))return NaN;
|
|
2012
|
+
const width=Number(xScale.bandwidth)||0;
|
|
2013
|
+
return edge==='right'?left+width:left;
|
|
2014
|
+
}
|
|
2015
|
+
const n=xNumber(xScale,raw);
|
|
2016
|
+
return n===null?NaN:xScale.of(n);
|
|
2017
|
+
}
|
|
2018
|
+
function warnDroppedAnnotation(anno,axis,reason){
|
|
2019
|
+
const kind=anno.kind||'line';
|
|
2020
|
+
const named=anno.label?` (${JSON.stringify(anno.label)})`:'';
|
|
2021
|
+
warnOnce(
|
|
2022
|
+
`chart:annotation:dropped:${kind}:${axis}:${reason}`,
|
|
2023
|
+
`chart annotation${named} of kind ${JSON.stringify(kind)}, reading the ${axis} axis, `
|
|
2024
|
+
+`was not drawn: ${reason}.`,
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
function xText(raw,fmt){
|
|
2028
|
+
if(raw instanceof Date){
|
|
2029
|
+
const t=raw.getTime();
|
|
2030
|
+
return Number.isFinite(t)?raw.toISOString().slice(0,10):String(raw);
|
|
2228
2031
|
}
|
|
2032
|
+
if(typeof raw==='number')return Number.isFinite(raw)?fmt(raw):String(raw);
|
|
2033
|
+
const n=toNumber(raw);
|
|
2034
|
+
return n===null||typeof raw==='string'?String(raw):fmt(n);
|
|
2229
2035
|
}
|
|
2230
|
-
|
|
2036
|
+
function poolFor(series,anno,axis){
|
|
2037
|
+
const out=[];
|
|
2038
|
+
for(const s of series){
|
|
2039
|
+
const side=s.axis==='right'?'right':'left';
|
|
2040
|
+
if(side!==axis)continue;
|
|
2041
|
+
if(anno.series!==undefined&&s.key!==anno.series)continue;
|
|
2042
|
+
for(const p of s.points)if(isNumber(p.y))out.push(Number(p.y));
|
|
2231
2043
|
}
|
|
2232
|
-
|
|
2233
|
-
if(scale.kind==='band')return scale.centre(rawX);
|
|
2234
|
-
const n=scale.kind==='time'?toTime(rawX):toNumber(rawX);
|
|
2235
|
-
return n===null?NaN:scale.of(n);
|
|
2044
|
+
return out;
|
|
2236
2045
|
}
|
|
2237
|
-
function
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2046
|
+
function percentile(values,p){
|
|
2047
|
+
if(!values.length)return null;
|
|
2048
|
+
const sorted=[...values].sort((a,b)=>a-b);
|
|
2049
|
+
if(sorted.length===1)return sorted[0];
|
|
2050
|
+
const rank=(Math.min(100,Math.max(0,p))/100)*(sorted.length-1);
|
|
2051
|
+
const low=Math.floor(rank);
|
|
2052
|
+
const high=Math.ceil(rank);
|
|
2053
|
+
if(low===high)return sorted[low];
|
|
2054
|
+
return sorted[low]+(sorted[high]-sorted[low])*(rank-low);
|
|
2242
2055
|
}
|
|
2243
|
-
|
|
2056
|
+
function annotationValue(anno,series,axis){
|
|
2057
|
+
if(!anno.compute){
|
|
2058
|
+
return toNumber(anno.value);
|
|
2244
2059
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
if(x===null||!Number.isFinite(x)||!Number.isFinite(y))continue;
|
|
2251
|
-
pairs.push({x,y});
|
|
2060
|
+
const values=poolFor(series,anno,axis);
|
|
2061
|
+
if(!values.length)return null;
|
|
2062
|
+
const compute=String(anno.compute).toLowerCase();
|
|
2063
|
+
if(compute==='mean'||compute==='avg'){
|
|
2064
|
+
return values.reduce((t,v)=>t+v,0)/values.length;
|
|
2252
2065
|
}
|
|
2253
|
-
|
|
2254
|
-
return
|
|
2066
|
+
if(compute==='median'||compute==='p50')return percentile(values,50);
|
|
2067
|
+
if(compute==='min')return Math.min(...values);
|
|
2068
|
+
if(compute==='max')return Math.max(...values);
|
|
2069
|
+
const match=/^p(\d+(?:\.\d+)?)$/.exec(compute);
|
|
2070
|
+
if(match)return percentile(values,Number(match[1]));
|
|
2071
|
+
return null;
|
|
2255
2072
|
}
|
|
2256
|
-
function
|
|
2257
|
-
|
|
2258
|
-
if(n<2)return null;
|
|
2259
|
-
let mx=0;
|
|
2260
|
-
let my=0;
|
|
2261
|
-
for(const p of pairs){mx+=p.x;my+=p.y;}
|
|
2262
|
-
mx/=n;
|
|
2263
|
-
my/=n;
|
|
2264
|
-
let sxx=0;
|
|
2265
|
-
let sxy=0;
|
|
2266
|
-
let syy=0;
|
|
2267
|
-
for(const p of pairs){
|
|
2268
|
-
const dx=p.x-mx;
|
|
2269
|
-
const dy=p.y-my;
|
|
2270
|
-
sxx+=dx*dx;
|
|
2271
|
-
sxy+=dx*dy;
|
|
2272
|
-
syy+=dy*dy;
|
|
2073
|
+
function annotationAxis(anno){
|
|
2074
|
+
return anno.axis==='right'||anno.axis==='y2'?'right':'left';
|
|
2273
2075
|
}
|
|
2274
|
-
|
|
2275
|
-
const
|
|
2276
|
-
const
|
|
2277
|
-
const
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
const
|
|
2281
|
-
|
|
2282
|
-
const projected=[];
|
|
2283
|
-
let band=null;
|
|
2284
|
-
const steps=Math.max(0,Math.floor(Number(forecast)||0));
|
|
2285
|
-
if(steps>0&&hi>lo){
|
|
2286
|
-
const step=(hi-lo)/(n-1);
|
|
2287
|
-
if(step>0){
|
|
2288
|
-
projected.push(at(hi),at(hi+steps*step));
|
|
2289
|
-
if(n>2){
|
|
2290
|
-
const conf=Number.isFinite(opts.confidence)
|
|
2291
|
-
&&opts.confidence>0&&opts.confidence<1?Number(opts.confidence):0.95;
|
|
2292
|
-
const tail=1-(1-conf)/2;
|
|
2293
|
-
const sse=Math.max(0,syy-slope*sxy);
|
|
2294
|
-
const s=Math.sqrt(sse/(n-2));
|
|
2295
|
-
const t=studentTQuantile(tail,n-2);
|
|
2296
|
-
const points=[];
|
|
2297
|
-
for(let h=0;h<=steps;h++){
|
|
2298
|
-
const x0=hi+h*step;
|
|
2299
|
-
const mean=intercept+slope*x0;
|
|
2300
|
-
const leverage=1/n+((x0-mx)**2)/sxx;
|
|
2301
|
-
const sePred=s*Math.sqrt(1+leverage);
|
|
2302
|
-
const seMean=s*Math.sqrt(leverage);
|
|
2303
|
-
points.push({
|
|
2304
|
-
x:x0,
|
|
2305
|
-
mean,
|
|
2306
|
-
lower:mean-t*sePred,
|
|
2307
|
-
upper:mean+t*sePred,
|
|
2308
|
-
lowerMean:mean-t*seMean,
|
|
2309
|
-
upperMean:mean+t*seMean,
|
|
2310
|
-
});
|
|
2076
|
+
function annotationText(anno,resolved,fmt,dual){
|
|
2077
|
+
const label=anno.label?`${anno.label}: `:'';
|
|
2078
|
+
const axis=dual?` (${annotationAxis(anno)==='right'?'right axis':'left axis'})`:'';
|
|
2079
|
+
const kind=anno.kind||'line';
|
|
2080
|
+
if(kind==='band'){
|
|
2081
|
+
if(!Array.isArray(resolved)||resolved[0]===null||resolved[1]===null)return'';
|
|
2082
|
+
const[lo,hi]=resolved;
|
|
2083
|
+
return`${label||'Band: '}${fmt(Math.min(lo,hi))} to ${fmt(Math.max(lo,hi))}${axis}`;
|
|
2311
2084
|
}
|
|
2312
|
-
|
|
2085
|
+
if(resolved===null||resolved===undefined)return'';
|
|
2086
|
+
const noun=kind==='target'?'Target':(kind==='callout'?'Callout':'Reference');
|
|
2087
|
+
return`${label||`${noun}: `}${fmt((resolved))}${axis}`;
|
|
2313
2088
|
}
|
|
2089
|
+
function bandFirst(x){
|
|
2090
|
+
return(x.kind||'line')==='band'?0:1;
|
|
2314
2091
|
}
|
|
2092
|
+
function drawAnnotations(opts){
|
|
2093
|
+
const{
|
|
2094
|
+
group,plot,xScale,yScale,rightScale,series,format,
|
|
2095
|
+
}=opts;
|
|
2096
|
+
const pool=new Pool(overlayLayer(group,`${NS}__annotations`));
|
|
2097
|
+
const described=[];
|
|
2098
|
+
const list=Array.isArray(opts.annotations)?opts.annotations:[];
|
|
2099
|
+
const ordered=[...list].sort((a,b)=>bandFirst(a)-bandFirst(b));
|
|
2100
|
+
for(const anno of ordered){
|
|
2101
|
+
const kind=anno.kind||'line';
|
|
2102
|
+
if(!KINDS.has(kind))continue;
|
|
2103
|
+
const axis=annotationAxis(anno);
|
|
2104
|
+
const scale=axis==='right'&&rightScale?rightScale:yScale;
|
|
2105
|
+
if(kind==='band'){
|
|
2106
|
+
if(anno.orient==='vertical'){
|
|
2107
|
+
const x1=xPixel(xScale,anno.from,'left');
|
|
2108
|
+
const x2=xPixel(xScale,anno.to,'right');
|
|
2109
|
+
if(Number.isNaN(x1)||Number.isNaN(x2)){
|
|
2110
|
+
const edge=Number.isNaN(x1)&&Number.isNaN(x2)?'from and to':(Number.isNaN(x1)?'from':'to');
|
|
2111
|
+
warnDroppedAnnotation(anno,axis,`its ${edge} value could not be placed on the x scale`);
|
|
2112
|
+
continue;
|
|
2315
2113
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2114
|
+
const left=round(Math.min(x1,x2));
|
|
2115
|
+
const right=round(Math.max(x1,x2));
|
|
2116
|
+
attrs(pool.next('rect',`${NS}__annotation-band ${anno.className||''}`.trim()),{
|
|
2117
|
+
x:left,
|
|
2118
|
+
y:round(plot.top),
|
|
2119
|
+
width:Math.max(0,right-left),
|
|
2120
|
+
height:round(Math.max(0,plot.bottom-plot.top)),
|
|
2121
|
+
fill:anno.colour||'currentColor',
|
|
2122
|
+
'fill-opacity':anno.opacity===undefined?0.12:anno.opacity,
|
|
2123
|
+
});
|
|
2124
|
+
if(anno.label){
|
|
2125
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2126
|
+
attrs(text,{x:left+4,y:round(plot.top+12),'text-anchor':'start'});
|
|
2127
|
+
setText(text,anno.label);
|
|
2325
2128
|
}
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
let sum=0;
|
|
2330
|
-
const fit=[];
|
|
2331
|
-
for(const row of seq){
|
|
2332
|
-
if(Number.isFinite(row.value)){
|
|
2333
|
-
ring.push(row.value);
|
|
2334
|
-
sum+=row.value;
|
|
2335
|
-
if(ring.length>span)sum-=ring.shift();
|
|
2129
|
+
const noun=anno.label?`${anno.label}: `:'Event window: ';
|
|
2130
|
+
described.push({text:`${noun}${xText(anno.from,format)} to ${xText(anno.to,format)}`});
|
|
2131
|
+
continue;
|
|
2336
2132
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2133
|
+
const from=annotationValue({...anno,value:anno.from,compute:anno.fromCompute},series,axis);
|
|
2134
|
+
const to=annotationValue({...anno,value:anno.to,compute:anno.toCompute},series,axis);
|
|
2135
|
+
if(from===null||to===null)continue;
|
|
2136
|
+
const y1=round(scale.of(from));
|
|
2137
|
+
const y2=round(scale.of(to));
|
|
2138
|
+
attrs(pool.next('rect',`${NS}__annotation-band ${anno.className||''}`.trim()),{
|
|
2139
|
+
x:round(plot.left),
|
|
2140
|
+
y:Math.min(y1,y2),
|
|
2141
|
+
width:round(Math.max(0,plot.right-plot.left)),
|
|
2142
|
+
height:Math.max(0,Math.abs(y2-y1)),
|
|
2143
|
+
fill:anno.colour||'currentColor',
|
|
2144
|
+
'fill-opacity':anno.opacity===undefined?0.12:anno.opacity,
|
|
2145
|
+
});
|
|
2146
|
+
if(anno.label){
|
|
2147
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2148
|
+
attrs(text,{x:round(plot.left+4),y:Math.min(y1,y2)+12,'text-anchor':'start'});
|
|
2149
|
+
setText(text,anno.label);
|
|
2339
2150
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2151
|
+
described.push({text:annotationText(anno,[from,to],format,opts.dual)});
|
|
2152
|
+
continue;
|
|
2342
2153
|
}
|
|
2343
|
-
|
|
2344
|
-
const
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
for(let i=0;i<n;i++){
|
|
2349
|
-
const v=y[i];
|
|
2350
|
-
if(!Number.isFinite(v)){
|
|
2351
|
-
if(level!==null)smoothed[i]=level;
|
|
2154
|
+
if(kind==='event'){
|
|
2155
|
+
const raw=anno.x!==undefined?anno.x:anno.at;
|
|
2156
|
+
const at=round(xPixel(xScale,raw,'left')+(xScale.kind==='band'?(Number(xScale.bandwidth)||0)/2:0));
|
|
2157
|
+
if(Number.isNaN(at)){
|
|
2158
|
+
warnDroppedAnnotation(anno,axis,'its x value could not be placed on the x scale');
|
|
2352
2159
|
continue;
|
|
2353
2160
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2161
|
+
attrs(pool.next('path',`${NS}__annotation-event`),{
|
|
2162
|
+
d:path(['M',at,round(plot.top),'L',at,round(plot.bottom)]),
|
|
2163
|
+
stroke:anno.colour||'currentColor',
|
|
2164
|
+
fill:'none',
|
|
2165
|
+
});
|
|
2166
|
+
attrs(pool.next('circle',`${NS}__annotation-event-flag`),{
|
|
2167
|
+
cx:at,cy:round(plot.top),r:3,fill:anno.colour||'currentColor',
|
|
2168
|
+
});
|
|
2169
|
+
if(anno.label){
|
|
2170
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2171
|
+
attrs(text,{x:at+5,y:round(plot.top+10),'text-anchor':'start'});
|
|
2172
|
+
setText(text,anno.label);
|
|
2358
2173
|
}
|
|
2359
|
-
|
|
2174
|
+
const noun=anno.label?`${anno.label} — `:'Event — ';
|
|
2175
|
+
described.push({text:`${noun}at ${xText(raw,format)}`});
|
|
2176
|
+
continue;
|
|
2360
2177
|
}
|
|
2361
|
-
|
|
2362
|
-
const
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
if(level!==null){level+=trend;smoothed[i]=level;}
|
|
2178
|
+
if(kind==='callout'){
|
|
2179
|
+
const value=annotationValue(anno,series,axis);
|
|
2180
|
+
if(value===null)continue;
|
|
2181
|
+
const cx=anno.at!==undefined
|
|
2182
|
+
?round(xScale.kind==='band'?xScale.centre(anno.at):xScale.of(xNumber(xScale,anno.at)??NaN))
|
|
2183
|
+
:round(plot.right-4);
|
|
2184
|
+
const cy=round(scale.of(value));
|
|
2185
|
+
if(Number.isNaN(cx)){
|
|
2186
|
+
warnDroppedAnnotation(anno,axis,'its x value could not be placed on the x scale');
|
|
2371
2187
|
continue;
|
|
2372
2188
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2189
|
+
attrs(pool.next('circle',`${NS}__annotation-point`),{
|
|
2190
|
+
cx,cy,r:3.5,fill:anno.colour||'currentColor',
|
|
2191
|
+
});
|
|
2192
|
+
if(anno.label){
|
|
2193
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2194
|
+
attrs(text,{x:cx+6,y:cy-6,'text-anchor':'start'});
|
|
2195
|
+
setText(text,anno.label);
|
|
2196
|
+
}
|
|
2197
|
+
described.push({text:annotationText(anno,value,format,opts.dual)});
|
|
2382
2198
|
continue;
|
|
2383
2199
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
const
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2200
|
+
if(anno.orient==='vertical'||anno.x!==undefined){
|
|
2201
|
+
const raw=anno.x!==undefined?anno.x:anno.value;
|
|
2202
|
+
const at=xScale.kind==='band'
|
|
2203
|
+
?round(xScale.centre(raw))
|
|
2204
|
+
:round(xScale.of(xNumber(xScale,raw)??NaN));
|
|
2205
|
+
if(Number.isNaN(at)){
|
|
2206
|
+
warnDroppedAnnotation(anno,axis,'its x value could not be placed on the x scale');
|
|
2207
|
+
continue;
|
|
2390
2208
|
}
|
|
2391
|
-
|
|
2209
|
+
const cls=kind==='target'?`${NS}__annotation-target`:`${NS}__annotation-line`;
|
|
2210
|
+
attrs(pool.next('path',cls),{
|
|
2211
|
+
d:path(['M',at,round(plot.top),'L',at,round(plot.bottom)]),
|
|
2212
|
+
stroke:anno.colour||'currentColor',
|
|
2213
|
+
fill:'none',
|
|
2214
|
+
});
|
|
2215
|
+
if(anno.label){
|
|
2216
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2217
|
+
attrs(text,{
|
|
2218
|
+
x:at+4,y:round(plot.top+10),'text-anchor':'start',
|
|
2219
|
+
});
|
|
2220
|
+
setText(text,anno.label);
|
|
2392
2221
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
let a=lo;
|
|
2396
|
-
let b=hi;
|
|
2397
|
-
let c=b-invphi*(b-a);
|
|
2398
|
-
let d=a+invphi*(b-a);
|
|
2399
|
-
let fc=f(c);
|
|
2400
|
-
let fd=f(d);
|
|
2401
|
-
for(let i=0;i<iters;i++){
|
|
2402
|
-
if(fc<fd){b=d;d=c;fd=fc;c=b-invphi*(b-a);fc=f(c);}
|
|
2403
|
-
else{a=c;c=d;fc=fd;d=a+invphi*(b-a);fd=f(d);}
|
|
2222
|
+
described.push({text:anno.label?`${anno.label} — at ${xText(raw,format)}`:''});
|
|
2223
|
+
continue;
|
|
2404
2224
|
}
|
|
2405
|
-
|
|
2225
|
+
const value=annotationValue(anno,series,axis);
|
|
2226
|
+
if(value===null)continue;
|
|
2227
|
+
const at=round(scale.of(value));
|
|
2228
|
+
const cls=kind==='target'?`${NS}__annotation-target`:`${NS}__annotation-line`;
|
|
2229
|
+
attrs(pool.next('path',cls),{
|
|
2230
|
+
d:path(['M',round(plot.left),at,'L',round(plot.right),at]),
|
|
2231
|
+
stroke:anno.colour||'currentColor',
|
|
2232
|
+
fill:'none',
|
|
2233
|
+
});
|
|
2234
|
+
if(anno.label){
|
|
2235
|
+
const text=pool.next('text',`${NS}__annotation-label`);
|
|
2236
|
+
attrs(text,{x:round(plot.right-4),y:at-4,'text-anchor':'end'});
|
|
2237
|
+
setText(text,anno.label);
|
|
2406
2238
|
}
|
|
2407
|
-
|
|
2408
|
-
const holt=String(spec.kind||spec.model||'').toLowerCase()==='holt';
|
|
2409
|
-
const y=seq.map((row)=>(Number.isFinite(row.value)?row.value:null));
|
|
2410
|
-
const finite=y.filter((v)=>v!==null).length;
|
|
2411
|
-
if(finite<(holt?2:1))return null;
|
|
2412
|
-
const clamp=(x)=>Math.min(SMOOTH_HI,Math.max(SMOOTH_LO,x));
|
|
2413
|
-
let alpha=Number.isFinite(spec.alpha)?clamp(Number(spec.alpha)):null;
|
|
2414
|
-
let beta=holt&&Number.isFinite(spec.beta)?clamp(Number(spec.beta)):null;
|
|
2415
|
-
if(holt){
|
|
2416
|
-
if(alpha===null||beta===null){
|
|
2417
|
-
let a=alpha===null?0.5:alpha;
|
|
2418
|
-
let b=beta===null?0.5:beta;
|
|
2419
|
-
for(let r=0;r<6;r++){
|
|
2420
|
-
if(alpha===null)a=goldenMin((x)=>runHolt(y,x,b).sse,SMOOTH_LO,SMOOTH_HI);
|
|
2421
|
-
if(beta===null)b=goldenMin((x)=>runHolt(y,a,x).sse,SMOOTH_LO,SMOOTH_HI);
|
|
2239
|
+
described.push({text:annotationText(anno,value,format,opts.dual)});
|
|
2422
2240
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2241
|
+
pool.finish();
|
|
2242
|
+
return described.filter((d)=>d.text);
|
|
2425
2243
|
}
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2244
|
+
});
|
|
2245
|
+
__def("packages/modules/charts/combo.js",function(__exports,__req){
|
|
2246
|
+
'use strict';
|
|
2247
|
+
Object.defineProperty(__exports,"toPareto",{enumerable:true,get:function(){return toPareto;}});
|
|
2248
|
+
Object.defineProperty(__exports,"drawCombo",{enumerable:true,get:function(){return drawCombo;}});
|
|
2249
|
+
Object.defineProperty(__exports,"drawRightAxis",{enumerable:true,get:function(){return drawRightAxis;}});
|
|
2250
|
+
const __m0=__req("packages/modules/charts/axis.js");
|
|
2251
|
+
const drawAxisLines=__m0["drawAxisLines"];
|
|
2252
|
+
const drawCategoryAxis=__m0["drawCategoryAxis"];
|
|
2253
|
+
const drawContinuousAxis=__m0["drawContinuousAxis"];
|
|
2254
|
+
const drawMeasureAxis=__m0["drawMeasureAxis"];
|
|
2255
|
+
const overhangFor=__m0["overhangFor"];
|
|
2256
|
+
const setPlotClip=__m0["setPlotClip"];
|
|
2257
|
+
const __m1=__req("packages/modules/charts/frame.js");
|
|
2258
|
+
const Pool=__m1["Pool"];
|
|
2259
|
+
const shouldRotate=__m1["shouldRotate"];
|
|
2260
|
+
const __m2=__req("packages/modules/charts/format.js");
|
|
2261
|
+
const formatters=__m2["formatters"];
|
|
2262
|
+
const __m3=__req("packages/modules/charts/scale.js");
|
|
2263
|
+
const bandScale=__m3["bandScale"];
|
|
2264
|
+
const extent=__m3["extent"];
|
|
2265
|
+
const isNumber=__m3["isNumber"];
|
|
2266
|
+
const linearScale=__m3["linearScale"];
|
|
2267
|
+
const measureDomain=__m3["measureDomain"];
|
|
2268
|
+
const timeScale=__m3["timeScale"];
|
|
2269
|
+
const toNumber=__m3["toNumber"];
|
|
2270
|
+
const toTime=__m3["toTime"];
|
|
2271
|
+
const __m4=__req("packages/modules/charts/svg.js");
|
|
2272
|
+
const attrs=__m4["attrs"];
|
|
2273
|
+
const path=__m4["path"];
|
|
2274
|
+
const round=__m4["round"];
|
|
2275
|
+
const __m5=__req("packages/modules/charts/styles.js");
|
|
2276
|
+
const NS=__m5["NS"];
|
|
2277
|
+
const __m6=__req("packages/modules/charts/scheme.js");
|
|
2278
|
+
const resolveScheme=__m6["resolveScheme"];
|
|
2279
|
+
const __m7=__req("packages/modules/charts/labels.js");
|
|
2280
|
+
const drawDataLabels=__m7["drawDataLabels"];
|
|
2281
|
+
const __m8=__req("packages/modules/charts/annotations.js");
|
|
2282
|
+
const drawAnnotations=__m8["drawAnnotations"];
|
|
2283
|
+
function byAxis(series){
|
|
2284
|
+
return{
|
|
2285
|
+
left:series.filter((s)=>s.axis!=='right'),
|
|
2286
|
+
right:series.filter((s)=>s.axis==='right'),
|
|
2287
|
+
};
|
|
2428
2288
|
}
|
|
2429
|
-
|
|
2430
|
-
const
|
|
2431
|
-
for(
|
|
2432
|
-
|
|
2433
|
-
if(level===null||!Number.isFinite(level))continue;
|
|
2434
|
-
fit.push({x:seq[i].rawX,y:level});
|
|
2289
|
+
function domainFor(series,zero){
|
|
2290
|
+
const values=[];
|
|
2291
|
+
for(const s of series)for(const p of s.points)values.push(p.y);
|
|
2292
|
+
return measureDomain(values,{zero});
|
|
2435
2293
|
}
|
|
2436
|
-
|
|
2294
|
+
function toPareto(bound){
|
|
2295
|
+
const source=bound.series[0];
|
|
2296
|
+
if(!source)return bound;
|
|
2297
|
+
const ranked=source.points
|
|
2298
|
+
.map((point,i)=>({point,label:bound.labels[i],category:bound.categories[i]}))
|
|
2299
|
+
.filter((entry)=>isNumber(entry.point.y))
|
|
2300
|
+
.sort((a,b)=>(b.point.y)-(a.point.y));
|
|
2301
|
+
const total=ranked.reduce((t,entry)=>t+(entry.point.y),0);
|
|
2302
|
+
let running=0;
|
|
2303
|
+
const cumulative=ranked.map((entry)=>{
|
|
2304
|
+
running+=(entry.point.y);
|
|
2305
|
+
return total>0?(running/total)*100:0;
|
|
2306
|
+
});
|
|
2437
2307
|
return{
|
|
2438
|
-
|
|
2308
|
+
...bound,
|
|
2309
|
+
categories:ranked.map((entry)=>entry.category),
|
|
2310
|
+
labels:ranked.map((entry)=>entry.label),
|
|
2311
|
+
series:[
|
|
2312
|
+
{
|
|
2313
|
+
...source,
|
|
2314
|
+
index:0,
|
|
2315
|
+
mark:'bar',
|
|
2316
|
+
axis:'left',
|
|
2317
|
+
points:ranked.map((entry)=>entry.point),
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
key:'cumulative',
|
|
2321
|
+
label:bound.cumulativeLabel||'%',
|
|
2322
|
+
index:1,
|
|
2323
|
+
mark:'line',
|
|
2324
|
+
axis:'right',
|
|
2325
|
+
points:ranked.map((entry,i)=>({
|
|
2326
|
+
x:entry.category,
|
|
2327
|
+
xKey:entry.point.xKey,
|
|
2328
|
+
label:entry.label,
|
|
2329
|
+
y:cumulative[i],
|
|
2330
|
+
rows:entry.point.rows,
|
|
2331
|
+
rowKey:entry.point.rowKey,
|
|
2332
|
+
})),
|
|
2333
|
+
},
|
|
2334
|
+
],
|
|
2439
2335
|
};
|
|
2440
2336
|
}
|
|
2441
|
-
function
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
return
|
|
2337
|
+
function comboXScale(bound,plot){
|
|
2338
|
+
const range=([plot.left,plot.right]);
|
|
2339
|
+
if(bound.kind!=='time'&&bound.kind!=='linear'){
|
|
2340
|
+
return bandScale(bound.categories,range,0.2);
|
|
2445
2341
|
}
|
|
2446
|
-
const
|
|
2447
|
-
|
|
2448
|
-
|
|
2342
|
+
const numbers=bound.kind==='time'
|
|
2343
|
+
?bound.categories.map(toTime)
|
|
2344
|
+
:bound.categories.map(toNumber);
|
|
2345
|
+
if(bound.kind==='time'){
|
|
2346
|
+
const found=extent(numbers);
|
|
2347
|
+
if(found&&found.min===found.max){
|
|
2348
|
+
return timeScale({min:found.min-30000,max:found.max+30000},range);
|
|
2449
2349
|
}
|
|
2450
|
-
return exponentialTrend(seq,spec);
|
|
2451
2350
|
}
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
if(stats.method==='linear'){
|
|
2455
|
-
const r2=Number.isFinite(stats.r2)?`, R² ${stats.r2.toFixed(2)}`:'';
|
|
2456
|
-
let text=`Trend (linear)${who}: slope ${fmt(stats.slope)}${r2}`;
|
|
2457
|
-
if(stats.forecast>0&&forecast&&forecast.length){
|
|
2458
|
-
const end=forecast[forecast.length-1];
|
|
2459
|
-
text+=`; forecast ${stats.forecast} step${stats.forecast===1?'':'s'} ahead to ${fmt(end.y)}`;
|
|
2460
|
-
if(band&&band.points.length){
|
|
2461
|
-
const last=band.points[band.points.length-1];
|
|
2462
|
-
const mean=bandKind==='confidence'||bandKind==='mean';
|
|
2463
|
-
const lo=mean?last.lowerMean:last.lower;
|
|
2464
|
-
const up=mean?last.upperMean:last.upper;
|
|
2465
|
-
const kind=mean?'confidence':'prediction';
|
|
2466
|
-
const pct=Math.round(band.confidence*100);
|
|
2467
|
-
text+=`; ${pct}% ${kind} band ${fmt(lo)} to ${fmt(up)} at the horizon`;
|
|
2351
|
+
const domain=measureDomain(numbers,{zero:false,nice:bound.kind!=='time'});
|
|
2352
|
+
return bound.kind==='time'?timeScale(domain,range):linearScale(domain,range);
|
|
2468
2353
|
}
|
|
2354
|
+
function continuousBarWidth(numbers,scale){
|
|
2355
|
+
const distinct=[...new Set(numbers.filter((n)=>Number.isFinite(n)))]
|
|
2356
|
+
.sort((a,b)=>(a)-(b));
|
|
2357
|
+
if(distinct.length<2){
|
|
2358
|
+
const[from,to]=scale.range;
|
|
2359
|
+
return Math.max(4,(to-from)/10);
|
|
2360
|
+
}
|
|
2361
|
+
const gaps=[];
|
|
2362
|
+
for(let i=1;i<distinct.length;i++){
|
|
2363
|
+
gaps.push((distinct[i])-(distinct[i-1]));
|
|
2364
|
+
}
|
|
2365
|
+
gaps.sort((a,b)=>a-b);
|
|
2366
|
+
const mid=Math.floor(gaps.length/2);
|
|
2367
|
+
const medianGap=gaps.length%2?gaps[mid]:(gaps[mid-1]+gaps[mid])/2;
|
|
2368
|
+
const pxGap=Math.abs(
|
|
2369
|
+
scale.of((distinct[0])+medianGap)-scale.of((distinct[0])),
|
|
2370
|
+
);
|
|
2371
|
+
return Math.max(1,pxGap*0.8);
|
|
2469
2372
|
}
|
|
2470
|
-
|
|
2373
|
+
function drawCombo(ctx){
|
|
2374
|
+
const scheme=ctx.scheme||resolveScheme();
|
|
2375
|
+
const{plot}=ctx;
|
|
2376
|
+
const bound=ctx.pareto?toPareto(ctx.bound):ctx.bound;
|
|
2377
|
+
const visible=bound.series.filter((s)=>!ctx.hidden.has(s.key));
|
|
2378
|
+
const sides=byAxis(visible);
|
|
2379
|
+
const hasBars=sides.left.some((s)=>(s.mark||'bar')==='bar');
|
|
2380
|
+
const leftDomain=domainFor(sides.left,hasBars);
|
|
2381
|
+
const yScale=linearScale(leftDomain,[plot.bottom,plot.top]);
|
|
2382
|
+
const rightDomain=sides.right.length
|
|
2383
|
+
?(ctx.pareto?{min:0,max:100}:domainFor(sides.right,false))
|
|
2384
|
+
:null;
|
|
2385
|
+
const rightScale=rightDomain?linearScale(rightDomain,[plot.bottom,plot.top]):null;
|
|
2386
|
+
const xScale=comboXScale(bound,plot);
|
|
2387
|
+
const continuousX=xScale.kind!=='band';
|
|
2388
|
+
const xNumbers=continuousX
|
|
2389
|
+
?bound.categories.map((v)=>(bound.kind==='time'?toTime(v):toNumber(v)))
|
|
2390
|
+
:null;
|
|
2391
|
+
drawMeasureAxis({
|
|
2392
|
+
gridGroup:ctx.groups.grid,
|
|
2393
|
+
axisGroup:ctx.groups.axis,
|
|
2394
|
+
plot,
|
|
2395
|
+
scale:yScale,
|
|
2396
|
+
format:formatters(ctx.grid,{
|
|
2397
|
+
kind:'linear',step:(leftDomain.max-leftDomain.min)/5,
|
|
2398
|
+
}),
|
|
2399
|
+
});
|
|
2400
|
+
if(continuousX){
|
|
2401
|
+
drawContinuousAxis({
|
|
2402
|
+
group:ctx.groups.overlay,
|
|
2403
|
+
plot,
|
|
2404
|
+
scale:xScale,
|
|
2405
|
+
format:formatters(ctx.grid,{
|
|
2406
|
+
kind:bound.kind,
|
|
2407
|
+
span:xScale.domain.max-xScale.domain.min,
|
|
2408
|
+
step:(xScale.domain.max-xScale.domain.min)/5,
|
|
2409
|
+
}),
|
|
2410
|
+
grid:ctx.grid,
|
|
2411
|
+
size:ctx.fontSize,
|
|
2412
|
+
});
|
|
2413
|
+
}else{
|
|
2414
|
+
drawCategoryAxis({
|
|
2415
|
+
group:ctx.groups.overlay,
|
|
2416
|
+
plot,
|
|
2417
|
+
scale:xScale,
|
|
2418
|
+
labels:bound.labels,
|
|
2419
|
+
fontSize:ctx.fontSize,
|
|
2420
|
+
rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize),
|
|
2421
|
+
});
|
|
2471
2422
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2423
|
+
drawAxisLines({group:ctx.groups.rules,plot});
|
|
2424
|
+
if(rightScale){
|
|
2425
|
+
drawRightAxis({
|
|
2426
|
+
group:ctx.groups.axis,
|
|
2427
|
+
plot,
|
|
2428
|
+
scale:rightScale,
|
|
2429
|
+
colour:scheme.series(sides.right[0].index),
|
|
2430
|
+
format:formatters(ctx.grid,{
|
|
2431
|
+
kind:'linear',step:(rightDomain.max-rightDomain.min)/5,
|
|
2432
|
+
}),
|
|
2433
|
+
suffix:ctx.pareto?'%':'',
|
|
2434
|
+
});
|
|
2474
2435
|
}
|
|
2475
|
-
|
|
2476
|
-
const
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2436
|
+
setPlotClip(ctx.groups,plot,overhangFor(ctx.type));
|
|
2437
|
+
const pool=new Pool(ctx.groups.marks);
|
|
2438
|
+
const bars=visible.filter((s)=>(s.mark||'bar')==='bar');
|
|
2439
|
+
const barWidth=continuousX?continuousBarWidth(xNumbers,xScale):xScale.bandwidth;
|
|
2440
|
+
const slot=bars.length?barWidth/bars.length:barWidth;
|
|
2441
|
+
let barIndex=0;
|
|
2442
|
+
for(const series of visible){
|
|
2443
|
+
const mark=series.mark||'bar';
|
|
2444
|
+
const scale=series.axis==='right'&&rightScale?rightScale:yScale;
|
|
2445
|
+
const colour=scheme.series(series.index);
|
|
2446
|
+
if(mark==='bar'){
|
|
2447
|
+
const offset=barIndex*slot;
|
|
2448
|
+
barIndex++;
|
|
2449
|
+
const base=scale.of(Math.max(scale.domain.min,0));
|
|
2450
|
+
for(let i=0;i<series.points.length;i++){
|
|
2451
|
+
const point=series.points[i];
|
|
2452
|
+
if(!isNumber(point.y))continue;
|
|
2453
|
+
let start;
|
|
2454
|
+
if(continuousX){
|
|
2455
|
+
const n=bound.kind==='time'?toTime(point.x):toNumber(point.x);
|
|
2456
|
+
start=n===null?NaN:xScale.of(n)-barWidth/2;
|
|
2457
|
+
}else{
|
|
2458
|
+
start=xScale.of(point.x);
|
|
2479
2459
|
}
|
|
2480
|
-
|
|
2481
|
-
const
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2460
|
+
if(Number.isNaN(start))continue;
|
|
2461
|
+
const top=scale.of((point.y));
|
|
2462
|
+
attrs(pool.next('rect',`${NS}__bar ${NS}__mark`),{
|
|
2463
|
+
x:round(start+offset),
|
|
2464
|
+
y:round(Math.min(top,base)),
|
|
2465
|
+
width:round(Math.max(0,slot)),
|
|
2466
|
+
height:round(Math.max(1,Math.abs(base-top))),
|
|
2467
|
+
fill:colour,
|
|
2468
|
+
'data-series':series.index,
|
|
2469
|
+
'data-point':i,
|
|
2470
|
+
});
|
|
2471
|
+
point.px=round(start+offset+slot/2);
|
|
2472
|
+
point.py=round(Math.min(top,base));
|
|
2489
2473
|
}
|
|
2474
|
+
continue;
|
|
2490
2475
|
}
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2476
|
+
const commands=[];
|
|
2477
|
+
let open=false;
|
|
2478
|
+
for(const point of series.points){
|
|
2479
|
+
if(!isNumber(point.y)){open=false;continue;}
|
|
2480
|
+
let x;
|
|
2481
|
+
if(continuousX){
|
|
2482
|
+
const n=bound.kind==='time'?toTime(point.x):toNumber(point.x);
|
|
2483
|
+
x=n===null?NaN:round(xScale.of(n));
|
|
2484
|
+
}else{
|
|
2485
|
+
x=round(xScale.centre(point.x));
|
|
2495
2486
|
}
|
|
2496
|
-
if(
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
const yScale=(series.axis==='right'&&opts.rightScale)?opts.rightScale:opts.yScale;
|
|
2503
|
-
const overlay=computeTrend(series,spec,opts.xScale);
|
|
2504
|
-
if(!overlay)continue;
|
|
2505
|
-
const colour=opts.scheme.series(series.index);
|
|
2506
|
-
const line=[];
|
|
2507
|
-
for(const point of overlay.fit){
|
|
2508
|
-
const px=placeX(opts.xScale,point.x);
|
|
2509
|
-
const py=yScale.of(point.y);
|
|
2510
|
-
if(!Number.isFinite(px)||!Number.isFinite(py))continue;
|
|
2511
|
-
line.push(line.length?'L':'M',round(px),round(py));
|
|
2487
|
+
if(Number.isNaN(x)){open=false;continue;}
|
|
2488
|
+
const y=round(scale.of((point.y)));
|
|
2489
|
+
commands.push(open?'L':'M',x,y);
|
|
2490
|
+
open=true;
|
|
2491
|
+
point.px=x;
|
|
2492
|
+
point.py=y;
|
|
2512
2493
|
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
d:path(line),
|
|
2516
|
-
fill:'none',
|
|
2494
|
+
attrs(pool.next('path',`${NS}__line ${NS}__mark`),{
|
|
2495
|
+
d:commands.length?path(commands):'',
|
|
2517
2496
|
stroke:colour,
|
|
2518
2497
|
'data-series':series.index,
|
|
2519
2498
|
});
|
|
2520
|
-
const
|
|
2521
|
-
if(
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
for(const point of overlay.band.points){
|
|
2525
|
-
const px=placeX(opts.xScale,point.x);
|
|
2526
|
-
const lo=mean?point.lowerMean:point.lower;
|
|
2527
|
-
const up=mean?point.upperMean:point.upper;
|
|
2528
|
-
const pl=yScale.of(lo);
|
|
2529
|
-
const pu=yScale.of(up);
|
|
2530
|
-
if(!Number.isFinite(px)||!Number.isFinite(pl)||!Number.isFinite(pu))continue;
|
|
2531
|
-
rows.push({x:round(px),lower:round(pl),upper:round(pu)});
|
|
2532
|
-
}
|
|
2533
|
-
const d=ribbonPath(rows);
|
|
2534
|
-
if(d){
|
|
2535
|
-
attrs(pool.next('path',`${NS}__trend-band`),{
|
|
2536
|
-
d,
|
|
2537
|
-
fill:colour,
|
|
2538
|
-
'fill-opacity':0.15,
|
|
2539
|
-
stroke:'none',
|
|
2540
|
-
'data-series':series.index,
|
|
2499
|
+
for(const point of series.points){
|
|
2500
|
+
if(point.px===undefined)continue;
|
|
2501
|
+
attrs(pool.next('circle',`${NS}__point ${NS}__mark`),{
|
|
2502
|
+
cx:point.px,cy:point.py,r:3,fill:colour,
|
|
2541
2503
|
});
|
|
2542
2504
|
}
|
|
2543
2505
|
}
|
|
2544
|
-
|
|
2545
|
-
if(
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2506
|
+
pool.finish();
|
|
2507
|
+
if(ctx.labels&&ctx.labels.show){
|
|
2508
|
+
drawDataLabels({
|
|
2509
|
+
group:ctx.groups.labels,
|
|
2510
|
+
series:visible,
|
|
2511
|
+
plot,
|
|
2512
|
+
options:ctx.labels,
|
|
2513
|
+
grid:ctx.grid,
|
|
2514
|
+
size:(ctx.typography&&ctx.typography.small)||ctx.fontSize,
|
|
2515
|
+
});
|
|
2552
2516
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2517
|
+
let annotations=null;
|
|
2518
|
+
if(ctx.annotations&&ctx.annotations.length){
|
|
2519
|
+
annotations=drawAnnotations({
|
|
2520
|
+
group:ctx.groups.overlay,
|
|
2521
|
+
plot,
|
|
2522
|
+
xScale,
|
|
2523
|
+
yScale,
|
|
2524
|
+
rightScale,
|
|
2525
|
+
series:visible,
|
|
2526
|
+
annotations:ctx.annotations,
|
|
2527
|
+
dual:!!rightScale,
|
|
2528
|
+
format:formatters(ctx.grid,{
|
|
2529
|
+
kind:'linear',step:(leftDomain.max-leftDomain.min)/5,
|
|
2530
|
+
}).tick,
|
|
2559
2531
|
});
|
|
2560
2532
|
}
|
|
2533
|
+
return{
|
|
2534
|
+
xScale,yScale,rightScale,dual:!!rightScale,series:visible,bound,annotations,
|
|
2535
|
+
};
|
|
2561
2536
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
const
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
y:round(yScale.of(last.y))-4,
|
|
2570
|
-
'text-anchor':'end',
|
|
2571
|
-
fill:colour,
|
|
2537
|
+
function drawRightAxis(opts){
|
|
2538
|
+
const{group,plot,scale,format}=opts;
|
|
2539
|
+
const pool=new Pool(group);
|
|
2540
|
+
attrs(pool.next('line',`${NS}__axis-right`),{
|
|
2541
|
+
x1:round(plot.right),x2:round(plot.right),
|
|
2542
|
+
y1:round(plot.top),y2:round(plot.bottom),
|
|
2543
|
+
stroke:opts.colour,
|
|
2572
2544
|
});
|
|
2573
|
-
|
|
2545
|
+
for(const value of scale.ticks(5)){
|
|
2546
|
+
const at=round(scale.of(value));
|
|
2547
|
+
const label=pool.next('text',`${NS}__tick`);
|
|
2548
|
+
attrs(label,{
|
|
2549
|
+
x:round(plot.right+6),y:at,'text-anchor':'start',
|
|
2550
|
+
'dominant-baseline':'middle',fill:opts.colour,
|
|
2551
|
+
});
|
|
2552
|
+
label.textContent=`${format.tick(value)}${opts.suffix||''}`;
|
|
2553
|
+
}
|
|
2554
|
+
pool.finish();
|
|
2574
2555
|
}
|
|
2575
|
-
described.push({
|
|
2576
|
-
text:trendText(overlay.stats,series.label,opts.format,forecast,
|
|
2577
|
-
spec.band===false?null:overlay.band,spec.band),
|
|
2578
2556
|
});
|
|
2557
|
+
__def("packages/modules/charts/quantile.js",function(__exports,__req){
|
|
2558
|
+
'use strict';
|
|
2559
|
+
Object.defineProperty(__exports,"normalQuantile",{enumerable:true,get:function(){return normalQuantile;}});
|
|
2560
|
+
Object.defineProperty(__exports,"studentTQuantile",{enumerable:true,get:function(){return studentTQuantile;}});
|
|
2561
|
+
const LANCZOS=Object.freeze([
|
|
2562
|
+
676.5203681218851,-1259.1392167224028,771.32342877765313,
|
|
2563
|
+
-176.61502916214059,12.507343278686905,-0.13857109526572012,
|
|
2564
|
+
9.9843695780195716e-6,1.5056327351493116e-7,
|
|
2565
|
+
]);
|
|
2566
|
+
const EPS=3e-12;
|
|
2567
|
+
const TINY=1e-300;
|
|
2568
|
+
function logGamma(x){
|
|
2569
|
+
if(x<0.5)return Math.log(Math.PI/Math.sin(Math.PI*x))-logGamma(1-x);
|
|
2570
|
+
const z=x-1;
|
|
2571
|
+
let a=0.99999999999980993;
|
|
2572
|
+
const t=z+7.5;
|
|
2573
|
+
for(let i=0;i<LANCZOS.length;i++)a+=LANCZOS[i]/(z+i+1);
|
|
2574
|
+
return 0.5*Math.log(2*Math.PI)+(z+0.5)*Math.log(t)-t+Math.log(a);
|
|
2575
|
+
}
|
|
2576
|
+
function betaContinuedFraction(a,b,x){
|
|
2577
|
+
const qab=a+b;
|
|
2578
|
+
const qap=a+1;
|
|
2579
|
+
const qam=a-1;
|
|
2580
|
+
let c=1;
|
|
2581
|
+
let d=1-(qab*x)/qap;
|
|
2582
|
+
if(Math.abs(d)<TINY)d=TINY;
|
|
2583
|
+
d=1/d;
|
|
2584
|
+
let h=d;
|
|
2585
|
+
for(let m=1;m<=300;m++){
|
|
2586
|
+
const m2=2*m;
|
|
2587
|
+
let aa=(m*(b-m)*x)/((qam+m2)*(a+m2));
|
|
2588
|
+
d=1+aa*d;
|
|
2589
|
+
if(Math.abs(d)<TINY)d=TINY;
|
|
2590
|
+
c=1+aa/c;
|
|
2591
|
+
if(Math.abs(c)<TINY)c=TINY;
|
|
2592
|
+
d=1/d;
|
|
2593
|
+
h*=d*c;
|
|
2594
|
+
aa=(-(a+m)*(qab+m)*x)/((a+m2)*(qap+m2));
|
|
2595
|
+
d=1+aa*d;
|
|
2596
|
+
if(Math.abs(d)<TINY)d=TINY;
|
|
2597
|
+
c=1+aa/c;
|
|
2598
|
+
if(Math.abs(c)<TINY)c=TINY;
|
|
2599
|
+
d=1/d;
|
|
2600
|
+
const step=d*c;
|
|
2601
|
+
h*=step;
|
|
2602
|
+
if(Math.abs(step-1)<EPS)break;
|
|
2603
|
+
}
|
|
2604
|
+
return h;
|
|
2605
|
+
}
|
|
2606
|
+
function incompleteBeta(a,b,x){
|
|
2607
|
+
if(!(a>0)||!(b>0)||!Number.isFinite(x))return Number.NaN;
|
|
2608
|
+
if(x<=0)return 0;
|
|
2609
|
+
if(x>=1)return 1;
|
|
2610
|
+
const front=Math.exp(
|
|
2611
|
+
logGamma(a+b)-logGamma(a)-logGamma(b)+a*Math.log(x)+b*Math.log(1-x),
|
|
2612
|
+
);
|
|
2613
|
+
return x<(a+1)/(a+b+2)
|
|
2614
|
+
?(front*betaContinuedFraction(a,b,x))/a
|
|
2615
|
+
:1-(front*betaContinuedFraction(b,a,1-x))/b;
|
|
2579
2616
|
}
|
|
2617
|
+
function erfc(x){
|
|
2618
|
+
const z=Math.abs(x);
|
|
2619
|
+
const t=2/(2+z);
|
|
2620
|
+
const ty=4*t-2;
|
|
2621
|
+
const cof=[-1.3026537197817094,6.4196979235649026e-1,1.9476473204185836e-2,
|
|
2622
|
+
-9.561514786808631e-3,-9.46595344482036e-4,3.66839497852761e-4,
|
|
2623
|
+
4.2523324806907e-5,-2.0278578112534e-5,-1.624290004647e-6,
|
|
2624
|
+
1.303655835580e-6,1.5626441722e-8,-8.5238095915e-8,6.529054439e-9,
|
|
2625
|
+
5.059343495e-9,-9.91364156e-10,-2.27365122e-10,9.6467911e-11,
|
|
2626
|
+
2.394038e-12,-6.886027e-12,8.94487e-13,3.13092e-13,-1.12708e-13,
|
|
2627
|
+
3.81e-16,7.106e-15];
|
|
2628
|
+
let dd=0;
|
|
2629
|
+
let dv=0;
|
|
2630
|
+
let tmp;
|
|
2631
|
+
for(let j=cof.length-1;j>0;j--){
|
|
2632
|
+
tmp=dv;
|
|
2633
|
+
dv=ty*dv-dd+cof[j];
|
|
2634
|
+
dd=tmp;
|
|
2580
2635
|
}
|
|
2581
|
-
|
|
2582
|
-
return
|
|
2636
|
+
const ans=t*Math.exp(-z*z+0.5*(cof[0]+ty*dv)-dd);
|
|
2637
|
+
return x>=0?ans:2-ans;
|
|
2583
2638
|
}
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
Object.defineProperty(__exports,"Lru",{enumerable:true,get:function(){return Lru;}});
|
|
2612
|
-
Object.defineProperty(__exports,"collator",{enumerable:true,get:function(){return collator;}});
|
|
2613
|
-
Object.defineProperty(__exports,"defaultCompare",{enumerable:true,get:function(){return defaultCompare;}});
|
|
2614
|
-
Object.defineProperty(__exports,"now",{enumerable:true,get:function(){return now;}});
|
|
2615
|
-
Object.defineProperty(__exports,"nextFrame",{enumerable:true,get:function(){return nextFrame;}});
|
|
2616
|
-
Object.defineProperty(__exports,"cancelFrame",{enumerable:true,get:function(){return cancelFrame;}});
|
|
2617
|
-
Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){return frameBatched;}});
|
|
2618
|
-
Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
|
|
2619
|
-
Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
|
|
2620
|
-
Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
|
|
2621
|
-
const STAMPED_VERSION="1.67.0";
|
|
2622
|
-
async function resolveVersion(){
|
|
2623
|
-
if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
|
|
2624
|
-
return STAMPED_VERSION;
|
|
2639
|
+
function normalQuantile(p){
|
|
2640
|
+
if(!(p>0)||!(p<1))return p===0?-Infinity:(p===1?Infinity:Number.NaN);
|
|
2641
|
+
const a=[-3.969683028665376e+1,2.209460984245205e+2,-2.759285104469687e+2,
|
|
2642
|
+
1.383577518672690e+2,-3.066479806614716e+1,2.506628277459239];
|
|
2643
|
+
const b=[-5.447609879822406e+1,1.615858368580409e+2,-1.556989798598866e+2,
|
|
2644
|
+
6.680131188771972e+1,-1.328068155288572e+1];
|
|
2645
|
+
const c=[-7.784894002430293e-3,-3.223964580411365e-1,-2.400758277161838,
|
|
2646
|
+
-2.549732539343734,4.374664141464968,2.938163982698783];
|
|
2647
|
+
const d=[7.784695709041462e-3,3.224671290700398e-1,2.445134137142996,
|
|
2648
|
+
3.754408661907416];
|
|
2649
|
+
const low=0.02425;
|
|
2650
|
+
let q;
|
|
2651
|
+
let r;
|
|
2652
|
+
let x;
|
|
2653
|
+
if(p<low){
|
|
2654
|
+
q=Math.sqrt(-2*Math.log(p));
|
|
2655
|
+
x=(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5])
|
|
2656
|
+
/ ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
|
|
2657
|
+
}else if(p<=1-low){
|
|
2658
|
+
q=p-0.5;
|
|
2659
|
+
r=q*q;
|
|
2660
|
+
x=((((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q)
|
|
2661
|
+
/ (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
|
|
2662
|
+
}else{
|
|
2663
|
+
q=Math.sqrt(-2*Math.log(1-p));
|
|
2664
|
+
x=-(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5])
|
|
2665
|
+
/ ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
|
|
2625
2666
|
}
|
|
2626
|
-
const
|
|
2627
|
-
const
|
|
2628
|
-
|
|
2629
|
-
function rememberWarned(key){
|
|
2630
|
-
warned.add(key);
|
|
2631
|
-
if(warned.size>WARNED_LIMIT){
|
|
2632
|
-
const oldest=warned.values().next().value;
|
|
2633
|
-
if(oldest!==undefined)warned.delete(oldest);
|
|
2667
|
+
const e=0.5*erfc(-x/Math.SQRT2)-p;
|
|
2668
|
+
const u=e*Math.sqrt(2*Math.PI)*Math.exp((x*x)/2);
|
|
2669
|
+
return x-u/(1+(x*u)/2);
|
|
2634
2670
|
}
|
|
2671
|
+
function studentT(t,df){
|
|
2672
|
+
if(!(df>0)||!Number.isFinite(t))return Number.NaN;
|
|
2673
|
+
const tail=0.5*incompleteBeta(df/2,0.5,df/(df+t*t));
|
|
2674
|
+
return t>0?1-tail:tail;
|
|
2635
2675
|
}
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
if(
|
|
2676
|
+
function studentTQuantile(p,df){
|
|
2677
|
+
if(!(p>0)||!(p<1)||!(df>0))return Number.NaN;
|
|
2678
|
+
if(df>1e7)return normalQuantile(p);
|
|
2679
|
+
let lo=-1e4;
|
|
2680
|
+
let hi=1e4;
|
|
2681
|
+
let x=normalQuantile(p);
|
|
2682
|
+
const logBeta=logGamma(df/2)+logGamma(0.5)-logGamma((df+1)/2);
|
|
2683
|
+
for(let i=0;i<60;i++){
|
|
2684
|
+
const cdf=studentT(x,df);
|
|
2685
|
+
if(cdf<p)lo=x;else hi=x;
|
|
2686
|
+
const pdf=Math.exp(-((df+1)/2)*Math.log(1+(x*x)/df)-logBeta)
|
|
2687
|
+
/ Math.sqrt(df);
|
|
2688
|
+
const step=pdf>0?(cdf-p)/pdf:0;
|
|
2689
|
+
if(Math.abs(step)<1e-12)break;
|
|
2690
|
+
const next=x-step;
|
|
2691
|
+
x=next>lo&&next<hi&&Number.isFinite(next)?next:(lo+hi)/2;
|
|
2692
|
+
if(hi-lo<1e-12)break;
|
|
2646
2693
|
}
|
|
2647
|
-
|
|
2648
|
-
if(value instanceof Error)return value.message;
|
|
2649
|
-
try{return JSON.stringify(value);}catch{return String(value);}
|
|
2694
|
+
return x;
|
|
2650
2695
|
}
|
|
2651
|
-
|
|
2652
|
-
function
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2696
|
+
});
|
|
2697
|
+
__def("packages/modules/charts/trendline.js",function(__exports,__req){
|
|
2698
|
+
'use strict';
|
|
2699
|
+
Object.defineProperty(__exports,"normaliseTrends",{enumerable:true,get:function(){return normaliseTrends;}});
|
|
2700
|
+
Object.defineProperty(__exports,"linearTrend",{enumerable:true,get:function(){return linearTrend;}});
|
|
2701
|
+
Object.defineProperty(__exports,"movingAverageTrend",{enumerable:true,get:function(){return movingAverageTrend;}});
|
|
2702
|
+
Object.defineProperty(__exports,"exponentialTrend",{enumerable:true,get:function(){return exponentialTrend;}});
|
|
2703
|
+
Object.defineProperty(__exports,"computeTrend",{enumerable:true,get:function(){return computeTrend;}});
|
|
2704
|
+
Object.defineProperty(__exports,"trendText",{enumerable:true,get:function(){return trendText;}});
|
|
2705
|
+
Object.defineProperty(__exports,"drawTrendlines",{enumerable:true,get:function(){return drawTrendlines;}});
|
|
2706
|
+
const __m0=__req("packages/modules/charts/frame.js");
|
|
2707
|
+
const Pool=__m0["Pool"];
|
|
2708
|
+
const __m1=__req("packages/modules/charts/svg.js");
|
|
2709
|
+
const attrs=__m1["attrs"];
|
|
2710
|
+
const path=__m1["path"];
|
|
2711
|
+
const ribbonPath=__m1["ribbonPath"];
|
|
2712
|
+
const round=__m1["round"];
|
|
2713
|
+
const setText=__m1["setText"];
|
|
2714
|
+
const SVG_NS=__m1["SVG_NS"];
|
|
2715
|
+
const __m2=__req("packages/modules/charts/typography.js");
|
|
2716
|
+
const applySize=__m2["applySize"];
|
|
2717
|
+
const __m3=__req("packages/modules/charts/styles.js");
|
|
2718
|
+
const NS=__m3["NS"];
|
|
2719
|
+
const __m4=__req("packages/modules/charts/scale.js");
|
|
2720
|
+
const toNumber=__m4["toNumber"];
|
|
2721
|
+
const toTime=__m4["toTime"];
|
|
2722
|
+
const __m5=__req("packages/modules/charts/quantile.js");
|
|
2723
|
+
const studentTQuantile=__m5["studentTQuantile"];
|
|
2724
|
+
const METHODS={
|
|
2725
|
+
linear:new Set(['linear','lr','ols','regression','least-squares']),
|
|
2726
|
+
movingAverage:new Set(['movingaverage','moving-average','ma','sma','rolling']),
|
|
2727
|
+
exponential:new Set(['exponential','exp','ewma','ses','holt','smoothing']),
|
|
2728
|
+
};
|
|
2729
|
+
const SMOOTH_LO=1e-4;
|
|
2730
|
+
const SMOOTH_HI=1-1e-4;
|
|
2731
|
+
function methodOf(name){
|
|
2732
|
+
const key=String(name||'linear').toLowerCase();
|
|
2733
|
+
if(METHODS.linear.has(key))return'linear';
|
|
2734
|
+
if(METHODS.movingAverage.has(key))return'movingAverage';
|
|
2735
|
+
if(METHODS.exponential.has(key))return'exponential';
|
|
2736
|
+
return null;
|
|
2657
2737
|
}
|
|
2658
|
-
function
|
|
2659
|
-
if(
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2738
|
+
function normaliseTrends(trend){
|
|
2739
|
+
if(!trend)return[];
|
|
2740
|
+
const raw=Array.isArray(trend)?trend:[trend];
|
|
2741
|
+
const out=[];
|
|
2742
|
+
for(const entry of raw){
|
|
2743
|
+
if(entry===true){out.push({method:'linear'});continue;}
|
|
2744
|
+
if(typeof entry==='string'){
|
|
2745
|
+
const method=methodOf(entry);
|
|
2746
|
+
if(method)out.push({method});
|
|
2747
|
+
continue;
|
|
2663
2748
|
}
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2749
|
+
if(entry&&typeof entry==='object'){
|
|
2750
|
+
const method=methodOf(entry.method);
|
|
2751
|
+
if(method)out.push({...entry,method});
|
|
2667
2752
|
}
|
|
2668
|
-
function fail(message,extra){
|
|
2669
|
-
const err=new Error(`[lattice] ${message}`);
|
|
2670
|
-
if(extra!==undefined)err.cause=extra;
|
|
2671
|
-
throw err;
|
|
2672
2753
|
}
|
|
2673
|
-
|
|
2674
|
-
if(!condition)fail(message);
|
|
2754
|
+
return out;
|
|
2675
2755
|
}
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
}catch{
|
|
2681
|
-
return true;
|
|
2756
|
+
function placeX(scale,rawX){
|
|
2757
|
+
if(scale.kind==='band')return scale.centre(rawX);
|
|
2758
|
+
const n=scale.kind==='time'?toTime(rawX):toNumber(rawX);
|
|
2759
|
+
return n===null?NaN:scale.of(n);
|
|
2682
2760
|
}
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2761
|
+
function sequenceOf(series){
|
|
2762
|
+
const seq=[];
|
|
2763
|
+
for(const point of series.points){
|
|
2764
|
+
const y=Number(point.y);
|
|
2765
|
+
seq.push({value:Number.isFinite(y)?y:null,rawX:point.x});
|
|
2686
2766
|
}
|
|
2687
|
-
|
|
2688
|
-
return typeof v==='function';
|
|
2767
|
+
return seq;
|
|
2689
2768
|
}
|
|
2690
|
-
function
|
|
2691
|
-
|
|
2769
|
+
function numericPairs(series,xScale){
|
|
2770
|
+
const pairs=[];
|
|
2771
|
+
for(const point of series.points){
|
|
2772
|
+
const x=xScale.kind==='time'?toTime(point.x):toNumber(point.x);
|
|
2773
|
+
const y=Number(point.y);
|
|
2774
|
+
if(x===null||!Number.isFinite(x)||!Number.isFinite(y))continue;
|
|
2775
|
+
pairs.push({x,y});
|
|
2692
2776
|
}
|
|
2693
|
-
|
|
2694
|
-
return
|
|
2777
|
+
pairs.sort((a,b)=>a.x-b.x);
|
|
2778
|
+
return pairs;
|
|
2695
2779
|
}
|
|
2696
|
-
function
|
|
2697
|
-
|
|
2698
|
-
if(
|
|
2699
|
-
|
|
2780
|
+
function linearTrend(pairs,forecast,opts={}){
|
|
2781
|
+
const n=pairs.length;
|
|
2782
|
+
if(n<2)return null;
|
|
2783
|
+
let mx=0;
|
|
2784
|
+
let my=0;
|
|
2785
|
+
for(const p of pairs){mx+=p.x;my+=p.y;}
|
|
2786
|
+
mx/=n;
|
|
2787
|
+
my/=n;
|
|
2788
|
+
let sxx=0;
|
|
2789
|
+
let sxy=0;
|
|
2790
|
+
let syy=0;
|
|
2791
|
+
for(const p of pairs){
|
|
2792
|
+
const dx=p.x-mx;
|
|
2793
|
+
const dy=p.y-my;
|
|
2794
|
+
sxx+=dx*dx;
|
|
2795
|
+
sxy+=dx*dy;
|
|
2796
|
+
syy+=dy*dy;
|
|
2700
2797
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
}
|
|
2708
|
-
const
|
|
2709
|
-
const
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2798
|
+
if(sxx===0)return null;
|
|
2799
|
+
const slope=sxy/sxx;
|
|
2800
|
+
const intercept=my-slope*mx;
|
|
2801
|
+
const r2=syy===0?1:Math.max(0,Math.min(1,(sxy*sxy)/(sxx*syy)));
|
|
2802
|
+
const lo=pairs[0].x;
|
|
2803
|
+
const hi=pairs[n-1].x;
|
|
2804
|
+
const at=(x)=>({x,y:intercept+slope*x});
|
|
2805
|
+
const fit=[at(lo),at(hi)];
|
|
2806
|
+
const projected=[];
|
|
2807
|
+
let band=null;
|
|
2808
|
+
const steps=Math.max(0,Math.floor(Number(forecast)||0));
|
|
2809
|
+
if(steps>0&&hi>lo){
|
|
2810
|
+
const step=(hi-lo)/(n-1);
|
|
2811
|
+
if(step>0){
|
|
2812
|
+
projected.push(at(hi),at(hi+steps*step));
|
|
2813
|
+
if(n>2){
|
|
2814
|
+
const conf=Number.isFinite(opts.confidence)
|
|
2815
|
+
&&opts.confidence>0&&opts.confidence<1?Number(opts.confidence):0.95;
|
|
2816
|
+
const tail=1-(1-conf)/2;
|
|
2817
|
+
const sse=Math.max(0,syy-slope*sxy);
|
|
2818
|
+
const s=Math.sqrt(sse/(n-2));
|
|
2819
|
+
const t=studentTQuantile(tail,n-2);
|
|
2820
|
+
const points=[];
|
|
2821
|
+
for(let h=0;h<=steps;h++){
|
|
2822
|
+
const x0=hi+h*step;
|
|
2823
|
+
const mean=intercept+slope*x0;
|
|
2824
|
+
const leverage=1/n+((x0-mx)**2)/sxx;
|
|
2825
|
+
const sePred=s*Math.sqrt(1+leverage);
|
|
2826
|
+
const seMean=s*Math.sqrt(leverage);
|
|
2827
|
+
points.push({
|
|
2828
|
+
x:x0,
|
|
2829
|
+
mean,
|
|
2830
|
+
lower:mean-t*sePred,
|
|
2831
|
+
upper:mean+t*sePred,
|
|
2832
|
+
lowerMean:mean-t*seMean,
|
|
2833
|
+
upperMean:mean+t*seMean,
|
|
2834
|
+
});
|
|
2715
2835
|
}
|
|
2716
|
-
|
|
2717
|
-
};
|
|
2836
|
+
band={confidence:conf,points};
|
|
2718
2837
|
}
|
|
2719
|
-
pathCache.set(path,fn);
|
|
2720
|
-
return fn;
|
|
2721
2838
|
}
|
|
2722
|
-
const setterCache=new Map();
|
|
2723
|
-
function pathSetter(path){
|
|
2724
|
-
let fn=setterCache.get(path);
|
|
2725
|
-
if(fn)return fn;
|
|
2726
|
-
if(!path.includes('.')){
|
|
2727
|
-
fn=(o,v)=>{if(o!=null)o[path]=v;};
|
|
2728
|
-
}else{
|
|
2729
|
-
const parts=path.split('.');
|
|
2730
|
-
const last=parts.length-1;
|
|
2731
|
-
fn=(o,v)=>{
|
|
2732
|
-
let cur=o;
|
|
2733
|
-
for(let i=0;i<last;i++){
|
|
2734
|
-
if(cur==null)return;
|
|
2735
|
-
const k=parts[i];
|
|
2736
|
-
if(cur[k]==null)cur[k]={};
|
|
2737
|
-
cur=cur[k];
|
|
2738
2839
|
}
|
|
2739
|
-
|
|
2840
|
+
return{
|
|
2841
|
+
fit,
|
|
2842
|
+
forecast:projected,
|
|
2843
|
+
band,
|
|
2844
|
+
stats:{
|
|
2845
|
+
method:'linear',slope,intercept,r2,n,forecast:projected.length?steps:0,
|
|
2846
|
+
confidence:band?band.confidence:null,
|
|
2847
|
+
},
|
|
2740
2848
|
};
|
|
2741
2849
|
}
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2850
|
+
function movingAverageTrend(seq,window){
|
|
2851
|
+
const span=Math.max(1,Math.floor(Number(window)||3));
|
|
2852
|
+
const ring=[];
|
|
2853
|
+
let sum=0;
|
|
2854
|
+
const fit=[];
|
|
2855
|
+
for(const row of seq){
|
|
2856
|
+
if(Number.isFinite(row.value)){
|
|
2857
|
+
ring.push(row.value);
|
|
2858
|
+
sum+=row.value;
|
|
2859
|
+
if(ring.length>span)sum-=ring.shift();
|
|
2747
2860
|
}
|
|
2748
|
-
|
|
2749
|
-
|
|
2861
|
+
if(!ring.length)continue;
|
|
2862
|
+
fit.push({x:row.rawX,y:sum/ring.length});
|
|
2750
2863
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
const leaf=field.includes('.')?field.slice(field.lastIndexOf('.')+1):field;
|
|
2754
|
-
return leaf
|
|
2755
|
-
.replace(/[_-]+/g,' ')
|
|
2756
|
-
.replace(/([a-z0-9])([A-Z])/g,'$1 $2')
|
|
2757
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g,'$1 $2')
|
|
2758
|
-
.replace(/\s+/g,' ')
|
|
2759
|
-
.trim()
|
|
2760
|
-
.replace(/^./,(c)=>c.toUpperCase());
|
|
2864
|
+
if(fit.length<2)return null;
|
|
2865
|
+
return{fit,stats:{method:'movingAverage',window:span}};
|
|
2761
2866
|
}
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2867
|
+
function runSes(y,alpha){
|
|
2868
|
+
const n=y.length;
|
|
2869
|
+
const smoothed=new Array(n).fill(null);
|
|
2870
|
+
let level=null;
|
|
2871
|
+
let sse=0;
|
|
2872
|
+
for(let i=0;i<n;i++){
|
|
2873
|
+
const v=y[i];
|
|
2874
|
+
if(!Number.isFinite(v)){
|
|
2875
|
+
if(level!==null)smoothed[i]=level;
|
|
2876
|
+
continue;
|
|
2766
2877
|
}
|
|
2767
|
-
|
|
2768
|
-
|
|
2878
|
+
if(level===null){level=v;smoothed[i]=v;continue;}
|
|
2879
|
+
sse+=(v-level)**2;
|
|
2880
|
+
level=alpha*v+(1-alpha)*level;
|
|
2881
|
+
smoothed[i]=level;
|
|
2769
2882
|
}
|
|
2770
|
-
|
|
2771
|
-
if(value===undefined)return undefined;
|
|
2772
|
-
if(value===true)return{enabled:true,...whenTrue};
|
|
2773
|
-
if(value===false)return{enabled:false};
|
|
2774
|
-
if(isObject(value))return value;
|
|
2775
|
-
return{[key]:value,enabled:true};
|
|
2883
|
+
return{smoothed,sse};
|
|
2776
2884
|
}
|
|
2777
|
-
function
|
|
2778
|
-
|
|
2779
|
-
|
|
2885
|
+
function runHolt(y,alpha,beta){
|
|
2886
|
+
const n=y.length;
|
|
2887
|
+
const smoothed=new Array(n).fill(null);
|
|
2888
|
+
let level=null;
|
|
2889
|
+
let trend=null;
|
|
2890
|
+
let sse=0;
|
|
2891
|
+
for(let i=0;i<n;i++){
|
|
2892
|
+
const v=y[i];
|
|
2893
|
+
if(!Number.isFinite(v)){
|
|
2894
|
+
if(level!==null){level+=trend;smoothed[i]=level;}
|
|
2895
|
+
continue;
|
|
2780
2896
|
}
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2897
|
+
if(level===null){level=v;smoothed[i]=v;continue;}
|
|
2898
|
+
if(trend===null){
|
|
2899
|
+
trend=v-level;
|
|
2900
|
+
const forecast=level+trend;
|
|
2901
|
+
sse+=(v-forecast)**2;
|
|
2902
|
+
const prev=level;
|
|
2903
|
+
level=alpha*v+(1-alpha)*(prev+trend);
|
|
2904
|
+
trend=beta*(level-prev)+(1-beta)*trend;
|
|
2905
|
+
smoothed[i]=level;
|
|
2906
|
+
continue;
|
|
2791
2907
|
}
|
|
2792
|
-
|
|
2908
|
+
const forecast=level+trend;
|
|
2909
|
+
sse+=(v-forecast)**2;
|
|
2910
|
+
const prev=level;
|
|
2911
|
+
level=alpha*v+(1-alpha)*(prev+trend);
|
|
2912
|
+
trend=beta*(level-prev)+(1-beta)*trend;
|
|
2913
|
+
smoothed[i]=level;
|
|
2793
2914
|
}
|
|
2794
|
-
|
|
2795
|
-
if(!isObject(previous)||!isObject(patch)||previous===patch)return patch;
|
|
2796
|
-
const out=Object.create(Object.getPrototypeOf(previous));
|
|
2797
|
-
Object.assign(out,previous,patch);
|
|
2798
|
-
return out;
|
|
2915
|
+
return{smoothed,sse};
|
|
2799
2916
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2917
|
+
function goldenMin(f,lo,hi,iters=80){
|
|
2918
|
+
const invphi=(Math.sqrt(5)-1)/2;
|
|
2919
|
+
let a=lo;
|
|
2920
|
+
let b=hi;
|
|
2921
|
+
let c=b-invphi*(b-a);
|
|
2922
|
+
let d=a+invphi*(b-a);
|
|
2923
|
+
let fc=f(c);
|
|
2924
|
+
let fd=f(d);
|
|
2925
|
+
for(let i=0;i<iters;i++){
|
|
2926
|
+
if(fc<fd){b=d;d=c;fd=fc;c=b-invphi*(b-a);fc=f(c);}
|
|
2927
|
+
else{a=c;c=d;fc=fd;d=a+invphi*(b-a);fd=f(d);}
|
|
2807
2928
|
}
|
|
2808
|
-
|
|
2809
|
-
return this.#map.size;
|
|
2929
|
+
return(a+b)/2;
|
|
2810
2930
|
}
|
|
2811
|
-
|
|
2812
|
-
|
|
2931
|
+
function exponentialTrend(seq,spec){
|
|
2932
|
+
const holt=String(spec.kind||spec.model||'').toLowerCase()==='holt';
|
|
2933
|
+
const y=seq.map((row)=>(Number.isFinite(row.value)?row.value:null));
|
|
2934
|
+
const finite=y.filter((v)=>v!==null).length;
|
|
2935
|
+
if(finite<(holt?2:1))return null;
|
|
2936
|
+
const clamp=(x)=>Math.min(SMOOTH_HI,Math.max(SMOOTH_LO,x));
|
|
2937
|
+
let alpha=Number.isFinite(spec.alpha)?clamp(Number(spec.alpha)):null;
|
|
2938
|
+
let beta=holt&&Number.isFinite(spec.beta)?clamp(Number(spec.beta)):null;
|
|
2939
|
+
if(holt){
|
|
2940
|
+
if(alpha===null||beta===null){
|
|
2941
|
+
let a=alpha===null?0.5:alpha;
|
|
2942
|
+
let b=beta===null?0.5:beta;
|
|
2943
|
+
for(let r=0;r<6;r++){
|
|
2944
|
+
if(alpha===null)a=goldenMin((x)=>runHolt(y,x,b).sse,SMOOTH_LO,SMOOTH_HI);
|
|
2945
|
+
if(beta===null)b=goldenMin((x)=>runHolt(y,a,x).sse,SMOOTH_LO,SMOOTH_HI);
|
|
2813
2946
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
this.#trim();
|
|
2947
|
+
alpha=alpha===null?a:alpha;
|
|
2948
|
+
beta=beta===null?b:beta;
|
|
2817
2949
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2950
|
+
}else if(alpha===null){
|
|
2951
|
+
alpha=goldenMin((x)=>runSes(y,x).sse,SMOOTH_LO,SMOOTH_HI);
|
|
2820
2952
|
}
|
|
2821
|
-
|
|
2822
|
-
const
|
|
2823
|
-
|
|
2824
|
-
const
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
return v;
|
|
2953
|
+
const run=holt?runHolt(y,alpha,beta):runSes(y,alpha);
|
|
2954
|
+
const fit=[];
|
|
2955
|
+
for(let i=0;i<seq.length;i++){
|
|
2956
|
+
const level=run.smoothed[i];
|
|
2957
|
+
if(level===null||!Number.isFinite(level))continue;
|
|
2958
|
+
fit.push({x:seq[i].rawX,y:level});
|
|
2828
2959
|
}
|
|
2829
|
-
|
|
2830
|
-
return
|
|
2960
|
+
if(fit.length<2)return null;
|
|
2961
|
+
return{
|
|
2962
|
+
fit,stats:{method:'exponential',kind:holt?'holt':'ses',alpha,beta:holt?beta:null},
|
|
2963
|
+
};
|
|
2831
2964
|
}
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
this.#trim();
|
|
2837
|
-
return v;
|
|
2965
|
+
function computeTrend(series,spec,xScale){
|
|
2966
|
+
if(spec.method==='linear'){
|
|
2967
|
+
const pairs=numericPairs(series,xScale);
|
|
2968
|
+
return linearTrend(pairs,spec.forecast,{confidence:spec.confidence});
|
|
2838
2969
|
}
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
return v;
|
|
2970
|
+
const seq=sequenceOf(series);
|
|
2971
|
+
if(spec.method==='movingAverage'){
|
|
2972
|
+
return movingAverageTrend(seq,spec.window||spec.period);
|
|
2843
2973
|
}
|
|
2844
|
-
|
|
2845
|
-
if(this.#onEvict)for(const[k,v]of this.#map)this.#onEvict(v,k);
|
|
2846
|
-
this.#map.clear();
|
|
2974
|
+
return exponentialTrend(seq,spec);
|
|
2847
2975
|
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2976
|
+
function trendText(stats,label,fmt,forecast,band,bandKind){
|
|
2977
|
+
const who=label?` for ${label}`:'';
|
|
2978
|
+
if(stats.method==='linear'){
|
|
2979
|
+
const r2=Number.isFinite(stats.r2)?`, R² ${stats.r2.toFixed(2)}`:'';
|
|
2980
|
+
let text=`Trend (linear)${who}: slope ${fmt(stats.slope)}${r2}`;
|
|
2981
|
+
if(stats.forecast>0&&forecast&&forecast.length){
|
|
2982
|
+
const end=forecast[forecast.length-1];
|
|
2983
|
+
text+=`; forecast ${stats.forecast} step${stats.forecast===1?'':'s'} ahead to ${fmt(end.y)}`;
|
|
2984
|
+
if(band&&band.points.length){
|
|
2985
|
+
const last=band.points[band.points.length-1];
|
|
2986
|
+
const mean=bandKind==='confidence'||bandKind==='mean';
|
|
2987
|
+
const lo=mean?last.lowerMean:last.lower;
|
|
2988
|
+
const up=mean?last.upperMean:last.upper;
|
|
2989
|
+
const kind=mean?'confidence':'prediction';
|
|
2990
|
+
const pct=Math.round(band.confidence*100);
|
|
2991
|
+
text+=`; ${pct}% ${kind} band ${fmt(lo)} to ${fmt(up)} at the horizon`;
|
|
2850
2992
|
}
|
|
2851
|
-
values(){
|
|
2852
|
-
return this.#map.values();
|
|
2853
2993
|
}
|
|
2854
|
-
|
|
2855
|
-
const m=this.#map;
|
|
2856
|
-
while(m.size>this.#max){
|
|
2857
|
-
const oldest=m.keys().next().value;
|
|
2858
|
-
const v=m.get(oldest);
|
|
2859
|
-
m.delete(oldest);
|
|
2860
|
-
if(this.#onEvict)this.#onEvict(v,oldest);
|
|
2994
|
+
return text;
|
|
2861
2995
|
}
|
|
2996
|
+
if(stats.method==='movingAverage'){
|
|
2997
|
+
return`Trend (moving average, window ${stats.window})${who}`;
|
|
2862
2998
|
}
|
|
2999
|
+
const kind=stats.kind==='holt'?'Holt':'single';
|
|
3000
|
+
const a=Number.isFinite(stats.alpha)?`, α ${stats.alpha.toFixed(2)}`:'';
|
|
3001
|
+
const b=Number.isFinite(stats.beta)?`, β ${stats.beta.toFixed(2)}`:'';
|
|
3002
|
+
return`Trend (exponential, ${kind})${who}${a}${b}`;
|
|
2863
3003
|
}
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
3004
|
+
function drawTrendlines(opts){
|
|
3005
|
+
const specs=normaliseTrends(opts.trend);
|
|
3006
|
+
if(!specs.length)return[];
|
|
3007
|
+
const doc=opts.group.ownerDocument;
|
|
3008
|
+
let host=null;
|
|
3009
|
+
for(const child of opts.group.childNodes||[]){
|
|
3010
|
+
if(child&&String(child.getAttribute&&child.getAttribute('class'))===`${NS}__trends`){
|
|
3011
|
+
host=child;
|
|
3012
|
+
break;
|
|
2873
3013
|
}
|
|
2874
|
-
return c;
|
|
2875
3014
|
}
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
if(typeof a==='number'&&typeof b==='number'){
|
|
2881
|
-
if(Number.isNaN(a))return Number.isNaN(b)?0:1;
|
|
2882
|
-
if(Number.isNaN(b))return-1;
|
|
2883
|
-
return a<b?-1:a>b?1:0;
|
|
3015
|
+
if(!host){
|
|
3016
|
+
host=doc.createElementNS(SVG_NS,'g');
|
|
3017
|
+
host.setAttribute('class',`${NS}__trends`);
|
|
3018
|
+
opts.group.appendChild(host);
|
|
2884
3019
|
}
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3020
|
+
if(opts.clip)host.setAttribute('clip-path',`url(#${opts.clip})`);
|
|
3021
|
+
else host.removeAttribute('clip-path');
|
|
3022
|
+
const pool=new Pool(host);
|
|
3023
|
+
const described=[];
|
|
3024
|
+
for(const spec of specs){
|
|
3025
|
+
for(const series of opts.series){
|
|
3026
|
+
const yScale=(series.axis==='right'&&opts.rightScale)?opts.rightScale:opts.yScale;
|
|
3027
|
+
const overlay=computeTrend(series,spec,opts.xScale);
|
|
3028
|
+
if(!overlay)continue;
|
|
3029
|
+
const colour=opts.scheme.series(series.index);
|
|
3030
|
+
const line=[];
|
|
3031
|
+
for(const point of overlay.fit){
|
|
3032
|
+
const px=placeX(opts.xScale,point.x);
|
|
3033
|
+
const py=yScale.of(point.y);
|
|
3034
|
+
if(!Number.isFinite(px)||!Number.isFinite(py))continue;
|
|
3035
|
+
line.push(line.length?'L':'M',round(px),round(py));
|
|
2888
3036
|
}
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
:
|
|
3037
|
+
if(line.length<4)continue;
|
|
3038
|
+
attrs(pool.next('path',`${NS}__trend`),{
|
|
3039
|
+
d:path(line),
|
|
3040
|
+
fill:'none',
|
|
3041
|
+
stroke:colour,
|
|
3042
|
+
'data-series':series.index,
|
|
3043
|
+
});
|
|
3044
|
+
const wantsBand=spec.band!==false&&overlay.band&&overlay.band.points.length>=2;
|
|
3045
|
+
if(wantsBand){
|
|
3046
|
+
const mean=spec.band==='confidence'||spec.band==='mean';
|
|
3047
|
+
const rows=[];
|
|
3048
|
+
for(const point of overlay.band.points){
|
|
3049
|
+
const px=placeX(opts.xScale,point.x);
|
|
3050
|
+
const lo=mean?point.lowerMean:point.lower;
|
|
3051
|
+
const up=mean?point.upperMean:point.upper;
|
|
3052
|
+
const pl=yScale.of(lo);
|
|
3053
|
+
const pu=yScale.of(up);
|
|
3054
|
+
if(!Number.isFinite(px)||!Number.isFinite(pl)||!Number.isFinite(pu))continue;
|
|
3055
|
+
rows.push({x:round(px),lower:round(pl),upper:round(pu)});
|
|
2893
3056
|
}
|
|
2894
|
-
const
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
3057
|
+
const d=ribbonPath(rows);
|
|
3058
|
+
if(d){
|
|
3059
|
+
attrs(pool.next('path',`${NS}__trend-band`),{
|
|
3060
|
+
d,
|
|
3061
|
+
fill:colour,
|
|
3062
|
+
'fill-opacity':0.15,
|
|
3063
|
+
stroke:'none',
|
|
3064
|
+
'data-series':series.index,
|
|
3065
|
+
});
|
|
2898
3066
|
}
|
|
2899
|
-
function cancelFrame(handle){
|
|
2900
|
-
if(handle==null)return;
|
|
2901
|
-
if(hasRaf)cancelAnimationFrame(handle);
|
|
2902
|
-
else clearTimeout(handle);
|
|
2903
3067
|
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
const
|
|
2908
|
-
|
|
2909
|
-
const
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
};
|
|
2913
|
-
const wrapped=(...args)=>{
|
|
2914
|
-
lastArgs=args;
|
|
2915
|
-
if(handle===null)handle=nextFrame(run);
|
|
2916
|
-
};
|
|
2917
|
-
wrapped.cancel=()=>{
|
|
2918
|
-
cancelFrame(handle);
|
|
2919
|
-
handle=null;
|
|
2920
|
-
lastArgs=null;
|
|
2921
|
-
};
|
|
2922
|
-
wrapped.flush=()=>{
|
|
2923
|
-
if(handle!==null){
|
|
2924
|
-
cancelFrame(handle);
|
|
2925
|
-
run();
|
|
3068
|
+
const forecast=overlay.forecast||[];
|
|
3069
|
+
if(forecast.length>=2){
|
|
3070
|
+
const seg=[];
|
|
3071
|
+
for(const point of forecast){
|
|
3072
|
+
const px=placeX(opts.xScale,point.x);
|
|
3073
|
+
const py=yScale.of(point.y);
|
|
3074
|
+
if(!Number.isFinite(px)||!Number.isFinite(py))continue;
|
|
3075
|
+
seg.push(seg.length?'L':'M',round(px),round(py));
|
|
2926
3076
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
3077
|
+
if(seg.length>=4){
|
|
3078
|
+
attrs(pool.next('path',`${NS}__trend-forecast`),{
|
|
3079
|
+
d:path(seg),
|
|
3080
|
+
fill:'none',
|
|
3081
|
+
stroke:colour,
|
|
3082
|
+
'data-series':series.index,
|
|
3083
|
+
});
|
|
2929
3084
|
}
|
|
2930
|
-
function settleDebounce(fn,waitMs){
|
|
2931
|
-
let timer=null;
|
|
2932
|
-
let held=null;
|
|
2933
|
-
const trailing=()=>{
|
|
2934
|
-
timer=null;
|
|
2935
|
-
if(held===null)return;
|
|
2936
|
-
const args=held;
|
|
2937
|
-
held=null;
|
|
2938
|
-
fn(...args);
|
|
2939
|
-
arm();
|
|
2940
|
-
};
|
|
2941
|
-
const arm=()=>{
|
|
2942
|
-
timer=setTimeout(trailing,waitMs);
|
|
2943
|
-
if(typeof timer?.unref==='function')timer.unref();
|
|
2944
|
-
};
|
|
2945
|
-
const wrapped=(...args)=>{
|
|
2946
|
-
if(timer===null){
|
|
2947
|
-
fn(...args);
|
|
2948
|
-
arm();
|
|
2949
|
-
}else{
|
|
2950
|
-
held=args;
|
|
2951
|
-
clearTimeout(timer);
|
|
2952
|
-
arm();
|
|
2953
3085
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
held=null;
|
|
2967
|
-
};
|
|
2968
|
-
wrapped.pending=()=>timer!==null||held!==null;
|
|
2969
|
-
return wrapped;
|
|
3086
|
+
if(spec.label!==false&&overlay.stats.method==='linear'
|
|
3087
|
+
&&Number.isFinite(overlay.stats.r2)){
|
|
3088
|
+
const last=overlay.fit[overlay.fit.length-1];
|
|
3089
|
+
const text=pool.next('text',`${NS}__trend-label`);
|
|
3090
|
+
applySize(text,opts.size);
|
|
3091
|
+
attrs(text,{
|
|
3092
|
+
x:round(placeX(opts.xScale,last.x)),
|
|
3093
|
+
y:round(yScale.of(last.y))-4,
|
|
3094
|
+
'text-anchor':'end',
|
|
3095
|
+
fill:colour,
|
|
3096
|
+
});
|
|
3097
|
+
setText(text,`R² ${overlay.stats.r2.toFixed(2)}`);
|
|
2970
3098
|
}
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
3099
|
+
described.push({
|
|
3100
|
+
text:trendText(overlay.stats,series.label,opts.format,forecast,
|
|
3101
|
+
spec.band===false?null:overlay.band,spec.band),
|
|
3102
|
+
});
|
|
2974
3103
|
}
|
|
2975
|
-
return setTimeout(()=>fn({timeRemaining:()=>0,didTimeout:true}),1);
|
|
2976
3104
|
}
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
return`${prefix}${(++idSeq).toString(36)}`;
|
|
3105
|
+
pool.finish();
|
|
3106
|
+
return described.filter((d)=>d.text);
|
|
2980
3107
|
}
|
|
2981
3108
|
});
|
|
2982
3109
|
__def("packages/modules/charts/cartesian.js",function(__exports,__req){
|
|
@@ -4476,7 +4603,7 @@ const measure=typeof entry==='string'?{col:entry}:entry;
|
|
|
4476
4603
|
return{
|
|
4477
4604
|
spec:measure,
|
|
4478
4605
|
result:bindSeries(grid,{
|
|
4479
|
-
x:spec.x,from:spec.from,limit:spec.limit,
|
|
4606
|
+
x:spec.x,from:spec.from,limit:spec.limit,axis:spec.axis,
|
|
4480
4607
|
y:{col:measure.col,fn:measure.fn},
|
|
4481
4608
|
}),
|
|
4482
4609
|
};
|
|
@@ -4495,7 +4622,7 @@ if(at!==undefined)aligned[at]=point;
|
|
|
4495
4622
|
}
|
|
4496
4623
|
return{
|
|
4497
4624
|
key:measure.col,
|
|
4498
|
-
label:measure.label||(column&&column.title)||measure.col,
|
|
4625
|
+
label:measure.title||measure.label||(column&&column.title)||measure.col,
|
|
4499
4626
|
index:i,
|
|
4500
4627
|
mark:measure.type||null,
|
|
4501
4628
|
axis:measure.axis==='right'?'right':'left',
|