@pushwoosh/kit-charts 0.0.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 +21 -0
- package/ai-documentation.md +378 -0
- package/core/Chart/Axes.d.ts +19 -0
- package/core/Chart/Axes.js +204 -0
- package/core/Chart/Chart.d.ts +33 -0
- package/core/Chart/Chart.js +616 -0
- package/core/Chart/Chart.styles.d.ts +109 -0
- package/core/Chart/Chart.styles.js +227 -0
- package/core/Chart/ChartErrorBoundary.d.ts +15 -0
- package/core/Chart/ChartErrorBoundary.js +27 -0
- package/core/Chart/Hinted.d.ts +11 -0
- package/core/Chart/Hinted.js +63 -0
- package/core/Chart/Legend.d.ts +15 -0
- package/core/Chart/Legend.js +92 -0
- package/core/Chart/PlotDecorations.d.ts +17 -0
- package/core/Chart/PlotDecorations.js +172 -0
- package/core/Chart/StackLabels.d.ts +6 -0
- package/core/Chart/StackLabels.js +85 -0
- package/core/Chart/Titles.d.ts +6 -0
- package/core/Chart/Titles.js +67 -0
- package/core/Chart/Tooltip.d.ts +13 -0
- package/core/Chart/Tooltip.js +87 -0
- package/core/Chart/useSize.d.ts +5 -0
- package/core/Chart/useSize.js +45 -0
- package/core/animation/motion.d.ts +20 -0
- package/core/animation/motion.js +20 -0
- package/core/animation/useTweenedNumbers.d.ts +1 -0
- package/core/animation/useTweenedNumbers.js +51 -0
- package/core/data/points.d.ts +14 -0
- package/core/data/points.js +73 -0
- package/core/format/time.d.ts +2 -0
- package/core/format/time.js +38 -0
- package/core/geometry/path.d.ts +19 -0
- package/core/geometry/path.js +76 -0
- package/core/layout/legend-layout.d.ts +21 -0
- package/core/layout/legend-layout.js +103 -0
- package/core/layout/measure-text.d.ts +9 -0
- package/core/layout/measure-text.js +57 -0
- package/core/layout/metrics.d.ts +63 -0
- package/core/layout/metrics.js +66 -0
- package/core/layout/point-width.d.ts +11 -0
- package/core/layout/point-width.js +86 -0
- package/core/layout/title-layout.d.ts +30 -0
- package/core/layout/title-layout.js +99 -0
- package/core/model/build-model.d.ts +69 -0
- package/core/model/build-model.js +556 -0
- package/core/model/palette.d.ts +15 -0
- package/core/model/palette.js +17 -0
- package/core/options/normalize.d.ts +8 -0
- package/core/options/normalize.js +44 -0
- package/core/registry/registry.d.ts +5 -0
- package/core/registry/registry.js +32 -0
- package/core/scale/band.d.ts +10 -0
- package/core/scale/band.js +33 -0
- package/core/scale/color.d.ts +9 -0
- package/core/scale/color.js +69 -0
- package/core/scale/linear.d.ts +17 -0
- package/core/scale/linear.js +64 -0
- package/core/scale/time.d.ts +19 -0
- package/core/scale/time.js +187 -0
- package/core/stack/stack.d.ts +9 -0
- package/core/stack/stack.js +76 -0
- package/core/types/formatter.d.ts +59 -0
- package/core/types/formatter.js +1 -0
- package/core/types/geometry.d.ts +16 -0
- package/core/types/geometry.js +1 -0
- package/core/types/options.d.ts +331 -0
- package/core/types/options.js +2 -0
- package/core/types/renderer.d.ts +101 -0
- package/core/types/renderer.js +1 -0
- package/core/types/scale.d.ts +34 -0
- package/core/types/scale.js +1 -0
- package/index.d.ts +16 -0
- package/index.js +10 -0
- package/package.json +64 -0
- package/presets/AreaChart.d.ts +3 -0
- package/presets/AreaChart.js +13 -0
- package/presets/ColumnChart.d.ts +3 -0
- package/presets/ColumnChart.js +13 -0
- package/presets/LineChart.d.ts +3 -0
- package/presets/LineChart.js +13 -0
- package/presets/PieChart.d.ts +3 -0
- package/presets/PieChart.js +13 -0
- package/presets/StackedColumnChart.d.ts +7 -0
- package/presets/StackedColumnChart.js +31 -0
- package/presets/index.d.ts +5 -0
- package/presets/index.js +5 -0
- package/series/area/area.d.ts +2 -0
- package/series/area/area.js +57 -0
- package/series/area/index.d.ts +1 -0
- package/series/area/index.js +1 -0
- package/series/column/column.d.ts +2 -0
- package/series/column/column.js +163 -0
- package/series/column/index.d.ts +1 -0
- package/series/column/index.js +1 -0
- package/series/heatmap/heatmap.d.ts +2 -0
- package/series/heatmap/heatmap.js +172 -0
- package/series/heatmap/index.d.ts +1 -0
- package/series/heatmap/index.js +1 -0
- package/series/line/index.d.ts +1 -0
- package/series/line/index.js +1 -0
- package/series/line/line.d.ts +2 -0
- package/series/line/line.js +49 -0
- package/series/pie/index.d.ts +1 -0
- package/series/pie/index.js +1 -0
- package/series/pie/pie.d.ts +2 -0
- package/series/pie/pie.js +224 -0
- package/series/shared/DataLabels.d.ts +14 -0
- package/series/shared/DataLabels.js +124 -0
- package/series/shared/Markers.d.ts +9 -0
- package/series/shared/Markers.js +34 -0
- package/series/shared/color.d.ts +1 -0
- package/series/shared/color.js +19 -0
- package/series/shared/domain.d.ts +3 -0
- package/series/shared/domain.js +14 -0
- package/series/shared/hit.d.ts +3 -0
- package/series/shared/hit.js +33 -0
- package/series/shared/legend.d.ts +3 -0
- package/series/shared/legend.js +12 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { Chart } from '../core/Chart/Chart';
|
|
4
|
+
import { column } from '../series/column';
|
|
5
|
+
export function StackedColumnChart(props) {
|
|
6
|
+
const {
|
|
7
|
+
renderers,
|
|
8
|
+
stacking = 'normal',
|
|
9
|
+
options,
|
|
10
|
+
...rest
|
|
11
|
+
} = props;
|
|
12
|
+
const stackedOptions = useMemo(() => {
|
|
13
|
+
const plotOptions = options.plotOptions ?? {};
|
|
14
|
+
const columnOptions = plotOptions.column ?? {};
|
|
15
|
+
return {
|
|
16
|
+
...options,
|
|
17
|
+
plotOptions: {
|
|
18
|
+
...plotOptions,
|
|
19
|
+
column: {
|
|
20
|
+
stacking,
|
|
21
|
+
...columnOptions
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}, [options, stacking]);
|
|
26
|
+
return _jsx(Chart, {
|
|
27
|
+
...rest,
|
|
28
|
+
options: stackedOptions,
|
|
29
|
+
renderers: renderers ? [column, ...renderers] : [column]
|
|
30
|
+
});
|
|
31
|
+
}
|
package/presets/index.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { drawable, projectSeries, toAreaPath, toLinePath } from '../../core/geometry/path';
|
|
3
|
+
import { includeZero } from '../shared/domain';
|
|
4
|
+
import { nearestByX } from '../shared/hit';
|
|
5
|
+
import { seriesLegend } from '../shared/legend';
|
|
6
|
+
import { Markers } from '../shared/Markers';
|
|
7
|
+
const DEFAULT_FILL_OPACITY = 0.75;
|
|
8
|
+
export const area = {
|
|
9
|
+
type: 'area',
|
|
10
|
+
scales: {
|
|
11
|
+
x: 'linear',
|
|
12
|
+
y: 'linear'
|
|
13
|
+
},
|
|
14
|
+
extendDomain: (series, acc) => includeZero(series, acc),
|
|
15
|
+
render: ctx => {
|
|
16
|
+
var _ctx$hovered, _ctx$series$marker;
|
|
17
|
+
const slots = projectSeries(ctx);
|
|
18
|
+
const projected = drawable(slots);
|
|
19
|
+
if (!projected.length) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const color = ctx.color;
|
|
23
|
+
const lineWidth = ctx.series.lineWidth ?? 2;
|
|
24
|
+
const hoveredIndex = (_ctx$hovered = ctx.hovered) === null || _ctx$hovered === void 0 ? void 0 : _ctx$hovered.pointIndex;
|
|
25
|
+
const hovered = hoveredIndex === undefined ? undefined : projected.find(({
|
|
26
|
+
point
|
|
27
|
+
}) => point.index === hoveredIndex);
|
|
28
|
+
return _jsxs("g", {
|
|
29
|
+
children: [_jsx("path", {
|
|
30
|
+
d: toAreaPath(slots),
|
|
31
|
+
fill: color,
|
|
32
|
+
fillOpacity: ctx.series.fillOpacity ?? DEFAULT_FILL_OPACITY,
|
|
33
|
+
stroke: "none"
|
|
34
|
+
}), lineWidth ? _jsx("path", {
|
|
35
|
+
d: toLinePath(slots),
|
|
36
|
+
fill: "none",
|
|
37
|
+
stroke: color,
|
|
38
|
+
strokeWidth: lineWidth,
|
|
39
|
+
strokeLinecap: "round",
|
|
40
|
+
strokeLinejoin: "round"
|
|
41
|
+
}) : null, _jsx(Markers, {
|
|
42
|
+
marker: ctx.series.marker,
|
|
43
|
+
projected: projected,
|
|
44
|
+
color: color
|
|
45
|
+
}), hovered ? _jsx("circle", {
|
|
46
|
+
cx: hovered.px,
|
|
47
|
+
cy: hovered.py,
|
|
48
|
+
r: ((_ctx$series$marker = ctx.series.marker) === null || _ctx$series$marker === void 0 || (_ctx$series$marker = _ctx$series$marker.states) === null || _ctx$series$marker === void 0 || (_ctx$series$marker = _ctx$series$marker.hover) === null || _ctx$series$marker === void 0 ? void 0 : _ctx$series$marker.radius) ?? 4,
|
|
49
|
+
fill: color,
|
|
50
|
+
stroke: "#FFFFFF",
|
|
51
|
+
strokeWidth: 2
|
|
52
|
+
}) : null]
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
hitTest: (ctx, pointer) => nearestByX(ctx, pointer),
|
|
56
|
+
legendItems: (series, seriesIndex) => seriesLegend(series, seriesIndex, 'square')
|
|
57
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { area } from './area';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { area } from './area';
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { pointKey } from '../../core/data/points';
|
|
3
|
+
import { drawable, projectSeries } from '../../core/geometry/path';
|
|
4
|
+
import { TEXT_BASELINE_SHIFT, VALUE_LABEL_GAP } from '../../core/layout/metrics';
|
|
5
|
+
import { brighten } from '../shared/color';
|
|
6
|
+
import { DataLabels } from '../shared/DataLabels';
|
|
7
|
+
import { includeZero } from '../shared/domain';
|
|
8
|
+
import { seriesLegend } from '../shared/legend';
|
|
9
|
+
const DEFAULT_HOVER_BRIGHTNESS = 0.1;
|
|
10
|
+
const SLOT_FALLBACK = {
|
|
11
|
+
width: 10,
|
|
12
|
+
offset: 0
|
|
13
|
+
};
|
|
14
|
+
function toBars(ctx) {
|
|
15
|
+
const slot = ctx.slot ?? SLOT_FALLBACK;
|
|
16
|
+
const minLength = ctx.series.minPointLength ?? 0;
|
|
17
|
+
return drawable(projectSeries(ctx)).map(projected => {
|
|
18
|
+
const centre = projected.px + slot.offset;
|
|
19
|
+
// Switched off: sit flat on the bar's own base. Every bar then shrinks into the
|
|
20
|
+
// place it grew from, which for a stack is the segment below it.
|
|
21
|
+
if (ctx.hidden) {
|
|
22
|
+
return {
|
|
23
|
+
...projected,
|
|
24
|
+
x: centre - slot.width / 2,
|
|
25
|
+
y: projected.baseY,
|
|
26
|
+
width: slot.width,
|
|
27
|
+
height: 0
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const raw = Math.abs(projected.py - projected.baseY);
|
|
31
|
+
const height = Math.max(raw, minLength);
|
|
32
|
+
// Growing a bar to `minPointLength` must keep it on its own side of the
|
|
33
|
+
// baseline, so a value at the axis minimum stays visible without flipping.
|
|
34
|
+
const top = projected.py <= projected.baseY ? Math.min(projected.py, projected.baseY) - (height - raw) : Math.min(projected.py, projected.baseY);
|
|
35
|
+
return {
|
|
36
|
+
...projected,
|
|
37
|
+
x: centre - slot.width / 2,
|
|
38
|
+
y: top,
|
|
39
|
+
width: slot.width,
|
|
40
|
+
height
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const fillOf = (ctx, bar, hovered) => {
|
|
45
|
+
var _ctx$series$states;
|
|
46
|
+
const base = bar.point.color ?? ctx.color;
|
|
47
|
+
if (!hovered) {
|
|
48
|
+
return base;
|
|
49
|
+
}
|
|
50
|
+
return brighten(base, ((_ctx$series$states = ctx.series.states) === null || _ctx$series$states === void 0 || (_ctx$series$states = _ctx$series$states.hover) === null || _ctx$series$states === void 0 ? void 0 : _ctx$series$states.brightness) ?? DEFAULT_HOVER_BRIGHTNESS);
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A translucent body under a solid rule is the funnel look: the series keeps its
|
|
54
|
+
* real colour, so the legend and the tooltip swatch stay readable, and only the
|
|
55
|
+
* bar is washed out. Hovering deepens it.
|
|
56
|
+
*/
|
|
57
|
+
const opacityOf = (ctx, hovered) => {
|
|
58
|
+
var _ctx$series$states2;
|
|
59
|
+
const base = ctx.series.fillOpacity;
|
|
60
|
+
if (!hovered) {
|
|
61
|
+
return base;
|
|
62
|
+
}
|
|
63
|
+
return ((_ctx$series$states2 = ctx.series.states) === null || _ctx$series$states2 === void 0 || (_ctx$series$states2 = _ctx$series$states2.hover) === null || _ctx$series$states2 === void 0 ? void 0 : _ctx$series$states2.fillOpacity) ?? base;
|
|
64
|
+
};
|
|
65
|
+
export const column = {
|
|
66
|
+
type: 'column',
|
|
67
|
+
scales: {
|
|
68
|
+
x: 'band',
|
|
69
|
+
y: 'linear'
|
|
70
|
+
},
|
|
71
|
+
exit: 'collapse',
|
|
72
|
+
extendDomain: (series, acc) => includeZero(series, acc),
|
|
73
|
+
render: ctx => {
|
|
74
|
+
var _ctx$hovered;
|
|
75
|
+
const bars = toBars(ctx);
|
|
76
|
+
if (!bars.length) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const hoveredIndex = (_ctx$hovered = ctx.hovered) === null || _ctx$hovered === void 0 ? void 0 : _ctx$hovered.pointIndex;
|
|
80
|
+
const radius = ctx.series.borderRadius;
|
|
81
|
+
const borderWidth = ctx.series.borderWidth ?? 0;
|
|
82
|
+
const capped = borderWidth > 0 && ctx.series.borderPosition === 'top';
|
|
83
|
+
return _jsxs("g", {
|
|
84
|
+
children: [bars.map(bar => _jsx("rect", {
|
|
85
|
+
x: bar.x,
|
|
86
|
+
y: bar.y,
|
|
87
|
+
width: bar.width,
|
|
88
|
+
height: bar.height,
|
|
89
|
+
rx: radius,
|
|
90
|
+
ry: radius,
|
|
91
|
+
fill: fillOf(ctx, bar, bar.point.index === hoveredIndex),
|
|
92
|
+
fillOpacity: opacityOf(ctx, bar.point.index === hoveredIndex),
|
|
93
|
+
stroke: borderWidth && !capped ? ctx.series.borderColor : undefined,
|
|
94
|
+
strokeWidth: borderWidth && !capped ? borderWidth : undefined
|
|
95
|
+
}, `c-${bar.point.index}`)), capped ? bars.map(bar => {
|
|
96
|
+
// The rule sits on the value edge, so a bar counting down wears it below.
|
|
97
|
+
const edge = bar.py <= bar.baseY ? bar.y : bar.y + bar.height;
|
|
98
|
+
return _jsx("line", {
|
|
99
|
+
x1: bar.x,
|
|
100
|
+
x2: bar.x + bar.width,
|
|
101
|
+
y1: edge,
|
|
102
|
+
y2: edge,
|
|
103
|
+
stroke: ctx.series.borderColor ?? ctx.color,
|
|
104
|
+
strokeWidth: borderWidth
|
|
105
|
+
}, `cap-${bar.point.index}`);
|
|
106
|
+
}) : null, _jsx(DataLabels, {
|
|
107
|
+
ctx: ctx,
|
|
108
|
+
projected: bars,
|
|
109
|
+
positionOf: projected => {
|
|
110
|
+
const bar = projected;
|
|
111
|
+
return ctx.stacked ? {
|
|
112
|
+
x: bar.x + bar.width / 2,
|
|
113
|
+
y: bar.y + bar.height / 2 + TEXT_BASELINE_SHIFT
|
|
114
|
+
} : {
|
|
115
|
+
x: bar.x + bar.width / 2,
|
|
116
|
+
y: bar.y - VALUE_LABEL_GAP
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
})]
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
hitTest: (ctx, pointer) => {
|
|
123
|
+
var _ctx$slot;
|
|
124
|
+
const bars = toBars(ctx);
|
|
125
|
+
if (!bars.length) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const top = ctx.plot.y;
|
|
129
|
+
const bottom = ctx.plot.y + ctx.plot.height;
|
|
130
|
+
if (pointer.y < top || pointer.y > bottom) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const step = ((_ctx$slot = ctx.slot) === null || _ctx$slot === void 0 ? void 0 : _ctx$slot.step) ?? ctx.plot.width / 2;
|
|
134
|
+
let candidate;
|
|
135
|
+
let candidateGap = Infinity;
|
|
136
|
+
bars.forEach(bar => {
|
|
137
|
+
const gap = Math.abs(pointer.x - bar.px);
|
|
138
|
+
if (gap < candidateGap) {
|
|
139
|
+
candidate = bar;
|
|
140
|
+
candidateGap = gap;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
if (!candidate || candidateGap > step / 2) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const gapTo = (from, to, value) => Math.max(0, from - value, value - to);
|
|
147
|
+
const horizontal = gapTo(candidate.x, candidate.x + candidate.width, pointer.x);
|
|
148
|
+
const vertical = gapTo(candidate.y, candidate.y + candidate.height, pointer.y);
|
|
149
|
+
return [{
|
|
150
|
+
seriesIndex: ctx.seriesIndex,
|
|
151
|
+
pointIndex: candidate.point.index,
|
|
152
|
+
x: pointKey(candidate.point),
|
|
153
|
+
y: candidate.point.y,
|
|
154
|
+
value: candidate.point.value,
|
|
155
|
+
anchor: {
|
|
156
|
+
x: candidate.x + candidate.width / 2,
|
|
157
|
+
y: candidate.y
|
|
158
|
+
},
|
|
159
|
+
distance: horizontal + vertical
|
|
160
|
+
}];
|
|
161
|
+
},
|
|
162
|
+
legendItems: (series, seriesIndex) => seriesLegend(series, seriesIndex, 'square')
|
|
163
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { column } from './column';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { column } from './column';
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { pointKey } from '../../core/data/points';
|
|
3
|
+
import { TEXT_BASELINE_SHIFT, VALUE_LABEL_GAP } from '../../core/layout/metrics';
|
|
4
|
+
import { brighten } from '../shared/color';
|
|
5
|
+
import { DataLabels } from '../shared/DataLabels';
|
|
6
|
+
const DEFAULT_HOVER_BRIGHTNESS = 0.1;
|
|
7
|
+
/** Width of one column: a unit step on the x axis, or the whole plot if there is none. */
|
|
8
|
+
function columnWidth(ctx) {
|
|
9
|
+
const scale = ctx.scales.x;
|
|
10
|
+
if (scale.kind === 'band') {
|
|
11
|
+
return Math.abs(scale.step());
|
|
12
|
+
}
|
|
13
|
+
if (scale.kind === 'color') {
|
|
14
|
+
return ctx.plot.width;
|
|
15
|
+
}
|
|
16
|
+
const width = Math.abs(scale.map(1) - scale.map(0));
|
|
17
|
+
return width > 0 ? width : ctx.plot.width;
|
|
18
|
+
}
|
|
19
|
+
/** Top edge and height of the row a point belongs to. */
|
|
20
|
+
function rowOf(scale, point) {
|
|
21
|
+
if (scale.kind === 'band') {
|
|
22
|
+
const rows = scale.domain();
|
|
23
|
+
const row = point.y === null ? -1 : Math.round(point.y);
|
|
24
|
+
const category = rows[row];
|
|
25
|
+
if (category === undefined) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
top: scale.map(category),
|
|
30
|
+
height: Math.abs(scale.bandwidth())
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (point.y === null) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const height = Math.abs(scale.map(1) - scale.map(0));
|
|
37
|
+
return {
|
|
38
|
+
top: scale.map(point.y) - height / 2,
|
|
39
|
+
height
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Horizontal centre of the cell: a band slot centre, or the point's x. */
|
|
43
|
+
function cellCentre(scale, point) {
|
|
44
|
+
if (scale.kind === 'band') {
|
|
45
|
+
return scale.map(point.band ?? String(point.name ?? point.x)) + Math.abs(scale.bandwidth()) / 2;
|
|
46
|
+
}
|
|
47
|
+
if (scale.kind === 'color') {
|
|
48
|
+
return NaN;
|
|
49
|
+
}
|
|
50
|
+
return scale.map(Number(point.x));
|
|
51
|
+
}
|
|
52
|
+
function toCells(ctx) {
|
|
53
|
+
const width = columnWidth(ctx);
|
|
54
|
+
return ctx.points.reduce((cells, point) => {
|
|
55
|
+
const row = rowOf(ctx.scales.y, point);
|
|
56
|
+
if (!row) {
|
|
57
|
+
return cells;
|
|
58
|
+
}
|
|
59
|
+
const centre = cellCentre(ctx.scales.x, point);
|
|
60
|
+
if (!Number.isFinite(centre) || !Number.isFinite(row.top)) {
|
|
61
|
+
return cells;
|
|
62
|
+
}
|
|
63
|
+
cells.push({
|
|
64
|
+
point,
|
|
65
|
+
px: centre,
|
|
66
|
+
py: row.top + row.height / 2,
|
|
67
|
+
baseY: row.top + row.height,
|
|
68
|
+
x: centre - width / 2,
|
|
69
|
+
y: row.top,
|
|
70
|
+
width,
|
|
71
|
+
height: row.height
|
|
72
|
+
});
|
|
73
|
+
return cells;
|
|
74
|
+
}, []);
|
|
75
|
+
}
|
|
76
|
+
const fillOf = (ctx, cell, hovered) => {
|
|
77
|
+
var _ctx$scales$color, _ctx$series$states;
|
|
78
|
+
const scaled = cell.point.value === null ? undefined : (_ctx$scales$color = ctx.scales.color) === null || _ctx$scales$color === void 0 ? void 0 : _ctx$scales$color.map(cell.point.value);
|
|
79
|
+
const base = cell.point.color ?? scaled ?? ctx.color;
|
|
80
|
+
if (!hovered) {
|
|
81
|
+
return base;
|
|
82
|
+
}
|
|
83
|
+
return brighten(base, ((_ctx$series$states = ctx.series.states) === null || _ctx$series$states === void 0 || (_ctx$series$states = _ctx$series$states.hover) === null || _ctx$series$states === void 0 ? void 0 : _ctx$series$states.brightness) ?? DEFAULT_HOVER_BRIGHTNESS);
|
|
84
|
+
};
|
|
85
|
+
const labelX = (ctx, cell) => {
|
|
86
|
+
var _ctx$series$dataLabel, _ctx$series$dataLabel2;
|
|
87
|
+
const padding = ((_ctx$series$dataLabel = ctx.series.dataLabels) === null || _ctx$series$dataLabel === void 0 ? void 0 : _ctx$series$dataLabel.padding) ?? VALUE_LABEL_GAP;
|
|
88
|
+
const align = (_ctx$series$dataLabel2 = ctx.series.dataLabels) === null || _ctx$series$dataLabel2 === void 0 ? void 0 : _ctx$series$dataLabel2.align;
|
|
89
|
+
if (align === 'left') {
|
|
90
|
+
return cell.x + padding;
|
|
91
|
+
}
|
|
92
|
+
if (align === 'right') {
|
|
93
|
+
return cell.x + cell.width - padding;
|
|
94
|
+
}
|
|
95
|
+
return cell.px;
|
|
96
|
+
};
|
|
97
|
+
export const heatmap = {
|
|
98
|
+
type: 'heatmap',
|
|
99
|
+
scales: {
|
|
100
|
+
x: 'linear',
|
|
101
|
+
y: 'band'
|
|
102
|
+
},
|
|
103
|
+
// Cells have no baseline to fall into; they fade with their colour.
|
|
104
|
+
exit: 'fade',
|
|
105
|
+
// A cell is one unit wide and centred on its x, so the axis has to hold half a
|
|
106
|
+
// column of slack on each side or the first and last cells hang out of the plot.
|
|
107
|
+
extendDomain: (_series, acc) => {
|
|
108
|
+
if (!Number.isFinite(acc.x.min) || !Number.isFinite(acc.x.max)) {
|
|
109
|
+
return acc;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...acc,
|
|
113
|
+
x: {
|
|
114
|
+
min: acc.x.min - 0.5,
|
|
115
|
+
max: acc.x.max + 0.5
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
render: ctx => {
|
|
120
|
+
var _ctx$hovered;
|
|
121
|
+
const cells = toCells(ctx);
|
|
122
|
+
if (!cells.length) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const hoveredIndex = (_ctx$hovered = ctx.hovered) === null || _ctx$hovered === void 0 ? void 0 : _ctx$hovered.pointIndex;
|
|
126
|
+
const borderWidth = ctx.series.borderWidth ?? 0;
|
|
127
|
+
const radius = ctx.series.borderRadius;
|
|
128
|
+
return _jsxs("g", {
|
|
129
|
+
children: [cells.map(cell => _jsx("rect", {
|
|
130
|
+
x: cell.x,
|
|
131
|
+
y: cell.y,
|
|
132
|
+
width: cell.width,
|
|
133
|
+
height: cell.height,
|
|
134
|
+
rx: radius,
|
|
135
|
+
ry: radius,
|
|
136
|
+
fill: fillOf(ctx, cell, cell.point.index === hoveredIndex),
|
|
137
|
+
stroke: borderWidth ? ctx.series.borderColor : undefined,
|
|
138
|
+
strokeWidth: borderWidth || undefined
|
|
139
|
+
}, `h-${cell.point.index}`)), _jsx(DataLabels, {
|
|
140
|
+
ctx: ctx,
|
|
141
|
+
projected: cells,
|
|
142
|
+
positionOf: projected => {
|
|
143
|
+
const cell = projected;
|
|
144
|
+
return {
|
|
145
|
+
x: labelX(ctx, cell),
|
|
146
|
+
y: cell.py + TEXT_BASELINE_SHIFT
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
})]
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
hitTest: (ctx, pointer) => {
|
|
153
|
+
const hit = toCells(ctx).find(cell => pointer.x >= cell.x && pointer.x <= cell.x + cell.width && pointer.y >= cell.y && pointer.y <= cell.y + cell.height);
|
|
154
|
+
if (!hit) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return [{
|
|
158
|
+
seriesIndex: ctx.seriesIndex,
|
|
159
|
+
pointIndex: hit.point.index,
|
|
160
|
+
x: pointKey(hit.point),
|
|
161
|
+
y: hit.point.y,
|
|
162
|
+
value: hit.point.value,
|
|
163
|
+
anchor: {
|
|
164
|
+
x: hit.px,
|
|
165
|
+
y: hit.y
|
|
166
|
+
},
|
|
167
|
+
distance: 0
|
|
168
|
+
}];
|
|
169
|
+
},
|
|
170
|
+
// A heatmap is read through its colour axis, not through a series swatch.
|
|
171
|
+
legendItems: () => []
|
|
172
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { heatmap } from './heatmap';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { heatmap } from './heatmap';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { line } from './line';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { line } from './line';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { drawable, projectSeries, toLinePath } from '../../core/geometry/path';
|
|
3
|
+
import { nearestByX } from '../shared/hit';
|
|
4
|
+
import { seriesLegend } from '../shared/legend';
|
|
5
|
+
import { Markers } from '../shared/Markers';
|
|
6
|
+
export const line = {
|
|
7
|
+
type: 'line',
|
|
8
|
+
scales: {
|
|
9
|
+
x: 'linear',
|
|
10
|
+
y: 'linear'
|
|
11
|
+
},
|
|
12
|
+
extendDomain: (_series, acc) => acc,
|
|
13
|
+
render: ctx => {
|
|
14
|
+
var _ctx$hovered, _ctx$series$marker;
|
|
15
|
+
const slots = projectSeries(ctx);
|
|
16
|
+
const projected = drawable(slots);
|
|
17
|
+
if (!projected.length) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const color = ctx.color;
|
|
21
|
+
const hoveredIndex = (_ctx$hovered = ctx.hovered) === null || _ctx$hovered === void 0 ? void 0 : _ctx$hovered.pointIndex;
|
|
22
|
+
const hovered = hoveredIndex === undefined ? undefined : projected.find(({
|
|
23
|
+
point
|
|
24
|
+
}) => point.index === hoveredIndex);
|
|
25
|
+
return _jsxs("g", {
|
|
26
|
+
children: [_jsx("path", {
|
|
27
|
+
d: toLinePath(slots),
|
|
28
|
+
fill: "none",
|
|
29
|
+
stroke: color,
|
|
30
|
+
strokeWidth: ctx.series.lineWidth ?? 2,
|
|
31
|
+
strokeLinecap: "round",
|
|
32
|
+
strokeLinejoin: "round"
|
|
33
|
+
}), _jsx(Markers, {
|
|
34
|
+
marker: ctx.series.marker,
|
|
35
|
+
projected: projected,
|
|
36
|
+
color: color
|
|
37
|
+
}), hovered ? _jsx("circle", {
|
|
38
|
+
cx: hovered.px,
|
|
39
|
+
cy: hovered.py,
|
|
40
|
+
r: ((_ctx$series$marker = ctx.series.marker) === null || _ctx$series$marker === void 0 || (_ctx$series$marker = _ctx$series$marker.states) === null || _ctx$series$marker === void 0 || (_ctx$series$marker = _ctx$series$marker.hover) === null || _ctx$series$marker === void 0 ? void 0 : _ctx$series$marker.radius) ?? 4,
|
|
41
|
+
fill: color,
|
|
42
|
+
stroke: "#FFFFFF",
|
|
43
|
+
strokeWidth: 2
|
|
44
|
+
}) : null]
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
hitTest: (ctx, pointer) => nearestByX(ctx, pointer),
|
|
48
|
+
legendItems: (series, seriesIndex) => seriesLegend(series, seriesIndex, 'line')
|
|
49
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { pie } from './pie';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { pie } from './pie';
|