@graphenedata/cli 0.0.13 → 0.0.14

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 (45) hide show
  1. package/dist/cli/cli.js +8591 -1214
  2. package/dist/docs/base.md +98 -0
  3. package/dist/docs/cli.md +22 -0
  4. package/dist/docs/graphene.md +10 -10
  5. package/dist/ui/component-utilities/echarts.js +2 -3
  6. package/dist/ui/component-utilities/formatting.js +3 -11
  7. package/dist/ui/component-utilities/getSeriesConfig.js +2 -1
  8. package/dist/ui/components/Area.svelte +188 -151
  9. package/dist/ui/components/AreaChart.svelte +43 -79
  10. package/dist/ui/components/Bar.svelte +273 -255
  11. package/dist/ui/components/BarChart.svelte +58 -112
  12. package/dist/ui/components/BigValue.svelte +13 -7
  13. package/dist/ui/components/Chart.svelte +280 -317
  14. package/dist/ui/components/Column.svelte +102 -113
  15. package/dist/ui/components/DateRange.svelte +37 -27
  16. package/dist/ui/components/Dropdown.svelte +77 -57
  17. package/dist/ui/components/DropdownOption.svelte +10 -7
  18. package/dist/ui/components/ECharts.svelte +23 -16
  19. package/dist/ui/components/ErrorChart.svelte +85 -21
  20. package/dist/ui/components/GrapheneQuery.svelte +7 -3
  21. package/dist/ui/components/InlineDelta.svelte +53 -34
  22. package/dist/ui/components/Line.svelte +192 -178
  23. package/dist/ui/components/LineChart.svelte +53 -96
  24. package/dist/ui/components/PieChart.svelte +26 -15
  25. package/dist/ui/components/QueryLoad.svelte +15 -10
  26. package/dist/ui/components/SortIcon.svelte +5 -1
  27. package/dist/ui/components/Table.svelte +15 -9
  28. package/dist/ui/components/TableCell.svelte +30 -17
  29. package/dist/ui/components/TableGroupRow.svelte +26 -19
  30. package/dist/ui/components/TableGroupToggle.svelte +9 -6
  31. package/dist/ui/components/TableHeader.svelte +37 -27
  32. package/dist/ui/components/TableRow.svelte +30 -20
  33. package/dist/ui/components/TableSubtotalRow.svelte +16 -9
  34. package/dist/ui/components/TableTotalRow.svelte +18 -11
  35. package/dist/ui/components/TextInput.svelte +23 -20
  36. package/dist/ui/components/_Table.svelte +303 -260
  37. package/dist/ui/internal/LocalApp.svelte +40 -0
  38. package/dist/ui/internal/NavSidebar.svelte +27 -30
  39. package/dist/ui/internal/PageError.svelte +23 -0
  40. package/dist/ui/internal/checkSocket.ts +48 -0
  41. package/dist/ui/internal/queryEngine.ts +9 -2
  42. package/dist/ui/internal/telemetry.ts +1 -0
  43. package/dist/ui/web.js +5 -55
  44. package/package.json +8 -9
  45. package/dist/ui/internal/NavSidebarHMR.svelte +0 -8
@@ -1,302 +1,317 @@
1
- <script>
2
- import {getContext, beforeUpdate} from 'svelte'
1
+ <script lang="ts">
2
+ import {getContext} from 'svelte'
3
3
  import {propKey, configKey} from '../component-utilities/chartContext.js'
4
- const props = getContext(propKey)
5
- const config = getContext(configKey)
6
-
4
+ import type {Writable} from 'svelte/store'
7
5
  import getSeriesConfig from '../component-utilities/getSeriesConfig.js'
8
6
  import getStackedData from '../component-utilities/getStackedData.js'
9
7
  import getSortedData from '../component-utilities/getSortedData.js'
10
8
  import formatTitle from '../component-utilities/formatTitle.js'
11
9
  import getCompletedData from '../component-utilities/getCompletedData.js'
12
10
  import getYAxisIndex from '../component-utilities/getYAxisIndex.js'
13
-
14
- import {
15
- formatValue,
16
- getFormatObjectFromString,
17
- } from '../component-utilities/formatting.js'
11
+ import {formatValue, getFormatObjectFromString} from '../component-utilities/formatting.js'
18
12
  import {getThemeStores} from '../component-utilities/themeStores'
