Add line chart and enable multiple data series for all charts

This commit is contained in:
Andrew Kingston 2020-11-03 09:43:45 +00:00
parent b0ee6d4ed3
commit 4f5d12468d
7 changed files with 287 additions and 229 deletions

View File

@ -1,5 +1,6 @@
import Input from "./PropertyPanelControls/Input.svelte" import Input from "./PropertyPanelControls/Input.svelte"
import OptionSelect from "./OptionSelect.svelte" import OptionSelect from "./OptionSelect.svelte"
import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte"
import Checkbox from "../common/Checkbox.svelte" import Checkbox from "../common/Checkbox.svelte"
import TableSelect from "components/userInterface/TableSelect.svelte" import TableSelect from "components/userInterface/TableSelect.svelte"
import TableViewSelect from "components/userInterface/TableViewSelect.svelte" import TableViewSelect from "components/userInterface/TableViewSelect.svelte"
@ -523,6 +524,11 @@ export default {
icon: "ri-bar-chart-fill", icon: "ri-bar-chart-fill",
properties: { properties: {
settings: [ settings: [
{
label: "Title",
key: "title",
control: Input,
},
{ {
label: "Data", label: "Data",
key: "datasource", key: "datasource",
@ -530,15 +536,15 @@ export default {
}, },
{ {
label: "Label Col.", label: "Label Col.",
key: "nameLabel", key: "labelColumn",
dependsOn: "datasource", dependsOn: "datasource",
control: TableViewFieldSelect, control: TableViewFieldSelect,
}, },
{ {
label: "Value Col.", label: "Data Cols.",
key: "valueLabel", key: "valueColumns",
dependsOn: "datasource", dependsOn: "datasource",
control: TableViewFieldSelect, control: MultiTableViewFieldSelect,
}, },
{ {
label: "Y Axis Label", label: "Y Axis Label",
@ -550,12 +556,12 @@ export default {
key: "xAxisLabel", key: "xAxisLabel",
control: Input, control: Input,
}, },
{ // {
label: "Color", // label: "Color",
key: "color", // key: "color",
control: Colorpicker, // control: Colorpicker,
defaultValue: "#4285f4", // defaultValue: "#4285f4",
}, // },
{ {
label: "Width", label: "Width",
key: "width", key: "width",
@ -587,6 +593,13 @@ export default {
valueKey: "checked", valueKey: "checked",
defaultValue: true, defaultValue: true,
}, },
{
label: "Legend",
key: "legend",
control: Checkbox,
valueKey: "checked",
defaultValue: false,
},
], ],
}, },
}, },
@ -693,172 +706,100 @@ export default {
// ], // ],
// }, // },
// }, // },
// { {
// name: "Line", name: "Line",
// _component: "@budibase/standard-components/line", _component: "@budibase/standard-components/line",
// description: "Line chart", description: "Line chart",
// icon: "ri-line-chart-line", icon: "ri-line-chart-line",
// properties: { properties: {
// settings: [ settings: [
// { {
// label: "Data", label: "Title",
// key: "datasource", key: "title",
// control: TableViewSelect, control: Input,
// }, },
// { {
// label: "Value Label", label: "Data",
// key: "valueLabel", key: "datasource",
// dependsOn: "datasource", control: TableViewSelect,
// control: TableViewFieldSelect, },
// }, {
// { label: "Label Col.",
// label: "Topic Label", key: "labelColumn",
// key: "topicLabel", dependsOn: "datasource",
// dependsOn: "datasource", control: TableViewFieldSelect,
// control: TableViewFieldSelect, },
// }, {
// { label: "Data Cols.",
// label: "Date Label", key: "valueColumns",
// key: "dateLabel", dependsOn: "datasource",
// dependsOn: "datasource", control: MultiTableViewFieldSelect,
// control: TableViewFieldSelect, },
// }, {
// { label: "Y Axis Label",
// label: "Colors", key: "yAxisLabel",
// key: "color", control: Input,
// control: OptionSelect, },
// options: [ {
// "britecharts", label: "X Axis Label",
// "blueGreen", key: "xAxisLabel",
// "green", control: Input,
// "grey", },
// "orange", // {
// "pink", // label: "Color",
// "purple", // key: "color",
// "red", // control: Colorpicker,
// "teal", // defaultValue: "#4285f4",
// "yellow", // },
// ], {
// }, label: "Width",
// { key: "width",
// label: "Gradients", control: Input,
// key: "lineGradient", },
// control: OptionSelect, {
// options: [ label: "Height",
// { value: "", label: "None" }, key: "height",
// { value: "bluePurple", label: "Blue Purple" }, control: Input,
// { value: "greenBlue", label: "Green Blue" }, defaultValue: "400",
// { value: "orangePink", label: "Orange Pink" }, },
// ], {
// }, label: "Curve",
// { key: "curve",
// label: "Line Curve", control: OptionSelect,
// key: "lineCurve", options: ["Smooth", "Straight", "Stepline"],
// control: OptionSelect, defaultValue: "Smooth",
// options: [ },
// "linear", {
// "basis", label: "Data Labels",
// "natural", key: "dataLabels",
// "monotoneX", control: Checkbox,
// "monotoneY", valueKey: "checked",
// "step", defaultValue: false,
// "stepAfter", },
// "stepBefore", {
// "cardinal", label: "Animate",
// "catmullRom", key: "animate",
// ], control: Checkbox,
// }, valueKey: "checked",
// { defaultValue: true,
// label: "X Axis Value Type", },
// key: "xAxisValueType", {
// control: OptionSelect, label: "Fill",
// options: ["date", "number"], key: "fill",
// }, control: Checkbox,
// { valueKey: "checked",
// label: "Grid", defaultValue: true,
// key: "grid", },
// control: OptionSelect, {
// options: ["vertical", "horizontal", "full"], label: "Legend",
// }, key: "legend",
// { control: Checkbox,
// label: "X Axis Label", valueKey: "checked",
// key: "xAxisLabel", defaultValue: false,
// control: Input, },
// }, ],
// { },
// label: "Y Axis Label", },
// key: "yAxisLabel",
// control: Input,
// },
// {
// label: "Show All Datapoints",
// key: "shouldShowAllDataPoints",
// valueKey: "checked",
// control: Checkbox,
// },
// {
// label: "Width",
// key: "width",
// control: Input,
// },
// {
// label: "Height",
// key: "height",
// control: Input,
// },
// {
// label: "Is Animated",
// key: "isAnimated",
// control: Checkbox,
// valueKey: "checked",
// },
// {
// label: "Locale",
// key: "locale",
// control: OptionSelect,
// options: ["en-GB", "en-US"],
// },
// {
// label: "X Axis Value Type",
// key: "xAxisValueType",
// control: OptionSelect,
// options: ["date", "numeric"],
// },
// {
// label: "X Axis Format",
// key: "xAxisFormat",
// control: OptionSelect,
// options: [
// "day-month",
// "minute-hour",
// "hour-daymonth",
// "month-year",
// "custom",
// ],
// },
// {
// label: "X Axis Custom Format",
// key: "xAxisCustomFormat",
// control: Input,
// },
// {
// label: "Tooltip Title",
// key: "tooltipTitle",
// control: Input,
// },
// {
// label: "X Ticks",
// key: "xTicks",
// control: Input,
// },
// {
// label: "Y Ticks",
// key: "yTicks",
// control: Input,
// },
// ],
// },
// },
], ],
}, },
{ {

View File

@ -549,9 +549,10 @@
"description": "Bar Chart", "description": "Bar Chart",
"data": true, "data": true,
"props": { "props": {
"title": "string",
"datasource": "tables", "datasource": "tables",
"nameLabel": "string", "labelColumn": "string",
"valueLabel": "string", "valueColumns": "string",
"color": { "color": {
"type": "string", "type": "string",
"default": "#4285f4" "default": "#4285f4"
@ -571,52 +572,57 @@
"default": true "default": true
}, },
"xAxisLabel": "string", "xAxisLabel": "string",
"yAxisLabel": "string" "yAxisLabel": "string",
"legend": {
"type": "bool",
"default": false
}
} }
}, },
"line": { "line": {
"description": "Line Chart", "description": "Line Chart",
"data": true, "data": true,
"props": { "props": {
"title": "string",
"datasource": "tables", "datasource": "tables",
"labelColumn": "string",
"valueColumns": "string",
"color": {
"type": "string",
"default": "#4285f4"
},
"height": {
"type": "number",
"default": "400"
},
"width": "number", "width": "number",
"height": "number", "dataLabels": {
"axisTimeCombinations": "string", "type": "bool",
"color": "string", "default": false
"grid": {
"type": "string",
"default": "horizontal"
}, },
"aspectRatio": "number", "animate": {
"dateLabel": "string",
"isAnimated": {
"type": "bool", "type": "bool",
"default": true "default": true
}, },
"lineCurve": "string",
"locale": "string",
"numberFormat": "string",
"shouldShowAllDataPoints": {
"type": "bool",
"default": true
},
"topicLabel": "string",
"valueLabel": "string",
"xAxisValueType": {
"type": "string",
"default": "date"
},
"xAxisScale": "string",
"xAxisFormat": {
"type": "string",
"default": "custom"
},
"xAxisCustomFormat": "string",
"xAxisLabel": "string", "xAxisLabel": "string",
"yAxisLabel": "string", "yAxisLabel": "string",
"tooltipTitle": "string", "curve": {
"xTicks": "number", "type": "options",
"yTicks": "number" "options": [
"Smooth",
"Straight",
"Stepline"
],
"default": "Smooth"
},
"fill": {
"type": "bool",
"default": true
},
"legend": {
"type": "bool",
"default": false
}
} }
}, },
"brush": { "brush": {

View File

@ -5,7 +5,7 @@ import postcss from "rollup-plugin-postcss"
import { terser } from "rollup-plugin-terser" import { terser } from "rollup-plugin-terser"
const production = !process.env.ROLLUP_WATCH const production = !process.env.ROLLUP_WATCH
const lodash_fp_exports = ["isEmpty"] const lodash_fp_exports = ["isEmpty", "sortBy"]
export default { export default {
input: "src/index.js", input: "src/index.js",

View File

@ -1,6 +1,19 @@
export class ApexOptionsBuilder { export class ApexOptionsBuilder {
options = { options = {
series: [], series: [],
legend: {
show: false,
position: "top",
horizontalAlign: "right",
showForSingleSeries: true,
showForNullSeries: true,
showForZeroSeries: true,
},
chart: {
toolbar: {
show: false,
},
},
} }
setOption(path, value) { setOption(path, value) {
@ -27,8 +40,12 @@ export class ApexOptionsBuilder {
return this.setOption(["chart", "type"], type) return this.setOption(["chart", "type"], type)
} }
title(title) {
return this.setOption(["title", "text"], title)
}
color(color) { color(color) {
return this.setOption(["colors"], color) return this.setOption(["colors"], [color])
} }
width(width) { width(width) {
@ -66,4 +83,25 @@ export class ApexOptionsBuilder {
animate(animate) { animate(animate) {
return this.setOption(["chart", "animations", "enabled"], animate) return this.setOption(["chart", "animations", "enabled"], animate)
} }
curve(curve) {
return this.setOption(["stroke", "curve"], curve)
}
gradient(gradient) {
const fill = {
type: "gradient",
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.9,
stops: [0, 90, 100],
},
}
return this.setOption(["fill"], gradient ? fill : undefined)
}
legend(legend) {
return this.setOption(["legend", "show"], legend)
}
} }

View File

@ -2,12 +2,13 @@
import { onMount } from "svelte" import { onMount } from "svelte"
import { chart } from "svelte-apexcharts" import { chart } from "svelte-apexcharts"
import fetchData from "../fetchData" import fetchData from "../fetchData"
import { isEmpty } from "lodash/fp" import { isEmpty, sortBy } from "lodash/fp"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder" import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
export let title
export let datasource export let datasource
export let nameLabel export let labelColumn
export let valueLabel export let valueColumns
export let xAxisLabel export let xAxisLabel
export let yAxisLabel export let yAxisLabel
export let height export let height
@ -16,6 +17,7 @@
export let horizontal export let horizontal
export let dataLabels export let dataLabels
export let animate export let animate
export let legend
let data let data
$: options = getChartOptions(data) $: options = getChartOptions(data)
@ -23,15 +25,16 @@
// Fetch data on mount // Fetch data on mount
onMount(async () => { onMount(async () => {
if (!isEmpty(datasource)) { if (!isEmpty(datasource)) {
data = await fetchData(datasource) const result = (await fetchData(datasource)).slice(0, 20)
data = sortBy(row => row[labelColumn])(result)
} }
}) })
function getChartOptions(rows = []) { function getChartOptions(rows = []) {
// Initialise default chart // Initialise default chart
let builder = new ApexOptionsBuilder() let builder = new ApexOptionsBuilder()
.title(title)
.type("bar") .type("bar")
.color(color)
.width(width) .width(width)
.height(height) .height(height)
.xLabel(xAxisLabel) .xLabel(xAxisLabel)
@ -39,20 +42,19 @@
.horizontal(horizontal) .horizontal(horizontal)
.dataLabels(dataLabels) .dataLabels(dataLabels)
.animate(animate) .animate(animate)
.legend(legend)
// Add data if valid datasource // Add data if valid datasource
if (rows && rows.length) { if (rows && rows.length) {
rows = rows.slice(0, 50) if (valueColumns && valueColumns.length) {
if (!isEmpty(nameLabel) && !isNaN(rows[0][valueLabel])) { const series = valueColumns.map(column => ({
builder = builder.series([ name: column,
{ data: rows.map(row => parseFloat(row[column])),
name: valueLabel, }))
data: rows.map(row => row[valueLabel]), builder = builder.series(series)
},
])
} }
if (!isEmpty(nameLabel)) { if (!isEmpty(rows[0][labelColumn])) {
builder = builder.categories(rows.map(row => row[nameLabel])) builder = builder.categories(rows.map(row => row[labelColumn]))
} }
} }

View File

@ -0,0 +1,71 @@
<script>
import { onMount } from "svelte"
import { chart } from "svelte-apexcharts"
import fetchData from "../fetchData"
import { isEmpty, sortBy } from "lodash/fp"
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
export let title
export let datasource
export let labelColumn
export let valueColumns
export let xAxisLabel
export let yAxisLabel
export let height
export let width
export let color
export let animate
export let dataLabels
export let curve
export let fill
export let legend
let data = []
$: options = getChartOptions(data)
// Fetch data on mount
onMount(async () => {
if (!isEmpty(datasource)) {
const result = (await fetchData(datasource)).slice(0, 20)
data = sortBy(row => row[labelColumn])(result)
}
})
function getChartOptions(rows = []) {
// Initialise default chart
let builder = new ApexOptionsBuilder()
.title(title)
.type(fill ? "area" : "line")
// .color(color)
.width(width)
.height(height)
.xLabel(xAxisLabel)
.yLabel(yAxisLabel)
.dataLabels(dataLabels)
.animate(animate)
.curve(curve.toLowerCase())
.gradient(fill)
.legend(legend)
// Add data if valid datasource
if (rows && rows.length) {
if (valueColumns && valueColumns.length) {
const series = valueColumns.map(column => ({
name: column,
data: rows.map(row => parseFloat(row[column])),
}))
builder = builder.series(series)
}
if (!isEmpty(rows[0][labelColumn])) {
builder = builder.categories(rows.map(row => row[labelColumn]))
}
}
// Build chart options
return builder.getOptions()
}
$: console.log(options)
</script>
<div use:chart={options} />

View File

@ -1,2 +1,2 @@
export { default as bar } from "./Bar.svelte" export { default as bar } from "./BarChart.svelte"
export { default as line } from "./Line.svelte" export { default as line } from "./LineChart.svelte"