1
0
Fork 0
mirror of synced 2024-08-07 22:28:15 +12:00

line chart

This commit is contained in:
Gerard Burns 2024-04-18 10:04:01 +01:00
parent 5751e92bbd
commit 441595dd6d
4 changed files with 112 additions and 108 deletions

View file

@ -1859,7 +1859,7 @@
"type": "select",
"label": "Colors",
"key": "palette",
"defaultValue": "Palette 1",
"defaultValue": "palette1",
"options": [
{ "label": "Custom", "value": "Custom" },
{ "label": "Palette 1", "value": "palette1" },

View file

@ -16,6 +16,9 @@
let chart;
const updateChart = async (newOptions) => {
// Line charts won't transition from category to datetime types properly without
// calling this with an empty object first; I don't know why this works.
await chart?.updateOptions({})
await chart?.updateOptions(newOptions)
}

View file

@ -33,7 +33,6 @@
$: labelType = dataProvider?.schema?.[labelColumn]?.type === 'datetime' ?
"datetime" : "category"
$: formatter = getFormatter(labelType, valueUnits)
$: xAxisFormatter = getFormatter(labelType, valueUnits, horizontal, "x")
$: yAxisFormatter = getFormatter(labelType, valueUnits, horizontal, "y")

View file

@ -16,7 +16,7 @@
export let dataLabels
export let curve
export let legend
export let yAxisUnits
export let valueUnits
export let palette
export let c1, c2, c3, c4, c5
@ -25,122 +25,124 @@
export let stacked
export let gradient
$: options = setUpChart(
title,
dataProvider,
labelColumn,
valueColumns,
xAxisLabel,
yAxisLabel,
height,
width,
animate,
dataLabels,
curve,
legend,
yAxisUnits,
palette,
area,
stacked,
gradient,
c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null,
customColor
)
$: {
console.log(palette);
}
$: customColor = palette === "Custom"
const formatters = {
["Default"]: val => val,
["Thousands"]: val => `${Math.round(val / 1000)}K`,
["Millions"]: val => `${Math.round(val / 1000000)}M`,
["Datetime"]: val => (new Date(val)).toLocaleString()
}
const setUpChart = (
title,
dataProvider,
labelColumn,
valueColumns,
xAxisLabel,
yAxisLabel,
height,
width,
animate,
dataLabels,
curve,
legend,
yAxisUnits,
palette,
area,
stacked,
gradient,
colors,
customColor
) => {
const allCols = [labelColumn, ...(valueColumns || [null])]
if (
!dataProvider ||
!dataProvider.rows?.length ||
allCols.find(x => x == null)
) {
return null
$: series = getSeries(dataProvider, valueColumns)
$: categories = getCategories(dataProvider, labelColumn);
$: labelType = dataProvider?.schema?.[labelColumn]?.type === 'datetime' ?
"datetime" : "category"
$: xAxisFormatter = getFormatter(labelType, valueUnits, "x")
$: yAxisFormatter = getFormatter(labelType, valueUnits, "y")
$: options = {
series,
stroke: {
curve: curve.toLowerCase()
},
colors: palette === "Custom" ? [c1, c2, c3, c4, c5] : [],
theme: {
palette: palette === "Custom" ? null : palette
},
legend: {
show: legend,
position: "top",
horizontalAlign: "right",
showForSingleSeries: true,
showForNullSeries: true,
showForZeroSeries: true,
},
title: {
text: title,
},
dataLabels: {
enabled: dataLabels
},
chart: {
height: height == null || height === "" ? "auto" : height,
width: width == null || width === "" ? "100%" : width,
type: "line",
stacked,
animations: {
enabled: animate
},
toolbar: {
show: false,
},
zoom: {
enabled: false,
},
},
xaxis: {
type: labelType,
categories,
labels: {
formatter: xAxisFormatter
},
title: {
text: xAxisLabel
}
},
yaxis: {
labels: {
formatter: yAxisFormatter
},
title: {
text: yAxisLabel
}
}
}
// Fetch, filter and sort data
const { schema, rows } = dataProvider
const data = rows
if (!schema || !data.length) {
return null
}
const getSeries = (datasource, valueColumns = []) => {
const rows = datasource.rows ?? [];
// Initialise default chart
let builder = new ApexOptionsBuilder()
.title(title)
.type(area ? "area" : "line")
.width(width)
.height(height)
.xLabel(xAxisLabel)
.yLabel(yAxisLabel)
.dataLabels(dataLabels)
.animate(animate)
.curve(curve.toLowerCase())
.gradient(gradient)
.stacked(stacked)
.legend(legend)
.yUnits(yAxisUnits)
.palette(palette)
.colors(customColor ? colors : null)
// Add data
let useDates = false
if (schema[labelColumn]) {
const labelFieldType = schema[labelColumn].type
builder = builder.xType(labelFieldType)
useDates = labelFieldType === "datetime"
}
const series = (valueColumns ?? []).map(column => ({
return valueColumns.map(column => ({
name: column,
data: data.map(row => {
if (!useDates) {
const value = get(row, column);
if (Array.isArray(value)) {
return null;
}
if (Number.isNaN(parseInt(value, 10))) {
return null;
}
return value;
} else {
return [row[labelColumn], row[column]]
}
data: rows.map(row => {
return row?.[column]
}),
}))
builder = builder.series(series)
if (!useDates) {
builder = builder.xCategories(data.map(row => row[labelColumn]))
} else {
builder = builder.clearXFormatter()
}
const getCategories = (datasource, labelColumn) => {
const rows = datasource.rows ?? [];
return rows.map(row => {
const value = row?.[labelColumn]
// If a nullish or non-scalar type, replace it with an empty string
if (!["string", "number", "boolean"].includes(typeof value)) {
return ""
}
return value;
})
}
const getFormatter = (labelType, valueUnits, axis) => {
const isLabelAxis = axis === "x"
if (labelType === "datetime" && isLabelAxis) {
return formatters["Datetime"]
}
// Build chart options
return builder.getOptions()
if (isLabelAxis) {
return formatters["Default"]
}
return formatters[valueUnits]
}
$: console.log("opt", options);
</script>
<ApexChart {options} />