prographs 0.12.0 → 0.13.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/CHANGELOG.md +9 -1
- package/README.md +6 -4
- package/dist/AutoGraph-PDPEAIXL.cjs +145 -0
- package/dist/GraphType.js +19 -0
- package/dist/autograph/chartIndex.js +521 -0
- package/dist/autograph/chartModules.js +2 -1
- package/dist/autograph/index.cjs +98 -93
- package/dist/catalog-DI4XZ46L.cjs +142 -0
- package/dist/catalog.js +2 -1
- package/dist/charts/biologycharts/BiologySamples.js +59 -0
- package/dist/charts/biologycharts/PunnettSquare.js +342 -0
- package/dist/charts/biologycharts/biologyEnums.js +22 -1
- package/dist/charts/biologycharts/index.js +5 -3
- package/dist/charts/doecharts/DoeSamples.js +78 -0
- package/dist/charts/doecharts/SipocDiagram.js +453 -0
- package/dist/charts/doecharts/index.js +4 -2
- package/dist/charts/fieldcharts/SpeciesAccumulationCurve.js +350 -0
- package/dist/charts/fieldcharts/fieldEnums.js +8 -1
- package/dist/charts/fieldcharts/index.js +5 -3
- package/dist/charts/signals/AntennaPatternChart.js +492 -0
- package/dist/charts/signals/SignalSamples.js +17 -0
- package/dist/charts/signals/index.js +5 -3
- package/dist/charts/softwarediagrams/ComponentDiagram.js +504 -0
- package/dist/charts/softwarediagrams/DeploymentDiagram.js +419 -0
- package/dist/charts/softwarediagrams/SoftwareSamples.js +283 -1
- package/dist/charts/softwarediagrams/index.js +7 -3
- package/dist/charts/softwarediagrams/softwareEnums.js +45 -1
- package/dist/charts/sportscharts/PowerDurationCurve.js +301 -0
- package/dist/charts/sportscharts/SportsSamples.js +102 -0
- package/dist/charts/sportscharts/TrainingLoadChart.js +325 -0
- package/dist/charts/sportscharts/index.js +6 -2
- package/dist/charts/strategycharts/BassDiffusionChart.js +362 -0
- package/dist/charts/strategycharts/BassModel.js +96 -0
- package/dist/charts/strategycharts/BurnRunwayChart.js +284 -0
- package/dist/charts/strategycharts/CapTableChart.js +366 -0
- package/dist/charts/strategycharts/KanbanBoard.js +324 -0
- package/dist/charts/strategycharts/OkrTree.js +339 -0
- package/dist/charts/strategycharts/StrategyPane.js +27 -0
- package/dist/charts/strategycharts/StrategySamples.js +251 -0
- package/dist/charts/strategycharts/index.js +15 -3
- package/dist/charts/threefields/BsfcMap3DChart.js +231 -0
- package/dist/charts/threefields/CompressorMap3DChart.js +217 -0
- package/dist/charts/threefields/FieldGrid.js +50 -0
- package/dist/charts/threefields/LossLandscape3DChart.js +201 -0
- package/dist/charts/threefields/MapSheet.js +77 -0
- package/dist/charts/threefields/TerrainRoute3DChart.js +201 -0
- package/dist/charts/threefields/TerrainRouteMath.js +40 -0
- package/dist/charts/threefields/ThreeFieldBase.js +117 -0
- package/dist/charts/threefields/ThreeFieldsSamples.js +80 -0
- package/dist/charts/threefields/WaferMap3DChart.js +218 -0
- package/dist/charts/threefields/index.js +19 -0
- package/dist/charts/threesurfaces/index.js +2 -2
- package/dist/charts/tradingcharts/KeltnerChannelChart.js +171 -0
- package/dist/charts/tradingcharts/TradingMath.js +20 -0
- package/dist/charts/tradingcharts/index.js +4 -2
- package/dist/{chunk-ZL6XDXMK.cjs → chunk-26PSLEP4.cjs} +8 -8
- package/dist/{chunk-W3US6EFP.cjs → chunk-2BO5DZUP.cjs} +12 -12
- package/dist/{chunk-5DP7OUSE.cjs → chunk-2GG5YYSC.cjs} +6 -6
- package/dist/{chunk-7FG4JSVO.cjs → chunk-2GL2VNJU.cjs} +253 -33
- package/dist/{chunk-LCWMRCLF.cjs → chunk-2PYOI7OY.cjs} +21 -21
- package/dist/{chunk-JFWJAEBD.cjs → chunk-3U4MCSKI.cjs} +4 -4
- package/dist/{chunk-CUPLHZRR.cjs → chunk-3ZMM3FSK.cjs} +4 -4
- package/dist/{chunk-L2AV62DP.cjs → chunk-4767WQJ7.cjs} +6 -6
- package/dist/{chunk-DA2EYIIP.cjs → chunk-4E7FSSBF.cjs} +1210 -168
- package/dist/{chunk-VS5LQEZB.cjs → chunk-526STI2S.cjs} +5 -5
- package/dist/{chunk-RXIMEK6C.cjs → chunk-55767YPI.cjs} +20 -20
- package/dist/{chunk-JXLSKIUV.cjs → chunk-5FBQOMMT.cjs} +26 -26
- package/dist/{chunk-27PZV5BR.cjs → chunk-5N4Z7MTS.cjs} +4 -4
- package/dist/{chunk-KEWCUIQA.cjs → chunk-5WEV6YWA.cjs} +22 -22
- package/dist/chunk-5XOVVC5X.cjs +3281 -0
- package/dist/{chunk-HK5J7Q2W.cjs → chunk-6HLXVWXU.cjs} +9 -9
- package/dist/{chunk-7JG47RW4.cjs → chunk-6LQT4WJ5.cjs} +25 -25
- package/dist/{chunk-OCVTI6X4.cjs → chunk-6YTWOUFD.cjs} +329 -36
- package/dist/{chunk-W7IQCAVN.cjs → chunk-7F6W6HKL.cjs} +11 -11
- package/dist/{chunk-F2DCJXDM.cjs → chunk-7L6KYU5A.cjs} +21 -21
- package/dist/{chunk-GTGR6LPR.cjs → chunk-A4GIN4FE.cjs} +17 -17
- package/dist/{chunk-B2CETSR6.cjs → chunk-A4US7SA7.cjs} +5 -5
- package/dist/{chunk-3DIF2YYW.cjs → chunk-AOXPBLPW.cjs} +10 -10
- package/dist/{chunk-7TTR4UF5.cjs → chunk-ATI45Z4M.cjs} +2 -2
- package/dist/{chunk-5BFCIX2V.cjs → chunk-CPPMO4IQ.cjs} +434 -148
- package/dist/{chunk-AYZZQ6AC.cjs → chunk-CZ5KGF6Q.cjs} +9 -9
- package/dist/{chunk-7THJ3ZBK.cjs → chunk-D4I35MCE.cjs} +2 -2
- package/dist/{chunk-MCPPFRLN.cjs → chunk-DCGAAN3Z.cjs} +2 -2
- package/dist/{chunk-VABL6CVX.cjs → chunk-DEY36N37.cjs} +21 -21
- package/dist/{chunk-RNCKGJCC.cjs → chunk-DXHXD3DK.cjs} +3 -3
- package/dist/{chunk-A56ZGMVZ.cjs → chunk-E7B45DBZ.cjs} +11 -11
- package/dist/{chunk-DOR6L4MT.cjs → chunk-EJC6EAC5.cjs} +18 -18
- package/dist/{chunk-UPGNM7MA.cjs → chunk-EULJOOMA.cjs} +11 -11
- package/dist/{chunk-G4AZL4GO.cjs → chunk-EYM6LEIF.cjs} +474 -70
- package/dist/{chunk-NJ4X6XGV.cjs → chunk-EZTYX2GH.cjs} +5 -5
- package/dist/chunk-FDD4UP73.cjs +521 -0
- package/dist/{chunk-WJ3VH2Q4.cjs → chunk-GEAIGM3J.cjs} +110 -615
- package/dist/{chunk-P3SBHF43.cjs → chunk-GRUYVXTS.cjs} +2 -2
- package/dist/{chunk-NX4Z5LMS.cjs → chunk-H3SZXND5.cjs} +5 -5
- package/dist/{chunk-EE4S4TOE.cjs → chunk-HS45TOFJ.cjs} +21 -21
- package/dist/chunk-INGOG6OV.cjs +899 -0
- package/dist/{chunk-UDKA6DGT.cjs → chunk-J3CDXZHF.cjs} +4 -4
- package/dist/{chunk-YO6G7TKI.cjs → chunk-JAU5ADEU.cjs} +11 -11
- package/dist/{chunk-22LBK4GA.cjs → chunk-JQEBSHX3.cjs} +4 -4
- package/dist/{chunk-RXX3U7VQ.cjs → chunk-KLXGLMFU.cjs} +10 -10
- package/dist/chunk-KVOX36J3.cjs +327 -0
- package/dist/chunk-L6BGNHFL.cjs +139 -0
- package/dist/{chunk-GMER35L3.cjs → chunk-L7TB7PU5.cjs} +20 -20
- package/dist/{chunk-AFXYNBL2.cjs → chunk-LBTRYEM2.cjs} +4 -4
- package/dist/{chunk-WYYCKIOD.cjs → chunk-LLULNJSP.cjs} +11 -11
- package/dist/{chunk-J27XOSLP.cjs → chunk-LSO46AFV.cjs} +8 -8
- package/dist/{chunk-5XJO45ES.cjs → chunk-LZ2KJ7ZX.cjs} +11 -11
- package/dist/chunk-M4IQ5LIZ.cjs +422 -0
- package/dist/{chunk-Y2KIUKJF.cjs → chunk-MPDHDKYZ.cjs} +11 -11
- package/dist/{chunk-4EMPKRZU.cjs → chunk-MRQ42ZJE.cjs} +3 -3
- package/dist/{chunk-EU5D2MF4.cjs → chunk-MYV4KZWP.cjs} +9 -9
- package/dist/{chunk-XD7KN4UN.cjs → chunk-MZXVLC24.cjs} +6 -6
- package/dist/{chunk-PPSONARU.cjs → chunk-NLBVDFIR.cjs} +41 -2
- package/dist/{chunk-L3PEGMGM.cjs → chunk-NY3TBZY4.cjs} +33 -33
- package/dist/{chunk-6YNYXXB6.cjs → chunk-OGVVSFAR.cjs} +3 -3
- package/dist/{chunk-MLV7QLB6.cjs → chunk-OMTQIQMN.cjs} +6 -6
- package/dist/{chunk-BEEOSNK7.cjs → chunk-PEJJ6TXJ.cjs} +15 -144
- package/dist/{chunk-SOKOWUF5.cjs → chunk-PPGWHIU7.cjs} +2 -2
- package/dist/{chunk-IELWOM2J.cjs → chunk-PPO6SDAN.cjs} +6 -6
- package/dist/{chunk-6JTZZCSL.cjs → chunk-PUMKX5F2.cjs} +3 -3
- package/dist/{chunk-RFOXFY2U.cjs → chunk-PXBYWCNB.cjs} +190 -799
- package/dist/{chunk-3BYXOISI.cjs → chunk-Q3HB3IX6.cjs} +4 -4
- package/dist/{chunk-RXCOVONX.cjs → chunk-RBMUOIXE.cjs} +289 -34
- package/dist/{chunk-MSBNHCSE.cjs → chunk-RJHGCUUD.cjs} +6 -6
- package/dist/{chunk-I6VG7F6Z.cjs → chunk-RSONDMYW.cjs} +708 -141
- package/dist/{chunk-GZDNPHMT.cjs → chunk-SHMPFCUE.cjs} +19 -19
- package/dist/{chunk-ZIBVCOW6.cjs → chunk-SN4FCXFC.cjs} +19 -19
- package/dist/{chunk-7KM52NMN.cjs → chunk-SN5T7WYO.cjs} +2 -2
- package/dist/{chunk-7MSZR65Z.cjs → chunk-SQJZGVDR.cjs} +7 -7
- package/dist/chunk-SYABFMD7.cjs +633 -0
- package/dist/{chunk-2RRFEYFH.cjs → chunk-TICB3MAC.cjs} +16 -16
- package/dist/{chunk-AOOKHUV5.cjs → chunk-U7Z7XYR2.cjs} +5 -5
- package/dist/{chunk-JEWQAXVG.cjs → chunk-UA2THQFV.cjs} +6 -6
- package/dist/{chunk-LHZPAHU3.cjs → chunk-VIK4L2YF.cjs} +112 -521
- package/dist/{chunk-4YWMAQ4J.cjs → chunk-VM2Y6BDY.cjs} +4 -4
- package/dist/{chunk-IRRKE2ZE.cjs → chunk-VMS3KWYI.cjs} +21 -21
- package/dist/{chunk-4SLARW6F.cjs → chunk-VU5NUD46.cjs} +17 -17
- package/dist/{chunk-XHY6TVYG.cjs → chunk-VV5CVOF7.cjs} +13 -13
- package/dist/{chunk-CCIBPGPZ.cjs → chunk-VYSAWPSS.cjs} +57 -57
- package/dist/{chunk-TTNEMQ2A.cjs → chunk-W7YRWEWQ.cjs} +22 -22
- package/dist/{chunk-C7MUOGEW.cjs → chunk-X7R5SY62.cjs} +6 -6
- package/dist/{chunk-ILR5KBMB.cjs → chunk-XOK3KTSS.cjs} +6 -6
- package/dist/{chunk-2CZM2I3T.cjs → chunk-XUIX45VU.cjs} +19 -19
- package/dist/{chunk-TGRMPS3A.cjs → chunk-XWH46PVJ.cjs} +165 -43
- package/dist/{chunk-WQYXXECR.cjs → chunk-Y5XVMK3K.cjs} +6 -6
- package/dist/{chunk-AK4TX2WG.cjs → chunk-YCNKEDTG.cjs} +13 -13
- package/dist/{chunk-PJJB24DU.cjs → chunk-YEF7SE3X.cjs} +20 -20
- package/dist/{chunk-RVLV4XW6.cjs → chunk-YMTVPMU3.cjs} +22 -22
- package/dist/data/index.cjs +2 -2
- package/dist/entries/autograph-lazy.cjs +2 -2
- package/dist/entries/charts/acoustictransport.cjs +3 -3
- package/dist/entries/charts/analysischarts.cjs +3 -3
- package/dist/entries/charts/astrocharts.cjs +3 -3
- package/dist/entries/charts/bars.cjs +3 -3
- package/dist/entries/charts/bayesiancharts.cjs +3 -3
- package/dist/entries/charts/biocharts.cjs +3 -3
- package/dist/entries/charts/biologycharts.cjs +11 -3
- package/dist/entries/charts/biologycharts.d.ts +1 -1
- package/dist/entries/charts/biologycharts.js +3 -2
- package/dist/entries/charts/business.cjs +3 -3
- package/dist/entries/charts/carecharts.cjs +3 -3
- package/dist/entries/charts/chemistrycharts.cjs +3 -3
- package/dist/entries/charts/civicscharts.cjs +3 -3
- package/dist/entries/charts/clinicalcharts.cjs +3 -3
- package/dist/entries/charts/comparison.cjs +3 -3
- package/dist/entries/charts/demography.cjs +3 -3
- package/dist/entries/charts/density.cjs +3 -3
- package/dist/entries/charts/diagrams.cjs +3 -3
- package/dist/entries/charts/distribution.cjs +3 -3
- package/dist/entries/charts/doecharts.cjs +13 -3
- package/dist/entries/charts/doecharts.d.ts +1 -1
- package/dist/entries/charts/doecharts.js +2 -1
- package/dist/entries/charts/earthscience.cjs +3 -3
- package/dist/entries/charts/economicscharts.cjs +3 -3
- package/dist/entries/charts/energycharts.cjs +3 -3
- package/dist/entries/charts/engineering.cjs +3 -3
- package/dist/entries/charts/fieldcharts.cjs +7 -3
- package/dist/entries/charts/fieldcharts.d.ts +1 -1
- package/dist/entries/charts/fieldcharts.js +3 -2
- package/dist/entries/charts/financial.cjs +3 -3
- package/dist/entries/charts/flow.cjs +3 -3
- package/dist/entries/charts/frameworks.cjs +3 -3
- package/dist/entries/charts/genomics.cjs +3 -3
- package/dist/entries/charts/geoflows.cjs +3 -3
- package/dist/entries/charts/geomaps.cjs +3 -3
- package/dist/entries/charts/geosciencecharts.cjs +3 -3
- package/dist/entries/charts/hierarchy.cjs +3 -3
- package/dist/entries/charts/indicators.cjs +3 -3
- package/dist/entries/charts/inferencecharts.cjs +3 -3
- package/dist/entries/charts/layoutcharts.cjs +3 -3
- package/dist/entries/charts/lifescience.cjs +4 -4
- package/dist/entries/charts/linesareas.cjs +3 -3
- package/dist/entries/charts/logisticscharts.cjs +3 -3
- package/dist/entries/charts/machinecharts.cjs +7 -3
- package/dist/entries/charts/machinecharts.d.ts +1 -1
- package/dist/entries/charts/machinecharts.js +2 -1
- package/dist/entries/charts/massive.cjs +3 -3
- package/dist/entries/charts/mathematical.cjs +3 -3
- package/dist/entries/charts/matrix.cjs +3 -3
- package/dist/entries/charts/medicalcharts.cjs +4 -4
- package/dist/entries/charts/mlcharts.cjs +4 -4
- package/dist/entries/charts/modelcharts.cjs +6 -5
- package/dist/entries/charts/multivariate.cjs +3 -3
- package/dist/entries/charts/musiccharts.cjs +3 -3
- package/dist/entries/charts/network.cjs +3 -3
- package/dist/entries/charts/physicscharts.cjs +3 -3
- package/dist/entries/charts/pictorial.cjs +4 -4
- package/dist/entries/charts/portfoliocharts.cjs +3 -3
- package/dist/entries/charts/productcharts.cjs +3 -3
- package/dist/entries/charts/proportion.cjs +3 -3
- package/dist/entries/charts/qualitycharts.cjs +3 -3
- package/dist/entries/charts/radial.cjs +3 -3
- package/dist/entries/charts/reliabilitycharts.cjs +5 -3
- package/dist/entries/charts/scatter.cjs +3 -3
- package/dist/entries/charts/scientific.cjs +3 -3
- package/dist/entries/charts/seriescharts.cjs +3 -3
- package/dist/entries/charts/signals.cjs +7 -3
- package/dist/entries/charts/signals.d.ts +1 -1
- package/dist/entries/charts/signals.js +2 -1
- package/dist/entries/charts/softwarediagrams.cjs +21 -3
- package/dist/entries/charts/softwarediagrams.d.ts +1 -1
- package/dist/entries/charts/softwarediagrams.js +4 -2
- package/dist/entries/charts/sportscharts.cjs +13 -3
- package/dist/entries/charts/sportscharts.d.ts +1 -1
- package/dist/entries/charts/sportscharts.js +3 -1
- package/dist/entries/charts/statistics.cjs +6 -6
- package/dist/entries/charts/strategycharts.cjs +30 -3
- package/dist/entries/charts/strategycharts.d.ts +1 -1
- package/dist/entries/charts/strategycharts.js +6 -1
- package/dist/entries/charts/structure.cjs +3 -3
- package/dist/entries/charts/surveycharts.cjs +3 -3
- package/dist/entries/charts/systemscharts.cjs +3 -3
- package/dist/entries/charts/textcharts.cjs +5 -5
- package/dist/entries/charts/thematicmaps.cjs +4 -4
- package/dist/entries/charts/threebars.cjs +3 -3
- package/dist/entries/charts/threefields.cjs +53 -0
- package/dist/entries/charts/threefields.d.ts +1 -0
- package/dist/entries/charts/threefields.js +6 -0
- package/dist/entries/charts/threeglobe.cjs +3 -3
- package/dist/entries/charts/threenetwork.cjs +3 -3
- package/dist/entries/charts/threestrata.cjs +3 -3
- package/dist/entries/charts/threesurfaces.cjs +7 -3
- package/dist/entries/charts/threesurfaces.d.ts +1 -1
- package/dist/entries/charts/threesurfaces.js +2 -1
- package/dist/entries/charts/threevolume.cjs +4 -4
- package/dist/entries/charts/timeline.cjs +3 -3
- package/dist/entries/charts/tracecharts.cjs +3 -3
- package/dist/entries/charts/trackscharts.cjs +3 -3
- package/dist/entries/charts/tradingcharts.cjs +6 -4
- package/dist/entries/charts/tradingcharts.d.ts +1 -1
- package/dist/entries/charts/tradingcharts.js +2 -1
- package/dist/entries/three.cjs +60 -20
- package/dist/entries/three.d.ts +1 -1
- package/dist/entries/three.js +7 -1
- package/dist/index.cjs +258 -97
- package/dist/index.d.cts +1953 -10
- package/dist/index.d.ts +1953 -10
- package/dist/index.js +26 -5
- package/dist/page/index.cjs +2 -2
- package/dist/react/components.js +58 -1
- package/dist/react/index.cjs +135 -92
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +2 -2
- package/package.json +1 -1
- package/dist/AutoGraph-XLBJQDRB.cjs +0 -140
- package/dist/catalog-O7XGDD2H.cjs +0 -137
- package/dist/chunk-77K2HTRC.cjs +0 -3220
- package/dist/chunk-XEK47TVD.cjs +0 -323
- /package/dist/{chunk-UMEKIIHJ.cjs → chunk-LNWTC72Y.cjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12; var _class13; var _class14; var _class15; var _class16;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10; var _class11; var _class12; var _class13; var _class14; var _class15; var _class16; var _class17; var _class18;
|
|
2
2
|
|
|
3
3
|
var _chunkXX2YTCORcjs = require('./chunk-XX2YTCOR.cjs');
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ var _chunkEEF5WRRZcjs = require('./chunk-EEF5WRRZ.cjs');
|
|
|
10
10
|
var _chunkPY4R3IFFcjs = require('./chunk-PY4R3IFF.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunkLNWTC72Ycjs = require('./chunk-LNWTC72Y.cjs');
|
|
14
14
|
|
|
15
15
|
// src/charts/sportscharts/FootballPitch.ts
|
|
16
16
|
var PitchCoordinates = /* @__PURE__ */ ((PitchCoordinates2) => {
|
|
@@ -80,7 +80,7 @@ var FootballPitch = (_class = class {
|
|
|
80
80
|
{ key: "corner-a", points: circle(LENGTH, 0, 1, Math.PI / 2, Math.PI) },
|
|
81
81
|
{ key: "corner-b", points: circle(LENGTH, WIDTH, 1, Math.PI, Math.PI * 1.5) }
|
|
82
82
|
];
|
|
83
|
-
return lines.map((
|
|
83
|
+
return lines.map((line6) => ({ ...line6, key: `${key}-${line6.key}`, points: flip ? line6.points.map((point) => this.flip(point)) : line6.points }));
|
|
84
84
|
}
|
|
85
85
|
/** The markings a view shows, in pitch metres. */
|
|
86
86
|
static markings(view) {
|
|
@@ -142,7 +142,7 @@ var SportsFieldChart = class extends _chunkEEF5WRRZcjs.Chart2D {
|
|
|
142
142
|
}
|
|
143
143
|
/** Paints field lines in a frame group, which `chartStyle` leaves alone. */
|
|
144
144
|
fieldLines(ctx, name, lines, frame) {
|
|
145
|
-
ctx.marks(`axis-${name}`, "path", lines, (
|
|
145
|
+
ctx.marks(`axis-${name}`, "path", lines, (line6) => line6.key).attr("d", (line6) => this.trace(line6.points, frame, line6.filled)).attr("fill", (line6) => line6.filled ? ctx.theme.grid : "none").attr("fill-opacity", (line6) => line6.filled ? 0.5 : null).attr("stroke", (line6) => line6.filled ? "none" : line6.strong ? ctx.theme.inkMuted : ctx.theme.axis).attr("stroke-width", 1.25).attr("stroke-dasharray", (line6) => line6.dashed ? "5 4" : null);
|
|
146
146
|
}
|
|
147
147
|
/** Text that never takes a series colour, cut to the room left in the plot. */
|
|
148
148
|
captions(ctx, name, items) {
|
|
@@ -204,6 +204,11 @@ var GOLF_BAG = [
|
|
|
204
204
|
{ club: "8 iron", target: 150, long: 6, wide: 7, bias: -2 },
|
|
205
205
|
{ club: "Wedge", target: 105, long: 4.5, wide: 4.5, bias: 0 }
|
|
206
206
|
];
|
|
207
|
+
var RIDERS = ["Ines Halvard", "Tomas Rehn", "Mirela Stanek", "Jonah Averill"];
|
|
208
|
+
var POWER_PERIODS = ["This season", "Last season", "Two seasons ago"];
|
|
209
|
+
var POWER_DURATIONS = [1, 2, 3, 5, 8, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300, 420, 600, 900, 1200, 1800, 2700, 3600, 5400, 7200, 10800, 14400, 18e3];
|
|
210
|
+
var TRAINING_WEEK = [0, 85, 60, 95, 0, 150, 110];
|
|
211
|
+
var TRAINING_BLOCK = [0.85, 1, 1.2, 0.55];
|
|
207
212
|
var weighted = (items, roll) => {
|
|
208
213
|
let pick = roll * items.reduce((sum, item) => sum + (_nullishCoalesce(_nullishCoalesce(item.weight, () => ( item.share)), () => ( 1))), 0);
|
|
209
214
|
for (const item of items) {
|
|
@@ -219,7 +224,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
219
224
|
}
|
|
220
225
|
/** `{ team, player, minute, x, y, xg, outcome }`, in metres, every team attacking the right-hand goal. */
|
|
221
226
|
static shots(seed) {
|
|
222
|
-
const { u, n } =
|
|
227
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed), { LENGTH, WIDTH, GOAL_WIDTH } = FootballPitch;
|
|
223
228
|
const shot = (team, names) => {
|
|
224
229
|
const depth = clamp(6 + Math.abs(n()) * 11, 3, 33), wide = clamp(n() * (3 + depth * 0.6), -26, 26);
|
|
225
230
|
const distance = Math.hypot(depth, wide);
|
|
@@ -234,7 +239,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
234
239
|
}
|
|
235
240
|
/** `{ passer, receiver, shirt, x, y, endX, endY }`, one row per completed pass, in metres, attacking right. */
|
|
236
241
|
static passes(seed) {
|
|
237
|
-
const { u, n } =
|
|
242
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
238
243
|
const reach = LINEUP.map((a) => LINEUP.map((b) => a === b || a.shirt === 1 && b.x > 40 ? 0 : Math.exp(-Math.hypot(a.x - b.x, a.y - b.y) / 14) * (b.x > 70 ? 0.75 : 1)));
|
|
239
244
|
return Array.from({ length: 420 }, () => {
|
|
240
245
|
const from = clamp(Math.floor(u() ** 1.2 * LINEUP.length * 0.9 + u() * 1.4), 0, LINEUP.length - 1), a = LINEUP[from], weights = reach[from];
|
|
@@ -246,7 +251,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
246
251
|
}
|
|
247
252
|
/** `{ angle, distance, trajectory, result }`: spray angle in degrees, negative toward left field, and feet from the plate. */
|
|
248
253
|
static battedBalls(seed, lines = 330, centre = 400) {
|
|
249
|
-
const { u, n } =
|
|
254
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
250
255
|
return Array.from({ length: 150 }, () => {
|
|
251
256
|
const kind = u(), angle = clamp(n() * 22 - 4, -44, 44), wall = lines + (centre - lines) * Math.cos(2 * angle * Math.PI / 180);
|
|
252
257
|
if (kind < 0.44) {
|
|
@@ -264,7 +269,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
264
269
|
}
|
|
265
270
|
/** `{ ball, angle, distance, runs }`, one row per legal ball: angle in degrees from straight, positive to the off side, and metres from the striker. */
|
|
266
271
|
static deliveries(seed) {
|
|
267
|
-
const { u, n } =
|
|
272
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
268
273
|
const zones = [{ at: 35, spread: 20, weight: 0.34 }, { at: 100, spread: 18, weight: 0.14 }, { at: -60, spread: 24, weight: 0.3 }, { at: -125, spread: 22, weight: 0.12 }, { at: -8, spread: 12, weight: 0.1 }];
|
|
269
274
|
return Array.from({ length: 72 }, (_, i) => {
|
|
270
275
|
const roll = u(), runs = roll < 0.38 ? 0 : roll < 0.72 ? 1 : roll < 0.8 ? 2 : roll < 0.82 ? 3 : roll < 0.95 ? 4 : 6;
|
|
@@ -277,7 +282,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
277
282
|
}
|
|
278
283
|
/** `{ serve, x, y, rally, won }`: metres across from the centre line, left negative from behind the server, and metres past the net. */
|
|
279
284
|
static serves(seed) {
|
|
280
|
-
const { u, n } =
|
|
285
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
281
286
|
return Array.from({ length: 140 }, () => {
|
|
282
287
|
const serve = u() < 0.64 ? 1 : 2, deuce = u() < 0.5, aim = u();
|
|
283
288
|
const lane = serve === 1 ? aim < 0.42 ? 0.86 : aim < 0.86 ? 0.14 : 0.5 : aim < 0.2 ? 0.8 : aim < 0.5 ? 0.2 : 0.5;
|
|
@@ -290,7 +295,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
290
295
|
}
|
|
291
296
|
/** `{ minute, team, probability, leverage, event }`, a row for each side each minute of an 80 minute match in which the side behind scores a little more often. `leverage` is the swing a converted try either way would cause. */
|
|
292
297
|
static winProbability(seed) {
|
|
293
|
-
const { u, n } =
|
|
298
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed), edge = (u() - 0.5) * 4;
|
|
294
299
|
const chance = (lead2, minute) => {
|
|
295
300
|
const left = Math.max(0, 80 - minute) / 80;
|
|
296
301
|
if (!left) return lead2 > 0 ? 1 : lead2 < 0 ? 0 : 0.5;
|
|
@@ -311,7 +316,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
311
316
|
}
|
|
312
317
|
/** `{ over, team, runs, wickets }`: what each over of a 20 over innings added, the second side stopping once it passes the first. */
|
|
313
318
|
static overs(seed) {
|
|
314
|
-
const { u, n } =
|
|
319
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
315
320
|
const innings = (team, target) => {
|
|
316
321
|
const rows = [];
|
|
317
322
|
for (let over = 1, total = 0, out = 0; over <= 20 && out < 10 && total <= target; over++) {
|
|
@@ -328,7 +333,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
328
333
|
}
|
|
329
334
|
/** `{ player, category, metric, value, percentile }`: per 90 figures of two midfielders and where each ranks among players in the position. */
|
|
330
335
|
static percentiles(seed) {
|
|
331
|
-
const { n } =
|
|
336
|
+
const { n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
332
337
|
return ["Lund", "Sousa"].flatMap((player, p) => PIZZA_METRICS.map(([category, metric, low, high, digits]) => {
|
|
333
338
|
const lean = category === "Attacking" ? 14 : category === "Defending" ? -12 : 6;
|
|
334
339
|
const percentile = clamp(Math.round(52 + (p ? -lean : lean) + n() * 20), 2, 99);
|
|
@@ -337,7 +342,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
337
342
|
}
|
|
338
343
|
/** `{ x, z, pitch, speed, result }`: feet across from the middle of the plate as the catcher sees it, feet above the ground, and miles an hour. */
|
|
339
344
|
static pitches(seed) {
|
|
340
|
-
const { u, n } =
|
|
345
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
341
346
|
return Array.from({ length: 96 }, () => {
|
|
342
347
|
const kind = weighted(PITCH_MIX, u());
|
|
343
348
|
const x = round(kind.x + n() * kind.spread), z = round(clamp(kind.z + n() * kind.spread * 1.1, 0.2, 4.8));
|
|
@@ -351,7 +356,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
351
356
|
* `event` reads `Pit` on an in-lap and `Retired` on a car's last lap, and `flag` names a neutralised lap.
|
|
352
357
|
*/
|
|
353
358
|
static raceLaps(seed, laps = 30) {
|
|
354
|
-
const { u, n } =
|
|
359
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed), caution = 11 + Math.floor(u() * 6);
|
|
355
360
|
const quitters = /* @__PURE__ */ new Map([[2 + Math.floor(u() * 4), 8 + Math.floor(u() * 6)], [6 + Math.floor(u() * 4), 18 + Math.floor(u() * 8)]]);
|
|
356
361
|
const cars = RACE_GRID.map(([driver, team], index) => {
|
|
357
362
|
const two = u() < 0.4, hard = u() < 0.5;
|
|
@@ -397,7 +402,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
397
402
|
}
|
|
398
403
|
/** `{ player, type, x, y }`: where one wide player touched the ball, in metres, attacking right. */
|
|
399
404
|
static touches(seed) {
|
|
400
|
-
const { u, n } =
|
|
405
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
401
406
|
return Array.from({ length: 360 }, () => {
|
|
402
407
|
const spot = weighted(TOUCH_SPOTS, u());
|
|
403
408
|
return { player: "Amadi", type: TOUCH_KINDS[Math.floor(u() * TOUCH_KINDS.length)], x: round(clamp(spot.x + n() * spot.sx, 0, 105), 1), y: round(clamp(spot.y + n() * spot.sy, 0, 68), 1) };
|
|
@@ -405,7 +410,7 @@ var SportsSamples = class _SportsSamples {
|
|
|
405
410
|
}
|
|
406
411
|
/** `{ team, player, period, x, y, result }`: feet from centre ice, the first team shooting at the goal on the right. */
|
|
407
412
|
static rinkShots(seed) {
|
|
408
|
-
const { u, n } =
|
|
413
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
409
414
|
const shot = (team, names, side) => {
|
|
410
415
|
const distance = clamp(8 + Math.abs(n()) * 22, 5, 62), angle = clamp(n() * 0.75, -1.35, 1.35);
|
|
411
416
|
const quality = 0.34 * Math.exp(-distance / 18) * Math.cos(angle), roll = u();
|
|
@@ -417,12 +422,42 @@ var SportsSamples = class _SportsSamples {
|
|
|
417
422
|
}
|
|
418
423
|
/** `{ club, target, carry, offline }` in yards: the distance aimed for, the distance flown, and how far right of the target line the ball landed. */
|
|
419
424
|
static golfShots(seed) {
|
|
420
|
-
const { n } =
|
|
425
|
+
const { n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
421
426
|
return GOLF_BAG.flatMap(({ club, target, long, wide, bias }) => Array.from({ length: 18 }, () => {
|
|
422
427
|
const side = n(), depth = n();
|
|
423
428
|
return { club, target, carry: round(target - 2 + depth * long - Math.abs(side) * long * 0.45, 1), offline: round(bias + side * wide, 1) };
|
|
424
429
|
}));
|
|
425
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* `{ athlete, period, duration, power, weight }`: one rider's best mean power in watts for efforts of a second to five hours,
|
|
433
|
+
* this season and the two before, with body weight in kilograms. Power follows a three-parameter critical power curve that fades past half an hour.
|
|
434
|
+
*/
|
|
435
|
+
static powerCurve(seed) {
|
|
436
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
437
|
+
const athlete = RIDERS[Math.floor(u() * RIDERS.length)], cp = 250 + u() * 55, reserve = 17e3 + u() * 8e3, sprint = 950 + u() * 350, mass = 62 + u() * 14;
|
|
438
|
+
return POWER_PERIODS.flatMap((period, back) => {
|
|
439
|
+
const steady = cp * (1 - back * (0.03 + u() * 0.02)), burst = reserve * (1 - back * 0.06), top = sprint * [1, 1.04, 0.97][back];
|
|
440
|
+
const weight = round(mass + back * 0.9 + n() * 0.3, 1);
|
|
441
|
+
let best = Infinity;
|
|
442
|
+
return POWER_DURATIONS.map((duration) => {
|
|
443
|
+
const fade = duration > 1800 ? 1 - 0.06 * Math.log(duration / 1800) : 1;
|
|
444
|
+
best = Math.min(best, Math.round((steady + burst / (duration + burst / (top - steady))) * fade * (1 + n() * 8e-3)));
|
|
445
|
+
return { athlete, period, duration, power: best, weight };
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
/** `{ date, athlete, load }`: a training stress score for each session of 20 weeks in four week blocks, ending in a taper and a race. Rest days and missed sessions have no row. */
|
|
450
|
+
static trainingLoad(seed, weeks = 20) {
|
|
451
|
+
const { u, n } = _chunkLNWTC72Ycjs.SampleData.rng(seed);
|
|
452
|
+
const athlete = RIDERS[Math.floor(u() * RIDERS.length)], start = Date.UTC(2025, 1, 3 + 7 * (seed % 4)), last = weeks * 7 - 1;
|
|
453
|
+
return Array.from({ length: weeks * 7 }, (_, day) => {
|
|
454
|
+
const week = Math.floor(day / 7), left = weeks - 1 - week;
|
|
455
|
+
const share = left === 0 ? 0.45 : left === 1 ? 0.7 : TRAINING_BLOCK[week % 4] * (0.7 + week * 0.035);
|
|
456
|
+
const planned = day === last ? 240 : TRAINING_WEEK[day % 7] * share;
|
|
457
|
+
if (!planned || day !== last && u() < 0.06) return [];
|
|
458
|
+
return [{ date: new Date(start + day * 864e5).toISOString().slice(0, 10), athlete, load: Math.max(10, Math.round(planned * (1 + n() * 0.12))) }];
|
|
459
|
+
}).flat();
|
|
460
|
+
}
|
|
426
461
|
};
|
|
427
462
|
|
|
428
463
|
// src/charts/sportscharts/BaseballSprayChart.ts
|
|
@@ -573,7 +608,7 @@ var BaseballSprayChart = (_class2 = class extends SportsFieldChart {
|
|
|
573
608
|
for (const name of HITS) if (balls.some((ball) => ball.result === name)) ctx.palette.color(name);
|
|
574
609
|
}
|
|
575
610
|
this.#drawSectors(ctx, sectors ? this.sectorsOf(balls) : [], frame);
|
|
576
|
-
this.fieldLines(ctx, "field", this.#field(reach).filter((
|
|
611
|
+
this.fieldLines(ctx, "field", this.#field(reach).filter((line6) => !(sectors && line6.key === "turf")), frame);
|
|
577
612
|
const rings = [100, 200, 300, 400, 500].filter((ring2) => ring2 < reach);
|
|
578
613
|
this.captions(ctx, "rings", rings.map((ring2) => {
|
|
579
614
|
const [x, y] = ground(-FAIR, ring2);
|
|
@@ -724,9 +759,9 @@ var CricketWagonWheel = (_class3 = class extends SportsFieldChart {
|
|
|
724
759
|
const zoned = marks === "zones" /* Zones */;
|
|
725
760
|
const reach = boundary * 1.02;
|
|
726
761
|
const frame = this.frame({ x: 0, y: 0, width: ctx.plot.width, height: ctx.plot.height - FOOT2 }, [-reach, reach], [-reach, reach]);
|
|
727
|
-
this.fieldLines(ctx, "ground", this.#ground().filter((
|
|
762
|
+
this.fieldLines(ctx, "ground", this.#ground().filter((line6) => !(zoned && line6.key === "outfield")), frame);
|
|
728
763
|
this.#drawZones(ctx, zoned ? this.zonesOf(balls) : [], frame);
|
|
729
|
-
this.fieldLines(ctx, "pitch-top", zoned ? this.#ground().filter((
|
|
764
|
+
this.fieldLines(ctx, "pitch-top", zoned ? this.#ground().filter((line6) => line6.key !== "outfield") : [], frame);
|
|
730
765
|
this.#drawRays(ctx, zoned ? [] : this.#shown(balls), frame);
|
|
731
766
|
const right = hand === "right" /* Right */;
|
|
732
767
|
this.captions(ctx, "sides", [
|
|
@@ -949,7 +984,7 @@ var HockeyRink = (_class5 = class {
|
|
|
949
984
|
{ key: `neutral${side}`, points: arc(NEUTRAL_SPOT, side * SPOT_Y, 1, 0, Math.PI * 2, 8), filled: true }
|
|
950
985
|
])
|
|
951
986
|
];
|
|
952
|
-
return lines.map((
|
|
987
|
+
return lines.map((line6) => ({ ...line6, key: `${key}-${line6.key}`, points: flip ? line6.points.map((point) => this.flip(point)) : line6.points }));
|
|
953
988
|
}
|
|
954
989
|
/** The lines, circles and creases a view shows, in rink feet. */
|
|
955
990
|
static markings(view) {
|
|
@@ -1108,7 +1143,7 @@ var HockeyRinkShotMap = (_class6 = class _HockeyRinkShotMap extends SportsFieldC
|
|
|
1108
1143
|
const frame = this.frame({ x: 0, y: 0, width: ctx.plot.width, height: ctx.plot.height - FOOT4 }, wide, tall);
|
|
1109
1144
|
const seen = (point) => HockeyRink.project(view, point);
|
|
1110
1145
|
this.#drawBins(ctx, binned ? this.binsOf(attempts) : [], seen, frame);
|
|
1111
|
-
this.fieldLines(ctx, "rink", HockeyRink.markings(view).map((
|
|
1146
|
+
this.fieldLines(ctx, "rink", HockeyRink.markings(view).map((line6) => ({ ...line6, points: line6.points.map(seen) })), frame);
|
|
1112
1147
|
this.#drawShots(ctx, binned ? [] : attempts, (shot) => {
|
|
1113
1148
|
const [x, y] = seen(shot.at);
|
|
1114
1149
|
return [frame.x(x), frame.y(y)];
|
|
@@ -1218,7 +1253,7 @@ var PassingNetworkPitch = (_class7 = class extends SportsFieldChart {
|
|
|
1218
1253
|
const [x, y] = seen([node.x, node.y]);
|
|
1219
1254
|
return [frame.x(x), frame.y(y)];
|
|
1220
1255
|
};
|
|
1221
|
-
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((
|
|
1256
|
+
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((line6) => ({ ...line6, points: line6.points.map(seen) })), frame);
|
|
1222
1257
|
const busiest = Math.max(1, ...nodes.map((node) => node.passes + node.received));
|
|
1223
1258
|
const radius = (node) => Math.max(MIN_RADIUS, MAX_RADIUS * Math.sqrt((node.passes + node.received) / busiest));
|
|
1224
1259
|
const peak = Math.max(1, ...links.map((link) => link.passes));
|
|
@@ -1377,7 +1412,7 @@ var PitchHeatmap = (_class8 = class extends SportsFieldChart {
|
|
|
1377
1412
|
const cells = bins === "grid" /* Grid */ ? this.gridCells(events) : bins === "hex" /* Hex */ ? this.hexCells(events) : [];
|
|
1378
1413
|
this.#drawCells(ctx, cells, seen, frame, Math.max(1, events.length));
|
|
1379
1414
|
this.#drawContours(ctx, bins === "contour" /* Contour */ ? events : [], seen, frame);
|
|
1380
|
-
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((
|
|
1415
|
+
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((line6) => ({ ...line6, points: line6.points.map(seen) })), frame);
|
|
1381
1416
|
const note = events.length ? `${events.length} events, attacking ${upright ? "up" : "right"}. Tone: events in the area` : "No events on the pitch";
|
|
1382
1417
|
this.captions(ctx, "note", [{ key: "note", text: note, x: 0, y: ctx.plot.height - 3, tone: "muted" }]);
|
|
1383
1418
|
}
|
|
@@ -1498,7 +1533,7 @@ var PizzaChart = (_class9 = class extends SportsFieldChart {
|
|
|
1498
1533
|
}
|
|
1499
1534
|
}, _class9.__initStatic30(), _class9);
|
|
1500
1535
|
|
|
1501
|
-
// src/charts/sportscharts/
|
|
1536
|
+
// src/charts/sportscharts/PowerDurationCurve.ts
|
|
1502
1537
|
|
|
1503
1538
|
|
|
1504
1539
|
// src/charts/sportscharts/SportsTimelineChart.ts
|
|
@@ -1522,14 +1557,212 @@ var SportsTimelineChart = class extends _chunkXX2YTCORcjs.CartesianChart {
|
|
|
1522
1557
|
}
|
|
1523
1558
|
};
|
|
1524
1559
|
|
|
1560
|
+
// src/charts/sportscharts/PowerDurationCurve.ts
|
|
1561
|
+
var PowerDurationUnit = /* @__PURE__ */ ((PowerDurationUnit2) => {
|
|
1562
|
+
PowerDurationUnit2["Watts"] = "watts";
|
|
1563
|
+
PowerDurationUnit2["PerKilogram"] = "watts-per-kg";
|
|
1564
|
+
return PowerDurationUnit2;
|
|
1565
|
+
})(PowerDurationUnit || {});
|
|
1566
|
+
var STANDARD = [5, 60, 300, 1200, 3600];
|
|
1567
|
+
var ROUND = [1, 18e3, 10, 30, 600, 1800, 7200, 36e3, 86400, 2, 15, 120, 10800];
|
|
1568
|
+
var TICK_GAP = 40;
|
|
1569
|
+
var DOT2 = 4.5;
|
|
1570
|
+
var CHAR4 = 6.2;
|
|
1571
|
+
var PowerDurationCurve = (_class10 = class _PowerDurationCurve extends SportsTimelineChart {
|
|
1572
|
+
static __initStatic31() {this.meta = {
|
|
1573
|
+
id: "power-duration-curve",
|
|
1574
|
+
name: "Power-duration curve",
|
|
1575
|
+
family: "trend" /* Trend */,
|
|
1576
|
+
dimension: 2 /* Two */,
|
|
1577
|
+
shape: "table" /* Table */,
|
|
1578
|
+
description: "Plots an athlete's best mean power against effort duration on a log axis, with the fitted critical power model, earlier periods for reference and the standard durations marked, in watts or watts per kilogram. The sample rider is invented.",
|
|
1579
|
+
tags: ["sports", "cycling", "critical power", "mean maximal power", "W prime", "power profile"],
|
|
1580
|
+
sample: (seed) => SportsSamples.powerCurve(seed),
|
|
1581
|
+
variants: {
|
|
1582
|
+
unit: ["watts" /* Watts */, "watts-per-kg" /* PerKilogram */],
|
|
1583
|
+
model: [true, false],
|
|
1584
|
+
references: [true, false],
|
|
1585
|
+
markers: [true, false]
|
|
1586
|
+
}
|
|
1587
|
+
}}
|
|
1588
|
+
#periods = [];
|
|
1589
|
+
#fit = null;
|
|
1590
|
+
#who = "";
|
|
1591
|
+
#timeAxis = null;
|
|
1592
|
+
#powerAxis = null;
|
|
1593
|
+
defaults() {
|
|
1594
|
+
return {
|
|
1595
|
+
x: "duration",
|
|
1596
|
+
y: "power",
|
|
1597
|
+
period: "period",
|
|
1598
|
+
weight: "weight",
|
|
1599
|
+
athlete: "athlete",
|
|
1600
|
+
unit: "watts" /* Watts */,
|
|
1601
|
+
model: true,
|
|
1602
|
+
fitWindow: [120, 1800],
|
|
1603
|
+
references: true,
|
|
1604
|
+
markers: true
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
get #perKilo() {
|
|
1608
|
+
return this.options.unit === "watts-per-kg" /* PerKilogram */;
|
|
1609
|
+
}
|
|
1610
|
+
get #unit() {
|
|
1611
|
+
return this.#perKilo ? "W/kg" : "W";
|
|
1612
|
+
}
|
|
1613
|
+
#value(power) {
|
|
1614
|
+
return this.#perKilo ? power.toFixed(power < 10 ? 2 : 1) : Math.round(power).toLocaleString("en");
|
|
1615
|
+
}
|
|
1616
|
+
/** A duration in the largest units that keep it whole: `5 s`, `20 min`, `1 h 30 min`. */
|
|
1617
|
+
static span(seconds) {
|
|
1618
|
+
if (seconds < 60) return `${+seconds.toFixed(1)} s`;
|
|
1619
|
+
const whole = Math.round(seconds), minutes = Math.round(whole / 60);
|
|
1620
|
+
if (whole < 3600) return whole % 60 ? `${Math.floor(whole / 60)} min ${whole % 60} s` : `${whole / 60} min`;
|
|
1621
|
+
return minutes % 60 ? `${Math.floor(minutes / 60)} h ${minutes % 60} min` : `${minutes / 60} h`;
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Least squares fit of P = CP + W'/t to the readings inside `window`, as a straight line of power against 1/t.
|
|
1625
|
+
* `null` with fewer than two durations there, or when the line gives a critical power or W' at or below zero.
|
|
1626
|
+
*/
|
|
1627
|
+
static fit(points, [from, to]) {
|
|
1628
|
+
const used = points.filter((point) => point.t >= from && point.t <= to), n = used.length;
|
|
1629
|
+
let sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
1630
|
+
for (const { t, p } of used) {
|
|
1631
|
+
sx += 1 / t;
|
|
1632
|
+
sy += p;
|
|
1633
|
+
sxx += 1 / (t * t);
|
|
1634
|
+
sxy += p / t;
|
|
1635
|
+
}
|
|
1636
|
+
const spread = n * sxx - sx * sx;
|
|
1637
|
+
if (n < 2 || spread <= 1e-15) return null;
|
|
1638
|
+
const wPrime = (n * sxy - sx * sy) / spread, cp = (sy - wPrime * sx) / n;
|
|
1639
|
+
return cp > 0 && wPrime > 0 ? { cp, wPrime } : null;
|
|
1640
|
+
}
|
|
1641
|
+
/** Power at `t` seconds, read between the two nearest durations along log time. `null` outside the curve. */
|
|
1642
|
+
static at(points, t) {
|
|
1643
|
+
const after = points.findIndex((point) => point.t >= t), b = points[after];
|
|
1644
|
+
if (!b) return null;
|
|
1645
|
+
if (b.t === t) return b.p;
|
|
1646
|
+
const a = points[after - 1];
|
|
1647
|
+
return a ? a.p + (b.p - a.p) * Math.log(t / a.t) / Math.log(b.t / a.t) : null;
|
|
1648
|
+
}
|
|
1649
|
+
/** Axis ticks at round durations at least `gap` px apart, the standard test durations first. */
|
|
1650
|
+
static ticks(scale, gap = TICK_GAP) {
|
|
1651
|
+
const [low, high] = scale.domain(), kept = [];
|
|
1652
|
+
for (const tick of [...STANDARD, ...ROUND]) if (tick >= low && tick <= high && kept.every((other) => Math.abs(scale(other) - scale(tick)) >= gap)) kept.push(tick);
|
|
1653
|
+
return kept.sort((a, b) => a - b);
|
|
1654
|
+
}
|
|
1655
|
+
/** The first athlete's curves, the current period first, each with one reading per duration in rising order. */
|
|
1656
|
+
get curves() {
|
|
1657
|
+
const { x, y, period, weight, athlete, current } = this.options, rows = this.rows(), perKilo = this.#perKilo;
|
|
1658
|
+
const who = this.#who = _nullishCoalesce(rows.map((row) => this.word(row[athlete])).find(Boolean), () => ( ""));
|
|
1659
|
+
const best = /* @__PURE__ */ new Map();
|
|
1660
|
+
for (const row of rows) {
|
|
1661
|
+
const t = this.number(row[x]), watts = this.number(row[y]), mass = this.number(row[weight]);
|
|
1662
|
+
if (this.word(row[athlete], who) !== who || t === null || t <= 0 || watts === null || perKilo && !(mass !== null && mass > 0)) continue;
|
|
1663
|
+
const name = this.word(row[period], "Power"), held = _nullishCoalesce(best.get(name), () => ( best.set(name, /* @__PURE__ */ new Map()).get(name)));
|
|
1664
|
+
held.set(t, Math.max(_nullishCoalesce(held.get(t), () => ( -Infinity)), perKilo ? watts / mass : watts));
|
|
1665
|
+
}
|
|
1666
|
+
const curves = [...best].map(([name, held]) => ({ period: name, points: [...held].sort((a, b) => a[0] - b[0]).map(([t, p]) => ({ t, p })) }));
|
|
1667
|
+
const lead = curves.findIndex((curve) => curve.period === current);
|
|
1668
|
+
return lead > 0 ? [curves[lead], ...curves.filter((_, i) => i !== lead)] : curves;
|
|
1669
|
+
}
|
|
1670
|
+
scales(ctx) {
|
|
1671
|
+
const { width, height } = ctx.plot, { references, model, fitWindow } = this.options;
|
|
1672
|
+
const periods = this.#periods = references ? this.curves : this.curves.slice(0, 1);
|
|
1673
|
+
this.#fit = model && periods[0] ? _PowerDurationCurve.fit(periods[0].points, fitWindow) : null;
|
|
1674
|
+
const points = periods.flatMap((curve) => curve.points), times = points.map((point) => point.t), powers = points.map((point) => point.p);
|
|
1675
|
+
let [low, high] = points.length ? [Math.min(...times), Math.max(...times)] : [1, 3600];
|
|
1676
|
+
if (low === high) [low, high] = [low / 2, high * 2];
|
|
1677
|
+
const top = Math.max(0, ...powers), bottom = Math.min(0, ...powers);
|
|
1678
|
+
const x = _d3.scaleLog.call(void 0, [low, high], [0, width]), y = this.#powerAxis = _d3.scaleLinear.call(void 0, [bottom, top > bottom ? top * 1.04 : bottom + 1], [height, 0]).nice();
|
|
1679
|
+
this.#timeAxis = Object.assign(x, { ticks: () => _PowerDurationCurve.ticks(x) });
|
|
1680
|
+
return { x, y };
|
|
1681
|
+
}
|
|
1682
|
+
/** Time ticks name their duration, and the top power tick carries the unit. */
|
|
1683
|
+
tickFormat(scale) {
|
|
1684
|
+
if (scale === this.#timeAxis) return (value) => _PowerDurationCurve.span(+value);
|
|
1685
|
+
const plain = super.tickFormat(scale);
|
|
1686
|
+
if (scale !== this.#powerAxis || !plain) return plain;
|
|
1687
|
+
const top = Math.max(...this.#powerAxis.ticks(this.yTicks()));
|
|
1688
|
+
return (value) => +value === top ? `${plain(value)} ${this.#unit}` : plain(value);
|
|
1689
|
+
}
|
|
1690
|
+
plotMarks(ctx, { x, y }) {
|
|
1691
|
+
const { markers, fitWindow } = this.options, periods = this.#periods, fit = this.#fit, lead = periods[0], unit = this.#unit;
|
|
1692
|
+
const color = (name) => ctx.palette.color(name);
|
|
1693
|
+
for (const curve of periods) color(curve.period);
|
|
1694
|
+
const [low, high] = x.domain(), top = y.domain()[1], { width, height } = ctx.plot;
|
|
1695
|
+
const reading = (power) => `${this.#value(power)} ${unit}`;
|
|
1696
|
+
const asymptote = ctx.marks("axis-critical", "line", fit ? [fit] : []).attr("stroke", ctx.theme.axis).attr("stroke-width", 1).attr("stroke-dasharray", "2 3");
|
|
1697
|
+
ctx.set(asymptote, { x1: 0, x2: width, y1: (d) => y(d.cp), y2: (d) => y(d.cp) });
|
|
1698
|
+
const marked = markers && lead ? STANDARD.flatMap((t) => {
|
|
1699
|
+
const p = _PowerDurationCurve.at(lead.points, t);
|
|
1700
|
+
return p === null || t < low || t > high ? [] : [{ t, p }];
|
|
1701
|
+
}) : [];
|
|
1702
|
+
const drops = ctx.marks("axis-standard", "line", marked, (d) => d.t).attr("stroke", ctx.theme.axis).attr("stroke-width", 1).attr("stroke-dasharray", "1 3");
|
|
1703
|
+
ctx.set(drops, { x1: (d) => x(d.t), x2: (d) => x(d.t), y1: (d) => y(d.p), y2: height });
|
|
1704
|
+
const trace = _d3.line.call(void 0, ).curve(_chunkPY4R3IFFcjs.Scales.curve()).x((d) => x(d.t)).y((d) => y(d.p));
|
|
1705
|
+
const drawn = [...periods].reverse();
|
|
1706
|
+
const paths = ctx.marks("curves", "path", drawn.filter((curve) => curve.points.length > 1), (d) => d.period).attr("fill", "none").attr("stroke", (d) => color(d.period)).attr("stroke-width", (d) => d === lead ? 2 : 1.5).attr("stroke-opacity", (d) => d === lead ? 1 : 0.7).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
1707
|
+
ctx.set(paths, { d: (d) => _nullishCoalesce(trace(d.points), () => ( "")) });
|
|
1708
|
+
ctx.drawOn(paths);
|
|
1709
|
+
ctx.hover(paths, (d) => ({
|
|
1710
|
+
title: d.period,
|
|
1711
|
+
color: color(d.period),
|
|
1712
|
+
rows: STANDARD.flatMap((t) => {
|
|
1713
|
+
const p = _PowerDurationCurve.at(d.points, t);
|
|
1714
|
+
return p === null ? [] : [[_PowerDurationCurve.span(t), reading(p)]];
|
|
1715
|
+
})
|
|
1716
|
+
}));
|
|
1717
|
+
const lone = ctx.marks("single", "circle", drawn.filter((curve) => curve.points.length === 1), (d) => d.period).attr("fill", (d) => color(d.period)).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
|
|
1718
|
+
ctx.set(lone, { cx: (d) => x(d.points[0].t), cy: (d) => y(d.points[0].p), r: DOT2 }, { r: 0 });
|
|
1719
|
+
ctx.hover(lone, (d) => ({ title: d.period, color: color(d.period), rows: [[_PowerDurationCurve.span(d.points[0].t), reading(d.points[0].p)]] }));
|
|
1720
|
+
const start = fit ? Math.max(low, fit.wPrime / Math.max(1e-9, top - fit.cp)) : high;
|
|
1721
|
+
const steps = start < high ? Array.from({ length: 64 }, (_, i) => start * (high / start) ** (i / 63)) : [];
|
|
1722
|
+
const fitted = ctx.marks("model", "path", fit && steps.length ? [fit] : []).attr("fill", "none").attr("stroke", ctx.theme.ink).attr("stroke-width", 1.5).attr("stroke-dasharray", "5 4");
|
|
1723
|
+
ctx.set(fitted, { d: (d) => _nullishCoalesce(_d3.line.call(void 0, ).x((t) => x(t)).y((t) => y(d.cp + d.wPrime / t))(steps), () => ( "")) });
|
|
1724
|
+
ctx.hover(fitted, (d) => ({
|
|
1725
|
+
title: "Critical power model",
|
|
1726
|
+
rows: [["Critical power", reading(d.cp)], ["W'", this.#work(d.wPrime)], ["Fitted over", `${_PowerDurationCurve.span(fitWindow[0])} to ${_PowerDurationCurve.span(fitWindow[1])}`]]
|
|
1727
|
+
}));
|
|
1728
|
+
const dots = ctx.marks("standard", "circle", marked, (d) => d.t).attr("fill", lead ? color(lead.period) : null).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
|
|
1729
|
+
ctx.set(dots, { cx: (d) => x(d.t), cy: (d) => y(d.p), r: DOT2 }, { r: 0 }, 30);
|
|
1730
|
+
ctx.hover(dots, (d) => ({
|
|
1731
|
+
title: `Best ${_PowerDurationCurve.span(d.t)}`,
|
|
1732
|
+
color: lead ? color(lead.period) : void 0,
|
|
1733
|
+
rows: [[_nullishCoalesce(_optionalChain([lead, 'optionalAccess', _14 => _14.period]), () => ( "")), reading(d.p)], ...fit ? [["Model", reading(fit.cp + fit.wPrime / d.t)]] : []]
|
|
1734
|
+
}));
|
|
1735
|
+
let edge = -Infinity;
|
|
1736
|
+
const values = marked.flatMap((d) => {
|
|
1737
|
+
const text = this.#value(d.p), wide = text.length * CHAR4, flip = x(d.t) + 7 + wide > width, left = flip ? x(d.t) - 7 - wide : x(d.t) + 7;
|
|
1738
|
+
if (left < edge + 4 || y(d.p) < 18) return [];
|
|
1739
|
+
edge = left + wide;
|
|
1740
|
+
return [{ key: `value-${d.t}`, text, x: flip ? x(d.t) - 7 : x(d.t) + 7, y: y(d.p) - 7, anchor: flip ? "end" : "start", tone: "ink" }];
|
|
1741
|
+
});
|
|
1742
|
+
const summary = !lead ? [{ key: "empty", text: this.#perKilo && this.rows().length ? "No body weight to divide by" : "No power readings", x: 4, y: 12, tone: "muted" }] : [
|
|
1743
|
+
...this.#who ? [{ key: "who", text: this.#who, x: width - 4, y: 12, anchor: "end", tone: "ink" }] : [],
|
|
1744
|
+
...fit ? [
|
|
1745
|
+
{ key: "fit", text: `CP ${reading(fit.cp)}, W' ${this.#work(fit.wPrime)}`, x: width - 4, y: this.#who ? 26 : 12, anchor: "end" },
|
|
1746
|
+
{ key: "critical", text: "CP", x: 4, y: y(fit.cp) - 5, tone: "muted", size: 10 }
|
|
1747
|
+
] : []
|
|
1748
|
+
];
|
|
1749
|
+
this.notes(ctx, "notes", [...values, ...summary]);
|
|
1750
|
+
}
|
|
1751
|
+
/** W' in kilojoules, or in joules per kilogram when power is per kilogram. */
|
|
1752
|
+
#work(wPrime) {
|
|
1753
|
+
return this.#perKilo ? `${Math.round(wPrime)} J/kg` : `${(wPrime / 1e3).toFixed(1)} kJ`;
|
|
1754
|
+
}
|
|
1755
|
+
}, _class10.__initStatic31(), _class10);
|
|
1756
|
+
|
|
1525
1757
|
// src/charts/sportscharts/RaceLapChart.ts
|
|
1758
|
+
|
|
1526
1759
|
var PIT = /pit|stop|box/i;
|
|
1527
1760
|
var OUT2 = /ret|dnf|out|crash|accident/i;
|
|
1528
|
-
var
|
|
1761
|
+
var CHAR5 = 6.2;
|
|
1529
1762
|
var NAME_MAX = 78;
|
|
1530
1763
|
var cross = _nullishCoalesce(_d3.symbol.call(void 0, _d3.symbolCross, 64)(), () => ( ""));
|
|
1531
|
-
var RaceLapChart = (
|
|
1532
|
-
static
|
|
1764
|
+
var RaceLapChart = (_class11 = class extends SportsTimelineChart {
|
|
1765
|
+
static __initStatic32() {this.meta = {
|
|
1533
1766
|
id: "race-lap-chart",
|
|
1534
1767
|
name: "Lap chart",
|
|
1535
1768
|
family: "trend" /* Trend */,
|
|
@@ -1584,7 +1817,7 @@ var RaceLapChart = (_class10 = class extends SportsTimelineChart {
|
|
|
1584
1817
|
}
|
|
1585
1818
|
/** Px kept right of the last lap for the finishers' names. */
|
|
1586
1819
|
#nameRoom(width, cars) {
|
|
1587
|
-
const longest = Math.max(0, ...cars.map((car) => _chunkEEF5WRRZcjs.TextFit.width(car.driver,
|
|
1820
|
+
const longest = Math.max(0, ...cars.map((car) => _chunkEEF5WRRZcjs.TextFit.width(car.driver, CHAR5)));
|
|
1588
1821
|
return width < 220 || !cars.length ? 0 : Math.min(NAME_MAX, width * 0.26, longest + 12);
|
|
1589
1822
|
}
|
|
1590
1823
|
tickFormat(scale) {
|
|
@@ -1615,7 +1848,7 @@ var RaceLapChart = (_class10 = class extends SportsTimelineChart {
|
|
|
1615
1848
|
ctx.set(crosses, { transform: (car) => `translate(${x(end(car).lap).toFixed(2)},${y(end(car).position).toFixed(2)}) rotate(45)` }, { "fill-opacity": 0 });
|
|
1616
1849
|
ctx.hover(crosses, (car) => ({ title: `${car.driver} retired`, color: color(car), rows: [["Lap", end(car).lap], ["Position", end(car).position]] }));
|
|
1617
1850
|
const room = this.#nameRoom(ctx.plot.width, cars), edge = x.range()[1];
|
|
1618
|
-
const finishers = room ? cars.filter((car) => !car.retired && car.points.length).map((car) => ({ key: car.driver, text: _chunkEEF5WRRZcjs.TextFit.fit(car.driver, room - 8,
|
|
1851
|
+
const finishers = room ? cars.filter((car) => !car.retired && car.points.length).map((car) => ({ key: car.driver, text: _chunkEEF5WRRZcjs.TextFit.fit(car.driver, room - 8, CHAR5), x: edge + 8, y: y(end(car).position) + 4 })) : [];
|
|
1619
1852
|
const taken = /* @__PURE__ */ new Set();
|
|
1620
1853
|
const named = finishers.filter((label) => {
|
|
1621
1854
|
const slot = Math.round(label.y / 11);
|
|
@@ -1624,7 +1857,7 @@ var RaceLapChart = (_class10 = class extends SportsTimelineChart {
|
|
|
1624
1857
|
const quit = gone.map((car) => ({ key: `out-${car.driver}`, text: car.driver, x: x(end(car).lap) + 8, y: y(end(car).position) + 4, size: 10, tone: "ink" })).filter((label) => label.x + _chunkEEF5WRRZcjs.TextFit.width(label.text, 5.6) < edge);
|
|
1625
1858
|
this.notes(ctx, "names", [...named, ...quit, ...cars.length ? [] : [{ key: "empty", text: "No laps", x: 4, y: 12, tone: "muted" }]]);
|
|
1626
1859
|
}
|
|
1627
|
-
},
|
|
1860
|
+
}, _class11.__initStatic32(), _class11);
|
|
1628
1861
|
|
|
1629
1862
|
// src/charts/sportscharts/ScoreWormChart.ts
|
|
1630
1863
|
|
|
@@ -1634,8 +1867,8 @@ var WormMeasure = /* @__PURE__ */ ((WormMeasure2) => {
|
|
|
1634
1867
|
return WormMeasure2;
|
|
1635
1868
|
})(WormMeasure || {});
|
|
1636
1869
|
var END_ROOM = 34;
|
|
1637
|
-
var ScoreWormChart = (
|
|
1638
|
-
static
|
|
1870
|
+
var ScoreWormChart = (_class12 = class _ScoreWormChart extends SportsTimelineChart {
|
|
1871
|
+
static __initStatic33() {this.meta = {
|
|
1639
1872
|
id: "score-worm",
|
|
1640
1873
|
name: "Worm chart",
|
|
1641
1874
|
family: "trend" /* Trend */,
|
|
@@ -1676,8 +1909,8 @@ var ScoreWormChart = (_class11 = class _ScoreWormChart extends SportsTimelineCha
|
|
|
1676
1909
|
}
|
|
1677
1910
|
/** The first side's lead over `other` at every period either side has, up to where the shorter of the two ends. */
|
|
1678
1911
|
static margin(first, other) {
|
|
1679
|
-
const end = Math.min(_nullishCoalesce(_optionalChain([first, 'access',
|
|
1680
|
-
const at = (side, x) => _nullishCoalesce(_optionalChain([side, 'access',
|
|
1912
|
+
const end = Math.min(_nullishCoalesce(_optionalChain([first, 'access', _15 => _15.points, 'access', _16 => _16.at, 'call', _17 => _17(-1), 'optionalAccess', _18 => _18.x]), () => ( 0)), _nullishCoalesce(_optionalChain([other, 'access', _19 => _19.points, 'access', _20 => _20.at, 'call', _21 => _21(-1), 'optionalAccess', _22 => _22.x]), () => ( 0)));
|
|
1913
|
+
const at = (side, x) => _nullishCoalesce(_optionalChain([side, 'access', _23 => _23.points, 'access', _24 => _24.findLast, 'call', _25 => _25((point) => point.x <= x), 'optionalAccess', _26 => _26.value]), () => ( 0));
|
|
1681
1914
|
const periods = [...new Set([...first.points, ...other.points].map((point) => point.x))].filter((x) => x <= end).sort((a, b) => a - b);
|
|
1682
1915
|
return periods.map((x) => ({ x, value: at(first, x) - at(other, x), added: 0, events: 0 }));
|
|
1683
1916
|
}
|
|
@@ -1707,7 +1940,7 @@ var ScoreWormChart = (_class11 = class _ScoreWormChart extends SportsTimelineCha
|
|
|
1707
1940
|
const { curve, markers } = this.options, lines = this.#lines, sides = this.#sides, margin = this.#margin;
|
|
1708
1941
|
const color = (team) => ctx.palette.color(team);
|
|
1709
1942
|
for (const side of sides) color(side.team);
|
|
1710
|
-
const first = _nullishCoalesce(_optionalChain([sides, 'access',
|
|
1943
|
+
const first = _nullishCoalesce(_optionalChain([sides, 'access', _27 => _27[0], 'optionalAccess', _28 => _28.team]), () => ( "")), duel = margin && lines.length === 1;
|
|
1711
1944
|
const zero = ctx.marks("axis-zero", "line", margin && lines.length ? [0] : []).attr("stroke", ctx.theme.axis).attr("stroke-width", 1);
|
|
1712
1945
|
ctx.set(zero, { x1: 0, x2: ctx.plot.width, y1: y(0), y2: y(0) });
|
|
1713
1946
|
const outline = duel ? curve === "linear" /* Linear */ ? _ScoreWormChart.zeroCrossings(lines[0].points) : lines[0].points : [];
|
|
@@ -1719,14 +1952,14 @@ var ScoreWormChart = (_class11 = class _ScoreWormChart extends SportsTimelineCha
|
|
|
1719
1952
|
const worms = ctx.marks("worms", "path", duel ? [] : lines.filter((entry) => entry.points.length > 1), (d) => d.key).attr("fill", "none").attr("stroke", (d) => color(d.team)).attr("stroke-width", 2).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
1720
1953
|
ctx.set(worms, { d: (d) => _nullishCoalesce(trace(d.points), () => ( "")) });
|
|
1721
1954
|
ctx.drawOn(worms);
|
|
1722
|
-
ctx.hover(worms, (d) => ({ title: margin ? `${first} against ${d.team}` : d.team, color: color(d.team), rows: [[margin ? "Final lead" : "Total", _nullishCoalesce(_optionalChain([d, 'access',
|
|
1955
|
+
ctx.hover(worms, (d) => ({ title: margin ? `${first} against ${d.team}` : d.team, color: color(d.team), rows: [[margin ? "Final lead" : "Total", _nullishCoalesce(_optionalChain([d, 'access', _29 => _29.points, 'access', _30 => _30.at, 'call', _31 => _31(-1), 'optionalAccess', _32 => _32.value]), () => ( 0))]] }));
|
|
1723
1956
|
const height = (team, at) => {
|
|
1724
1957
|
const track = margin ? _nullishCoalesce(lines.find((entry) => entry.team === team), () => ( lines[0])) : lines.find((entry) => entry.team === team);
|
|
1725
|
-
return _nullishCoalesce(_optionalChain([track, 'optionalAccess',
|
|
1958
|
+
return _nullishCoalesce(_optionalChain([track, 'optionalAccess', _33 => _33.points, 'access', _34 => _34.findLast, 'call', _35 => _35((point) => point.x <= at), 'optionalAccess', _36 => _36.value]), () => ( null));
|
|
1726
1959
|
};
|
|
1727
1960
|
const marks = (markers ? sides : []).flatMap((side) => side.points.flatMap((point) => {
|
|
1728
1961
|
const value = point.events > 0 ? height(side.team, point.x) : null;
|
|
1729
|
-
const reach = margin ? _nullishCoalesce(_optionalChain([(_nullishCoalesce(lines.find((entry) => entry.team === side.team), () => ( lines[0]))), 'optionalAccess',
|
|
1962
|
+
const reach = margin ? _nullishCoalesce(_optionalChain([(_nullishCoalesce(lines.find((entry) => entry.team === side.team), () => ( lines[0]))), 'optionalAccess', _37 => _37.points, 'access', _38 => _38.at, 'call', _39 => _39(-1), 'optionalAccess', _40 => _40.x]), () => ( -Infinity)) : Infinity;
|
|
1730
1963
|
return value === null || point.x > reach ? [] : [{ key: `${side.team}/${point.x}`, team: side.team, x: point.x, value, events: point.events, total: point.value }];
|
|
1731
1964
|
}));
|
|
1732
1965
|
const dots = ctx.marks("events", "circle", marks, (d) => d.key).attr("fill", (d) => color(d.team)).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
|
|
@@ -1745,7 +1978,7 @@ var ScoreWormChart = (_class11 = class _ScoreWormChart extends SportsTimelineCha
|
|
|
1745
1978
|
] : margin ? [{ key: "first", text: `Lead of ${first}`, x: 4, y: 12, tone: "muted" }] : [];
|
|
1746
1979
|
this.notes(ctx, "notes", [...ends, ...corners]);
|
|
1747
1980
|
}
|
|
1748
|
-
},
|
|
1981
|
+
}, _class12.__initStatic33(), _class12);
|
|
1749
1982
|
|
|
1750
1983
|
// src/charts/sportscharts/StrikeZonePlot.ts
|
|
1751
1984
|
|
|
@@ -1770,8 +2003,8 @@ var FOOT8 = 18;
|
|
|
1770
2003
|
var NAMES = ["Low", "Middle", "High"];
|
|
1771
2004
|
var SIDES = ["left", "middle", "right"];
|
|
1772
2005
|
var clips2 = 0;
|
|
1773
|
-
var StrikeZonePlot = (
|
|
1774
|
-
static
|
|
2006
|
+
var StrikeZonePlot = (_class13 = class extends SportsFieldChart {
|
|
2007
|
+
static __initStatic34() {this.meta = {
|
|
1775
2008
|
id: "strike-zone-plot",
|
|
1776
2009
|
name: "Strike zone plot",
|
|
1777
2010
|
family: "pictorial" /* Pictorial */,
|
|
@@ -1812,13 +2045,13 @@ var StrikeZonePlot = (_class12 = class extends SportsFieldChart {
|
|
|
1812
2045
|
}));
|
|
1813
2046
|
const far = HALF_PLATE + CHASE, floor = low - CHASE, roof = high + CHASE;
|
|
1814
2047
|
const outer = this.options.zones === 13 ? [[-1, -1, "Below left"], [1, -1, "Below right"], [-1, 1, "Above left"], [1, 1, "Above right"]].map(([sx, sz, name]) => {
|
|
1815
|
-
const side = sx, up = sz, edge = up > 0 ? roof : floor,
|
|
2048
|
+
const side = sx, up = sz, edge = up > 0 ? roof : floor, line6 = up > 0 ? high : low;
|
|
1816
2049
|
return {
|
|
1817
2050
|
key: `out-${side}-${up}`,
|
|
1818
2051
|
name,
|
|
1819
2052
|
count: 0,
|
|
1820
2053
|
at: [side * (HALF_PLATE + CHASE / 2), edge - up * CHASE / 2],
|
|
1821
|
-
corners: [[0, edge], [side * far, edge], [side * far, mid], [side * HALF_PLATE, mid], [side * HALF_PLATE,
|
|
2054
|
+
corners: [[0, edge], [side * far, edge], [side * far, mid], [side * HALF_PLATE, mid], [side * HALF_PLATE, line6], [0, line6]]
|
|
1822
2055
|
};
|
|
1823
2056
|
}) : [];
|
|
1824
2057
|
for (const pitch of pitches) {
|
|
@@ -1884,14 +2117,14 @@ var StrikeZonePlot = (_class12 = class extends SportsFieldChart {
|
|
|
1884
2117
|
const lines = this.#frameLines();
|
|
1885
2118
|
this.#drawZones(ctx, marks === "zone-grid" /* Grid */ ? this.zonesOf(pitches) : [], frame, Math.max(1, pitches.length));
|
|
1886
2119
|
this.#drawContours(ctx, marks === "contour" /* Contour */ ? pitches : [], frame);
|
|
1887
|
-
this.fieldLines(ctx, "zone", marks === "zone-grid" /* Grid */ ? lines.filter((
|
|
2120
|
+
this.fieldLines(ctx, "zone", marks === "zone-grid" /* Grid */ ? lines.filter((line6) => !line6.dashed) : lines, frame);
|
|
1888
2121
|
this.#drawPitches(ctx, marks === "pitches" /* Pitches */ ? pitches : [], frame);
|
|
1889
2122
|
const inside = pitches.filter((pitch) => Math.abs(pitch.x) <= HALF_PLATE + BALL && pitch.z >= low - BALL && pitch.z <= high + BALL).length;
|
|
1890
2123
|
const seat = view === "pitcher" /* Pitcher */ ? "pitcher's view" : "catcher's view";
|
|
1891
2124
|
const note = pitches.length ? `${pitches.length} pitches, ${Math.round(inside / pitches.length * 100)}% in the zone, ${seat}` : "No pitches";
|
|
1892
2125
|
this.captions(ctx, "note", [{ key: "note", text: note, x: 0, y: ctx.plot.height - 3, tone: "muted" }]);
|
|
1893
2126
|
}
|
|
1894
|
-
},
|
|
2127
|
+
}, _class13.__initStatic34(), _class13);
|
|
1895
2128
|
|
|
1896
2129
|
// src/charts/sportscharts/TennisServePlacement.ts
|
|
1897
2130
|
var ServeMarks = /* @__PURE__ */ ((ServeMarks2) => {
|
|
@@ -1930,8 +2163,8 @@ var BANDS = [
|
|
|
1930
2163
|
{ label: "5-8", low: 5, high: 8, tone: 0.7 },
|
|
1931
2164
|
{ label: "9+", low: 9, high: Infinity, tone: 1 }
|
|
1932
2165
|
];
|
|
1933
|
-
var TennisServePlacement = (
|
|
1934
|
-
static
|
|
2166
|
+
var TennisServePlacement = (_class14 = class extends SportsFieldChart {
|
|
2167
|
+
static __initStatic35() {this.meta = {
|
|
1935
2168
|
id: "tennis-serve-placement",
|
|
1936
2169
|
name: "Serve placement",
|
|
1937
2170
|
family: "pictorial" /* Pictorial */,
|
|
@@ -2080,9 +2313,9 @@ var TennisServePlacement = (_class13 = class extends SportsFieldChart {
|
|
|
2080
2313
|
const room = { x: 0, y: 0, width: ctx.plot.width - panel, height: ctx.plot.height - FOOT9 - BOX_LABEL };
|
|
2081
2314
|
const frame = this.frame(room, [-DOUBLES - MARGIN, DOUBLES + MARGIN], [0, top + (view === "half-court" /* HalfCourt */ ? MARGIN : 2)]);
|
|
2082
2315
|
const court = this.#court(view);
|
|
2083
|
-
this.fieldLines(ctx, "floor", court.filter((
|
|
2316
|
+
this.fieldLines(ctx, "floor", court.filter((line6) => line6.key === "floor" && !zoned), frame);
|
|
2084
2317
|
this.#drawZones(ctx, zoned ? this.zonesOf(bounces) : [], frame);
|
|
2085
|
-
this.fieldLines(ctx, "court", court.filter((
|
|
2318
|
+
this.fieldLines(ctx, "court", court.filter((line6) => line6.key !== "floor"), frame);
|
|
2086
2319
|
this.captions(ctx, "boxes", [
|
|
2087
2320
|
{ key: "deuce", text: "Deuce", x: frame.x(-SINGLES / 2), y: frame.y(0) + 14, anchor: "middle", tone: "muted" },
|
|
2088
2321
|
{ key: "ad", text: "Ad", x: frame.x(SINGLES / 2), y: frame.y(0) + 14, anchor: "middle", tone: "muted" }
|
|
@@ -2092,7 +2325,171 @@ var TennisServePlacement = (_class13 = class extends SportsFieldChart {
|
|
|
2092
2325
|
const note = !bounces.length ? "No serves" : zoned ? `${bounces.length} serves. Tone: share of serves` : `${bounces.length} serves. Filled: point won`;
|
|
2093
2326
|
this.captions(ctx, "note", [{ key: "note", text: note, x: 0, y: ctx.plot.height - 3, tone: "muted" }]);
|
|
2094
2327
|
}
|
|
2095
|
-
},
|
|
2328
|
+
}, _class14.__initStatic35(), _class14);
|
|
2329
|
+
|
|
2330
|
+
// src/charts/sportscharts/TrainingLoadChart.ts
|
|
2331
|
+
|
|
2332
|
+
var TrainingLoadForm = /* @__PURE__ */ ((TrainingLoadForm2) => {
|
|
2333
|
+
TrainingLoadForm2["Band"] = "band";
|
|
2334
|
+
TrainingLoadForm2["Line"] = "line";
|
|
2335
|
+
return TrainingLoadForm2;
|
|
2336
|
+
})(TrainingLoadForm || {});
|
|
2337
|
+
var TrainingLoadLayout = /* @__PURE__ */ ((TrainingLoadLayout2) => {
|
|
2338
|
+
TrainingLoadLayout2["Split"] = "split";
|
|
2339
|
+
TrainingLoadLayout2["Overlay"] = "overlay";
|
|
2340
|
+
return TrainingLoadLayout2;
|
|
2341
|
+
})(TrainingLoadLayout || {});
|
|
2342
|
+
var DAY = 864e5;
|
|
2343
|
+
var MOST_DAYS = 3660;
|
|
2344
|
+
var END_ROOM2 = 34;
|
|
2345
|
+
var PANEL_GAP = 12;
|
|
2346
|
+
var ZONES2 = [
|
|
2347
|
+
{ name: "Transition", from: 25, to: Infinity, token: "warning" },
|
|
2348
|
+
{ name: "Fresh", from: 5, to: 25, token: "grid" },
|
|
2349
|
+
{ name: "Neutral", from: -10, to: 5, token: null },
|
|
2350
|
+
{ name: "Productive", from: -30, to: -10, token: "good" },
|
|
2351
|
+
{ name: "Overreaching", from: -Infinity, to: -30, token: "critical" }
|
|
2352
|
+
];
|
|
2353
|
+
var TrainingLoadChart = (_class15 = class _TrainingLoadChart extends SportsTimelineChart {
|
|
2354
|
+
static __initStatic36() {this.meta = {
|
|
2355
|
+
id: "training-load",
|
|
2356
|
+
name: "Training load chart",
|
|
2357
|
+
family: "trend" /* Trend */,
|
|
2358
|
+
dimension: 2 /* Two */,
|
|
2359
|
+
shape: "table" /* Table */,
|
|
2360
|
+
description: "Draws daily training stress as bars with fitness (a 42 day exponentially weighted average), fatigue (7 day) and form (fitness less fatigue) as a line or a filled band over its zones. The sample athlete is invented.",
|
|
2361
|
+
tags: ["sports", "performance management", "fitness", "fatigue", "form", "training stress", "endurance"],
|
|
2362
|
+
sample: (seed) => SportsSamples.trainingLoad(seed),
|
|
2363
|
+
variants: {
|
|
2364
|
+
form: ["band" /* Band */, "line" /* Line */],
|
|
2365
|
+
layout: ["split" /* Split */, "overlay" /* Overlay */],
|
|
2366
|
+
loadBars: [true, false],
|
|
2367
|
+
zones: [true, false]
|
|
2368
|
+
}
|
|
2369
|
+
}}
|
|
2370
|
+
#days = [];
|
|
2371
|
+
#dated = false;
|
|
2372
|
+
#who = "";
|
|
2373
|
+
#formAxis = _d3.scaleLinear.call(void 0, );
|
|
2374
|
+
defaults() {
|
|
2375
|
+
return { x: "date", y: "load", athlete: "athlete", fitnessDays: 42, fatigueDays: 7, form: "band" /* Band */, layout: "split" /* Split */, loadBars: true, zones: true };
|
|
2376
|
+
}
|
|
2377
|
+
/** The form panel has an axis of its own, so only time zooms. */
|
|
2378
|
+
zoomAxes() {
|
|
2379
|
+
return "x" /* X */;
|
|
2380
|
+
}
|
|
2381
|
+
legendItems() {
|
|
2382
|
+
const items = super.legendItems();
|
|
2383
|
+
return this.options.loadBars && items.length ? [{ key: "Daily load", color: this.theme.inkMuted }, ...items] : items;
|
|
2384
|
+
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Fitness, fatigue and form for a run of daily loads. Each average moves toward the day's load by 1 - exp(-1 / days) of the gap,
|
|
2387
|
+
* and form is the day's fitness less its fatigue. Both averages start at `baseline`, or at the mean of the first `fitnessDays` loads.
|
|
2388
|
+
*/
|
|
2389
|
+
static model(loads, fitnessDays, fatigueDays, baseline) {
|
|
2390
|
+
const gain = (days) => days > 0 ? 1 - Math.exp(-1 / days) : 1, slow = gain(fitnessDays), fast = gain(fatigueDays);
|
|
2391
|
+
const early = loads.slice(0, Math.max(1, Math.ceil(fitnessDays) || 1));
|
|
2392
|
+
let fitness = _nullishCoalesce(baseline, () => ( (early.length ? early.reduce((sum, load) => sum + load, 0) / early.length : 0))), fatigue = fitness;
|
|
2393
|
+
return loads.map((load) => {
|
|
2394
|
+
fitness += (load - fitness) * slow;
|
|
2395
|
+
fatigue += (load - fatigue) * fast;
|
|
2396
|
+
return { load, fitness, fatigue, form: fitness - fatigue };
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
/** Every day from the first athlete's first session to the last, with the sessions of a day added up and rest days at zero. */
|
|
2400
|
+
get days() {
|
|
2401
|
+
const { x, y, athlete, fitnessDays, fatigueDays, baseline } = this.options, rows = this.rows();
|
|
2402
|
+
const who = this.#who = _nullishCoalesce(rows.map((row) => this.word(row[athlete])).find(Boolean), () => ( ""));
|
|
2403
|
+
const totals = /* @__PURE__ */ new Map();
|
|
2404
|
+
let dated = false;
|
|
2405
|
+
for (const row of rows) {
|
|
2406
|
+
const cell = row[x], load = this.number(row[y]), numbered = this.number(cell);
|
|
2407
|
+
const stamp = numbered !== null ? NaN : cell instanceof Date ? cell.getTime() : typeof cell === "string" ? Date.parse(cell) : NaN;
|
|
2408
|
+
const day = numbered !== null ? Math.floor(numbered) : Number.isFinite(stamp) ? Math.floor(stamp / DAY) : null;
|
|
2409
|
+
if (this.word(row[athlete], who) !== who || day === null || load === null) continue;
|
|
2410
|
+
dated ||= numbered === null;
|
|
2411
|
+
totals.set(day, (_nullishCoalesce(totals.get(day), () => ( 0))) + Math.max(0, load));
|
|
2412
|
+
}
|
|
2413
|
+
this.#dated = dated;
|
|
2414
|
+
if (!totals.size) return [];
|
|
2415
|
+
const last = Math.max(...totals.keys()), first = Math.max(Math.min(...totals.keys()), last - MOST_DAYS + 1);
|
|
2416
|
+
const loads = Array.from({ length: last - first + 1 }, (_, i) => _nullishCoalesce(totals.get(first + i), () => ( 0)));
|
|
2417
|
+
return _TrainingLoadChart.model(loads, fitnessDays, fatigueDays, baseline).map((entry, i) => ({ day: first + i, ...entry }));
|
|
2418
|
+
}
|
|
2419
|
+
get #split() {
|
|
2420
|
+
return this.options.layout === "split" /* Split */;
|
|
2421
|
+
}
|
|
2422
|
+
/** The range of form the zones are drawn over: wide enough to show the three middle zones whole. */
|
|
2423
|
+
#reach(days) {
|
|
2424
|
+
const forms = days.map((entry) => entry.form);
|
|
2425
|
+
return [Math.min(-30, ...forms) - 6, Math.max(25, ...forms) + 6];
|
|
2426
|
+
}
|
|
2427
|
+
scales(ctx) {
|
|
2428
|
+
const { width, height } = ctx.plot, { loadBars } = this.options, days = this.#days = this.days, split = this.#split;
|
|
2429
|
+
const first = _nullishCoalesce(_optionalChain([days, 'access', _41 => _41[0], 'optionalAccess', _42 => _42.day]), () => ( 0)), last = _nullishCoalesce(_optionalChain([days, 'access', _43 => _43.at, 'call', _44 => _44(-1), 'optionalAccess', _45 => _45.day]), () => ( first)), range = [0, Math.max(10, width - END_ROOM2)];
|
|
2430
|
+
const x = this.#dated ? _d3.scaleUtc.call(void 0, [new Date((first - 0.5) * DAY), new Date((last + 0.5) * DAY)], range) : _d3.scaleLinear.call(void 0, [first - 0.5, last + 0.5], range);
|
|
2431
|
+
const panel = split ? Math.max(36, Math.min(110, height * 0.3)) : 0, main = Math.max(10, height - (split ? panel + PANEL_GAP : 0));
|
|
2432
|
+
const top = Math.max(1, ...days.flatMap((entry) => [loadBars ? entry.load : 0, entry.fitness, entry.fatigue]));
|
|
2433
|
+
const y = _d3.scaleLinear.call(void 0, [0, top], [main, 0]).nice(), deepest = split ? 0 : Math.min(0, ...days.map((entry) => entry.form));
|
|
2434
|
+
if (deepest < 0) y.domain([deepest * 1.1, y.domain()[1]]);
|
|
2435
|
+
this.#formAxis = split ? _d3.scaleLinear.call(void 0, this.#reach(days), [height, height - panel]) : y;
|
|
2436
|
+
return { x, y };
|
|
2437
|
+
}
|
|
2438
|
+
plotMarks(ctx, { x, y }) {
|
|
2439
|
+
const { form, loadBars, zones, fitnessDays, fatigueDays } = this.options, days = this.#days, split = this.#split, formY = this.#formAxis, { theme } = ctx;
|
|
2440
|
+
const at = (day) => x(this.#dated ? new Date(day * DAY) : day);
|
|
2441
|
+
const named = (day) => this.#dated ? new Date(day * DAY).toISOString().slice(0, 10) : `Day ${day}`;
|
|
2442
|
+
const whole = (value) => `${Math.round(value)}`;
|
|
2443
|
+
const series = [
|
|
2444
|
+
{ key: "Fitness", value: (entry) => entry.fitness, scale: y, days: fitnessDays },
|
|
2445
|
+
{ key: "Fatigue", value: (entry) => entry.fatigue, scale: y, days: fatigueDays }
|
|
2446
|
+
];
|
|
2447
|
+
const color = (key) => ctx.palette.color(key);
|
|
2448
|
+
if (days.length) for (const key of ["Fitness", "Fatigue", "Form"]) color(key);
|
|
2449
|
+
const right = at((_nullishCoalesce(_optionalChain([days, 'access', _46 => _46.at, 'call', _47 => _47(-1), 'optionalAccess', _48 => _48.day]), () => ( 0))) + 0.5), [low, high] = this.#reach(days);
|
|
2450
|
+
const shaded = zones && days.length ? ZONES2.flatMap((zone) => {
|
|
2451
|
+
const y0 = formY(Math.min(high, zone.to)), y1 = formY(Math.max(low, zone.from));
|
|
2452
|
+
return y1 - y0 > 0.5 ? [{ ...zone, y0, y1 }] : [];
|
|
2453
|
+
}) : [];
|
|
2454
|
+
const strips = ctx.marks("axis-zones", "rect", shaded.filter((zone) => zone.token), (d) => d.name).attr("fill", (d) => theme[d.token]).attr("fill-opacity", (d) => d.token === "grid" ? 0.6 : 0.14);
|
|
2455
|
+
ctx.set(strips, { x: 0, width: Math.max(0, right), y: (d) => d.y0, height: (d) => d.y1 - d.y0 });
|
|
2456
|
+
const step = Math.abs(at(1) - at(0)), wide = Math.max(1, step - (step > 4 ? 2 : step > 2.5 ? 1 : 0));
|
|
2457
|
+
const bars = ctx.marks("loads", "rect", loadBars ? days.filter((entry) => entry.load > 0) : [], (d) => d.day).attr("fill", theme.inkMuted).attr("fill-opacity", 0.45);
|
|
2458
|
+
ctx.set(bars, { x: (d) => at(d.day) - wide / 2, width: wide, y: (d) => y(d.load), height: (d) => Math.max(0, y(0) - y(d.load)) }, { y: y(0), height: 0 });
|
|
2459
|
+
ctx.hover(bars, (d) => ({ title: named(d.day), rows: [["Load", whole(d.load)], ["Fitness", whole(d.fitness)], ["Fatigue", whole(d.fatigue)], ["Form", whole(d.form)]] }));
|
|
2460
|
+
const zero = ctx.marks("axis-form-zero", "line", days.length && (split || y.domain()[0] < 0) ? [0] : []).attr("stroke", theme.axis).attr("stroke-width", 1);
|
|
2461
|
+
ctx.set(zero, { x1: 0, x2: ctx.plot.width, y1: formY(0), y2: formY(0) });
|
|
2462
|
+
if (split) {
|
|
2463
|
+
const axis = ctx.group("axis-form").call(_d3.axisLeft.call(void 0, formY).ticks(3).tickSize(0).tickFormat((value) => whole(+value)));
|
|
2464
|
+
axis.select(".domain").attr("stroke", "none");
|
|
2465
|
+
axis.selectAll("text").attr("fill", theme.inkSecondary).attr("font-size", 11).attr("font-family", theme.fontFamily);
|
|
2466
|
+
} else ctx.group("axis-form").selectAll("*").remove();
|
|
2467
|
+
const joined = days.length > 1 ? days : [];
|
|
2468
|
+
const latest = days.at(-1);
|
|
2469
|
+
const tell = (key, value, span) => ({ title: key, color: color(key), rows: [["Latest", whole(value)], ...span ? [["Time constant", `${span} days`]] : []] });
|
|
2470
|
+
const fill = _d3.area.call(void 0, ).curve(_chunkPY4R3IFFcjs.Scales.curve()).x((d) => at(d.day)).y0(formY(0));
|
|
2471
|
+
const bands = ctx.marks("form-band", "path", form === "band" /* Band */ && joined.length ? [joined] : []).attr("fill", color("Form")).attr("fill-opacity", 0.7);
|
|
2472
|
+
ctx.set(bands, { d: (d) => _nullishCoalesce(fill.y1((entry) => formY(entry.form))(d), () => ( "")) }, { d: (d) => _nullishCoalesce(fill.y1(formY(0))(d), () => ( "")) });
|
|
2473
|
+
ctx.hover(bands, () => tell("Form", _nullishCoalesce(_optionalChain([latest, 'optionalAccess', _49 => _49.form]), () => ( 0))));
|
|
2474
|
+
const trace = (value, scale) => _d3.line.call(void 0, ).curve(_chunkPY4R3IFFcjs.Scales.curve()).x((d) => at(d.day)).y((d) => scale(value(d)));
|
|
2475
|
+
const traced = [...series, ...form === "line" /* Line */ ? [{ key: "Form", value: (entry) => entry.form, scale: formY, days: 0 }] : []];
|
|
2476
|
+
const lines = ctx.marks("lines", "path", joined.length ? traced : [], (d) => d.key).attr("fill", "none").attr("stroke", (d) => color(d.key)).attr("stroke-width", 2).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
|
|
2477
|
+
ctx.set(lines, { d: (d) => _nullishCoalesce(trace(d.value, d.scale)(joined), () => ( "")) });
|
|
2478
|
+
ctx.drawOn(lines);
|
|
2479
|
+
ctx.hover(lines, (d) => tell(d.key, latest ? d.value(latest) : 0, d.days));
|
|
2480
|
+
const ends = !latest ? [] : [
|
|
2481
|
+
{ key: "fitness", text: whole(latest.fitness), x: right + 5, y: y(latest.fitness) + 4, tone: "ink" },
|
|
2482
|
+
{ key: "fatigue", text: whole(latest.fatigue), x: right + 5, y: y(latest.fatigue) + 4, tone: "ink" },
|
|
2483
|
+
{ key: "form", text: whole(latest.form), x: right + 5, y: formY(latest.form) + 4, tone: "ink" }
|
|
2484
|
+
].sort((a, b) => a.y - b.y);
|
|
2485
|
+
ends.forEach((label, i) => {
|
|
2486
|
+
if (i && label.y - ends[i - 1].y < 12) label.y = ends[i - 1].y + 12;
|
|
2487
|
+
});
|
|
2488
|
+
const zoneNames = shaded.filter((zone) => zone.y1 - zone.y0 >= 11).map((zone) => ({ key: `zone-${zone.name}`, text: zone.name, x: 4, y: (zone.y0 + zone.y1) / 2 + 3.5, tone: "muted", size: 10 }));
|
|
2489
|
+
const corner = !days.length ? [{ key: "empty", text: "No training load", x: 4, y: 12, tone: "muted" }] : this.#who ? [{ key: "who", text: this.#who, x: 4, y: 12, tone: "muted" }] : [];
|
|
2490
|
+
this.notes(ctx, "notes", [...zoneNames, ...ends, ...corner]);
|
|
2491
|
+
}
|
|
2492
|
+
}, _class15.__initStatic36(), _class15);
|
|
2096
2493
|
|
|
2097
2494
|
// src/charts/sportscharts/TyreStrategyChart.ts
|
|
2098
2495
|
|
|
@@ -2105,9 +2502,9 @@ var TyreStrategyOrder = /* @__PURE__ */ ((TyreStrategyOrder2) => {
|
|
|
2105
2502
|
var PIT2 = /pit|stop|box/i;
|
|
2106
2503
|
var RACING = /^(green|clear|none)?$/i;
|
|
2107
2504
|
var HEAD2 = 14;
|
|
2108
|
-
var
|
|
2109
|
-
var TyreStrategyChart = (
|
|
2110
|
-
static
|
|
2505
|
+
var CHAR6 = 5.6;
|
|
2506
|
+
var TyreStrategyChart = (_class16 = class extends SportsTimelineChart {
|
|
2507
|
+
static __initStatic37() {this.meta = {
|
|
2111
2508
|
id: "tyre-strategy",
|
|
2112
2509
|
name: "Tyre strategy chart",
|
|
2113
2510
|
family: "temporal" /* Temporal */,
|
|
@@ -2186,7 +2583,7 @@ var TyreStrategyChart = (_class14 = class extends SportsTimelineChart {
|
|
|
2186
2583
|
}));
|
|
2187
2584
|
const text = (stint) => {
|
|
2188
2585
|
const range = stint.from === stint.to ? `${stint.from}` : `${stint.from}-${stint.to}`, count = `${stint.to - stint.from + 1}`;
|
|
2189
|
-
return _nullishCoalesce([range, count].find((label) => _chunkEEF5WRRZcjs.TextFit.width(label,
|
|
2586
|
+
return _nullishCoalesce([range, count].find((label) => _chunkEEF5WRRZcjs.TextFit.width(label, CHAR6) + 8 <= wide(stint)), () => ( ""));
|
|
2190
2587
|
};
|
|
2191
2588
|
const named = labels && thick >= 12 ? stints.filter(text) : [];
|
|
2192
2589
|
const captions = ctx.text(ctx.marks("stint-labels", "text", named, (stint) => stint.key), 10).attr("text-anchor", "middle").attr("fill", (stint) => ctx.palette.inkOn(color(stint))).style("pointer-events", "none").text(text);
|
|
@@ -2194,13 +2591,13 @@ var TyreStrategyChart = (_class14 = class extends SportsTimelineChart {
|
|
|
2194
2591
|
const pauses = this.#shaded, start = (pause) => x(pause.from - 1), span = (pause) => Math.max(1, x(pause.to) - x(pause.from - 1));
|
|
2195
2592
|
const shades = ctx.marks("axis-neutral", "rect", pauses, (pause) => pause.key).attr("fill", ctx.theme.ink).attr("fill-opacity", 0.16).style("pointer-events", "none");
|
|
2196
2593
|
ctx.set(shades, { x: start, y: HEAD2, width: span, height: Math.max(0, ctx.plot.height - HEAD2) });
|
|
2197
|
-
const short = (name) => name.split(/\s+/).map((word) => _nullishCoalesce(_optionalChain([word, 'access',
|
|
2594
|
+
const short = (name) => name.split(/\s+/).map((word) => _nullishCoalesce(_optionalChain([word, 'access', _50 => _50[0], 'optionalAccess', _51 => _51.toUpperCase, 'call', _52 => _52()]), () => ( ""))).join("");
|
|
2198
2595
|
this.notes(ctx, "neutral-names", [
|
|
2199
2596
|
...pauses.map((pause) => ({ key: pause.key, text: _chunkEEF5WRRZcjs.TextFit.width(pause.name, 5.6) <= span(pause) + 24 ? pause.name : short(pause.name), x: start(pause) + span(pause) / 2, y: 10, anchor: "middle", tone: "muted", size: 10 })),
|
|
2200
2597
|
...cars.length ? [] : [{ key: "empty", text: "No laps", x: 4, y: 12, tone: "muted" }]
|
|
2201
2598
|
]);
|
|
2202
2599
|
}
|
|
2203
|
-
},
|
|
2600
|
+
}, _class16.__initStatic37(), _class16);
|
|
2204
2601
|
|
|
2205
2602
|
// src/charts/sportscharts/WinProbabilityChart.ts
|
|
2206
2603
|
|
|
@@ -2210,11 +2607,11 @@ var WinProbabilityForm = /* @__PURE__ */ ((WinProbabilityForm2) => {
|
|
|
2210
2607
|
return WinProbabilityForm2;
|
|
2211
2608
|
})(WinProbabilityForm || {});
|
|
2212
2609
|
var EVEN = 0.5;
|
|
2213
|
-
var
|
|
2610
|
+
var DOT3 = 4.5;
|
|
2214
2611
|
var LABELS = 3;
|
|
2215
2612
|
var STRIP_GAP = 16;
|
|
2216
|
-
var WinProbabilityChart = (
|
|
2217
|
-
static
|
|
2613
|
+
var WinProbabilityChart = (_class17 = class _WinProbabilityChart extends SportsTimelineChart {
|
|
2614
|
+
static __initStatic38() {this.meta = {
|
|
2218
2615
|
id: "win-probability",
|
|
2219
2616
|
name: "Win probability chart",
|
|
2220
2617
|
family: "trend" /* Trend */,
|
|
@@ -2324,7 +2721,7 @@ var WinProbabilityChart = (_class15 = class _WinProbabilityChart extends SportsT
|
|
|
2324
2721
|
ctx.hover(bars, (d) => ({ title: `${d.time}`, color: tone(d), rows: [["Leverage", +d.leverage.toFixed(3)], [sideName, `${Math.round(d.p * 100)}%`]] }));
|
|
2325
2722
|
const shown = marked ? events : [];
|
|
2326
2723
|
const dots = ctx.marks("events", "circle", shown, (d) => d.key).attr("fill", (d) => color(d.team)).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
|
|
2327
|
-
ctx.set(dots, { cx: (d) => x(d.time), cy: (d) => y(d.p), r:
|
|
2724
|
+
ctx.set(dots, { cx: (d) => x(d.time), cy: (d) => y(d.p), r: DOT3 }, { r: 0 }, 20);
|
|
2328
2725
|
ctx.hover(dots, (d) => ({
|
|
2329
2726
|
title: d.text,
|
|
2330
2727
|
color: color(d.team),
|
|
@@ -2332,7 +2729,7 @@ var WinProbabilityChart = (_class15 = class _WinProbabilityChart extends SportsT
|
|
|
2332
2729
|
}));
|
|
2333
2730
|
const placed = [];
|
|
2334
2731
|
const named = [...shown].sort((a, b) => Math.abs(b.swing) - Math.abs(a.swing)).flatMap((d) => {
|
|
2335
|
-
const px = x(d.time), up = d.p >= EVEN, py = y(d.p) + (up ? -
|
|
2732
|
+
const px = x(d.time), up = d.p >= EVEN, py = y(d.p) + (up ? -DOT3 - 5 : DOT3 + 13), half = d.text.length * 3.1 + 4;
|
|
2336
2733
|
if (placed.length >= LABELS || px - half < 0 || px + half > ctx.plot.width || py < 10 || py > y(0) - 2) return [];
|
|
2337
2734
|
if (placed.some(([qx, qy, qh]) => Math.abs(qy - py) < 13 && Math.abs(qx - px) < half + qh)) return [];
|
|
2338
2735
|
placed.push([px, py, half]);
|
|
@@ -2345,7 +2742,7 @@ var WinProbabilityChart = (_class15 = class _WinProbabilityChart extends SportsT
|
|
|
2345
2742
|
const strips = leverageBars && points.length ? [{ key: "leverage", text: "Leverage", x: 4, y: ctx.plot.height - strip - 4, tone: "muted", size: 10 }] : [];
|
|
2346
2743
|
this.notes(ctx, "notes", [...corners, ...strips, ...named]);
|
|
2347
2744
|
}
|
|
2348
|
-
},
|
|
2745
|
+
}, _class17.__initStatic38(), _class17);
|
|
2349
2746
|
|
|
2350
2747
|
// src/charts/sportscharts/XgShotMap.ts
|
|
2351
2748
|
var XgMarks = /* @__PURE__ */ ((XgMarks2) => {
|
|
@@ -2363,8 +2760,8 @@ var FOOT10 = 18;
|
|
|
2363
2760
|
var KEY = [0.5, 0.2, 0.05];
|
|
2364
2761
|
var LANES = [0, 13.84, 24.84, 43.16, 54.16, 68];
|
|
2365
2762
|
var BANDS2 = [52.5, 70, 88.5, 99.5, 105];
|
|
2366
|
-
var XgShotMap = (
|
|
2367
|
-
static
|
|
2763
|
+
var XgShotMap = (_class18 = class _XgShotMap extends SportsFieldChart {
|
|
2764
|
+
static __initStatic39() {this.meta = {
|
|
2368
2765
|
id: "xg-shot-map",
|
|
2369
2766
|
name: "xG shot map",
|
|
2370
2767
|
family: "pictorial" /* Pictorial */,
|
|
@@ -2506,16 +2903,16 @@ var XgShotMap = (_class16 = class _XgShotMap extends SportsFieldChart {
|
|
|
2506
2903
|
};
|
|
2507
2904
|
const radius = (xg) => Math.max(MIN_RADIUS2, Math.sqrt(xg) * FULL_XG * frame.scale);
|
|
2508
2905
|
this.#drawZones(ctx, zoned ? this.#zones(shots) : [], seen, frame);
|
|
2509
|
-
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((
|
|
2906
|
+
this.fieldLines(ctx, "pitch", FootballPitch.markings(view).map((line6) => ({ ...line6, points: line6.points.map(seen) })), frame);
|
|
2510
2907
|
this.#drawShots(ctx, zoned ? [] : shots, (shot) => px(shot.at), radius);
|
|
2511
2908
|
if (rail) this.#drawRail(ctx, shots, frame.right + 16, rail - 16, radius, room.height);
|
|
2512
2909
|
else this.#drawRail(ctx, [], 0, 0, radius, 0);
|
|
2513
2910
|
const totals = _XgShotMap.#totals(shots).slice(0, 2).map(({ team, xg }) => `${team} ${xg.toFixed(2)} xG`).join(", ");
|
|
2514
2911
|
const key = zoned ? "Figures show xG by zone" : "Area shows xG. Filled: goal";
|
|
2515
|
-
const note = !_optionalChain([data, 'optionalAccess',
|
|
2912
|
+
const note = !_optionalChain([data, 'optionalAccess', _53 => _53.length]) || !shots.length ? "No shots" : rail ? key : `${totals}. ${key}`;
|
|
2516
2913
|
this.captions(ctx, "note", [{ key: "note", text: note, x: rail ? frame.left : 0, y: ctx.plot.height - 3, tone: "muted" }]);
|
|
2517
2914
|
}
|
|
2518
|
-
},
|
|
2915
|
+
}, _class18.__initStatic39(), _class18);
|
|
2519
2916
|
|
|
2520
2917
|
// src/charts/sportscharts/index.ts
|
|
2521
2918
|
var sportschartsCatalog = [
|
|
@@ -2532,7 +2929,9 @@ var sportschartsCatalog = [
|
|
|
2532
2929
|
TyreStrategyChart,
|
|
2533
2930
|
PitchHeatmap,
|
|
2534
2931
|
HockeyRinkShotMap,
|
|
2535
|
-
GolfShotDispersion
|
|
2932
|
+
GolfShotDispersion,
|
|
2933
|
+
PowerDurationCurve,
|
|
2934
|
+
TrainingLoadChart
|
|
2536
2935
|
];
|
|
2537
2936
|
|
|
2538
2937
|
|
|
@@ -2575,4 +2974,9 @@ var sportschartsCatalog = [
|
|
|
2575
2974
|
|
|
2576
2975
|
|
|
2577
2976
|
|
|
2578
|
-
|
|
2977
|
+
|
|
2978
|
+
|
|
2979
|
+
|
|
2980
|
+
|
|
2981
|
+
|
|
2982
|
+
exports.PitchCoordinates = PitchCoordinates; exports.PitchView = PitchView; exports.SprayMarks = SprayMarks; exports.BaseballSprayChart = BaseballSprayChart; exports.WagonMarks = WagonMarks; exports.BatterHand = BatterHand; exports.WagonShots = WagonShots; exports.CricketWagonWheel = CricketWagonWheel; exports.GolfDispersionView = GolfDispersionView; exports.GolfShotDispersion = GolfShotDispersion; exports.HockeyRinkView = HockeyRinkView; exports.HockeyRinkMarks = HockeyRinkMarks; exports.HockeyRinkShots = HockeyRinkShots; exports.HockeyShotResult = HockeyShotResult; exports.HockeyRinkShotMap = HockeyRinkShotMap; exports.PassLinkMode = PassLinkMode; exports.PassPositionBasis = PassPositionBasis; exports.PassingNetworkPitch = PassingNetworkPitch; exports.PitchHeatBins = PitchHeatBins; exports.PitchHeatmap = PitchHeatmap; exports.PizzaSort = PizzaSort; exports.PizzaChart = PizzaChart; exports.PowerDurationUnit = PowerDurationUnit; exports.PowerDurationCurve = PowerDurationCurve; exports.RaceLapChart = RaceLapChart; exports.WormMeasure = WormMeasure; exports.ScoreWormChart = ScoreWormChart; exports.StrikeZoneMarks = StrikeZoneMarks; exports.StrikeZoneView = StrikeZoneView; exports.StrikeZonePlot = StrikeZonePlot; exports.ServeMarks = ServeMarks; exports.ServeView = ServeView; exports.ServeFilter = ServeFilter; exports.TennisServePlacement = TennisServePlacement; exports.TrainingLoadForm = TrainingLoadForm; exports.TrainingLoadLayout = TrainingLoadLayout; exports.TrainingLoadChart = TrainingLoadChart; exports.TyreStrategyOrder = TyreStrategyOrder; exports.TyreStrategyChart = TyreStrategyChart; exports.WinProbabilityForm = WinProbabilityForm; exports.WinProbabilityChart = WinProbabilityChart; exports.XgMarks = XgMarks; exports.XgShotMap = XgShotMap; exports.sportschartsCatalog = sportschartsCatalog;
|