@mstone6969/graph 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 (238) hide show
  1. package/README.md +111 -14
  2. package/dist/ExcelWriter-3ZSYUH4T.cjs +154 -0
  3. package/dist/GraphType.js +24 -38
  4. package/dist/PdfWriter-6HJFYMCO.cjs +205 -0
  5. package/dist/catalog-YWX6FHRM.cjs +8 -0
  6. package/dist/catalog.js +5 -1
  7. package/dist/charts/bars/index.js +2 -12
  8. package/dist/charts/comparison/EffectForestPlot.js +1 -1
  9. package/dist/charts/comparison/index.js +1 -8
  10. package/dist/charts/demography/Nomogram.js +3 -3
  11. package/dist/charts/density/HexbinChart.js +6 -4
  12. package/dist/charts/diagrams/ArchitectureCanvas.js +68 -0
  13. package/dist/charts/diagrams/ArchitectureDiagram.js +331 -0
  14. package/dist/charts/diagrams/ArchitectureLayout.js +106 -0
  15. package/dist/charts/diagrams/ArchitectureLinkLabels.js +78 -0
  16. package/dist/charts/diagrams/ArchitectureModel.js +108 -0
  17. package/dist/charts/diagrams/ArchitectureRouter.js +348 -0
  18. package/dist/charts/diagrams/ArchitectureSamples.js +312 -0
  19. package/dist/charts/diagrams/ArchitectureShapes.js +130 -0
  20. package/dist/charts/diagrams/ArchitectureText.js +25 -0
  21. package/dist/charts/diagrams/DiagramText.js +38 -0
  22. package/dist/charts/diagrams/EntityRelationshipDiagram.js +465 -0
  23. package/dist/charts/diagrams/ErCrowsFoot.js +33 -0
  24. package/dist/charts/diagrams/ErSamples.js +205 -0
  25. package/dist/charts/diagrams/ErSchema.js +122 -0
  26. package/dist/charts/diagrams/LogicCircuit.js +154 -0
  27. package/dist/charts/diagrams/LogicCircuitLayout.js +600 -0
  28. package/dist/charts/diagrams/LogicCircuitSamples.js +66 -0
  29. package/dist/charts/diagrams/LogicGateDiagram.js +216 -0
  30. package/dist/charts/diagrams/LogicGateSymbol.js +113 -0
  31. package/dist/charts/diagrams/NetworkTopologyDiagram.js +247 -0
  32. package/dist/charts/diagrams/SequenceDiagram.js +351 -0
  33. package/dist/charts/diagrams/SequenceLayout.js +422 -0
  34. package/dist/charts/diagrams/SequenceModel.js +221 -0
  35. package/dist/charts/diagrams/TopologyLayout.js +143 -0
  36. package/dist/charts/diagrams/architectureEnums.js +50 -0
  37. package/dist/charts/diagrams/index.js +26 -0
  38. package/dist/charts/diagrams/logicEnums.js +42 -0
  39. package/dist/charts/diagrams/sequenceEnums.js +40 -0
  40. package/dist/charts/distribution/HistogramChart.js +25 -3
  41. package/dist/charts/distribution/index.js +1 -3
  42. package/dist/charts/earthscience/HovmollerDiagram.js +477 -0
  43. package/dist/charts/earthscience/HovmollerEnums.js +42 -0
  44. package/dist/charts/earthscience/HovmollerField.js +180 -0
  45. package/dist/charts/earthscience/HovmollerSample.js +40 -0
  46. package/dist/charts/earthscience/HovmollerSpeed.js +71 -0
  47. package/dist/charts/earthscience/index.js +10 -2
  48. package/dist/charts/engineering/ConstellationDiagram.js +26 -6
  49. package/dist/charts/engineering/EyeDiagram.js +2 -1
  50. package/dist/charts/engineering/PoleZeroPlot.js +32 -8
  51. package/dist/charts/financial/RelativeStrengthRotation.js +434 -0
  52. package/dist/charts/financial/RelativeStrengthRotationMath.js +71 -0
  53. package/dist/charts/financial/RelativeStrengthRotationSamples.js +27 -0
  54. package/dist/charts/financial/index.js +5 -3
  55. package/dist/charts/flow/index.js +1 -5
  56. package/dist/charts/frameworks/AnsoffMatrix.js +523 -0
  57. package/dist/charts/frameworks/FrameworkText.js +98 -0
  58. package/dist/charts/frameworks/NpsGauge.js +279 -0
  59. package/dist/charts/frameworks/NpsSurvey.js +58 -0
  60. package/dist/charts/frameworks/PerceptualMap.js +419 -0
  61. package/dist/charts/frameworks/PerceptualProjection.js +142 -0
  62. package/dist/charts/frameworks/PositioningSamples.js +191 -0
  63. package/dist/charts/frameworks/RaciMatrix.js +458 -0
  64. package/dist/charts/frameworks/RaciPlan.js +81 -0
  65. package/dist/charts/frameworks/RaciSamples.js +76 -0
  66. package/dist/charts/frameworks/SwotMatrix.js +358 -0
  67. package/dist/charts/frameworks/SwotSamples.js +85 -0
  68. package/dist/charts/frameworks/VanWestendorpChart.js +187 -0
  69. package/dist/charts/frameworks/VanWestendorpSurvey.js +197 -0
  70. package/dist/charts/frameworks/index.js +26 -0
  71. package/dist/charts/frameworks/raciEnums.js +30 -0
  72. package/dist/charts/frameworks/swotEnums.js +34 -0
  73. package/dist/charts/genomics/CircosPlot.js +1 -1
  74. package/dist/charts/geoflows/GeoFlowChart.js +2 -2
  75. package/dist/charts/geoflows/GeoFlowSample.js +2 -1
  76. package/dist/charts/geomaps/FloorPlanMap.js +324 -0
  77. package/dist/charts/geomaps/FloorPlanModel.js +179 -0
  78. package/dist/charts/geomaps/FloorPlanSamples.js +416 -0
  79. package/dist/charts/geomaps/GeoLand.js +2 -2
  80. package/dist/charts/geomaps/GeoSamples.js +2 -1
  81. package/dist/charts/geomaps/GraticuleMap.js +2 -2
  82. package/dist/charts/geomaps/RoomLabelFit.js +200 -0
  83. package/dist/charts/geomaps/TissotMap.js +2 -2
  84. package/dist/charts/geomaps/index.js +8 -4
  85. package/dist/charts/hierarchy/SunburstChart.js +17 -10
  86. package/dist/charts/hierarchy/index.js +2 -11
  87. package/dist/charts/indicators/BulletChart.js +8 -2
  88. package/dist/charts/indicators/SpeedometerChart.js +1 -1
  89. package/dist/charts/indicators/ThermometerChart.js +1 -1
  90. package/dist/charts/lifescience/LoessFit.js +113 -0
  91. package/dist/charts/lifescience/MaPlot.js +337 -0
  92. package/dist/charts/lifescience/MaPlotSamples.js +35 -0
  93. package/dist/charts/lifescience/OncoGlyph.js +137 -0
  94. package/dist/charts/lifescience/OncoPrint.js +373 -0
  95. package/dist/charts/lifescience/OncoPrintMatrix.js +107 -0
  96. package/dist/charts/lifescience/OncoPrintSamples.js +142 -0
  97. package/dist/charts/lifescience/PedigreeChart.js +306 -0
  98. package/dist/charts/lifescience/PedigreeLayout.js +261 -0
  99. package/dist/charts/lifescience/PedigreeRows.js +70 -0
  100. package/dist/charts/lifescience/PedigreeSamples.js +161 -0
  101. package/dist/charts/lifescience/PedigreeSymbol.js +47 -0
  102. package/dist/charts/lifescience/RamachandranPlot.js +364 -0
  103. package/dist/charts/lifescience/RamachandranRegions.js +2712 -0
  104. package/dist/charts/lifescience/RamachandranSamples.js +235 -0
  105. package/dist/charts/lifescience/index.js +25 -0
  106. package/dist/charts/lifescience/pedigreeEnums.js +21 -0
  107. package/dist/charts/lifescience/ramachandranEnums.js +34 -0
  108. package/dist/charts/linesareas/DualAxisChart.js +1 -1
  109. package/dist/charts/linesareas/LineEnums.js +1 -15
  110. package/dist/charts/linesareas/MultiLineChart.js +1 -1
  111. package/dist/charts/linesareas/TrendChart.js +15 -5
  112. package/dist/charts/linesareas/index.js +2 -6
  113. package/dist/charts/massive/MassiveChart.js +3 -2
  114. package/dist/charts/mathematical/FourierSeriesChart.js +7 -1
  115. package/dist/charts/mathematical/index.js +2 -6
  116. package/dist/charts/matrix/GridPlot.js +27 -2
  117. package/dist/charts/matrix/TilegramChart.js +2 -2
  118. package/dist/charts/mlcharts/AttentionGrid.js +79 -0
  119. package/dist/charts/mlcharts/AttentionHeatmap.js +329 -0
  120. package/dist/charts/mlcharts/AttentionModel.js +132 -0
  121. package/dist/charts/mlcharts/AttentionSamples.js +82 -0
  122. package/dist/charts/mlcharts/CellNumber.js +8 -0
  123. package/dist/charts/mlcharts/CurveDiagnosticSamples.js +95 -0
  124. package/dist/charts/mlcharts/CurvePickMark.js +31 -0
  125. package/dist/charts/mlcharts/DecisionBoundaryChart.js +316 -0
  126. package/dist/charts/mlcharts/DecisionSamples.js +60 -0
  127. package/dist/charts/mlcharts/DecisionSurface.js +130 -0
  128. package/dist/charts/mlcharts/DistinctTicks.js +13 -0
  129. package/dist/charts/mlcharts/ElbowMath.js +153 -0
  130. package/dist/charts/mlcharts/ElbowPlot.js +273 -0
  131. package/dist/charts/mlcharts/ExplainabilitySamples.js +70 -0
  132. package/dist/charts/mlcharts/FeatureImportanceChart.js +150 -0
  133. package/dist/charts/mlcharts/ImportanceRanking.js +98 -0
  134. package/dist/charts/mlcharts/LearningCurveChart.js +276 -0
  135. package/dist/charts/mlcharts/LearningCurveMath.js +92 -0
  136. package/dist/charts/mlcharts/PartialDependence.js +92 -0
  137. package/dist/charts/mlcharts/PartialDependencePlot.js +225 -0
  138. package/dist/charts/mlcharts/WideLabel.js +28 -0
  139. package/dist/charts/mlcharts/curveDiagnosticEnums.js +37 -0
  140. package/dist/charts/mlcharts/index.js +32 -0
  141. package/dist/charts/proportion/index.js +5 -9
  142. package/dist/charts/scatter/CategoryScatterBase.js +1 -4
  143. package/dist/charts/scatter/ConnectedScatter.js +7 -4
  144. package/dist/charts/scatter/MarginalScatter.js +13 -8
  145. package/dist/charts/scatter/index.js +4 -17
  146. package/dist/charts/scientific/SpectrogramChart.js +9 -3
  147. package/dist/charts/scientific/index.js +2 -2
  148. package/dist/charts/signals/index.js +3 -13
  149. package/dist/charts/statistics/LorenzCurve.js +7 -4
  150. package/dist/charts/threebars/Candlestick3DChart.js +18 -2
  151. package/dist/charts/threeglobe/GlobeChart.js +2 -2
  152. package/dist/charts/threeglobe/GlobeSamples.js +2 -1
  153. package/dist/charts/threeglobe/RingGlobe.js +1 -1
  154. package/dist/charts/threenetwork/ConeTreeChart.js +2 -1
  155. package/dist/charts/threenetwork/Gantt3DChart.js +3 -2
  156. package/dist/charts/threesurfaces/Ridgeline3DChart.js +22 -4
  157. package/dist/charts/threevolume/LorenzAttractor.js +19 -0
  158. package/dist/charts/threevolume/VolumeRaycastChart.js +4 -3
  159. package/dist/charts/threevolume/volumeEnums.js +1 -0
  160. package/dist/charts/timeline/index.js +2 -10
  161. package/dist/chunk-753UBLV2.cjs +33 -0
  162. package/dist/chunk-VX54A7KA.cjs +17 -0
  163. package/dist/{chunk-W5GAAAZY.cjs → chunk-WAODDPYX.cjs} +24874 -17620
  164. package/dist/chunk-Z3JPIJSC.cjs +338 -0
  165. package/dist/core/CartesianChart.js +87 -11
  166. package/dist/core/Chart.js +63 -15
  167. package/dist/core/Chart2D.js +54 -17
  168. package/dist/core/Chart3D.js +56 -20
  169. package/dist/core/ChartExportError.js +2 -0
  170. package/dist/core/ChartExporter.js +50 -8
  171. package/dist/core/ColumnCheck.js +53 -0
  172. package/dist/core/Context2D.js +29 -15
  173. package/dist/core/Context3D.js +7 -2
  174. package/dist/core/ExcelWriter.js +152 -0
  175. package/dist/core/ExportText.js +28 -0
  176. package/dist/core/MarkOrigin.js +88 -0
  177. package/dist/core/MarkStyle.js +294 -0
  178. package/dist/core/Palette.js +27 -7
  179. package/dist/core/PdfPage.js +13 -0
  180. package/dist/core/PdfWriter.js +245 -0
  181. package/dist/core/Scales.js +52 -2
  182. package/dist/core/SceneOverlay.js +4 -4
  183. package/dist/core/TextFit.js +37 -0
  184. package/dist/core/Theme.js +28 -1
  185. package/dist/core/enums.js +33 -1
  186. package/dist/core/pathMorph.js +15 -0
  187. package/dist/data/SampleData.js +1 -17
  188. package/dist/data/WorldSample.js +23 -0
  189. package/dist/index.cjs +810 -691
  190. package/dist/index.d.cts +8390 -2925
  191. package/dist/index.d.ts +8392 -2927
  192. package/dist/index.js +106 -56
  193. package/dist/react/ChartView.js +18 -8
  194. package/dist/react/GraphHandle.js +2 -0
  195. package/dist/react/components.js +74 -116
  196. package/package.json +13 -3
  197. package/dist/catalog-4UP2YFNR.cjs +0 -7
  198. package/dist/charts/bars/BulletBar.js +0 -184
  199. package/dist/charts/bars/ErrorBarColumn.js +0 -147
  200. package/dist/charts/bars/HistogramBar.js +0 -217
  201. package/dist/charts/bars/MarimekkoBar.js +0 -191
  202. package/dist/charts/bars/ParetoBar.js +0 -143
  203. package/dist/charts/comparison/PanelChart.js +0 -70
  204. package/dist/charts/comparison/SmallMultipleBars.js +0 -134
  205. package/dist/charts/comparison/SpanChart.js +0 -118
  206. package/dist/charts/comparison/TrellisChart.js +0 -158
  207. package/dist/charts/distribution/RidgeSlabs3DChart.js +0 -169
  208. package/dist/charts/financial/Candlestick3D.js +0 -157
  209. package/dist/charts/flow/BumpFlow.js +0 -212
  210. package/dist/charts/flow/StreamFlow.js +0 -174
  211. package/dist/charts/geomaps/ThiessenMap.js +0 -106
  212. package/dist/charts/hierarchy/ConeTree3D.js +0 -135
  213. package/dist/charts/hierarchy/Hierarchy3DChart.js +0 -27
  214. package/dist/charts/hierarchy/SpherePack3D.js +0 -81
  215. package/dist/charts/hierarchy/SunburstTower3D.js +0 -93
  216. package/dist/charts/hierarchy/TreemapSkyline3D.js +0 -98
  217. package/dist/charts/linesareas/ConnectedScatterTime.js +0 -206
  218. package/dist/charts/linesareas/SmallMultipleLines.js +0 -153
  219. package/dist/charts/mathematical/ParametricSurface3D.js +0 -234
  220. package/dist/charts/mathematical/StrangeAttractor3D.js +0 -251
  221. package/dist/charts/proportion/ConeFunnel.js +0 -126
  222. package/dist/charts/proportion/ExtrudedPieChart.js +0 -123
  223. package/dist/charts/scatter/BeeswarmScatter.js +0 -151
  224. package/dist/charts/scatter/BinnedScatterBase.js +0 -51
  225. package/dist/charts/scatter/ContourScatter.js +0 -116
  226. package/dist/charts/scatter/GridBinScatter.js +0 -98
  227. package/dist/charts/scatter/HexbinScatter.js +0 -74
  228. package/dist/charts/scatter/StripScatter.js +0 -107
  229. package/dist/charts/scatter/SunflowerScatter.js +0 -109
  230. package/dist/charts/signals/ConstellationChart.js +0 -153
  231. package/dist/charts/signals/CorrelogramChart.js +0 -171
  232. package/dist/charts/signals/EyeDiagramChart.js +0 -155
  233. package/dist/charts/signals/PoleZeroChart.js +0 -164
  234. package/dist/charts/signals/SpectrogramChart.js +0 -79
  235. package/dist/charts/timeline/CalendarSkylineChart.js +0 -128
  236. package/dist/charts/timeline/ScheduleBlocksChart.js +0 -119
  237. package/dist/charts/timeline/SpiralTimeline.js +0 -154
  238. package/dist/charts/timeline/StreamTimeline.js +0 -141
