From 9109e8a072832fb0500997c9cad555b57721e3a6 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 Apr 2024 10:04:43 +0200 Subject: [PATCH] Dashboard: Customize chart colors (#2045) --- .../boxs/chart/ApexChartAreaOptions.js | 4 +- .../boxs/chart/ApexChartBarOptions.js | 4 +- .../boxs/chart/ApexChartComponent.jsx | 24 ++++-- .../boxs/chart/ApexChartLineOptions.js | 4 +- .../boxs/chart/ApexChartStepLineOptions.js | 4 +- front/src/components/boxs/chart/Chart.jsx | 2 + front/src/components/boxs/chart/EditChart.jsx | 74 +++++++++++++++++++ front/src/config/i18n/de.json | 14 +++- front/src/config/i18n/en.json | 16 ++-- front/src/config/i18n/fr.json | 18 +++-- front/src/utils/mergeArray.js | 20 +++++ server/models/dashboard.js | 1 + 12 files changed, 154 insertions(+), 31 deletions(-) create mode 100644 front/src/utils/mergeArray.js diff --git a/front/src/components/boxs/chart/ApexChartAreaOptions.js b/front/src/components/boxs/chart/ApexChartAreaOptions.js index e343abcd71..a18875760a 100644 --- a/front/src/components/boxs/chart/ApexChartAreaOptions.js +++ b/front/src/components/boxs/chart/ApexChartAreaOptions.js @@ -1,4 +1,4 @@ -const getApexChartAreaOptions = ({ displayAxes, height, series, COLORS, locales, defaultLocale }) => { +const getApexChartAreaOptions = ({ displayAxes, height, series, colors, locales, defaultLocale }) => { const options = { chart: { locales, @@ -54,7 +54,7 @@ const getApexChartAreaOptions = ({ displayAxes, height, series, COLORS, locales, padding: 4 } }, - colors: COLORS, + colors, legend: { show: displayAxes, position: 'bottom' diff --git a/front/src/components/boxs/chart/ApexChartBarOptions.js b/front/src/components/boxs/chart/ApexChartBarOptions.js index fcfa0a1dd0..43705a389e 100644 --- a/front/src/components/boxs/chart/ApexChartBarOptions.js +++ b/front/src/components/boxs/chart/ApexChartBarOptions.js @@ -1,4 +1,4 @@ -const getApexChartBarOptions = ({ displayAxes, series, COLORS, locales, defaultLocale }) => { +const getApexChartBarOptions = ({ displayAxes, series, colors, locales, defaultLocale }) => { const options = { chart: { locales, @@ -62,7 +62,7 @@ const getApexChartBarOptions = ({ displayAxes, series, COLORS, locales, defaultL padding: 4 } }, - colors: COLORS, + colors, legend: { show: displayAxes, position: 'bottom' diff --git a/front/src/components/boxs/chart/ApexChartComponent.jsx b/front/src/components/boxs/chart/ApexChartComponent.jsx index e0a79a5463..fa9b7468f2 100644 --- a/front/src/components/boxs/chart/ApexChartComponent.jsx +++ b/front/src/components/boxs/chart/ApexChartComponent.jsx @@ -11,10 +11,22 @@ import { getApexChartBarOptions } from './ApexChartBarOptions'; import { getApexChartAreaOptions } from './ApexChartAreaOptions'; import { getApexChartLineOptions } from './ApexChartLineOptions'; import { getApexChartStepLineOptions } from './ApexChartStepLineOptions'; +import mergeArray from '../../../utils/mergeArray'; dayjs.extend(localizedFormat); -const COLORS = ['#206bc4', '#FF7878', '#E0C097', '#F7D59C']; +const DEFAULT_COLORS = [ + '#316cbe', + '#d63031', + '#00b894', + '#fdcb6e', + '#6c5ce7', + '#00cec9', + '#e84393', + '#e17055', + '#636e72' +]; +const DEFAULT_COLORS_NAME = ['blue', 'red', 'green', 'yellow', 'purple', 'aqua', 'pink', 'orange', 'grey']; class ApexChartComponent extends Component { chartRef = createRef(); @@ -43,7 +55,7 @@ class ApexChartComponent extends Component { const options = getApexChartBarOptions({ displayAxes: this.props.display_axes, series: this.props.series, - COLORS, + colors: mergeArray(this.props.colors, DEFAULT_COLORS), locales: [fr, en, de], defaultLocale: this.props.user.language }); @@ -63,7 +75,7 @@ class ApexChartComponent extends Component { height, series: this.props.series, displayAxes: this.props.display_axes, - COLORS, + colors: mergeArray(this.props.colors, DEFAULT_COLORS), locales: [fr, en, de], defaultLocale: this.props.user.language }); @@ -82,7 +94,7 @@ class ApexChartComponent extends Component { } const options = getApexChartLineOptions({ height, - COLORS, + colors: mergeArray(this.props.colors, DEFAULT_COLORS), displayAxes: this.props.display_axes, series: this.props.series, locales: [fr, en, de], @@ -102,7 +114,7 @@ class ApexChartComponent extends Component { } const options = getApexChartStepLineOptions({ height, - COLORS, + colors: mergeArray(this.props.colors, DEFAULT_COLORS), displayAxes: this.props.display_axes, series: this.props.series, locales: [fr, en, de], @@ -155,3 +167,5 @@ class ApexChartComponent extends Component { } export default ApexChartComponent; + +export { DEFAULT_COLORS, DEFAULT_COLORS_NAME }; diff --git a/front/src/components/boxs/chart/ApexChartLineOptions.js b/front/src/components/boxs/chart/ApexChartLineOptions.js index 986cf94273..990a92ee80 100644 --- a/front/src/components/boxs/chart/ApexChartLineOptions.js +++ b/front/src/components/boxs/chart/ApexChartLineOptions.js @@ -1,4 +1,4 @@ -const getApexChartLineOptions = ({ height, displayAxes, series, COLORS, locales, defaultLocale }) => { +const getApexChartLineOptions = ({ height, displayAxes, series, colors, locales, defaultLocale }) => { const options = { chart: { locales, @@ -53,7 +53,7 @@ const getApexChartLineOptions = ({ height, displayAxes, series, COLORS, locales, padding: 4 } }, - colors: COLORS, + colors, legend: { show: displayAxes, position: 'bottom' diff --git a/front/src/components/boxs/chart/ApexChartStepLineOptions.js b/front/src/components/boxs/chart/ApexChartStepLineOptions.js index df5425a16d..b6b695e100 100644 --- a/front/src/components/boxs/chart/ApexChartStepLineOptions.js +++ b/front/src/components/boxs/chart/ApexChartStepLineOptions.js @@ -1,4 +1,4 @@ -const getApexChartStepLineOptions = ({ height, displayAxes, series, COLORS, locales, defaultLocale }) => { +const getApexChartStepLineOptions = ({ height, displayAxes, series, colors, locales, defaultLocale }) => { const options = { chart: { locales, @@ -52,7 +52,7 @@ const getApexChartStepLineOptions = ({ height, displayAxes, series, COLORS, loca padding: 4 } }, - colors: COLORS, + colors, legend: { show: displayAxes, position: 'bottom' diff --git a/front/src/components/boxs/chart/Chart.jsx b/front/src/components/boxs/chart/Chart.jsx index c574d357d2..53f23b0985 100644 --- a/front/src/components/boxs/chart/Chart.jsx +++ b/front/src/components/boxs/chart/Chart.jsx @@ -441,6 +441,7 @@ class Chartbox extends Component { size="big" chart_type={props.box.chart_type} display_axes={props.box.display_axes} + colors={props.box.colors} /> )} @@ -477,6 +478,7 @@ class Chartbox extends Component { size="big" chart_type={props.box.chart_type} display_axes={props.box.display_axes} + colors={props.box.colors} /> )} diff --git a/front/src/components/boxs/chart/EditChart.jsx b/front/src/components/boxs/chart/EditChart.jsx index 4ba5c2336f..d0877178b7 100644 --- a/front/src/components/boxs/chart/EditChart.jsx +++ b/front/src/components/boxs/chart/EditChart.jsx @@ -9,6 +9,7 @@ import Chart from './Chart'; import { getDeviceFeatureName } from '../../../utils/device'; import { DEVICE_FEATURE_TYPES } from '../../../../../server/utils/constants'; import withIntlAsProp from '../../../utils/withIntlAsProp'; +import { DEFAULT_COLORS, DEFAULT_COLORS_NAME } from './ApexChartComponent'; const FEATURES_THAT_ARE_NOT_COMPATIBLE = { [DEVICE_FEATURE_TYPES.LIGHT.BINARY]: true, @@ -17,6 +18,41 @@ const FEATURES_THAT_ARE_NOT_COMPATIBLE = { [DEVICE_FEATURE_TYPES.CAMERA.IMAGE]: true }; +const square = (color = 'transparent') => ({ + alignItems: 'center', + display: 'flex', + + ':before': { + backgroundColor: color, + content: '" "', + display: 'block', + marginRight: 8, + height: 10, + width: 10 + } +}); + +const colorSelectorStyles = { + control: styles => ({ ...styles, backgroundColor: 'white' }), + option: (styles, { data, isDisabled, isFocused, isSelected }) => { + const { value: color } = data; + return { + ...styles, + backgroundColor: isDisabled ? undefined : isSelected ? color : isFocused ? color : undefined, + color: isDisabled ? '#ccc' : isSelected ? 'white' : isFocused ? 'white' : color, + cursor: isDisabled ? 'not-allowed' : 'default', + + ':active': { + ...styles[':active'], + backgroundColor: !isDisabled ? color : undefined + } + }; + }, + input: styles => ({ ...styles, ...square() }), + placeholder: styles => ({ ...styles, ...square('#ccc') }), + singleValue: (styles, { data }) => ({ ...styles, ...square(data.value) }) +}; + class EditChart extends Component { showPreview = () => { this.setState({ @@ -40,6 +76,17 @@ class EditChart extends Component { } }; + updateChartColor = (i, value) => { + const colors = this.props.box.colors || []; + if (value) { + colors[i] = value; + } else { + colors[i] = null; + } + const atLeastOneColor = colors.some(Boolean); + this.props.updateBoxConfig(this.props.x, this.props.y, { colors: atLeastOneColor ? colors : undefined }); + }; + updateDisplayAxes = e => { if (e.target.value && e.target.value.length) { const valueBoolean = e.target.value === 'yes'; @@ -150,6 +197,11 @@ class EditChart extends Component { } render(props, { selectedDeviceFeaturesOptions, deviceOptions, loading, displayPreview }) { + const manyFeatures = selectedDeviceFeaturesOptions && selectedDeviceFeaturesOptions.length > 1; + const colorOptions = DEFAULT_COLORS.map((colorValue, i) => ({ + value: colorValue, + label: props.intl.dictionary.color[DEFAULT_COLORS_NAME[i]] || DEFAULT_COLORS_NAME[i] + })); return (
@@ -207,6 +259,28 @@ class EditChart extends Component {
+ {selectedDeviceFeaturesOptions && + selectedDeviceFeaturesOptions.map((feature, i) => ( +
+ +