@sportsdataverse/sdvplot 0.1.0 → 0.2.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.
Files changed (135) hide show
  1. package/NOTICE.md +15 -0
  2. package/README.md +84 -8
  3. package/dist/chartjs-surface.d.ts +2 -2
  4. package/dist/chartjs-surface.js +2 -2
  5. package/dist/chartjs-surface.js.map +1 -1
  6. package/dist/chartjs.d.ts +32 -2
  7. package/dist/chartjs.js +7 -4
  8. package/dist/chartjs.js.map +1 -1
  9. package/dist/chunk-57WFSI4Q.js +128 -0
  10. package/dist/chunk-57WFSI4Q.js.map +1 -0
  11. package/dist/{chunk-KKH6ABMA.js → chunk-7ULOCCFL.js} +94 -4
  12. package/dist/chunk-7ULOCCFL.js.map +1 -0
  13. package/dist/chunk-AMXASQHT.js +120 -0
  14. package/dist/chunk-AMXASQHT.js.map +1 -0
  15. package/dist/chunk-B2MP37SR.js +175 -0
  16. package/dist/chunk-B2MP37SR.js.map +1 -0
  17. package/dist/{chunk-NLPH2VZT.js → chunk-DYMUVE6K.js} +4 -4
  18. package/dist/{chunk-NLPH2VZT.js.map → chunk-DYMUVE6K.js.map} +1 -1
  19. package/dist/{chunk-QY65DUEF.js → chunk-H2C3FMMA.js} +4 -10
  20. package/dist/chunk-H2C3FMMA.js.map +1 -0
  21. package/dist/{chunk-JJFTD4VB.js → chunk-J4P4HDBF.js} +4 -4
  22. package/dist/{chunk-JJFTD4VB.js.map → chunk-J4P4HDBF.js.map} +1 -1
  23. package/dist/chunk-M3XD2OSN.js +132 -0
  24. package/dist/chunk-M3XD2OSN.js.map +1 -0
  25. package/dist/{chunk-OKEE4AH6.js → chunk-OIILARXI.js} +3 -3
  26. package/dist/{chunk-OKEE4AH6.js.map → chunk-OIILARXI.js.map} +1 -1
  27. package/dist/chunk-RPVVJY74.js +170 -0
  28. package/dist/chunk-RPVVJY74.js.map +1 -0
  29. package/dist/chunk-UL5M6KDE.js +205 -0
  30. package/dist/chunk-UL5M6KDE.js.map +1 -0
  31. package/dist/chunk-WQT4IVLX.js +10 -0
  32. package/dist/chunk-WQT4IVLX.js.map +1 -0
  33. package/dist/{chunk-TAXO3VXH.js → chunk-ZAEQXFJM.js} +3 -3
  34. package/dist/{chunk-TAXO3VXH.js.map → chunk-ZAEQXFJM.js.map} +1 -1
  35. package/dist/cytoscape.d.ts +188 -0
  36. package/dist/cytoscape.js +219 -0
  37. package/dist/cytoscape.js.map +1 -0
  38. package/dist/d3.d.ts +3 -3
  39. package/dist/d3.js +6 -6
  40. package/dist/d3.js.map +1 -1
  41. package/dist/deckgl.d.ts +232 -0
  42. package/dist/deckgl.js +197 -0
  43. package/dist/deckgl.js.map +1 -0
  44. package/dist/echarts.js +5 -5
  45. package/dist/g2.d.ts +251 -0
  46. package/dist/g2.js +102 -0
  47. package/dist/g2.js.map +1 -0
  48. package/dist/index.d.ts +2 -1
  49. package/dist/index.js +4 -5
  50. package/dist/lightweight-charts.d.ts +217 -0
  51. package/dist/lightweight-charts.js +155 -0
  52. package/dist/lightweight-charts.js.map +1 -0
  53. package/dist/maplibre.d.ts +271 -0
  54. package/dist/maplibre.js +175 -0
  55. package/dist/maplibre.js.map +1 -0
  56. package/dist/mui.d.ts +338 -0
  57. package/dist/mui.js +184 -0
  58. package/dist/mui.js.map +1 -0
  59. package/dist/nivo.d.ts +193 -0
  60. package/dist/nivo.js +8 -0
  61. package/dist/nivo.js.map +1 -0
  62. package/dist/perspective.d.ts +198 -0
  63. package/dist/perspective.js +171 -0
  64. package/dist/perspective.js.map +1 -0
  65. package/dist/placement-UWkqUzpa.d.ts +32 -0
  66. package/dist/plot.d.ts +7 -5
  67. package/dist/plot.js +9 -8
  68. package/dist/plot.js.map +1 -1
  69. package/dist/plotly.js +5 -5
  70. package/dist/react.d.ts +279 -3
  71. package/dist/react.js +364 -6
  72. package/dist/react.js.map +1 -1
  73. package/dist/recharts.d.ts +162 -0
  74. package/dist/recharts.js +8 -0
  75. package/dist/recharts.js.map +1 -0
  76. package/dist/shadcn.d.ts +83 -0
  77. package/dist/shadcn.js +88 -0
  78. package/dist/shadcn.js.map +1 -0
  79. package/dist/shots.js +3 -2
  80. package/dist/shots.js.map +1 -1
  81. package/dist/surface-TR7YFJW3.js +4 -0
  82. package/dist/surface-TR7YFJW3.js.map +1 -0
  83. package/dist/surfaces-MIG7HOFU.js +6 -0
  84. package/dist/surfaces-MIG7HOFU.js.map +1 -0
  85. package/dist/surfaces-W-odWLpT.d.ts +47 -0
  86. package/dist/svelte/HeadshotMark.svelte +25 -0
  87. package/dist/svelte/HeadshotMark.svelte.d.ts +10 -0
  88. package/dist/svelte/HeadshotMark.svelte.d.ts.map +1 -0
  89. package/dist/svelte/LogoMark.svelte +25 -0
  90. package/dist/svelte/LogoMark.svelte.d.ts +10 -0
  91. package/dist/svelte/LogoMark.svelte.d.ts.map +1 -0
  92. package/dist/svelte/Marks.svelte +25 -0
  93. package/dist/svelte/Marks.svelte.d.ts +10 -0
  94. package/dist/svelte/Marks.svelte.d.ts.map +1 -0
  95. package/dist/svelte/Surface.svelte +29 -0
  96. package/dist/svelte/Surface.svelte.d.ts +9 -0
  97. package/dist/svelte/Surface.svelte.d.ts.map +1 -0
  98. package/dist/svelte/SurfaceBackdrop.svelte +26 -0
  99. package/dist/svelte/SurfaceBackdrop.svelte.d.ts +11 -0
  100. package/dist/svelte/SurfaceBackdrop.svelte.d.ts.map +1 -0
  101. package/dist/svelte/index.d.ts +13 -0
  102. package/dist/svelte/index.d.ts.map +1 -0
  103. package/dist/svelte/index.js +11 -0
  104. package/dist/svelte-core.d.ts +139 -0
  105. package/dist/svelte-core.js +123 -0
  106. package/dist/svelte-core.js.map +1 -0
  107. package/dist/tanstack.d.ts +240 -0
  108. package/dist/tanstack.js +110 -0
  109. package/dist/tanstack.js.map +1 -0
  110. package/dist/testing.js +4 -5
  111. package/dist/testing.js.map +1 -1
  112. package/dist/three.d.ts +223 -0
  113. package/dist/three.js +50 -0
  114. package/dist/three.js.map +1 -0
  115. package/dist/{tiers-B6pUBPcE.d.ts → tiers-BN4md-GB.d.ts} +2 -30
  116. package/dist/unovis.d.ts +127 -0
  117. package/dist/unovis.js +108 -0
  118. package/dist/unovis.js.map +1 -0
  119. package/dist/uplot.d.ts +120 -0
  120. package/dist/uplot.js +110 -0
  121. package/dist/uplot.js.map +1 -0
  122. package/dist/vega.js +5 -5
  123. package/dist/victory.d.ts +107 -0
  124. package/dist/victory.js +38 -0
  125. package/dist/victory.js.map +1 -0
  126. package/package.json +218 -6
  127. package/dist/chunk-KKH6ABMA.js.map +0 -1
  128. package/dist/chunk-QY65DUEF.js.map +0 -1
  129. package/dist/chunk-RMT2GMFH.js +0 -97
  130. package/dist/chunk-RMT2GMFH.js.map +0 -1
  131. package/dist/chunk-SEBO35DV.js +0 -76
  132. package/dist/chunk-SEBO35DV.js.map +0 -1
  133. package/dist/chunk-TDNBAEQB.js +0 -105
  134. package/dist/chunk-TDNBAEQB.js.map +0 -1
  135. package/dist/surfaces-ChaD9nei.d.ts +0 -38