@@ -1,158 +0,0 @@
1
- import { ChartFamily, DataShape, Dimension, LegendPosition } from "../../core/enums.js";
2
- import { SampleData } from "../../data/SampleData.js";
3
- import { PanelChart, PanelFlow } from "./PanelChart.js";
4
- import { Tally } from "./Tally.js";
5
- import { settleMarks } from "./settleMarks.js";
6
- import { area, group, line, max, mean, min, scaleLinear, scaleUtc, utcFormat } from "d3";
7
- // src/charts/comparison/TrellisChart.ts
8
- var TrellisMark = /* @__PURE__ */ function(TrellisMark) {
9
- TrellisMark["Line"] = "line";
10
- TrellisMark["Area"] = "area";
11
- TrellisMark["Dots"] = "dots";
12
- return TrellisMark;
13
- }({});
14
- var DAY = utcFormat("%b %-d");
15
- /** Cleveland's trellis: one panel per group on common axes, with the other groups as faint context. */
16
- var TrellisChart = class extends PanelChart {
17
- static meta = {
18
- id: "comparison-trellis",
19
- name: "Trellis chart",
20
- family: ChartFamily.Comparison,
21
- dimension: Dimension.Two,
22
- shape: DataShape.Table,
23
- description: "Repeats an x-y panel per group on shared axes, untangling many series that would overlap in one plot.",
24
- tags: [
25
- "lattice",
26
- "facet grid",
27
- "small multiples",
28
- "spaghetti alternative"
29
- ],
30
- sample: (seed) => SampleData.timeSeries(seed, 48, 6).map((row) => ({
31
- series: row.series,
32
- date: row.date,
33
- value: row.value
34
- })),
35
- variants: {
36
- mark: [
37
- "line",
38
- "area",
39
- "dots"
40
- ],
41
- fit: [false, true],
42
- context: [true, false],
43
- freeScale: [false, true],
44
- flow: [
45
- PanelFlow.Auto,
46
- PanelFlow.Row,
47
- PanelFlow.Column
48
- ]
49
- },
50
- valid: (values) => !(values.context && values.freeScale)
51
- };
52
- defaults() {
53
- return {
54
- legend: LegendPosition.None,
55
- facet: "series",
56
- x: "date",
57
- y: "value",
58
- mark: "line",
59
- fit: false,
60
- context: true,
61
- freeScale: false,
62
- flow: PanelFlow.Auto
63
- };
64
- }
65
- plotMargin() {
66
- return {
67
- top: 6,
68
- right: 16,
69
- bottom: 8,
70
- left: 16
71
- };
72
- }
73
- points() {
74
- const { data, facet, x, y } = this.options;
75
- return data.flatMap((row) => {
76
- const cell = row[x], time = cell instanceof Date, at = Tally.num(cell), value = Tally.num(row[y]);
77
- return at === null || value === null ? [] : [{
78
- facet: String(row[facet] ?? ""),
79
- x: at,
80
- y: value,
81
- time
82
- }];
83
- }).sort((a, b) => a.x - b.x);
84
- }
85
- trend(points) {
86
- const mx = mean(points, (d) => d.x) ?? 0, my = mean(points, (d) => d.y) ?? 0;
87
- let top = 0, bottom = 0;
88
- for (const d of points) {
89
- top += (d.x - mx) * (d.y - my);
90
- bottom += (d.x - mx) ** 2;
91
- }
92
- const slope = bottom ? top / bottom : 0;
93
- return [points[0], points[points.length - 1]].map((d) => ({
94
- ...d,
95
- y: my + slope * (d.x - mx)
96
- }));
97
- }
98
- draw(ctx) {
99
- const { mark, fit, context, freeScale } = this.options;
100
- const points = this.points();
101
- const groups = group(points, (d) => d.facet);
102
- const low = min(points, (d) => d.x) ?? 0, high = max(points, (d) => d.x) ?? 1;
103
- const span = [low, high > low ? high : low + 1];
104
- const floor = (list) => mark === "area" ? Math.min(0, min(list, (d) => d.y) ?? 0) : min(list, (d) => d.y) ?? 0;
105
- const reach = Tally.width(Math.round(max(points, (d) => Math.abs(d.y)) ?? 0).toLocaleString("en")) + 8;
106
- const panels = this.panels(ctx, [...groups.keys()], {
107
- left: reach,
108
- bottom: 16,
109
- gapX: freeScale ? reach + 6 : 12
110
- });
111
- const time = points[0]?.time ?? false;
112
- this.eachPanel(ctx, panels, (panel, parent) => {
113
- const own = groups.get(panel.key);
114
- const basis = freeScale ? own : points;
115
- const top = max(basis, (d) => d.y) ?? 1, bottom = floor(basis);
116
- const y = scaleLinear([bottom, top > bottom ? top : bottom + 1], [panel.height, 0]).nice();
117
- const x = time ? scaleUtc().domain(span).range([0, panel.width]) : scaleLinear(span, [0, panel.width]);
118
- const px = (d) => x(d.x), py = (d) => y(d.y);
119
- const color = ctx.palette.color(panel.key);
120
- const draw = line().x(px).y(py);
121
- const tip = (d) => ({
122
- title: panel.key,
123
- color,
124
- rows: [[time ? new Date(d.x).toISOString().slice(0, 10) : Tally.format(d.x), Tally.format(d.y)]]
125
- });
126
- this.panelGrid(ctx, parent, panel, y, "y", freeScale || panel.left);
127
- this.xLabels(ctx, parent, panel, x, time);
128
- const others = context ? [...groups].filter(([key]) => key !== panel.key) : [];
129
- const ghosts = ctx.marks("ghosts", "path", others, ([key]) => key, parent).attr("fill", "none").attr("stroke", ctx.theme.axis).attr("stroke-width", 1);
130
- settleMarks(ctx, ghosts, { d: ([, list]) => draw(list) });
131
- const shade = ctx.marks("area", "path", mark === "area" ? [own] : [], (_, i) => i, parent).attr("fill", color).attr("fill-opacity", .28);
132
- settleMarks(ctx, shade, { d: (list) => area().x(px).y0(y(Math.max(0, y.domain()[0]))).y1(py)(list) });
133
- const path = ctx.marks("line", "path", mark === "dots" ? [] : [own], (_, i) => i, parent).attr("fill", "none").attr("stroke", color).attr("stroke-width", 2);
134
- settleMarks(ctx, path, { d: (list) => draw(list) }, { d: (list) => line().x(px).y(panel.height)(list) });
135
- ctx.hover(path, () => ({
136
- title: panel.key,
137
- color,
138
- rows: [["Latest", Tally.format(own[own.length - 1].y)], ["Points", own.length]]
139
- }));
140
- const dots = ctx.marks("dots", "circle", mark === "dots" ? own : own.slice(-1), (d) => d.x, parent).attr("fill", color).attr("stroke", ctx.theme.surface).attr("stroke-width", mark === "dots" ? 1 : 2);
141
- settleMarks(ctx, dots, {
142
- cx: px,
143
- cy: py,
144
- r: mark === "dots" ? 2.5 : 4
145
- }, { r: 0 });
146
- ctx.hover(dots, tip);
147
- const trend = ctx.marks("trend", "path", fit ? [this.trend(own)] : [], (_, i) => i, parent).attr("fill", "none").attr("stroke", ctx.theme.ink).attr("stroke-width", 2).attr("stroke-dasharray", "5 3");
148
- settleMarks(ctx, trend, { d: (list) => draw(list) });
149
- });
150
- }
151
- /** x labels for the bottom row, spaced by the panel's width and kept off its corners. */
152
- xLabels(ctx, parent, panel, x, time) {
153
- const ticks = x.ticks(Math.max(2, Math.floor(panel.width / 64)));
154
- const shown = panel.bottom ? ticks.filter((tick) => x(tick) > 16 && x(tick) < panel.width - 16) : [];
155
- ctx.text(ctx.marks("x-ticks", "text", shown, (tick) => +tick, parent), 10, "muted").attr("text-anchor", "middle").attr("x", (tick) => x(tick)).attr("y", panel.height + 12).text((tick) => time ? DAY(/* @__PURE__ */ new Date(+tick)) : Tally.format(+tick));
156
- }
157
- };
158
- export { TrellisChart, TrellisMark };
@@ -1,169 +0,0 @@
1
- import { Chart3D } from "../../core/Chart3D.js";
2
- import { ChartFamily, DataShape, Dimension } from "../../core/enums.js";
3
- import { readable } from "./DistributionChart.js";
4
- import { DistributionSamples } from "./DistributionSamples.js";
5
- import { DistributionStats } from "./DistributionStats.js";
6
- import { GroupOrder, KernelKind, KernelSmoothing, Ridge3DForm, RidgeScaling } from "./enums.js";
7
- import { max, scaleLinear } from "d3";
8
- import { BufferAttribute, BufferGeometry, DoubleSide, ExtrudeGeometry, Mesh, MeshStandardMaterial, PlaneGeometry, Shape } from "three";
9
- // src/charts/distribution/RidgeSlabs3DChart.ts
10
- var STEPS = 72;
11
- var FLOOR = -.7;
12
- var RISE = 1.1;
13
- /** Density curves stood up in depth: slabs, thin blades or one lofted terrain, for a shift across ordered groups. */
14
- var RidgeSlabs3DChart = class extends Chart3D {
15
- static meta = {
16
- id: "distribution-ridgeline-3d",
17
- name: "3D ridgeline",
18
- family: ChartFamily.Distribution,
19
- dimension: Dimension.Three,
20
- shape: DataShape.Table,
21
- description: "Extrudes each group density into depth, or lofts them into a terrain, to show a shift across ordered groups.",
22
- tags: [
23
- "joyplot",
24
- "density surface",
25
- "distribution terrain"
26
- ],
27
- sample: (seed) => DistributionSamples.uneven(seed, 140, 6),
28
- variants: {
29
- form: [
30
- Ridge3DForm.Slabs,
31
- Ridge3DForm.Blades,
32
- Ridge3DForm.Terrain
33
- ],
34
- smoothing: [
35
- KernelSmoothing.Balanced,
36
- KernelSmoothing.Tight,
37
- KernelSmoothing.Loose
38
- ],
39
- order: [GroupOrder.Given, GroupOrder.Ascending],
40
- ridgeScaling: [RidgeScaling.Shared, RidgeScaling.Row]
41
- }
42
- };
43
- defaults() {
44
- return {
45
- value: "value",
46
- group: "group",
47
- form: Ridge3DForm.Slabs,
48
- smoothing: KernelSmoothing.Balanced,
49
- order: GroupOrder.Given,
50
- ridgeScaling: RidgeScaling.Shared,
51
- distance: 5,
52
- elevation: 32
53
- };
54
- }
55
- ordered() {
56
- const samples = DistributionStats.samples(Array.isArray(this.options.data) ? this.options.data : [], this.options.value, this.options.group);
57
- return this.options.order === GroupOrder.Ascending ? samples.sort((a, b) => a.summary.median - b.summary.median) : samples;
58
- }
59
- build(ctx) {
60
- const { form, smoothing, ridgeScaling } = this.options;
61
- const samples = this.ordered();
62
- const floor = new Mesh(new PlaneGeometry(2.1, 2.1), new MeshStandardMaterial({ color: ctx.theme.grid }));
63
- floor.rotation.x = -Math.PI / 2;
64
- floor.position.y = FLOOR;
65
- floor.receiveShadow = true;
66
- ctx.root.add(floor);
67
- if (!samples.length) return;
68
- const curves = samples.map((s) => DistributionStats.density(s.values, KernelKind.Gaussian, smoothing));
69
- const lo = Math.min(...curves.map((c) => c[0].v)), hi = Math.max(...curves.map((c) => c[c.length - 1].v));
70
- const value = scaleLinear([lo, hi || lo + 1], [-1, .74]).nice();
71
- const grid = Array.from({ length: 73 }, (_, i) => value.domain()[0] + (value.domain()[1] - value.domain()[0]) * i / STEPS);
72
- const inside = (curve, v) => v < curve[0].v || v > curve[curve.length - 1].v ? 0 : DistributionStats.at(curve, v);
73
- const raw = curves.map((curve) => grid.map((v) => inside(curve, v)));
74
- const shared = max(raw.flat()) || 1;
75
- const heights = raw.map((row) => {
76
- const top = ridgeScaling === RidgeScaling.Row ? max(row) || 1 : shared;
77
- return row.map((d) => d / top * RISE);
78
- });
79
- const depth = (i) => samples.length > 1 ? -.9 + 1.8 * i / (samples.length - 1) : 0;
80
- const pitch = samples.length > 1 ? 1.8 / (samples.length - 1) : .8;
81
- if (form === Ridge3DForm.Terrain) this.terrain(ctx, samples, heights, grid.map((v) => value(v)), depth);
82
- else samples.forEach((sample, i) => {
83
- const outline = new Shape();
84
- outline.moveTo(value(grid[0]), 0);
85
- grid.forEach((v, g) => outline.lineTo(value(v), Math.max(.002, heights[i][g])));
86
- outline.lineTo(value(grid[STEPS]), 0);
87
- const thick = form === Ridge3DForm.Blades ? Math.min(.05, pitch * .25) : pitch * .82;
88
- const geometry = new ExtrudeGeometry(outline, {
89
- depth: thick,
90
- bevelEnabled: false,
91
- curveSegments: 1
92
- });
93
- geometry.translate(0, 0, depth(i) - thick / 2);
94
- const mesh = new Mesh(geometry, new MeshStandardMaterial({
95
- color: ctx.color(ctx.palette.color(sample.name)),
96
- roughness: .6
97
- }));
98
- mesh.position.y = FLOOR;
99
- mesh.castShadow = mesh.receiveShadow = true;
100
- ctx.reveal((p) => mesh.scale.set(1, Math.max(.001, p), 1), .9, i * .06);
101
- ctx.root.add(mesh);
102
- ctx.pick(mesh, () => this.tell(sample));
103
- });
104
- for (const tick of value.ticks(5)) ctx.label(readable(tick), [
105
- value(tick),
106
- -.75,
107
- 1
108
- ], "secondary", 10);
109
- samples.forEach((sample, i) => {
110
- if (sample.name) ctx.label(sample.name, [
111
- .86,
112
- FLOOR,
113
- depth(i)
114
- ], "secondary", 10);
115
- });
116
- }
117
- tell(sample) {
118
- const s = sample.summary;
119
- return {
120
- title: sample.name || this.options.value,
121
- rows: [
122
- ["n", s.n],
123
- ["Median", readable(s.median)],
124
- ["Mean", readable(s.mean)]
125
- ]
126
- };
127
- }
128
- terrain(ctx, samples, heights, xs, depth) {
129
- const across = xs.length, rows = samples.length;
130
- const positions = new Float32Array(across * rows * 3), colors = new Float32Array(across * rows * 3);
131
- const indices = [];
132
- samples.forEach((_, r) => xs.forEach((x, c) => {
133
- const y = heights[r][c], at = (r * across + c) * 3, tone = ctx.color(ctx.palette.sequential(.15 + .85 * y / RISE));
134
- positions.set([
135
- x,
136
- y,
137
- depth(r)
138
- ], at);
139
- colors.set([
140
- tone.r,
141
- tone.g,
142
- tone.b
143
- ], at);
144
- if (r < rows - 1 && c < across - 1) {
145
- const a = r * across + c, b = a + 1, d = a + across, e = d + 1;
146
- indices.push(a, d, b, b, d, e);
147
- }
148
- }));
149
- const geometry = new BufferGeometry();
150
- geometry.setAttribute("position", new BufferAttribute(positions, 3));
151
- geometry.setAttribute("color", new BufferAttribute(colors, 3));
152
- geometry.setIndex(indices);
153
- geometry.computeVertexNormals();
154
- const mesh = new Mesh(geometry, new MeshStandardMaterial({
155
- vertexColors: true,
156
- roughness: .7,
157
- side: DoubleSide
158
- }));
159
- mesh.position.y = -.692;
160
- mesh.castShadow = mesh.receiveShadow = true;
161
- ctx.reveal((p) => mesh.scale.set(1, Math.max(.001, p), 1));
162
- ctx.root.add(mesh);
163
- ctx.pick(mesh, () => ({
164
- title: this.meta.name,
165
- rows: [["Groups", rows]]
166
- }));
167
- }
168
- };
169
- export { RidgeSlabs3DChart };
@@ -1,157 +0,0 @@
1
- import { Chart3D } from "../../core/Chart3D.js";
2
- import { ChartFamily, DataShape, Dimension } from "../../core/enums.js";
3
- import { SampleData } from "../../data/SampleData.js";
4
- import { Candle3DDepth } from "./financeEnums.js";
5
- import { FinanceMath } from "./FinanceMath.js";
6
- import { Quotes } from "./Quotes.js";
7
- import { extent, scaleBand, scaleLinear, scaleSqrt } from "d3";
8
- import { BoxGeometry, CatmullRomCurve3, InstancedMesh, Mesh, MeshStandardMaterial, Object3D, PlaneGeometry, TubeGeometry, Vector3 } from "three";
9
- // src/charts/financial/Candlestick3D.ts
10
- var BASE = -.7;
11
- /** Candlesticks as solid objects: use it for presentation views where volume adds a physical third dimension. */
12
- var Candlestick3D = class extends Chart3D {
13
- static meta = {
14
- id: "candlestick-3d",
15
- name: "3D candlestick chart",
16
- family: ChartFamily.Financial,
17
- dimension: Dimension.Three,
18
- shape: DataShape.Table,
19
- description: "Stands each session as a solid candle on a floor, with depth or a rear wall carrying traded volume.",
20
- tags: [
21
- "ohlc",
22
- "stock",
23
- "volume",
24
- "solid"
25
- ],
26
- sample: (seed) => SampleData.ohlc(seed, 36),
27
- variants: {
28
- depth: [Candle3DDepth.Uniform, Candle3DDepth.Volume],
29
- volumeWall: [true, false],
30
- ribbon: [false, true]
31
- }
32
- };
33
- defaults() {
34
- return {
35
- date: "date",
36
- open: "open",
37
- high: "high",
38
- low: "low",
39
- close: "close",
40
- volume: "volume",
41
- depth: Candle3DDepth.Uniform,
42
- volumeWall: true,
43
- ribbon: false
44
- };
45
- }
46
- build(ctx) {
47
- const { depth, volumeWall, ribbon } = this.options;
48
- const bars = Quotes.read(this.options.data, this.options);
49
- const floor = new Mesh(new PlaneGeometry(2.4, 1.4), new MeshStandardMaterial({ color: ctx.theme.grid }));
50
- floor.rotation.x = -Math.PI / 2;
51
- floor.position.y = BASE;
52
- floor.receiveShadow = true;
53
- ctx.root.add(floor);
54
- if (!bars.length) return;
55
- const band = scaleBand(bars.map((bar) => String(bar.index)), [-1.05, 1.05]).padding(.22);
56
- const [low, high] = [Math.min(...bars.map((bar) => bar.low)), Math.max(...bars.map((bar) => bar.high))];
57
- const price = scaleLinear([low, high === low ? low + 1 : high], [-.62, .7]);
58
- const heaviest = Math.max(1, ...bars.map((bar) => bar.volume));
59
- const width = band.bandwidth();
60
- const deep = scaleSqrt([0, heaviest], [width * .5, width * 5]);
61
- const center = (i) => band(String(i)) + width / 2;
62
- const dummy = new Object3D();
63
- const bodies = new InstancedMesh(new BoxGeometry(width, 1, 1), new MeshStandardMaterial({ roughness: .45 }), bars.length);
64
- const wicks = new InstancedMesh(new BoxGeometry(width * .16, 1, width * .16), new MeshStandardMaterial({ roughness: .6 }), bars.length);
65
- bodies.castShadow = wicks.castShadow = true;
66
- const tone = (rising) => ctx.color(ctx.palette.diverging(rising ? -1 : 1));
67
- bars.forEach((bar, i) => {
68
- bodies.setColorAt(i, tone(bar.close >= bar.open));
69
- wicks.setColorAt(i, tone(bar.close >= bar.open));
70
- });
71
- const place = (progress) => {
72
- bars.forEach((bar, i) => {
73
- const mid = (price(bar.open) + price(bar.close)) / 2;
74
- const tall = Math.max(.012, Math.abs(price(bar.close) - price(bar.open))) * progress + 5e-4;
75
- dummy.position.set(center(i), BASE + (mid - BASE) * progress, 0);
76
- dummy.scale.set(1, tall, depth === Candle3DDepth.Volume ? deep(bar.volume) : width * 1.4);
77
- dummy.updateMatrix();
78
- bodies.setMatrixAt(i, dummy.matrix);
79
- dummy.position.set(center(i), BASE + ((price(bar.high) + price(bar.low)) / 2 - BASE) * progress, 0);
80
- dummy.scale.set(1, Math.max(.001, (price(bar.high) - price(bar.low)) * progress), 1);
81
- dummy.updateMatrix();
82
- wicks.setMatrixAt(i, dummy.matrix);
83
- });
84
- bodies.instanceMatrix.needsUpdate = wicks.instanceMatrix.needsUpdate = true;
85
- };
86
- ctx.reveal(place);
87
- ctx.root.add(bodies, wicks);
88
- const tip = (i) => {
89
- const bar = bars[i];
90
- return {
91
- title: bar.label,
92
- rows: [
93
- ["Open", Quotes.money(bar.open)],
94
- ["High", Quotes.money(bar.high)],
95
- ["Low", Quotes.money(bar.low)],
96
- ["Close", Quotes.money(bar.close)],
97
- ["Volume", Quotes.compact(bar.volume)]
98
- ]
99
- };
100
- };
101
- ctx.pick(bodies, tip);
102
- if (volumeWall) {
103
- const height = scaleLinear([0, heaviest], [.005, .5]);
104
- const wall = new InstancedMesh(new BoxGeometry(width, 1, .04), new MeshStandardMaterial({
105
- roughness: .8,
106
- color: ctx.theme.inkMuted
107
- }), bars.length);
108
- wall.castShadow = true;
109
- const raise = (progress) => {
110
- bars.forEach((bar, i) => {
111
- const tall = Math.max(.002, height(bar.volume) * progress);
112
- dummy.position.set(center(i), BASE + tall / 2, -.62);
113
- dummy.scale.set(1, tall, 1);
114
- dummy.updateMatrix();
115
- wall.setMatrixAt(i, dummy.matrix);
116
- });
117
- wall.instanceMatrix.needsUpdate = true;
118
- };
119
- ctx.reveal(raise, .9, .2);
120
- ctx.root.add(wall);
121
- ctx.pick(wall, tip);
122
- }
123
- if (ribbon) {
124
- const knots = FinanceMath.ema(bars.map((bar) => bar.close), Math.min(10, Math.max(2, Math.floor(bars.length / 3)))).flatMap((value, i) => value === null ? [] : [new Vector3(center(i), price(value), .34)]);
125
- if (knots.length > 1) {
126
- const tube = new Mesh(new TubeGeometry(new CatmullRomCurve3(knots), knots.length * 3, .012, 8), new MeshStandardMaterial({
127
- color: ctx.theme.categorical[1],
128
- roughness: .4
129
- }));
130
- tube.castShadow = true;
131
- ctx.root.add(tube);
132
- }
133
- }
134
- const [first, last] = extent(bars, (bar) => bar.index);
135
- ctx.label(bars[first].label, [
136
- center(first),
137
- -.7999999999999999,
138
- .82
139
- ], "secondary", 10);
140
- ctx.label(bars[last].label, [
141
- center(last),
142
- -.7999999999999999,
143
- .82
144
- ], "secondary", 10);
145
- ctx.label(Quotes.money(high), [
146
- -1.2,
147
- .7,
148
- 0
149
- ], "muted", 10);
150
- ctx.label(Quotes.money(low), [
151
- -1.2,
152
- -.62,
153
- 0
154
- ], "muted", 10);
155
- }
156
- };
157
- export { Candlestick3D };
@@ -1,212 +0,0 @@
1
- import { ChartFamily, CurveKind, DataShape, Dimension, Orientation } from "../../core/enums.js";
2
- import { Scales } from "../../core/Scales.js";
3
- import { SampleData } from "../../data/SampleData.js";
4
- import { FlowChart } from "./FlowChart.js";
5
- import { FlowRibbon, FlowRouter, FlowSort } from "./flowEnums.js";
6
- import { FlowGeometry } from "./FlowPathKit.js";
7
- import { FlowTable } from "./FlowTable.js";
8
- import { line, scaleLinear, scalePoint } from "d3";
9
- // src/charts/flow/BumpFlow.ts
10
- /** `Line` is rank alone. `Ribbon` also makes thickness proportional to value. */
11
- var BumpMark = /* @__PURE__ */ function(BumpMark) {
12
- BumpMark["Line"] = "line";
13
- BumpMark["Ribbon"] = "ribbon";
14
- return BumpMark;
15
- }({});
16
- /** `Rank` spaces positions evenly; `Value` keeps rank order but spaces by actual gap. */
17
- var BumpSpacing = /* @__PURE__ */ function(BumpSpacing) {
18
- BumpSpacing["Rank"] = "rank";
19
- BumpSpacing["Value"] = "value";
20
- return BumpSpacing;
21
- }({});
22
- var BumpLeader = /* @__PURE__ */ function(BumpLeader) {
23
- BumpLeader["Top"] = "top";
24
- BumpLeader["Bottom"] = "bottom";
25
- return BumpLeader;
26
- }({});
27
- /** Track how rankings change over time when position matters more than the underlying value. */
28
- var BumpFlow = class extends FlowChart {
29
- static meta = {
30
- id: "bump-flow",
31
- name: "Bump flow",
32
- family: ChartFamily.Flow,
33
- dimension: Dimension.Two,
34
- shape: DataShape.Table,
35
- description: "Follows each series through its rank in every period, making overtakes and streaks easy to read.",
36
- tags: [
37
- "bump chart",
38
- "ranking",
39
- "league table"
40
- ],
41
- sample: (seed) => SampleData.categories(seed, 7, 6),
42
- variants: {
43
- mark: ["line", "ribbon"],
44
- curve: [
45
- CurveKind.Bump,
46
- CurveKind.Linear,
47
- CurveKind.StepAfter,
48
- CurveKind.Monotone
49
- ],
50
- spacing: ["rank", "value"],
51
- leader: ["top", "bottom"],
52
- dots: [true, false],
53
- orientation: [Orientation.Horizontal, Orientation.Vertical]
54
- },
55
- valid: (v) => v.mark === "line" || v.curve !== CurveKind.Monotone && v.dots === false
56
- };
57
- defaults() {
58
- return {
59
- x: "category",
60
- series: "series",
61
- y: "value",
62
- mark: "line",
63
- curve: CurveKind.Bump,
64
- spacing: "rank",
65
- leader: "top",
66
- dots: true,
67
- orientation: Orientation.Horizontal
68
- };
69
- }
70
- plotMargin() {
71
- return this.options.orientation === Orientation.Vertical ? {
72
- top: 8,
73
- right: 10,
74
- bottom: 8,
75
- left: 58
76
- } : {
77
- top: 10,
78
- right: 12,
79
- bottom: 26,
80
- left: 12
81
- };
82
- }
83
- draw(ctx) {
84
- const { data, x, series, y, mark, curve, spacing, leader, dots, orientation } = this.options;
85
- const vertical = orientation === Orientation.Vertical;
86
- const to = FlowGeometry.project(orientation);
87
- const [length, breadth] = vertical ? [ctx.plot.height, ctx.plot.width] : [ctx.plot.width, ctx.plot.height];
88
- const table = FlowTable.pivot(data, x, series, y);
89
- const gutter = vertical ? 0 : Math.min(length * .16, 12 + Math.max(0, ...table.series.map((name) => FlowTable.width(name))));
90
- const along = scalePoint(table.columns.map((_, c) => c), vertical ? [18, length - 18] : [gutter, length - gutter]);
91
- const rows = Math.max(1, table.series.length);
92
- const inset = 12;
93
- const rankScale = scaleLinear([1, Math.max(2, rows)], leader === "top" ? [inset, breadth - inset] : [breadth - inset, inset]);
94
- const values = table.columns.flatMap((_, c) => table.series.map((name) => table.at(c, name)));
95
- const valueScale = scaleLinear([Math.min(0, ...values), Math.max(1, ...values)], leader === "top" ? [breadth - inset, inset] : [inset, breadth - inset]);
96
- const stops = table.series.map((name) => ({
97
- name,
98
- stops: []
99
- }));
100
- table.columns.forEach((_, c) => {
101
- FlowTable.sorted(table.series, FlowSort.Descending, (name) => table.at(c, name)).forEach((name, i) => {
102
- const value = table.at(c, name);
103
- stops.find((row) => row.name === name).stops.push({
104
- series: name,
105
- column: c,
106
- rank: i + 1,
107
- value,
108
- u: along(c),
109
- v: spacing === "value" ? valueScale(value) : rankScale(i + 1),
110
- label: table.labels[c]
111
- });
112
- });
113
- });
114
- const color = (name) => ctx.palette.color(name);
115
- for (const name of table.series) color(name);
116
- const peak = Math.max(1, ...values);
117
- const room = breadth / rows * .8;
118
- const trace = line().curve(Scales.curve(curve)).x((d) => to(d.u, d.v)[0]).y((d) => to(d.u, d.v)[1]);
119
- const form = curve === CurveKind.Linear ? FlowRibbon.Angular : curve === CurveKind.StepAfter ? FlowRibbon.Shoulder : FlowRibbon.Curved;
120
- const lanes = ctx.marks("lanes", "path", mark === "line" ? stops : [], (d) => d.name).attr("fill", "none").attr("stroke", (d) => color(d.name)).attr("stroke-width", 3).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
121
- const lanePath = (d) => vertical && curve === CurveKind.Bump ? FlowGeometry.route(d.stops.map((stop) => [stop.u, stop.v]), FlowRouter.Curved, to) : trace(d.stops) ?? "";
122
- this.stroke(ctx, lanes, lanePath);
123
- ctx.hover(lanes, (d) => ({
124
- title: d.name,
125
- color: color(d.name),
126
- rows: d.stops.map((stop) => [stop.label, `#${stop.rank}`])
127
- }));
128
- const pieces = mark === "ribbon" ? stops.flatMap((row) => row.stops.slice(1).map((stop, i) => {
129
- const a = row.stops[i];
130
- const half = (value) => Math.max(1, value / peak * room) / 2;
131
- return {
132
- key: `${row.name}#${i}`,
133
- from: color(row.name),
134
- datum: row,
135
- d: FlowGeometry.ribbon({
136
- u: a.u,
137
- v0: a.v - half(a.value),
138
- v1: a.v + half(a.value)
139
- }, {
140
- u: stop.u,
141
- v0: stop.v - half(stop.value),
142
- v1: stop.v + half(stop.value)
143
- }, form, to)
144
- };
145
- })) : [];
146
- this.bands(ctx, "ribbons", pieces, (row) => ({
147
- title: row.name,
148
- color: color(row.name),
149
- rows: row.stops.map((stop) => [stop.label, stop.value])
150
- }), .72);
151
- const all = stops.flatMap((row) => row.stops);
152
- const dotted = dots ? all : [];
153
- const marks = ctx.marks("dots", "circle", dotted, (d) => `${d.series}/${d.column}`).attr("fill", (d) => color(d.series)).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
154
- const at = (d) => to(d.u, d.v);
155
- ctx.set(marks, {
156
- cx: (d) => at(d)[0],
157
- cy: (d) => at(d)[1],
158
- r: 5
159
- }, {
160
- cx: (d) => at(d)[0],
161
- cy: (d) => at(d)[1],
162
- r: 0
163
- }, 4);
164
- ctx.hover(marks, (d) => ({
165
- title: d.series,
166
- color: color(d.series),
167
- rows: [[d.label, d.value], ["Rank", `#${d.rank}`]]
168
- }));
169
- this.labels(ctx, "names", vertical ? stops.flatMap(({ name, stops: list }) => {
170
- const end = list[list.length - 1];
171
- return end ? [{
172
- key: name,
173
- x: at(end)[0],
174
- y: at(end)[1] + 11,
175
- text: name,
176
- anchor: "middle",
177
- tone: "ink",
178
- halo: true
179
- }] : [];
180
- }) : stops.flatMap(({ name, stops: list }) => {
181
- const start = list[0], end = list[list.length - 1];
182
- if (!start || !end) return [];
183
- return [{
184
- key: `${name}<`,
185
- x: at(start)[0] - 9,
186
- y: at(start)[1],
187
- text: name,
188
- anchor: "end"
189
- }, {
190
- key: `${name}>`,
191
- x: at(end)[0] + 9,
192
- y: at(end)[1],
193
- text: name,
194
- tone: "ink"
195
- }];
196
- }));
197
- this.ticks(ctx, "columns", table.columns.map((_, c) => vertical ? {
198
- key: `c${c}`,
199
- x: -6,
200
- y: along(c),
201
- text: table.labels[c],
202
- anchor: "end"
203
- } : {
204
- key: `c${c}`,
205
- x: along(c),
206
- y: 0,
207
- text: table.labels[c],
208
- anchor: "middle"
209
- }), vertical ? "left" : "bottom");
210
- }
211
- };
212
- export { BumpFlow, BumpLeader, BumpMark, BumpSpacing };