@graphenedata/cli 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.md +100 -0
- package/THIRD_PARTY_NOTICES.md +12 -0
- package/cli.ts +157 -0
- package/dist/cli/cli.js +43 -0
- package/dist/docs/data_apps/components/charts/annotations.md +673 -0
- package/dist/docs/data_apps/components/charts/area-chart.md +202 -0
- package/dist/docs/data_apps/components/charts/bar-chart.md +317 -0
- package/dist/docs/data_apps/components/charts/box-plot.md +190 -0
- package/dist/docs/data_apps/components/charts/bubble-chart.md +151 -0
- package/dist/docs/data_apps/components/charts/calendar-heatmap.md +112 -0
- package/dist/docs/data_apps/components/charts/custom-echarts.md +308 -0
- package/dist/docs/data_apps/components/charts/echarts-options.md +217 -0
- package/dist/docs/data_apps/components/charts/funnel-chart.md +106 -0
- package/dist/docs/data_apps/components/charts/heatmap.md +180 -0
- package/dist/docs/data_apps/components/charts/histogram.md +107 -0
- package/dist/docs/data_apps/components/charts/line-chart.md +265 -0
- package/dist/docs/data_apps/components/charts/mixed-type-charts.md +240 -0
- package/dist/docs/data_apps/components/charts/sankey-diagram.md +301 -0
- package/dist/docs/data_apps/components/charts/scatter-plot.md +134 -0
- package/dist/docs/data_apps/components/charts/sparkline.md +68 -0
- package/dist/docs/data_apps/components/data/big-value.md +153 -0
- package/dist/docs/data_apps/components/data/delta.md +89 -0
- package/dist/docs/data_apps/components/data/table.md +470 -0
- package/dist/docs/data_apps/components/data/value.md +97 -0
- package/dist/docs/data_apps/components/inputs/button-group.md +154 -0
- package/dist/docs/data_apps/components/inputs/checkbox.md +52 -0
- package/dist/docs/data_apps/components/inputs/date-input.md +131 -0
- package/dist/docs/data_apps/components/inputs/date-range.md +124 -0
- package/dist/docs/data_apps/components/inputs/dimension-grid.md +67 -0
- package/dist/docs/data_apps/components/inputs/dropdown.md +199 -0
- package/dist/docs/data_apps/components/inputs/index.md +3 -0
- package/dist/docs/data_apps/components/inputs/slider.md +126 -0
- package/dist/docs/data_apps/components/inputs/text-input.md +86 -0
- package/dist/docs/data_apps/components/maps/area-map.md +397 -0
- package/dist/docs/data_apps/components/maps/base-map.md +269 -0
- package/dist/docs/data_apps/components/maps/bubble-map.md +361 -0
- package/dist/docs/data_apps/components/maps/point-map.md +326 -0
- package/dist/docs/data_apps/components/maps/us-map.md +167 -0
- package/dist/docs/data_apps/components/ui/accordion.md +116 -0
- package/dist/docs/data_apps/components/ui/alert.md +37 -0
- package/dist/docs/data_apps/components/ui/big-link.md +19 -0
- package/dist/docs/data_apps/components/ui/details.md +58 -0
- package/dist/docs/data_apps/components/ui/download-data.md +41 -0
- package/dist/docs/data_apps/components/ui/embed.md +47 -0
- package/dist/docs/data_apps/components/ui/grid.md +45 -0
- package/dist/docs/data_apps/components/ui/image.md +61 -0
- package/dist/docs/data_apps/components/ui/info.md +47 -0
- package/dist/docs/data_apps/components/ui/last-refreshed.md +28 -0
- package/dist/docs/data_apps/components/ui/link-button.md +20 -0
- package/dist/docs/data_apps/components/ui/link.md +40 -0
- package/dist/docs/data_apps/components/ui/modal.md +57 -0
- package/dist/docs/data_apps/components/ui/note.md +32 -0
- package/dist/docs/data_apps/components/ui/print-format-components.md +85 -0
- package/dist/docs/data_apps/components/ui/tabs.md +122 -0
- package/dist/docs/graphene.md +129 -0
- package/dist/ui/app.css +332 -0
- package/dist/ui/assets/favicon.ico +0 -0
- package/dist/ui/component-utilities/autoFormatting.js +301 -0
- package/dist/ui/component-utilities/builtInFormats.js +482 -0
- package/dist/ui/component-utilities/chartContext.js +12 -0
- package/dist/ui/component-utilities/chartWindowDebug.js +21 -0
- package/dist/ui/component-utilities/checkInputs.js +95 -0
- package/dist/ui/component-utilities/convert.js +15 -0
- package/dist/ui/component-utilities/dateParsing.js +57 -0
- package/dist/ui/component-utilities/dropdownContext.ts +1 -0
- package/dist/ui/component-utilities/echarts.js +262 -0
- package/dist/ui/component-utilities/echartsThemes.js +453 -0
- package/dist/ui/component-utilities/formatTitle.js +24 -0
- package/dist/ui/component-utilities/formatting.js +258 -0
- package/dist/ui/component-utilities/getColumnExtents.js +79 -0
- package/dist/ui/component-utilities/getColumnSummary.js +67 -0
- package/dist/ui/component-utilities/getCompletedData.js +114 -0
- package/dist/ui/component-utilities/getDistinctCount.js +7 -0
- package/dist/ui/component-utilities/getDistinctValues.js +15 -0
- package/dist/ui/component-utilities/getSeriesConfig.js +236 -0
- package/dist/ui/component-utilities/getSortedData.js +7 -0
- package/dist/ui/component-utilities/getStackPercentages.js +43 -0
- package/dist/ui/component-utilities/getStackedData.js +17 -0
- package/dist/ui/component-utilities/getYAxisIndex.js +15 -0
- package/dist/ui/component-utilities/globalContexts.js +1 -0
- package/dist/ui/component-utilities/helpers/getCompletedData.helpers.js +119 -0
- package/dist/ui/component-utilities/inputUtils.ts +25 -0
- package/dist/ui/component-utilities/replaceNulls.js +14 -0
- package/dist/ui/component-utilities/tableUtils.ts +120 -0
- package/dist/ui/component-utilities/themeStores.ts +116 -0
- package/dist/ui/components/Area.svelte +174 -0
- package/dist/ui/components/AreaChart.svelte +150 -0
- package/dist/ui/components/Bar.svelte +326 -0
- package/dist/ui/components/BarChart.svelte +194 -0
- package/dist/ui/components/BigValue.svelte +69 -0
- package/dist/ui/components/Chart.svelte +1070 -0
- package/dist/ui/components/Column.svelte +172 -0
- package/dist/ui/components/DateRange.svelte +324 -0
- package/dist/ui/components/Dropdown.svelte +738 -0
- package/dist/ui/components/DropdownOption.svelte +21 -0
- package/dist/ui/components/ECharts.svelte +77 -0
- package/dist/ui/components/ErrorChart.svelte +54 -0
- package/dist/ui/components/GrapheneQuery.svelte +12 -0
- package/dist/ui/components/InlineDelta.svelte +150 -0
- package/dist/ui/components/Line.svelte +210 -0
- package/dist/ui/components/LineChart.svelte +178 -0
- package/dist/ui/components/PieChart.svelte +36 -0
- package/dist/ui/components/QueryLoad.svelte +82 -0
- package/dist/ui/components/Row.svelte +14 -0
- package/dist/ui/components/SortIcon.svelte +32 -0
- package/dist/ui/components/Table.svelte +19 -0
- package/dist/ui/components/TableCell.svelte +75 -0
- package/dist/ui/components/TableGroupRow.svelte +136 -0
- package/dist/ui/components/TableGroupToggle.svelte +42 -0
- package/dist/ui/components/TableHeader.svelte +242 -0
- package/dist/ui/components/TableRow.svelte +283 -0
- package/dist/ui/components/TableSubtotalRow.svelte +62 -0
- package/dist/ui/components/TableTotalRow.svelte +88 -0
- package/dist/ui/components/TextInput.svelte +92 -0
- package/dist/ui/components/_Table.svelte +516 -0
- package/dist/ui/internal/clientCache.ts +43 -0
- package/dist/ui/internal/queryEngine.ts +169 -0
- package/dist/ui/internal/telemetry.ts +28 -0
- package/dist/ui/internal/theme.ts +88 -0
- package/dist/ui/layout.svelte +3 -0
- package/dist/ui/playwright.config.ts +30 -0
- package/dist/ui/web.js +106 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1070 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import {writable} from 'svelte/store'
|
|
3
|
+
import {setContext} from 'svelte'
|
|
4
|
+
import {propKey, configKey} from '../component-utilities/chartContext.js'
|
|
5
|
+
let props = writable({})
|
|
6
|
+
/** @type {import("svelte/store").Writable<import("echarts").Options>} */
|
|
7
|
+
let config = writable({})
|
|
8
|
+
|
|
9
|
+
setContext(propKey, props)
|
|
10
|
+
setContext(configKey, config)
|
|
11
|
+
|
|
12
|
+
import ECharts from './ECharts.svelte'
|
|
13
|
+
import getColumnSummary from '../component-utilities/getColumnSummary.js'
|
|
14
|
+
import getDistinctValues from '../component-utilities/getDistinctValues.js'
|
|
15
|
+
import getDistinctCount from '../component-utilities/getDistinctCount.js'
|
|
16
|
+
import getStackPercentages from '../component-utilities/getStackPercentages.js'
|
|
17
|
+
import getSortedData from '../component-utilities/getSortedData.js'
|
|
18
|
+
import getYAxisIndex from '../component-utilities/getYAxisIndex.js'
|
|
19
|
+
import {standardizeDateColumn} from '../component-utilities/dateParsing.js'
|
|
20
|
+
import {formatAxisValue, formatValue, getFormatObjectFromString} from '../component-utilities/formatting.js'
|
|
21
|
+
import formatTitle from '../component-utilities/formatTitle.js'
|
|
22
|
+
import ErrorChart from './ErrorChart.svelte'
|
|
23
|
+
import checkInputs from '../component-utilities/checkInputs.js'
|
|
24
|
+
import {getThemeStores} from '../component-utilities/themeStores'
|
|
25
|
+
import {toBoolean} from '../component-utilities/convert'
|
|
26
|
+
|
|
27
|
+
const {theme, resolveColor, resolveColorsObject, resolveColorPalette} = getThemeStores()
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------------------
|
|
30
|
+
// Input Props
|
|
31
|
+
// ---------------------------------------------------------------------------------------
|
|
32
|
+
// Data and columns:
|
|
33
|
+
export let data = undefined
|
|
34
|
+
export let queryID = undefined
|
|
35
|
+
export let x = undefined
|
|
36
|
+
export let y = undefined
|
|
37
|
+
export let y2 = undefined
|
|
38
|
+
export let series = undefined
|
|
39
|
+
export let size = undefined
|
|
40
|
+
export let tooltipTitle = undefined
|
|
41
|
+
|
|
42
|
+
export let showAllXAxisLabels = undefined
|
|
43
|
+
|
|
44
|
+
// This should be reworked to fit better with svelte's reactivity.
|
|
45
|
+
|
|
46
|
+
// We rewrite the x and y values with fallbacks if they aren't present
|
|
47
|
+
// the fallback logic *depends* on the values of x and y
|
|
48
|
+
// when x and y are replaced by the fallbacks, the fallback logic doesn't reset.
|
|
49
|
+
// if the y value isn't set, var y gets populated with a fall back from the data.
|
|
50
|
+
// if the data changes, we are now acting as if the fallback from above was entered by the user, and
|
|
51
|
+
// then we throw if the fallback column is now missing.
|
|
52
|
+
|
|
53
|
+
// This is a hack to get around the above
|
|
54
|
+
// Reactively updated below to prevent circular reactivity
|
|
55
|
+
let ySet = y ? true : false
|
|
56
|
+
// const y2Set = y2 ? true : false;
|
|
57
|
+
let xSet = x ? true : false
|
|
58
|
+
|
|
59
|
+
export let swapXY = false // Flipped axis chart
|
|
60
|
+
$: swapXY = toBoolean(swapXY)
|
|
61
|
+
|
|
62
|
+
// Chart titles:
|
|
63
|
+
export let title = undefined
|
|
64
|
+
export let subtitle = undefined
|
|
65
|
+
|
|
66
|
+
// Chart type:
|
|
67
|
+
export let chartType = 'Chart' // Used to label chart error messages
|
|
68
|
+
export let bubble = false
|
|
69
|
+
export let hist = false
|
|
70
|
+
export let boxplot = false
|
|
71
|
+
let reqCols
|
|
72
|
+
|
|
73
|
+
// X axis:
|
|
74
|
+
export let xType = undefined // category or value
|
|
75
|
+
export let xAxisTitle = 'false' // Default false. If true, use formatTitle(x). Or you can supply a custom string
|
|
76
|
+
export let xBaseline = true
|
|
77
|
+
$: xBaseline = toBoolean(xBaseline)
|
|
78
|
+
export let xTickMarks = false
|
|
79
|
+
$: xTickMarks = toBoolean(xTickMarks)
|
|
80
|
+
export let xGridlines = false
|
|
81
|
+
$: xGridlines = toBoolean(xGridlines)
|
|
82
|
+
export let xAxisLabels = true
|
|
83
|
+
$: xAxisLabels = toBoolean(xAxisLabels)
|
|
84
|
+
export let sort = true // sorts x values in case x is out of order in dataset (e.g., would create line chart that is out of order)
|
|
85
|
+
$: sort = toBoolean(sort)
|
|
86
|
+
export let xFmt = undefined
|
|
87
|
+
export let xMin = undefined
|
|
88
|
+
export let xMax = undefined
|
|
89
|
+
|
|
90
|
+
// Y axis:
|
|
91
|
+
export let yLog = false
|
|
92
|
+
$: yLog = toBoolean(yLog)
|
|
93
|
+
export let yType = yLog === true ? 'log' : 'value' // value or log
|
|
94
|
+
export let yLogBase = 10
|
|
95
|
+
export let yAxisTitle = 'false' // Default false. If true, use formatTitle(x). Or you can supply a custom string
|
|
96
|
+
export let yBaseline = false
|
|
97
|
+
$: yBaseline = toBoolean(yBaseline)
|
|
98
|
+
|
|
99
|
+
export let yTickMarks = false
|
|
100
|
+
$: yTickMarks = toBoolean(yTickMarks)
|
|
101
|
+
export let yGridlines = true
|
|
102
|
+
$: yGridlines = toBoolean(yGridlines)
|
|
103
|
+
export let yAxisLabels = true
|
|
104
|
+
$: yAxisLabels = toBoolean(yAxisLabels)
|
|
105
|
+
|
|
106
|
+
export let yMin = undefined
|
|
107
|
+
export let yMax = undefined
|
|
108
|
+
export let yScale = false
|
|
109
|
+
$: yScale = toBoolean(yScale)
|
|
110
|
+
export let yFmt = undefined
|
|
111
|
+
|
|
112
|
+
export let yAxisColor = 'true'
|
|
113
|
+
$: yAxisColorStore = resolveColor(yAxisColor)
|
|
114
|
+
|
|
115
|
+
// Y2 axis:
|
|
116
|
+
export let y2AxisTitle = 'false' // Default false. If true, use formatTitle(x). Or you can supply a custom string
|
|
117
|
+
export let y2Baseline = false
|
|
118
|
+
$: y2Baseline = toBoolean(y2Baseline)
|
|
119
|
+
export let y2TickMarks = false
|
|
120
|
+
$: y2TickMarks = toBoolean(y2TickMarks)
|
|
121
|
+
export let y2Gridlines = true
|
|
122
|
+
$: y2Gridlines = toBoolean(y2Gridlines)
|
|
123
|
+
export let y2AxisLabels = true
|
|
124
|
+
$: y2AxisLabels = toBoolean(y2AxisLabels)
|
|
125
|
+
export let y2Min = undefined
|
|
126
|
+
export let y2Max = undefined
|
|
127
|
+
export let y2Scale = false
|
|
128
|
+
$: y2Scale = toBoolean(y2Scale)
|
|
129
|
+
export let y2Fmt = undefined
|
|
130
|
+
|
|
131
|
+
export let y2AxisColor = 'true'
|
|
132
|
+
$: y2AxisColorStore = resolveColor(y2AxisColor)
|
|
133
|
+
|
|
134
|
+
// Other column formats:
|
|
135
|
+
export let sizeFmt = undefined
|
|
136
|
+
|
|
137
|
+
// Color palette:
|
|
138
|
+
export let colorPalette = 'default'
|
|
139
|
+
$: colorPaletteStore = resolveColorPalette(colorPalette)
|
|
140
|
+
|
|
141
|
+
// Legend:
|
|
142
|
+
export let legend = undefined
|
|
143
|
+
|
|
144
|
+
// Additional Config Options:
|
|
145
|
+
export let echartsOptions = undefined // additional ECharts config object that will append to the config generated by our API
|
|
146
|
+
export let seriesOptions = undefined // additional ECharts config object that will be applied to every series in the config
|
|
147
|
+
|
|
148
|
+
export let seriesColors = undefined
|
|
149
|
+
$: seriesColorsStore = resolveColorsObject(seriesColors)
|
|
150
|
+
|
|
151
|
+
export let stackType = undefined // used in BarChart (stacked, grouped) and AreaChart (stacked)
|
|
152
|
+
export let stacked100 = false
|
|
153
|
+
|
|
154
|
+
export let chartAreaHeight = undefined
|
|
155
|
+
|
|
156
|
+
export let connectGroup = undefined // string represent name of group for connected charts. Charts with same connectGroup will have connected interactions
|
|
157
|
+
|
|
158
|
+
export let leftPadding = undefined
|
|
159
|
+
export let rightPadding = undefined
|
|
160
|
+
|
|
161
|
+
export let xLabelWrap = false // false = truncate, true = wrap
|
|
162
|
+
$: xLabelWrap = toBoolean(xLabelWrap)
|
|
163
|
+
|
|
164
|
+
const xAxisLabelOverflow = xLabelWrap ? 'break' : 'truncate'
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------------------
|
|
167
|
+
// Variable Declaration
|
|
168
|
+
// ---------------------------------------------------------------------------------------
|
|
169
|
+
// Column Summary:
|
|
170
|
+
let columnSummary
|
|
171
|
+
let columnNames
|
|
172
|
+
let uColNames = []
|
|
173
|
+
let unusedColumns = []
|
|
174
|
+
let uColType
|
|
175
|
+
let uColName
|
|
176
|
+
let xDataType
|
|
177
|
+
let xMismatch
|
|
178
|
+
let xFormat
|
|
179
|
+
let yFormat
|
|
180
|
+
let y2Format
|
|
181
|
+
let sizeFormat
|
|
182
|
+
let xUnitSummary
|
|
183
|
+
let yUnitSummary
|
|
184
|
+
let y2UnitSummary
|
|
185
|
+
let xDistinct
|
|
186
|
+
|
|
187
|
+
// Individual Config Sections:
|
|
188
|
+
let horizAxisConfig
|
|
189
|
+
let verticalAxisConfig
|
|
190
|
+
let horizAxisTitleConfig
|
|
191
|
+
let chartConfig
|
|
192
|
+
|
|
193
|
+
// Chart area sizing:
|
|
194
|
+
let hasTitle
|
|
195
|
+
let hasSubtitle
|
|
196
|
+
let hasLegend
|
|
197
|
+
let hasTopAxisTitle
|
|
198
|
+
let hasBottomAxisTitle
|
|
199
|
+
let titleFontSize
|
|
200
|
+
let subtitleFontSize
|
|
201
|
+
let titleBoxPadding
|
|
202
|
+
let titleBoxHeight
|
|
203
|
+
let chartAreaPaddingTop
|
|
204
|
+
let chartAreaPaddingBottom
|
|
205
|
+
let bottomAxisTitleSize
|
|
206
|
+
let topAxisTitleSize
|
|
207
|
+
let legendHeight
|
|
208
|
+
let legendPaddingTop
|
|
209
|
+
let legendTop
|
|
210
|
+
let chartTop
|
|
211
|
+
let chartBottom
|
|
212
|
+
let chartContainerHeight
|
|
213
|
+
let topAxisTitleTop
|
|
214
|
+
|
|
215
|
+
let horizAxisTitle
|
|
216
|
+
|
|
217
|
+
// Adjustment to avoid small bars on horizontal bar chart (extend chart height to accomodate):
|
|
218
|
+
let maxBars
|
|
219
|
+
let barCount
|
|
220
|
+
let heightMultiplier
|
|
221
|
+
|
|
222
|
+
// Set final chart height:
|
|
223
|
+
let height
|
|
224
|
+
let width
|
|
225
|
+
|
|
226
|
+
let missingCols = []
|
|
227
|
+
|
|
228
|
+
let originalRun = true
|
|
229
|
+
|
|
230
|
+
// Error Handling:
|
|
231
|
+
|
|
232
|
+
let inputCols = []
|
|
233
|
+
let optCols = []
|
|
234
|
+
let i
|
|
235
|
+
|
|
236
|
+
let error
|
|
237
|
+
|
|
238
|
+
// Date String Handling:
|
|
239
|
+
let columnSummaryArray
|
|
240
|
+
let dateCols
|
|
241
|
+
|
|
242
|
+
$: {
|
|
243
|
+
try {
|
|
244
|
+
error = undefined
|
|
245
|
+
missingCols = []
|
|
246
|
+
unusedColumns = []
|
|
247
|
+
// Error Handling:
|
|
248
|
+
inputCols = []
|
|
249
|
+
optCols = []
|
|
250
|
+
uColName = []
|
|
251
|
+
ySet = y ? true : false
|
|
252
|
+
xSet = x ? true : false
|
|
253
|
+
|
|
254
|
+
checkInputs(data) // check that dataset exists
|
|
255
|
+
|
|
256
|
+
// ---------------------------------------------------------------------------------------
|
|
257
|
+
// Get column information
|
|
258
|
+
// ---------------------------------------------------------------------------------------
|
|
259
|
+
// Get column summary:
|
|
260
|
+
columnSummary = getColumnSummary(data)
|
|
261
|
+
|
|
262
|
+
// Get column names:
|
|
263
|
+
columnNames = Object.keys(columnSummary)
|
|
264
|
+
|
|
265
|
+
// ---------------------------------------------------------------------------------------
|
|
266
|
+
// Make assumptions to complete required props
|
|
267
|
+
// ---------------------------------------------------------------------------------------
|
|
268
|
+
// If no x column was supplied, assume first column in dataset is x
|
|
269
|
+
if (!xSet) {
|
|
270
|
+
x = columnNames[0]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// If no y column(s) supplied, assume all number columns other than x are the y columns:
|
|
274
|
+
if (!ySet) {
|
|
275
|
+
uColNames = columnNames.filter(function (col) {
|
|
276
|
+
return ![x, series, size].includes(col)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
for (let i = 0; i < uColNames.length; i++) {
|
|
280
|
+
uColName = uColNames[i]
|
|
281
|
+
uColType = columnSummary[uColName].type
|
|
282
|
+
if (uColType === 'number') {
|
|
283
|
+
unusedColumns.push(uColName)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
y = unusedColumns.length > 1 ? unusedColumns : unusedColumns[0]
|
|
288
|
+
}
|
|
289
|
+
// Establish required columns based on chart type:
|
|
290
|
+
if (bubble) {
|
|
291
|
+
reqCols = {
|
|
292
|
+
x: x,
|
|
293
|
+
y: y,
|
|
294
|
+
size: size,
|
|
295
|
+
}
|
|
296
|
+
} else if (hist) {
|
|
297
|
+
reqCols = {
|
|
298
|
+
x: x,
|
|
299
|
+
}
|
|
300
|
+
} else if (boxplot) {
|
|
301
|
+
reqCols = {}
|
|
302
|
+
} else {
|
|
303
|
+
reqCols = {
|
|
304
|
+
x: x,
|
|
305
|
+
y: y,
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Check which columns were not supplied to the chart:
|
|
310
|
+
for (let property in reqCols) {
|
|
311
|
+
if (reqCols[property] == null) {
|
|
312
|
+
missingCols.push(property)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (missingCols.length === 1) {
|
|
317
|
+
throw Error(new Intl.ListFormat().format(missingCols) + ' is required')
|
|
318
|
+
} else if (missingCols.length > 1) {
|
|
319
|
+
throw Error(new Intl.ListFormat().format(missingCols) + ' are required')
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Fix for stacked100 overwriting y variable. Bandaid fix - not a long-term solution:
|
|
323
|
+
if (stacked100 === true && y.includes('_pct') && originalRun === false) {
|
|
324
|
+
if (typeof y === 'object') {
|
|
325
|
+
for (let i = 0; i < y.length; i++) {
|
|
326
|
+
y[i] = y[i].replace('_pct', '')
|
|
327
|
+
}
|
|
328
|
+
originalRun = false
|
|
329
|
+
} else {
|
|
330
|
+
y = y.replace('_pct', '')
|
|
331
|
+
originalRun = false
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Check the inputs supplied to the chart:
|
|
336
|
+
if (x) {
|
|
337
|
+
inputCols.push(x)
|
|
338
|
+
}
|
|
339
|
+
if (y) {
|
|
340
|
+
if (typeof y === 'object') {
|
|
341
|
+
for (i = 0; i < y.length; i++) {
|
|
342
|
+
inputCols.push(y[i])
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
inputCols.push(y)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (y2) {
|
|
349
|
+
if (typeof y2 === 'object') {
|
|
350
|
+
for (i = 0; i < y2.length; i++) {
|
|
351
|
+
inputCols.push(y2[i])
|
|
352
|
+
}
|
|
353
|
+
} else {
|
|
354
|
+
inputCols.push(y2)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (size) {
|
|
358
|
+
inputCols.push(size)
|
|
359
|
+
}
|
|
360
|
+
if (series) {
|
|
361
|
+
optCols.push(series)
|
|
362
|
+
}
|
|
363
|
+
if (tooltipTitle) {
|
|
364
|
+
optCols.push(tooltipTitle)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
checkInputs(data, inputCols, optCols)
|
|
368
|
+
|
|
369
|
+
// ---------------------------------------------------------------------------------------
|
|
370
|
+
// Aggregate Data if Required
|
|
371
|
+
// ---------------------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
if (stacked100 === true) {
|
|
374
|
+
data = getStackPercentages(data, x, y)
|
|
375
|
+
|
|
376
|
+
if (typeof y === 'object') {
|
|
377
|
+
for (let i = 0; i < y.length; i++) {
|
|
378
|
+
y[i] = y[i] + '_pct'
|
|
379
|
+
}
|
|
380
|
+
originalRun = false
|
|
381
|
+
} else {
|
|
382
|
+
y = y + '_pct'
|
|
383
|
+
originalRun = false
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Re-run column summary for new columns (not ideal):
|
|
387
|
+
columnSummary = getColumnSummary(data)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ---------------------------------------------------------------------------------------
|
|
391
|
+
// Define x axis type
|
|
392
|
+
// ---------------------------------------------------------------------------------------
|
|
393
|
+
xDataType = columnSummary[x].type
|
|
394
|
+
|
|
395
|
+
// Get xDataType into ECharts default types:
|
|
396
|
+
switch (xDataType) {
|
|
397
|
+
case 'number':
|
|
398
|
+
xDataType = 'value'
|
|
399
|
+
break
|
|
400
|
+
case 'string':
|
|
401
|
+
xDataType = 'category'
|
|
402
|
+
break
|
|
403
|
+
case 'date':
|
|
404
|
+
xDataType = 'time'
|
|
405
|
+
break
|
|
406
|
+
default:
|
|
407
|
+
break
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
xType = xType === 'category' ? 'category' : xDataType
|
|
411
|
+
|
|
412
|
+
// Set xAxisLabel overflow behaviour based on column type
|
|
413
|
+
if (!showAllXAxisLabels) {
|
|
414
|
+
// if user has not set showXAxisLabels
|
|
415
|
+
showAllXAxisLabels = xType === 'category'
|
|
416
|
+
} else {
|
|
417
|
+
// if user has set showXAxisLabels, convert to boolean
|
|
418
|
+
showAllXAxisLabels = showAllXAxisLabels === 'true' || showAllXAxisLabels === true
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Throw error if attempting to plot value or time on horizontal x-axis:
|
|
422
|
+
if (swapXY && xType !== 'category') {
|
|
423
|
+
throw Error(
|
|
424
|
+
'Horizontal charts do not support a value or time-based x-axis. You can either change your SQL query to output string values or set swapXY=false.',
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Throw error if attempting to plot secondary y-axis on horizontal chart:
|
|
429
|
+
if (swapXY && y2) {
|
|
430
|
+
throw Error(
|
|
431
|
+
'Horizontal charts do not support a secondary y-axis. You can either set swapXY=false or remove the y2 prop from your chart.',
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Override xType if axes are swapped - only category enabled on horizontal axis
|
|
436
|
+
if (swapXY) {
|
|
437
|
+
xType = 'category'
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Check for x mismatch:
|
|
441
|
+
xMismatch = xDataType === 'value' && xType === 'category'
|
|
442
|
+
|
|
443
|
+
// ---------------------------------------------------------------------------------------
|
|
444
|
+
// Sort data based on xType
|
|
445
|
+
// ---------------------------------------------------------------------------------------
|
|
446
|
+
if (sort) {
|
|
447
|
+
let sortColumn = xDataType === 'category' ? y : x
|
|
448
|
+
let sortAscending = xDataType !== 'category'
|
|
449
|
+
data = getSortedData(data, sortColumn, sortAscending)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Always sort time axes by x - this prevents the lines from being drawn out of order
|
|
453
|
+
if (xDataType === 'time') {
|
|
454
|
+
data = getSortedData(data, x, true)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ---------------------------------------------------------------------------------------
|
|
458
|
+
// Standardize date columns
|
|
459
|
+
// ---------------------------------------------------------------------------------------
|
|
460
|
+
|
|
461
|
+
columnSummaryArray = getColumnSummary(data, 'array')
|
|
462
|
+
dateCols = columnSummaryArray.filter((d) => d.type === 'date')
|
|
463
|
+
dateCols = dateCols.map((d) => d.id)
|
|
464
|
+
|
|
465
|
+
if (dateCols.length > 0) {
|
|
466
|
+
for (let i = 0; i < dateCols.length; i++) {
|
|
467
|
+
data = standardizeDateColumn(data, dateCols[i])
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ---------------------------------------------------------------------------------------
|
|
472
|
+
// Get format codes for axes
|
|
473
|
+
// ---------------------------------------------------------------------------------------
|
|
474
|
+
if (xFmt) {
|
|
475
|
+
xFormat = getFormatObjectFromString(xFmt, columnSummary[x].format?.valueType)
|
|
476
|
+
} else {
|
|
477
|
+
xFormat = columnSummary[x].format
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (!y) {
|
|
481
|
+
yFormat = 'str'
|
|
482
|
+
} else {
|
|
483
|
+
if (yFmt) {
|
|
484
|
+
if (typeof y === 'object') {
|
|
485
|
+
yFormat = getFormatObjectFromString(yFmt, columnSummary[y[0]].format?.valueType)
|
|
486
|
+
} else {
|
|
487
|
+
yFormat = getFormatObjectFromString(yFmt, columnSummary[y].format?.valueType)
|
|
488
|
+
}
|
|
489
|
+
} else {
|
|
490
|
+
if (typeof y === 'object') {
|
|
491
|
+
yFormat = columnSummary[y[0]].format
|
|
492
|
+
} else {
|
|
493
|
+
yFormat = columnSummary[y].format
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (y2) {
|
|
499
|
+
if (y2Fmt) {
|
|
500
|
+
if (typeof y2 === 'object') {
|
|
501
|
+
y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2[0]].format?.valueType)
|
|
502
|
+
} else {
|
|
503
|
+
y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2].format?.valueType)
|
|
504
|
+
}
|
|
505
|
+
} else {
|
|
506
|
+
if (typeof y2 === 'object') {
|
|
507
|
+
y2Format = columnSummary[y2[0]].format
|
|
508
|
+
} else {
|
|
509
|
+
y2Format = columnSummary[y2].format
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (size) {
|
|
515
|
+
if (sizeFmt) {
|
|
516
|
+
sizeFormat = getFormatObjectFromString(sizeFmt, columnSummary[size].format?.valueType)
|
|
517
|
+
} else {
|
|
518
|
+
sizeFormat = columnSummary[size].format
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
xUnitSummary = columnSummary[x].columnUnitSummary
|
|
523
|
+
|
|
524
|
+
if (y) {
|
|
525
|
+
if (typeof y === 'object') {
|
|
526
|
+
yUnitSummary = columnSummary[y[0]].columnUnitSummary
|
|
527
|
+
} else {
|
|
528
|
+
yUnitSummary = columnSummary[y].columnUnitSummary
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (y2) {
|
|
533
|
+
if (typeof y2 === 'object') {
|
|
534
|
+
y2UnitSummary = columnSummary[y2[0]].columnUnitSummary
|
|
535
|
+
} else {
|
|
536
|
+
y2UnitSummary = columnSummary[y2].columnUnitSummary
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (xAxisTitle === 'true') {
|
|
541
|
+
xAxisTitle = formatTitle(x, xFormat)
|
|
542
|
+
} else if (xAxisTitle === 'false') {
|
|
543
|
+
xAxisTitle = ''
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (yAxisTitle === 'true') {
|
|
547
|
+
yAxisTitle = typeof y === 'object' ? '' : formatTitle(y, yFormat)
|
|
548
|
+
} else if (yAxisTitle === 'false') {
|
|
549
|
+
yAxisTitle = ''
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (y2AxisTitle === 'true') {
|
|
553
|
+
y2AxisTitle = typeof y2 === 'object' ? '' : formatTitle(y2, y2Format)
|
|
554
|
+
} else if (y2AxisTitle === 'false') {
|
|
555
|
+
y2AxisTitle = ''
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// ---------------------------------------------------------------------------------------
|
|
559
|
+
// Get total series count
|
|
560
|
+
// ---------------------------------------------------------------------------------------
|
|
561
|
+
let yCount = typeof y === 'object' ? y.length : 1
|
|
562
|
+
let seriesCount = series ? getDistinctCount(data, series) : 1
|
|
563
|
+
let ySeriesCount = yCount * seriesCount
|
|
564
|
+
|
|
565
|
+
// y2Count may need to be adjusted to also factor in the series column. For now, we really
|
|
566
|
+
// only need to know that it's multi-series, so > 1 is sufficient
|
|
567
|
+
let y2Count = 0
|
|
568
|
+
if (typeof y2 === 'object') {
|
|
569
|
+
y2Count = y2.length
|
|
570
|
+
} else if (y2) {
|
|
571
|
+
y2Count = 1
|
|
572
|
+
}
|
|
573
|
+
let totalSeriesCount = ySeriesCount + y2Count
|
|
574
|
+
|
|
575
|
+
// ---------------------------------------------------------------------------------------
|
|
576
|
+
// Set legend flag
|
|
577
|
+
// ---------------------------------------------------------------------------------------
|
|
578
|
+
if (legend !== undefined) {
|
|
579
|
+
legend = legend === 'true' || legend === true
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
legend = legend ?? totalSeriesCount > 1
|
|
583
|
+
|
|
584
|
+
// ---------------------------------------------------------------------------------------
|
|
585
|
+
// Handle errors for log axes (cannot be used with stacked charts)
|
|
586
|
+
// ---------------------------------------------------------------------------------------
|
|
587
|
+
|
|
588
|
+
if (stacked100 === true && yLog === true) {
|
|
589
|
+
throw Error('Log axis cannot be used in a 100% stacked chart')
|
|
590
|
+
} else if (stackType === 'stacked' && totalSeriesCount > 1 && yLog === true) {
|
|
591
|
+
throw Error('Log axis cannot be used in a stacked chart')
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let minYValue
|
|
595
|
+
if (typeof y === 'object') {
|
|
596
|
+
minYValue = columnSummary[y[0]].columnUnitSummary.min
|
|
597
|
+
for (let i = 0; i < y.length; i++) {
|
|
598
|
+
if (columnSummary[y[i]].columnUnitSummary.min < minYValue) {
|
|
599
|
+
minYValue = columnSummary[y[i]].columnUnitSummary.min
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
} else if (y) {
|
|
603
|
+
minYValue = columnSummary[y].columnUnitSummary.min
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (yLog === true && minYValue <= 0 && minYValue !== null) {
|
|
607
|
+
throw Error('Log axis cannot display values less than or equal to zero')
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// ---------------------------------------------------------------------------------------
|
|
611
|
+
// Add props to store to let child components access them
|
|
612
|
+
// ---------------------------------------------------------------------------------------
|
|
613
|
+
props.update((d) => {
|
|
614
|
+
return {
|
|
615
|
+
...d,
|
|
616
|
+
data,
|
|
617
|
+
x,
|
|
618
|
+
y,
|
|
619
|
+
y2,
|
|
620
|
+
series,
|
|
621
|
+
swapXY,
|
|
622
|
+
sort,
|
|
623
|
+
xType,
|
|
624
|
+
xFormat,
|
|
625
|
+
yFormat,
|
|
626
|
+
y2Format,
|
|
627
|
+
sizeFormat,
|
|
628
|
+
xMismatch,
|
|
629
|
+
size,
|
|
630
|
+
yMin,
|
|
631
|
+
y2Min,
|
|
632
|
+
columnSummary,
|
|
633
|
+
xAxisTitle,
|
|
634
|
+
yAxisTitle,
|
|
635
|
+
y2AxisTitle,
|
|
636
|
+
tooltipTitle,
|
|
637
|
+
chartAreaHeight,
|
|
638
|
+
chartType,
|
|
639
|
+
yCount,
|
|
640
|
+
y2Count,
|
|
641
|
+
}
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
// ---------------------------------------------------------------------------------------
|
|
645
|
+
// Axis Configuration
|
|
646
|
+
// ---------------------------------------------------------------------------------------
|
|
647
|
+
xDistinct = getDistinctValues(data, x)
|
|
648
|
+
let secondaryAxis
|
|
649
|
+
|
|
650
|
+
if (swapXY) {
|
|
651
|
+
horizAxisConfig = {
|
|
652
|
+
type: yType,
|
|
653
|
+
logBase: yLogBase,
|
|
654
|
+
position: 'top',
|
|
655
|
+
axisLabel: {
|
|
656
|
+
show: yAxisLabels,
|
|
657
|
+
hideOverlap: true,
|
|
658
|
+
showMaxLabel: true,
|
|
659
|
+
formatter: function (value) {
|
|
660
|
+
return formatAxisValue(value, yFormat, yUnitSummary)
|
|
661
|
+
},
|
|
662
|
+
margin: 4,
|
|
663
|
+
},
|
|
664
|
+
min: yMin,
|
|
665
|
+
max: yMax,
|
|
666
|
+
scale: yScale,
|
|
667
|
+
splitLine: {
|
|
668
|
+
show: yGridlines,
|
|
669
|
+
},
|
|
670
|
+
axisLine: {
|
|
671
|
+
show: yBaseline,
|
|
672
|
+
onZero: false,
|
|
673
|
+
},
|
|
674
|
+
axisTick: {
|
|
675
|
+
show: yTickMarks,
|
|
676
|
+
},
|
|
677
|
+
boundaryGap: false,
|
|
678
|
+
z: 2,
|
|
679
|
+
}
|
|
680
|
+
} else {
|
|
681
|
+
horizAxisConfig = {
|
|
682
|
+
type: xType,
|
|
683
|
+
min: xMin,
|
|
684
|
+
max: xMax,
|
|
685
|
+
tooltip: {
|
|
686
|
+
show: true,
|
|
687
|
+
position: 'inside',
|
|
688
|
+
formatter (p) {
|
|
689
|
+
if (p.isTruncated()) {
|
|
690
|
+
return p.name
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
splitLine: {
|
|
695
|
+
show: xGridlines,
|
|
696
|
+
},
|
|
697
|
+
axisLine: {
|
|
698
|
+
show: xBaseline,
|
|
699
|
+
},
|
|
700
|
+
axisTick: {
|
|
701
|
+
show: xTickMarks,
|
|
702
|
+
},
|
|
703
|
+
axisLabel: {
|
|
704
|
+
show: xAxisLabels,
|
|
705
|
+
hideOverlap: true,
|
|
706
|
+
showMaxLabel: xType === 'category' || xType === 'value', // max label for ECharts' time axis is a stub - default for that is false
|
|
707
|
+
formatter:
|
|
708
|
+
xType === 'time' || xType === 'category'
|
|
709
|
+
? false
|
|
710
|
+
: function (value) {
|
|
711
|
+
return formatAxisValue(value, xFormat, xUnitSummary)
|
|
712
|
+
},
|
|
713
|
+
margin: 6,
|
|
714
|
+
},
|
|
715
|
+
scale: true,
|
|
716
|
+
z: 2,
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (swapXY) {
|
|
721
|
+
verticalAxisConfig = {
|
|
722
|
+
type: xType,
|
|
723
|
+
inverse: 'true',
|
|
724
|
+
splitLine: {
|
|
725
|
+
show: xGridlines,
|
|
726
|
+
},
|
|
727
|
+
axisLine: {
|
|
728
|
+
show: xBaseline,
|
|
729
|
+
},
|
|
730
|
+
axisTick: {
|
|
731
|
+
show: xTickMarks,
|
|
732
|
+
},
|
|
733
|
+
axisLabel: {
|
|
734
|
+
show: xAxisLabels,
|
|
735
|
+
hideOverlap: true,
|
|
736
|
+
// formatter:
|
|
737
|
+
// function(value){
|
|
738
|
+
// return formatAxisValue(value, xFormat, xUnitSummary)
|
|
739
|
+
// },
|
|
740
|
+
},
|
|
741
|
+
scale: true,
|
|
742
|
+
min: xMin,
|
|
743
|
+
max: xMax,
|
|
744
|
+
z: 2,
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
let primaryAxisColor = (() => {
|
|
748
|
+
if (!y2) return undefined
|
|
749
|
+
if ($yAxisColorStore === 'true') return $colorPaletteStore[0]
|
|
750
|
+
if ($yAxisColorStore === 'false') return undefined
|
|
751
|
+
return $yAxisColorStore
|
|
752
|
+
})()
|
|
753
|
+
let secondaryAxisColor = (() => {
|
|
754
|
+
if ($y2AxisColorStore === 'true') return $colorPaletteStore[ySeriesCount]
|
|
755
|
+
if ($y2AxisColorStore === 'false') return undefined
|
|
756
|
+
return $y2AxisColorStore
|
|
757
|
+
})()
|
|
758
|
+
|
|
759
|
+
verticalAxisConfig = {
|
|
760
|
+
type: yType,
|
|
761
|
+
logBase: yLogBase,
|
|
762
|
+
splitLine: {
|
|
763
|
+
show: yGridlines,
|
|
764
|
+
},
|
|
765
|
+
axisLine: {
|
|
766
|
+
show: yBaseline,
|
|
767
|
+
onZero: false,
|
|
768
|
+
},
|
|
769
|
+
axisTick: {
|
|
770
|
+
show: yTickMarks,
|
|
771
|
+
},
|
|
772
|
+
axisLabel: {
|
|
773
|
+
show: yAxisLabels,
|
|
774
|
+
hideOverlap: true,
|
|
775
|
+
margin: 4,
|
|
776
|
+
formatter: function (value) {
|
|
777
|
+
return formatAxisValue(value, yFormat, yUnitSummary)
|
|
778
|
+
},
|
|
779
|
+
color: primaryAxisColor,
|
|
780
|
+
},
|
|
781
|
+
name: yAxisTitle,
|
|
782
|
+
nameLocation: 'end',
|
|
783
|
+
nameTextStyle: {
|
|
784
|
+
align: 'left',
|
|
785
|
+
verticalAlign: 'top',
|
|
786
|
+
padding: [0, 5, 0, 0],
|
|
787
|
+
color: primaryAxisColor,
|
|
788
|
+
},
|
|
789
|
+
nameGap: 6,
|
|
790
|
+
min: yMin,
|
|
791
|
+
max: yMax,
|
|
792
|
+
scale: yScale,
|
|
793
|
+
boundaryGap: ['0%', '1%'],
|
|
794
|
+
z: 2,
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
secondaryAxis = {
|
|
798
|
+
type: 'value',
|
|
799
|
+
show: false,
|
|
800
|
+
alignTicks: true,
|
|
801
|
+
splitLine: {
|
|
802
|
+
show: y2Gridlines,
|
|
803
|
+
},
|
|
804
|
+
axisLine: {
|
|
805
|
+
show: y2Baseline,
|
|
806
|
+
onZero: false,
|
|
807
|
+
},
|
|
808
|
+
axisTick: {
|
|
809
|
+
show: y2TickMarks,
|
|
810
|
+
},
|
|
811
|
+
axisLabel: {
|
|
812
|
+
show: y2AxisLabels,
|
|
813
|
+
hideOverlap: true,
|
|
814
|
+
margin: 4,
|
|
815
|
+
formatter: function (value) {
|
|
816
|
+
return formatAxisValue(value, y2Format, y2UnitSummary)
|
|
817
|
+
},
|
|
818
|
+
color: secondaryAxisColor,
|
|
819
|
+
},
|
|
820
|
+
name: y2AxisTitle,
|
|
821
|
+
nameLocation: 'end',
|
|
822
|
+
nameTextStyle: {
|
|
823
|
+
align: 'right',
|
|
824
|
+
verticalAlign: 'top',
|
|
825
|
+
padding: [0, 0, 0, 5],
|
|
826
|
+
color: secondaryAxisColor,
|
|
827
|
+
},
|
|
828
|
+
nameGap: 6,
|
|
829
|
+
min: y2Min,
|
|
830
|
+
max: y2Max,
|
|
831
|
+
scale: y2Scale,
|
|
832
|
+
boundaryGap: ['0%', '1%'],
|
|
833
|
+
z: 2,
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
verticalAxisConfig = [verticalAxisConfig, secondaryAxis]
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// ---------------------------------------------------------------------------------------
|
|
840
|
+
// Set up chart area
|
|
841
|
+
// ---------------------------------------------------------------------------------------
|
|
842
|
+
|
|
843
|
+
if (chartAreaHeight) {
|
|
844
|
+
// if chartAreaHeight was user-supplied
|
|
845
|
+
chartAreaHeight = Number(chartAreaHeight)
|
|
846
|
+
if (isNaN(chartAreaHeight)) {
|
|
847
|
+
// input must be a number
|
|
848
|
+
throw Error('chartAreaHeight must be a number')
|
|
849
|
+
} else if (chartAreaHeight <= 0) {
|
|
850
|
+
throw Error('chartAreaHeight must be a positive number')
|
|
851
|
+
}
|
|
852
|
+
} else {
|
|
853
|
+
chartAreaHeight = 220
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
hasTitle = title ? true : false
|
|
857
|
+
hasSubtitle = subtitle ? true : false
|
|
858
|
+
hasLegend = legend * (series !== null || (typeof y === 'object' && y.length > 1))
|
|
859
|
+
hasTopAxisTitle = yAxisTitle !== '' && swapXY
|
|
860
|
+
hasBottomAxisTitle = xAxisTitle !== '' && !swapXY
|
|
861
|
+
|
|
862
|
+
titleFontSize = 15
|
|
863
|
+
subtitleFontSize = 13
|
|
864
|
+
titleBoxPadding = 6 * hasSubtitle
|
|
865
|
+
|
|
866
|
+
titleBoxHeight =
|
|
867
|
+
hasTitle * titleFontSize +
|
|
868
|
+
hasSubtitle * subtitleFontSize +
|
|
869
|
+
titleBoxPadding * Math.max(hasTitle, hasSubtitle)
|
|
870
|
+
|
|
871
|
+
chartAreaPaddingTop = 10
|
|
872
|
+
chartAreaPaddingBottom = 10
|
|
873
|
+
|
|
874
|
+
bottomAxisTitleSize = 14
|
|
875
|
+
topAxisTitleSize = 14 + 0 // font size + padding top
|
|
876
|
+
|
|
877
|
+
legendHeight = 15
|
|
878
|
+
legendHeight = legendHeight * hasLegend
|
|
879
|
+
|
|
880
|
+
legendPaddingTop = 7
|
|
881
|
+
legendPaddingTop = legendPaddingTop * Math.max(hasTitle, hasSubtitle)
|
|
882
|
+
|
|
883
|
+
legendTop = titleBoxHeight + legendPaddingTop
|
|
884
|
+
chartTop =
|
|
885
|
+
legendTop + legendHeight + topAxisTitleSize * hasTopAxisTitle + chartAreaPaddingTop
|
|
886
|
+
chartBottom = hasBottomAxisTitle * bottomAxisTitleSize + chartAreaPaddingBottom
|
|
887
|
+
|
|
888
|
+
// Adjustment to avoid small bars on horizontal bar chart (extend chart height to accomodate)
|
|
889
|
+
// Small bars are allowed on normal bar chart (e.g., time series bar chart)
|
|
890
|
+
maxBars = 8
|
|
891
|
+
heightMultiplier = 1
|
|
892
|
+
if (swapXY) {
|
|
893
|
+
barCount = xDistinct.length
|
|
894
|
+
heightMultiplier = Math.max(1, barCount / maxBars)
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
chartContainerHeight = chartAreaHeight * heightMultiplier + chartTop + chartBottom
|
|
898
|
+
|
|
899
|
+
topAxisTitleTop = legendTop + legendHeight + 7
|
|
900
|
+
|
|
901
|
+
// Set final chart height:
|
|
902
|
+
height = chartContainerHeight + 'px'
|
|
903
|
+
width = '100%'
|
|
904
|
+
|
|
905
|
+
// ---------------------------------------------------------------------------------------
|
|
906
|
+
// Set up horizontal axis title (custom graphic)
|
|
907
|
+
// ---------------------------------------------------------------------------------------
|
|
908
|
+
horizAxisTitle = swapXY ? yAxisTitle : xAxisTitle
|
|
909
|
+
if (horizAxisTitle !== '') {
|
|
910
|
+
horizAxisTitle = horizAxisTitle + ' →' // u2192 is js escaped version of →
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
horizAxisTitleConfig = {
|
|
914
|
+
id: 'horiz-axis-title',
|
|
915
|
+
type: 'text',
|
|
916
|
+
style: {
|
|
917
|
+
text: horizAxisTitle,
|
|
918
|
+
textAlign: 'right',
|
|
919
|
+
fill: $theme.colors['base-content-muted'],
|
|
920
|
+
},
|
|
921
|
+
cursor: 'auto',
|
|
922
|
+
// Positioning (if swapXY, top right; otherwise bottom right)
|
|
923
|
+
right: swapXY ? '2%' : '3%',
|
|
924
|
+
top: swapXY ? topAxisTitleTop : null,
|
|
925
|
+
bottom: swapXY ? null : '2%',
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// ---------------------------------------------------------------------------------------
|
|
929
|
+
// Build chart config and update config store so child components can access it
|
|
930
|
+
// ---------------------------------------------------------------------------------------
|
|
931
|
+
|
|
932
|
+
chartConfig = {
|
|
933
|
+
title: {
|
|
934
|
+
text: title,
|
|
935
|
+
subtext: subtitle,
|
|
936
|
+
subtextStyle: {
|
|
937
|
+
width: width,
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
tooltip: {
|
|
941
|
+
trigger: 'axis',
|
|
942
|
+
show: true,
|
|
943
|
+
// formatter function is overridden in ScatterPlot, BubbleChart, and Histogram
|
|
944
|
+
formatter: function (params) {
|
|
945
|
+
let output
|
|
946
|
+
let xVal
|
|
947
|
+
let yVal
|
|
948
|
+
let yCol
|
|
949
|
+
if (totalSeriesCount > 1) {
|
|
950
|
+
// If multi-series, add series name as title of tooltip
|
|
951
|
+
xVal = params[0].value[swapXY ? 1 : 0]
|
|
952
|
+
output = `<span id="tooltip" style='font-weight: 600;'>${formatValue(
|
|
953
|
+
xVal,
|
|
954
|
+
xFormat,
|
|
955
|
+
)}</span>`
|
|
956
|
+
for (let i = params.length - 1; i >= 0; i--) {
|
|
957
|
+
if (params[i].seriesName !== 'stackTotal') {
|
|
958
|
+
yVal = params[i].value[swapXY ? 0 : 1]
|
|
959
|
+
output =
|
|
960
|
+
output +
|
|
961
|
+
`<br> <span style='font-size: 11px;'>${params[i].marker} ${
|
|
962
|
+
params[i].seriesName
|
|
963
|
+
}<span/><span style='float:right; margin-left: 10px; font-size: 12px;'>${formatValue(
|
|
964
|
+
yVal,
|
|
965
|
+
// Not sure if this will work. Need to check with multi series on both axes
|
|
966
|
+
// Check if echarts does the order in the same way - y first, then y2
|
|
967
|
+
getYAxisIndex(params[i].componentIndex, yCount, y2Count) === 0
|
|
968
|
+
? yFormat
|
|
969
|
+
: y2Format,
|
|
970
|
+
)}</span>`
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
} else if (xType === 'value') {
|
|
974
|
+
// If single-series and a numerical x-axis, include x column as a normal column rather than title (so as not to show a number as the title)
|
|
975
|
+
xVal = params[0].value[swapXY ? 1 : 0]
|
|
976
|
+
yVal = params[0].value[swapXY ? 0 : 1]
|
|
977
|
+
yCol = params[0].seriesName
|
|
978
|
+
output = `<span id="tooltip" style='font-weight: 600;'>${formatTitle(
|
|
979
|
+
x,
|
|
980
|
+
xFormat,
|
|
981
|
+
)}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
|
|
982
|
+
xVal,
|
|
983
|
+
xFormat,
|
|
984
|
+
)}</span><br/><span style='font-weight: 600;'>${formatTitle(
|
|
985
|
+
yCol,
|
|
986
|
+
yFormat,
|
|
987
|
+
)}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
|
|
988
|
+
yVal,
|
|
989
|
+
yFormat,
|
|
990
|
+
)}</span>`
|
|
991
|
+
} else {
|
|
992
|
+
// If single series and categorical or date x-axis, use x value as title of tooltip
|
|
993
|
+
xVal = params[0].value[swapXY ? 1 : 0]
|
|
994
|
+
yVal = params[0].value[swapXY ? 0 : 1]
|
|
995
|
+
yCol = params[0].seriesName
|
|
996
|
+
output = `<span id="tooltip" style='font-weight: 600;'>${formatValue(
|
|
997
|
+
xVal,
|
|
998
|
+
xFormat,
|
|
999
|
+
)}</span><br/><span>${formatTitle(
|
|
1000
|
+
yCol,
|
|
1001
|
+
yFormat,
|
|
1002
|
+
)}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
|
|
1003
|
+
yVal,
|
|
1004
|
+
yFormat,
|
|
1005
|
+
)}</span>`
|
|
1006
|
+
}
|
|
1007
|
+
return output
|
|
1008
|
+
},
|
|
1009
|
+
confine: true,
|
|
1010
|
+
axisPointer: {
|
|
1011
|
+
// Use axis to trigger tooltip
|
|
1012
|
+
type: 'shadow', // 'shadow' as default; can also be 'line' or 'shadow'
|
|
1013
|
+
},
|
|
1014
|
+
extraCssText:
|
|
1015
|
+
'box-shadow: 0 3px 6px rgba(0,0,0,.15); box-shadow: 0 2px 4px rgba(0,0,0,.12); z-index: 1; font-feature-settings: "cv02", "tnum";',
|
|
1016
|
+
order: 'valueDesc',
|
|
1017
|
+
},
|
|
1018
|
+
legend: {
|
|
1019
|
+
show: legend,
|
|
1020
|
+
type: 'scroll',
|
|
1021
|
+
top: legendTop,
|
|
1022
|
+
padding: [0, 0, 0, 0],
|
|
1023
|
+
data: [],
|
|
1024
|
+
},
|
|
1025
|
+
grid: {
|
|
1026
|
+
left: leftPadding ?? (swapXY ? '1%' : '0.8%'),
|
|
1027
|
+
right: rightPadding ?? (swapXY ? '4%' : '3%'),
|
|
1028
|
+
bottom: chartBottom,
|
|
1029
|
+
top: chartTop,
|
|
1030
|
+
containLabel: true,
|
|
1031
|
+
},
|
|
1032
|
+
xAxis: horizAxisConfig,
|
|
1033
|
+
yAxis: verticalAxisConfig,
|
|
1034
|
+
series: [],
|
|
1035
|
+
animation: true,
|
|
1036
|
+
graphic: horizAxisTitleConfig,
|
|
1037
|
+
color: $colorPaletteStore,
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
config.update(() => {
|
|
1041
|
+
return chartConfig
|
|
1042
|
+
})
|
|
1043
|
+
} catch (e) {
|
|
1044
|
+
error = e.message
|
|
1045
|
+
let setTextRed = '\x1b[31m%s\x1b[0m'
|
|
1046
|
+
console.error(setTextRed, `Error in ${chartType}: ${e.message}`)
|
|
1047
|
+
props.update((d) => {
|
|
1048
|
+
return {...d, error}
|
|
1049
|
+
})
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
</script>
|
|
1053
|
+
|
|
1054
|
+
{#if !error}
|
|
1055
|
+
<slot />
|
|
1056
|
+
<ECharts
|
|
1057
|
+
config={$config}
|
|
1058
|
+
{height}
|
|
1059
|
+
{width}
|
|
1060
|
+
{data}
|
|
1061
|
+
{queryID}
|
|
1062
|
+
{echartsOptions}
|
|
1063
|
+
{seriesOptions}
|
|
1064
|
+
{connectGroup}
|
|
1065
|
+
{xAxisLabelOverflow}
|
|
1066
|
+
seriesColors={seriesColorsStore}
|
|
1067
|
+
/>
|
|
1068
|
+
{:else}
|
|
1069
|
+
<ErrorChart {error} title={chartType} />
|
|
1070
|
+
{/if}
|