@voila.dev/chart 6.0.125 → 6.0.126
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axes.d.ts","sourceRoot":"","sources":["../../../src/core/guides/axes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EACX,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,SAAS,EACT,MAAM,iBAAiB,CAAC;AAgBzB,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;CACxC;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACnC,aAAa,CAAC,UAAU,CAAC,CAM3B;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,UAAU,GACf,MAAM,CAER;
|
|
1
|
+
{"version":3,"file":"axes.d.ts","sourceRoot":"","sources":["../../../src/core/guides/axes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EACX,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,SAAS,EACT,MAAM,iBAAiB,CAAC;AAgBzB,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;CACxC;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACnC,aAAa,CAAC,UAAU,CAAC,CAM3B;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,UAAU,GACf,MAAM,CAER;AAOD,8DAA8D;AAC9D,wBAAgB,QAAQ,CACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,iBAAiB,GAC5B,MAAM,CASR;AAMD,+EAA+E;AAC/E,wBAAgB,UAAU,CACzB,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,MAAM,GAChB,MAAM,CAgBR;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAW5D;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAa3D;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CAC1C;AAsBD,wBAAgB,UAAU,CACzB,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,OAAO,GACX,SAAS,CAwDX;AAED,wBAAgB,QAAQ,CACvB,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,MAAM,GAChB,SAAS,CAmEX"}
|
package/dist/core/guides/axes.js
CHANGED
|
@@ -14,6 +14,9 @@ function axisTicks(scale, options) {
|
|
|
14
14
|
function tickLabel(scale, options, value) {
|
|
15
15
|
return options?.tickFormat?.(value) ?? scale.format(value);
|
|
16
16
|
}
|
|
17
|
+
function tickKey(value) {
|
|
18
|
+
return value instanceof Date ? String(value.getTime()) : String(value);
|
|
19
|
+
}
|
|
17
20
|
function truncate(text, maxWidth, fontSize, measureText) {
|
|
18
21
|
if (measureText(text, fontSize) <= maxWidth) {
|
|
19
22
|
return text;
|
|
@@ -78,7 +81,7 @@ function bottomAxis(input, plot, grid) {
|
|
|
78
81
|
const positions = ticks.map((tick) => scale.center(tick));
|
|
79
82
|
const gridNodes = grid ? ticks.map((tick, index) => ({
|
|
80
83
|
kind: "line",
|
|
81
|
-
key: `grid-x:${
|
|
84
|
+
key: `grid-x:${tickKey(tick)}`,
|
|
82
85
|
role: "grid",
|
|
83
86
|
x1: positions[index],
|
|
84
87
|
y1: plot.y,
|
|
@@ -95,7 +98,7 @@ function bottomAxis(input, plot, grid) {
|
|
|
95
98
|
const labels = thinned(ticks, widths, positions).map(
|
|
96
99
|
(index) => ({
|
|
97
100
|
kind: "text",
|
|
98
|
-
key: `tick-x:${
|
|
101
|
+
key: `tick-x:${tickKey(ticks[index])}`,
|
|
99
102
|
role: "axis",
|
|
100
103
|
x: positions[index],
|
|
101
104
|
y: baseline,
|
|
@@ -133,7 +136,7 @@ function leftAxis(input, plot, grid, chartWidth) {
|
|
|
133
136
|
const positions = ticks.map((tick) => scale.center(tick));
|
|
134
137
|
const gridNodes = grid ? ticks.map((tick, index) => ({
|
|
135
138
|
kind: "line",
|
|
136
|
-
key: `grid-y:${
|
|
139
|
+
key: `grid-y:${tickKey(tick)}`,
|
|
137
140
|
role: "grid",
|
|
138
141
|
x1: plot.x,
|
|
139
142
|
y1: positions[index],
|
|
@@ -158,7 +161,7 @@ function leftAxis(input, plot, grid, chartWidth) {
|
|
|
158
161
|
const labels = thinned(ticks, heights, positions).map(
|
|
159
162
|
(index) => ({
|
|
160
163
|
kind: "text",
|
|
161
|
-
key: `tick-y:${
|
|
164
|
+
key: `tick-y:${tickKey(ticks[index])}`,
|
|
162
165
|
role: "axis",
|
|
163
166
|
x: plot.x - TICK_GAP,
|
|
164
167
|
y: positions[index],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/core/guides/axes.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ChartAxisOptions } from \"#/core/define-chart.ts\";\nimport type {\n\tChartPositionScale,\n\tChartRect,\n\tChartTextMeasurer,\n\tChartTheme,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\n/**\n * The axes as scene nodes: grid lines behind the marks, tick labels and\n * titles in front. They are measured before the plot exists, so the margins\n * fit the widest label instead of a guessed constant.\n */\n\nconst TICK_GAP = 8;\nconst TITLE_GAP = 6;\nconst LABEL_SPACING = 8;\nconst EDGE = 8;\n/** A category label on a horizontal bar chart never takes more of the width than this. */\nconst MAX_CATEGORY_SHARE = 0.35;\nconst ELLIPSIS = \"\u2026\";\n\nexport interface AxisMeasureInput {\n\treadonly scale: ChartPositionScale;\n\treadonly options: ChartAxisOptions | undefined;\n\treadonly title: string | undefined;\n\treadonly theme: ChartTheme;\n\treadonly measureText: ChartTextMeasurer;\n}\n\nexport function axisTicks(\n\tscale: ChartPositionScale,\n\toptions: ChartAxisOptions | undefined,\n): ReadonlyArray<ChartValue> {\n\tconst ticks = options?.ticks;\n\tif (Array.isArray(ticks)) {\n\t\treturn ticks;\n\t}\n\treturn scale.ticks(typeof ticks === \"number\" ? ticks : undefined);\n}\n\nexport function tickLabel(\n\tscale: ChartPositionScale,\n\toptions: ChartAxisOptions | undefined,\n\tvalue: ChartValue,\n): string {\n\treturn options?.tickFormat?.(value) ?? scale.format(value);\n}\n\n/** Cuts a label down to `maxWidth`, ending on an ellipsis. */\nexport function truncate(\n\ttext: string,\n\tmaxWidth: number,\n\tfontSize: number,\n\tmeasureText: ChartTextMeasurer,\n): string {\n\tif (measureText(text, fontSize) <= maxWidth) {\n\t\treturn text;\n\t}\n\tlet kept = text;\n\twhile (kept.length > 1 && measureText(kept + ELLIPSIS, fontSize) > maxWidth) {\n\t\tkept = kept.slice(0, -1);\n\t}\n\treturn kept + ELLIPSIS;\n}\n\nfunction hidden(options: ChartAxisOptions | undefined): boolean {\n\treturn options?.axis === false;\n}\n\n/** Room the left axis needs: its widest tick label, the gap, and the title. */\nexport function leftMargin(\n\tinput: AxisMeasureInput,\n\tchartWidth: number,\n): number {\n\tconst { scale, options, title, theme, measureText } = input;\n\tif (hidden(options)) {\n\t\treturn EDGE;\n\t}\n\tconst discrete = scale.kind === \"band\" || scale.kind === \"point\";\n\tconst widest = Math.max(\n\t\t0,\n\t\t...axisTicks(scale, options).map((tick) =>\n\t\t\tmeasureText(tickLabel(scale, options, tick), theme.fontSize),\n\t\t),\n\t);\n\tconst labels = discrete\n\t\t? Math.min(widest, chartWidth * MAX_CATEGORY_SHARE)\n\t\t: widest;\n\treturn EDGE + labels + TICK_GAP + (title ? theme.fontSize + TITLE_GAP : 0);\n}\n\nexport function bottomMargin(input: AxisMeasureInput): number {\n\tconst { options, title, theme } = input;\n\tif (hidden(options)) {\n\t\treturn EDGE;\n\t}\n\treturn (\n\t\tTICK_GAP +\n\t\ttheme.fontSize +\n\t\tEDGE / 2 +\n\t\t(title ? theme.fontSize + TITLE_GAP : 0)\n\t);\n}\n\n/** Half the last x label hangs past the plot's right edge; leave it room. */\nexport function rightMargin(input: AxisMeasureInput): number {\n\tconst { scale, options, theme, measureText } = input;\n\tif (hidden(options) || scale.kind === \"band\" || scale.kind === \"point\") {\n\t\treturn EDGE;\n\t}\n\tconst ticks = axisTicks(scale, options);\n\tconst last = ticks[ticks.length - 1];\n\tif (last === undefined) {\n\t\treturn EDGE;\n\t}\n\tconst half = measureText(tickLabel(scale, options, last), theme.fontSize) / 2;\n\tconst overhang = half - (scale.range[1] - scale.map(last));\n\treturn Math.max(EDGE, overhang + 2);\n}\n\nexport interface AxisNodes {\n\treadonly grid: ReadonlyArray<SceneNode>;\n\treadonly labels: ReadonlyArray<SceneNode>;\n}\n\n/**\n * Every `step`-th label, so neighbours never overlap. The step is the same\n * across the axis: thinning by skipping single labels reads as noise.\n */\nfunction thinned(\n\tticks: ReadonlyArray<ChartValue>,\n\twidths: ReadonlyArray<number>,\n\tpositions: ReadonlyArray<number>,\n): ReadonlyArray<number> {\n\tif (ticks.length < 2) {\n\t\treturn ticks.map((_tick, index) => index);\n\t}\n\tconst spacing = Math.abs(positions[1] - positions[0]) || 1;\n\tconst widest = Math.max(...widths);\n\tconst step = Math.max(1, Math.ceil((widest + LABEL_SPACING) / spacing));\n\treturn ticks\n\t\t.map((_tick, index) => index)\n\t\t.filter((index) => index % step === 0);\n}\n\nexport function bottomAxis(\n\tinput: AxisMeasureInput,\n\tplot: ChartRect,\n\tgrid: boolean,\n): AxisNodes {\n\tconst { scale, options, title, theme, measureText } = input;\n\tconst ticks = axisTicks(scale, options);\n\tconst positions = ticks.map((tick) => scale.center(tick));\n\tconst gridNodes: SceneNode[] = grid\n\t\t? ticks.map((tick, index) => ({\n\t\t\t\tkind: \"line\",\n\t\t\t\tkey: `grid-x:${
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { ChartAxisOptions } from \"#/core/define-chart.ts\";\nimport type {\n\tChartPositionScale,\n\tChartRect,\n\tChartTextMeasurer,\n\tChartTheme,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\n/**\n * The axes as scene nodes: grid lines behind the marks, tick labels and\n * titles in front. They are measured before the plot exists, so the margins\n * fit the widest label instead of a guessed constant.\n */\n\nconst TICK_GAP = 8;\nconst TITLE_GAP = 6;\nconst LABEL_SPACING = 8;\nconst EDGE = 8;\n/** A category label on a horizontal bar chart never takes more of the width than this. */\nconst MAX_CATEGORY_SHARE = 0.35;\nconst ELLIPSIS = \"\u2026\";\n\nexport interface AxisMeasureInput {\n\treadonly scale: ChartPositionScale;\n\treadonly options: ChartAxisOptions | undefined;\n\treadonly title: string | undefined;\n\treadonly theme: ChartTheme;\n\treadonly measureText: ChartTextMeasurer;\n}\n\nexport function axisTicks(\n\tscale: ChartPositionScale,\n\toptions: ChartAxisOptions | undefined,\n): ReadonlyArray<ChartValue> {\n\tconst ticks = options?.ticks;\n\tif (Array.isArray(ticks)) {\n\t\treturn ticks;\n\t}\n\treturn scale.ticks(typeof ticks === \"number\" ? ticks : undefined);\n}\n\nexport function tickLabel(\n\tscale: ChartPositionScale,\n\toptions: ChartAxisOptions | undefined,\n\tvalue: ChartValue,\n): string {\n\treturn options?.tickFormat?.(value) ?? scale.format(value);\n}\n\n/** Two ticks can share a label (\"11:00\" on two days), never a value. */\nfunction tickKey(value: ChartValue): string {\n\treturn value instanceof Date ? String(value.getTime()) : String(value);\n}\n\n/** Cuts a label down to `maxWidth`, ending on an ellipsis. */\nexport function truncate(\n\ttext: string,\n\tmaxWidth: number,\n\tfontSize: number,\n\tmeasureText: ChartTextMeasurer,\n): string {\n\tif (measureText(text, fontSize) <= maxWidth) {\n\t\treturn text;\n\t}\n\tlet kept = text;\n\twhile (kept.length > 1 && measureText(kept + ELLIPSIS, fontSize) > maxWidth) {\n\t\tkept = kept.slice(0, -1);\n\t}\n\treturn kept + ELLIPSIS;\n}\n\nfunction hidden(options: ChartAxisOptions | undefined): boolean {\n\treturn options?.axis === false;\n}\n\n/** Room the left axis needs: its widest tick label, the gap, and the title. */\nexport function leftMargin(\n\tinput: AxisMeasureInput,\n\tchartWidth: number,\n): number {\n\tconst { scale, options, title, theme, measureText } = input;\n\tif (hidden(options)) {\n\t\treturn EDGE;\n\t}\n\tconst discrete = scale.kind === \"band\" || scale.kind === \"point\";\n\tconst widest = Math.max(\n\t\t0,\n\t\t...axisTicks(scale, options).map((tick) =>\n\t\t\tmeasureText(tickLabel(scale, options, tick), theme.fontSize),\n\t\t),\n\t);\n\tconst labels = discrete\n\t\t? Math.min(widest, chartWidth * MAX_CATEGORY_SHARE)\n\t\t: widest;\n\treturn EDGE + labels + TICK_GAP + (title ? theme.fontSize + TITLE_GAP : 0);\n}\n\nexport function bottomMargin(input: AxisMeasureInput): number {\n\tconst { options, title, theme } = input;\n\tif (hidden(options)) {\n\t\treturn EDGE;\n\t}\n\treturn (\n\t\tTICK_GAP +\n\t\ttheme.fontSize +\n\t\tEDGE / 2 +\n\t\t(title ? theme.fontSize + TITLE_GAP : 0)\n\t);\n}\n\n/** Half the last x label hangs past the plot's right edge; leave it room. */\nexport function rightMargin(input: AxisMeasureInput): number {\n\tconst { scale, options, theme, measureText } = input;\n\tif (hidden(options) || scale.kind === \"band\" || scale.kind === \"point\") {\n\t\treturn EDGE;\n\t}\n\tconst ticks = axisTicks(scale, options);\n\tconst last = ticks[ticks.length - 1];\n\tif (last === undefined) {\n\t\treturn EDGE;\n\t}\n\tconst half = measureText(tickLabel(scale, options, last), theme.fontSize) / 2;\n\tconst overhang = half - (scale.range[1] - scale.map(last));\n\treturn Math.max(EDGE, overhang + 2);\n}\n\nexport interface AxisNodes {\n\treadonly grid: ReadonlyArray<SceneNode>;\n\treadonly labels: ReadonlyArray<SceneNode>;\n}\n\n/**\n * Every `step`-th label, so neighbours never overlap. The step is the same\n * across the axis: thinning by skipping single labels reads as noise.\n */\nfunction thinned(\n\tticks: ReadonlyArray<ChartValue>,\n\twidths: ReadonlyArray<number>,\n\tpositions: ReadonlyArray<number>,\n): ReadonlyArray<number> {\n\tif (ticks.length < 2) {\n\t\treturn ticks.map((_tick, index) => index);\n\t}\n\tconst spacing = Math.abs(positions[1] - positions[0]) || 1;\n\tconst widest = Math.max(...widths);\n\tconst step = Math.max(1, Math.ceil((widest + LABEL_SPACING) / spacing));\n\treturn ticks\n\t\t.map((_tick, index) => index)\n\t\t.filter((index) => index % step === 0);\n}\n\nexport function bottomAxis(\n\tinput: AxisMeasureInput,\n\tplot: ChartRect,\n\tgrid: boolean,\n): AxisNodes {\n\tconst { scale, options, title, theme, measureText } = input;\n\tconst ticks = axisTicks(scale, options);\n\tconst positions = ticks.map((tick) => scale.center(tick));\n\tconst gridNodes: SceneNode[] = grid\n\t\t? ticks.map((tick, index) => ({\n\t\t\t\tkind: \"line\",\n\t\t\t\tkey: `grid-x:${tickKey(tick)}`,\n\t\t\t\trole: \"grid\",\n\t\t\t\tx1: positions[index],\n\t\t\t\ty1: plot.y,\n\t\t\t\tx2: positions[index],\n\t\t\t\ty2: plot.y + plot.height,\n\t\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1 },\n\t\t\t}))\n\t\t: [];\n\tif (hidden(options)) {\n\t\treturn { grid: gridNodes, labels: [] };\n\t}\n\tconst texts = ticks.map((tick) => tickLabel(scale, options, tick));\n\tconst widths = texts.map((text) => measureText(text, theme.fontSize));\n\tconst baseline = plot.y + plot.height + TICK_GAP;\n\tconst labels: SceneNode[] = thinned(ticks, widths, positions).map(\n\t\t(index) => ({\n\t\t\tkind: \"text\",\n\t\t\tkey: `tick-x:${tickKey(ticks[index])}`,\n\t\t\trole: \"axis\",\n\t\t\tx: positions[index],\n\t\t\ty: baseline,\n\t\t\ttext: texts[index],\n\t\t\tpaint: {\n\t\t\t\tfill: theme.muted,\n\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\ttextAnchor: \"middle\",\n\t\t\t\tbaseline: \"top\",\n\t\t\t},\n\t\t}),\n\t);\n\tif (title) {\n\t\tlabels.push({\n\t\t\tkind: \"text\",\n\t\t\tkey: \"title-x\",\n\t\t\trole: \"axis-title\",\n\t\t\tx: plot.x + plot.width / 2,\n\t\t\ty: baseline + theme.fontSize + TITLE_GAP,\n\t\t\ttext: title,\n\t\t\tpaint: {\n\t\t\t\tfill: theme.muted,\n\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\tfontWeight: 500,\n\t\t\t\ttextAnchor: \"middle\",\n\t\t\t\tbaseline: \"top\",\n\t\t\t},\n\t\t});\n\t}\n\treturn { grid: gridNodes, labels };\n}\n\nexport function leftAxis(\n\tinput: AxisMeasureInput,\n\tplot: ChartRect,\n\tgrid: boolean,\n\tchartWidth: number,\n): AxisNodes {\n\tconst { scale, options, title, theme, measureText } = input;\n\tconst ticks = axisTicks(scale, options);\n\tconst positions = ticks.map((tick) => scale.center(tick));\n\tconst gridNodes: SceneNode[] = grid\n\t\t? ticks.map((tick, index) => ({\n\t\t\t\tkind: \"line\",\n\t\t\t\tkey: `grid-y:${tickKey(tick)}`,\n\t\t\t\trole: \"grid\",\n\t\t\t\tx1: plot.x,\n\t\t\t\ty1: positions[index],\n\t\t\t\tx2: plot.x + plot.width,\n\t\t\t\ty2: positions[index],\n\t\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1 },\n\t\t\t}))\n\t\t: [];\n\tif (hidden(options)) {\n\t\treturn { grid: gridNodes, labels: [] };\n\t}\n\tconst discrete = scale.kind === \"band\" || scale.kind === \"point\";\n\tconst maxWidth = discrete\n\t\t? chartWidth * MAX_CATEGORY_SHARE\n\t\t: Number.POSITIVE_INFINITY;\n\tconst texts = ticks.map((tick) =>\n\t\ttruncate(\n\t\t\ttickLabel(scale, options, tick),\n\t\t\tmaxWidth,\n\t\t\ttheme.fontSize,\n\t\t\tmeasureText,\n\t\t),\n\t);\n\tconst heights = texts.map(() => theme.fontSize);\n\tconst labels: SceneNode[] = thinned(ticks, heights, positions).map(\n\t\t(index) => ({\n\t\t\tkind: \"text\",\n\t\t\tkey: `tick-y:${tickKey(ticks[index])}`,\n\t\t\trole: \"axis\",\n\t\t\tx: plot.x - TICK_GAP,\n\t\t\ty: positions[index],\n\t\t\ttext: texts[index],\n\t\t\tpaint: {\n\t\t\t\tfill: theme.muted,\n\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\ttextAnchor: \"end\",\n\t\t\t\tbaseline: \"middle\",\n\t\t\t},\n\t\t}),\n\t);\n\tif (title) {\n\t\tlabels.push({\n\t\t\tkind: \"text\",\n\t\t\tkey: \"title-y\",\n\t\t\trole: \"axis-title\",\n\t\t\tx: EDGE / 2 + theme.fontSize / 2,\n\t\t\ty: plot.y + plot.height / 2,\n\t\t\ttext: title,\n\t\t\trotate: -90,\n\t\t\tpaint: {\n\t\t\t\tfill: theme.muted,\n\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\tfontWeight: 500,\n\t\t\t\ttextAnchor: \"middle\",\n\t\t\t\tbaseline: \"middle\",\n\t\t\t},\n\t\t});\n\t}\n\treturn { grid: gridNodes, labels };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voila.dev/chart",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.126",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Charts as data: a definition of marks, channels and scales, drawn to SVG or Canvas, keyboard and screen-reader accessible. The core has no dependencies; the heavy layouts (geo, hierarchy, sankey…) sit behind their own subpaths.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"sideEffects": false,
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@voila.dev/motion": "6.0.
|
|
67
|
+
"@voila.dev/motion": "6.0.126",
|
|
68
68
|
"d3-contour": "4.0.2",
|
|
69
69
|
"d3-delaunay": "6.0.4",
|
|
70
70
|
"d3-force": "3.0.0",
|
package/src/core/guides/axes.ts
CHANGED
|
@@ -49,6 +49,11 @@ export function tickLabel(
|
|
|
49
49
|
return options?.tickFormat?.(value) ?? scale.format(value);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/** Two ticks can share a label ("11:00" on two days), never a value. */
|
|
53
|
+
function tickKey(value: ChartValue): string {
|
|
54
|
+
return value instanceof Date ? String(value.getTime()) : String(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
52
57
|
/** Cuts a label down to `maxWidth`, ending on an ellipsis. */
|
|
53
58
|
export function truncate(
|
|
54
59
|
text: string,
|
|
@@ -157,7 +162,7 @@ export function bottomAxis(
|
|
|
157
162
|
const gridNodes: SceneNode[] = grid
|
|
158
163
|
? ticks.map((tick, index) => ({
|
|
159
164
|
kind: "line",
|
|
160
|
-
key: `grid-x:${
|
|
165
|
+
key: `grid-x:${tickKey(tick)}`,
|
|
161
166
|
role: "grid",
|
|
162
167
|
x1: positions[index],
|
|
163
168
|
y1: plot.y,
|
|
@@ -175,7 +180,7 @@ export function bottomAxis(
|
|
|
175
180
|
const labels: SceneNode[] = thinned(ticks, widths, positions).map(
|
|
176
181
|
(index) => ({
|
|
177
182
|
kind: "text",
|
|
178
|
-
key: `tick-x:${
|
|
183
|
+
key: `tick-x:${tickKey(ticks[index])}`,
|
|
179
184
|
role: "axis",
|
|
180
185
|
x: positions[index],
|
|
181
186
|
y: baseline,
|
|
@@ -220,7 +225,7 @@ export function leftAxis(
|
|
|
220
225
|
const gridNodes: SceneNode[] = grid
|
|
221
226
|
? ticks.map((tick, index) => ({
|
|
222
227
|
kind: "line",
|
|
223
|
-
key: `grid-y:${
|
|
228
|
+
key: `grid-y:${tickKey(tick)}`,
|
|
224
229
|
role: "grid",
|
|
225
230
|
x1: plot.x,
|
|
226
231
|
y1: positions[index],
|
|
@@ -248,7 +253,7 @@ export function leftAxis(
|
|
|
248
253
|
const labels: SceneNode[] = thinned(ticks, heights, positions).map(
|
|
249
254
|
(index) => ({
|
|
250
255
|
kind: "text",
|
|
251
|
-
key: `tick-y:${
|
|
256
|
+
key: `tick-y:${tickKey(ticks[index])}`,
|
|
252
257
|
role: "axis",
|
|
253
258
|
x: plot.x - TICK_GAP,
|
|
254
259
|
y: positions[index],
|