nuxt-charts 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +53 -6
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +56 -3
  4. package/dist/runtime/assets/components.css +1 -1
  5. package/dist/runtime/assets/theme.css +1 -1
  6. package/dist/runtime/components/AreaChart.vue +1 -0
  7. package/dist/runtime/components/BarChart.vue +1 -0
  8. package/dist/runtime/components/DataChart.vue +91 -0
  9. package/dist/runtime/components/DataChart.vue.d.ts +27 -0
  10. package/dist/runtime/components/DottedMap.vue +261 -0
  11. package/dist/runtime/components/DottedMap.vue.d.ts +45 -0
  12. package/dist/runtime/components/LineChart.vue +1 -0
  13. package/dist/runtime/components/MetricChart.vue +322 -0
  14. package/dist/runtime/components/MetricChart.vue.d.ts +54 -0
  15. package/dist/runtime/components/TopoJSONMap.vue +273 -0
  16. package/dist/runtime/components/TopoJSONMap.vue.d.ts +45 -0
  17. package/dist/runtime/components/internal/CartesianFrame.vue +73 -4
  18. package/dist/runtime/components/internal/CartesianFrame.vue.d.ts +5 -0
  19. package/dist/runtime/components/internal/ChartAccessibility.vue.d.ts +1 -1
  20. package/dist/runtime/components/internal/CubeBarShape.vue.d.ts +1 -1
  21. package/dist/runtime/components/internal/MapCanvas.vue +297 -0
  22. package/dist/runtime/components/internal/MapCanvas.vue.d.ts +79 -0
  23. package/dist/runtime/components/internal/VariantBarShape.vue.d.ts +2 -2
  24. package/dist/runtime/data/world.json +182 -0
  25. package/dist/runtime/maps.d.ts +2 -0
  26. package/dist/runtime/maps.js +1 -0
  27. package/dist/runtime/spec/csv.d.ts +14 -0
  28. package/dist/runtime/spec/csv.js +13 -0
  29. package/dist/runtime/spec/index.d.ts +11 -0
  30. package/dist/runtime/spec/index.js +5 -0
  31. package/dist/runtime/spec/metric.d.ts +130 -0
  32. package/dist/runtime/spec/metric.js +63 -0
  33. package/dist/runtime/spec/resolve.d.ts +44 -0
  34. package/dist/runtime/spec/resolve.js +41 -0
  35. package/dist/runtime/spec/transform.d.ts +58 -0
  36. package/dist/runtime/spec/transform.js +199 -0
  37. package/dist/runtime/spec/types.d.ts +132 -0
  38. package/dist/runtime/spec/types.js +2 -0
  39. package/dist/runtime/types/charts.d.ts +131 -0
  40. package/dist/runtime/types/maps.d.ts +237 -0
  41. package/dist/runtime/types/maps.js +0 -0
  42. package/dist/runtime/types.d.ts +3 -0
  43. package/dist/runtime/utils/axis.d.ts +18 -0
  44. package/dist/runtime/utils/axis.js +44 -1
  45. package/dist/runtime/utils/dottedMap.d.ts +14 -0
  46. package/dist/runtime/utils/dottedMap.js +69 -0
  47. package/dist/runtime/utils/maps.d.ts +33 -0
  48. package/dist/runtime/utils/maps.js +77 -0
  49. package/package.json +23 -3
