diff --git a/samples/vanilla-js/column/data-color.html b/samples/vanilla-js/column/data-color.html new file mode 100644 index 000000000..35ef9679c --- /dev/null +++ b/samples/vanilla-js/column/data-color.html @@ -0,0 +1,104 @@ + + + + + + + + Basic Column - Grouped + + + + + + + + +
+ +
+ + + + + + + + \ No newline at end of file diff --git a/samples/vanilla-js/column/histogram.html b/samples/vanilla-js/column/histogram.html index ac802ef12..f31c361d2 100644 --- a/samples/vanilla-js/column/histogram.html +++ b/samples/vanilla-js/column/histogram.html @@ -20,6 +20,10 @@ opacity: 1; border: 0; } + + .selection { + opacity: 0; + } @@ -27,7 +31,9 @@
- Selected: 0 +
+ Selected: 0 +
@@ -59,7 +65,6 @@ }, plotOptions: { bar: { - distributed: true, dataLabels: { enabled: false } @@ -73,16 +78,6 @@ allowMultipleDataPointsSelection: true } }, - markers: { - size: 5, - strokeColor: "#fff", - strokeWidth: 3, - strokeOpacity: 1, - fillOpacity: 1, - hover: { - size: 8 - } - }, xaxis: { categories: [10,20,30,40,50,60,70], axisBorder: { @@ -114,8 +109,8 @@ chart.addEventListener("dataPointSelection", function(e, opts) { - console.log(e, opts) - }) + console.log(e, opts) + }) diff --git a/src/charts/Bar.js b/src/charts/Bar.js index 2a69017f2..4b46362b1 100644 --- a/src/charts/Bar.js +++ b/src/charts/Bar.js @@ -46,7 +46,6 @@ class Bar { draw(series, seriesIndex) { let w = this.w let graphics = new Graphics(this.ctx) - let fill = new Fill(this.ctx) const coreUtils = new CoreUtils(this.ctx, w) this.series = coreUtils.getLogSeries(series) @@ -190,23 +189,7 @@ class Bar { yArrj.push(y) - let seriesNumber = this.barOptions.distributed ? j : i - - let fillColor = null - - if (this.barOptions.colors.ranges.length > 0) { - const colorRange = this.barOptions.colors.ranges - colorRange.map((range) => { - if (series[i][j] >= range.from && series[i][j] <= range.to) { - fillColor = range.color - } - }) - } - - let pathFill = fill.fillPath({ - seriesNumber: this.barOptions.distributed ? seriesNumber : realIndex, - color: fillColor - }) + let pathFill = this.getPathFillColor(i, j, realIndex) elSeries = this.renderSeries({ realIndex, @@ -238,6 +221,34 @@ class Bar { return ret } + getPathFillColor(i, j, realIndex) { + const w = this.w + let fill = new Fill(this.ctx) + + let fillColor = null + let seriesNumber = this.barOptions.distributed ? j : i + + if (this.barOptions.colors.ranges.length > 0) { + const colorRange = this.barOptions.colors.ranges + colorRange.map((range) => { + if (series[i][j] >= range.from && series[i][j] <= range.to) { + fillColor = range.color + } + }) + } + + if (w.config.series[i].data[j] && w.config.series[i].data[j].fillColor) { + fillColor = w.config.series[i].data[j].fillColor + } + + let pathFill = fill.fillPath({ + seriesNumber: this.barOptions.distributed ? seriesNumber : realIndex, + color: fillColor + }) + + return pathFill + } + renderSeries({ realIndex, pathFill, @@ -267,6 +278,10 @@ class Bar { : w.globals.stroke.colors[realIndex] } + if (w.config.series[i].data[j] && w.config.series[i].data[j].strokeColor) { + lineFill = w.config.series[i].data[j].strokeColor + } + if (this.isNullValue) { pathFill = 'none' } @@ -507,8 +522,6 @@ class Bar { pathTo + graphics.line(endingShape.newX, barYPosition) + endingShape.path + - // graphics.line(x, barYPosition) + - // graphics.line(x, barYPosition + barHeight - strokeWidth) + graphics.line(zeroW, barYPosition + barHeight - strokeWidth) + graphics.line(zeroW, barYPosition) @@ -614,17 +627,15 @@ class Bar { pathTo + graphics.line(barXPosition, endingShape.newY) + endingShape.path + - // graphics.line(barXPosition, y) + - // graphics.line(barXPosition + barWidth - strokeWidth, y) + graphics.line(barXPosition + barWidth - strokeWidth, zeroH) + - graphics.line(barXPosition, zeroH) + graphics.line(barXPosition - strokeWidth / 2, zeroH) pathFrom = pathFrom + graphics.line(barXPosition, zeroH) + endingShape.ending_p_from + graphics.line(barXPosition + barWidth - strokeWidth, zeroH) + graphics.line(barXPosition + barWidth - strokeWidth, zeroH) + - graphics.line(barXPosition, zeroH) + graphics.line(barXPosition - strokeWidth / 2, zeroH) if (!w.globals.isXNumeric) { x = x + xDivision diff --git a/src/charts/BarStacked.js b/src/charts/BarStacked.js index 1278ab8e5..897e7f552 100644 --- a/src/charts/BarStacked.js +++ b/src/charts/BarStacked.js @@ -178,23 +178,7 @@ class BarStacked extends Bar { xArrValues.push(x) yArrValues.push(y) - let seriesNumber = w.config.plotOptions.bar.distributed ? j : i - - let fillColor = null - - if (this.barOptions.colors.ranges.length > 0) { - const colorRange = this.barOptions.colors.ranges - colorRange.map((range, index) => { - if (series[i][j] >= range.from && series[i][j] <= range.to) { - fillColor = range.color - } - }) - } - - let pathFill = this.fill.fillPath({ - seriesNumber: this.barOptions.distributed ? seriesNumber : realIndex, - color: fillColor - }) + let pathFill = this.bar.getPathFillColor(i, j, realIndex) elSeries = this.renderSeries({ realIndex, @@ -530,14 +514,14 @@ class BarStacked extends Bar { this.graphics.line(barXPosition, endingShape.newY) + endingShape.path + this.graphics.line(barXPosition + barWidth - strokeWidth, barYPosition) + - this.graphics.line(barXPosition, barYPosition) + this.graphics.line(barXPosition - strokeWidth / 2, barYPosition) pathFrom = pathFrom + this.graphics.line(barXPosition, barYPosition) + this.graphics.line(barXPosition + barWidth - strokeWidth, barYPosition) + this.graphics.line(barXPosition + barWidth - strokeWidth, barYPosition) + this.graphics.line(barXPosition + barWidth - strokeWidth, barYPosition) + - this.graphics.line(barXPosition, barYPosition) + this.graphics.line(barXPosition - strokeWidth / 2, barYPosition) if ( w.config.plotOptions.bar.colors.backgroundBarColors.length > 0 && diff --git a/src/charts/Scatter.js b/src/charts/Scatter.js index 4f5dfc97b..d82d81751 100644 --- a/src/charts/Scatter.js +++ b/src/charts/Scatter.js @@ -100,21 +100,33 @@ export default class Scatter { drawPoint(x, y, radius, finishRadius, realIndex, dataPointIndex, j) { const w = this.w + let i = realIndex let anim = new Animations(this.ctx) let filters = new Filters(this.ctx) let fill = new Fill(this.ctx) + let markers = new Markers(this.ctx) const graphics = new Graphics(this.ctx) + const markerConfig = markers.getMarkerConfig('apexcharts-marker', i) + let pathFillCircle = fill.fillPath({ seriesNumber: realIndex, patternUnits: 'objectBoundingBox' }) let circle = graphics.drawCircle(radius) + if (w.config.series[i].data[dataPointIndex]) { + if (w.config.series[i].data[dataPointIndex].fillColor) { + pathFillCircle = w.config.series[i].data[dataPointIndex].fillColor + } + } + circle.attr({ cx: x, cy: y, - fill: pathFillCircle + fill: pathFillCircle, + stroke: markerConfig.pointStrokeColor, + strokeWidth: markerConfig.pWidth }) if (w.config.chart.dropShadow.enabled) { @@ -192,7 +204,6 @@ export default class Scatter { 'default-marker-size': finishRadius }) - const markers = new Markers(this.ctx) filters.setSelectionFilter(circle, realIndex, dataPointIndex) markers.addEvents(circle) diff --git a/src/modules/Core.js b/src/modules/Core.js index ac16e8830..bd3fbbea7 100644 --- a/src/modules/Core.js +++ b/src/modules/Core.js @@ -478,6 +478,7 @@ export default class Core { } else { this.twoDSeries.push(Utils.parseNumber(ser[i].data[j][1])) } + gl.dataFormat2DArray = true } if (cnf.xaxis.type === 'datetime') { // if timestamps are provided and xaxis type is datettime, @@ -509,6 +510,7 @@ export default class Core { // fix #368 activeI = this.activeSeriesIndex } + gl.dataFormatXY = true // get series for (let j = 0; j < ser[i].data.length; j++) { @@ -737,7 +739,7 @@ export default class Core { // user didn't provided labels, fallback to 1-2-3-4-5 let labelArr = [] if (gl.axisCharts) { - if (this.twoDSeriesX.length > 0) { + if (gl.dataFormat2DArray) { const scales = new Scales(this.ctx) labelArr = scales .linearScale( diff --git a/src/modules/Markers.js b/src/modules/Markers.js index 8489a7c5a..67b8fab8b 100644 --- a/src/modules/Markers.js +++ b/src/modules/Markers.js @@ -39,6 +39,7 @@ export default class Markers { plotChartMarkers(pointsPos, seriesIndex, j) { let w = this.w + let i = seriesIndex let p = pointsPos let elPointsWrap = null @@ -99,6 +100,16 @@ export default class Markers { } }) + if (w.config.series[i].data[j]) { + if (w.config.series[i].data[j].fillColor) { + opts.pointFillColor = w.config.series[i].data[j].fillColor + } + + if (w.config.series[i].data[j].strokeColor) { + opts.pointStrokeColor = w.config.series[i].data[j].strokeColor + } + } + point = graphics.drawMarker(p.x[q], p.y[q], opts) point.attr('rel', dataPointIndex) diff --git a/src/modules/Range.js b/src/modules/Range.js index d029d67d8..dd615678c 100644 --- a/src/modules/Range.js +++ b/src/modules/Range.js @@ -284,7 +284,7 @@ class Range { if ( (gl.isXNumeric || gl.noLabelsProvided) && - !cnf.xaxis.convertedCatToNumeric + (!cnf.xaxis.convertedCatToNumeric || gl.dataFormat2DArray) ) { let ticks @@ -356,6 +356,11 @@ class Range { gl.maxX = gl.maxX + 2 } } + + return { + minX: gl.minX, + maxX: gl.maxX + } } setZRange() { diff --git a/src/modules/settings/Globals.js b/src/modules/settings/Globals.js index 1edd0706b..e9ebd5e98 100644 --- a/src/modules/settings/Globals.js +++ b/src/modules/settings/Globals.js @@ -60,6 +60,8 @@ export default class Globals { ancillaryCollapsedSeries: [], // when user collapses an "alwaysVisible" series, it goes into this array ancillaryCollapsedSeriesIndices: [], // this stores the index of the collapsedSeries whose y-axis is always visible risingSeries: [], // when user re-opens a collapsed series, it goes here + dataFormat2DArray: false, + dataFormatXY: false, selectedDataPoints: [], ignoreYAxisIndexes: [], // when series are being collapsed in multiple y axes, ignore certain index padHorizontal: 0, diff --git a/src/modules/tooltip/Position.js b/src/modules/tooltip/Position.js index ff6765676..e7a9aaf83 100644 --- a/src/modules/tooltip/Position.js +++ b/src/modules/tooltip/Position.js @@ -279,10 +279,13 @@ export default class Position { `.apexcharts-series[data\\:realIndex='${capturedSeries}'] .apexcharts-series-markers circle` ) - point.setAttribute('r', hoverSize) + if (point) { + point.setAttribute('r', hoverSize) + + point.setAttribute('cx', cx) + point.setAttribute('cy', cy) + } - point.setAttribute('cx', cx) - point.setAttribute('cy', cy) // point.style.opacity = w.config.markers.hover.opacity this.moveXCrosshairs(cx) diff --git a/tests/unit/data/series2dArrayNumeric.js b/tests/unit/data/series2dArrayNumeric.js new file mode 100644 index 000000000..0fbdfa4b1 --- /dev/null +++ b/tests/unit/data/series2dArrayNumeric.js @@ -0,0 +1,44 @@ +module.exports = [ + { + data: [ + [6.4, 5.4], + [11.7, 4], + [15.4, 3], + [9, 2], + [10.9, 11], + [20.9, 7], + [12.9, 8.2], + [6.4, 14], + [11.6, 12] + ] + }, + { + data: [ + [16.4, 5.4], + [21.7, 4], + [25.4, 3], + [19, 2], + [10.9, 1], + [13.6, 3.2], + [10.9, 7], + [10.9, 8.2], + [16.4, 4], + [13.6, 4.3], + [13.6, 12], + [29.9, 3], + [10.9, 5.2], + [16.4, 6.5], + [10.9, 8], + [24.5, 7.1], + [10.9, 7], + [8.1, 4.7], + [19, 10], + [27.1, 10], + [24.5, 8], + [27.1, 3], + [29.9, 11.5], + [27.1, 0.8], + [22.1, 2] + ] + } +] diff --git a/tests/unit/data/series2dArray.js b/tests/unit/data/series2dArrayTimestamp.js similarity index 100% rename from tests/unit/data/series2dArray.js rename to tests/unit/data/series2dArrayTimestamp.js diff --git a/tests/unit/xaxis-min-max.spec.js b/tests/unit/xaxis-min-max.spec.js new file mode 100644 index 000000000..50c434fb2 --- /dev/null +++ b/tests/unit/xaxis-min-max.spec.js @@ -0,0 +1,24 @@ +import Range from '../../src/modules/Range.js' +import series2dArrayNumeric from './data/series2dArrayNumeric.js' +import { createChartWithOptions } from './utils/utils.js' + +describe('X-axis data', () => { + it('should set the min and max of x-axis based on user input', () => { + const chart = createChartWithOptions({ + chart: { + type: 'line' + }, + series: series2dArrayNumeric, + xaxis: { + min: 0, + max: 40 + } + }) + + const range = new Range(chart) + const xRange = range.setXRange() + + expect(xRange.minX).toEqual(0) + expect(xRange.maxX).toEqual(40) + }) +})