@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.
- package/README.md +111 -14
- package/dist/ExcelWriter-3ZSYUH4T.cjs +154 -0
- package/dist/GraphType.js +24 -38
- package/dist/PdfWriter-6HJFYMCO.cjs +205 -0
- package/dist/catalog-YWX6FHRM.cjs +8 -0
- package/dist/catalog.js +5 -1
- package/dist/charts/bars/index.js +2 -12
- package/dist/charts/comparison/EffectForestPlot.js +1 -1
- package/dist/charts/comparison/index.js +1 -8
- package/dist/charts/demography/Nomogram.js +3 -3
- package/dist/charts/density/HexbinChart.js +6 -4
- package/dist/charts/diagrams/ArchitectureCanvas.js +68 -0
- package/dist/charts/diagrams/ArchitectureDiagram.js +331 -0
- package/dist/charts/diagrams/ArchitectureLayout.js +106 -0
- package/dist/charts/diagrams/ArchitectureLinkLabels.js +78 -0
- package/dist/charts/diagrams/ArchitectureModel.js +108 -0
- package/dist/charts/diagrams/ArchitectureRouter.js +348 -0
- package/dist/charts/diagrams/ArchitectureSamples.js +312 -0
- package/dist/charts/diagrams/ArchitectureShapes.js +130 -0
- package/dist/charts/diagrams/ArchitectureText.js +25 -0
- package/dist/charts/diagrams/DiagramText.js +38 -0
- package/dist/charts/diagrams/EntityRelationshipDiagram.js +465 -0
- package/dist/charts/diagrams/ErCrowsFoot.js +33 -0
- package/dist/charts/diagrams/ErSamples.js +205 -0
- package/dist/charts/diagrams/ErSchema.js +122 -0
- package/dist/charts/diagrams/LogicCircuit.js +154 -0
- package/dist/charts/diagrams/LogicCircuitLayout.js +600 -0
- package/dist/charts/diagrams/LogicCircuitSamples.js +66 -0
- package/dist/charts/diagrams/LogicGateDiagram.js +216 -0
- package/dist/charts/diagrams/LogicGateSymbol.js +113 -0
- package/dist/charts/diagrams/NetworkTopologyDiagram.js +247 -0
- package/dist/charts/diagrams/SequenceDiagram.js +351 -0
- package/dist/charts/diagrams/SequenceLayout.js +422 -0
- package/dist/charts/diagrams/SequenceModel.js +221 -0
- package/dist/charts/diagrams/TopologyLayout.js +143 -0
- package/dist/charts/diagrams/architectureEnums.js +50 -0
- package/dist/charts/diagrams/index.js +26 -0
- package/dist/charts/diagrams/logicEnums.js +42 -0
- package/dist/charts/diagrams/sequenceEnums.js +40 -0
- package/dist/charts/distribution/HistogramChart.js +25 -3
- package/dist/charts/distribution/index.js +1 -3
- package/dist/charts/earthscience/HovmollerDiagram.js +477 -0
- package/dist/charts/earthscience/HovmollerEnums.js +42 -0
- package/dist/charts/earthscience/HovmollerField.js +180 -0
- package/dist/charts/earthscience/HovmollerSample.js +40 -0
- package/dist/charts/earthscience/HovmollerSpeed.js +71 -0
- package/dist/charts/earthscience/index.js +10 -2
- package/dist/charts/engineering/ConstellationDiagram.js +26 -6
- package/dist/charts/engineering/EyeDiagram.js +2 -1
- package/dist/charts/engineering/PoleZeroPlot.js +32 -8
- package/dist/charts/financial/RelativeStrengthRotation.js +434 -0
- package/dist/charts/financial/RelativeStrengthRotationMath.js +71 -0
- package/dist/charts/financial/RelativeStrengthRotationSamples.js +27 -0
- package/dist/charts/financial/index.js +5 -3
- package/dist/charts/flow/index.js +1 -5
- package/dist/charts/frameworks/AnsoffMatrix.js +523 -0
- package/dist/charts/frameworks/FrameworkText.js +98 -0
- package/dist/charts/frameworks/NpsGauge.js +279 -0
- package/dist/charts/frameworks/NpsSurvey.js +58 -0
- package/dist/charts/frameworks/PerceptualMap.js +419 -0
- package/dist/charts/frameworks/PerceptualProjection.js +142 -0
- package/dist/charts/frameworks/PositioningSamples.js +191 -0
- package/dist/charts/frameworks/RaciMatrix.js +458 -0
- package/dist/charts/frameworks/RaciPlan.js +81 -0
- package/dist/charts/frameworks/RaciSamples.js +76 -0
- package/dist/charts/frameworks/SwotMatrix.js +358 -0
- package/dist/charts/frameworks/SwotSamples.js +85 -0
- package/dist/charts/frameworks/VanWestendorpChart.js +187 -0
- package/dist/charts/frameworks/VanWestendorpSurvey.js +197 -0
- package/dist/charts/frameworks/index.js +26 -0
- package/dist/charts/frameworks/raciEnums.js +30 -0
- package/dist/charts/frameworks/swotEnums.js +34 -0
- package/dist/charts/genomics/CircosPlot.js +1 -1
- package/dist/charts/geoflows/GeoFlowChart.js +2 -2
- package/dist/charts/geoflows/GeoFlowSample.js +2 -1
- package/dist/charts/geomaps/FloorPlanMap.js +324 -0
- package/dist/charts/geomaps/FloorPlanModel.js +179 -0
- package/dist/charts/geomaps/FloorPlanSamples.js +416 -0
- package/dist/charts/geomaps/GeoLand.js +2 -2
- package/dist/charts/geomaps/GeoSamples.js +2 -1
- package/dist/charts/geomaps/GraticuleMap.js +2 -2
- package/dist/charts/geomaps/RoomLabelFit.js +200 -0
- package/dist/charts/geomaps/TissotMap.js +2 -2
- package/dist/charts/geomaps/index.js +8 -4
- package/dist/charts/hierarchy/SunburstChart.js +17 -10
- package/dist/charts/hierarchy/index.js +2 -11
- package/dist/charts/indicators/BulletChart.js +8 -2
- package/dist/charts/indicators/SpeedometerChart.js +1 -1
- package/dist/charts/indicators/ThermometerChart.js +1 -1
- package/dist/charts/lifescience/LoessFit.js +113 -0
- package/dist/charts/lifescience/MaPlot.js +337 -0
- package/dist/charts/lifescience/MaPlotSamples.js +35 -0
- package/dist/charts/lifescience/OncoGlyph.js +137 -0
- package/dist/charts/lifescience/OncoPrint.js +373 -0
- package/dist/charts/lifescience/OncoPrintMatrix.js +107 -0
- package/dist/charts/lifescience/OncoPrintSamples.js +142 -0
- package/dist/charts/lifescience/PedigreeChart.js +306 -0
- package/dist/charts/lifescience/PedigreeLayout.js +261 -0
- package/dist/charts/lifescience/PedigreeRows.js +70 -0
- package/dist/charts/lifescience/PedigreeSamples.js +161 -0
- package/dist/charts/lifescience/PedigreeSymbol.js +47 -0
- package/dist/charts/lifescience/RamachandranPlot.js +364 -0
- package/dist/charts/lifescience/RamachandranRegions.js +2712 -0
- package/dist/charts/lifescience/RamachandranSamples.js +235 -0
- package/dist/charts/lifescience/index.js +25 -0
- package/dist/charts/lifescience/pedigreeEnums.js +21 -0
- package/dist/charts/lifescience/ramachandranEnums.js +34 -0
- package/dist/charts/linesareas/DualAxisChart.js +1 -1
- package/dist/charts/linesareas/LineEnums.js +1 -15
- package/dist/charts/linesareas/MultiLineChart.js +1 -1
- package/dist/charts/linesareas/TrendChart.js +15 -5
- package/dist/charts/linesareas/index.js +2 -6
- package/dist/charts/massive/MassiveChart.js +3 -2
- package/dist/charts/mathematical/FourierSeriesChart.js +7 -1
- package/dist/charts/mathematical/index.js +2 -6
- package/dist/charts/matrix/GridPlot.js +27 -2
- package/dist/charts/matrix/TilegramChart.js +2 -2
- package/dist/charts/mlcharts/AttentionGrid.js +79 -0
- package/dist/charts/mlcharts/AttentionHeatmap.js +329 -0
- package/dist/charts/mlcharts/AttentionModel.js +132 -0
- package/dist/charts/mlcharts/AttentionSamples.js +82 -0
- package/dist/charts/mlcharts/CellNumber.js +8 -0
- package/dist/charts/mlcharts/CurveDiagnosticSamples.js +95 -0
- package/dist/charts/mlcharts/CurvePickMark.js +31 -0
- package/dist/charts/mlcharts/DecisionBoundaryChart.js +316 -0
- package/dist/charts/mlcharts/DecisionSamples.js +60 -0
- package/dist/charts/mlcharts/DecisionSurface.js +130 -0
- package/dist/charts/mlcharts/DistinctTicks.js +13 -0
- package/dist/charts/mlcharts/ElbowMath.js +153 -0
- package/dist/charts/mlcharts/ElbowPlot.js +273 -0
- package/dist/charts/mlcharts/ExplainabilitySamples.js +70 -0
- package/dist/charts/mlcharts/FeatureImportanceChart.js +150 -0
- package/dist/charts/mlcharts/ImportanceRanking.js +98 -0
- package/dist/charts/mlcharts/LearningCurveChart.js +276 -0
- package/dist/charts/mlcharts/LearningCurveMath.js +92 -0
- package/dist/charts/mlcharts/PartialDependence.js +92 -0
- package/dist/charts/mlcharts/PartialDependencePlot.js +225 -0
- package/dist/charts/mlcharts/WideLabel.js +28 -0
- package/dist/charts/mlcharts/curveDiagnosticEnums.js +37 -0
- package/dist/charts/mlcharts/index.js +32 -0
- package/dist/charts/proportion/index.js +5 -9
- package/dist/charts/scatter/CategoryScatterBase.js +1 -4
- package/dist/charts/scatter/ConnectedScatter.js +7 -4
- package/dist/charts/scatter/MarginalScatter.js +13 -8
- package/dist/charts/scatter/index.js +4 -17
- package/dist/charts/scientific/SpectrogramChart.js +9 -3
- package/dist/charts/scientific/index.js +2 -2
- package/dist/charts/signals/index.js +3 -13
- package/dist/charts/statistics/LorenzCurve.js +7 -4
- package/dist/charts/threebars/Candlestick3DChart.js +18 -2
- package/dist/charts/threeglobe/GlobeChart.js +2 -2
- package/dist/charts/threeglobe/GlobeSamples.js +2 -1
- package/dist/charts/threeglobe/RingGlobe.js +1 -1
- package/dist/charts/threenetwork/ConeTreeChart.js +2 -1
- package/dist/charts/threenetwork/Gantt3DChart.js +3 -2
- package/dist/charts/threesurfaces/Ridgeline3DChart.js +22 -4
- package/dist/charts/threevolume/LorenzAttractor.js +19 -0
- package/dist/charts/threevolume/VolumeRaycastChart.js +4 -3
- package/dist/charts/threevolume/volumeEnums.js +1 -0
- package/dist/charts/timeline/index.js +2 -10
- package/dist/chunk-753UBLV2.cjs +33 -0
- package/dist/chunk-VX54A7KA.cjs +17 -0
- package/dist/{chunk-W5GAAAZY.cjs → chunk-WAODDPYX.cjs} +24874 -17620
- package/dist/chunk-Z3JPIJSC.cjs +338 -0
- package/dist/core/CartesianChart.js +87 -11
- package/dist/core/Chart.js +63 -15
- package/dist/core/Chart2D.js +54 -17
- package/dist/core/Chart3D.js +56 -20
- package/dist/core/ChartExportError.js +2 -0
- package/dist/core/ChartExporter.js +50 -8
- package/dist/core/ColumnCheck.js +53 -0
- package/dist/core/Context2D.js +29 -15
- package/dist/core/Context3D.js +7 -2
- package/dist/core/ExcelWriter.js +152 -0
- package/dist/core/ExportText.js +28 -0
- package/dist/core/MarkOrigin.js +88 -0
- package/dist/core/MarkStyle.js +294 -0
- package/dist/core/Palette.js +27 -7
- package/dist/core/PdfPage.js +13 -0
- package/dist/core/PdfWriter.js +245 -0
- package/dist/core/Scales.js +52 -2
- package/dist/core/SceneOverlay.js +4 -4
- package/dist/core/TextFit.js +37 -0
- package/dist/core/Theme.js +28 -1
- package/dist/core/enums.js +33 -1
- package/dist/core/pathMorph.js +15 -0
- package/dist/data/SampleData.js +1 -17
- package/dist/data/WorldSample.js +23 -0
- package/dist/index.cjs +810 -691
- package/dist/index.d.cts +8390 -2925
- package/dist/index.d.ts +8392 -2927
- package/dist/index.js +106 -56
- package/dist/react/ChartView.js +18 -8
- package/dist/react/GraphHandle.js +2 -0
- package/dist/react/components.js +74 -116
- package/package.json +13 -3
- package/dist/catalog-4UP2YFNR.cjs +0 -7
- package/dist/charts/bars/BulletBar.js +0 -184
- package/dist/charts/bars/ErrorBarColumn.js +0 -147
- package/dist/charts/bars/HistogramBar.js +0 -217
- package/dist/charts/bars/MarimekkoBar.js +0 -191
- package/dist/charts/bars/ParetoBar.js +0 -143
- package/dist/charts/comparison/PanelChart.js +0 -70
- package/dist/charts/comparison/SmallMultipleBars.js +0 -134
- package/dist/charts/comparison/SpanChart.js +0 -118
- package/dist/charts/comparison/TrellisChart.js +0 -158
- package/dist/charts/distribution/RidgeSlabs3DChart.js +0 -169
- package/dist/charts/financial/Candlestick3D.js +0 -157
- package/dist/charts/flow/BumpFlow.js +0 -212
- package/dist/charts/flow/StreamFlow.js +0 -174
- package/dist/charts/geomaps/ThiessenMap.js +0 -106
- package/dist/charts/hierarchy/ConeTree3D.js +0 -135
- package/dist/charts/hierarchy/Hierarchy3DChart.js +0 -27
- package/dist/charts/hierarchy/SpherePack3D.js +0 -81
- package/dist/charts/hierarchy/SunburstTower3D.js +0 -93
- package/dist/charts/hierarchy/TreemapSkyline3D.js +0 -98
- package/dist/charts/linesareas/ConnectedScatterTime.js +0 -206
- package/dist/charts/linesareas/SmallMultipleLines.js +0 -153
- package/dist/charts/mathematical/ParametricSurface3D.js +0 -234
- package/dist/charts/mathematical/StrangeAttractor3D.js +0 -251
- package/dist/charts/proportion/ConeFunnel.js +0 -126
- package/dist/charts/proportion/ExtrudedPieChart.js +0 -123
- package/dist/charts/scatter/BeeswarmScatter.js +0 -151
- package/dist/charts/scatter/BinnedScatterBase.js +0 -51
- package/dist/charts/scatter/ContourScatter.js +0 -116
- package/dist/charts/scatter/GridBinScatter.js +0 -98
- package/dist/charts/scatter/HexbinScatter.js +0 -74
- package/dist/charts/scatter/StripScatter.js +0 -107
- package/dist/charts/scatter/SunflowerScatter.js +0 -109
- package/dist/charts/signals/ConstellationChart.js +0 -153
- package/dist/charts/signals/CorrelogramChart.js +0 -171
- package/dist/charts/signals/EyeDiagramChart.js +0 -155
- package/dist/charts/signals/PoleZeroChart.js +0 -164
- package/dist/charts/signals/SpectrogramChart.js +0 -79
- package/dist/charts/timeline/CalendarSkylineChart.js +0 -128
- package/dist/charts/timeline/ScheduleBlocksChart.js +0 -119
- package/dist/charts/timeline/SpiralTimeline.js +0 -154
- package/dist/charts/timeline/StreamTimeline.js +0 -141
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { Chart3D } from "../../core/Chart3D.js";
|
|
2
|
-
import { ChartFamily, DataShape, Dimension, ScaleKind } from "../../core/enums.js";
|
|
3
|
-
import { SampleData } from "../../data/SampleData.js";
|
|
4
|
-
import { CalendarWeekStart } from "./CalendarHeatmap.js";
|
|
5
|
-
import { TimeRows } from "./TimeRows.js";
|
|
6
|
-
import { rollup, scaleLinear, scalePow, sum, utcDay, utcMonday, utcSunday } from "d3";
|
|
7
|
-
import { BoxGeometry, CylinderGeometry, InstancedMesh, Mesh, MeshStandardMaterial, Object3D, PlaneGeometry } from "three";
|
|
8
|
-
// src/charts/timeline/CalendarSkylineChart.ts
|
|
9
|
-
var SkylineShape = /* @__PURE__ */ function(SkylineShape) {
|
|
10
|
-
SkylineShape["Block"] = "blocks";
|
|
11
|
-
SkylineShape["Column"] = "columns";
|
|
12
|
-
return SkylineShape;
|
|
13
|
-
}({});
|
|
14
|
-
var BASE = -.7;
|
|
15
|
-
var MONTH_NAMES = [
|
|
16
|
-
"Jan",
|
|
17
|
-
"Feb",
|
|
18
|
-
"Mar",
|
|
19
|
-
"Apr",
|
|
20
|
-
"May",
|
|
21
|
-
"Jun",
|
|
22
|
-
"Jul",
|
|
23
|
-
"Aug",
|
|
24
|
-
"Sep",
|
|
25
|
-
"Oct",
|
|
26
|
-
"Nov",
|
|
27
|
-
"Dec"
|
|
28
|
-
];
|
|
29
|
-
/** A year of daily activity as a city: weeks run along the floor and each day rises by its value. */
|
|
30
|
-
var CalendarSkylineChart = class extends Chart3D {
|
|
31
|
-
static meta = {
|
|
32
|
-
id: "calendar-skyline",
|
|
33
|
-
name: "Calendar skyline",
|
|
34
|
-
family: ChartFamily.Temporal,
|
|
35
|
-
dimension: Dimension.Three,
|
|
36
|
-
shape: DataShape.Table,
|
|
37
|
-
description: "Raises a calendar grid into 3D so that peak days stand out as towers above the year.",
|
|
38
|
-
tags: [
|
|
39
|
-
"contribution",
|
|
40
|
-
"daily",
|
|
41
|
-
"skyline",
|
|
42
|
-
"city"
|
|
43
|
-
],
|
|
44
|
-
sample: (seed) => SampleData.timeSeries(seed, 280, 1).map((row, i, rows) => ({
|
|
45
|
-
date: row.date,
|
|
46
|
-
value: +(.5 + Math.min(3, Math.abs(+row.value - +(rows[i - 1]?.value ?? row.value))) * (row.date.getUTCDay() % 6 ? 2 : .6)).toFixed(1)
|
|
47
|
-
})),
|
|
48
|
-
variants: {
|
|
49
|
-
shape: Object.values(SkylineShape),
|
|
50
|
-
weekStart: Object.values(CalendarWeekStart),
|
|
51
|
-
scale: [ScaleKind.Linear, ScaleKind.Sqrt]
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
defaults() {
|
|
55
|
-
return {
|
|
56
|
-
date: "date",
|
|
57
|
-
value: "value",
|
|
58
|
-
shape: "blocks",
|
|
59
|
-
weekStart: CalendarWeekStart.Monday,
|
|
60
|
-
scale: ScaleKind.Linear,
|
|
61
|
-
distance: 3.7,
|
|
62
|
-
elevation: 40,
|
|
63
|
-
azimuth: 24
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
build(ctx) {
|
|
67
|
-
const { data, date, value, shape, weekStart, scale } = this.options;
|
|
68
|
-
const rows = data.flatMap((row) => {
|
|
69
|
-
const when = TimeRows.date(row[date]);
|
|
70
|
-
return when ? [{
|
|
71
|
-
day: +TimeRows.floorDay(when),
|
|
72
|
-
value: Math.max(0, TimeRows.number(row[value]) ?? 0)
|
|
73
|
-
}] : [];
|
|
74
|
-
});
|
|
75
|
-
const totals = rollup(rows, (list) => sum(list, (d) => d.value), (d) => d.day);
|
|
76
|
-
const floor = new Mesh(new PlaneGeometry(2.2, 1.1), new MeshStandardMaterial({ color: ctx.theme.grid }));
|
|
77
|
-
floor.rotation.x = -Math.PI / 2;
|
|
78
|
-
floor.position.y = BASE;
|
|
79
|
-
floor.receiveShadow = true;
|
|
80
|
-
ctx.root.add(floor);
|
|
81
|
-
if (!totals.size) return;
|
|
82
|
-
const stamps = [...totals.keys()], first = new Date(Math.min(...stamps)), last = new Date(Math.max(...stamps));
|
|
83
|
-
const days = utcDay.range(first, utcDay.offset(last, 1));
|
|
84
|
-
const week = weekStart === CalendarWeekStart.Monday ? utcMonday : utcSunday;
|
|
85
|
-
const origin = week.floor(first), weeks = week.count(origin, last) + 1;
|
|
86
|
-
const cell = Math.min(2 / weeks, 1 / 7), gap = cell * .86;
|
|
87
|
-
const top = Math.max(1e-9, ...totals.values());
|
|
88
|
-
const height = scale === ScaleKind.Sqrt ? scalePow().exponent(.5).domain([0, top]).range([0, .7]) : scaleLinear([0, top], [0, .7]);
|
|
89
|
-
const geometry = shape === "blocks" ? new BoxGeometry(gap, 1, gap) : new CylinderGeometry(gap / 2, gap / 2, 1, 12);
|
|
90
|
-
const towers = new InstancedMesh(geometry, new MeshStandardMaterial({ roughness: .5 }), days.length);
|
|
91
|
-
towers.castShadow = towers.receiveShadow = true;
|
|
92
|
-
const weekday = (day) => weekStart === CalendarWeekStart.Monday ? (day.getUTCDay() + 6) % 7 : day.getUTCDay();
|
|
93
|
-
const dummy = new Object3D();
|
|
94
|
-
const place = (progress) => {
|
|
95
|
-
days.forEach((day, i) => {
|
|
96
|
-
const h = Math.max(.006, height(totals.get(+day) ?? 0) * progress);
|
|
97
|
-
dummy.position.set((week.count(origin, day) - weeks / 2 + .5) * cell, BASE + h / 2, (weekday(day) - 3) * cell);
|
|
98
|
-
dummy.scale.set(1, h, 1);
|
|
99
|
-
dummy.updateMatrix();
|
|
100
|
-
towers.setMatrixAt(i, dummy.matrix);
|
|
101
|
-
});
|
|
102
|
-
towers.instanceMatrix.needsUpdate = true;
|
|
103
|
-
};
|
|
104
|
-
days.forEach((day, i) => {
|
|
105
|
-
const amount = totals.get(+day);
|
|
106
|
-
towers.setColorAt(i, ctx.color(amount === void 0 ? ctx.theme.grid : ctx.palette.sequential(.15 + .85 * (amount / top))));
|
|
107
|
-
});
|
|
108
|
-
ctx.reveal(place);
|
|
109
|
-
ctx.root.add(towers);
|
|
110
|
-
ctx.pick(towers, (i) => ({
|
|
111
|
-
title: TimeRows.long(days[i]),
|
|
112
|
-
rows: [["Value", +(totals.get(+days[i]) ?? 0).toFixed(1)]]
|
|
113
|
-
}));
|
|
114
|
-
let previous = -1, labelled = -Infinity;
|
|
115
|
-
for (const day of days) {
|
|
116
|
-
const month = day.getUTCMonth(), at = week.count(origin, day);
|
|
117
|
-
if (month === previous || (at - labelled) * cell < .26) continue;
|
|
118
|
-
previous = month;
|
|
119
|
-
labelled = at;
|
|
120
|
-
ctx.label(MONTH_NAMES[month], [
|
|
121
|
-
(at - weeks / 2 + .5) * cell,
|
|
122
|
-
BASE,
|
|
123
|
-
.6
|
|
124
|
-
], "secondary", 10);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
export { CalendarSkylineChart, SkylineShape };
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { Chart3D } from "../../core/Chart3D.js";
|
|
2
|
-
import { ChartFamily, DataShape, Dimension } from "../../core/enums.js";
|
|
3
|
-
import { TimeRows } from "./TimeRows.js";
|
|
4
|
-
import { TimeSamples } from "./TimeSamples.js";
|
|
5
|
-
import { scaleBand, scaleLinear, scaleUtc } from "d3";
|
|
6
|
-
import { BoxGeometry, InstancedMesh, Mesh, MeshStandardMaterial, Object3D, PlaneGeometry } from "three";
|
|
7
|
-
// src/charts/timeline/ScheduleBlocksChart.ts
|
|
8
|
-
var ScheduleBlockHeight = /* @__PURE__ */ function(ScheduleBlockHeight) {
|
|
9
|
-
ScheduleBlockHeight["Flat"] = "flat";
|
|
10
|
-
ScheduleBlockHeight["Effort"] = "by-effort";
|
|
11
|
-
ScheduleBlockHeight["Progress"] = "by-progress";
|
|
12
|
-
return ScheduleBlockHeight;
|
|
13
|
-
}({});
|
|
14
|
-
var ScheduleBlockOrder = /* @__PURE__ */ function(ScheduleBlockOrder) {
|
|
15
|
-
ScheduleBlockOrder["Start"] = "by-start";
|
|
16
|
-
ScheduleBlockOrder["Group"] = "by-group";
|
|
17
|
-
return ScheduleBlockOrder;
|
|
18
|
-
}({});
|
|
19
|
-
var ScheduleBlockBase = /* @__PURE__ */ function(ScheduleBlockBase) {
|
|
20
|
-
ScheduleBlockBase["Floor"] = "on-floor";
|
|
21
|
-
ScheduleBlockBase["Stairs"] = "stairs";
|
|
22
|
-
return ScheduleBlockBase;
|
|
23
|
-
}({});
|
|
24
|
-
var FLOOR = -.7;
|
|
25
|
-
/** A schedule as a landscape: for presenting phasing and effort together, not for reading exact dates. */
|
|
26
|
-
var ScheduleBlocksChart = class extends Chart3D {
|
|
27
|
-
static meta = {
|
|
28
|
-
id: "schedule-blocks",
|
|
29
|
-
name: "Schedule blocks",
|
|
30
|
-
family: ChartFamily.Project,
|
|
31
|
-
dimension: Dimension.Three,
|
|
32
|
-
shape: DataShape.Table,
|
|
33
|
-
description: "Extrudes schedule bars into blocks, with height carrying effort or completion on top of time and row.",
|
|
34
|
-
tags: [
|
|
35
|
-
"schedule",
|
|
36
|
-
"waterfall",
|
|
37
|
-
"phasing"
|
|
38
|
-
],
|
|
39
|
-
sample: (seed) => TimeSamples.plan(seed, 12),
|
|
40
|
-
variants: {
|
|
41
|
-
blockHeight: Object.values(ScheduleBlockHeight),
|
|
42
|
-
order: Object.values(ScheduleBlockOrder),
|
|
43
|
-
base: Object.values(ScheduleBlockBase)
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
defaults() {
|
|
47
|
-
return {
|
|
48
|
-
task: "task",
|
|
49
|
-
start: "start",
|
|
50
|
-
end: "end",
|
|
51
|
-
group: "group",
|
|
52
|
-
progress: "progress",
|
|
53
|
-
blockHeight: "flat",
|
|
54
|
-
order: "by-start",
|
|
55
|
-
base: "on-floor",
|
|
56
|
-
distance: 4.6,
|
|
57
|
-
elevation: 30
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
lift(span) {
|
|
61
|
-
const { blockHeight, progress } = this.options;
|
|
62
|
-
if (blockHeight === "flat") return .12;
|
|
63
|
-
if (blockHeight === "by-effort") return .08 + .6 * Math.min(1, TimeRows.days(span.start, span.end) / 20);
|
|
64
|
-
const done = TimeRows.number(span.row[progress]) ?? 0;
|
|
65
|
-
return .08 + .6 * Math.max(0, Math.min(1, done > 1 ? done / 100 : done));
|
|
66
|
-
}
|
|
67
|
-
build(ctx) {
|
|
68
|
-
const { data, task, start, end, group, order, base } = this.options;
|
|
69
|
-
const spans = TimeRows.spans(data, {
|
|
70
|
-
label: task,
|
|
71
|
-
start,
|
|
72
|
-
end,
|
|
73
|
-
group
|
|
74
|
-
});
|
|
75
|
-
for (const span of spans) ctx.palette.color(span.group);
|
|
76
|
-
spans.sort(order === "by-group" ? (a, b) => a.group.localeCompare(b.group) || +a.start - +b.start : (a, b) => +a.start - +b.start);
|
|
77
|
-
const keys = TimeRows.unique(spans.map((span) => span.label));
|
|
78
|
-
const x = scaleUtc(TimeRows.extent(spans.flatMap((span) => [span.start, span.end])), [-1, 1]);
|
|
79
|
-
const z = scaleBand(keys, [-1, 1]).padding(.22);
|
|
80
|
-
const rise = scaleLinear([0, Math.max(1, spans.length - 1)], [.7, 0]);
|
|
81
|
-
const floor = new Mesh(new PlaneGeometry(2.05, 2.05), new MeshStandardMaterial({ color: ctx.theme.grid }));
|
|
82
|
-
floor.rotation.x = -Math.PI / 2;
|
|
83
|
-
floor.position.y = FLOOR;
|
|
84
|
-
floor.receiveShadow = true;
|
|
85
|
-
ctx.root.add(floor);
|
|
86
|
-
if (!spans.length) return;
|
|
87
|
-
const blocks = new InstancedMesh(new BoxGeometry(1, 1, 1), new MeshStandardMaterial({ roughness: .5 }), spans.length);
|
|
88
|
-
blocks.castShadow = blocks.receiveShadow = true;
|
|
89
|
-
const dummy = new Object3D();
|
|
90
|
-
const place = (progress) => {
|
|
91
|
-
spans.forEach((span, i) => {
|
|
92
|
-
const left = x(span.start), width = Math.max(.02, x(span.end) - left) * Math.max(.001, progress), h = this.lift(span);
|
|
93
|
-
dummy.position.set(left + width / 2, FLOOR + (base === "stairs" ? rise(i) : 0) + h / 2, z(keys[i]) + z.bandwidth() / 2);
|
|
94
|
-
dummy.scale.set(width, h, z.bandwidth());
|
|
95
|
-
dummy.updateMatrix();
|
|
96
|
-
blocks.setMatrixAt(i, dummy.matrix);
|
|
97
|
-
});
|
|
98
|
-
blocks.instanceMatrix.needsUpdate = true;
|
|
99
|
-
};
|
|
100
|
-
spans.forEach((span, i) => blocks.setColorAt(i, ctx.color(ctx.palette.color(span.group))));
|
|
101
|
-
ctx.reveal(place);
|
|
102
|
-
ctx.root.add(blocks);
|
|
103
|
-
ctx.pick(blocks, (i) => {
|
|
104
|
-
const span = spans[i];
|
|
105
|
-
return {
|
|
106
|
-
title: span.label,
|
|
107
|
-
color: ctx.palette.color(span.group),
|
|
108
|
-
rows: [["Start", TimeRows.long(span.start)], ["End", TimeRows.long(span.end)]]
|
|
109
|
-
};
|
|
110
|
-
});
|
|
111
|
-
const ticks = x.ticks(4);
|
|
112
|
-
for (const tick of ticks) ctx.label(TimeRows.short(tick), [
|
|
113
|
-
x(tick),
|
|
114
|
-
FLOOR,
|
|
115
|
-
1.18
|
|
116
|
-
], "secondary", 10);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
export { ScheduleBlockBase, ScheduleBlockHeight, ScheduleBlockOrder, ScheduleBlocksChart };
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { ChartFamily, DataShape, Dimension, LegendPosition } from "../../core/enums.js";
|
|
2
|
-
import { RadialChart } from "../../core/RadialChart.js";
|
|
3
|
-
import { SampleData } from "../../data/SampleData.js";
|
|
4
|
-
import { TimeRows } from "./TimeRows.js";
|
|
5
|
-
import { max, min, utcFormat } from "d3";
|
|
6
|
-
// src/charts/timeline/SpiralTimeline.ts
|
|
7
|
-
var SpiralPeriod = /* @__PURE__ */ function(SpiralPeriod) {
|
|
8
|
-
SpiralPeriod["Fortnight"] = "fortnight";
|
|
9
|
-
SpiralPeriod["Month"] = "month";
|
|
10
|
-
SpiralPeriod["Quarter"] = "quarter";
|
|
11
|
-
return SpiralPeriod;
|
|
12
|
-
}({});
|
|
13
|
-
var SpiralMark = /* @__PURE__ */ function(SpiralMark) {
|
|
14
|
-
SpiralMark["Bar"] = "bars";
|
|
15
|
-
SpiralMark["Dot"] = "dots";
|
|
16
|
-
SpiralMark["Line"] = "line";
|
|
17
|
-
return SpiralMark;
|
|
18
|
-
}({});
|
|
19
|
-
var SpiralDirection = /* @__PURE__ */ function(SpiralDirection) {
|
|
20
|
-
SpiralDirection["Outward"] = "outward";
|
|
21
|
-
SpiralDirection["Inward"] = "inward";
|
|
22
|
-
return SpiralDirection;
|
|
23
|
-
}({});
|
|
24
|
-
var LENGTH = {
|
|
25
|
-
["fortnight"]: 14,
|
|
26
|
-
["month"]: 30.44,
|
|
27
|
-
["quarter"]: 91.31
|
|
28
|
-
};
|
|
29
|
-
var STAMP = utcFormat("%b %-d");
|
|
30
|
-
/** Wind time into a spiral so each turn lines up with the last and a repeating cycle becomes a pattern along one spoke. */
|
|
31
|
-
var SpiralTimeline = class extends RadialChart {
|
|
32
|
-
static meta = {
|
|
33
|
-
id: "spiral-timeline",
|
|
34
|
-
name: "Spiral timeline",
|
|
35
|
-
family: ChartFamily.Temporal,
|
|
36
|
-
dimension: Dimension.Two,
|
|
37
|
-
shape: DataShape.Table,
|
|
38
|
-
description: "Winds a time series along an Archimedean spiral, with one turn per period, to expose repeating patterns.",
|
|
39
|
-
tags: [
|
|
40
|
-
"cyclical",
|
|
41
|
-
"seasonal",
|
|
42
|
-
"spiral plot"
|
|
43
|
-
],
|
|
44
|
-
sample: (seed) => SampleData.timeSeries(seed, 200, 1).map((row, i) => ({
|
|
45
|
-
date: row.date,
|
|
46
|
-
value: +(+row.value * (1 + .6 * Math.sin(i / 30.44 * 2 * Math.PI))).toFixed(1)
|
|
47
|
-
})),
|
|
48
|
-
variants: {
|
|
49
|
-
period: [
|
|
50
|
-
"month",
|
|
51
|
-
"fortnight",
|
|
52
|
-
"quarter"
|
|
53
|
-
],
|
|
54
|
-
mark: Object.values(SpiralMark),
|
|
55
|
-
direction: Object.values(SpiralDirection)
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
defaults() {
|
|
59
|
-
return {
|
|
60
|
-
date: "date",
|
|
61
|
-
value: "value",
|
|
62
|
-
period: "month",
|
|
63
|
-
mark: "bars",
|
|
64
|
-
direction: "outward",
|
|
65
|
-
legend: LegendPosition.None
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
points(radius) {
|
|
69
|
-
const { data, date, value, period, direction } = this.options;
|
|
70
|
-
const rows = data.flatMap((row) => {
|
|
71
|
-
const when = TimeRows.date(row[date]), amount = TimeRows.number(row[value]);
|
|
72
|
-
return when && amount !== null ? [{
|
|
73
|
-
when,
|
|
74
|
-
amount
|
|
75
|
-
}] : [];
|
|
76
|
-
}).sort((a, b) => +a.when - +b.when);
|
|
77
|
-
const inner = radius * .16, days = rows.length ? TimeRows.days(rows[0].when, rows[rows.length - 1].when) || 1 : 1;
|
|
78
|
-
const turns = days / LENGTH[period], band = (radius - inner) / (turns + 1);
|
|
79
|
-
const low = min(rows, (row) => row.amount) ?? 0, high = max(rows, (row) => row.amount) ?? 1;
|
|
80
|
-
return {
|
|
81
|
-
points: rows.map(({ when, amount }) => {
|
|
82
|
-
const elapsed = TimeRows.days(rows[0].when, when);
|
|
83
|
-
const turn = (direction === "inward" ? days - elapsed : elapsed) / LENGTH[period];
|
|
84
|
-
return {
|
|
85
|
-
date: when,
|
|
86
|
-
value: amount,
|
|
87
|
-
angle: turn * 2 * Math.PI - Math.PI / 2,
|
|
88
|
-
radius: inner + band * turn,
|
|
89
|
-
share: (amount - low) / (high - low || 1)
|
|
90
|
-
};
|
|
91
|
-
}),
|
|
92
|
-
band,
|
|
93
|
-
inner
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
drawRadial(ctx, { radius }) {
|
|
97
|
-
const { mark } = this.options;
|
|
98
|
-
const { points, band } = this.points(radius - 8);
|
|
99
|
-
const polar = (angle, r) => `${Math.cos(angle) * r},${Math.sin(angle) * r}`;
|
|
100
|
-
const guide = [...points].sort((a, b) => a.angle - b.angle);
|
|
101
|
-
const coil = ctx.marks("coil", "path", guide.length > 1 ? [guide] : [], (_, i) => i).attr("fill", "none").attr("stroke", mark === "line" ? ctx.theme.grid : ctx.theme.axis).attr("stroke-width", 1);
|
|
102
|
-
ctx.set(coil, { d: (list) => `M${list.map((p) => polar(p.angle, p.radius)).join("L")}` });
|
|
103
|
-
const reach = (p) => Math.max(1, p.share * band * .9);
|
|
104
|
-
const bars = ctx.marks("bars", "path", mark === "bars" ? points : [], (p) => +p.date).attr("stroke-linecap", "round").attr("fill", "none").attr("stroke-width", Math.min(3, Math.max(1.5, radius / 40))).attr("stroke", (p) => ctx.palette.sequential(.25 + p.share * .75));
|
|
105
|
-
ctx.set(bars, { d: (p) => `M${polar(p.angle, p.radius)}L${polar(p.angle, p.radius + reach(p))}` }, { d: (p) => `M${polar(p.angle, p.radius)}L${polar(p.angle, p.radius)}` }, 2);
|
|
106
|
-
ctx.hover(bars, (p) => this.about(p));
|
|
107
|
-
const dots = ctx.marks("dots", "circle", mark === "dots" ? points : [], (p) => +p.date).attr("fill", (p) => ctx.palette.sequential(.25 + p.share * .75));
|
|
108
|
-
ctx.set(dots, {
|
|
109
|
-
cx: (p) => Math.cos(p.angle) * p.radius,
|
|
110
|
-
cy: (p) => Math.sin(p.angle) * p.radius,
|
|
111
|
-
r: (p) => Math.max(.8, Math.sqrt(p.share) * Math.min(band / 2, 5))
|
|
112
|
-
}, {
|
|
113
|
-
cx: (p) => Math.cos(p.angle) * p.radius,
|
|
114
|
-
cy: (p) => Math.sin(p.angle) * p.radius,
|
|
115
|
-
r: 0
|
|
116
|
-
}, 2);
|
|
117
|
-
ctx.hover(dots, (p) => this.about(p));
|
|
118
|
-
const trace = ctx.marks("trace", "path", mark === "line" && guide.length > 1 ? [guide] : [], (_, i) => i).attr("fill", "none").attr("stroke", ctx.palette.color("value")).attr("stroke-width", 2).attr("stroke-linejoin", "round");
|
|
119
|
-
ctx.set(trace, { d: (list) => `M${list.map((p) => polar(p.angle, p.radius + reach(p))).join("L")}` });
|
|
120
|
-
ctx.drawOn(trace);
|
|
121
|
-
const hits = ctx.marks("hits", "circle", mark === "line" ? points : [], (p) => +p.date).attr("fill", "transparent").attr("r", 5);
|
|
122
|
-
ctx.set(hits, {
|
|
123
|
-
cx: (p) => Math.cos(p.angle) * (p.radius + reach(p)),
|
|
124
|
-
cy: (p) => Math.sin(p.angle) * (p.radius + reach(p))
|
|
125
|
-
});
|
|
126
|
-
ctx.hover(hits, (p) => this.about(p));
|
|
127
|
-
const rim = Math.max(0, ctx.plot.width / 2 - 2), tip = guide[guide.length - 1];
|
|
128
|
-
const out = tip ? tip.radius + (mark === "line" ? reach(tip) : 0) + 8 : 0;
|
|
129
|
-
const tipX = tip ? Math.cos(tip.angle) * out : 0, tipY = tip ? Math.sin(tip.angle) * out : 0;
|
|
130
|
-
const ends = tip && guide.length > 1 ? [{
|
|
131
|
-
point: guide[0],
|
|
132
|
-
x: 0,
|
|
133
|
-
y: 4,
|
|
134
|
-
anchor: "middle"
|
|
135
|
-
}, {
|
|
136
|
-
point: tip,
|
|
137
|
-
x: Math.max(-rim, Math.min(rim, tipX)),
|
|
138
|
-
y: Math.max(-radius + 8, Math.min(radius, tipY + 4)),
|
|
139
|
-
anchor: tipX < 0 ? "end" : "start"
|
|
140
|
-
}] : [];
|
|
141
|
-
const stamps = ctx.marks("ends", "text", ends, (d) => d.anchor).attr("text-anchor", (d) => d.anchor).attr("font-weight", 600).text((d) => STAMP(d.point.date));
|
|
142
|
-
ctx.text(ctx.set(stamps, {
|
|
143
|
-
x: (d) => d.x,
|
|
144
|
-
y: (d) => d.y
|
|
145
|
-
}), 10, "ink");
|
|
146
|
-
}
|
|
147
|
-
about(point) {
|
|
148
|
-
return {
|
|
149
|
-
title: TimeRows.long(point.date),
|
|
150
|
-
rows: [["Value", point.value]]
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
export { SpiralDirection, SpiralMark, SpiralPeriod, SpiralTimeline };
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { Chart2D } from "../../core/Chart2D.js";
|
|
2
|
-
import { ChartFamily, DataShape, Dimension } from "../../core/enums.js";
|
|
3
|
-
import { SampleData } from "../../data/SampleData.js";
|
|
4
|
-
import { TimeMarks } from "./TimeMarks.js";
|
|
5
|
-
import { TimeRows } from "./TimeRows.js";
|
|
6
|
-
import { area, curveBasis, curveMonotoneX, max, min, scaleLinear, scaleUtc, stack, stackOffsetExpand, stackOffsetSilhouette, stackOffsetWiggle, stackOrderAscending, stackOrderInsideOut, stackOrderNone, utcWeek } from "d3";
|
|
7
|
-
// src/charts/timeline/StreamTimeline.ts
|
|
8
|
-
var StreamTimelineBin = /* @__PURE__ */ function(StreamTimelineBin) {
|
|
9
|
-
StreamTimelineBin["Day"] = "daily";
|
|
10
|
-
StreamTimelineBin["Week"] = "weekly";
|
|
11
|
-
return StreamTimelineBin;
|
|
12
|
-
}({});
|
|
13
|
-
var StreamTimelineOffset = /* @__PURE__ */ function(StreamTimelineOffset) {
|
|
14
|
-
StreamTimelineOffset["Wiggle"] = "wiggle";
|
|
15
|
-
StreamTimelineOffset["Silhouette"] = "silhouette";
|
|
16
|
-
StreamTimelineOffset["Expand"] = "expand";
|
|
17
|
-
return StreamTimelineOffset;
|
|
18
|
-
}({});
|
|
19
|
-
var StreamTimelineOrder = /* @__PURE__ */ function(StreamTimelineOrder) {
|
|
20
|
-
StreamTimelineOrder["InsideOut"] = "inside-out";
|
|
21
|
-
StreamTimelineOrder["Ascending"] = "ascending";
|
|
22
|
-
StreamTimelineOrder["Input"] = "input-order";
|
|
23
|
-
return StreamTimelineOrder;
|
|
24
|
-
}({});
|
|
25
|
-
var StreamTimelineCurve = /* @__PURE__ */ function(StreamTimelineCurve) {
|
|
26
|
-
StreamTimelineCurve["Basis"] = "smooth";
|
|
27
|
-
StreamTimelineCurve["Monotone"] = "monotone";
|
|
28
|
-
return StreamTimelineCurve;
|
|
29
|
-
}({});
|
|
30
|
-
/** Show how many categories swell and fade over a long span, trading exact reading for overall shape. */
|
|
31
|
-
var StreamTimeline = class extends Chart2D {
|
|
32
|
-
static meta = {
|
|
33
|
-
id: "stream-timeline",
|
|
34
|
-
name: "Stream timeline",
|
|
35
|
-
family: ChartFamily.Temporal,
|
|
36
|
-
dimension: Dimension.Two,
|
|
37
|
-
shape: DataShape.Table,
|
|
38
|
-
description: "Flows stacked categories around a central baseline to show how the mix of activity changes through time.",
|
|
39
|
-
tags: [
|
|
40
|
-
"streamgraph",
|
|
41
|
-
"theme river",
|
|
42
|
-
"flow"
|
|
43
|
-
],
|
|
44
|
-
sample: (seed) => SampleData.timeSeries(seed, 120, 5),
|
|
45
|
-
variants: {
|
|
46
|
-
offset: Object.values(StreamTimelineOffset),
|
|
47
|
-
order: Object.values(StreamTimelineOrder),
|
|
48
|
-
curve: Object.values(StreamTimelineCurve),
|
|
49
|
-
bin: ["weekly", "daily"],
|
|
50
|
-
labels: [true, false]
|
|
51
|
-
},
|
|
52
|
-
valid: ({ offset, order }) => offset !== "expand" || order !== "inside-out"
|
|
53
|
-
};
|
|
54
|
-
defaults() {
|
|
55
|
-
return {
|
|
56
|
-
date: "date",
|
|
57
|
-
series: "series",
|
|
58
|
-
value: "value",
|
|
59
|
-
bin: "weekly",
|
|
60
|
-
offset: "wiggle",
|
|
61
|
-
order: "inside-out",
|
|
62
|
-
curve: "smooth",
|
|
63
|
-
labels: true
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
plotMargin() {
|
|
67
|
-
return {
|
|
68
|
-
top: 8,
|
|
69
|
-
right: 26,
|
|
70
|
-
bottom: 26,
|
|
71
|
-
left: 26
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
layers() {
|
|
75
|
-
const { data, date, series, value, bin, offset, order } = this.options;
|
|
76
|
-
const rows = bin === "weekly" ? data.map((row) => {
|
|
77
|
-
const when = TimeRows.date(row[date]);
|
|
78
|
-
return {
|
|
79
|
-
...row,
|
|
80
|
-
[date]: when ? utcWeek.floor(when) : null
|
|
81
|
-
};
|
|
82
|
-
}) : data;
|
|
83
|
-
const { names, table } = TimeRows.pivot(rows, date, series, value);
|
|
84
|
-
const offsets = {
|
|
85
|
-
["wiggle"]: stackOffsetWiggle,
|
|
86
|
-
["silhouette"]: stackOffsetSilhouette,
|
|
87
|
-
["expand"]: stackOffsetExpand
|
|
88
|
-
};
|
|
89
|
-
const orders = {
|
|
90
|
-
["inside-out"]: stackOrderInsideOut,
|
|
91
|
-
["ascending"]: stackOrderAscending,
|
|
92
|
-
["input-order"]: stackOrderNone
|
|
93
|
-
};
|
|
94
|
-
return {
|
|
95
|
-
names,
|
|
96
|
-
table,
|
|
97
|
-
layers: stack().keys(names).offset(offsets[offset]).order(orders[order])(table)
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
draw(ctx) {
|
|
101
|
-
const { names, table, layers } = this.layers();
|
|
102
|
-
const { width, height } = ctx.plot;
|
|
103
|
-
names.forEach((name) => ctx.palette.color(name));
|
|
104
|
-
const safe = (value) => Number.isFinite(value) ? value : 0;
|
|
105
|
-
const low = min(layers, (layer) => min(layer, (point) => safe(point[0]))) ?? 0;
|
|
106
|
-
const high = max(layers, (layer) => max(layer, (point) => safe(point[1]))) ?? 1;
|
|
107
|
-
const x = scaleUtc(TimeRows.extent(table.map((row) => new Date(row.date))), [0, width]);
|
|
108
|
-
const y = scaleLinear([low, high === low ? low + 1 : high], [height, 0]);
|
|
109
|
-
TimeMarks.axis(ctx, x);
|
|
110
|
-
const curve = this.options.curve === "smooth" ? curveBasis : curveMonotoneX;
|
|
111
|
-
const at = (d) => x(new Date(d.data.date));
|
|
112
|
-
const shape = area().x(at).y0((d) => y(safe(d[0]))).y1((d) => y(safe(d[1]))).curve(curve);
|
|
113
|
-
const mid = area().x(at).y0((d) => y((safe(d[0]) + safe(d[1])) / 2)).y1((d) => y((safe(d[0]) + safe(d[1])) / 2)).curve(curve);
|
|
114
|
-
const paths = ctx.marks("streams", "path", layers, (layer) => layer.key).attr("fill", (layer) => ctx.palette.color(layer.key)).attr("stroke", ctx.theme.surface).attr("stroke-width", 1.5);
|
|
115
|
-
ctx.set(paths, { d: (layer) => shape(layer) ?? "" }, { d: (layer) => mid(layer) ?? "" }, 50);
|
|
116
|
-
ctx.hover(paths, (layer) => {
|
|
117
|
-
const values = layer.map((point) => point.data[layer.key] ?? 0);
|
|
118
|
-
return {
|
|
119
|
-
title: layer.key,
|
|
120
|
-
color: ctx.palette.color(layer.key),
|
|
121
|
-
rows: [["Peak", +(max(values) ?? 0).toFixed(1)], ["Latest", +(values[values.length - 1] ?? 0).toFixed(1)]]
|
|
122
|
-
};
|
|
123
|
-
});
|
|
124
|
-
const tags = !this.options.labels ? [] : layers.flatMap((layer) => {
|
|
125
|
-
const point = layer[layer.reduce((best, point, i) => point[1] - point[0] > layer[best][1] - layer[best][0] ? i : best, 0)];
|
|
126
|
-
if (!point) return [];
|
|
127
|
-
const thick = y(safe(point[0])) - y(safe(point[1])), place = x(new Date(point.data.date)), half = TimeRows.width(layer.key) / 2;
|
|
128
|
-
return thick >= 14 ? [{
|
|
129
|
-
name: layer.key,
|
|
130
|
-
x: Math.max(half, Math.min(width - half, place)),
|
|
131
|
-
y: (y(safe(point[0])) + y(safe(point[1]))) / 2 + 4
|
|
132
|
-
}] : [];
|
|
133
|
-
});
|
|
134
|
-
const labels = ctx.marks("names", "text", tags, (d) => d.name).attr("text-anchor", "middle").style("pointer-events", "none").text((d) => d.name);
|
|
135
|
-
ctx.set(ctx.text(labels, 11, "ink").attr("fill", (d) => ctx.palette.inkOn(ctx.palette.color(d.name))), {
|
|
136
|
-
x: (d) => d.x,
|
|
137
|
-
y: (d) => d.y
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
export { StreamTimeline, StreamTimelineBin, StreamTimelineCurve, StreamTimelineOffset, StreamTimelineOrder };
|