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