@@ -0,0 +1,273 @@
1
+ <script setup>
2
+ import { computed, nextTick, shallowRef, watch } from "vue";
3
+ import { geoGraticule10, geoPath } from "d3-geo";
4
+ import { createMapProjection, mapCountryId, mapFeatures, mapValue, projectMapPoint } from "../utils/maps";
5
+ import { sampleData } from "../utils/data";
6
+ import MapCanvas from "./internal/MapCanvas.vue";
7
+ const props = defineProps({
8
+ topoJson: { type: Object, required: false },
9
+ geoJson: { type: Object, required: false },
10
+ mapFeatureKey: { type: String, required: false },
11
+ featureId: { type: [String, Function], required: false },
12
+ data: { type: Object, required: false },
13
+ areaColor: { type: [String, Function], required: false },
14
+ areaCursor: { type: [String, Function], required: false },
15
+ areaStroke: { type: [String, Function], required: false },
16
+ areaStrokeWidth: { type: [Number, Function], required: false },
17
+ value: { type: Function, required: false, skipCheck: true },
18
+ colorScale: { type: Function, required: false },
19
+ colorRange: { type: Array, required: false },
20
+ valueDomain: { type: Array, required: false },
21
+ pointColor: { type: [String, Function], required: false },
22
+ pointSize: { type: [Number, Function], required: false },
23
+ pointRadius: { type: [Number, Function], required: false },
24
+ pointStrokeColor: { type: [String, Function], required: false },
25
+ pointStrokeWidth: { type: [Number, Function], required: false },
26
+ pointCursor: { type: [String, Function], required: false },
27
+ pointLabel: { type: [String, Function], required: false },
28
+ showPointLabels: { type: Boolean, required: false },
29
+ linkColor: { type: [String, Function], required: false },
30
+ linkWidth: { type: [Number, Function], required: false },
31
+ linkCursor: { type: [String, Function], required: false },
32
+ linkDasharray: { type: [String, Function], required: false },
33
+ linkCurve: { type: String, required: false },
34
+ linkCurvature: { type: Number, required: false },
35
+ mapFitToPoints: { type: Boolean, required: false },
36
+ zoomOnClick: { type: Boolean, required: false },
37
+ heatmapMode: { type: Boolean, required: false },
38
+ heatmapModeBlurStdDeviation: { type: Number, required: false },
39
+ heatmapModeZoomLevelThreshold: { type: Number, required: false },
40
+ tooltipTitleFormatter: { type: Function, required: false },
41
+ yFormatter: { type: Function, required: false },
42
+ height: { type: [Number, String], required: false },
43
+ width: { type: [Number, String], required: false },
44
+ projection: { type: [String, Function, Object], required: false },
45
+ fitView: { type: Boolean, required: false },
46
+ fitViewPadding: { type: Number, required: false },
47
+ padding: { type: [Number, Object], required: false },
48
+ disableZoom: { type: Boolean, required: false },
49
+ zoomFactor: { type: Number, required: false },
50
+ zoomExtent: { type: Array, required: false },
51
+ zoomOnScroll: { type: Boolean, required: false },
52
+ zoomDuration: { type: Number, required: false },
53
+ duration: { type: Number, required: false },
54
+ showControls: { type: Boolean, required: false },
55
+ hideTooltip: { type: Boolean, required: false },
56
+ hideLegend: { type: Boolean, required: false },
57
+ categories: { type: Object, required: false },
58
+ legendPosition: { type: String, required: false },
59
+ legendStyle: { type: [String, Object], required: false },
60
+ backgroundColor: { type: String, required: false },
61
+ theme: { type: Object, required: false },
62
+ showGraticule: { type: Boolean, required: false },
63
+ showSphere: { type: Boolean, required: false },
64
+ graticuleColor: { type: String, required: false },
65
+ sphereColor: { type: String, required: false },
66
+ ariaLabel: { type: String, required: false },
67
+ ariaDescription: { type: String, required: false },
68
+ accessibleDataTable: { type: Boolean, required: false },
69
+ maxDataPoints: { type: Number, required: false },
70
+ emptyLabel: { type: String, required: false },
71
+ error: { type: String, required: false },
72
+ legendVariant: { type: String, required: false },
73
+ tooltipVariant: { type: String, required: false },
74
+ tooltipRoundness: { type: String, required: false },
75
+ loading: { type: Boolean, required: false },
76
+ loadingLabel: { type: String, required: false }
77
+ });
78
+ defineSlots();
79
+ const emit = defineEmits(["feature-click", "point-click", "link-click", "mouseenter", "mouseleave", "zoom"]);
80
+ const canvas = shallowRef();
81
+ const size = shallowRef([960, typeof props.height === "number" ? props.height : 400]);
82
+ const geometry = computed(() => {
83
+ try {
84
+ return { collection: mapFeatures(props.geoJson ?? props.topoJson, props.mapFeatureKey), error: void 0 };
85
+ } catch (error) {
86
+ return {
87
+ collection: { type: "FeatureCollection", features: [] },
88
+ error: error instanceof Error ? error.message : "Invalid map geometry"
89
+ };
90
+ }
91
+ });
92
+ const view = computed(() => {
93
+ const collection = geometry.value.collection;
94
+ const projection = createMapProjection(
95
+ props.projection,
96
+ collection.features.length ? collection : { type: "Sphere" },
97
+ size.value[0],
98
+ size.value[1],
99
+ props
100
+ );
101
+ return { projection, path: geoPath(projection) };
102
+ });
103
+ const path = computed(() => view.value.path);
104
+ const areas = computed(() => {
105
+ const rows = new Map((props.data?.areas ?? []).map((area) => [String(area.id), area]));
106
+ return geometry.value.collection.features.map((feature, index) => {
107
+ const properties = feature.properties ?? {};
108
+ const id = typeof props.featureId === "function" ? props.featureId(feature) : props.featureId ? properties[props.featureId] : mapCountryId(feature, index);
109
+ const aliases = props.featureId !== void 0 ? [id] : [
110
+ id,
111
+ properties.iso_a2,
112
+ properties.iso_a3,
113
+ properties.iso_n3,
114
+ properties.iso_n3 == null ? void 0 : Number(properties.iso_n3),
115
+ properties.ISO_A2,
116
+ properties.ISO_A3,
117
+ properties.name
118
+ ];
119
+ const row = aliases.map((key) => rows.get(String(key))).find(Boolean);
120
+ return { ...properties, ...row, id: row?.id ?? id, properties, feature };
121
+ });
122
+ });
123
+ function areaValue(area) {
124
+ const value = typeof props.value === "function" ? props.value(area) : props.value ? area[props.value] : area.value;
125
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
126
+ }
127
+ const domain = computed(() => {
128
+ if (props.valueDomain) return props.valueDomain;
129
+ const values = areas.value.map(areaValue).filter((value) => value !== void 0);
130
+ return values.length ? [Math.min(...values), Math.max(...values)] : [0, 1];
131
+ });
132
+ function areaColor(area, index) {
133
+ if (props.areaColor !== void 0) return mapValue(props.areaColor, area, index, "var(--vc-map-feature-color)");
134
+ if (area.color) return area.color;
135
+ const value = areaValue(area);
136
+ if (value === void 0) return "var(--vc-map-feature-color)";
137
+ if (props.colorScale) return props.colorScale(value);
138
+ const t = domain.value[0] === domain.value[1] ? 1 : Math.max(0, Math.min(1, (value - domain.value[0]) / (domain.value[1] - domain.value[0])));
139
+ const [low, high] = props.colorRange ?? ["var(--vc-map-feature-color)", "var(--vc-series-0)"];
140
+ return `color-mix(in srgb, ${high} ${Math.round(t * 100)}%, ${low})`;
141
+ }
142
+ const projectedPoints = computed(() => sampleData(props.data?.points ?? [], props.maxDataPoints ?? 2e3).flatMap((point, index) => {
143
+ const coordinates = projectMapPoint(view.value.projection, [point.longitude, point.latitude], path.value);
144
+ return coordinates ? [{ point, index, coordinates }] : [];
145
+ }));
146
+ const marks = computed(() => {
147
+ const features = areas.value.flatMap((area, index) => {
148
+ const d = path.value(area.feature);
149
+ return d ? [{
150
+ key: `feature-${index}`,
151
+ kind: "feature",
152
+ values: area,
153
+ path: d,
154
+ color: areaColor(area, index),
155
+ stroke: mapValue(props.areaStroke, area, index, "var(--vc-map-boundary-color)"),
156
+ strokeWidth: mapValue(props.areaStrokeWidth, area, index, 0.6),
157
+ cursor: mapValue(props.areaCursor, area, index, "pointer"),
158
+ label: String(area.name ?? area.properties.name ?? area.id)
159
+ }] : [];
160
+ });
161
+ const pointsById = new Map((props.data?.points ?? []).map((point) => [String(point.id), point]));
162
+ const links = sampleData(props.data?.links ?? [], props.maxDataPoints ?? 2e3).flatMap((link, index) => {
163
+ const source = typeof link.source === "object" ? link.source : pointsById.get(String(link.source));
164
+ const target = typeof link.target === "object" ? link.target : pointsById.get(String(link.target));
165
+ if (!source || !target) return [];
166
+ const start = [source.longitude, source.latitude];
167
+ const end = [target.longitude, target.latitude];
168
+ if (![...start, ...end].every(Number.isFinite) || Math.abs(start[1]) > 90 || Math.abs(end[1]) > 90) return [];
169
+ let d = null;
170
+ if (!props.linkCurve || props.linkCurve === "geodesic") d = path.value({ type: "LineString", coordinates: [start, end] });
171
+ else {
172
+ const a = projectMapPoint(view.value.projection, start);
173
+ const b = projectMapPoint(view.value.projection, end);
174
+ if (!a || !b) return [];
175
+ const curve = props.linkCurvature ?? 0.2;
176
+ d = props.linkCurve === "straight" ? `M${a}L${b}` : `M${a}Q${(a[0] + b[0]) / 2 - (b[1] - a[1]) * curve},${(a[1] + b[1]) / 2 + (b[0] - a[0]) * curve} ${b}`;
177
+ }
178
+ if (!d) return [];
179
+ const color = mapValue(props.linkColor, link, index, link.color ?? target.color ?? "var(--vc-series-0)");
180
+ return [{
181
+ key: `link-${index}`,
182
+ kind: "link",
183
+ values: link,
184
+ path: d,
185
+ color,
186
+ stroke: color,
187
+ strokeWidth: mapValue(props.linkWidth, link, index, link.width ?? 1.5),
188
+ dasharray: mapValue(props.linkDasharray, link, index, ""),
189
+ cursor: mapValue(props.linkCursor, link, index, "pointer"),
190
+ label: link.label ?? `${source.label ?? source.id} \u2192 ${target.label ?? target.id}`
191
+ }];
192
+ });
193
+ const points = projectedPoints.value.map(({ point, index, coordinates }) => ({
194
+ key: `point-${point.id}`,
195
+ kind: "point",
196
+ values: point,
197
+ x: coordinates[0],
198
+ y: coordinates[1],
199
+ radius: mapValue(props.pointRadius ?? props.pointSize, point, index, point.radius ?? 5),
200
+ color: mapValue(props.pointColor, point, index, point.color ?? "var(--vc-series-0)"),
201
+ stroke: mapValue(props.pointStrokeColor, point, index, "var(--vc-surface-bg)"),
202
+ strokeWidth: mapValue(props.pointStrokeWidth, point, index, 1.5),
203
+ cursor: mapValue(props.pointCursor, point, index, "pointer"),
204
+ label: mapValue(props.pointLabel, point, index, point.label ?? String(point.id)),
205
+ showLabel: props.showPointLabels
206
+ }));
207
+ return [...features, ...links, ...points];
208
+ });
209
+ function fitToPoints(points = props.data?.points ?? []) {
210
+ const positions = points.flatMap((point) => {
211
+ const projected = projectMapPoint(view.value.projection, [point.longitude, point.latitude], path.value);
212
+ return projected ? [projected] : [];
213
+ });
214
+ if (!positions.length) return;
215
+ canvas.value?.fitBounds([[Math.min(...positions.map((p) => p[0])), Math.min(...positions.map((p) => p[1]))], [Math.max(...positions.map((p) => p[0])), Math.max(...positions.map((p) => p[1]))]]);
216
+ }
217
+ function zoomToFeature(id) {
218
+ const area = areas.value.find((area2) => String(area2.id) === String(id) || String(area2.feature.id) === String(id));
219
+ if (area) canvas.value?.fitBounds(path.value.bounds(area.feature));
220
+ }
221
+ function click(mark, event) {
222
+ if (mark.kind === "feature") {
223
+ emit("feature-click", mark.values, event);
224
+ if (props.zoomOnClick) zoomToFeature(mark.values.id);
225
+ }
226
+ if (mark.kind === "point") {
227
+ emit("point-click", mark.values, event);
228
+ if (props.zoomOnClick) fitToPoints([mark.values]);
229
+ }
230
+ if (mark.kind === "link") emit("link-click", mark.values, event);
231
+ }
232
+ watch([() => props.mapFitToPoints, projectedPoints, size], async () => {
233
+ await nextTick();
234
+ if (props.mapFitToPoints) fitToPoints();
235
+ }, { immediate: true });
236
+ defineExpose({
237
+ zoomIn: () => canvas.value?.zoomIn(),
238
+ zoomOut: () => canvas.value?.zoomOut(),
239
+ zoomTo: (k) => canvas.value?.zoomTo(k),
240
+ resetView: () => canvas.value?.resetView(),
241
+ fitToPoints,
242
+ zoomToFeature
243
+ });
244
+ </script>
245
+
246
+ <template>
247
+ <MapCanvas
248
+ ref="canvas"
249
+ v-bind="props"
250
+ :marks="marks"
251
+ :size="size"
252
+ :geometry-error="geometry.error"
253
+ :sphere="showSphere ? path({ type: 'Sphere' }) ?? void 0 : void 0"
254
+ :graticule="showGraticule ? path(geoGraticule10()) ?? void 0 : void 0"
255
+ :tooltip-title="tooltipTitleFormatter ? (datum) => tooltipTitleFormatter(datum) : void 0"
256
+ :tooltip-value="yFormatter ? (value) => yFormatter(value) : void 0"
257
+ :heatmap="heatmapMode"
258
+ :heatmap-blur="heatmapModeBlurStdDeviation"
259
+ :heatmap-threshold="heatmapModeZoomLevelThreshold"
260
+ @resize="size = $event"
261
+ @click="click"
262
+ @mouseenter="(mark, event) => emit('mouseenter', mark.values, event)"
263
+ @mouseleave="(mark, event) => emit('mouseleave', mark.values, event)"
264
+ @zoom="emit('zoom', $event)"
265
+ >
266
+ <template v-if="$slots.tooltip" #tooltip="scope"><slot name="tooltip" v-bind="scope" /></template>
267
+ <template v-if="$slots.feature" #feature="scope"><slot name="feature" v-bind="scope" :values="scope.values" :projection="view.projection" /></template>
268
+ <template v-if="$slots.point" #point="scope"><slot name="point" v-bind="scope" :values="scope.values" :projection="view.projection" /></template>
269
+ <template v-if="$slots.link" #link="scope"><slot name="link" v-bind="scope" :values="scope.values" :projection="view.projection" /></template>
270
+ <template v-if="$slots.legend" #legend="scope"><slot name="legend" v-bind="scope" /></template>
271
+ <template v-if="$slots.default" #default="scope"><slot v-bind="scope" :projection="view.projection" /></template>
272
+ </MapCanvas>
273
+ </template>
@@ -0,0 +1,45 @@
1
+ import type { MapArea, MapPoint, MapLink, MapFeature, TopoJSONMapProps, MapZoom, MapMarkSlot, MapOverlaySlot, MapTooltipSlot } from "../types/maps.js";
2
+ declare const __VLS_export: <A extends MapArea = MapArea, P extends MapPoint = MapPoint, L extends MapLink<P> = MapLink<P>>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<TopoJSONMapProps<A, P, L> & {
4
+ onMouseenter?: ((values: P | L | MapFeature<A>, event: MouseEvent | FocusEvent) => any) | undefined;
5
+ onMouseleave?: ((values: P | L | MapFeature<A>, event: MouseEvent | FocusEvent) => any) | undefined;
6
+ onZoom?: ((transform: MapZoom) => any) | undefined;
7
+ "onPoint-click"?: ((values: P, event: MouseEvent | KeyboardEvent) => any) | undefined;
8
+ "onFeature-click"?: ((values: MapFeature<A>, event: MouseEvent | KeyboardEvent) => any) | undefined;
9
+ "onLink-click"?: ((values: L, event: MouseEvent | KeyboardEvent) => any) | undefined;
10
+ }> & (typeof globalThis extends {
11
+ __VLS_PROPS_FALLBACK: infer P_1;
12
+ } ? P_1 : {});
13
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
14
+ zoomIn: () => void | undefined;
15
+ zoomOut: () => void | undefined;
16
+ zoomTo: (k: number) => void | undefined;
17
+ resetView: () => void | undefined;
18
+ fitToPoints: (points?: P[]) => void;
19
+ zoomToFeature: (id: string | number) => void;
20
+ }>) => void;
21
+ attrs: any;
22
+ slots: {
23
+ tooltip?: (props: MapTooltipSlot<A, P, L>) => unknown;
24
+ feature?: (props: MapMarkSlot<MapFeature<A>>) => unknown;
25
+ point?: (props: MapMarkSlot<P>) => unknown;
26
+ link?: (props: MapMarkSlot<L>) => unknown;
27
+ legend?: (props: {
28
+ items: Array<{
29
+ value: string;
30
+ color?: string;
31
+ }>;
32
+ }) => unknown;
33
+ default?: (props: MapOverlaySlot) => unknown;
34
+ };
35
+ emit: ((evt: "mouseenter", values: P | L | MapFeature<A>, event: MouseEvent | FocusEvent) => void) & ((evt: "mouseleave", values: P | L | MapFeature<A>, event: MouseEvent | FocusEvent) => void) & ((evt: "zoom", transform: MapZoom) => void) & ((evt: "point-click", values: P, event: MouseEvent | KeyboardEvent) => void) & ((evt: "feature-click", values: MapFeature<A>, event: MouseEvent | KeyboardEvent) => void) & ((evt: "link-click", values: L, event: MouseEvent | KeyboardEvent) => void);
36
+ }>) => import("vue").VNode & {
37
+ __ctx?: Awaited<typeof __VLS_setup>;
38
+ };
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
41
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
42
+ [K in keyof T]: T[K];
43
+ } : {
44
+ [K in keyof T as K]: T[K];
45
+ }) & {};
@@ -13,6 +13,7 @@ import { legendPositionToLegendProps, resolveLegendWrapperStyle } from "../../ut
13
13
  import {
14
14
  AXIS_TICK_MARGIN,
15
15
  equidistantCategoryTicks,
16
+ niceTickValues,
16
17
  resolveAxisProps,
17
18
  resolveYAxes,
18
19
  resolveXAxisHeight,
@@ -21,7 +22,7 @@ import {
21
22
  toTickFormatter,
22
23
  toTickProp
23
24
  } from "../../utils/axis";
24
- import { categoriesToSeries } from "../../utils/categories";
25
+ import { categoriesToSeries, normalizeAxisId } from "../../utils/categories";
25
26
  import { toAxisDomain, toCssProperties } from "../../utils/style";
26
27
  import { axisTickVars, resolveHoverRadius, resolveHoverVisible, themeToVars } from "../../utils/theme";
27
28
  import ChartTooltip from "./ChartTooltip.vue";
@@ -87,7 +88,8 @@ const props = defineProps({
87
88
  frameClass: { type: String, required: false },
88
89
  legendColors: { type: Object, required: false },
89
90
  skeletonShape: { type: String, required: false },
90
- percentAxis: { type: Boolean, required: false }
91
+ percentAxis: { type: Boolean, required: false },
92
+ valueStacked: { type: Boolean, required: false }
91
93
  });
92
94
  const numericKeys = computed(() => Object.keys(props.categories));
93
95
  const normalizedData = computed(() => normalizeNumericRows(props.data, numericKeys.value));
@@ -177,10 +179,77 @@ const yAxisTitle = computed(
177
179
  const isCategoryYAxis = computed(
178
180
  () => layout.value === "vertical" && props.xAxisKey !== void 0
179
181
  );
182
+ function sampleLabelsFor(keys, format, explicitTicks, domain) {
183
+ const toLabel = (value, index) => format ? String(format(value, index)) : String(value);
184
+ if (explicitTicks?.length) return explicitTicks.map((tick, i) => toLabel(Number(tick), i));
185
+ if (!keys.length || !chartData.value.length) return void 0;
186
+ let min = 0;
187
+ let max = 0;
188
+ for (const row of chartData.value) {
189
+ const record = row;
190
+ let positive = 0;
191
+ let negative = 0;
192
+ for (const key of keys) {
193
+ const value = Number(record[key]);
194
+ if (!Number.isFinite(value)) continue;
195
+ if (props.valueStacked) {
196
+ if (value >= 0) positive += value;
197
+ else negative += value;
198
+ } else {
199
+ positive = Math.max(positive, value);
200
+ negative = Math.min(negative, value);
201
+ }
202
+ }
203
+ max = Math.max(max, positive);
204
+ min = Math.min(min, negative);
205
+ }
206
+ if (domain) {
207
+ min = domain[0];
208
+ max = domain[1];
209
+ }
210
+ const ticks = niceTickValues(min, max);
211
+ return ticks.length ? ticks.map(toLabel) : void 0;
212
+ }
213
+ const seriesKeysByAxis = computed(() => {
214
+ const map = /* @__PURE__ */ new Map();
215
+ for (const series of categoriesToSeries(props.categories)) {
216
+ const id = normalizeAxisId(series.yAxisId);
217
+ const keys = map.get(id);
218
+ if (keys) keys.push(series.dataKey);
219
+ else map.set(id, [series.dataKey]);
220
+ }
221
+ return map;
222
+ });
223
+ const valueAxisSampleLabels = computed(() => {
224
+ if (isCategoryYAxis.value || props.percentAxis) return void 0;
225
+ return sampleLabelsFor(
226
+ numericKeys.value,
227
+ valueFormatter.value,
228
+ layout.value === "vertical" ? xAxis.value.ticks : yAxis.value.ticks,
229
+ yAxisDomain.value
230
+ );
231
+ });
180
232
  const xAxisHeight = computed(() => resolveXAxisHeight({ hasTitle: !!xAxisTitle.value }));
181
233
  const yAxisWidth = computed(
182
- () => resolveYAxisWidth({ hasTitle: !!yAxisTitle.value, isCategoryAxis: isCategoryYAxis.value })
234
+ () => resolveYAxisWidth({
235
+ hasTitle: !!yAxisTitle.value,
236
+ isCategoryAxis: isCategoryYAxis.value,
237
+ sampleLabels: valueAxisSampleLabels.value,
238
+ tickMargin: AXIS_TICK_MARGIN.y
239
+ })
183
240
  );
241
+ function widthForAxis(axis) {
242
+ if (props.percentAxis) {
243
+ return resolveYAxisWidth({ hasTitle: !!axis.label, isCategoryAxis: false });
244
+ }
245
+ const keys = seriesKeysByAxis.value.get(normalizeAxisId(axis.id)) ?? [];
246
+ return resolveYAxisWidth({
247
+ hasTitle: !!axis.label,
248
+ isCategoryAxis: false,
249
+ sampleLabels: sampleLabelsFor(keys, axis.tickFormatter, axis.ticks, axis.domain),
250
+ tickMargin: AXIS_TICK_MARGIN.y
251
+ });
252
+ }
184
253
  const rootStyle = computed(() => ({
185
254
  ...themeToVars(props.theme),
186
255
  ...axisTickVars("x", xAxis.value.tick),
@@ -350,7 +419,7 @@ const resolvedYAxes = computed(() => {
350
419
  :y-axis-id="axis.id"
351
420
  :orientation="axis.orientation"
352
421
  :hide="axis.hide"
353
- :width="yAxisWidth"
422
+ :width="widthForAxis(axis)"
354
423
  :tick="toTickProp(axis.tick)"
355
424
  :tick-margin="AXIS_TICK_MARGIN.y"
356
425
  :tick-line="axis.tickLine ? yTickLineProp : false"
@@ -33,6 +33,11 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
33
33
  * ticks read as percentages rather than as raw fractions.
34
34
  */
35
35
  percentAxis?: boolean;
36
+ /**
37
+ * Series are summed into one stack, so the value axis runs to the stacked
38
+ * total rather than the largest single series. Only affects axis sizing.
39
+ */
40
+ valueStacked?: boolean;
36
41
  }> & (typeof globalThis extends {
37
42
  __VLS_PROPS_FALLBACK: infer P;
38
43
  } ? P : {});
@@ -14,8 +14,8 @@ type __VLS_Props = {
14
14
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
15
15
  label: string;
16
16
  description: string;
17
- rows: AccessibleRow[];
18
17
  showTable: boolean;
18
+ rows: AccessibleRow[];
19
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
20
  declare const _default: typeof __VLS_export;
21
21
  export default _default;
@@ -21,10 +21,10 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
21
21
  width: number;
22
22
  height: number;
23
23
  fill: string;
24
+ x: number | null;
24
25
  radius: number;
25
26
  background: CubeColumnBand | null;
26
27
  emptyColor: string;
27
- x: number | null;
28
28
  y: number | null;
29
29
  gap: number;
30
30
  preferredSize: number;