19
13
  import {parseCommaList} from '../component-utilities/inputUtils.ts'
20
14
 
15
+ interface Props {
16
+ y?: any, y2?: any, series?: any, options?: any, name?: any, type?: string, stackName?: any
17
+ fillColor?: any, fillOpacity?: any, outlineColor?: any, outlineWidth?: any
18
+ labels?: boolean | string, seriesLabels?: boolean | string, labelSize?: number
19
+ labelPosition?: string, labelColor?: any, labelFmt?: any, yLabelFmt?: any, y2LabelFmt?: any
20
+ y2SeriesType?: string, stackTotalLabel?: boolean | string, showAllLabels?: boolean | string
21
+ seriesOrder?: any, seriesLabelFmt?: any
22
+ }
23
+
24
+ const chartProps: Writable<any> = getContext(propKey)
25
+ const config: Writable<any> = getContext(configKey)
21
26
  const {resolveColor} = getThemeStores()
22
27
 
23
- export let y = undefined
24
- const ySet = y ? true : false // Hack, see chart.svelte
25
- export let y2 = undefined
26
- const y2Set = y2 ? true : false // Hack, see chart.svelte
27
- export let series = undefined
28
- const seriesSet = series ? true : false // Hack, see chart.svelte
29
- export let options = undefined
30
- export let name = undefined // name to appear in legend (for single series graphics)
31
- export let type = 'stacked' // stacked, grouped, or stacked100
32
- export let stackName = undefined
33
-
34
- export let fillColor = undefined
35
- $: fillColorStore = resolveColor(fillColor)
36
-
37
- export let fillOpacity = undefined
38
-
39
- export let outlineColor = undefined
40
- $: outlineColorStore = resolveColor(outlineColor)
41
-
42
- export let outlineWidth = undefined
43
-
44
- export let labels = false
45
- $: labels = labels === 'true' || labels === true
46
- export let seriesLabels = true
47
- $: seriesLabels = seriesLabels === 'true' || seriesLabels === true
48
- export let labelSize = 11
49
- export let labelPosition = undefined
50
-
51
- export let labelColor = undefined
52
- $: labelColorStore = resolveColor(labelColor)
53
-
54
- export let labelFmt = undefined
55
- let labelFormat
56
- if (labelFmt) {
57
- labelFormat = getFormatObjectFromString(labelFmt)
58
- }
59
- export let yLabelFmt = undefined
60
- let yLabelFormat
61
- if (yLabelFmt) {
62
- yLabelFormat = getFormatObjectFromString(yLabelFmt)
28
+ let {
29
+ y = undefined, y2 = undefined, series = undefined, options = undefined, name = undefined,
30
+ type = 'stacked', stackName = undefined, fillColor = undefined, fillOpacity = undefined,
31
+ outlineColor = undefined, outlineWidth = undefined, labels = false, seriesLabels = true,
32
+ labelSize = 11, labelPosition = undefined, labelColor = undefined, labelFmt = undefined,
33
+ yLabelFmt = undefined, y2LabelFmt = undefined, y2SeriesType = 'bar', stackTotalLabel = true,
34
+ showAllLabels = false, seriesOrder = undefined, seriesLabelFmt = undefined,
35
+ }: Props = $props()
36
+
37
+ // Use $derived for values that depend on props
38
+ let ySet = $derived(y ? true : false)
39
+ let y2Set = $derived(y2 ? true : false)
40
+ let seriesSet = $derived(series ? true : false)
41
+
42
+ let fillColorStore = $derived(resolveColor(fillColor))
43
+ let outlineColorStore = $derived(resolveColor(outlineColor))
44
+ let labelColorStore = $derived(resolveColor(labelColor))
45
+ let labelsBool = $derived(labels === 'true' || labels === true)
46
+ let seriesLabelsBool = $derived(seriesLabels === 'true' || seriesLabels === true)
47
+ let stackTotalLabelBool = $derived(stackTotalLabel === 'true' || stackTotalLabel === true)
48
+
49
+ // Format objects derived from props
50
+ let labelFormat = $derived(labelFmt ? getFormatObjectFromString(labelFmt) : undefined)
51
+ let yLabelFormat = $derived(yLabelFmt ? getFormatObjectFromString(yLabelFmt) : undefined)
52
+ let y2LabelFormat = $derived(y2LabelFmt ? getFormatObjectFromString(y2LabelFmt) : undefined)
53
+
54
+ let barMaxWidth = 60
55
+
56
+ // Derive values from chartProps store instead of using $effect to assign
57
+ let data = $derived($chartProps.data)
58
+ let x = $derived($chartProps.x)
59
+ let resolvedY = $derived(ySet ? parseCommaList(y) : $chartProps.y)
60
+ let resolvedY2 = $derived(y2Set ? parseCommaList(y2) : $chartProps.y2)
61
+ let yFormat = $derived($chartProps.yFormat)
62
+ let y2Format = $derived($chartProps.y2Format)
63
+ let yCount = $derived($chartProps.yCount)
64
+ let y2Count = $derived($chartProps.y2Count)
65
+ let swapXY = $derived($chartProps.swapXY)
66
+ let baseXType = $derived($chartProps.xType)
67
+ let xMismatch = $derived($chartProps.xMismatch)
68
+ let columnSummary = $derived($chartProps.columnSummary)
69
+ let sort = $derived($chartProps.sort)
70
+ let resolvedSeries = $derived(seriesSet ? series : $chartProps.series)
71
+ let resolvedSeriesOrder = $derived(parseCommaList(seriesOrder))
72
+
73
+ // Value label positions:
74
+ const labelPositions = {
75
+ outside: 'top',
76
+ inside: 'inside',
63
77
  }
64
- export let y2LabelFmt = undefined
65
- let y2LabelFormat
66
- if (y2LabelFmt) {
67
- y2LabelFormat = getFormatObjectFromString(y2LabelFmt)
78
+
79
+ const swapXYLabelPositions = {
80
+ outside: 'right',
81
+ inside: 'inside',
68
82
  }
69
83
 
70
- export let y2SeriesType = 'bar'
84
+ // Compute all the derived state in one $derived.by block to avoid read/write conflicts
85
+ let computedState = $derived.by(() => {
86
+ let isSingleSeries = !resolvedSeries && (!Array.isArray(resolvedY) || resolvedY.length === 1)
87
+ let computedData = data
88
+ let computedXType = baseXType
89
+ let computedName = name
90
+ let computedStackName = stackName
91
+ let computedDefaultLabelPosition = swapXY ? 'right' : 'top'
92
+ let computedStackTotalSeries: any[] = []
93
+
94
+ if (!data || !columnSummary) {
95
+ return {
96
+ data: computedData,
97
+ xType: computedXType,
98
+ name: computedName,
99
+ stackName: computedStackName,
100
+ defaultLabelPosition: computedDefaultLabelPosition,
101
+ stackTotalSeries: computedStackTotalSeries,
102
+ }
103
+ }
71
104
 
72
- export let stackTotalLabel = true
73
- $: stackTotalLabel = stackTotalLabel === 'true' || stackTotalLabel === true
74
- export let showAllLabels = false
75
- export let seriesOrder = undefined
76
- let barMaxWidth = 60
105
+ if (isSingleSeries) {
106
+ // Single Series
107
+ let col = Array.isArray(resolvedY) ? resolvedY[0] : resolvedY
108
+ if (col && columnSummary[col]) {
109
+ computedName = computedName ?? formatTitle(col, columnSummary[col].title)
110
+ }
77
111
 
78
- // Prop check. If local props supplied, use those. Otherwise fall back to global props.
79
- $: data = $props.data
80
- $: x = $props.x
81
- $: y = ySet ? parseCommaList(y) : $props.y
82
- $: y2 = y2Set ? parseCommaList(y2) : $props.y2
83
- $: yFormat = $props.yFormat
84
- $: y2Format = $props.y2Format
85
- $: yCount = $props.yCount
86
- $: y2Count = $props.y2Count
87
- $: swapXY = $props.swapXY
88
- $: xType = $props.xType
89
- $: xMismatch = $props.xMismatch
90
- $: columnSummary = $props.columnSummary
91
- $: sort = $props.sort
92
- $: series = seriesSet ? series : $props.series
93
- $: seriesOrder = parseCommaList(seriesOrder)
94
-
95
- let stackedData
96
- let sortOrder
97
- let defaultLabelPosition
98
-
99
- $: if (!series && (!Array.isArray(y) || y.length === 1)) {
100
- // Single Series
101
- {
102
- let col = Array.isArray(y) ? y[0] : y
103
- name = name ?? formatTitle(col, columnSummary[col].title)
104
- }
112
+ if (swapXY && computedXType !== 'category') {
113
+ computedData = getCompletedData(computedData, x, resolvedY, resolvedSeries, true, computedXType !== 'time')
114
+ computedXType = 'category'
115
+ }
105
116
 
106
- if (swapXY && xType !== 'category') {
107
- data = getCompletedData(data, x, y, series, true, xType !== 'time')
108
- xType = 'category'
109
- }
117
+ computedStackName = 'stack1'
118
+ computedDefaultLabelPosition = swapXY ? 'right' : 'top'
119
+ } else {
120
+ // Multi Series
121
+ // Sort by stack total for category axis
122
+ if (sort === true && computedXType === 'category') {
123
+ let stackedData = getStackedData(computedData, x, resolvedY)
110
124
 
111
- stackName = 'stack1'
125
+ if (Array.isArray(resolvedY) && resolvedY.length > 1) {
126
+ stackedData = getSortedData(stackedData, 'stackTotal', false)
127
+ } else {
128
+ let col = Array.isArray(resolvedY) ? resolvedY[0] : resolvedY
129
+ stackedData = getSortedData(stackedData, col, false)
130
+ }
112
131
 
113
- defaultLabelPosition = swapXY ? 'right' : 'top'
114
- } else {
115
- // Multi Series
116
- // Sort by stack total for category axis
117
- if (sort === true && xType === 'category') {
118
- stackedData = getStackedData(data, x, y)
132
+ let sortOrder = stackedData.map((d: any) => d[x])
133
+ computedData = [...computedData].sort(function (a: any, b: any) {
134
+ return sortOrder.indexOf(a[x]) - sortOrder.indexOf(b[x])
135
+ })
136
+ }
119
137
 
120
- if (Array.isArray(y) && y.length > 1) {
121
- stackedData = getSortedData(stackedData, 'stackTotal', false)
122
- } else {
123
- let col = Array.isArray(y) ? y[0] : y
124
- stackedData = getSortedData(stackedData, col, false)
138
+ // Run fill for missing series entries, only if it's a stacked bar
139
+ if (swapXY || ((computedXType === 'value' || computedXType === 'category') && type.includes('stacked'))) {
140
+ computedData = getCompletedData(computedData, x, resolvedY, resolvedSeries, true, computedXType === 'value')
141
+ computedXType = 'category'
142
+ } else if (computedXType === 'time' && type.includes('stacked')) {
143
+ computedData = getCompletedData(computedData, x, resolvedY, resolvedSeries, true, true)
125
144
  }
126
145
 
127
- sortOrder = stackedData.map((d) => d[x])
128
- data = [...data].sort(function (a, b) {
129
- return sortOrder.indexOf(a[x]) - sortOrder.indexOf(b[x])
130
- })
146
+ if (type.includes('stacked')) {
147
+ computedStackName = computedStackName ?? 'stack1'
148
+ computedDefaultLabelPosition = 'inside'
149
+ } else {
150
+ computedStackName = undefined
151
+ computedDefaultLabelPosition = swapXY ? 'right' : 'top'
152
+ }
131
153
  }
132
154
 
133
- // Run fill for missing series entries, only if it's a stacked bar
134
- if (swapXY || ((xType === 'value' || xType === 'category') && type.includes('stacked'))) {
135
- data = getCompletedData(data, x, y, series, true, xType === 'value')
136
- xType = 'category'
137
- } else if (xType === 'time' && type.includes('stacked')) {
138
- data = getCompletedData(data, x, y, series, true, true)
155
+ // Compute stack total series for stacked charts
156
+ if (type === 'stacked' && computedData) {
157
+ computedStackTotalSeries = getStackedData(computedData, x, resolvedY)
139
158
  }
140
159
 
141
- if (type.includes('stacked')) {
142
- // Set up stacks
143
- stackName = stackName ?? 'stack1'
144
- defaultLabelPosition = 'inside'
145
- } else {
146
- stackName = undefined
147
- defaultLabelPosition = swapXY ? 'right' : 'top'
160
+ return {
161
+ data: computedData,
162
+ xType: computedXType,
163
+ name: computedName,
164
+ stackName: computedStackName,
165
+ defaultLabelPosition: computedDefaultLabelPosition,
166
+ stackTotalSeries: computedStackTotalSeries,
148
167
  }
149
- }
168
+ })
150
169
 
151
- let stackTotalSeries
152
- $: if (type === 'stacked') {
153
- stackTotalSeries = getStackedData(data, x, y)
154
- }
170
+ // Extract computed values for use in template and other derived values
171
+ let processedData = $derived(computedState.data)
172
+ let xType = $derived(computedState.xType)
173
+ let resolvedName = $derived(computedState.name)
174
+ let resolvedStackName = $derived(computedState.stackName)
175
+ let defaultLabelPosition = $derived(computedState.defaultLabelPosition)
176
+ let stackTotalSeries = $derived(computedState.stackTotalSeries)
155
177
 
156
- // Value label positions:
157
- const labelPositions = {
158
- outside: 'top',
159
- inside: 'inside',
160
- }
161
-
162
- const swapXYLabelPositions = {
163
- outside: 'right',
164
- inside: 'inside',
165
- }
178
+ let resolvedLabelPosition = $derived(
179
+ (swapXY ? swapXYLabelPositions[labelPosition] : labelPositions[labelPosition]) ?? defaultLabelPosition,
180
+ )
166
181
 
167
- $: labelPosition =
168
- (swapXY ? swapXYLabelPositions[labelPosition] : labelPositions[labelPosition]) ??
169
- defaultLabelPosition
170
-
171
- $: baseConfig = {
172
- type: 'bar',
173
- stack: stackName,
174
- label: {
175
- show: labels && seriesLabels,
176
- // formatter: function (params) {
177
- // let output;
178
- // output =
179
- // params.value[swapXY ? 0 : 1] === 0
180
- // ? ''
181
- // : formatValue(params.value[swapXY ? 0 : 1], labelFormat ?? yFormat);
182
- // return output;
183
- // },
184
- formatter: function (params) {
185
- return params.value[swapXY ? 0 : 1] === 0
186
- ? ''
187
- : formatValue(
188
- params.value[swapXY ? 0 : 1],
189
- [yLabelFormat ?? labelFormat ?? yFormat, y2LabelFormat ?? labelFormat ?? y2Format][
190
- getYAxisIndex(params.componentIndex, yCount, y2Count)
191
- ],
192
- )
182
+ $effect(() => {
183
+ // Don't run until we have data
184
+ if (!processedData || !columnSummary) return
185
+
186
+ let baseConfig = {
187
+ type: 'bar',
188
+ stack: resolvedStackName,
189
+ label: {
190
+ show: labelsBool && seriesLabelsBool,
191
+ formatter: function (params: any) {
192
+ return params.value[swapXY ? 0 : 1] === 0
193
+ ? ''
194
+ : formatValue(
195
+ params.value[swapXY ? 0 : 1],
196
+ [yLabelFormat ?? labelFormat ?? yFormat, y2LabelFormat ?? labelFormat ?? y2Format][
197
+ getYAxisIndex(params.componentIndex, yCount, y2Count)
198
+ ],
199
+ )
200
+ },
201
+ position: resolvedLabelPosition,
202
+ fontSize: labelSize,
203
+ color: $labelColorStore,
193
204
  },
194
- position: labelPosition,
195
- fontSize: labelSize,
196
- color: $labelColorStore,
197
- },
198
- labelLayout: {
199
- hideOverlap: showAllLabels ? false : true,
200
- },
201
- emphasis: {
202
- focus: 'series',
203
- },
204
- barMaxWidth: barMaxWidth,
205
- itemStyle: {
206
- color: $fillColorStore,
207
- opacity: fillOpacity,
208
- borderColor: $outlineColorStore,
209
- borderWidth: outlineWidth,
210
- },
211
- }
212
-
213
- export let seriesLabelFmt = undefined
214
-
215
- $: seriesConfig = getSeriesConfig(
216
- data,
217
- x,
218
- y,
219
- series,
220
- swapXY,
221
- baseConfig,
222
- name,
223
- xMismatch,
224
- columnSummary,
225
- seriesOrder,
226
- undefined,
227
- undefined,
228
- y2,
229
- seriesLabelFmt,
230
- )
205
+ labelLayout: {
206
+ hideOverlap: showAllLabels ? false : true,
207
+ },
208
+ emphasis: {
209
+ focus: 'series',
210
+ },
211
+ barMaxWidth: barMaxWidth,
212
+ itemStyle: {
213
+ color: $fillColorStore,
214
+ opacity: fillOpacity,
215
+ borderColor: $outlineColorStore,
216
+ borderWidth: outlineWidth,
217
+ },
218
+ }
231
219
 
232
- $: config.update((d) => {
233
- d.series.push(...seriesConfig)
234
- // Push series into legend:
235
- d.legend.data.push(...seriesConfig.map((d) => d.name.toString()))
236
-
237
- // Stacked chart total label:
238
- // series !== x is to avoid an issue where same column is used for both - stackTotalLabel can't handle that
239
- if (
240
- labels === true &&
241
- type === 'stacked' &&
242
- ((Array.isArray(y) && y.length > 1) || (series !== undefined)) &&
243
- stackTotalLabel === true &&
244
- series !== x
245
- ) {
246
- // push stack total series for total label
247
- d.series.push({
248
- type: 'bar',
249
- stack: stackName,
250
- name: 'stackTotal',
251
- color: 'none',
252
- data: stackTotalSeries.map((row) => {
253
- let axisValue = xMismatch ? row[x].toString() : row[x]
254
- if (swapXY) return [0, axisValue]
255
- return [axisValue, 0]
256
- }),
257
- label: {
258
- show: true,
259
- position: swapXY ? 'right' : 'top',
260
- formatter: function (params) {
261
- let sum = 0
262
- seriesConfig.forEach((s) => {
263
- sum += s.data[params.dataIndex][swapXY ? 0 : 1]
264
- })
265
- return sum === 0 ? '' : formatValue(sum, labelFormat ?? yFormat)
220
+ let seriesConfig = getSeriesConfig(
221
+ processedData,
222
+ x,
223
+ resolvedY,
224
+ resolvedSeries,
225
+ swapXY,
226
+ baseConfig,
227
+ resolvedName,
228
+ xMismatch,
229
+ columnSummary,
230
+ resolvedSeriesOrder,
231
+ undefined,
232
+ undefined,
233
+ resolvedY2,
234
+ seriesLabelFmt,
235
+ )
236
+
237
+ config.update((d: any) => {
238
+ // Guard against incomplete config state
239
+ if (!d.series) d.series = []
240
+ if (!d.legend) d.legend = {data: []}
241
+ if (!d.legend.data) d.legend.data = []
242
+
243
+ d.series.push(...seriesConfig)
244
+ // Push series into legend:
245
+ d.legend.data.push(...seriesConfig.map((s: any) => s.name.toString()))
246
+
247
+ // Stacked chart total label:
248
+ // series !== x is to avoid an issue where same column is used for both - stackTotalLabel can't handle that
249
+ if (
250
+ labelsBool === true &&
251
+ type === 'stacked' &&
252
+ ((Array.isArray(resolvedY) && resolvedY.length > 1) || (resolvedSeries !== undefined)) &&
253
+ stackTotalLabelBool === true &&
254
+ resolvedSeries !== x
255
+ ) {
256
+ // push stack total series for total label
257
+ d.series.push({
258
+ type: 'bar',
259
+ stack: resolvedStackName,
260
+ name: 'stackTotal',
261
+ color: 'none',
262
+ data: stackTotalSeries.map((row: any) => {
263
+ let axisValue = xMismatch ? row[x].toString() : row[x]
264
+ if (swapXY) return [0, axisValue]
265
+ return [axisValue, 0]
266
+ }),
267
+ label: {
268
+ show: true,
269
+ position: swapXY ? 'right' : 'top',
270
+ formatter: function (params: any) {
271
+ let sum = 0
272
+ seriesConfig.forEach((s: any) => {
273
+ sum += s.data[params.dataIndex][swapXY ? 0 : 1]
274
+ })
275
+ return sum === 0 ? '' : formatValue(sum, labelFormat ?? yFormat)
276
+ },
277
+ fontWeight: 'bold',
278
+ fontSize: labelSize,
279
+ padding: swapXY ? [0, 0, 0, 5] : undefined,
266
280
  },
267
- fontWeight: 'bold',
268
- fontSize: labelSize,
269
- padding: swapXY ? [0, 0, 0, 5] : undefined,
270
- },
271
- })
281
+ })
272
282
 
273
- // disable legend selected mode when stackTotalLabel is displayed:
274
- d.legend.selectedMode = false
275
- }
276
- return d
283
+ // disable legend selected mode when stackTotalLabel is displayed:
284
+ d.legend.selectedMode = false
285
+ }
286
+ return d
287
+ })
277
288
  })
278
289
 
279
- $: chartOverrides = {
290
+ let chartOverrides = $derived({
280
291
  // Evidence definition of axes (yAxis = dependent, xAxis = independent)
281
292
  xAxis: {
282
293
  boundaryGap: ['1%', '2%'],
283
294
  type: xType,
284
295
  },
285
- }
296
+ })
286
297
 
287
- beforeUpdate(() => {
288
- // beforeUpdate ensures that these overrides always run before we render the chart.
298
+ // Use $effect.pre() instead of beforeUpdate for runes mode
299
+ $effect.pre(() => {
300
+ // This ensures that these overrides always run before we render the chart.
289
301
  // otherwise, this block won't re-execute after a change to the data object, and
290
302
  // the chart will re-render using the base config from Chart.svelte
291
303
 
292
304
  if (options) {
293
- config.update((d) => {
305
+ config.update((d: any) => {
294
306
  return {...d, ...options}
295
307
  })
296
308
  }
297
309
 
298
310
  if (chartOverrides) {
299
- config.update((d) => {
311
+ config.update((d: any) => {
312
+ // Guard against incomplete config state
313
+ if (!d.yAxis || !Array.isArray(d.yAxis)) return d
314
+
300
315
  if (type.includes('stacked')) {
301
316
  d.tooltip = {...d.tooltip, order: 'seriesDesc'}
302
317
  } else {
@@ -305,22 +320,25 @@
305
320
  if (type === 'stacked100') {
306
321
  if (swapXY) {
307
322
  d.xAxis = {...d.xAxis, max: 1}
308
- } else {
323
+ } else if (d.yAxis[0]) {
309
324
  d.yAxis[0] = {...d.yAxis[0], max: 1}
310
325
  }
311
326
  }
312
327
  if (swapXY) {
313
328
  d.yAxis = {...d.yAxis, ...chartOverrides.xAxis}
314
- d.xAxis = {...d.xAxis, ...chartOverrides.yAxis}
329
+ d.xAxis = {...d.xAxis}
315
330
  } else {
316
- d.yAxis[0] = {...d.yAxis[0], ...chartOverrides.yAxis}
331
+ if (d.yAxis[0]) {
332
+ d.yAxis[0] = {...d.yAxis[0]}
333
+ }
317
334
  d.xAxis = {...d.xAxis, ...chartOverrides.xAxis}
318
- if (y2Count > 0) {
319
- d.yAxis[1] = {...d.yAxis[1], show: true}
320
- if (['line', 'bar', 'scatter'].includes(y2SeriesType)) {
335
+ if (y2Count > 0 && d.yAxis[1]) {
336
+ if (['line', 'bar', 'scatter'].includes(y2SeriesType) && d.series) {
321
337
  for (let i = 0; i < y2Count; i++) {
322
- d.series[yCount + i].type = y2SeriesType
323
- d.series[yCount + i].stack = undefined
338
+ if (d.series[yCount + i]) {
339
+ d.series[yCount + i].type = y2SeriesType
340
+ d.series[yCount + i].stack = undefined
341
+ }
324
342
  }
325
343
  }
326
344
  }