From 0ea30587de22f0ad4cf2b32504d27e4f241e7cba Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 3 Nov 2020 09:43:45 +0000 Subject: [PATCH] Add line chart and enable multiple data series for all charts --- .../userInterface/temporaryPanelStructure.js | 293 +++++++----------- packages/standard-components/components.json | 74 +++-- packages/standard-components/rollup.config.js | 2 +- .../src/Chart/ApexOptionsBuilder.js | 40 ++- .../src/Chart/{Bar.svelte => BarChart.svelte} | 32 +- .../src/Chart/LineChart.svelte | 71 +++++ .../standard-components/src/Chart/index.js | 4 +- 7 files changed, 287 insertions(+), 229 deletions(-) rename packages/standard-components/src/Chart/{Bar.svelte => BarChart.svelte} (59%) create mode 100644 packages/standard-components/src/Chart/LineChart.svelte diff --git a/packages/builder/src/components/userInterface/temporaryPanelStructure.js b/packages/builder/src/components/userInterface/temporaryPanelStructure.js index 2c8c50a0cb..05925b9b61 100644 --- a/packages/builder/src/components/userInterface/temporaryPanelStructure.js +++ b/packages/builder/src/components/userInterface/temporaryPanelStructure.js @@ -1,5 +1,6 @@ import Input from "./PropertyPanelControls/Input.svelte" import OptionSelect from "./OptionSelect.svelte" +import MultiTableViewFieldSelect from "./MultiTableViewFieldSelect.svelte" import Checkbox from "../common/Checkbox.svelte" import TableSelect from "components/userInterface/TableSelect.svelte" import TableViewSelect from "components/userInterface/TableViewSelect.svelte" @@ -523,6 +524,11 @@ export default { icon: "ri-bar-chart-fill", properties: { settings: [ + { + label: "Title", + key: "title", + control: Input, + }, { label: "Data", key: "datasource", @@ -530,15 +536,15 @@ export default { }, { label: "Label Col.", - key: "nameLabel", + key: "labelColumn", dependsOn: "datasource", control: TableViewFieldSelect, }, { - label: "Value Col.", - key: "valueLabel", + label: "Data Cols.", + key: "valueColumns", dependsOn: "datasource", - control: TableViewFieldSelect, + control: MultiTableViewFieldSelect, }, { label: "Y Axis Label", @@ -550,12 +556,12 @@ export default { key: "xAxisLabel", control: Input, }, - { - label: "Color", - key: "color", - control: Colorpicker, - defaultValue: "#4285f4", - }, + // { + // label: "Color", + // key: "color", + // control: Colorpicker, + // defaultValue: "#4285f4", + // }, { label: "Width", key: "width", @@ -587,6 +593,13 @@ export default { valueKey: "checked", defaultValue: true, }, + { + label: "Legend", + key: "legend", + control: Checkbox, + valueKey: "checked", + defaultValue: false, + }, ], }, }, @@ -693,172 +706,100 @@ export default { // ], // }, // }, - // { - // name: "Line", - // _component: "@budibase/standard-components/line", - // description: "Line chart", - // icon: "ri-line-chart-line", - // properties: { - // settings: [ - // { - // label: "Data", - // key: "datasource", - // control: TableViewSelect, - // }, - // { - // label: "Value Label", - // key: "valueLabel", - // dependsOn: "datasource", - // control: TableViewFieldSelect, - // }, - // { - // label: "Topic Label", - // key: "topicLabel", - // dependsOn: "datasource", - // control: TableViewFieldSelect, - // }, - // { - // label: "Date Label", - // key: "dateLabel", - // dependsOn: "datasource", - // control: TableViewFieldSelect, - // }, - // { - // label: "Colors", - // key: "color", - // control: OptionSelect, - // options: [ - // "britecharts", - // "blueGreen", - // "green", - // "grey", - // "orange", - // "pink", - // "purple", - // "red", - // "teal", - // "yellow", - // ], - // }, - // { - // label: "Gradients", - // key: "lineGradient", - // control: OptionSelect, - // options: [ - // { value: "", label: "None" }, - // { value: "bluePurple", label: "Blue Purple" }, - // { value: "greenBlue", label: "Green Blue" }, - // { value: "orangePink", label: "Orange Pink" }, - // ], - // }, - // { - // label: "Line Curve", - // key: "lineCurve", - // control: OptionSelect, - // options: [ - // "linear", - // "basis", - // "natural", - // "monotoneX", - // "monotoneY", - // "step", - // "stepAfter", - // "stepBefore", - // "cardinal", - // "catmullRom", - // ], - // }, - // { - // label: "X Axis Value Type", - // key: "xAxisValueType", - // control: OptionSelect, - // options: ["date", "number"], - // }, - // { - // label: "Grid", - // key: "grid", - // control: OptionSelect, - // options: ["vertical", "horizontal", "full"], - // }, - // { - // label: "X Axis Label", - // key: "xAxisLabel", - // 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, - // }, - // ], - // }, - // }, + { + name: "Line", + _component: "@budibase/standard-components/line", + description: "Line chart", + icon: "ri-line-chart-line", + properties: { + settings: [ + { + label: "Title", + key: "title", + control: Input, + }, + { + label: "Data", + key: "datasource", + control: TableViewSelect, + }, + { + label: "Label Col.", + key: "labelColumn", + dependsOn: "datasource", + control: TableViewFieldSelect, + }, + { + label: "Data Cols.", + key: "valueColumns", + dependsOn: "datasource", + control: MultiTableViewFieldSelect, + }, + { + label: "Y Axis Label", + key: "yAxisLabel", + control: Input, + }, + { + label: "X Axis Label", + key: "xAxisLabel", + control: Input, + }, + // { + // label: "Color", + // key: "color", + // control: Colorpicker, + // defaultValue: "#4285f4", + // }, + { + label: "Width", + key: "width", + control: Input, + }, + { + label: "Height", + key: "height", + control: Input, + defaultValue: "400", + }, + { + label: "Curve", + key: "curve", + control: OptionSelect, + options: ["Smooth", "Straight", "Stepline"], + defaultValue: "Smooth", + }, + { + label: "Data Labels", + key: "dataLabels", + control: Checkbox, + valueKey: "checked", + defaultValue: false, + }, + { + label: "Animate", + key: "animate", + control: Checkbox, + valueKey: "checked", + defaultValue: true, + }, + { + label: "Fill", + key: "fill", + control: Checkbox, + valueKey: "checked", + defaultValue: true, + }, + { + label: "Legend", + key: "legend", + control: Checkbox, + valueKey: "checked", + defaultValue: false, + }, + ], + }, + }, ], }, { diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index f63ce9d56b..5a93ef2c2f 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -549,9 +549,10 @@ "description": "Bar Chart", "data": true, "props": { + "title": "string", "datasource": "tables", - "nameLabel": "string", - "valueLabel": "string", + "labelColumn": "string", + "valueColumns": "string", "color": { "type": "string", "default": "#4285f4" @@ -571,52 +572,57 @@ "default": true }, "xAxisLabel": "string", - "yAxisLabel": "string" + "yAxisLabel": "string", + "legend": { + "type": "bool", + "default": false + } } }, "line": { "description": "Line Chart", "data": true, "props": { + "title": "string", "datasource": "tables", + "labelColumn": "string", + "valueColumns": "string", + "color": { + "type": "string", + "default": "#4285f4" + }, + "height": { + "type": "number", + "default": "400" + }, "width": "number", - "height": "number", - "axisTimeCombinations": "string", - "color": "string", - "grid": { - "type": "string", - "default": "horizontal" + "dataLabels": { + "type": "bool", + "default": false }, - "aspectRatio": "number", - "dateLabel": "string", - "isAnimated": { + "animate": { "type": "bool", "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", "yAxisLabel": "string", - "tooltipTitle": "string", - "xTicks": "number", - "yTicks": "number" + "curve": { + "type": "options", + "options": [ + "Smooth", + "Straight", + "Stepline" + ], + "default": "Smooth" + }, + "fill": { + "type": "bool", + "default": true + }, + "legend": { + "type": "bool", + "default": false + } } }, "brush": { diff --git a/packages/standard-components/rollup.config.js b/packages/standard-components/rollup.config.js index 202adde702..1948fca8f5 100644 --- a/packages/standard-components/rollup.config.js +++ b/packages/standard-components/rollup.config.js @@ -5,7 +5,7 @@ import postcss from "rollup-plugin-postcss" import { terser } from "rollup-plugin-terser" const production = !process.env.ROLLUP_WATCH -const lodash_fp_exports = ["isEmpty"] +const lodash_fp_exports = ["isEmpty", "sortBy"] export default { input: "src/index.js", diff --git a/packages/standard-components/src/Chart/ApexOptionsBuilder.js b/packages/standard-components/src/Chart/ApexOptionsBuilder.js index 4fb66e90f6..30723f0b28 100644 --- a/packages/standard-components/src/Chart/ApexOptionsBuilder.js +++ b/packages/standard-components/src/Chart/ApexOptionsBuilder.js @@ -1,6 +1,19 @@ export class ApexOptionsBuilder { options = { series: [], + legend: { + show: false, + position: "top", + horizontalAlign: "right", + showForSingleSeries: true, + showForNullSeries: true, + showForZeroSeries: true, + }, + chart: { + toolbar: { + show: false, + }, + }, } setOption(path, value) { @@ -27,8 +40,12 @@ export class ApexOptionsBuilder { return this.setOption(["chart", "type"], type) } + title(title) { + return this.setOption(["title", "text"], title) + } + color(color) { - return this.setOption(["colors"], color) + return this.setOption(["colors"], [color]) } width(width) { @@ -66,4 +83,25 @@ export class ApexOptionsBuilder { animate(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) + } } diff --git a/packages/standard-components/src/Chart/Bar.svelte b/packages/standard-components/src/Chart/BarChart.svelte similarity index 59% rename from packages/standard-components/src/Chart/Bar.svelte rename to packages/standard-components/src/Chart/BarChart.svelte index d73a0681a3..edc0f8dcc1 100644 --- a/packages/standard-components/src/Chart/Bar.svelte +++ b/packages/standard-components/src/Chart/BarChart.svelte @@ -2,12 +2,13 @@ import { onMount } from "svelte" import { chart } from "svelte-apexcharts" import fetchData from "../fetchData" - import { isEmpty } from "lodash/fp" + import { isEmpty, sortBy } from "lodash/fp" import { ApexOptionsBuilder } from "./ApexOptionsBuilder" + export let title export let datasource - export let nameLabel - export let valueLabel + export let labelColumn + export let valueColumns export let xAxisLabel export let yAxisLabel export let height @@ -16,6 +17,7 @@ export let horizontal export let dataLabels export let animate + export let legend let data $: options = getChartOptions(data) @@ -23,15 +25,16 @@ // Fetch data on mount onMount(async () => { if (!isEmpty(datasource)) { - data = await fetchData(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("bar") - .color(color) .width(width) .height(height) .xLabel(xAxisLabel) @@ -39,20 +42,19 @@ .horizontal(horizontal) .dataLabels(dataLabels) .animate(animate) + .legend(legend) // Add data if valid datasource if (rows && rows.length) { - rows = rows.slice(0, 50) - if (!isEmpty(nameLabel) && !isNaN(rows[0][valueLabel])) { - builder = builder.series([ - { - name: valueLabel, - data: rows.map(row => row[valueLabel]), - }, - ]) + if (valueColumns && valueColumns.length) { + const series = valueColumns.map(column => ({ + name: column, + data: rows.map(row => parseFloat(row[column])), + })) + builder = builder.series(series) } - if (!isEmpty(nameLabel)) { - builder = builder.categories(rows.map(row => row[nameLabel])) + if (!isEmpty(rows[0][labelColumn])) { + builder = builder.categories(rows.map(row => row[labelColumn])) } } diff --git a/packages/standard-components/src/Chart/LineChart.svelte b/packages/standard-components/src/Chart/LineChart.svelte new file mode 100644 index 0000000000..599ce1fed1 --- /dev/null +++ b/packages/standard-components/src/Chart/LineChart.svelte @@ -0,0 +1,71 @@ + + +
diff --git a/packages/standard-components/src/Chart/index.js b/packages/standard-components/src/Chart/index.js index 0dafa8a70d..5a9e94f00d 100644 --- a/packages/standard-components/src/Chart/index.js +++ b/packages/standard-components/src/Chart/index.js @@ -1,2 +1,2 @@ -export { default as bar } from "./Bar.svelte" -export { default as line } from "./Line.svelte" +export { default as bar } from "./BarChart.svelte" +export { default as line } from "./LineChart.svelte"