@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,98 +0,0 @@
1
- import { ChartFamily, DataShape, Dimension } from "../../core/enums.js";
2
- import { Hierarchy3DChart } from "./Hierarchy3DChart.js";
3
- import { HierarchyMeasure, SkylineHeight, TreemapTile } from "./hierarchyEnums.js";
4
- import { treemapTiling } from "./TreemapTiling.js";
5
- import { TreeSamples } from "./TreeSamples.js";
6
- import { max, treemap } from "d3";
7
- import { BoxGeometry, InstancedMesh, Mesh, MeshStandardMaterial, Object3D, PlaneGeometry } from "three";
8
- // src/charts/hierarchy/TreemapSkyline3D.ts
9
- var FLOOR = -.7;
10
- var STEP = .05;
11
- var TOP = 1.3;
12
- /** Treemap extruded into a city: footprint and height can carry two measures of the same items. */
13
- var TreemapSkyline3D = class extends Hierarchy3DChart {
14
- static meta = {
15
- id: "treemap-skyline-3d",
16
- name: "3D treemap skyline",
17
- family: ChartFamily.Hierarchy,
18
- dimension: Dimension.Three,
19
- shape: DataShape.Hierarchy,
20
- description: "Extrudes treemap cells into a city, so footprint and height can carry different views of the same items.",
21
- tags: [
22
- "city",
23
- "extruded treemap",
24
- "skyline",
25
- "software city"
26
- ],
27
- sample: (seed) => TreeSamples.broad(seed, 3, 4),
28
- variants: {
29
- tile: [
30
- TreemapTile.Squarify,
31
- TreemapTile.Binary,
32
- TreemapTile.SliceDice
33
- ],
34
- heightBy: Object.values(SkylineHeight),
35
- terraces: [true, false],
36
- measure: [HierarchyMeasure.Value, HierarchyMeasure.LeafCount]
37
- }
38
- };
39
- defaults() {
40
- return {
41
- ...super.defaults(),
42
- tile: TreemapTile.Squarify,
43
- heightBy: SkylineHeight.Value,
44
- terraces: true
45
- };
46
- }
47
- buildTree(ctx) {
48
- const { tile, heightBy, terraces } = this.options;
49
- const gap = .012;
50
- const root = treemap().size([2, 2]).tile(treemapTiling(tile)).paddingInner(gap).paddingOuter((node) => terraces && node.depth > 0 ? gap * 2 : 0)(this.tree());
51
- const cells = root.leaves();
52
- const groups = terraces ? root.descendants().filter((node) => node.depth > 0 && node.children) : [];
53
- const peak = max(cells, (cell) => cell.data.total) || 1;
54
- const rise = (cell) => {
55
- const share = cell.data.total / peak;
56
- if (heightBy === SkylineHeight.Depth) return .06 + .5 * share * (cell.depth / Math.max(1, root.height));
57
- return Math.max(.02, TOP * (heightBy === SkylineHeight.Sqrt ? Math.sqrt(share) : share));
58
- };
59
- const base = (node) => FLOOR + (terraces ? (node.depth - 1) * STEP : 0);
60
- const floor = new Mesh(new PlaneGeometry(2.3, 2.3), new MeshStandardMaterial({ color: ctx.theme.grid }));
61
- floor.rotation.x = -Math.PI / 2;
62
- floor.position.y = -.701;
63
- floor.receiveShadow = true;
64
- ctx.root.add(floor);
65
- const dummy = new Object3D();
66
- const box = new BoxGeometry(1, 1, 1);
67
- const plinths = groups.length ? new InstancedMesh(box.clone(), new MeshStandardMaterial({ roughness: .8 }), groups.length) : null;
68
- groups.forEach((group, i) => {
69
- dummy.position.set((group.x0 + group.x1) / 2 - 1, base(group) + STEP / 2, (group.y0 + group.y1) / 2 - 1);
70
- dummy.scale.set(group.x1 - group.x0, STEP, group.y1 - group.y0);
71
- dummy.updateMatrix();
72
- plinths.setMatrixAt(i, dummy.matrix);
73
- plinths.setColorAt(i, ctx.color(this.style.tint(this.style.branch(group), .72 - .2 * (group.depth - 1))));
74
- });
75
- if (plinths) {
76
- plinths.receiveShadow = true;
77
- ctx.root.add(plinths);
78
- ctx.pick(plinths, (i) => this.style.tooltip(groups[i]));
79
- }
80
- const towers = new InstancedMesh(box, new MeshStandardMaterial({ roughness: .55 }), cells.length);
81
- towers.castShadow = towers.receiveShadow = true;
82
- cells.forEach((cell, i) => towers.setColorAt(i, ctx.color(this.style.fill(cell))));
83
- ctx.reveal((progress) => {
84
- cells.forEach((cell, i) => {
85
- const tall = Math.max(.001, rise(cell) * progress);
86
- const floorY = base(cell) + (terraces ? STEP : 0);
87
- dummy.position.set((cell.x0 + cell.x1) / 2 - 1, floorY + tall / 2, (cell.y0 + cell.y1) / 2 - 1);
88
- dummy.scale.set(cell.x1 - cell.x0, tall, cell.y1 - cell.y0);
89
- dummy.updateMatrix();
90
- towers.setMatrixAt(i, dummy.matrix);
91
- });
92
- towers.instanceMatrix.needsUpdate = true;
93
- });
94
- ctx.root.add(towers);
95
- ctx.pick(towers, (i) => this.style.tooltip(cells[i]));
96
- }
97
- };
98
- export { TreemapSkyline3D };
@@ -1,206 +0,0 @@
1
- import { CartesianChart } from "../../core/CartesianChart.js";
2
- import { ChartFamily, CurveKind, DataShape, Dimension, LegendPosition, ScaleKind } from "../../core/enums.js";
3
- import { Scales } from "../../core/Scales.js";
4
- import { SampleData } from "../../data/SampleData.js";
5
- import { ConnectedDates, ConnectedDots } from "./LineEnums.js";
6
- import { TrendHover } from "./TrendHover.js";
7
- import { TrendLabels } from "./TrendLabels.js";
8
- import { TrendTable } from "./TrendTable.js";
9
- import { extent, group, line, utcFormat } from "d3";
10
- // src/charts/linesareas/ConnectedScatterTime.ts
11
- var dateLabel = utcFormat("%b %-d");
12
- /** Two measures moving together through time, where the loops of the path are the story. Needs a reader willing to follow direction. */
13
- var ConnectedScatterTime = class ConnectedScatterTime extends CartesianChart {
14
- static meta = {
15
- id: "connected-scatter-time",
16
- name: "Connected scatter over time",
17
- family: ChartFamily.Relationship,
18
- dimension: Dimension.Two,
19
- shape: DataShape.Table,
20
- description: "Joins x-y points in time order, so that the path shows how two measures move together.",
21
- tags: [
22
- "phase plot",
23
- "path",
24
- "trajectory"
25
- ],
26
- sample: (seed) => {
27
- const rows = SampleData.timeSeries(seed, 26, 2);
28
- const half = rows.length / 2;
29
- return rows.slice(0, half).map((row, i) => ({
30
- date: row.date,
31
- x: row.value,
32
- y: rows[half + i].value
33
- }));
34
- },
35
- variants: {
36
- curve: [
37
- CurveKind.CatmullRom,
38
- CurveKind.Linear,
39
- CurveKind.Cardinal,
40
- CurveKind.Basis
41
- ],
42
- dots: [
43
- ConnectedDots.Ends,
44
- ConnectedDots.All,
45
- ConnectedDots.None
46
- ],
47
- dates: [
48
- ConnectedDates.Ends,
49
- ConnectedDates.Periodic,
50
- ConnectedDates.None
51
- ],
52
- arrows: [true, false],
53
- scale: [ScaleKind.Linear, ScaleKind.Log]
54
- }
55
- };
56
- defaults() {
57
- return {
58
- x: "x",
59
- y: "y",
60
- time: "date",
61
- series: "series",
62
- curve: CurveKind.CatmullRom,
63
- scale: ScaleKind.Linear,
64
- dots: ConnectedDots.Ends,
65
- dates: ConnectedDates.Ends,
66
- arrows: true
67
- };
68
- }
69
- get log() {
70
- return this.options.scale === ScaleKind.Log;
71
- }
72
- get legendPosition() {
73
- return this.trails.length > 1 ? super.legendPosition : LegendPosition.None;
74
- }
75
- static moment(cell) {
76
- if (cell instanceof Date) return +cell;
77
- if (typeof cell === "number") return cell;
78
- if (typeof cell !== "string" || !cell) return null;
79
- const parsed = +new Date(cell);
80
- return Number.isNaN(parsed) ? null : parsed;
81
- }
82
- get trails() {
83
- const { data, x, y, time, series } = this.options;
84
- const parsed = (Array.isArray(data) ? data : []).flatMap((row) => {
85
- const at = ConnectedScatterTime.moment(row[time]), a = TrendTable.number(row[x]), b = TrendTable.number(row[y]);
86
- if (at === null || a === null || b === null || this.log && (a <= 0 || b <= 0)) return [];
87
- const label = row[time] instanceof Date ? dateLabel(row[time]) : String(row[time]);
88
- return [{
89
- key: `${row[series] ?? ""}/${at}`,
90
- name: String(row[series] ?? y),
91
- x: a,
92
- y: b,
93
- time: at,
94
- label
95
- }];
96
- });
97
- return [...group(parsed, (d) => d.name)].map(([key, items]) => {
98
- const sorted = [...items].sort((a, b) => a.time - b.time);
99
- return {
100
- key,
101
- stops: sorted.map((d, i) => ({
102
- ...d,
103
- share: sorted.length > 1 ? i / (sorted.length - 1) : 1,
104
- position: i
105
- }))
106
- };
107
- });
108
- }
109
- axis(values, range) {
110
- const [lo = this.log ? 1 : 0, hi = this.log ? 10 : 1] = extent(values);
111
- const pad = (hi - lo) * .05 || Math.abs(lo) * .1 || 1;
112
- const scale = Scales.continuous(this.options.scale).domain(this.log ? [lo / 1.05, hi * 1.05] : [lo - pad, hi + pad]).range(range);
113
- return this.log ? scale : scale.nice();
114
- }
115
- scales(ctx) {
116
- const stops = this.trails.flatMap((trail) => trail.stops);
117
- return {
118
- x: this.axis(stops.map((s) => s.x), [0, ctx.plot.width]),
119
- y: this.axis(stops.map((s) => s.y), [ctx.plot.height, 0])
120
- };
121
- }
122
- /** Where the drawn curve really passes a stop: B-splines cut inside their control points. */
123
- onCurve(stops, i) {
124
- const here = stops[i];
125
- if (this.options.curve !== CurveKind.Basis) return here;
126
- const before = stops[i - 1] ?? here, after = stops[i + 1] ?? here;
127
- return [(before[0] + 4 * here[0] + after[0]) / 6, (before[1] + 4 * here[1] + after[1]) / 6];
128
- }
129
- plotMarks(ctx, axes) {
130
- const { curve, dots, dates, arrows } = this.options;
131
- const trails = this.trails;
132
- const single = trails.length === 1;
133
- const cx = (s) => axes.x(s.x) ?? 0, cy = (s) => axes.y(s.y) ?? 0;
134
- const path = line().x(cx).y(cy).curve(Scales.curve(curve));
135
- const lines = ctx.marks("lines", "path", trails, (t) => t.key).attr("fill", "none").attr("stroke", (t) => ctx.palette.color(t.key)).attr("stroke-width", 2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
136
- lines.filter(function() {
137
- return !this.getAttribute("d");
138
- }).attr("d", (t) => path(t.stops) ?? "");
139
- ctx.drawOn(lines);
140
- ctx.set(lines, { d: (t) => path(t.stops) ?? "" });
141
- const heads = trails.flatMap((trail) => {
142
- const at = trail.stops.map((s) => [cx(s), cy(s)]);
143
- const every = Math.max(2, Math.ceil(at.length / 6));
144
- return arrows ? trail.stops.flatMap((stop, i) => {
145
- if (i === 0 || i >= at.length - 1 || i % every) return [];
146
- const before = this.onCurve(at, i - 1), after = this.onCurve(at, i + 1), place = this.onCurve(at, i);
147
- return [{
148
- key: stop.key,
149
- color: ctx.palette.color(trail.key),
150
- x: place[0],
151
- y: place[1],
152
- angle: Math.atan2(after[1] - before[1], after[0] - before[0]) * 180 / Math.PI
153
- }];
154
- }) : [];
155
- });
156
- const arrowMarks = ctx.marks("arrows", "path", heads, (d) => d.key).attr("fill", (d) => d.color).attr("stroke", ctx.theme.surface).attr("stroke-width", 1).attr("d", "M-6,-5L6,0L-6,5L-3,0Z");
157
- ctx.set(arrowMarks, { transform: (d) => `translate(${d.x},${d.y}) rotate(${d.angle})` });
158
- const dotted = trails.flatMap((trail) => trail.stops.filter((s, i) => dots === ConnectedDots.All || dots === ConnectedDots.Ends && (i === 0 || i === trail.stops.length - 1)).map((stop) => ({
159
- stop,
160
- trail
161
- })));
162
- const marks = ctx.marks("dots", "circle", dotted, (d) => d.stop.key).attr("stroke", ctx.theme.surface).attr("stroke-width", 2).attr("fill", (d) => single ? ctx.palette.sequential(.3 + d.stop.share * .7) : ctx.palette.color(d.trail.key));
163
- ctx.set(marks, {
164
- cx: (d) => cx(d.stop),
165
- cy: (d) => cy(d.stop),
166
- r: 5
167
- }, {
168
- cx: (d) => cx(d.stop),
169
- cy: (d) => cy(d.stop),
170
- r: 0
171
- });
172
- const noted = dates === ConnectedDates.None ? [] : trails.flatMap((trail) => {
173
- const every = Math.max(1, Math.ceil(trail.stops.length / 5)), last = trail.stops.length - 1;
174
- return trail.stops.filter((_, i) => i === 0 || i === last || dates === ConnectedDates.Periodic && i % every === 0).map((stop) => {
175
- const w = stop.label.length * 6.2;
176
- return {
177
- key: stop.key,
178
- text: stop.label,
179
- w,
180
- h: 12,
181
- x: Math.max(w / 2, Math.min(ctx.plot.width - w / 2, cx(stop))),
182
- y: cy(stop) < 18 ? cy(stop) + 15 : cy(stop) - 13
183
- };
184
- });
185
- });
186
- const notes = ctx.text(ctx.marks("dates", "text", TrendLabels.reject(noted), (d) => d.key), 11, "ink").attr("text-anchor", "middle").attr("dy", ".32em").attr("paint-order", "stroke").attr("stroke", ctx.theme.surface).attr("stroke-width", 3).text((d) => d.text);
187
- ctx.set(notes, {
188
- x: (d) => d.x,
189
- y: (d) => d.y
190
- }, {
191
- x: (d) => d.x,
192
- y: (d) => d.y
193
- });
194
- const stops = trails.flatMap((trail) => trail.stops.map((stop) => ({
195
- stop,
196
- trail
197
- })));
198
- const hits = ctx.marks("hits", "circle", stops, (d) => d.stop.key).attr("fill", "transparent").attr("r", 12).attr("cx", (d) => cx(d.stop)).attr("cy", (d) => cy(d.stop));
199
- ctx.hover(hits, ({ stop, trail }) => ({
200
- title: stop.label,
201
- color: ctx.palette.color(trail.key),
202
- rows: [[this.options.xLabel ?? this.options.x, TrendHover.value(stop.x)], [this.options.yLabel ?? this.options.y, TrendHover.value(stop.y)]]
203
- }));
204
- }
205
- };
206
- export { ConnectedScatterTime };
@@ -1,153 +0,0 @@
1
- import { Chart2D } from "../../core/Chart2D.js";
2
- import { ChartFamily, CurveKind, DataShape, Dimension, LegendPosition } from "../../core/enums.js";
3
- import { Scales } from "../../core/Scales.js";
4
- import { SampleData } from "../../data/SampleData.js";
5
- import { FacetScale, LineAggregate } from "./LineEnums.js";
6
- import { TrendHover } from "./TrendHover.js";
7
- import { TrendLabels } from "./TrendLabels.js";
8
- import { TrendTable } from "./TrendTable.js";
9
- import { area, extent, line, scaleLinear, select, ticks, utcFormat } from "d3";
10
- // src/charts/linesareas/SmallMultipleLines.ts
11
- var HEAD = 16;
12
- var GAP_X = 18;
13
- var AXIS = 16;
14
- var YAXIS = 26;
15
- var shortDate = utcFormat("%b %-d");
16
- /** One small chart per series on shared axes. The fix for spaghetti: use it whenever a multi-line chart has more than about six lines. */
17
- var SmallMultipleLines = class SmallMultipleLines extends Chart2D {
18
- static meta = {
19
- id: "small-multiple-lines",
20
- name: "Small multiple lines",
21
- family: ChartFamily.Trend,
22
- dimension: Dimension.Two,
23
- shape: DataShape.Table,
24
- description: "Splits series into a grid of small line charts on shared scales, comparing many series without tangling them.",
25
- tags: [
26
- "trellis",
27
- "facets",
28
- "lattice",
29
- "panel"
30
- ],
31
- sample: (seed) => SampleData.timeSeries(seed, 40, 6),
32
- variants: {
33
- columns: [
34
- 3,
35
- 2,
36
- 1
37
- ],
38
- yScale: [FacetScale.Shared, FacetScale.Free],
39
- context: [true, false],
40
- fill: [false, true],
41
- curve: [
42
- CurveKind.Monotone,
43
- CurveKind.Linear,
44
- CurveKind.StepAfter
45
- ]
46
- },
47
- valid: ({ yScale, context }) => yScale === FacetScale.Shared || !context
48
- };
49
- defaults() {
50
- return {
51
- x: "date",
52
- y: "value",
53
- series: "series",
54
- aggregate: LineAggregate.Mean,
55
- curve: CurveKind.Monotone,
56
- yScale: FacetScale.Shared,
57
- context: true,
58
- fill: false
59
- };
60
- }
61
- get legendPosition() {
62
- return LegendPosition.None;
63
- }
64
- legendItems() {
65
- return [];
66
- }
67
- plotMargin() {
68
- return {
69
- top: 6,
70
- right: 12,
71
- bottom: 6,
72
- left: 12
73
- };
74
- }
75
- static range(points, zero) {
76
- const [lo = 0, hi = 1] = extent(points.flatMap((p) => p.y === null ? [] : zero ? [p.y, 0] : [p.y]));
77
- return lo === hi ? [lo - 1, hi + 1] : [lo, hi];
78
- }
79
- static tick(x) {
80
- return x instanceof Date ? shortDate(x) : String(x);
81
- }
82
- draw(ctx) {
83
- const { x, y, series, aggregate, curve, yScale, context, fill } = this.options;
84
- const table = new TrendTable(this.options.data, {
85
- x,
86
- y,
87
- series,
88
- aggregate
89
- });
90
- const lines = table.series;
91
- const { width, height } = ctx.plot;
92
- const auto = Math.max(1, Math.round(Math.sqrt(lines.length * width / (height * 1.6))));
93
- const columns = Math.max(1, Math.min(this.options.columns ?? auto, lines.length || 1));
94
- const rows = Math.max(1, Math.ceil(lines.length / columns));
95
- const cellWidth = (width - GAP_X * (columns - 1)) / columns;
96
- const gap = rows > 3 ? 3 : 10;
97
- const innerWidth = Math.max(10, cellWidth - YAXIS), innerHeight = Math.max(8, (height - AXIS - gap * (rows - 1)) / rows - HEAD);
98
- const px = table.xScale([0, innerWidth]);
99
- const shared = SmallMultipleLines.range(lines.flatMap((s) => s.points), fill);
100
- const facet = ctx.marks("facets", "g", lines, (s) => s.key).attr("transform", (_, i) => `translate(${i % columns * (cellWidth + GAP_X) + YAXIS},${Math.floor(i / columns) * (innerHeight + HEAD + gap) + HEAD})`);
101
- const chart = this;
102
- facet.each(function(s, i) {
103
- const group = select(this);
104
- const domain = yScale === FacetScale.Shared ? shared : SmallMultipleLines.range(s.points, fill);
105
- const py = scaleLinear(domain, [innerHeight, 0]).nice();
106
- const ownColumn = i % columns === 0 || yScale === FacetScale.Free, bottom = i + columns >= lines.length;
107
- chart.frame(ctx, group, s, py, innerWidth, innerHeight, ownColumn, bottom ? [table.xs[0], table.xs.at(-1)].flatMap((p) => p ?? []) : []);
108
- const known = (p) => p.y !== null;
109
- const path = line().defined(known).x((p) => px(p.x)).y((p) => py(p.y)).curve(Scales.curve(curve));
110
- const ghosts = ctx.marks("ghosts", "path", context ? lines.filter((other) => other !== s) : [], (o) => o.key, group).attr("fill", "none").attr("stroke", ctx.theme.grid).attr("stroke-width", 1.5);
111
- ctx.set(ghosts, { d: (o) => path(o.points) ?? "" });
112
- const color = ctx.palette.color(s.key);
113
- const base = py(Math.max(py.domain()[0], 0));
114
- const under = area().defined(known).x((p) => px(p.x)).y0(base).y1((p) => py(p.y)).curve(Scales.curve(curve));
115
- const flat = area().defined(known).x((p) => px(p.x)).y(base).curve(Scales.curve(curve));
116
- ctx.set(ctx.marks("fill", "path", fill ? [s] : [], void 0, group).attr("fill", color).attr("fill-opacity", .22), { d: under(s.points) ?? "" }, { d: flat(s.points) ?? "" });
117
- const stroke = ctx.marks("line", "path", [s], void 0, group).attr("fill", "none").attr("stroke", color).attr("stroke-width", 2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
118
- stroke.filter(function() {
119
- return !this.getAttribute("d");
120
- }).attr("d", path(s.points) ?? "");
121
- ctx.drawOn(stroke);
122
- ctx.set(stroke, { d: path(s.points) ?? "" });
123
- const last = s.points.filter(known).at(-1);
124
- const end = ctx.marks("end", "circle", last ? [last] : [], void 0, group).attr("fill", color).attr("stroke", ctx.theme.surface).attr("stroke-width", 2);
125
- ctx.set(end, {
126
- cx: (p) => px(p.x),
127
- cy: (p) => py(p.y),
128
- r: 5
129
- }, {
130
- cx: (p) => px(p.x),
131
- cy: (p) => py(p.y),
132
- r: 0
133
- });
134
- TrendHover.attach(ctx, TrendHover.slices([s], {
135
- place: (p) => [px(p.x), py(p.y)],
136
- color: () => color
137
- }), innerWidth, innerHeight, group);
138
- });
139
- }
140
- frame(ctx, group, s, py, width, height, showY, xTicks) {
141
- const [lo, hi] = py.domain();
142
- const room = Math.max(1, Math.floor(height / 14));
143
- const candidates = ticks(lo, hi, Math.min(4, room));
144
- const levels = candidates.filter((_, n) => (candidates.length - 1 - n) % Math.ceil(candidates.length / room) === 0);
145
- ctx.marks("grid", "line", levels, (v) => v, group).attr("stroke", ctx.theme.grid).attr("x1", 0).attr("x2", width).attr("y1", py).attr("y2", py);
146
- ctx.text(ctx.marks("y-ticks", "text", showY ? levels : [], (v) => v, group), 10).attr("x", -4).attr("y", py).attr("dy", ".32em").attr("text-anchor", "end").text((v) => Scales.format(v, Math.max(Math.abs(lo), Math.abs(hi))));
147
- ctx.marks("axis", "line", [0], void 0, group).attr("stroke", ctx.theme.axis).attr("x1", 0).attr("x2", width).attr("y1", height).attr("y2", height);
148
- const dated = width >= 80 ? xTicks : xTicks.slice(0, 1);
149
- ctx.text(ctx.marks("x-ticks", "text", dated, (p) => p.order, group), 10).attr("x", (_, i) => i ? width : 0).attr("y", height + 12).attr("text-anchor", (_, i) => i ? "end" : "start").text((p) => SmallMultipleLines.tick(p.x));
150
- ctx.text(ctx.marks("head", "text", [s.key], void 0, group), 11, "ink").attr("x", 0).attr("y", -5).attr("font-weight", 600).text((key) => TrendLabels.fit(key, width));
151
- }
152
- };
153
- export { SmallMultipleLines };
@@ -1,234 +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 { MathNumerics } from "./MathNumerics.js";
5
- import { BufferGeometry, Color, DoubleSide, Float32BufferAttribute, InstancedMesh, LineBasicMaterial, LineSegments, Mesh, MeshStandardMaterial, Object3D, SphereGeometry } from "three";
6
- // src/charts/mathematical/ParametricSurface3D.ts
7
- var SurfaceForm = /* @__PURE__ */ function(SurfaceForm) {
8
- SurfaceForm["Torus"] = "torus";
9
- SurfaceForm["Mobius"] = "mobius";
10
- SurfaceForm["Klein"] = "klein";
11
- SurfaceForm["Seashell"] = "seashell";
12
- SurfaceForm["Enneper"] = "enneper";
13
- SurfaceForm["Helicoid"] = "helicoid";
14
- SurfaceForm["Dini"] = "dini";
15
- SurfaceForm["Boy"] = "boy";
16
- return SurfaceForm;
17
- }({});
18
- var SurfaceRender = /* @__PURE__ */ function(SurfaceRender) {
19
- SurfaceRender["Solid"] = "solid";
20
- SurfaceRender["Mesh"] = "mesh";
21
- SurfaceRender["Dots"] = "dots";
22
- return SurfaceRender;
23
- }({});
24
- var TAU = Math.PI * 2;
25
- var U = 150;
26
- var V = 60;
27
- function named(form, a, b) {
28
- const { sin, cos, tan, log, exp } = Math;
29
- switch (form) {
30
- case "mobius": return {
31
- u: [0, TAU],
32
- v: [-1, 1],
33
- fn: (u, v) => [
34
- (1 + v / 2 * cos(u / 2)) * cos(u),
35
- (1 + v / 2 * cos(u / 2)) * sin(u),
36
- v / 2 * sin(u / 2)
37
- ]
38
- };
39
- case "klein": return {
40
- u: [0, TAU],
41
- v: [0, TAU],
42
- fn: (u, v) => {
43
- const r = 2 + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v);
44
- return [
45
- r * cos(u),
46
- r * sin(u),
47
- sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v)
48
- ];
49
- }
50
- };
51
- case "seashell": return {
52
- u: [0, 3 * TAU],
53
- v: [0, TAU],
54
- fn: (u, v) => {
55
- const g = exp(u / 7), r = g * (1 + .55 * cos(v));
56
- return [
57
- r * cos(u),
58
- r * sin(u),
59
- g * (.55 * sin(v)) - g * 1.6
60
- ];
61
- }
62
- };
63
- case "enneper": return {
64
- u: [-1.6, 1.6],
65
- v: [-1.6, 1.6],
66
- fn: (u, v) => [
67
- u - u ** 3 / 3 + u * v * v,
68
- v - v ** 3 / 3 + v * u * u,
69
- u * u - v * v
70
- ]
71
- };
72
- case "helicoid": return {
73
- u: [-TAU, TAU],
74
- v: [-1.6, 1.6],
75
- fn: (u, v) => [
76
- v * cos(u * b),
77
- v * sin(u * b),
78
- u / 2.4
79
- ]
80
- };
81
- case "dini": return {
82
- u: [0, 2.5 * TAU],
83
- v: [.08, 2],
84
- fn: (u, v) => [
85
- cos(u) * sin(v),
86
- sin(u) * sin(v),
87
- cos(v) + log(tan(v / 2)) + .18 * u
88
- ]
89
- };
90
- case "boy": return {
91
- u: [0, Math.PI],
92
- v: [0, Math.PI],
93
- fn: (u, v) => {
94
- const c = cos(u), s = sin(u), cv = cos(v), q = 2 ** .5, d = 2 - q * sin(3 * u) * sin(2 * v);
95
- return [
96
- (q * cv * cv * cos(2 * u) + c * sin(2 * v)) / d,
97
- (q * cv * cv * sin(2 * u) - s * sin(2 * v)) / d,
98
- 3 * cv * cv / d
99
- ];
100
- }
101
- };
102
- default: return {
103
- u: [0, TAU],
104
- v: [0, TAU],
105
- fn: (u, v) => [
106
- (a + b * cos(v)) * cos(u),
107
- (a + b * cos(v)) * sin(u),
108
- b * sin(v)
109
- ]
110
- };
111
- }
112
- }
113
- /** Surfaces given by two parameters, including one-sided and self-crossing forms that no height map can draw. */
114
- var ParametricSurface3D = class extends Chart3D {
115
- static meta = {
116
- id: "parametric-surface-3d",
117
- name: "Parametric surface",
118
- family: ChartFamily.Mathematical,
119
- dimension: Dimension.Three,
120
- shape: DataShape.Function,
121
- description: "Renders a surface in (u, v) as a solid, a mesh or a point cloud, from named forms such as the Möbius strip and Klein bottle.",
122
- tags: [
123
- "mobius",
124
- "klein bottle",
125
- "torus",
126
- "minimal surface",
127
- "topology"
128
- ],
129
- sample: (seed) => SampleData.categories(seed, 1, 1).map((row) => ({
130
- name: String(row.category),
131
- a: 2,
132
- b: .6 + +row.value % 5 * .08
133
- })),
134
- variants: {
135
- form: Object.values(SurfaceForm),
136
- render: Object.values(SurfaceRender),
137
- sweep: [1, .7]
138
- }
139
- };
140
- defaults() {
141
- return {
142
- form: "torus",
143
- render: "solid",
144
- sweep: 1,
145
- azimuth: 35,
146
- elevation: 28,
147
- distance: 3.9
148
- };
149
- }
150
- grid(spec) {
151
- const { form, sweep } = this.options;
152
- const base = named(form, spec.a ?? 2, spec.b ?? .7);
153
- const fn = spec.fn ?? base.fn, u = spec.u ?? base.u, v = spec.v ?? base.v;
154
- const us = MathNumerics.linspace(u[0], u[0] + (u[1] - u[0]) * sweep, U), vs = MathNumerics.linspace(v[0], v[1], V);
155
- return us.map((a) => vs.map((b) => fn(a, b).map((c) => Number.isFinite(c) ? c : 0)));
156
- }
157
- build(ctx) {
158
- const { render, data } = this.options;
159
- const spec = data[0];
160
- if (!spec) return;
161
- const grid = this.grid(spec);
162
- const flat = grid.flat();
163
- const axis = (k) => {
164
- const values = flat.map((p) => p[k]);
165
- return [Math.min(...values), Math.max(...values)];
166
- };
167
- const [a0, a1] = axis(0), [b0, b1] = axis(1), [c0, c1] = axis(2);
168
- const unit = 1.9 / Math.max(a1 - a0, b1 - b0, c1 - c0, 1e-6);
169
- const positions = (p) => [
170
- (p[0] - (a0 + a1) / 2) * unit,
171
- (p[2] - (c0 + c1) / 2) * unit,
172
- (p[1] - (b0 + b1) / 2) * unit
173
- ];
174
- const tone = (i) => new Color(ctx.palette.sequential(.25 + .75 * i / 149)).toArray();
175
- const vertices = grid.flatMap((line) => line.flatMap(positions));
176
- const colors = grid.flatMap((line, i) => line.flatMap(() => tone(i)));
177
- const tag = () => ({
178
- title: spec.name,
179
- rows: [["Vertices", 9e3]]
180
- });
181
- if (render === "dots") {
182
- const picked = flat.filter((_, i) => i % 3 === 0);
183
- const cloud = new InstancedMesh(new SphereGeometry(.014, 6, 5), new MeshStandardMaterial({ roughness: .5 }), picked.length);
184
- const dummy = new Object3D();
185
- picked.forEach((p, i) => {
186
- dummy.position.set(...positions(p));
187
- dummy.updateMatrix();
188
- cloud.setMatrixAt(i, dummy.matrix);
189
- cloud.setColorAt(i, new Color(...tone(Math.floor(i * 3 / V))));
190
- });
191
- cloud.castShadow = true;
192
- ctx.reveal((progress) => {
193
- cloud.count = Math.max(1, Math.floor(picked.length * progress));
194
- }, 1.6);
195
- ctx.root.add(cloud);
196
- ctx.pick(cloud, tag);
197
- return;
198
- }
199
- const geometry = new BufferGeometry();
200
- geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
201
- geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));
202
- if (render === "mesh") {
203
- const pairs = [];
204
- for (let i = 0; i < U; i++) for (let j = 0; j < V; j++) {
205
- const at = i * V + j;
206
- if (j % 4 === 0 && i < 149) pairs.push(at, at + V);
207
- if (i % 6 === 0 && j < 59) pairs.push(at, at + 1);
208
- }
209
- geometry.setIndex(pairs);
210
- const lines = new LineSegments(geometry, new LineBasicMaterial({ vertexColors: true }));
211
- ctx.reveal((progress) => geometry.setDrawRange(0, Math.floor(pairs.length * progress)), 1.6);
212
- ctx.root.add(lines);
213
- return;
214
- }
215
- const faces = [];
216
- for (let i = 0; i < 149; i++) for (let j = 0; j < 59; j++) {
217
- const p = i * V + j;
218
- faces.push(p, p + V, p + 1, p + 1, p + V, p + V + 1);
219
- }
220
- geometry.setIndex(faces);
221
- geometry.computeVertexNormals();
222
- const mesh = new Mesh(geometry, new MeshStandardMaterial({
223
- vertexColors: true,
224
- side: DoubleSide,
225
- roughness: .48,
226
- metalness: .05
227
- }));
228
- mesh.castShadow = mesh.receiveShadow = true;
229
- ctx.reveal((progress) => geometry.setDrawRange(0, Math.floor(faces.length * progress)), 1.4);
230
- ctx.root.add(mesh);
231
- ctx.pick(mesh, tag);
232
- }
233
- };
234
- export { ParametricSurface3D, SurfaceForm, SurfaceRender };