package/dist/d3.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/d3/faces.ts","../src/d3/shots.ts","../src/d3/index.ts"],"names":["sportyAppendSurface"],"mappings":";;;;;;;;;;;;;AAgBA,IAAM,EAAA,GAAK,4BAAA;AACX,IAAM,IAAA,GAAO,CAAC,CAAA,EAAwB,EAAA,KACpC,OAAO,CAAA,KAAM,UAAA,GAAa,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AAG7B,SAAS,SAAA,CAAa,GAAiD,CAAA,EAAsB;AAClG,EAAA,IAAI,CAAA,CAAE,SAAS,QAAA,EAAU;AACzB,EAAA,KAAA,MAAW,OAAO,CAAA,CAAE,SAAA,CAAoC,OAAO,CAAA,CAAE,OAAM,EAAG;AACxE,IAAA,MAAM,MAAM,GAAA,CAAI,aAAA;AAChB,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,YAAA,CAAa,aAAa,CAAA,IAAK,EAAA;AAC9C,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,YAAA,CAAa,OAAO,CAAC,CAAA;AAC3C,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,GAAA,CAAI,YAAA,CAAa,QAAQ,CAAC,CAAA;AAC5C,IAAA,MAAM,KAAK,MAAA,CAAO,GAAA,CAAI,aAAa,GAAG,CAAC,IAAI,EAAA,GAAK,CAAA;AAChD,IAAA,MAAM,KAAK,MAAA,CAAO,GAAA,CAAI,aAAa,GAAG,CAAC,IAAI,EAAA,GAAK,CAAA;AAChD,IAAA,MAAM,IAAI,EAAA,GAAK,CAAA;AACf,IAAA,MAAM,IAAI,GAAA,GAAM,CAAA;AAChB,IAAA,MAAM,CAAA,GAAI,EAAA,GAAK,CAAA,GAAK,CAAA,GAAI,KAAM,EAAA,GAAK,CAAA;AACnC,IAAA,GAAA,CAAI,YAAA,CAAa,OAAA,EAAS,MAAA,CAAO,CAAC,CAAC,CAAA;AACnC,IAAA,GAAA,CAAI,YAAA,CAAa,QAAA,EAAU,MAAA,CAAO,CAAC,CAAC,CAAA;AACpC,IAAA,GAAA,CAAI,aAAa,GAAA,EAAK,MAAA,CAAO,EAAA,GAAK,CAAA,GAAI,CAAC,CAAC,CAAA;AACxC,IAAA,GAAA,CAAI,aAAa,GAAA,EAAK,MAAA,CAAO,EAAA,GAAK,IAAA,GAAO,CAAC,CAAC,CAAA;AAC3C,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,UAAA,EAAY,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA;AAC7D,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,eAAA,CAAgB,EAAA,EAAI,UAAU,CAAA;AAC/C,IAAA,IAAA,CAAK,YAAA,CAAa,MAAM,MAAM,CAAA;AAC9B,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,eAAA,CAAgB,EAAA,EAAI,QAAQ,CAAA;AAC7C,IAAA,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM,MAAA,CAAO,EAAE,CAAC,CAAA;AAClC,IAAA,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM,MAAA,CAAO,EAAE,CAAC,CAAA;AAClC,IAAA,IAAA,CAAK,YAAA,CAAa,GAAA,EAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAChC,IAAA,IAAA,CAAK,YAAY,IAAI,CAAA;AACrB,IAAA,GAAA,CAAI,YAAA,CAAa,WAAA,EAAa,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAA,CAAG,CAAA;AAC/C,IAAA,GAAA,CAAI,OAAO,IAAI,CAAA;AACf,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,CAAA,CAAE,WAAA,EAAa,EAAE,CAAA;AACnC,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,MAAM,EAAA,GAAK,KAAK,SAAA,EAAU;AAC1B,MAAA,EAAA,CAAG,YAAA,CAAa,QAAQ,IAAI,CAAA;AAC5B,MAAA,EAAA,CAAG,YAAA,CAAa,gBAAgB,MAAM,CAAA;AACtC,MAAA,GAAA,CAAI,OAAO,EAAE,CAAA;AAAA,IACf;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,CAAA,CAAE,IAAA,EAAM,EAAE,CAAA;AAC9B,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,MAAM,IAAA,GAAO,KAAK,SAAA,EAAU;AAC5B,MAAA,IAAA,CAAK,YAAA,CAAa,QAAQ,MAAM,CAAA;AAChC,MAAA,IAAA,CAAK,YAAA,CAAa,UAAU,MAAM,CAAA;AAClC,MAAA,IAAA,CAAK,YAAA,CAAa,gBAAgB,KAAK,CAAA;AACvC,MAAA,GAAA,CAAI,MAAM,IAAI,CAAA;AAAA,IAChB;AAAA,EACF;AACF;ACpDA,IAAM,OAAA,GAAU,EAAA;AAChB,IAAM,OAAA,GAAU,GAAA;AAChB,IAAM,MAAA,GAAS,EAAA;AACf,IAAM,KAAA,GAAQ,gCAAA;AAGd,IAAM,SAAS,CAAC,CAAA,KAAsB,CAAA,EAAG,CAAA,IAAK,IAAI,GAAA,GAAM,QAAG,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,GAAI,GAAG,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAG1F,SAAS,IAAA,CAAK,MAAc,QAAA,EAA4B;AACtD,EAAA,MAAM,OAAA,GAAU,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,QAAA,GAAW,OAAO,CAAC,CAAA;AAC1D,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,EAAG;AAClC,IAAA,IAAI,OAAO,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,IAAA,CAAK,SAAS,OAAA,EAAS;AACjD,MAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AACd,MAAA,GAAA,GAAM,IAAA;AAAA,IACR,OAAO,GAAA,GAAM,GAAA,GAAM,GAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,GAAK,IAAA;AAAA,EACxC;AACA,EAAA,IAAI,GAAA,EAAK,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AACvB,EAAA,OAAO,KAAA;AACT;AAoDO,SAAS,aACd,CAAA,EACA,KAAA,GAAmB,WAAU,EAC7B,CAAA,GAAyB,EAAC,EAClB;AACR,EAAA,MAAM,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AACjB,EAAA,MAAM,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AACjB,EAAA,MAAM,QAAA,GAAW,EAAE,KAAA,IAAS,GAAA;AAC5B,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,GAAG,CAAA;AACpC,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,CAAA,CAAE,UAAU,CAAC,KAAA,CAAM,KAAA,CAAM,CAAC,KAAK,CAAA,EAAG,KAAA,CAAM,MAAM,EAAA,CAAG,EAAE,KAAK,CAAC,CAAA;AAC1E,EAAA,IAAI,EAAE,OAAO,QAAA,CAAS,EAAE,KAAK,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,IAAK,EAAA,GAAK,EAAA,CAAA;AACvD,IAAA,MAAM,IAAI,UAAA,CAAW,CAAA,6DAAA,EAAgE,EAAE,CAAA,EAAA,EAAK,EAAE,CAAA,CAAA,CAAG,CAAA;AAEnG,EAAA,MAAM,EAAA,GAAK,CAAC,EAAA,EAAI,GAAG,MAAM,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,GAAI,EAAA,IAAM,CAAA,GAAI,EAAE,GAAG,EAAE,CAAA;AAClE,EAAA,MAAM,KAAA,GAAQ,EAAA,CAAG,GAAA,CAAI,CAAC,MAAM,CAAA,CAAG,CAAA,GAAI,EAAA,KAAO,EAAA,GAAK,EAAA,CAAA,GAAO,GAAA,EAAK,KAAA,CAAM,CAAC,CAAC,CAAU,CAAA;AAC7E,EAAA,MAAM,EAAA,GAAK,SAAA,CAAU,YAAA,EAAc,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA;AAC1E,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA,CAAE,OAAO,gBAAgB,CAAA,CAAE,IAAA,CAAK,IAAA,EAAM,EAAE,CAAA;AACpE,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,MAAM,CAAA,IAAK,KAAA;AAC7B,IAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,CAAA,EAAG,MAAM,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,EAAE,MAAA,KAAW,CAAC,MAAe,CAAA,KAAM,CAAA,GAAI,GAAA,GAAM,MAAA,CAAO,CAAC,CAAA,CAAA;AACpE,EAAA,CAAA,CAAE,OAAO,MAAM,CAAA,CACZ,IAAA,CAAK,GAAA,EAAK,CAAC,CAAA,CACX,IAAA,CAAK,GAAA,EAAK,CAAC,EACX,IAAA,CAAK,OAAA,EAAS,KAAK,CAAA,CACnB,IAAA,CAAK,UAAU,CAAC,CAAA,CAChB,IAAA,CAAK,IAAA,EAAM,CAAC,CAAA,CACZ,IAAA,CAAK,cAAc,CAAA,2BAAA,EAA8B,MAAA,CAAO,EAAE,CAAC,CAAA,IAAA,EAAO,MAAA,CAAO,EAAE,CAAC,CAAA,CAAE,CAAA,CAC9E,MAAM,MAAA,EAAQ,CAAA,KAAA,EAAQ,EAAE,CAAA,CAAA,CAAG,CAAA;AAC9B,EAAA,KAAA,MAAW,CAAA,IAAK,CAAA,CAAE,KAAA,KAAU,EAAA,GAAK,KAAK,EAAA,GAAK,CAAA,GAAI,CAAC,EAAA,EAAI,GAAG,EAAE,CAAA,GAAI,CAAC,EAAA,EAAI,EAAE,CAAA,CAAA,EAAI;AACtE,IAAA,CAAA,CAAE,OAAO,MAAM,CAAA,CACZ,KAAK,GAAA,EAAK,CAAA,GAAA,CAAM,IAAI,EAAA,KAAO,EAAA,GAAK,MAAO,KAAK,CAAA,CAC5C,KAAK,GAAA,EAAK,CAAA,GAAI,IAAI,OAAA,GAAU,CAAC,EAC7B,IAAA,CAAK,aAAA,EAAe,CAAA,KAAM,EAAA,GAAK,UAAU,CAAA,KAAM,EAAA,GAAK,QAAQ,QAAQ,CAAA,CACpE,MAAM,WAAA,EAAa,CAAA,EAAG,OAAO,CAAA,EAAA,CAAI,CAAA,CACjC,MAAM,MAAA,EAAQ,KAAK,EACnB,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EACnB;AACA,EAAA,IAAI,IAAA,GAAO,IAAI,OAAA,GAAU,CAAA;AACzB,EAAA,MAAM,OAAA,GACJ,CAAA,CAAE,OAAA,KAAY,MAAA,GACV,CAAC,0BAA0B,oCAAiC,CAAA,GAC3D,CAAA,CAAE,OAAA,IAAW,EAAC;AACrB,EAAA,MAAM,QAAQ,CAAC,GAAG,OAAA,EAAS,GAAI,EAAE,KAAA,IAAS,EAAG,CAAA,CAAE,QAAQ,CAAC,CAAA,KAAM,IAAA,CAAK,CAAA,EAAG,QAAQ,CAAC,CAAA;AAC/E,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACtB,IAAA,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA,CACZ,IAAA,CAAK,GAAA,EAAK,CAAC,CAAA,CACX,IAAA,CAAK,GAAA,EAAK,CAAA,GAAI,IAAA,GAAO,OAAA,GAAU,CAAA,GAAI,MAAM,CAAA,CACzC,KAAA,CAAM,WAAA,EAAa,CAAA,EAAG,OAAO,CAAA,EAAA,CAAI,CAAA,CACjC,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA,CACnB,IAAA,CAAK,CAAC,CAAA;AAAA,EACX,CAAC,CAAA;AACD,EAAA,IAAA,IAAQ,MAAM,MAAA,GAAS,MAAA;AACvB,EAAA,MAAM,OAAO,CAAA,CAAE,IAAA;AACf,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,KAAA;AAC5B,IAAA,MAAM,GAAA,GAAM,CAAA,CAAE,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,WAAA,EAAa,CAAA,UAAA,EAAa,CAAC,CAAA,CAAA,EAAI,CAAA,GAAI,IAAA,GAAO,CAAC,CAAA,CAAA,CAAG,CAAA;AAC7E,IAAA,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AAC3B,MAAA,MAAM,EAAA,GAAK,KAAK,CAAA,GAAI,EAAA;AACpB,MAAA,GAAA,CACG,MAAA,CAAO,MAAM,CAAA,CACb,IAAA,CAAK,aAAa,CAAA,UAAA,EAAa,EAAE,MAAM,CAAA,CACvC,IAAA,CAAK,KAAK,QAAA,CAAS,KAAA,EAAO,KAAK,EAAA,CAAG,CAAC,CAAC,CAAC,CAAA,CACrC,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA;AACtB,MAAA,GAAA,CACG,OAAO,MAAM,CAAA,CACb,IAAA,CAAK,GAAA,EAAK,EAAE,CAAA,CACZ,IAAA,CAAK,GAAA,EAAK,EAAE,EACZ,IAAA,CAAK,aAAA,EAAe,QAAQ,CAAA,CAC5B,MAAM,WAAA,EAAa,CAAA,EAAG,OAAO,CAAA,EAAA,CAAI,EACjC,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA,CACnB,KAAK,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,IAAI,CAAA,EAAG,CAAC,CAAA,CAAA,CAAA,GAAM,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IAC3D,CAAC,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,KAAK,IAAA,CAAK,IAAA,IAAQ,GAAG,KAAK,CAAA,eAAA,CAAA,EAAmB,WAAW,GAAG,CAAA;AACxE,IAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACrB,MAAA,GAAA,CACG,MAAA,CAAO,MAAM,CAAA,CACb,IAAA,CAAK,GAAA,EAAK,GAAG,CAAA,CACb,IAAA,CAAK,GAAA,EAAK,CAAA,GAAI,OAAA,GAAU,CAAA,GAAI,MAAM,CAAA,CAClC,KAAA,CAAM,WAAA,EAAa,CAAA,EAAG,OAAO,CAAA,EAAA,CAAI,CAAA,CACjC,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA,CACnB,IAAA,CAAK,CAAC,CAAA;AAAA,IACX,CAAC,CAAA;AACD,IAAA,IAAA,IAAQ,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,GAAI,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,EACnD;AACA,EAAA,OAAO,IAAA;AACT;AA+CO,SAAS,eAAA,CACd,GAAA,EACA,MAAA,EACA,CAAA,EACM;AACN,EAAA,MAAM,KAAA,GAAA,CAAS,CAAA,CAAE,KAAA,IAAS,YAAA,MAAkB,UAAU,UAAA,GAAa,cAAA;AACnE,EAAA,MAAM,EAAE,QAAA,EAAU,KAAA,EAAO,KAAA,EAAO,EAAA,EAAI,UAAA,EAAW,GAAI,iBAAA,CAAkB,MAAA,EAAQ,CAAA,CAAE,IAAA,IAAQ,SAAA,EAAW,CAAA;AAClG,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,SAAA,KAAc,CAAC,CAAA,EAAmB,CAAA,KAAc,IAAA,CAAK,GAAA,CAAK,CAAA,CAAE,KAAA,GAAQ,CAAA,GAAK,EAAA,EAAI,IAAI,CAAA,CAAA;AAChG,EAAA,MAAM,IAAI,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,SAAS,eAAe,CAAA;AACvD,EAAA,IAAI,CAAA,CAAE,UAAU,IAAA,EAAM;AACpB,IAAA,KAAA,MAAW,MAAA,IAAU,CAAC,KAAA,EAAO,IAAI,CAAA,EAAG;AAClC,MAAA,MAAM,CAAA,GAAI,IAAA,EAAqB,CAC5B,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,IAAA,KAAS,CAAC,MAAA,IAAU,CAAA,CAAE,KAAA,KAAU,IAAA,CAAK,EACtE,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAA,CAAE,QAAQ,CAAC,CAAA,CACxB,EAAE,CAAC,CAAA,KAAM,CAAA,CAAE,CAAA,CAAE,EAAE,WAAA,IAAe,CAAC,CAAC,CAAA,CAChC,MAAM,KAAK,CAAA;AACd,MAAA,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA,CACZ,IAAA,CAAK,GAAA,EAAK,CAAA,CAAE,CAAC,GAAG,MAAM,CAAC,CAAA,IAAK,EAAE,CAAA,CAC9B,KAAA,CAAM,MAAA,EAAQ,MAAM,CAAA,CACpB,KAAA,CAAM,QAAA,EAAU,KAAK,CAAA,CACrB,KAAA,CAAM,gBAAA,EAAkB,MAAA,GAAS,CAAA,GAAI,GAAG,CAAA,CACxC,KAAA,CAAM,oBAAoB,KAAK,CAAA;AAAA,IACpC;AAAA,EACF;AACA,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,CAAC,OAAO,CAAA,CAAE,CAAA,CAAE,CAAC,CAAC,GAAG,MAAA,CAAO,CAAA,CAAE,CAAA,CAAE,KAAK,CAAC,CAAC,CAAA;AACpD,EAAA,MAAM,EAAA,GAAK,UAAA,CAAW,EAAA,EAAI,EAAE,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,CAAA,CACV,MAAA,CAAO,MAAM,CAAA,CACb,MAAA,CAAO,gBAAgB,CAAA,CACvB,IAAA,CAAK,IAAA,EAAM,EAAE,CAAA,CACb,KAAK,eAAA,EAAiB,gBAAgB,CAAA,CACtC,IAAA,CAAK,IAAA,EAAM,EAAE,CAAA,CACb,IAAA,CAAK,IAAA,EAAM,EAAE,CAAA,CACb,IAAA,CAAK,IAAA,EAAM,GAAG,CAAA,CACd,IAAA,CAAK,MAAM,GAAG,CAAA;AACjB,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,MAAM,CAAA,IAAK,KAAA;AAC7B,IAAA,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,CAAA,EAAG,MAAM,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,MAAqB,CACjC,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,KAAU,IAAI,CAAA,CAC/B,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAA,CAAE,QAAQ,CAAC,CAAA,CACxB,EAAA,CAAG,CAAC,CAAA,KAAM,CAAA,CAAE,CAAA,CAAE,EAAE,KAAA,IAAS,CAAC,IAAI,IAAA,CAAK,CAAA,EAAG,QAAQ,CAAC,CAAA,CAC/C,EAAA,CAAG,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAA,CAAE,KAAA,IAAS,CAAC,CAAA,GAAI,IAAA,CAAK,GAAG,QAAQ,CAAC,CAAA,CAC/C,KAAA,CAAM,KAAK,CAAA;AACd,EAAA,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA,CACZ,IAAA,CAAK,KAAK,MAAA,CAAO,CAAC,GAAG,MAAM,CAAC,CAAA,IAAK,EAAE,CAAA,CACnC,KAAK,YAAA,EAAc,cAAc,CAAA,CACjC,KAAA,CAAM,MAAA,EAAQ,CAAA,KAAA,EAAQ,EAAE,CAAA,CAAA,CAAG,EAC3B,KAAA,CAAM,QAAA,EAAU,cAAc,CAAA,CAC9B,MAAM,gBAAA,EAAkB,GAAG,CAAA,CAC3B,KAAA,CAAM,gBAAgB,GAAG,CAAA;AAC5B,EAAA,OAAO,CAAA;AACT;;;AClOA,SAAS,KACP,GAAA,EACA,EAAA,EACA,IACA,GAAA,EACA,CAAA,EACA,MACA,KAAA,EACqB;AACrB,EAAA,MAAM,CAAA,GAAI,WAAA,CAAY,CAAA,CAAE,MAAA,IAAU,GAAG,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,CAAA,CAAE,KAAA,IAAS,CAAC,CAAA;AACrC,EAAA,IAAI,EAAE,OAAO,QAAA,CAAS,CAAA,CAAE,WAAW,CAAA,IAAK,CAAA,CAAE,cAAc,CAAA,CAAA,EAAI;AAC1D,IAAA,MAAM,IAAI,UAAA,CAAW,CAAA,0CAAA,EAA6C,OAAO,CAAA,CAAE,WAAW,CAAC,CAAA,CAAE,CAAA;AAAA,EAC3F;AACA,EAAA,MAAM,EAAA,GAAK,IAAI,CAAA,CAAE,WAAA;AACjB,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,EAAE,CAAA,EAAG,GAAA,EAAK,KAAK,CAAA;AACnE,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,OAAA,EAAS,CAAA,IAAA,EAAO,IAAI,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,WAAW,KAAK,CAAA;AAC7E,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,MAAM,GAAA,GAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,GAAG,CAAA,CAAE,IAAA,CAAK,qBAAA,EAAuB,eAAe,CAAA;AAC7F,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,EAAK;AACtB,IAAA,IAAI,SAAS,IAAA,EAAM;AACnB,IAAA,UAAA,CAAW,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,EAAA,EAAI,EAAE,WAAA,EAAa,CAAA,CAAE,CAAA,CAAE,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAA,CAAE,CAAA,CAAE,CAAC,CAAC,CAAA;AAC/D,IAAA,GAAA,CAAI,IAAA,CAAK,YAAA,EAAc,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,YAAA,EAAc,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAClE,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA;AACvB,IAAA,GAAA,CAAI,KAAK,YAAA,EAAc,CAAA,CAAE,SAAA,GAAY,GAAA,EAAK,EAAE,KAAK,CAAA,IAAK,CAAA,EAAG,UAAA,CAAW,GAAG,KAAA,CAAM,MAAA,EAAQ,GAAG,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAAA,EACrG;AACA,EAAA,OAAO,CAAA;AACT;AAQA,IAAM,QAAA,GACJ,CAAC,IAAA,KACD,CAAC,KAAK,EAAA,EAAI,EAAA,EAAI,KAAA,EAAO,CAAA,KACnB,KAAK,GAAA,EAAK,EAAA,EAAI,EAAA,EAAI,KAAA,EAAO,GAAG,IAAA,EAAM;AAAA,EAChC,QAAQ,CAAA,CAAE,MAAA;AAAA,EACV,IAAA;AAAA,EACA,OAAA,EAAS,EAAE,OAAA,IAAW,SAAA;AAAA,EACtB,GAAI,EAAE,QAAA,KAAa,MAAA,GAAY,EAAC,GAAI,EAAE,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,EAC3D,GAAI,EAAE,MAAA,KAAW,MAAA,GAAY,EAAC,GAAI,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA;AAChD,CAAC,CAAA;AAyBE,IAAM,WAAA,GAA+B,SAAS,MAAM;AAEpD,IAAM,eAAA,GAAmC,SAAS,UAAU;AA2B5D,SAAS,eAAA,CACd,GAAA,EACA,EAAA,EACA,EAAA,EACA,SACA,CAAA,EACqB;AACrB,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,EAAK,IAAI,EAAA,EAAI,OAAA,EAAS,GAAG,UAAA,EAAY;AAAA,IAClD,QAAQ,CAAA,CAAE,MAAA;AAAA,IACV,IAAA,EAAM,UAAA;AAAA,IACN,QAAA,EAAU,EAAE,QAAA,IAAY;AAAA,GACzB,CAAA;AACD,EAAA,SAAA,CAAU,GAAG,CAAC,CAAA;AACd,EAAA,OAAO,CAAA;AACT;AAeO,SAAS,cAAA,CACd,MAAA,EACA,CAAA,GAMI,EAAC,EACiC;AACtC,EAAA,MAAM,EAAA,GAAK,EAAE,OAAA,IAAW,MAAA;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,eAAA,CAAgB,QAAQ,CAAC,CAAA;AACpD,EAAA,OAAO,YAAA,EAA6B,CACjC,MAAA,CAAO,MAAM,EACb,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,MAAM,CAAA,IAAK,EAAE,CAAC,CAAA,CAChC,QAAQ,EAAE,CAAA;AACf;AASO,SAAS,aAAA,CACd,GAAA,EACA,MAAA,EACA,CAAA,EACqB;AACrB,EAAA,MAAM,EAAE,CAAA,EAAG,CAAA,EAAG,eAAA,EAAiB,GAAG,OAAM,GAAI,CAAA;AAC5C,EAAA,OAAOA,eAAA;AAAA,IACL,GAAA;AAAA,IACA,YAAA,CAAa,QAAQ,KAAK,CAAA;AAAA,IAC1B,CAAA;AAAA,IACA,CAAA;AAAA,IACA,eAAA,KAAoB,MAAA,GAAY,EAAC,GAAI,EAAE,eAAA;AAAgB,GACzD;AACF","file":"d3.js","sourcesContent":["import type { BaseType, Selection } from \"d3\";\nimport { contentId } from \"../content-id.js\";\n\n/** Face options for `appendHeadshots` (blazing-the-nets `main` scatter \"faces\", `lib/charts/scatterChart.ts:139-191`). */\nexport interface FaceOptions {\n /**\n * `\"circle\"`: the headshot inside a circle whose diameter is `height` × `frameHeight`. The image is drawn 2.3 R tall\n * so the head fills the circle, so `drawnMarks` reports 1.15 × `height` for a face.\n */\n clip?: \"circle\";\n /** Ring colour per player id (e.g. the team colour; `:183-188`, 1.5 px). Default none. */\n ring?: string | ((id: string) => string);\n /** A disc behind the face at 0.35 opacity, still there if the image fails (`:169-172`). Default none. */\n placeholder?: string | ((id: string) => string);\n}\n\nconst NS = \"http://www.w3.org/2000/svg\";\nconst pick = (c: FaceOptions[\"ring\"], id: string): string | undefined =>\n typeof c === \"function\" ? c(id) : c;\n\n/** Turn `appendHeadshots`' images into circular faces in place. */\nexport function clipFaces<D>(g: Selection<SVGGElement, D, BaseType, unknown>, o: FaceOptions): void {\n if (o.clip !== \"circle\") return;\n for (const img of g.selectAll<SVGImageElement, unknown>(\"image\").nodes()) {\n const doc = img.ownerDocument;\n const id = img.getAttribute(\"data-sdv-id\") ?? \"\";\n const w0 = Number(img.getAttribute(\"width\"));\n const h0 = Number(img.getAttribute(\"height\"));\n const cx = Number(img.getAttribute(\"x\")) + w0 / 2;\n const cy = Number(img.getAttribute(\"y\")) + h0 / 2;\n const r = h0 / 2;\n const h = 2.3 * r; // the head fills the circle: image 2.3 R tall, top 1.05 R above centre (:177-181)\n const w = h0 > 0 ? (h * w0) / h0 : 0;\n img.setAttribute(\"width\", String(w));\n img.setAttribute(\"height\", String(h));\n img.setAttribute(\"x\", String(cx - w / 2));\n img.setAttribute(\"y\", String(cy - 1.05 * r));\n const clipId = contentId(\"sdv-face\", `${id}|${cx}|${cy}|${r}`);\n const clip = doc.createElementNS(NS, \"clipPath\");\n clip.setAttribute(\"id\", clipId);\n const disc = doc.createElementNS(NS, \"circle\");\n disc.setAttribute(\"cx\", String(cx));\n disc.setAttribute(\"cy\", String(cy));\n disc.setAttribute(\"r\", String(r));\n clip.appendChild(disc);\n img.setAttribute(\"clip-path\", `url(#${clipId})`);\n img.before(clip);\n const fill = pick(o.placeholder, id);\n if (fill !== undefined) {\n const ph = disc.cloneNode() as Element;\n ph.setAttribute(\"fill\", fill);\n ph.setAttribute(\"fill-opacity\", \"0.35\");\n img.before(ph);\n }\n const stroke = pick(o.ring, id);\n if (stroke !== undefined) {\n const ring = disc.cloneNode() as Element;\n ring.setAttribute(\"fill\", \"none\");\n ring.setAttribute(\"stroke\", stroke);\n ring.setAttribute(\"stroke-width\", \"1.5\");\n img.after(ring);\n }\n }\n}\n","// d3 twins of the shot-chart marks: blazing-the-nets `main` lib/charts/theme.ts (legend), hexShotChart.ts (size key)\n// and shootingSignature.ts (@31427b8), which are d3 themselves. Never imports ../plot/*.\nimport { type BaseType, type Selection, area, curveBasis, curveMonotoneX, line } from \"d3\";\nimport { type BinShape, cellPath } from \"../bins/index.js\";\nimport { contentId } from \"../content-id.js\";\nimport { InputError } from \"../errors.js\";\nimport { type DiffScale, diffScale } from \"../shots/diff.js\";\nimport { SIGNATURE_NAME, type SignaturePoint, signatureGradient } from \"../shots/signature.js\";\n\n/** Any `<g>` selection, whatever its datum (d3's `Selection` is invariant in it; see `Sel` in ./index.ts). */\ntype G<D> = Selection<SVGGElement, D, BaseType, unknown>;\nconst FONT_PX = 11; // blazing-the-nets main lib/charts/theme.ts:24\nconst CHAR_PX = 6.2; // theme.ts:26\nconst LINE_H = 15; // theme.ts:92\nconst MUTED = \"var(--sdv-muted, currentColor)\"; // main's TOKENS.muted where the page sets it, else the page's ink\n\n/** Signed points from a fraction (blazing-the-nets `main` `lib/format.ts:8`): 0.042 → \"+4.2\", -0.042 → \"−4.2\". */\nconst fmtPts = (v: number): string => `${v >= 0 ? \"+\" : \"−\"}${Math.abs(v * 100).toFixed(1)}`;\n\n/** Greedy word wrap at an estimated 6.2 px per character (theme.ts:77-90): no measuring, so SSR-safe. */\nfunction wrap(text: string, maxWidth: number): string[] {\n const perLine = Math.max(8, Math.floor(maxWidth / CHAR_PX));\n const lines: string[] = [];\n let cur = \"\";\n for (const word of text.split(\" \")) {\n if (cur && cur.length + 1 + word.length > perLine) {\n lines.push(cur);\n cur = word;\n } else cur = cur ? `${cur} ${word}` : word;\n }\n if (cur) lines.push(cur);\n return lines;\n}\n\n/** Options for `appendLegend`. */\nexport interface AppendLegendOptions {\n /** Top-left corner of the legend in px; default (0, 0). */\n x?: number;\n /** See `x`. */\n y?: number;\n /** Space available, which the text wraps to; the bar is at most 240 px (theme.ts:122). */\n width?: number;\n /**\n * Diffs the bar spans; default the scale's end stops. `master`'s legend spanned [-0.30, 0.30]\n * (`ShootingSignature/Legend.js:36-38`): `{ domain: [-0.3, 0.3], ticks: [-0.3, -0.15, 0, 0.15, 0.3] }`.\n */\n domain?: readonly [lo: number, hi: number];\n /** Tick diffs; default the domain's ends, and 0 when it lies inside them. */\n ticks?: readonly number[];\n /** Tick text; default signed points, \"0\" at 0 (theme.ts:140). */\n format?: (d: number) => string;\n /** Caption and key in words (theme.ts:35, :120); `null` for none. */\n caption?: readonly string[] | null;\n /** More lines under the caption, wrapped to `width` (e.g. a shrinkage note). */\n notes?: readonly string[];\n /** A cell size key under the colour key: pixel size per attempt count and the counts (`sizeCells(...).steps`). */\n size?: {\n readonly px: (attempts: number) => number;\n readonly steps: readonly number[];\n /** The key's cell shape; default `\"hex\"`. */\n readonly shape?: BinShape;\n /** Default `\"hex size: attempts\"` or `\"square size: attempts\"`. */\n readonly note?: string;\n };\n}\n\n/**\n * A diff-colour legend for d3 charts: gradient bar, ticks, caption, notes and an optional cell size key\n * (blazing-the-nets `main` `lib/charts/theme.ts:109-143`, `lib/charts/hexShotChart.ts:196-213`). It replaces\n * `master`'s static PNG ramp (`ShootingSignature/Legend.js:45-50`, `rgy5.png`) with a gradient generated from the\n * scale, whose id is a hash of its stops. Nothing is measured (text wraps at an estimated 6.2 px per character), so\n * it renders the same in jsdom and SSR. Returns the height used. Plot users: `Plot.legend({ color: scale.plot })`.\n *\n * @example\n * ```ts\n * import { create } from \"d3\";\n * import { appendLegend } from \"@sportsdataverse/sdvplot/d3\";\n * import { diffScale } from \"@sportsdataverse/sdvplot/shots\";\n *\n * const svg = create(\"svg\").attr(\"viewBox\", \"0 0 300 80\");\n * appendLegend(svg.append(\"g\"), diffScale(), { width: 280 });\n * svg.node();\n * ```\n */\nexport function appendLegend<D>(\n g: G<D>,\n scale: DiffScale = diffScale(),\n o: AppendLegendOptions = {},\n): number {\n const x = o.x ?? 0;\n const y = o.y ?? 0;\n const maxWidth = o.width ?? 240;\n const width = Math.min(maxWidth, 240);\n const [lo, hi] = o.domain ?? [scale.stops[0] ?? 0, scale.stops.at(-1) ?? 0];\n if (!(Number.isFinite(lo) && Number.isFinite(hi) && hi > lo))\n throw new InputError(`appendLegend domain must be finite and run low to high, got [${lo}, ${hi}]`);\n // The domain's ends plus every scale stop inside it: exact for a piecewise-linear scale (master), 5 samples of RdBu.\n const at = [lo, ...scale.stops.filter((d) => d > lo && d < hi), hi];\n const stops = at.map((d) => [((d - lo) / (hi - lo)) * 100, scale(d)] as const);\n const id = contentId(\"sdv-legend\", stops.map((s) => s.join(\" \")).join(\";\"));\n const grad = g.append(\"defs\").append(\"linearGradient\").attr(\"id\", id);\n for (const [offset, colour] of stops)\n grad.append(\"stop\").attr(\"offset\", `${offset}%`).attr(\"stop-color\", colour);\n const format = o.format ?? ((d: number) => (d === 0 ? \"0\" : fmtPts(d)));\n g.append(\"rect\")\n .attr(\"x\", x)\n .attr(\"y\", y)\n .attr(\"width\", width)\n .attr(\"height\", 8)\n .attr(\"rx\", 2)\n .attr(\"aria-label\", `colour key, FG% vs league: ${format(lo)} to ${format(hi)}`)\n .style(\"fill\", `url(#${id})`);\n for (const d of o.ticks ?? (lo < 0 && hi > 0 ? [lo, 0, hi] : [lo, hi])) {\n g.append(\"text\")\n .attr(\"x\", x + ((d - lo) / (hi - lo)) * width)\n .attr(\"y\", y + 8 + FONT_PX + 2)\n .attr(\"text-anchor\", d === lo ? \"start\" : d === hi ? \"end\" : \"middle\")\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(format(d));\n }\n let used = 8 + FONT_PX + 6;\n const caption =\n o.caption === undefined\n ? [\"FG% vs league (points)\", \"red: above league · blue: below\"]\n : (o.caption ?? []);\n const lines = [...caption, ...(o.notes ?? [])].flatMap((n) => wrap(n, maxWidth));\n lines.forEach((t, i) => {\n g.append(\"text\")\n .attr(\"x\", x)\n .attr(\"y\", y + used + FONT_PX + i * LINE_H)\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(t);\n });\n used += lines.length * LINE_H;\n const size = o.size;\n if (size) {\n const shape = size.shape ?? \"hex\";\n const key = g.append(\"g\").attr(\"transform\", `translate(${x},${y + used + 8})`);\n size.steps.forEach((n, i) => {\n const cx = 12 + i * 34;\n key\n .append(\"path\")\n .attr(\"transform\", `translate(${cx},10)`)\n .attr(\"d\", cellPath(shape, size.px(n)))\n .style(\"fill\", MUTED);\n key\n .append(\"text\")\n .attr(\"x\", cx)\n .attr(\"y\", 36)\n .attr(\"text-anchor\", \"middle\")\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(i === size.steps.length - 1 ? `${n}+` : String(n));\n });\n // main's drawNotes(key, 118, 4, width - 24 - 118, …) (hexShotChart.ts:212): wrapped, 8 characters a line at the least\n const note = wrap(size.note ?? `${shape} size: attempts`, maxWidth - 118);\n note.forEach((t, i) => {\n key\n .append(\"text\")\n .attr(\"x\", 118)\n .attr(\"y\", 4 + FONT_PX + i * LINE_H)\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(t);\n });\n used += 8 + Math.max(42, 8 + note.length * LINE_H);\n }\n return used;\n}\n\n/** Options for `appendSignature`. */\nexport interface AppendSignatureOptions {\n /** The caller's scale from distance (ft) to px. */\n x: (distance: number) => number;\n /** The caller's scale from FG% (0-1) to px; a clamped scale clamps the ribbon's centre. */\n y: (fgPct: number) => number;\n /** Colour of `colourDiff`; default `diffScale()`. */\n fill?: DiffScale;\n /** `\"monotone-x\"` (default, `main`) or `\"basis\"` (`master` `ShootingSignature/index.js:96`). */\n curve?: \"monotone-x\" | \"basis\";\n /** Ribbon half-width in PIXELS; default `main`'s `max(share / maxShare * 20, 0.75)` (`shootingSignature.ts:131-132`). */\n halfWidth?: (p: SignaturePoint, maxShare: number) => number;\n /** The dashed league line, faint everywhere and full strength under the ribbon (`:165-181`); default true. */\n league?: boolean;\n}\n\n/**\n * The d3 twin of `sdvplot/plot`'s `shootingSignature`: the dashed league line and the ribbon along FG% by distance,\n * as wide as the shot share and coloured along x by the shrunk FG% vs league (blazing-the-nets `main`\n * `lib/charts/shootingSignature.ts:165-211`). The same points give the Plot mark's ribbon and league paths, gradient\n * stops and gradient id when the scales match (with a 190 px [0, 1] y axis for the default half-width). A null\n * `fgPct` is a gap. The gradient id hashes its stops and its pixel x range, so two signatures on a page, or one at\n * two widths, never share one. y goes through the caller's `y` as it is: the ribbon's edges are\n * `y(fgPct) ± halfWidth`, and a clamped scale clamps the centre (as `main` does). Returns the `<g>` it appended.\n *\n * @example\n * ```ts\n * import { create, scaleLinear } from \"d3\";\n * import { appendSignature } from \"@sportsdataverse/sdvplot/d3\";\n * import { fgPctByDistance, signaturePoints, vsLeague } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const shots = [\n * { x_legacy: -1, y_legacy: 7, shot_distance: 1, shot_value: 2, shot_result: \"Made\" },\n * { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Missed\" },\n * { x_legacy: -44, y_legacy: 252, shot_distance: 26, shot_value: 3, shot_result: \"Made\" },\n * ];\n * // the makes against all three attempts, which stand in for the league (the gallery's uses the 2025-26 league)\n * const made = fgPctByDistance(shots.filter((s) => s.shot_result === \"Made\"));\n * const points = signaturePoints(vsLeague(made, fgPctByDistance(shots)), { minAttempts: 1 });\n * const svg = create(\"svg\").attr(\"viewBox\", \"0 0 400 200\");\n * appendSignature(svg.append(\"g\"), points, { x: scaleLinear([0, 35], [0, 400]), y: scaleLinear([0, 1], [200, 0]) });\n * svg.node();\n * ```\n */\nexport function appendSignature<D>(\n sel: G<D>,\n points: readonly SignaturePoint[],\n o: AppendSignatureOptions,\n): G<D> {\n const curve = (o.curve ?? \"monotone-x\") === \"basis\" ? curveBasis : curveMonotoneX;\n const { maxShare, maxFt, stops, id: gradientId } = signatureGradient(points, o.fill ?? diffScale());\n const half = o.halfWidth ?? ((p: SignaturePoint, m: number) => Math.max((p.share / m) * 20, 0.75));\n const g = sel.append(\"g\").attr(\"class\", \"sdv-signature\");\n if (o.league ?? true) {\n for (const strong of [false, true]) {\n const l = line<SignaturePoint>()\n .defined((p) => p.leagueFgPct !== null && (!strong || p.fgPct !== null))\n .x((p) => o.x(p.distance))\n .y((p) => o.y(p.leagueFgPct ?? 0))\n .curve(curve);\n g.append(\"path\")\n .attr(\"d\", l([...points]) ?? \"\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", MUTED)\n .style(\"stroke-opacity\", strong ? 1 : 0.4)\n .style(\"stroke-dasharray\", \"3 3\");\n }\n }\n const [x1, x2] = [String(o.x(0)), String(o.x(maxFt))];\n const id = gradientId(x1, x2);\n const grad = g\n .append(\"defs\")\n .append(\"linearGradient\")\n .attr(\"id\", id)\n .attr(\"gradientUnits\", \"userSpaceOnUse\")\n .attr(\"x1\", x1)\n .attr(\"x2\", x2)\n .attr(\"y1\", \"0\")\n .attr(\"y2\", \"0\");\n for (const [offset, colour] of stops)\n grad.append(\"stop\").attr(\"offset\", `${offset}%`).attr(\"stop-color\", colour);\n const ribbon = area<SignaturePoint>()\n .defined((p) => p.fgPct !== null)\n .x((p) => o.x(p.distance))\n .y0((p) => o.y(p.fgPct ?? 0) + half(p, maxShare))\n .y1((p) => o.y(p.fgPct ?? 0) - half(p, maxShare))\n .curve(curve);\n g.append(\"path\")\n .attr(\"d\", ribbon([...points]) ?? \"\")\n .attr(\"aria-label\", SIGNATURE_NAME)\n .style(\"fill\", `url(#${id})`)\n .style(\"stroke\", \"currentColor\")\n .style(\"stroke-opacity\", 0.2)\n .style(\"stroke-width\", 0.5);\n return g;\n}\n","import { appendSurface as sportyAppendSurface } from \"@sportsdataverse/sporty/d3\";\nimport { type BaseType, type ScaleOrdinal, type Selection, scaleOrdinal } from \"d3\";\nimport { InputError } from \"../errors.js\";\nimport type { EspnHeadshotLeague } from \"../headshots.js\";\nimport { type Kind, checkAlpha, checkHeight, placeSync, placedName } from \"../placement.js\";\nimport type { Value } from \"../resolve.js\";\nimport { stampImage } from \"../stamp.js\";\nimport { type SurfaceSceneOptions, surfaceScene } from \"../surfaces.js\";\nimport { teamColorDomain } from \"../team-color-domain.js\";\nimport type { HeadshotIdSystem, IdSystem, League, SeasonInput, Variant, Which } from \"../types.js\";\nimport { type FaceOptions, clipFaces } from \"./faces.js\";\n\n/**\n * A selection of `G` with any datum `D` and any parent. d3's `Selection` is invariant in its datum, so a helper typed\n * with `unknown` would reject `create(\"svg\").append(\"g\")` (datum `undefined`) and every bound datum.\n */\ntype Sel<G extends Element, D> = Selection<G, D, BaseType, unknown>;\n/** Where d3 draws: the caller's scales, plus the pixel height the `height` fraction refers to (d3 has no figure). */\ninterface Frame {\n x: (v: Value) => number;\n y: (v: Value) => number;\n frameHeight: number;\n height?: number;\n alpha?: number;\n /**\n * Each image's accessible name from its input value and index; default the team (\"KC logo\", whatever id system the\n * values use) or the player id (\"3139477 headshot\").\n */\n ariaLabel?: (value: Value, i: number) => string;\n}\nexport interface D3MarkOptions extends Frame {\n league: League;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n}\nexport interface D3HeadshotOptions extends Frame, FaceOptions {\n league: EspnHeadshotLeague;\n /** \"espn\" (default) or \"gsis\". \"gsis\" needs `loadGsis()` to have run first, else this throws InputError. */\n idSystem?: HeadshotIdSystem;\n}\n\nfunction draw<G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n ids: readonly Value[],\n o: Frame,\n kind: Kind,\n place: Parameters<typeof placeSync>[3],\n): Sel<SVGGElement, D> {\n const h = checkHeight(o.height ?? 0.1);\n const alpha = checkAlpha(o.alpha ?? 1);\n if (!(Number.isFinite(o.frameHeight) && o.frameHeight > 0)) {\n throw new InputError(`frameHeight is the plot height in px, got ${String(o.frameHeight)}`);\n }\n const px = h * o.frameHeight;\n const placed = placeSync(Array.from(xs), Array.from(ys), ids, place);\n const g = sel.append(\"g\").attr(\"class\", `sdv-${kind}s`).attr(\"opacity\", alpha);\n for (const p of placed) {\n const img = g.append(\"image\").attr(\"href\", p.url).attr(\"preserveAspectRatio\", \"xMidYMid meet\");\n const node = img.node();\n if (node === null) continue;\n stampImage(node, p, kind, px, o.frameHeight, o.x(p.x), o.y(p.y));\n img.attr(\"data-sdv-x\", String(p.x)).attr(\"data-sdv-y\", String(p.y));\n const raw = ids[p.index] as Value;\n img.attr(\"aria-label\", o.ariaLabel?.(raw, p.index) ?? `${placedName(p, place.league, raw)} ${kind}`);\n }\n return g;\n}\nexport type AppendTeamMarks = <G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n teams: readonly Value[],\n o: D3MarkOptions,\n) => Sel<SVGGElement, D>;\nconst teamMark =\n (kind: \"logo\" | \"wordmark\"): AppendTeamMarks =>\n (sel, xs, ys, teams, o) =>\n draw(sel, xs, ys, teams, o, kind, {\n league: o.league,\n kind,\n variant: o.variant ?? \"default\",\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n ...(o.season === undefined ? {} : { season: o.season }),\n });\n/**\n * Append `<g class=\"sdv-logos\">` of team logos at (x, y) through the caller's scale functions. Needs\n * `loadLeague(league)` first.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { appendLogos } from \"@sportsdataverse/sdvplot/d3\";\n * import * as d3 from \"d3\";\n *\n * await loadLeague(\"nfl\");\n * const x = d3.scaleLinear([250, 550], [0, 480]);\n * const y = d3.scaleLinear([280, 420], [240, 0]);\n * const svg = d3.select(document.createElement(\"div\")).append(\"svg\").attr(\"viewBox\", [0, 0, 480, 240]);\n * appendLogos(svg, [385, 525, 425], [326, 368, 311], [\"KC\", \"BUF\", \"DEN\"], {\n * league: \"nfl\",\n * x: (v) => x(Number(v)),\n * y: (v) => y(Number(v)),\n * frameHeight: 240,\n * height: 0.2,\n * });\n * svg.node();\n * ```\n */\nexport const appendLogos: AppendTeamMarks = teamMark(\"logo\");\n/** As `appendLogos`, with wordmarks. */\nexport const appendWordmarks: AppendTeamMarks = teamMark(\"wordmark\");\n/**\n * Append `<g class=\"sdv-headshots\">` of ESPN player headshots; `idSystem: \"gsis\"` needs `loadGsis()` first.\n * `clip: \"circle\"` makes circular faces (`height` is then the circle's diameter), with an optional `ring` and `placeholder`.\n *\n * @example\n * ```ts\n * import { appendHeadshots } from \"@sportsdataverse/sdvplot/d3\";\n * import * as d3 from \"d3\";\n *\n * const x = d3.scaleLinear([0, 10], [0, 480]);\n * const y = d3.scaleLinear([0, 10], [240, 0]);\n * const svg = d3.select(document.createElement(\"div\")).append(\"svg\").attr(\"viewBox\", [0, 0, 480, 240]);\n * const team: Record<string, string> = { \"3139477\": \"#e31837\", \"4374302\": \"#0076b6\", \"4429160\": \"#008e97\" };\n * appendHeadshots(svg, [2, 5, 8], [4, 6, 3], [\"3139477\", \"4374302\", \"4429160\"], {\n * league: \"nfl\",\n * x: (v) => x(Number(v)),\n * y: (v) => y(Number(v)),\n * frameHeight: 240,\n * height: 0.25,\n * clip: \"circle\",\n * ring: (id) => team[id] ?? \"grey\",\n * placeholder: (id) => team[id] ?? \"grey\",\n * });\n * svg.node();\n * ```\n */\nexport function appendHeadshots<G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n players: readonly Value[],\n o: D3HeadshotOptions,\n): Sel<SVGGElement, D> {\n const g = draw(sel, xs, ys, players, o, \"headshot\", {\n league: o.league,\n kind: \"headshot\",\n idSystem: o.idSystem ?? \"espn\",\n });\n clipFaces(g, o);\n return g;\n}\n\n/**\n * A d3 ordinal scale from team (id or abbr) to team colour; anything unresolved maps to `naValue` (default \"grey\").\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorScale } from \"@sportsdataverse/sdvplot/d3\";\n *\n * await loadLeague(\"nba\");\n * const color = teamColorScale(\"nba\", { values: [\"LAL\", \"BOS\"] });\n * [\"LAL\", \"BOS\", \"not a team\"].map(color);\n * ```\n */\nexport function teamColorScale(\n league: League,\n o: {\n which?: Which;\n season?: SeasonInput;\n idSystem?: IdSystem;\n naValue?: string;\n values?: readonly Value[];\n } = {},\n): ScaleOrdinal<string, string, string> {\n const na = o.naValue ?? \"grey\";\n const { domain, colors } = teamColorDomain(league, o);\n return scaleOrdinal<string, string>()\n .domain(domain)\n .range(colors.map((c) => c ?? na))\n .unknown(na);\n}\n\nexport interface D3SurfaceOptions extends SurfaceSceneOptions {\n x: (v: number) => number;\n y: (v: number) => number;\n /** Describes the surface for assistive technology; default sporty's (\"nba basketball surface\" and so on). */\n ariaDescription?: string;\n}\n/** Paint a league's surface (in `team`'s colours) into `sel` through the caller's x/y scales. Throws InputError for a league with no surface. */\nexport function appendSurface<G extends SVGGElement | SVGSVGElement, D>(\n sel: Sel<G, D>,\n league: League,\n o: D3SurfaceOptions,\n): Sel<SVGGElement, D> {\n const { x, y, ariaDescription, ...scene } = o;\n return sportyAppendSurface(\n sel,\n surfaceScene(league, scene),\n x,\n y,\n ariaDescription === undefined ? {} : { ariaDescription },\n );\n}\nexport { appendLegend, appendSignature } from \"./shots.js\";\nexport type { AppendLegendOptions, AppendSignatureOptions } from \"./shots.js\";\nexport type { FaceOptions } from \"./faces.js\";\n"]}
1
+ {"version":3,"sources":["../src/d3/faces.ts","../src/d3/shots.ts","../src/d3/index.ts"],"names":["sportyAppendSurface"],"mappings":"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","file":"d3.js","sourcesContent":["import type { BaseType, Selection } from \"d3\";\nimport { contentId } from \"../content-id.js\";\n\n/** Face options for `appendHeadshots` (blazing-the-nets `main` scatter \"faces\", `lib/charts/scatterChart.ts:139-191`). */\nexport interface FaceOptions {\n /**\n * `\"circle\"`: the headshot inside a circle whose diameter is `height` × `frameHeight`. The image is drawn 2.3 R tall\n * so the head fills the circle, so `drawnMarks` reports 1.15 × `height` for a face.\n */\n clip?: \"circle\";\n /** Ring colour per player id (e.g. the team colour; `:183-188`, 1.5 px). Default none. */\n ring?: string | ((id: string) => string);\n /** A disc behind the face at 0.35 opacity, still there if the image fails (`:169-172`). Default none. */\n placeholder?: string | ((id: string) => string);\n}\n\nconst NS = \"http://www.w3.org/2000/svg\";\nconst pick = (c: FaceOptions[\"ring\"], id: string): string | undefined =>\n typeof c === \"function\" ? c(id) : c;\n\n/** Turn `appendHeadshots`' images into circular faces in place. */\nexport function clipFaces<D>(g: Selection<SVGGElement, D, BaseType, unknown>, o: FaceOptions): void {\n if (o.clip !== \"circle\") return;\n for (const img of g.selectAll<SVGImageElement, unknown>(\"image\").nodes()) {\n const doc = img.ownerDocument;\n const id = img.getAttribute(\"data-sdv-id\") ?? \"\";\n const w0 = Number(img.getAttribute(\"width\"));\n const h0 = Number(img.getAttribute(\"height\"));\n const cx = Number(img.getAttribute(\"x\")) + w0 / 2;\n const cy = Number(img.getAttribute(\"y\")) + h0 / 2;\n const r = h0 / 2;\n const h = 2.3 * r; // the head fills the circle: image 2.3 R tall, top 1.05 R above centre (:177-181)\n const w = h0 > 0 ? (h * w0) / h0 : 0;\n img.setAttribute(\"width\", String(w));\n img.setAttribute(\"height\", String(h));\n img.setAttribute(\"x\", String(cx - w / 2));\n img.setAttribute(\"y\", String(cy - 1.05 * r));\n const clipId = contentId(\"sdv-face\", `${id}|${cx}|${cy}|${r}`);\n const clip = doc.createElementNS(NS, \"clipPath\");\n clip.setAttribute(\"id\", clipId);\n const disc = doc.createElementNS(NS, \"circle\");\n disc.setAttribute(\"cx\", String(cx));\n disc.setAttribute(\"cy\", String(cy));\n disc.setAttribute(\"r\", String(r));\n clip.appendChild(disc);\n img.setAttribute(\"clip-path\", `url(#${clipId})`);\n img.before(clip);\n const fill = pick(o.placeholder, id);\n if (fill !== undefined) {\n const ph = disc.cloneNode() as Element;\n ph.setAttribute(\"fill\", fill);\n ph.setAttribute(\"fill-opacity\", \"0.35\");\n img.before(ph);\n }\n const stroke = pick(o.ring, id);\n if (stroke !== undefined) {\n const ring = disc.cloneNode() as Element;\n ring.setAttribute(\"fill\", \"none\");\n ring.setAttribute(\"stroke\", stroke);\n ring.setAttribute(\"stroke-width\", \"1.5\");\n img.after(ring);\n }\n }\n}\n","// d3 twins of the shot-chart marks: blazing-the-nets `main` lib/charts/theme.ts (legend), hexShotChart.ts (size key)\n// and shootingSignature.ts (@31427b8), which are d3 themselves. Never imports ../plot/*.\nimport { type BaseType, type Selection, area, curveBasis, curveMonotoneX, line } from \"d3\";\nimport { type BinShape, cellPath } from \"../bins/index.js\";\nimport { contentId } from \"../content-id.js\";\nimport { InputError } from \"../errors.js\";\nimport { type DiffScale, diffScale } from \"../shots/diff.js\";\nimport { SIGNATURE_NAME, type SignaturePoint, signatureGradient } from \"../shots/signature.js\";\n\n/** Any `<g>` selection, whatever its datum (d3's `Selection` is invariant in it; see `Sel` in ./index.ts). */\ntype G<D> = Selection<SVGGElement, D, BaseType, unknown>;\nconst FONT_PX = 11; // blazing-the-nets main lib/charts/theme.ts:24\nconst CHAR_PX = 6.2; // theme.ts:26\nconst LINE_H = 15; // theme.ts:92\nconst MUTED = \"var(--sdv-muted, currentColor)\"; // main's TOKENS.muted where the page sets it, else the page's ink\n\n/** Signed points from a fraction (blazing-the-nets `main` `lib/format.ts:8`): 0.042 → \"+4.2\", -0.042 → \"−4.2\". */\nconst fmtPts = (v: number): string => `${v >= 0 ? \"+\" : \"−\"}${Math.abs(v * 100).toFixed(1)}`;\n\n/** Greedy word wrap at an estimated 6.2 px per character (theme.ts:77-90): no measuring, so SSR-safe. */\nfunction wrap(text: string, maxWidth: number): string[] {\n const perLine = Math.max(8, Math.floor(maxWidth / CHAR_PX));\n const lines: string[] = [];\n let cur = \"\";\n for (const word of text.split(\" \")) {\n if (cur && cur.length + 1 + word.length > perLine) {\n lines.push(cur);\n cur = word;\n } else cur = cur ? `${cur} ${word}` : word;\n }\n if (cur) lines.push(cur);\n return lines;\n}\n\n/** Options for `appendLegend`. */\nexport interface AppendLegendOptions {\n /** Top-left corner of the legend in px; default (0, 0). */\n x?: number;\n /** See `x`. */\n y?: number;\n /** Space available, which the text wraps to; the bar is at most 240 px (theme.ts:122). */\n width?: number;\n /**\n * Diffs the bar spans; default the scale's end stops. `master`'s legend spanned [-0.30, 0.30]\n * (`ShootingSignature/Legend.js:36-38`): `{ domain: [-0.3, 0.3], ticks: [-0.3, -0.15, 0, 0.15, 0.3] }`.\n */\n domain?: readonly [lo: number, hi: number];\n /** Tick diffs; default the domain's ends, and 0 when it lies inside them. */\n ticks?: readonly number[];\n /** Tick text; default signed points, \"0\" at 0 (theme.ts:140). */\n format?: (d: number) => string;\n /** Caption and key in words (theme.ts:35, :120); `null` for none. */\n caption?: readonly string[] | null;\n /** More lines under the caption, wrapped to `width` (e.g. a shrinkage note). */\n notes?: readonly string[];\n /** A cell size key under the colour key: pixel size per attempt count and the counts (`sizeCells(...).steps`). */\n size?: {\n readonly px: (attempts: number) => number;\n readonly steps: readonly number[];\n /** The key's cell shape; default `\"hex\"`. */\n readonly shape?: BinShape;\n /** Default `\"hex size: attempts\"` or `\"square size: attempts\"`. */\n readonly note?: string;\n };\n}\n\n/**\n * A diff-colour legend for d3 charts: gradient bar, ticks, caption, notes and an optional cell size key\n * (blazing-the-nets `main` `lib/charts/theme.ts:109-143`, `lib/charts/hexShotChart.ts:196-213`). It replaces\n * `master`'s static PNG ramp (`ShootingSignature/Legend.js:45-50`, `rgy5.png`) with a gradient generated from the\n * scale, whose id is a hash of its stops. Nothing is measured (text wraps at an estimated 6.2 px per character), so\n * it renders the same in jsdom and SSR. Returns the height used. Plot users: `Plot.legend({ color: scale.plot })`.\n *\n * @example\n * ```ts\n * import { create } from \"d3\";\n * import { appendLegend } from \"@sportsdataverse/sdvplot/d3\";\n * import { diffScale } from \"@sportsdataverse/sdvplot/shots\";\n *\n * const svg = create(\"svg\").attr(\"viewBox\", \"0 0 300 80\");\n * appendLegend(svg.append(\"g\"), diffScale(), { width: 280 });\n * svg.node();\n * ```\n */\nexport function appendLegend<D>(\n g: G<D>,\n scale: DiffScale = diffScale(),\n o: AppendLegendOptions = {},\n): number {\n const x = o.x ?? 0;\n const y = o.y ?? 0;\n const maxWidth = o.width ?? 240;\n const width = Math.min(maxWidth, 240);\n const [lo, hi] = o.domain ?? [scale.stops[0] ?? 0, scale.stops.at(-1) ?? 0];\n if (!(Number.isFinite(lo) && Number.isFinite(hi) && hi > lo))\n throw new InputError(`appendLegend domain must be finite and run low to high, got [${lo}, ${hi}]`);\n // The domain's ends plus every scale stop inside it: exact for a piecewise-linear scale (master), 5 samples of RdBu.\n const at = [lo, ...scale.stops.filter((d) => d > lo && d < hi), hi];\n const stops = at.map((d) => [((d - lo) / (hi - lo)) * 100, scale(d)] as const);\n const id = contentId(\"sdv-legend\", stops.map((s) => s.join(\" \")).join(\";\"));\n const grad = g.append(\"defs\").append(\"linearGradient\").attr(\"id\", id);\n for (const [offset, colour] of stops)\n grad.append(\"stop\").attr(\"offset\", `${offset}%`).attr(\"stop-color\", colour);\n const format = o.format ?? ((d: number) => (d === 0 ? \"0\" : fmtPts(d)));\n g.append(\"rect\")\n .attr(\"x\", x)\n .attr(\"y\", y)\n .attr(\"width\", width)\n .attr(\"height\", 8)\n .attr(\"rx\", 2)\n .attr(\"aria-label\", `colour key, FG% vs league: ${format(lo)} to ${format(hi)}`)\n .style(\"fill\", `url(#${id})`);\n for (const d of o.ticks ?? (lo < 0 && hi > 0 ? [lo, 0, hi] : [lo, hi])) {\n g.append(\"text\")\n .attr(\"x\", x + ((d - lo) / (hi - lo)) * width)\n .attr(\"y\", y + 8 + FONT_PX + 2)\n .attr(\"text-anchor\", d === lo ? \"start\" : d === hi ? \"end\" : \"middle\")\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(format(d));\n }\n let used = 8 + FONT_PX + 6;\n const caption =\n o.caption === undefined\n ? [\"FG% vs league (points)\", \"red: above league · blue: below\"]\n : (o.caption ?? []);\n const lines = [...caption, ...(o.notes ?? [])].flatMap((n) => wrap(n, maxWidth));\n lines.forEach((t, i) => {\n g.append(\"text\")\n .attr(\"x\", x)\n .attr(\"y\", y + used + FONT_PX + i * LINE_H)\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(t);\n });\n used += lines.length * LINE_H;\n const size = o.size;\n if (size) {\n const shape = size.shape ?? \"hex\";\n const key = g.append(\"g\").attr(\"transform\", `translate(${x},${y + used + 8})`);\n size.steps.forEach((n, i) => {\n const cx = 12 + i * 34;\n key\n .append(\"path\")\n .attr(\"transform\", `translate(${cx},10)`)\n .attr(\"d\", cellPath(shape, size.px(n)))\n .style(\"fill\", MUTED);\n key\n .append(\"text\")\n .attr(\"x\", cx)\n .attr(\"y\", 36)\n .attr(\"text-anchor\", \"middle\")\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(i === size.steps.length - 1 ? `${n}+` : String(n));\n });\n // main's drawNotes(key, 118, 4, width - 24 - 118, …) (hexShotChart.ts:212): wrapped, 8 characters a line at the least\n const note = wrap(size.note ?? `${shape} size: attempts`, maxWidth - 118);\n note.forEach((t, i) => {\n key\n .append(\"text\")\n .attr(\"x\", 118)\n .attr(\"y\", 4 + FONT_PX + i * LINE_H)\n .style(\"font-size\", `${FONT_PX}px`)\n .style(\"fill\", MUTED)\n .text(t);\n });\n used += 8 + Math.max(42, 8 + note.length * LINE_H);\n }\n return used;\n}\n\n/** Options for `appendSignature`. */\nexport interface AppendSignatureOptions {\n /** The caller's scale from distance (ft) to px. */\n x: (distance: number) => number;\n /** The caller's scale from FG% (0-1) to px; a clamped scale clamps the ribbon's centre. */\n y: (fgPct: number) => number;\n /** Colour of `colourDiff`; default `diffScale()`. */\n fill?: DiffScale;\n /** `\"monotone-x\"` (default, `main`) or `\"basis\"` (`master` `ShootingSignature/index.js:96`). */\n curve?: \"monotone-x\" | \"basis\";\n /** Ribbon half-width in PIXELS; default `main`'s `max(share / maxShare * 20, 0.75)` (`shootingSignature.ts:131-132`). */\n halfWidth?: (p: SignaturePoint, maxShare: number) => number;\n /** The dashed league line, faint everywhere and full strength under the ribbon (`:165-181`); default true. */\n league?: boolean;\n}\n\n/**\n * The d3 twin of `sdvplot/plot`'s `shootingSignature`: the dashed league line and the ribbon along FG% by distance,\n * as wide as the shot share and coloured along x by the shrunk FG% vs league (blazing-the-nets `main`\n * `lib/charts/shootingSignature.ts:165-211`). The same points give the Plot mark's ribbon and league paths, gradient\n * stops and gradient id when the scales match (with a 190 px [0, 1] y axis for the default half-width). A null\n * `fgPct` is a gap. The gradient id hashes its stops and its pixel x range, so two signatures on a page, or one at\n * two widths, never share one. y goes through the caller's `y` as it is: the ribbon's edges are\n * `y(fgPct) ± halfWidth`, and a clamped scale clamps the centre (as `main` does). Returns the `<g>` it appended.\n *\n * @example\n * ```ts\n * import { create, scaleLinear } from \"d3\";\n * import { appendSignature } from \"@sportsdataverse/sdvplot/d3\";\n * import { fgPctByDistance, signaturePoints, vsLeague } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const shots = [\n * { x_legacy: -1, y_legacy: 7, shot_distance: 1, shot_value: 2, shot_result: \"Made\" },\n * { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Missed\" },\n * { x_legacy: -44, y_legacy: 252, shot_distance: 26, shot_value: 3, shot_result: \"Made\" },\n * ];\n * // the makes against all three attempts, which stand in for the league (the gallery's uses the 2025-26 league)\n * const made = fgPctByDistance(shots.filter((s) => s.shot_result === \"Made\"));\n * const points = signaturePoints(vsLeague(made, fgPctByDistance(shots)), { minAttempts: 1 });\n * const svg = create(\"svg\").attr(\"viewBox\", \"0 0 400 200\");\n * appendSignature(svg.append(\"g\"), points, { x: scaleLinear([0, 35], [0, 400]), y: scaleLinear([0, 1], [200, 0]) });\n * svg.node();\n * ```\n */\nexport function appendSignature<D>(\n sel: G<D>,\n points: readonly SignaturePoint[],\n o: AppendSignatureOptions,\n): G<D> {\n const curve = (o.curve ?? \"monotone-x\") === \"basis\" ? curveBasis : curveMonotoneX;\n const { maxShare, maxFt, stops, id: gradientId } = signatureGradient(points, o.fill ?? diffScale());\n const half = o.halfWidth ?? ((p: SignaturePoint, m: number) => Math.max((p.share / m) * 20, 0.75));\n const g = sel.append(\"g\").attr(\"class\", \"sdv-signature\");\n if (o.league ?? true) {\n for (const strong of [false, true]) {\n const l = line<SignaturePoint>()\n .defined((p) => p.leagueFgPct !== null && (!strong || p.fgPct !== null))\n .x((p) => o.x(p.distance))\n .y((p) => o.y(p.leagueFgPct ?? 0))\n .curve(curve);\n g.append(\"path\")\n .attr(\"d\", l([...points]) ?? \"\")\n .style(\"fill\", \"none\")\n .style(\"stroke\", MUTED)\n .style(\"stroke-opacity\", strong ? 1 : 0.4)\n .style(\"stroke-dasharray\", \"3 3\");\n }\n }\n const [x1, x2] = [String(o.x(0)), String(o.x(maxFt))];\n const id = gradientId(x1, x2);\n const grad = g\n .append(\"defs\")\n .append(\"linearGradient\")\n .attr(\"id\", id)\n .attr(\"gradientUnits\", \"userSpaceOnUse\")\n .attr(\"x1\", x1)\n .attr(\"x2\", x2)\n .attr(\"y1\", \"0\")\n .attr(\"y2\", \"0\");\n for (const [offset, colour] of stops)\n grad.append(\"stop\").attr(\"offset\", `${offset}%`).attr(\"stop-color\", colour);\n const ribbon = area<SignaturePoint>()\n .defined((p) => p.fgPct !== null)\n .x((p) => o.x(p.distance))\n .y0((p) => o.y(p.fgPct ?? 0) + half(p, maxShare))\n .y1((p) => o.y(p.fgPct ?? 0) - half(p, maxShare))\n .curve(curve);\n g.append(\"path\")\n .attr(\"d\", ribbon([...points]) ?? \"\")\n .attr(\"aria-label\", SIGNATURE_NAME)\n .style(\"fill\", `url(#${id})`)\n .style(\"stroke\", \"currentColor\")\n .style(\"stroke-opacity\", 0.2)\n .style(\"stroke-width\", 0.5);\n return g;\n}\n","import { appendSurface as sportyAppendSurface } from \"@sportsdataverse/sporty/d3\";\nimport { type BaseType, type ScaleOrdinal, type Selection, scaleOrdinal } from \"d3\";\nimport { InputError } from \"../errors.js\";\nimport type { EspnHeadshotLeague } from \"../headshots.js\";\nimport { type Kind, checkAlpha, checkHeight, placeSync, placedName } from \"../placement.js\";\nimport type { Value } from \"../resolve.js\";\nimport { stampImage } from \"../stamp.js\";\nimport { type SurfaceSceneOptions, surfaceScene } from \"../surfaces.js\";\nimport { teamColorDomain } from \"../team-color-domain.js\";\nimport type { HeadshotIdSystem, IdSystem, League, SeasonInput, Variant, Which } from \"../types.js\";\nimport { type FaceOptions, clipFaces } from \"./faces.js\";\n\n/**\n * A selection of `G` with any datum `D` and any parent. d3's `Selection` is invariant in its datum, so a helper typed\n * with `unknown` would reject `create(\"svg\").append(\"g\")` (datum `undefined`) and every bound datum.\n */\ntype Sel<G extends Element, D> = Selection<G, D, BaseType, unknown>;\n/** Where d3 draws: the caller's scales, plus the pixel height the `height` fraction refers to (d3 has no figure). */\ninterface Frame {\n x: (v: Value) => number;\n y: (v: Value) => number;\n frameHeight: number;\n height?: number;\n alpha?: number;\n /**\n * Each image's accessible name from its input value and index; default the team (\"KC logo\", whatever id system the\n * values use) or the player id (\"3139477 headshot\").\n */\n ariaLabel?: (value: Value, i: number) => string;\n}\nexport interface D3MarkOptions extends Frame {\n league: League;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n}\nexport interface D3HeadshotOptions extends Frame, FaceOptions {\n league: EspnHeadshotLeague;\n /** \"espn\" (default) or \"gsis\". \"gsis\" needs `loadGsis()` to have run first, else this throws InputError. */\n idSystem?: HeadshotIdSystem;\n}\n\nfunction draw<G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n ids: readonly Value[],\n o: Frame,\n kind: Kind,\n place: Parameters<typeof placeSync>[3],\n): Sel<SVGGElement, D> {\n const h = checkHeight(o.height ?? 0.1);\n const alpha = checkAlpha(o.alpha ?? 1);\n if (!(Number.isFinite(o.frameHeight) && o.frameHeight > 0)) {\n throw new InputError(`frameHeight is the plot height in px, got ${String(o.frameHeight)}`);\n }\n const px = h * o.frameHeight;\n const placed = placeSync(Array.from(xs), Array.from(ys), ids, place);\n const g = sel.append(\"g\").attr(\"class\", `sdv-${kind}s`).attr(\"opacity\", alpha);\n for (const p of placed) {\n const img = g.append(\"image\").attr(\"href\", p.url).attr(\"preserveAspectRatio\", \"xMidYMid meet\");\n const node = img.node();\n if (node === null) continue;\n stampImage(node, p, kind, px, o.frameHeight, o.x(p.x), o.y(p.y));\n img.attr(\"data-sdv-x\", String(p.x)).attr(\"data-sdv-y\", String(p.y));\n const raw = ids[p.index] as Value;\n img.attr(\"aria-label\", o.ariaLabel?.(raw, p.index) ?? `${placedName(p, place.league, raw)} ${kind}`);\n }\n return g;\n}\nexport type AppendTeamMarks = <G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n teams: readonly Value[],\n o: D3MarkOptions,\n) => Sel<SVGGElement, D>;\nconst teamMark =\n (kind: \"logo\" | \"wordmark\"): AppendTeamMarks =>\n (sel, xs, ys, teams, o) =>\n draw(sel, xs, ys, teams, o, kind, {\n league: o.league,\n kind,\n variant: o.variant ?? \"default\",\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n ...(o.season === undefined ? {} : { season: o.season }),\n });\n/**\n * Append `<g class=\"sdv-logos\">` of team logos at (x, y) through the caller's scale functions. Needs\n * `loadLeague(league)` first.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { appendLogos } from \"@sportsdataverse/sdvplot/d3\";\n * import * as d3 from \"d3\";\n *\n * await loadLeague(\"nfl\");\n * const x = d3.scaleLinear([250, 550], [0, 480]);\n * const y = d3.scaleLinear([280, 420], [240, 0]);\n * const svg = d3.select(document.createElement(\"div\")).append(\"svg\").attr(\"viewBox\", [0, 0, 480, 240]);\n * appendLogos(svg, [385, 525, 425], [326, 368, 311], [\"KC\", \"BUF\", \"DEN\"], {\n * league: \"nfl\",\n * x: (v) => x(Number(v)),\n * y: (v) => y(Number(v)),\n * frameHeight: 240,\n * height: 0.2,\n * });\n * svg.node();\n * ```\n */\nexport const appendLogos: AppendTeamMarks = teamMark(\"logo\");\n/** As `appendLogos`, with wordmarks. */\nexport const appendWordmarks: AppendTeamMarks = teamMark(\"wordmark\");\n/**\n * Append `<g class=\"sdv-headshots\">` of ESPN player headshots; `idSystem: \"gsis\"` needs `loadGsis()` first.\n * `clip: \"circle\"` makes circular faces (`height` is then the circle's diameter), with an optional `ring` and `placeholder`.\n *\n * @example\n * ```ts\n * import { appendHeadshots } from \"@sportsdataverse/sdvplot/d3\";\n * import * as d3 from \"d3\";\n *\n * const x = d3.scaleLinear([0, 10], [0, 480]);\n * const y = d3.scaleLinear([0, 10], [240, 0]);\n * const svg = d3.select(document.createElement(\"div\")).append(\"svg\").attr(\"viewBox\", [0, 0, 480, 240]);\n * const team: Record<string, string> = { \"3139477\": \"#e31837\", \"4374302\": \"#0076b6\", \"4429160\": \"#008e97\" };\n * appendHeadshots(svg, [2, 5, 8], [4, 6, 3], [\"3139477\", \"4374302\", \"4429160\"], {\n * league: \"nfl\",\n * x: (v) => x(Number(v)),\n * y: (v) => y(Number(v)),\n * frameHeight: 240,\n * height: 0.25,\n * clip: \"circle\",\n * ring: (id) => team[id] ?? \"grey\",\n * placeholder: (id) => team[id] ?? \"grey\",\n * });\n * svg.node();\n * ```\n */\nexport function appendHeadshots<G extends SVGElement, D>(\n sel: Sel<G, D>,\n xs: ArrayLike<Value>,\n ys: ArrayLike<Value>,\n players: readonly Value[],\n o: D3HeadshotOptions,\n): Sel<SVGGElement, D> {\n const g = draw(sel, xs, ys, players, o, \"headshot\", {\n league: o.league,\n kind: \"headshot\",\n idSystem: o.idSystem ?? \"espn\",\n });\n clipFaces(g, o);\n return g;\n}\n\n/**\n * A d3 ordinal scale from team (id or abbr) to team colour; anything unresolved maps to `naValue` (default \"grey\").\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorScale } from \"@sportsdataverse/sdvplot/d3\";\n *\n * await loadLeague(\"nba\");\n * const color = teamColorScale(\"nba\", { values: [\"LAL\", \"BOS\"] });\n * [\"LAL\", \"BOS\", \"not a team\"].map(color);\n * ```\n */\nexport function teamColorScale(\n league: League,\n o: {\n which?: Which;\n season?: SeasonInput;\n idSystem?: IdSystem;\n naValue?: string;\n values?: readonly Value[];\n } = {},\n): ScaleOrdinal<string, string, string> {\n const na = o.naValue ?? \"grey\";\n const { domain, colors } = teamColorDomain(league, o);\n return scaleOrdinal<string, string>()\n .domain(domain)\n .range(colors.map((c) => c ?? na))\n .unknown(na);\n}\n\nexport interface D3SurfaceOptions extends SurfaceSceneOptions {\n x: (v: number) => number;\n y: (v: number) => number;\n /** Describes the surface for assistive technology; default sporty's (\"nba basketball surface\" and so on). */\n ariaDescription?: string;\n}\n/** Paint a surface key's surface (in `team`'s colours) into `sel` through the caller's x/y scales. Throws InputError for a key with no surface (see `SURFACES`). */\nexport function appendSurface<G extends SVGGElement | SVGSVGElement, D>(\n sel: Sel<G, D>,\n league: League | (string & {}),\n o: D3SurfaceOptions,\n): Sel<SVGGElement, D> {\n const { x, y, ariaDescription, ...scene } = o;\n return sportyAppendSurface(\n sel,\n surfaceScene(league, scene),\n x,\n y,\n ariaDescription === undefined ? {} : { ariaDescription },\n );\n}\nexport { appendLegend, appendSignature } from \"./shots.js\";\nexport type { AppendLegendOptions, AppendSignatureOptions } from \"./shots.js\";\nexport type { FaceOptions } from \"./faces.js\";\n"]}
@@ -0,0 +1,232 @@
1
+ import { Sport, OptionsOf, LeagueOf } from '@sportsdataverse/sporty';
2
+ import { R as Row } from './_web-D7Aa5Rd8.js';
3
+ import { L as League, S as SeasonInput, V as Variant, I as IdSystem, W as Which } from './types-C7n6gJF3.js';
4
+
5
+ /** A deck.gl colour: `[r, g, b, a]`, each 0-255. */
6
+ type Rgba = [r: number, g: number, b: number, a: number];
7
+ /** An icon deck.gl fetches and packs into its atlas itself (an "auto-packed" icon), keyed by its URL. */
8
+ interface LogoIcon {
9
+ url: string;
10
+ /** The icon's size in the atlas, px: 128 tall, as wide as the logo's aspect makes it. */
11
+ width: number;
12
+ height: number;
13
+ /** Half the height: the logo is centred on its point. */
14
+ anchorY: number;
15
+ mask: false;
16
+ }
17
+ /** One `logoIconLayer` data row. `index` is the row's position in the input (left-out rows leave gaps). */
18
+ interface IconRow {
19
+ position: [x: number, y: number];
20
+ icon: LogoIcon;
21
+ /** The resolved team id. */
22
+ team: string;
23
+ index: number;
24
+ }
25
+ /**
26
+ * One `passArcLayer` data row. `team` is the resolved team id, or the row's own value as text when it does not
27
+ * resolve (a number without ".0", a missing value empty).
28
+ */
29
+ interface ArcRow {
30
+ source: [x: number, y: number];
31
+ target: [x: number, y: number];
32
+ sourceColor: Rgba;
33
+ targetColor: Rgba;
34
+ team: string;
35
+ index: number;
36
+ }
37
+ /** One `surfaceLayer` data row: a closed loop of a sporty polygon feature. */
38
+ interface SurfaceRow {
39
+ name: string;
40
+ /** One closed loop of the feature's path (deck.gl closes it). */
41
+ polygon: (readonly [x: number, y: number])[];
42
+ fillColor: Rgba;
43
+ }
44
+ /** `logoIconLayer`'s props, for deck.gl's `IconLayer`. */
45
+ interface LogoIconLayerProps {
46
+ id: string;
47
+ data: IconRow[];
48
+ getPosition: (d: IconRow) => [number, number];
49
+ getIcon: (d: IconRow) => LogoIcon;
50
+ getSize: number;
51
+ sizeUnits: "pixels";
52
+ opacity: number;
53
+ }
54
+ /** `passArcLayer`'s props, for deck.gl's `ArcLayer`. */
55
+ interface PassArcLayerProps {
56
+ id: string;
57
+ data: ArcRow[];
58
+ getSourcePosition: (d: ArcRow) => [number, number];
59
+ getTargetPosition: (d: ArcRow) => [number, number];
60
+ getSourceColor: (d: ArcRow) => Rgba;
61
+ getTargetColor: (d: ArcRow) => Rgba;
62
+ getWidth: number;
63
+ widthUnits: "pixels";
64
+ opacity: number;
65
+ getHeight?: number;
66
+ getTilt?: number;
67
+ }
68
+ /** `surfaceLayer`'s props, for deck.gl's `PolygonLayer`. */
69
+ interface SurfaceLayerProps {
70
+ id: string;
71
+ data: SurfaceRow[];
72
+ getPolygon: (d: SurfaceRow) => SurfaceRow["polygon"];
73
+ getFillColor: (d: SurfaceRow) => Rgba;
74
+ coordinateSystem: "cartesian";
75
+ filled: true;
76
+ stroked: false;
77
+ }
78
+ /** `logoIconLayer` options. */
79
+ interface LogoIconOptions {
80
+ /** Name of the row column holding each logo's x position (a longitude on a map, or a surface's own x). */
81
+ x: string;
82
+ /** Name of the row column holding each logo's y position. */
83
+ y: string;
84
+ /** Name of the row column holding the team (abbreviation, name or id; see `idSystem`). */
85
+ team: string;
86
+ /** The league the teams belong to, e.g. "nhl". */
87
+ league: League;
88
+ /** A season (number or string) for every row, or the name of a row column holding each row's season. */
89
+ season?: SeasonInput;
90
+ /** Logo variant, e.g. "dark". Default "default". */
91
+ variant?: Variant;
92
+ /** How the `team` values are read. Default "auto". */
93
+ idSystem?: IdSystem;
94
+ /** The logo's height on screen in px, 1 or more (deck.gl's `getSize` in "pixels" units). Default 32. */
95
+ size?: number;
96
+ /** The layer's opacity in [0, 1]. Default 1. */
97
+ alpha?: number;
98
+ /** The layer id. Default "sdvplot-logos". */
99
+ id?: string;
100
+ }
101
+ /** `passArcLayer` options. */
102
+ interface PassArcOptions {
103
+ /** Name of the row column holding each arc's source x. */
104
+ x: string;
105
+ /** Name of the row column holding each arc's source y. */
106
+ y: string;
107
+ /** Name of the row column holding each arc's target x. */
108
+ xend: string;
109
+ /** Name of the row column holding each arc's target y. */
110
+ yend: string;
111
+ /** Name of the row column holding the team the arc is coloured by. */
112
+ team: string;
113
+ /** The league the teams belong to, e.g. "soccer". */
114
+ league: League;
115
+ /** The season the teams are resolved for. */
116
+ season?: SeasonInput;
117
+ /** How the `team` values are read. Default "auto". */
118
+ idSystem?: IdSystem;
119
+ /** The colour at the source end, "primary" (default) or "secondary"; the target end takes the other. */
120
+ which?: Which;
121
+ /**
122
+ * The background the arcs are drawn on. Given, each end's colour keeps 3:1 contrast against it (dark mode) and
123
+ * aims to stay distinct (CIE76 ΔE of 20 or more) from every other team's colour at that end, through the shared team
124
+ * palette, as `teamColorPalette` does in the other adapters. Caveat: a colour that does not read gives way to the
125
+ * team's other colour, so when only one of a team's two colours reads on the background, both ends take it and the
126
+ * arcs no longer show their direction (France's navy and mint on a dark pitch are both mint). Pick a background on
127
+ * which both colours read (France's both read on a mid-tone green such as `#4a7f3a`), or check that
128
+ * `sourceColor` and `targetColor` differ.
129
+ */
130
+ background?: string;
131
+ /** The colour of a team that does not resolve, or has no colour. Default "#808080". */
132
+ fallback?: string;
133
+ /** The arc's width in px, 1 or more. Default 2. */
134
+ width?: number;
135
+ /** The layer's opacity in [0, 1]. Default 1. */
136
+ alpha?: number;
137
+ /**
138
+ * deck.gl's `getHeight`, how high each arc rises for its length, 0 or more (0 draws a straight line). Default none:
139
+ * deck.gl's 1. Lower, such as 0.3, keeps arcs laid flat (`tilt: 90`) close to their chord, inside the surface.
140
+ */
141
+ height?: number;
142
+ /**
143
+ * deck.gl's `getTilt`, degrees in [-90, 90]: 90 lays each arc flat on the surface, so a top-down 2D view (an
144
+ * OrthographicView) shows the curve. Default none: deck.gl's upright arcs, for a pitched 3D view.
145
+ */
146
+ tilt?: number;
147
+ /** The layer id. Default "sdvplot-arcs". */
148
+ id?: string;
149
+ }
150
+ /** `surfaceLayer` options: sporty's own `surface()` options for the sport, plus the layer id. */
151
+ type SurfaceLayerOptions<S extends Sport> = OptionsOf<S> & {
152
+ /** The layer id. Default "sdvplot-surface". */
153
+ id?: string;
154
+ };
155
+ /**
156
+ * deck.gl `IconLayer` props drawing each row's team logo at its (x, y). The logos are auto-packed icons: deck.gl
157
+ * fetches each URL once and packs it into its own atlas, at 128 px tall and the logo's aspect, centred on the point.
158
+ * A team with no logo (or one that does not resolve) is left out with one warning, as the other adapters do; so is a
159
+ * row with a missing x or y. `x` and `y` are in the layer's coordinates: longitude and latitude on a map, or a
160
+ * surface's own units on `surfaceLayer` (set `coordinateSystem: "cartesian"` on both, or use a non-geographic view).
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
165
+ * import { logoIconLayer } from "@sportsdataverse/sdvplot/deckgl";
166
+ *
167
+ * await loadLeague("nhl");
168
+ * // Edmonton's first shot of game 7 of the 2024 Stanley Cup Final (NHL api-web), in feet from centre ice
169
+ * const shot = { team: "EDM", x: 82, y: -3 };
170
+ * const props = logoIconLayer([shot], { x: "x", y: "y", team: "team", league: "nhl", size: 28 });
171
+ * // in the browser: new IconLayer({ ...props, coordinateSystem: "cartesian" })
172
+ * props.data[0]?.icon.url;
173
+ * ```
174
+ */
175
+ declare function logoIconLayer(rows: readonly Row[], o: LogoIconOptions): LogoIconLayerProps;
176
+ /**
177
+ * deck.gl `ArcLayer` props: one arc per row from (x, y) to (xend, yend), in the team's colours: its primary colour at
178
+ * the source and its secondary at the target (`which: "secondary"` swaps them), so the two ends tell the direction
179
+ * apart where the two colours differ (see `background`). Each team keeps one colour per end, the teams taken in the
180
+ * order they first appear. With `background`, every colour keeps 3:1 contrast against it and aims to stay distinct from
181
+ * the other teams' (the shared team palette; when it cannot, it keeps the readable colour and warns once). A team that
182
+ * does not resolve takes `fallback`, as given (its contrast is not checked); a row with a missing
183
+ * coordinate is left out with one warning.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
188
+ * import { passArcLayer } from "@sportsdataverse/sdvplot/deckgl";
189
+ *
190
+ * await loadLeague("soccer");
191
+ * // France's first completed pass of the 2018 World Cup final (StatsBomb open data through SPADL, metres from the
192
+ * // corner); France is ESPN soccer team 478
193
+ * const pass = { team: "478", start_x: 54.68750000000001, start_y: 6.375, end_x: 56.4375, end_y: 1.2750000000000057 };
194
+ * const props = passArcLayer([pass], {
195
+ * x: "start_x",
196
+ * y: "start_y",
197
+ * xend: "end_x",
198
+ * yend: "end_y",
199
+ * team: "team",
200
+ * league: "soccer",
201
+ * idSystem: "team_id",
202
+ * tilt: 90,
203
+ * });
204
+ * // in the browser: new ArcLayer({ ...props, coordinateSystem: "cartesian" })
205
+ * props.data[0]?.sourceColor;
206
+ * ```
207
+ */
208
+ declare function passArcLayer(rows: readonly Row[], o: PassArcOptions): PassArcLayerProps;
209
+ /**
210
+ * deck.gl `PolygonLayer` props drawing sporty's playing surface for `sport` and `league` (sporty's own league keys,
211
+ * e.g. `surfaceLayer("hockey", "nhl")`, `surfaceLayer("soccer", "fifa")`), in the surface's own coordinates: deck.gl's
212
+ * `"cartesian"` coordinate system, in the surface's units (feet for a rink, metres for a pitch) with the origin at its
213
+ * centre, the frame sporty draws in and NHL api-web's shot coordinates are in. Each closed loop of a polygon feature
214
+ * is one data row (a faceoff circle is two: its half rings; a loop that crosses itself is split at the crossing into
215
+ * rings that do not, and a loop with no area is left out), in sporty's drawing order, filled with its colour (alpha
216
+ * included). sporty's default strokes equal their fills, so
217
+ * the layer is fill-only; a hidden feature (a `#rrggbb00` fill) and text features (a football field's yard numbers)
218
+ * are left out. `o` is passed to sporty's `surface()` (`updates`, `colorUpdates`, `units`, `rotation`, ...); sporty's
219
+ * own errors escape unwrapped. Draw it with deck.gl's OrthographicView.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * import { surfaceLayer } from "@sportsdataverse/sdvplot/deckgl";
224
+ *
225
+ * const rink = surfaceLayer("hockey", "nhl");
226
+ * // in the browser: new PolygonLayer(rink), in a Deck with views: new OrthographicView({ flipY: false })
227
+ * rink.data.length;
228
+ * ```
229
+ */
230
+ declare function surfaceLayer<S extends Sport>(sport: S, league: LeagueOf<S>, o?: SurfaceLayerOptions<S>): SurfaceLayerProps;
231
+
232
+ export { type ArcRow, type IconRow, type LogoIcon, type LogoIconLayerProps, type LogoIconOptions, type PassArcLayerProps, type PassArcOptions, type Rgba, Row, type SurfaceLayerOptions, type SurfaceLayerProps, type SurfaceRow, logoIconLayer, passArcLayer, surfaceLayer };
package/dist/deckgl.js ADDED
@@ -0,0 +1,197 @@
1
+ import { markPlacements, aspect, column, colorList, teamPalette } from './chunk-UL5M6KDE.js';
2
+ import { checkAlpha } from './chunk-7ULOCCFL.js';
3
+ import { resolveSync, normValue } from './chunk-ZAEQXFJM.js';
4
+ import { hex6 } from './chunk-J6R2LEJ7.js';
5
+ import { InputError, warn } from './chunk-E7G7VSLV.js';
6
+ import { surface } from '@sportsdataverse/sporty';
7
+
8
+ var ICON_PX = 128;
9
+ var real = (v) => typeof v === "number" && Number.isFinite(v);
10
+ function checkPx(name, v) {
11
+ if (!real(v) || v < 1) throw new InputError(`${name} is in px, 1 or more, got ${String(v)}`);
12
+ return v;
13
+ }
14
+ function alphaOf(color) {
15
+ let c = String(color).trim().replace(/^#+/, "");
16
+ if (c.length === 4) c = [...c].map((ch) => ch + ch).join("");
17
+ return c.length === 8 ? Number.parseInt(c.slice(6), 16) : 255;
18
+ }
19
+ function rgba(color) {
20
+ const a = alphaOf(color);
21
+ const [r, g, b] = [1, 3, 5].map(
22
+ (i) => Number.parseInt(hex6(color, { dropAlpha: true }).slice(i, i + 2), 16)
23
+ );
24
+ return [r, g, b, a];
25
+ }
26
+ function logoIconLayer(rows, o) {
27
+ const size = checkPx("size", o.size ?? 32);
28
+ const opacity = checkAlpha(o.alpha ?? 1);
29
+ const data = markPlacements(rows, "logo", o).map((p) => {
30
+ const height = ICON_PX;
31
+ return {
32
+ position: [Number(p.x), Number(p.y)],
33
+ icon: { url: p.url, width: Math.round(ICON_PX * aspect(p)), height, anchorY: height / 2, mask: false },
34
+ team: p.id,
35
+ index: p.index
36
+ };
37
+ });
38
+ return {
39
+ id: o.id ?? "sdvplot-logos",
40
+ data,
41
+ getPosition: (d) => d.position,
42
+ getIcon: (d) => d.icon,
43
+ getSize: size,
44
+ sizeUnits: "pixels",
45
+ opacity
46
+ };
47
+ }
48
+ var label = (t) => t === null || t === void 0 ? "" : typeof t === "number" ? normValue(t) ?? "" : String(t);
49
+ function endColors(ids, o, which) {
50
+ const fallback = hex6(o.fallback ?? "#808080");
51
+ const co = { idSystem: "team_id", ...o.season === void 0 ? {} : { season: o.season } };
52
+ const known = ids.filter((id) => id !== null);
53
+ const main = colorList(o.league, known, { ...co, which });
54
+ const other = colorList(o.league, known, { ...co, which: which === "primary" ? "secondary" : "primary" });
55
+ let colors = main.map((c, i) => hex6(c ?? other[i] ?? fallback, { dropAlpha: true }));
56
+ if (o.background !== void 0) colors = teamPalette(colors, other, hex6(o.background), known);
57
+ let k = 0;
58
+ return ids.map((id) => id === null ? fallback : colors[k++]);
59
+ }
60
+ function passArcLayer(rows, o) {
61
+ const width = checkPx("width", o.width ?? 2);
62
+ const opacity = checkAlpha(o.alpha ?? 1);
63
+ if (o.tilt !== void 0 && !(real(o.tilt) && o.tilt >= -90 && o.tilt <= 90))
64
+ throw new InputError(`tilt is in degrees, in [-90, 90], got ${String(o.tilt)}`);
65
+ if (o.height !== void 0 && !(real(o.height) && o.height >= 0))
66
+ throw new InputError(`height is an arc's height multiplier, 0 or more, got ${String(o.height)}`);
67
+ const cols = [o.x, o.y, o.xend, o.yend].map(
68
+ (c, k) => column(rows, c, ["x", "y", "xend", "yend"][k])
69
+ );
70
+ const teams = column(rows, o.team, "team");
71
+ const keep = [];
72
+ const missing = [];
73
+ rows.forEach((_, i) => {
74
+ if (cols.every((c) => real(c[i]))) keep.push(i);
75
+ else missing.push(teams[i]);
76
+ });
77
+ if (missing.length > 0) {
78
+ const shown = missing.slice(0, 10).map(String).join(", ") + (missing.length > 10 ? ` and ${missing.length - 10} more` : "");
79
+ warn(
80
+ `deckgl:arcs:${o.league}:missing:${shown}`,
81
+ `skipped ${missing.length} arc(s) with a missing coordinate: ${shown}`
82
+ );
83
+ }
84
+ const ro = {
85
+ ...o.season === void 0 ? {} : { season: o.season },
86
+ ...o.idSystem === void 0 ? {} : { idSystem: o.idSystem }
87
+ };
88
+ const kept = keep.map((i) => teams[i]);
89
+ const resolved = resolveSync(kept, o.league, ro);
90
+ const keys = kept.map((t, j) => resolved[j] ?? `?${label(t)}`);
91
+ const distinct = [...new Set(keys)];
92
+ const ids = distinct.map((k) => k.startsWith("?") ? null : k);
93
+ const which = o.which ?? "primary";
94
+ const src = endColors(ids, o, which);
95
+ const tgt = endColors(ids, o, which === "primary" ? "secondary" : "primary");
96
+ const at = new Map(distinct.map((k, j) => [k, j]));
97
+ const data = keep.map((i, j) => {
98
+ const k = at.get(keys[j]);
99
+ return {
100
+ source: [cols[0]?.[i], cols[1]?.[i]],
101
+ target: [cols[2]?.[i], cols[3]?.[i]],
102
+ sourceColor: rgba(src[k]),
103
+ targetColor: rgba(tgt[k]),
104
+ team: resolved[j] ?? label(kept[j]),
105
+ index: i
106
+ };
107
+ });
108
+ return {
109
+ id: o.id ?? "sdvplot-arcs",
110
+ data,
111
+ getSourcePosition: (d) => d.source,
112
+ getTargetPosition: (d) => d.target,
113
+ getSourceColor: (d) => d.sourceColor,
114
+ getTargetColor: (d) => d.targetColor,
115
+ getWidth: width,
116
+ widthUnits: "pixels",
117
+ opacity,
118
+ ...o.height === void 0 ? {} : { getHeight: o.height },
119
+ ...o.tilt === void 0 ? {} : { getTilt: o.tilt }
120
+ };
121
+ }
122
+ function loops(points) {
123
+ const out = [];
124
+ let loop = [];
125
+ let away = 0;
126
+ for (const p of points) {
127
+ const first = loop[0];
128
+ loop.push(p);
129
+ if (first === void 0) continue;
130
+ if (p[0] !== first[0] || p[1] !== first[1]) away++;
131
+ else if (away >= 2) {
132
+ out.push(loop);
133
+ loop = [];
134
+ away = 0;
135
+ }
136
+ }
137
+ if (away >= 2) out.push(loop);
138
+ return out;
139
+ }
140
+ var turn = (a, b, c) => (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
141
+ function signedArea(r) {
142
+ let s = 0;
143
+ for (let i = 0; i < r.length; i++) {
144
+ const [a, b] = [r[i], r[(i + 1) % r.length]];
145
+ s += a[0] * b[1] - b[0] * a[1];
146
+ }
147
+ return s / 2;
148
+ }
149
+ function empty(r) {
150
+ let [x0, y0, x1, y1] = [
151
+ Number.POSITIVE_INFINITY,
152
+ Number.POSITIVE_INFINITY,
153
+ Number.NEGATIVE_INFINITY,
154
+ Number.NEGATIVE_INFINITY
155
+ ];
156
+ for (const [x, y] of r)
157
+ [x0, y0, x1, y1] = [Math.min(x0, x), Math.min(y0, y), Math.max(x1, x), Math.max(y1, y)];
158
+ return r.length < 3 || Math.abs(signedArea(r)) <= 1e-9 * ((x1 - x0) ** 2 + (y1 - y0) ** 2);
159
+ }
160
+ function simple(r) {
161
+ const n = r.length;
162
+ const side = (a, b, c) => Math.sign(turn(a, b, c));
163
+ for (let i = 0; i < n; i++)
164
+ for (let j = i + 2; j < n; j++) {
165
+ if (i === 0 && j === n - 1) continue;
166
+ const [a, b, c, d] = [r[i], r[(i + 1) % n], r[j], r[(j + 1) % n]];
167
+ if (side(a, b, c) * side(a, b, d) >= 0 || side(c, d, a) * side(c, d, b) >= 0) continue;
168
+ const s = turn(c, d, a) / (turn(c, d, a) - turn(c, d, b));
169
+ const x = [a[0] + s * (b[0] - a[0]), a[1] + s * (b[1] - a[1])];
170
+ return [
171
+ ...simple([...r.slice(0, i + 1), x, ...r.slice(j + 1)]),
172
+ ...simple([x, ...r.slice(i + 1, j + 1)])
173
+ ];
174
+ }
175
+ return [[...r]];
176
+ }
177
+ var drawn = (f) => f.points.length > 0 && f.points.every(([x, y]) => Number.isFinite(x) && Number.isFinite(y)) && alphaOf(f.fill) !== 0;
178
+ function surfaceLayer(sport, league, o = {}) {
179
+ const { id = "sdvplot-surface", ...opts } = o;
180
+ const scene = surface(sport, league, opts);
181
+ const data = scene.features.filter((f) => f.kind === "polygon" && drawn(f)).flatMap(
182
+ (f) => loops(f.points).flatMap(simple).filter((r) => !empty(r)).map((polygon) => ({ name: f.name, polygon, fillColor: rgba(f.fill) }))
183
+ );
184
+ return {
185
+ id,
186
+ data,
187
+ getPolygon: (d) => d.polygon,
188
+ getFillColor: (d) => d.fillColor,
189
+ coordinateSystem: "cartesian",
190
+ filled: true,
191
+ stroked: false
192
+ };
193
+ }
194
+
195
+ export { logoIconLayer, passArcLayer, surfaceLayer };
196
+ //# sourceMappingURL=deckgl.js.map
197
+ //# sourceMappingURL=deckgl.js.map