From 22a84a99a621cbb35da82f52ee585340c86446eb Mon Sep 17 00:00:00 2001 From: Nikita Kotlyarevskyy Date: Mon, 15 Jul 2024 18:45:34 +0200 Subject: [PATCH] Adds a new 'styles' property to the OptsChartData interface to define styles for data points. Adds logic that allows custom border styles to be defined for each data point in the following charts: Bar, Line, Area, Scatter, Pie/Doughnut charts. --- src/core-interfaces.ts | 8 +++ src/gen-charts.ts | 121 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/src/core-interfaces.ts b/src/core-interfaces.ts index df6c617a..d03c85d0 100644 --- a/src/core-interfaces.ts +++ b/src/core-interfaces.ts @@ -1173,6 +1173,14 @@ export interface OptsChartData { * @example [2000, 2010, 2020] */ values?: number[] + /** + * custom styles, e.g border + * @example [ + {border: {pt:'1', color:'ff0000'} }, + {border: {pt:'2', color:'000000'} } + ] + */ + styles?: object[] /** * Override `chartColors` */ diff --git a/src/gen-charts.ts b/src/gen-charts.ts index efe0c95e..1a97e54f 100644 --- a/src/gen-charts.ts +++ b/src/gen-charts.ts @@ -831,6 +831,7 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh } ] */ + data.forEach(obj => { colorIndex++ strXml += '' @@ -900,7 +901,13 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh if (opts.lineDataSymbolSize) strXml += `` // Defaults to "auto" otherwise (but this is usually too small, so there is a default) strXml += ' ' strXml += ` ${createColorElement(opts.chartColors[obj._dataIndex + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : obj._dataIndex])}` - strXml += ` ${createColorElement(opts.lineDataSymbolLineColor || seriesColor)}` + strXml += ` ` + strXml += ' ' + strXml += ` ${createColorElement(opts.lineDataSymbolLineColor || seriesColor)}` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' strXml += ' ' strXml += ' ' strXml += '' @@ -988,7 +995,66 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh // Option: `smooth` if (chartType === CHART_TYPE.LINE) strXml += '' - // 4: Close "SERIES" + /* EX: + data: [ + { + name: 'Project Status', + labels: ['Red', 'On Hold', 'Green', 'Unknown'], + values: [10, 20, 38, 2] + styles: [ + {border: {pt: 2, color: '#ff0000'}} + {} + {border: {pt: 2, color: '#00ff00'}} + {} + ] + } + ] + */ + // 4: data point "Styles" + if (obj.styles) { + obj.styles.forEach((style: any, idx) => { + if (style !== undefined && style !== null) { + const borderStyle = 'border' in style ? style.border : {} + if (chartType === CHART_TYPE.BAR) { + strXml += '' + strXml += ` ` + strXml += ' ' + strXml += ' ' + strXml += ` ${createColorElement(seriesColor)}` + strXml += ' ' + strXml += ` ` + strXml += ' ' + strXml += ` ${createColorElement(borderStyle && 'color' in borderStyle ? borderStyle.color : seriesColor)}` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += '' + } else if (chartType === CHART_TYPE.LINE || chartType === CHART_TYPE.AREA) { + strXml += '' + strXml += ` ` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ` ${createColorElement(seriesColor)}` + strXml += ' ' + strXml += ` ` + strXml += ' ' + strXml += ` ${createColorElement(borderStyle && 'color' in borderStyle ? borderStyle.color : seriesColor)}` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += '' + } + } + }) + } + + // 5: Close "SERIES" strXml += '' }) @@ -1288,6 +1354,35 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh // Option: `smooth` strXml += '' + if (obj.styles) { + obj.styles.forEach((style: any, idx) => { + if (style !== undefined && style !== null) { + const color = opts.chartColors[colorIndex % opts.chartColors.length] + const borderStyle = 'border' in style ? style.border : {} + + strXml += '' + strXml += ` ` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ` ${createColorElement(color)}` + strXml += ' ' + strXml += ` ` + strXml += ' ' + strXml += ` ${createColorElement('color' in borderStyle ? borderStyle.color : color)}` + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += ' ' + strXml += '' + } + }) + } + // 4: Close "SERIES" strXml += '' }) @@ -1481,7 +1576,6 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh case CHART_TYPE.PIE: // Use the same let name so code blocks from barChart are interchangeable optsChartData = data[0] - /* EX: data: [ { @@ -1520,16 +1614,25 @@ function makeChartType (chartType: CHART_NAME, data: IOptsChartData[], opts: ICh // 2: "Data Point" block for every data row optsChartData.labels[0].forEach((_label, idx) => { + const color = opts.chartColors[idx + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : idx] + + const style = optsChartData?.styles?.[idx] ?? {} + + const borderStyle = 'border' in style + ? style.border as {pt, color} + : opts.dataBorder ? opts.dataBorder : {} + + const explosion = 'pt' in borderStyle ? borderStyle.pt : 0 + strXml += '' strXml += ` ` + strXml += ` ` strXml += ' ' strXml += ' ' - strXml += `${createColorElement( - opts.chartColors[idx + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : idx] - )}` - if (opts.dataBorder) { - strXml += `${createColorElement( - opts.dataBorder.color + strXml += `${createColorElement(color)}` + if (borderStyle) { + strXml += `${createColorElement( + borderStyle.color )}` } strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW)