@adminiumjs/charts 0.1.0-rc.1
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/LICENSE +661 -0
- package/dist/components/AnomalyChart.d.ts +30 -0
- package/dist/components/AnomalyChart.d.ts.map +1 -0
- package/dist/components/AnomalyChart.js +32 -0
- package/dist/components/AnomalyChart.js.map +1 -0
- package/dist/components/BarChart.d.ts +33 -0
- package/dist/components/BarChart.d.ts.map +1 -0
- package/dist/components/BarChart.js +40 -0
- package/dist/components/BarChart.js.map +1 -0
- package/dist/components/BoxPlotChart.d.ts +23 -0
- package/dist/components/BoxPlotChart.d.ts.map +1 -0
- package/dist/components/BoxPlotChart.js +24 -0
- package/dist/components/BoxPlotChart.js.map +1 -0
- package/dist/components/BulletChart.d.ts +27 -0
- package/dist/components/BulletChart.d.ts.map +1 -0
- package/dist/components/BulletChart.js +24 -0
- package/dist/components/BulletChart.js.map +1 -0
- package/dist/components/BumpChart.d.ts +27 -0
- package/dist/components/BumpChart.d.ts.map +1 -0
- package/dist/components/BumpChart.js +17 -0
- package/dist/components/BumpChart.js.map +1 -0
- package/dist/components/CandlestickChart.d.ts +26 -0
- package/dist/components/CandlestickChart.d.ts.map +1 -0
- package/dist/components/CandlestickChart.js +22 -0
- package/dist/components/CandlestickChart.js.map +1 -0
- package/dist/components/ChartSurface.d.ts +52 -0
- package/dist/components/ChartSurface.d.ts.map +1 -0
- package/dist/components/ChartSurface.js +15 -0
- package/dist/components/ChartSurface.js.map +1 -0
- package/dist/components/Chord.d.ts +30 -0
- package/dist/components/Chord.d.ts.map +1 -0
- package/dist/components/Chord.js +14 -0
- package/dist/components/Chord.js.map +1 -0
- package/dist/components/ChoroplethGridChart.d.ts +32 -0
- package/dist/components/ChoroplethGridChart.d.ts.map +1 -0
- package/dist/components/ChoroplethGridChart.js +15 -0
- package/dist/components/ChoroplethGridChart.js.map +1 -0
- package/dist/components/CohortMatrixChart.d.ts +30 -0
- package/dist/components/CohortMatrixChart.d.ts.map +1 -0
- package/dist/components/CohortMatrixChart.js +13 -0
- package/dist/components/CohortMatrixChart.js.map +1 -0
- package/dist/components/CorrelationMatrixChart.d.ts +24 -0
- package/dist/components/CorrelationMatrixChart.d.ts.map +1 -0
- package/dist/components/CorrelationMatrixChart.js +29 -0
- package/dist/components/CorrelationMatrixChart.js.map +1 -0
- package/dist/components/DonutChart.d.ts +31 -0
- package/dist/components/DonutChart.d.ts.map +1 -0
- package/dist/components/DonutChart.js +19 -0
- package/dist/components/DonutChart.js.map +1 -0
- package/dist/components/ForecastChart.d.ts +37 -0
- package/dist/components/ForecastChart.d.ts.map +1 -0
- package/dist/components/ForecastChart.js +39 -0
- package/dist/components/ForecastChart.js.map +1 -0
- package/dist/components/Funnel.d.ts +27 -0
- package/dist/components/Funnel.d.ts.map +1 -0
- package/dist/components/Funnel.js +25 -0
- package/dist/components/Funnel.js.map +1 -0
- package/dist/components/HeatCalendarChart.d.ts +39 -0
- package/dist/components/HeatCalendarChart.d.ts.map +1 -0
- package/dist/components/HeatCalendarChart.js +37 -0
- package/dist/components/HeatCalendarChart.js.map +1 -0
- package/dist/components/HeatMonthChart.d.ts +30 -0
- package/dist/components/HeatMonthChart.d.ts.map +1 -0
- package/dist/components/HeatMonthChart.js +14 -0
- package/dist/components/HeatMonthChart.js.map +1 -0
- package/dist/components/HexbinChart.d.ts +22 -0
- package/dist/components/HexbinChart.d.ts.map +1 -0
- package/dist/components/HexbinChart.js +31 -0
- package/dist/components/HexbinChart.js.map +1 -0
- package/dist/components/LineAreaChart.d.ts +26 -0
- package/dist/components/LineAreaChart.d.ts.map +1 -0
- package/dist/components/LineAreaChart.js +62 -0
- package/dist/components/LineAreaChart.js.map +1 -0
- package/dist/components/MarimekkoChart.d.ts +24 -0
- package/dist/components/MarimekkoChart.d.ts.map +1 -0
- package/dist/components/MarimekkoChart.js +20 -0
- package/dist/components/MarimekkoChart.js.map +1 -0
- package/dist/components/MultiLineChart.d.ts +36 -0
- package/dist/components/MultiLineChart.d.ts.map +1 -0
- package/dist/components/MultiLineChart.js +62 -0
- package/dist/components/MultiLineChart.js.map +1 -0
- package/dist/components/ParallelCoordinatesChart.d.ts +22 -0
- package/dist/components/ParallelCoordinatesChart.d.ts.map +1 -0
- package/dist/components/ParallelCoordinatesChart.js +16 -0
- package/dist/components/ParallelCoordinatesChart.js.map +1 -0
- package/dist/components/ParetoChart.d.ts +26 -0
- package/dist/components/ParetoChart.d.ts.map +1 -0
- package/dist/components/ParetoChart.js +26 -0
- package/dist/components/ParetoChart.js.map +1 -0
- package/dist/components/Radar.d.ts +27 -0
- package/dist/components/Radar.d.ts.map +1 -0
- package/dist/components/Radar.js +19 -0
- package/dist/components/Radar.js.map +1 -0
- package/dist/components/RadialBar.d.ts +25 -0
- package/dist/components/RadialBar.d.ts.map +1 -0
- package/dist/components/RadialBar.js +12 -0
- package/dist/components/RadialBar.js.map +1 -0
- package/dist/components/RankingBars.d.ts +27 -0
- package/dist/components/RankingBars.d.ts.map +1 -0
- package/dist/components/RankingBars.js +25 -0
- package/dist/components/RankingBars.js.map +1 -0
- package/dist/components/RidgelineChart.d.ts +23 -0
- package/dist/components/RidgelineChart.d.ts.map +1 -0
- package/dist/components/RidgelineChart.js +20 -0
- package/dist/components/RidgelineChart.js.map +1 -0
- package/dist/components/SankeyChart.d.ts +29 -0
- package/dist/components/SankeyChart.d.ts.map +1 -0
- package/dist/components/SankeyChart.js +21 -0
- package/dist/components/SankeyChart.js.map +1 -0
- package/dist/components/ScatterBubbleChart.d.ts +26 -0
- package/dist/components/ScatterBubbleChart.d.ts.map +1 -0
- package/dist/components/ScatterBubbleChart.js +31 -0
- package/dist/components/ScatterBubbleChart.js.map +1 -0
- package/dist/components/SlopeChart.d.ts +28 -0
- package/dist/components/SlopeChart.d.ts.map +1 -0
- package/dist/components/SlopeChart.js +18 -0
- package/dist/components/SlopeChart.js.map +1 -0
- package/dist/components/Sparkline.d.ts +15 -0
- package/dist/components/Sparkline.d.ts.map +1 -0
- package/dist/components/Sparkline.js +27 -0
- package/dist/components/Sparkline.js.map +1 -0
- package/dist/components/StackedBar100.d.ts +30 -0
- package/dist/components/StackedBar100.d.ts.map +1 -0
- package/dist/components/StackedBar100.js +21 -0
- package/dist/components/StackedBar100.js.map +1 -0
- package/dist/components/StreamChart.d.ts +23 -0
- package/dist/components/StreamChart.d.ts.map +1 -0
- package/dist/components/StreamChart.js +56 -0
- package/dist/components/StreamChart.js.map +1 -0
- package/dist/components/Sunburst.d.ts +24 -0
- package/dist/components/Sunburst.d.ts.map +1 -0
- package/dist/components/Sunburst.js +13 -0
- package/dist/components/Sunburst.js.map +1 -0
- package/dist/components/TimelineLanesChart.d.ts +25 -0
- package/dist/components/TimelineLanesChart.d.ts.map +1 -0
- package/dist/components/TimelineLanesChart.js +41 -0
- package/dist/components/TimelineLanesChart.js.map +1 -0
- package/dist/components/Treemap.d.ts +28 -0
- package/dist/components/Treemap.d.ts.map +1 -0
- package/dist/components/Treemap.js +22 -0
- package/dist/components/Treemap.js.map +1 -0
- package/dist/components/ViolinChart.d.ts +22 -0
- package/dist/components/ViolinChart.d.ts.map +1 -0
- package/dist/components/ViolinChart.js +21 -0
- package/dist/components/ViolinChart.js.map +1 -0
- package/dist/components/WaterfallChart.d.ts +23 -0
- package/dist/components/WaterfallChart.d.ts.map +1 -0
- package/dist/components/WaterfallChart.js +29 -0
- package/dist/components/WaterfallChart.js.map +1 -0
- package/dist/components/WordCloud.d.ts +24 -0
- package/dist/components/WordCloud.d.ts.map +1 -0
- package/dist/components/WordCloud.js +22 -0
- package/dist/components/WordCloud.js.map +1 -0
- package/dist/demo/barsRanking.d.ts +26 -0
- package/dist/demo/barsRanking.d.ts.map +1 -0
- package/dist/demo/barsRanking.js +80 -0
- package/dist/demo/barsRanking.js.map +1 -0
- package/dist/demo/generators.d.ts +44 -0
- package/dist/demo/generators.d.ts.map +1 -0
- package/dist/demo/generators.js +72 -0
- package/dist/demo/generators.js.map +1 -0
- package/dist/demo/mulberry32.d.ts +10 -0
- package/dist/demo/mulberry32.d.ts.map +1 -0
- package/dist/demo/mulberry32.js +26 -0
- package/dist/demo/mulberry32.js.map +1 -0
- package/dist/geometry/anomaly.d.ts +22 -0
- package/dist/geometry/anomaly.d.ts.map +1 -0
- package/dist/geometry/anomaly.js +52 -0
- package/dist/geometry/anomaly.js.map +1 -0
- package/dist/geometry/bars.d.ts +46 -0
- package/dist/geometry/bars.d.ts.map +1 -0
- package/dist/geometry/bars.js +68 -0
- package/dist/geometry/bars.js.map +1 -0
- package/dist/geometry/bullet.d.ts +53 -0
- package/dist/geometry/bullet.d.ts.map +1 -0
- package/dist/geometry/bullet.js +67 -0
- package/dist/geometry/bullet.js.map +1 -0
- package/dist/geometry/bump.d.ts +42 -0
- package/dist/geometry/bump.d.ts.map +1 -0
- package/dist/geometry/bump.js +29 -0
- package/dist/geometry/bump.js.map +1 -0
- package/dist/geometry/candles.d.ts +39 -0
- package/dist/geometry/candles.d.ts.map +1 -0
- package/dist/geometry/candles.js +42 -0
- package/dist/geometry/candles.js.map +1 -0
- package/dist/geometry/chord.d.ts +53 -0
- package/dist/geometry/chord.d.ts.map +1 -0
- package/dist/geometry/chord.js +111 -0
- package/dist/geometry/chord.js.map +1 -0
- package/dist/geometry/choropleth.d.ts +58 -0
- package/dist/geometry/choropleth.d.ts.map +1 -0
- package/dist/geometry/choropleth.js +101 -0
- package/dist/geometry/choropleth.js.map +1 -0
- package/dist/geometry/cohort.d.ts +54 -0
- package/dist/geometry/cohort.d.ts.map +1 -0
- package/dist/geometry/cohort.js +70 -0
- package/dist/geometry/cohort.js.map +1 -0
- package/dist/geometry/correlation.d.ts +138 -0
- package/dist/geometry/correlation.d.ts.map +1 -0
- package/dist/geometry/correlation.js +161 -0
- package/dist/geometry/correlation.js.map +1 -0
- package/dist/geometry/distribution.d.ts +115 -0
- package/dist/geometry/distribution.d.ts.map +1 -0
- package/dist/geometry/distribution.js +131 -0
- package/dist/geometry/distribution.js.map +1 -0
- package/dist/geometry/donut.d.ts +37 -0
- package/dist/geometry/donut.d.ts.map +1 -0
- package/dist/geometry/donut.js +46 -0
- package/dist/geometry/donut.js.map +1 -0
- package/dist/geometry/forecast.d.ts +30 -0
- package/dist/geometry/forecast.d.ts.map +1 -0
- package/dist/geometry/forecast.js +75 -0
- package/dist/geometry/forecast.js.map +1 -0
- package/dist/geometry/funnel.d.ts +37 -0
- package/dist/geometry/funnel.d.ts.map +1 -0
- package/dist/geometry/funnel.js +42 -0
- package/dist/geometry/funnel.js.map +1 -0
- package/dist/geometry/heat.d.ts +34 -0
- package/dist/geometry/heat.d.ts.map +1 -0
- package/dist/geometry/heat.js +50 -0
- package/dist/geometry/heat.js.map +1 -0
- package/dist/geometry/heatCalendar.d.ts +43 -0
- package/dist/geometry/heatCalendar.d.ts.map +1 -0
- package/dist/geometry/heatCalendar.js +82 -0
- package/dist/geometry/heatCalendar.js.map +1 -0
- package/dist/geometry/heatMonth.d.ts +47 -0
- package/dist/geometry/heatMonth.d.ts.map +1 -0
- package/dist/geometry/heatMonth.js +72 -0
- package/dist/geometry/heatMonth.js.map +1 -0
- package/dist/geometry/lineArea.d.ts +17 -0
- package/dist/geometry/lineArea.d.ts.map +1 -0
- package/dist/geometry/lineArea.js +37 -0
- package/dist/geometry/lineArea.js.map +1 -0
- package/dist/geometry/marimekko.d.ts +43 -0
- package/dist/geometry/marimekko.d.ts.map +1 -0
- package/dist/geometry/marimekko.js +45 -0
- package/dist/geometry/marimekko.js.map +1 -0
- package/dist/geometry/multiLine.d.ts +19 -0
- package/dist/geometry/multiLine.d.ts.map +1 -0
- package/dist/geometry/multiLine.js +25 -0
- package/dist/geometry/multiLine.js.map +1 -0
- package/dist/geometry/pareto.d.ts +44 -0
- package/dist/geometry/pareto.d.ts.map +1 -0
- package/dist/geometry/pareto.js +65 -0
- package/dist/geometry/pareto.js.map +1 -0
- package/dist/geometry/radar.d.ts +60 -0
- package/dist/geometry/radar.d.ts.map +1 -0
- package/dist/geometry/radar.js +67 -0
- package/dist/geometry/radar.js.map +1 -0
- package/dist/geometry/radialBar.d.ts +31 -0
- package/dist/geometry/radialBar.d.ts.map +1 -0
- package/dist/geometry/radialBar.js +53 -0
- package/dist/geometry/radialBar.js.map +1 -0
- package/dist/geometry/ranking.d.ts +48 -0
- package/dist/geometry/ranking.d.ts.map +1 -0
- package/dist/geometry/ranking.js +42 -0
- package/dist/geometry/ranking.js.map +1 -0
- package/dist/geometry/sankey.d.ts +60 -0
- package/dist/geometry/sankey.d.ts.map +1 -0
- package/dist/geometry/sankey.js +130 -0
- package/dist/geometry/sankey.js.map +1 -0
- package/dist/geometry/scales.d.ts +14 -0
- package/dist/geometry/scales.d.ts.map +1 -0
- package/dist/geometry/scales.js +33 -0
- package/dist/geometry/scales.js.map +1 -0
- package/dist/geometry/slope.d.ts +34 -0
- package/dist/geometry/slope.d.ts.map +1 -0
- package/dist/geometry/slope.js +44 -0
- package/dist/geometry/slope.js.map +1 -0
- package/dist/geometry/sparkline.d.ts +20 -0
- package/dist/geometry/sparkline.d.ts.map +1 -0
- package/dist/geometry/sparkline.js +43 -0
- package/dist/geometry/sparkline.js.map +1 -0
- package/dist/geometry/stacked100.d.ts +33 -0
- package/dist/geometry/stacked100.d.ts.map +1 -0
- package/dist/geometry/stacked100.js +34 -0
- package/dist/geometry/stacked100.js.map +1 -0
- package/dist/geometry/streamStack.d.ts +32 -0
- package/dist/geometry/streamStack.d.ts.map +1 -0
- package/dist/geometry/streamStack.js +56 -0
- package/dist/geometry/streamStack.js.map +1 -0
- package/dist/geometry/sunburst.d.ts +37 -0
- package/dist/geometry/sunburst.d.ts.map +1 -0
- package/dist/geometry/sunburst.js +84 -0
- package/dist/geometry/sunburst.js.map +1 -0
- package/dist/geometry/timelineLanes.d.ts +46 -0
- package/dist/geometry/timelineLanes.d.ts.map +1 -0
- package/dist/geometry/timelineLanes.js +52 -0
- package/dist/geometry/timelineLanes.js.map +1 -0
- package/dist/geometry/treemap.d.ts +42 -0
- package/dist/geometry/treemap.d.ts.map +1 -0
- package/dist/geometry/treemap.js +134 -0
- package/dist/geometry/treemap.js.map +1 -0
- package/dist/geometry/waterfall.d.ts +40 -0
- package/dist/geometry/waterfall.d.ts.map +1 -0
- package/dist/geometry/waterfall.js +80 -0
- package/dist/geometry/waterfall.js.map +1 -0
- package/dist/geometry/wordcloud.d.ts +46 -0
- package/dist/geometry/wordcloud.d.ts.map +1 -0
- package/dist/geometry/wordcloud.js +79 -0
- package/dist/geometry/wordcloud.js.map +1 -0
- package/dist/hooks/useChartSize.d.ts +6 -0
- package/dist/hooks/useChartSize.d.ts.map +1 -0
- package/dist/hooks/useChartSize.js +32 -0
- package/dist/hooks/useChartSize.js.map +1 -0
- package/dist/hooks/useMountAnimation.d.ts +4 -0
- package/dist/hooks/useMountAnimation.d.ts.map +1 -0
- package/dist/hooks/useMountAnimation.js +40 -0
- package/dist/hooks/useMountAnimation.js.map +1 -0
- package/dist/hooks/useRtl.d.ts +7 -0
- package/dist/hooks/useRtl.d.ts.map +1 -0
- package/dist/hooks/useRtl.js +18 -0
- package/dist/hooks/useRtl.js.map +1 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/format.d.ts +5 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +24 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/stats.d.ts +23 -0
- package/dist/utils/stats.d.ts.map +1 -0
- package/dist/utils/stats.js +82 -0
- package/dist/utils/stats.js.map +1 -0
- package/package.json +36 -0
- package/src/styles.css +205 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface Candle {
|
|
2
|
+
t: string;
|
|
3
|
+
o: number;
|
|
4
|
+
h: number;
|
|
5
|
+
l: number;
|
|
6
|
+
c: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CandleRect {
|
|
9
|
+
index: number;
|
|
10
|
+
/** Candle center x (wick line). */
|
|
11
|
+
centerX: number;
|
|
12
|
+
/** Body rect. */
|
|
13
|
+
x: number;
|
|
14
|
+
width: number;
|
|
15
|
+
bodyY: number;
|
|
16
|
+
bodyHeight: number;
|
|
17
|
+
/** Wick endpoints (pixel y). */
|
|
18
|
+
highY: number;
|
|
19
|
+
lowY: number;
|
|
20
|
+
/** Close ≥ open → rising (pos tone); else falling (danger tone). */
|
|
21
|
+
up: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface CandleLayout {
|
|
24
|
+
rects: CandleRect[];
|
|
25
|
+
/** Value → pixel y (price axis). */
|
|
26
|
+
yFor: (value: number) => number;
|
|
27
|
+
/** Nice price ticks (ascending). */
|
|
28
|
+
yTicks: number[];
|
|
29
|
+
}
|
|
30
|
+
export interface CandleLayoutOptions {
|
|
31
|
+
/** Fraction of each slot the body occupies (0–1, default 0.6). */
|
|
32
|
+
bodyRatio?: number;
|
|
33
|
+
tickCount?: number;
|
|
34
|
+
/** Minimum body height so doji candles stay visible (px, default 1). */
|
|
35
|
+
minBody?: number;
|
|
36
|
+
}
|
|
37
|
+
/** Index-ordered candle rects + a shared price y-scale over [low…high]. */
|
|
38
|
+
export declare function layoutCandles(candles: readonly Candle[], width: number, height: number, options?: CandleLayoutOptions): CandleLayout;
|
|
39
|
+
//# sourceMappingURL=candles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candles.d.ts","sourceRoot":"","sources":["../../src/geometry/candles.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,oCAAoC;IACpC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,oCAAoC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,mBAAwB,GAChC,YAAY,CAkCd"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OHLC candlestick geometry (`chart-candlestick`, research/widget-registry.md
|
|
3
|
+
* §2). Pure + DOM-free. The price axis is a fixed LTR-island convention
|
|
4
|
+
* (04 §7.4 exceptions: candlestick price axis never mirrors), so this layout
|
|
5
|
+
* takes no `rtl` flag — candles are index-ordered left→right regardless of
|
|
6
|
+
* page direction.
|
|
7
|
+
*/
|
|
8
|
+
import { extent, niceTicks } from '../utils/stats.js';
|
|
9
|
+
/** Index-ordered candle rects + a shared price y-scale over [low…high]. */
|
|
10
|
+
export function layoutCandles(candles, width, height, options = {}) {
|
|
11
|
+
const { bodyRatio = 0.6, tickCount = 4, minBody = 1 } = options;
|
|
12
|
+
const prices = candles.flatMap((candle) => [candle.h, candle.l, candle.o, candle.c]);
|
|
13
|
+
const [minPrice, maxPrice] = extent(prices) ?? [0, 1];
|
|
14
|
+
const yTicks = minPrice === maxPrice ? [minPrice, minPrice + 1] : niceTicks(minPrice, maxPrice, tickCount);
|
|
15
|
+
const domainLo = yTicks[0] ?? minPrice;
|
|
16
|
+
const domainHi = yTicks.at(-1) ?? maxPrice;
|
|
17
|
+
const span = domainHi - domainLo || 1;
|
|
18
|
+
const yFor = (value) => height - ((value - domainLo) / span) * height;
|
|
19
|
+
const slot = candles.length > 0 ? width / candles.length : width;
|
|
20
|
+
const bodyWidth = Math.max(1, slot * bodyRatio);
|
|
21
|
+
const rects = candles.map((candle, index) => {
|
|
22
|
+
const centerX = slot * (index + 0.5);
|
|
23
|
+
const openY = yFor(candle.o);
|
|
24
|
+
const closeY = yFor(candle.c);
|
|
25
|
+
const up = candle.c >= candle.o;
|
|
26
|
+
const top = Math.min(openY, closeY);
|
|
27
|
+
const bodyHeight = Math.max(minBody, Math.abs(closeY - openY));
|
|
28
|
+
return {
|
|
29
|
+
index,
|
|
30
|
+
centerX,
|
|
31
|
+
x: centerX - bodyWidth / 2,
|
|
32
|
+
width: bodyWidth,
|
|
33
|
+
bodyY: top,
|
|
34
|
+
bodyHeight,
|
|
35
|
+
highY: yFor(candle.h),
|
|
36
|
+
lowY: yFor(candle.l),
|
|
37
|
+
up,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
return { rects, yFor, yTicks };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=candles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candles.js","sourceRoot":"","sources":["../../src/geometry/candles.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA0CtD,2EAA2E;AAC3E,MAAM,UAAU,aAAa,CAC3B,OAA0B,EAC1B,KAAa,EACb,MAAc,EACd,UAA+B,EAAE;IAEjC,MAAM,EAAE,SAAS,GAAG,GAAG,EAAE,SAAS,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC3G,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC3C,MAAM,IAAI,GAAG,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;IAE9E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IACjE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAiB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACxD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;QAC/D,OAAO;YACL,KAAK;YACL,OAAO;YACP,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,CAAC;YAC1B,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,GAAG;YACV,UAAU;YACV,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACrB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACpB,EAAE;SACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface ChordNodeInput {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ChordArc {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
startAngle: number;
|
|
9
|
+
endAngle: number;
|
|
10
|
+
midAngle: number;
|
|
11
|
+
/** Total weight incident to this node. */
|
|
12
|
+
total: number;
|
|
13
|
+
path: string;
|
|
14
|
+
colorVar: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ChordRibbon {
|
|
17
|
+
from: string;
|
|
18
|
+
to: string;
|
|
19
|
+
weight: number;
|
|
20
|
+
path: string;
|
|
21
|
+
colorVar: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ChordLayout {
|
|
24
|
+
arcs: ChordArc[];
|
|
25
|
+
ribbons: ChordRibbon[];
|
|
26
|
+
radius: number;
|
|
27
|
+
center: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface ChordOptions {
|
|
33
|
+
size: number;
|
|
34
|
+
/** Arc band thickness in px (default 12). */
|
|
35
|
+
thickness?: number;
|
|
36
|
+
/** Angular padding between node arcs, radians (default 0.04). */
|
|
37
|
+
padAngle?: number;
|
|
38
|
+
rtl?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Chord layout for `nodes` and a symmetric `weights` matrix
|
|
42
|
+
* (weights[i][j] = volume between node i and node j; the diagonal is ignored).
|
|
43
|
+
* Nodes with zero total weight still receive a minimal arc so the ring stays
|
|
44
|
+
* stable. Returns empty layout for <2 nodes or a non-positive size.
|
|
45
|
+
*/
|
|
46
|
+
export declare function chordLayout(nodes: readonly ChordNodeInput[], weights: readonly (readonly number[])[], options: ChordOptions): ChordLayout;
|
|
47
|
+
/** Build a symmetric adjacency matrix from flows links keyed by node id. */
|
|
48
|
+
export declare function adjacencyMatrix(nodeIds: readonly string[], links: readonly {
|
|
49
|
+
from: string;
|
|
50
|
+
to: string;
|
|
51
|
+
weight: number;
|
|
52
|
+
}[]): number[][];
|
|
53
|
+
//# sourceMappingURL=chord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chord.d.ts","sourceRoot":"","sources":["../../src/geometry/chord.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAWD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,cAAc,EAAE,EAChC,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACvC,OAAO,EAAE,YAAY,GACpB,WAAW,CAuEb;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,GAC7D,MAAM,EAAE,EAAE,CAeZ"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure chord geometry (`chart-chord`, research/widget-registry.md §2): nodes on
|
|
3
|
+
* a ring sized by total pairwise volume, connected by quadratic-bezier ribbons
|
|
4
|
+
* whose thickness encodes pair weight. Built from a symmetric flows adjacency
|
|
5
|
+
* matrix. DOM-free + deterministic — the same ribbon paths render in Node and
|
|
6
|
+
* the browser (04 §7.1). Circular layouts step clockwise (LTR) or CCW (RTL) so
|
|
7
|
+
* node order mirrors per §7.4.
|
|
8
|
+
*/
|
|
9
|
+
import { arc } from 'd3-shape';
|
|
10
|
+
const TAU = Math.PI * 2;
|
|
11
|
+
function vizColor(index) {
|
|
12
|
+
return `var(--viz-${(index % 8) + 1})`;
|
|
13
|
+
}
|
|
14
|
+
function pointOnCircle(cx, cy, radius, angle) {
|
|
15
|
+
// Angles measured from 12 o'clock, clockwise.
|
|
16
|
+
return { x: cx + Math.sin(angle) * radius, y: cy - Math.cos(angle) * radius };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Chord layout for `nodes` and a symmetric `weights` matrix
|
|
20
|
+
* (weights[i][j] = volume between node i and node j; the diagonal is ignored).
|
|
21
|
+
* Nodes with zero total weight still receive a minimal arc so the ring stays
|
|
22
|
+
* stable. Returns empty layout for <2 nodes or a non-positive size.
|
|
23
|
+
*/
|
|
24
|
+
export function chordLayout(nodes, weights, options) {
|
|
25
|
+
const { size, thickness = 12, padAngle = 0.04, rtl = false } = options;
|
|
26
|
+
const n = nodes.length;
|
|
27
|
+
const radius = Math.max(0, size / 2);
|
|
28
|
+
const center = { x: radius, y: radius };
|
|
29
|
+
if (n < 2 || radius <= 0)
|
|
30
|
+
return { arcs: [], ribbons: [], radius, center };
|
|
31
|
+
const innerRing = radius - thickness;
|
|
32
|
+
const totals = nodes.map((_, i) => {
|
|
33
|
+
let sum = 0;
|
|
34
|
+
for (let j = 0; j < n; j += 1) {
|
|
35
|
+
if (i === j)
|
|
36
|
+
continue;
|
|
37
|
+
const w = weights[i]?.[j];
|
|
38
|
+
if (Number.isFinite(w) && w > 0)
|
|
39
|
+
sum += w;
|
|
40
|
+
}
|
|
41
|
+
return sum;
|
|
42
|
+
});
|
|
43
|
+
const grandTotal = totals.reduce((s, v) => s + v, 0);
|
|
44
|
+
const totalPad = padAngle * n;
|
|
45
|
+
const usable = Math.max(0, TAU - totalPad);
|
|
46
|
+
// Equal split fallback when there is no weight at all.
|
|
47
|
+
const share = (value) => (grandTotal > 0 ? (value / grandTotal) * usable : usable / n);
|
|
48
|
+
const arcGen = arc()
|
|
49
|
+
.innerRadius(innerRing)
|
|
50
|
+
.outerRadius(radius);
|
|
51
|
+
const arcs = [];
|
|
52
|
+
let angle = 0;
|
|
53
|
+
const direction = rtl ? -1 : 1;
|
|
54
|
+
for (let i = 0; i < n; i += 1) {
|
|
55
|
+
const span = share(totals[i]);
|
|
56
|
+
const start = angle + padAngle / 2;
|
|
57
|
+
const end = start + span;
|
|
58
|
+
angle = end + padAngle / 2;
|
|
59
|
+
const node = nodes[i];
|
|
60
|
+
// d3 arc angles are clockwise from 12 o'clock; apply direction for RTL.
|
|
61
|
+
const a0 = direction === 1 ? start : TAU - end;
|
|
62
|
+
const a1 = direction === 1 ? end : TAU - start;
|
|
63
|
+
arcs.push({
|
|
64
|
+
id: node.id,
|
|
65
|
+
label: node.label,
|
|
66
|
+
startAngle: a0,
|
|
67
|
+
endAngle: a1,
|
|
68
|
+
midAngle: (a0 + a1) / 2,
|
|
69
|
+
total: totals[i],
|
|
70
|
+
path: arcGen({ startAngle: a0, endAngle: a1 }) ?? '',
|
|
71
|
+
colorVar: vizColor(i),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const byId = new Map(arcs.map((a) => [a.id, a]));
|
|
75
|
+
const ribbons = [];
|
|
76
|
+
for (let i = 0; i < n; i += 1) {
|
|
77
|
+
for (let j = i + 1; j < n; j += 1) {
|
|
78
|
+
const w = weights[i]?.[j];
|
|
79
|
+
if (!Number.isFinite(w) || w <= 0)
|
|
80
|
+
continue;
|
|
81
|
+
const a = arcs[i];
|
|
82
|
+
const b = arcs[j];
|
|
83
|
+
const p1 = pointOnCircle(center.x, center.y, innerRing, a.midAngle);
|
|
84
|
+
const p2 = pointOnCircle(center.x, center.y, innerRing, b.midAngle);
|
|
85
|
+
// Quadratic bezier bowed toward the ring center.
|
|
86
|
+
const path = `M${p1.x.toFixed(3)},${p1.y.toFixed(3)}Q${center.x.toFixed(3)},${center.y.toFixed(3)} ${p2.x.toFixed(3)},${p2.y.toFixed(3)}`;
|
|
87
|
+
ribbons.push({ from: nodes[i].id, to: nodes[j].id, weight: w, path, colorVar: byId.get(a.id).colorVar });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { arcs, ribbons, radius, center };
|
|
91
|
+
}
|
|
92
|
+
/** Build a symmetric adjacency matrix from flows links keyed by node id. */
|
|
93
|
+
export function adjacencyMatrix(nodeIds, links) {
|
|
94
|
+
const index = new Map(nodeIds.map((id, i) => [id, i]));
|
|
95
|
+
const matrix = nodeIds.map(() => nodeIds.map(() => 0));
|
|
96
|
+
for (const link of links) {
|
|
97
|
+
const i = index.get(link.from);
|
|
98
|
+
const j = index.get(link.to);
|
|
99
|
+
if (i === undefined || j === undefined || i === j)
|
|
100
|
+
continue;
|
|
101
|
+
const rowI = matrix[i];
|
|
102
|
+
const rowJ = matrix[j];
|
|
103
|
+
if (rowI === undefined || rowJ === undefined)
|
|
104
|
+
continue;
|
|
105
|
+
const w = Number.isFinite(link.weight) ? Math.max(0, link.weight) : 0;
|
|
106
|
+
rowI[j] = (rowI[j] ?? 0) + w;
|
|
107
|
+
rowJ[i] = (rowJ[i] ?? 0) + w;
|
|
108
|
+
}
|
|
109
|
+
return matrix;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=chord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chord.js","sourceRoot":"","sources":["../../src/geometry/chord.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AA2CxB,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,aAAa,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,SAAS,aAAa,CAAC,EAAU,EAAE,EAAU,EAAE,MAAc,EAAE,KAAa;IAC1E,8CAA8C;IAC9C,OAAO,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC;AAChF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,KAAgC,EAChC,OAAuC,EACvC,OAAqB;IAErB,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACvE,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE3E,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChC,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC;gBAAE,SAAS;YACtB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAK,CAAY,GAAG,CAAC;gBAAE,GAAG,IAAI,CAAW,CAAC;QAClE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,CAAC;IAC3C,uDAAuD;IACvD,MAAM,KAAK,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEvG,MAAM,MAAM,GAAG,GAAG,EAA4C;SAC3D,WAAW,CAAC,SAAS,CAAC;SACtB,WAAW,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAW,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,KAAK,GAAG,IAAI,CAAC;QACzB,KAAK,GAAG,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAmB,CAAC;QACxC,wEAAwE;QACxE,MAAM,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;QAC/C,MAAM,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC;YACR,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,EAAE;YACd,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC;YACvB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAW;YAC1B,IAAI,EAAE,MAAM,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE;YACpD,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAK,CAAY,IAAI,CAAC;gBAAE,SAAS;YACxD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAa,CAAC;YAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAa,CAAC;YAC9B,MAAM,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACpE,MAAM,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACpE,iDAAiD;YACjD,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,CAC5F,CAAC,CACF,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAG,KAAK,CAAC,CAAC,CAAoB,CAAC,EAAE,EAAE,EAAE,EAAG,KAAK,CAAC,CAAC,CAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,CAAW,EAAE,IAAI,EAAE,QAAQ,EAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAc,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3K,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAC7B,OAA0B,EAC1B,KAA8D;IAE9D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACvD,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical 50-state + DC US tile grid (row, col) on an 8×11 board — a plausible
|
|
3
|
+
* geographic arrangement for the tilegram layout. Codes are USPS two-letter.
|
|
4
|
+
*/
|
|
5
|
+
export declare const US_TILEGRAM: Readonly<Record<string, readonly [number, number]>>;
|
|
6
|
+
export interface RegionPoint {
|
|
7
|
+
code?: string | undefined;
|
|
8
|
+
name?: string | undefined;
|
|
9
|
+
values: Record<string, number>;
|
|
10
|
+
}
|
|
11
|
+
export interface ChoroplethTile {
|
|
12
|
+
code: string;
|
|
13
|
+
name: string;
|
|
14
|
+
row: number;
|
|
15
|
+
col: number;
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
size: number;
|
|
19
|
+
value: number;
|
|
20
|
+
level: number;
|
|
21
|
+
colorVar: string;
|
|
22
|
+
textLight: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface ChoroplethLayout {
|
|
25
|
+
tiles: ChoroplethTile[];
|
|
26
|
+
levels: number;
|
|
27
|
+
maxValue: number;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
}
|
|
31
|
+
export type ChoroplethLayoutKind = 'us-tilegram' | 'grid';
|
|
32
|
+
export interface ChoroplethOptions {
|
|
33
|
+
layout?: ChoroplethLayoutKind;
|
|
34
|
+
/** Value key read from each point's `values` map. */
|
|
35
|
+
metric: string;
|
|
36
|
+
cellSize?: number;
|
|
37
|
+
gap?: number;
|
|
38
|
+
/** Columns for the compact `grid` layout (default 6). */
|
|
39
|
+
columns?: number;
|
|
40
|
+
/** Intensity levels incl. 0 (default 5). */
|
|
41
|
+
levels?: number;
|
|
42
|
+
rtl?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Tint region tiles by the selected metric. */
|
|
45
|
+
export declare function choroplethLayout(points: readonly RegionPoint[], options: ChoroplethOptions): ChoroplethLayout;
|
|
46
|
+
/**
|
|
47
|
+
* Whether any point carries a region code the US tilegram can actually place.
|
|
48
|
+
*
|
|
49
|
+
* The `us-tilegram` layout is a geographic island: it plots only the 50 states +
|
|
50
|
+
* DC it knows and silently drops every other code (the placement loop above). So
|
|
51
|
+
* a payload of non-US codes — or of coordinate-only points that carry no `code`
|
|
52
|
+
* at all — produces ZERO tiles there, leaving just the low→high legend: a legend
|
|
53
|
+
* for a map that is not on the page. Callers use this to fall back to the
|
|
54
|
+
* code-agnostic `grid` layout (which lays every point out in reading order,
|
|
55
|
+
* regardless of code) rather than render an empty board.
|
|
56
|
+
*/
|
|
57
|
+
export declare function hasUsTilegramTiles(points: readonly RegionPoint[]): boolean;
|
|
58
|
+
//# sourceMappingURL=choropleth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choropleth.d.ts","sourceRoot":"","sources":["../../src/geometry/choropleth.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAS3E,CAAC;AAKF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,EAAE,iBAAiB,GACzB,gBAAgB,CAoElB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAE1E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure tilegram / grid-choropleth geometry (research/widget-registry.md §2
|
|
3
|
+
* `chart-choropleth-grid`): region tiles tinted by value, label text flipping
|
|
4
|
+
* to the on-accent color on dark tiles, low→high legend. DOM-free and
|
|
5
|
+
* deterministic (workplan/04 §7.1).
|
|
6
|
+
*
|
|
7
|
+
* RTL policy (04 §7.4): the US tilegram is a geographic LTR island (its tiles
|
|
8
|
+
* never mirror, like `map-bubble`); the compact `grid` layout is a categorical
|
|
9
|
+
* flow and mirrors its columns under `rtl`. Legends/tooltips mirror at the
|
|
10
|
+
* widget layer via logical CSS.
|
|
11
|
+
*/
|
|
12
|
+
import { heatLevel, heatTextLight, rampColorVar } from './heat.js';
|
|
13
|
+
/**
|
|
14
|
+
* Canonical 50-state + DC US tile grid (row, col) on an 8×11 board — a plausible
|
|
15
|
+
* geographic arrangement for the tilegram layout. Codes are USPS two-letter.
|
|
16
|
+
*/
|
|
17
|
+
export const US_TILEGRAM = {
|
|
18
|
+
AK: [0, 0], ME: [0, 10],
|
|
19
|
+
VT: [1, 9], NH: [1, 10],
|
|
20
|
+
WA: [2, 0], ID: [2, 1], MT: [2, 2], ND: [2, 3], MN: [2, 4], IL: [2, 5], WI: [2, 6], MI: [2, 7], NY: [2, 9], MA: [2, 10],
|
|
21
|
+
OR: [3, 0], NV: [3, 1], WY: [3, 2], SD: [3, 3], IA: [3, 4], IN: [3, 5], OH: [3, 6], PA: [3, 7], NJ: [3, 8], CT: [3, 9], RI: [3, 10],
|
|
22
|
+
CA: [4, 0], UT: [4, 1], CO: [4, 2], NE: [4, 3], MO: [4, 4], KY: [4, 5], WV: [4, 6], VA: [4, 7], MD: [4, 8], DE: [4, 9],
|
|
23
|
+
AZ: [5, 1], NM: [5, 2], KS: [5, 3], AR: [5, 4], TN: [5, 5], NC: [5, 6], SC: [5, 7], DC: [5, 8],
|
|
24
|
+
OK: [6, 3], LA: [6, 4], MS: [6, 5], AL: [6, 6], GA: [6, 7],
|
|
25
|
+
HI: [7, 0], TX: [7, 3], FL: [7, 8],
|
|
26
|
+
};
|
|
27
|
+
const US_TILEGRAM_COLS = 11;
|
|
28
|
+
const US_TILEGRAM_ROWS = 8;
|
|
29
|
+
/** Tint region tiles by the selected metric. */
|
|
30
|
+
export function choroplethLayout(points, options) {
|
|
31
|
+
const { layout = 'us-tilegram', metric, cellSize = 34, gap = 4, columns = 6, levels = 5, rtl = false, } = options;
|
|
32
|
+
const step = cellSize + gap;
|
|
33
|
+
const valueOf = (p) => {
|
|
34
|
+
const v = p.values[metric];
|
|
35
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : 0;
|
|
36
|
+
};
|
|
37
|
+
const maxValue = points.reduce((max, p) => Math.max(max, valueOf(p)), 0);
|
|
38
|
+
let placed;
|
|
39
|
+
let cols;
|
|
40
|
+
let rows;
|
|
41
|
+
if (layout === 'us-tilegram') {
|
|
42
|
+
cols = US_TILEGRAM_COLS;
|
|
43
|
+
rows = US_TILEGRAM_ROWS;
|
|
44
|
+
placed = [];
|
|
45
|
+
for (const point of points) {
|
|
46
|
+
const code = (point.code ?? '').toUpperCase();
|
|
47
|
+
const cell = US_TILEGRAM[code];
|
|
48
|
+
if (cell === undefined)
|
|
49
|
+
continue; // unknown code — geographic island only plots known tiles
|
|
50
|
+
placed.push({ point, row: cell[0], col: cell[1] });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
cols = Math.max(1, columns);
|
|
55
|
+
rows = Math.max(1, Math.ceil(points.length / cols));
|
|
56
|
+
placed = points.map((point, i) => ({ point, row: Math.floor(i / cols), col: i % cols }));
|
|
57
|
+
}
|
|
58
|
+
// Geographic tilegram never mirrors; the categorical grid mirrors columns.
|
|
59
|
+
const mirror = rtl && layout === 'grid';
|
|
60
|
+
const colX = (col) => (mirror ? cols - 1 - col : col) * step;
|
|
61
|
+
const tiles = placed.map(({ point, row, col }) => {
|
|
62
|
+
const value = valueOf(point);
|
|
63
|
+
const level = heatLevel(value, maxValue, levels);
|
|
64
|
+
const code = (point.code ?? '').toUpperCase();
|
|
65
|
+
return {
|
|
66
|
+
code,
|
|
67
|
+
name: point.name ?? code,
|
|
68
|
+
row,
|
|
69
|
+
col,
|
|
70
|
+
x: colX(col),
|
|
71
|
+
y: row * step,
|
|
72
|
+
size: cellSize,
|
|
73
|
+
value,
|
|
74
|
+
level,
|
|
75
|
+
colorVar: rampColorVar(level, levels),
|
|
76
|
+
textLight: heatTextLight(level, levels),
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
tiles,
|
|
81
|
+
levels,
|
|
82
|
+
maxValue,
|
|
83
|
+
width: cols > 0 ? cols * step - gap : 0,
|
|
84
|
+
height: rows > 0 ? rows * step - gap : 0,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether any point carries a region code the US tilegram can actually place.
|
|
89
|
+
*
|
|
90
|
+
* The `us-tilegram` layout is a geographic island: it plots only the 50 states +
|
|
91
|
+
* DC it knows and silently drops every other code (the placement loop above). So
|
|
92
|
+
* a payload of non-US codes — or of coordinate-only points that carry no `code`
|
|
93
|
+
* at all — produces ZERO tiles there, leaving just the low→high legend: a legend
|
|
94
|
+
* for a map that is not on the page. Callers use this to fall back to the
|
|
95
|
+
* code-agnostic `grid` layout (which lays every point out in reading order,
|
|
96
|
+
* regardless of code) rather than render an empty board.
|
|
97
|
+
*/
|
|
98
|
+
export function hasUsTilegramTiles(points) {
|
|
99
|
+
return points.some((point) => US_TILEGRAM[(point.code ?? '').toUpperCase()] !== undefined);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=choropleth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choropleth.js","sourceRoot":"","sources":["../../src/geometry/choropleth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface CohortCell {
|
|
2
|
+
row: number;
|
|
3
|
+
col: number;
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
size: number;
|
|
7
|
+
/** Cell value (e.g. retention %); null renders the triangular gap. */
|
|
8
|
+
value: number | null;
|
|
9
|
+
/** Sequential ramp level; -1 for null gaps. */
|
|
10
|
+
level: number;
|
|
11
|
+
/** Ramp color var(), or 'none' for null gaps. */
|
|
12
|
+
colorVar: string;
|
|
13
|
+
/** Whether the value label should use the on-accent color. */
|
|
14
|
+
textLight: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface CohortAxisLabel {
|
|
17
|
+
index: number;
|
|
18
|
+
/** Center coordinate along the axis (x for columns, y for rows). */
|
|
19
|
+
pos: number;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CohortLayout {
|
|
23
|
+
cells: CohortCell[];
|
|
24
|
+
rowLabels: CohortAxisLabel[];
|
|
25
|
+
colLabels: CohortAxisLabel[];
|
|
26
|
+
/** Total plotted width/height (grid + gutters/header). */
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
/** Inline-start x of the cohort label gutter text anchor edge. */
|
|
30
|
+
rowLabelX: number;
|
|
31
|
+
/** Text anchor for the cohort (row) labels given the direction. */
|
|
32
|
+
rowLabelAnchor: 'start' | 'end';
|
|
33
|
+
}
|
|
34
|
+
export interface CohortOptions {
|
|
35
|
+
cellSize?: number;
|
|
36
|
+
gap?: number;
|
|
37
|
+
/** Width reserved for cohort (row) labels. */
|
|
38
|
+
rowLabelWidth?: number;
|
|
39
|
+
/** Height reserved for the period (column) header. */
|
|
40
|
+
colLabelHeight?: number;
|
|
41
|
+
rtl?: boolean;
|
|
42
|
+
/** Value at/above which label text flips to the on-accent color. Default 55. */
|
|
43
|
+
flipThreshold?: number;
|
|
44
|
+
/** Number of ramp levels (incl. 0). Default 7 → viz-ramp-1..6. */
|
|
45
|
+
levels?: number;
|
|
46
|
+
/** Value that maps to the darkest ramp step. Default 100 (percent scale). */
|
|
47
|
+
maxValue?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Lay out a (possibly triangular) cohort matrix. `cells[r][c]` is the value at
|
|
51
|
+
* cohort `r`, period `c`; `null`/`undefined` cells are transparent gaps.
|
|
52
|
+
*/
|
|
53
|
+
export declare function cohortLayout(rowKeys: readonly string[], colKeys: readonly string[], cells: readonly (readonly (number | null)[])[], options?: CohortOptions): CohortLayout;
|
|
54
|
+
//# sourceMappingURL=cohort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cohort.d.ts","sourceRoot":"","sources":["../../src/geometry/cohort.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,cAAc,EAAE,OAAO,GAAG,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,EAC9C,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAkEd"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure cohort-retention matrix geometry (research/widget-registry.md §2
|
|
3
|
+
* `chart-cohort-matrix`): cohort rows × period columns, accent alpha by value,
|
|
4
|
+
* triangular nulls transparent, label text flips to the on-accent color past a
|
|
5
|
+
* threshold (~55%). DOM-free and deterministic (workplan/04 §7.1) so the same
|
|
6
|
+
* SVG path/positions render in Node and the browser (acceptance #10).
|
|
7
|
+
*
|
|
8
|
+
* RTL policy (04 §7.4): the period columns are a horizontal categorical scale,
|
|
9
|
+
* so they mirror under `rtl` (rightmost = M0) with the cohort label gutter on
|
|
10
|
+
* the inline-start (physical right) side; the vertical cohort rows never move.
|
|
11
|
+
*/
|
|
12
|
+
import { heatLevel, rampColorVar } from './heat.js';
|
|
13
|
+
/**
|
|
14
|
+
* Lay out a (possibly triangular) cohort matrix. `cells[r][c]` is the value at
|
|
15
|
+
* cohort `r`, period `c`; `null`/`undefined` cells are transparent gaps.
|
|
16
|
+
*/
|
|
17
|
+
export function cohortLayout(rowKeys, colKeys, cells, options = {}) {
|
|
18
|
+
const { cellSize = 40, gap = 3, rowLabelWidth = 72, colLabelHeight = 20, rtl = false, flipThreshold = 55, levels = 7, maxValue = 100, } = options;
|
|
19
|
+
const step = cellSize + gap;
|
|
20
|
+
const cols = colKeys.length;
|
|
21
|
+
const rows = rowKeys.length;
|
|
22
|
+
const gridWidth = cols > 0 ? cols * step - gap : 0;
|
|
23
|
+
const gridHeight = rows > 0 ? rows * step - gap : 0;
|
|
24
|
+
const width = rowLabelWidth + gridWidth;
|
|
25
|
+
const height = colLabelHeight + gridHeight;
|
|
26
|
+
// Column x within the grid area; mirrors the categorical order in RTL. The
|
|
27
|
+
// cohort label gutter sits on the inline-start (left in LTR, right in RTL).
|
|
28
|
+
const gridOriginX = rtl ? 0 : rowLabelWidth;
|
|
29
|
+
const colX = (col) => gridOriginX + (rtl ? cols - 1 - col : col) * step;
|
|
30
|
+
const out = [];
|
|
31
|
+
for (let r = 0; r < rows; r += 1) {
|
|
32
|
+
const rowCells = cells[r] ?? [];
|
|
33
|
+
for (let c = 0; c < cols; c += 1) {
|
|
34
|
+
const raw = rowCells[c];
|
|
35
|
+
const value = typeof raw === 'number' && Number.isFinite(raw) ? raw : null;
|
|
36
|
+
const level = value === null ? -1 : heatLevel(value, maxValue, levels);
|
|
37
|
+
out.push({
|
|
38
|
+
row: r,
|
|
39
|
+
col: c,
|
|
40
|
+
x: colX(c),
|
|
41
|
+
y: colLabelHeight + r * step,
|
|
42
|
+
size: cellSize,
|
|
43
|
+
value,
|
|
44
|
+
level,
|
|
45
|
+
colorVar: value === null ? 'none' : rampColorVar(level, levels),
|
|
46
|
+
textLight: value !== null && value >= flipThreshold,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const colLabels = colKeys.map((label, c) => ({
|
|
51
|
+
index: c,
|
|
52
|
+
pos: colX(c) + cellSize / 2,
|
|
53
|
+
label,
|
|
54
|
+
}));
|
|
55
|
+
const rowLabels = rowKeys.map((label, r) => ({
|
|
56
|
+
index: r,
|
|
57
|
+
pos: colLabelHeight + r * step + cellSize / 2,
|
|
58
|
+
label,
|
|
59
|
+
}));
|
|
60
|
+
return {
|
|
61
|
+
cells: out,
|
|
62
|
+
rowLabels,
|
|
63
|
+
colLabels,
|
|
64
|
+
width,
|
|
65
|
+
height,
|
|
66
|
+
rowLabelX: rtl ? gridWidth + 8 : rowLabelWidth - 8,
|
|
67
|
+
rowLabelAnchor: rtl ? 'start' : 'end',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=cohort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../src/geometry/cohort.ts"],"names":[],"mappings":"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"}
|