Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: multiple lines added to a stack bar chart also stack #3477

Closed
wants to merge 13 commits into from
6 changes: 3 additions & 3 deletions dist/apexcharts.common.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/apexcharts.esm.js

Large diffs are not rendered by default.

113 changes: 76 additions & 37 deletions dist/apexcharts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* ApexCharts v3.36.2
* ApexCharts v3.36.3
* (c) 2018-2022 ApexCharts
* Released under the MIT License.
*/
Expand Down Expand Up @@ -3512,6 +3512,8 @@
},
stacked: false,
stackType: 'normal',
stackOnlyBar: true,
// mixed chart with stacked bars and line series - incorrect line draw #907
toolbar: {
show: true,
offsetX: 0,
Expand Down Expand Up @@ -4107,6 +4109,7 @@
enabled: true,
enabledOnSeries: undefined,
shared: true,
hideEmptyShared: true,
followCursor: false,
// when disabled, the tooltip will show on top of the series instead of mouse position
intersect: false,
Expand Down Expand Up @@ -5864,27 +5867,14 @@
var options = new Options();
var defaults = new Defaults(opts);
this.chartType = opts.chart.type;

if (this.chartType === 'histogram') {
// technically, a histogram can be drawn by a column chart with no spaces in between
opts.chart.type = 'bar';
opts = Utils$1.extend({
plotOptions: {
bar: {
columnWidth: '99.99%'
}
}
}, opts);
}

opts = this.extendYAxis(opts);
opts = this.extendAnnotations(opts);
var config = options.init();
var newDefaults = {};

if (opts && _typeof(opts) === 'object') {
var chartDefaults = {};
var chartTypes = ['line', 'area', 'bar', 'candlestick', 'boxPlot', 'rangeBar', 'rangeArea', 'histogram', 'bubble', 'scatter', 'heatmap', 'treemap', 'pie', 'polarArea', 'donut', 'radar', 'radialBar'];
var chartTypes = ['line', 'area', 'bar', 'candlestick', 'boxPlot', 'rangeBar', 'rangeArea', 'bubble', 'scatter', 'heatmap', 'treemap', 'pie', 'polarArea', 'donut', 'radar', 'radialBar'];

if (chartTypes.indexOf(opts.chart.type) !== -1) {
chartDefaults = defaults[opts.chart.type]();
Expand Down Expand Up @@ -9498,7 +9488,7 @@
});
var elXAxisTitleText = graphics.drawText({
x: w.globals.gridWidth / 2 + w.config.xaxis.title.offsetX,
y: this.offY + parseFloat(this.xaxisFontSize) + (w.config.xaxis.title.position === 'bottom' ? w.globals.xAxisLabelsHeight : -w.globals.xAxisLabelsHeight - 10) + w.config.xaxis.title.offsetY,
y: this.offY + parseFloat(this.xaxisFontSize) + (w.config.xaxis.position === 'bottom' ? w.globals.xAxisLabelsHeight : -w.globals.xAxisLabelsHeight - 10) + w.config.xaxis.title.offsetY,
text: w.config.xaxis.title.text,
textAnchor: 'middle',
fontSize: w.config.xaxis.title.style.fontSize,
Expand Down Expand Up @@ -9700,11 +9690,28 @@
multiY = label.length / 2 * parseInt(ylabels.style.fontSize, 10);
}

var offsetX = ylabels.offsetX - 15;
var textAnchor = 'end';

if (_this2.yaxis.opposite) {
textAnchor = 'start';
}

if (w.config.yaxis[0].labels.align === 'left') {
offsetX = ylabels.offsetX;
textAnchor = 'start';
} else if (w.config.yaxis[0].labels.align === 'center') {
offsetX = ylabels.offsetX;
textAnchor = 'middle';
} else if (w.config.yaxis[0].labels.align === 'right') {
textAnchor = 'end';
}

var elLabel = graphics.drawText({
x: ylabels.offsetX - 15,
x: offsetX,
y: yPos + colHeight + ylabels.offsetY - multiY,
text: label,
textAnchor: _this2.yaxis.opposite ? 'start' : 'end',
textAnchor: textAnchor,
foreColor: getForeColor(),
fontSize: ylabels.style.fontSize,
fontFamily: ylabels.style.fontFamily,
Expand Down Expand Up @@ -11518,15 +11525,19 @@
var negs = 0;

for (var i = 0; i < gl.series.length; i++) {
if (gl.series[i][j] !== null && Utils$1.isNumber(gl.series[i][j])) {
// 0.0001 fixes #185 when values are very small
gl.series[i][j] > 0 ? poss = poss + parseFloat(gl.series[i][j]) + 0.0001 : negs = negs + parseFloat(gl.series[i][j]);
}
var stackSeries = !this.w.config.chart.stackOnlyBar || gl.series[i] && gl.series[i].type && gl.series[i].type === 'bar';

if (i === gl.series.length - 1) {
// push all the totals to the array for future use
stackedPoss.push(poss);
stackedNegs.push(negs);
if (stackSeries) {
if (gl.series[i][j] !== null && Utils$1.isNumber(gl.series[i][j])) {
// 0.0001 fixes #185 when values are very small
gl.series[i][j] > 0 ? poss = poss + parseFloat(gl.series[i][j]) + 0.0001 : negs = negs + parseFloat(gl.series[i][j]);
}

if (i === gl.series.length - 1) {
// push all the totals to the array for future use
stackedPoss.push(poss);
stackedNegs.push(negs);
}
}
}
}
Expand Down Expand Up @@ -11616,6 +11627,20 @@
xPad = xPad * -1;
}

var textAnchor = 'end';

if (w.config.yaxis[realIndex].opposite) {
textAnchor = 'start';
}

if (w.config.yaxis[realIndex].labels.align === 'left') {
textAnchor = 'start';
} else if (w.config.yaxis[realIndex].labels.align === 'center') {
textAnchor = 'middle';
} else if (w.config.yaxis[realIndex].labels.align === 'right') {
textAnchor = 'end';
}

var yColors = _this.axesUtils.getYAxisForeColor(yaxisStyle.colors, realIndex);

var getForeColor = function getForeColor() {
Expand All @@ -11626,7 +11651,7 @@
x: xPad,
y: l + tickAmount / 10 + w.config.yaxis[realIndex].labels.offsetY + 1,
text: val,
textAnchor: w.config.yaxis[realIndex].opposite ? 'start' : 'end',
textAnchor: textAnchor,
fontSize: yaxisFontSize,
fontFamily: yaxisFontFamily,
fontWeight: yaxisFontWeight,
Expand Down Expand Up @@ -11950,7 +11975,7 @@
yaxis.forEach(function (y, index) {
var yaxe = w.config.yaxis[index]; // proceed only if user has specified alignment

if (yaxe && yaxe.labels.align !== undefined) {
if (yaxe && !yaxe.floating && yaxe.labels.align !== undefined) {
var yAxisInner = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis[rel='".concat(index, "'] .apexcharts-yaxis-texts-g"));
var yAxisTexts = w.globals.dom.baseEl.querySelectorAll(".apexcharts-yaxis[rel='".concat(index, "'] .apexcharts-yaxis-label"));
yAxisTexts = Utils$1.listToArray(yAxisTexts);
Expand Down Expand Up @@ -16136,6 +16161,19 @@

if (shared && ttItemsChildren[0]) {
// hide when no Val or series collapsed
if (w.config.tooltip.hideEmptyShared) {
var ttItemMarker = ttItems[t].querySelector('.apexcharts-tooltip-marker');
var ttItemText = ttItems[t].querySelector('.apexcharts-tooltip-text');

if (parseFloat(val) == 0) {
ttItemMarker.style.display = 'none';
ttItemText.style.display = 'none';
} else {
ttItemMarker.style.display = 'block';
ttItemText.style.display = 'block';
}
}

if (typeof val === 'undefined' || val === null || w.globals.ancillaryCollapsedSeriesIndices.indexOf(t) > -1 || w.globals.collapsedSeriesIndices.indexOf(t) > -1) {
ttItemsChildren[0].parentNode.style.display = 'none';
} else {
Expand Down Expand Up @@ -22968,9 +23006,10 @@
prevY = _ref3.prevY,
lineYPosition = _ref3.lineYPosition;
var w = this.w;
var stackSeries = w.config.chart.stacked && (!w.config.chart.stackOnlyBar || series[i] && series[i].type && series[i].type === 'bar');

if (typeof ((_series$i = series[i]) === null || _series$i === void 0 ? void 0 : _series$i[0]) !== 'undefined') {
if (w.config.chart.stacked) {
if (stackSeries) {
if (i > 0) {
// 1st y value of previous series
lineYPosition = this.lineCtx.prevSeriesY[i - 1][0];
Expand All @@ -22985,7 +23024,7 @@
prevY = lineYPosition - series[i][0] / this.lineCtx.yRatio[this.lineCtx.yaxisIndex] + (this.lineCtx.isReversed ? series[i][0] / this.lineCtx.yRatio[this.lineCtx.yaxisIndex] : 0) * 2;
} else {
// the first value in the current series is null
if (w.config.chart.stacked && i > 0 && typeof series[i][0] === 'undefined') {
if (stackSeries && i > 0 && typeof series[i][0] === 'undefined') {
// check for undefined value (undefined value will occur when we clear the series while user clicks on legend to hide serieses)
for (var s = i - 1; s >= 0; s--) {
// for loop to get to 1st previous value until we get it
Expand Down Expand Up @@ -23443,6 +23482,7 @@
}

var y2 = y;
var stackSeries = w.config.chart.stacked && (!this.w.config.chart.stackOnlyBar || this.w.config.series[realIndex] && this.w.config.series[realIndex].type && (this.w.config.series[realIndex].type === 'bar' || this.w.config.series[realIndex].type === ''));

for (var j = 0; j < iterations; j++) {
var isNull = typeof series[i][j + 1] === 'undefined' || series[i][j + 1] === null;
Expand All @@ -23460,7 +23500,7 @@
x = x + this.xDivision;
}

if (w.config.chart.stacked) {
if (stackSeries) {
if (i > 0 && w.globals.collapsedSeries.length < w.config.series.length - 1) {
// a collapsed series in a stacked bar chart may provide wrong result for the next series, hence find the prevIndex of prev series which is not collapsed - fixes apexcharts.js#1372
var prevIndex = function prevIndex(pi) {
Expand Down Expand Up @@ -24922,7 +24962,7 @@

var year = this._getYear(currentYear, month, yrCounter);

pos = hour === 0 && i === 0 ? remainingMins * minutesWidthOnXAxis : 60 * minutesWidthOnXAxis + pos;
pos = 60 * minutesWidthOnXAxis + pos;
var val = hour === 0 ? date : hour;
this.timeScaleArray.push({
position: pos,
Expand Down Expand Up @@ -32103,11 +32143,6 @@

me.grid = new Grid(me);
var elgrid = me.grid.drawGrid();

if (w.config.chart.type !== 'treemap') {
me.axes.drawAxis(w.config.chart.type, elgrid);
}

me.annotations = new Annotations(me);
me.annotations.drawImageAnnos();
me.annotations.drawTextAnnos();
Expand Down Expand Up @@ -32163,6 +32198,10 @@
me.annotations.drawAxesAnnotations();
}

if (w.config.chart.type !== 'treemap') {
me.axes.drawAxis(w.config.chart.type, elgrid);
}

if (!w.globals.noData) {
// draw tooltips at the end
if (w.config.tooltip.enabled && !w.globals.noData) {
Expand Down
6 changes: 3 additions & 3 deletions dist/apexcharts.min.js

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion src/charts/Line.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,15 @@ class Line {
}

let y2 = y

let stackSeries =
w.config.chart.stacked &&
(!this.w.config.chart.stackOnlyBar ||
(this.w.config.series[realIndex] &&
this.w.config.series[realIndex].type &&
(this.w.config.series[realIndex].type === 'bar' ||
this.w.config.series[realIndex].type === '')))

for (let j = 0; j < iterations; j++) {
const isNull =
typeof series[i][j + 1] === 'undefined' || series[i][j + 1] === null
Expand All @@ -505,7 +514,7 @@ class Line {
x = x + this.xDivision
}

if (w.config.chart.stacked) {
if (stackSeries) {
if (
i > 0 &&
w.globals.collapsedSeries.length < w.config.series.length - 1
Expand Down
6 changes: 4 additions & 2 deletions src/charts/common/line/Helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ export default class Helpers {

determineFirstPrevY({ i, series, prevY, lineYPosition }) {
let w = this.w
let stackSeries = w.config.chart.stacked && (!w.config.chart.stackOnlyBar || (series[i] && series[i].type && series[i].type === 'bar'));

if (typeof series[i]?.[0] !== 'undefined') {
if (w.config.chart.stacked) {
if (stackSeries) {
if (i > 0) {
// 1st y value of previous series
lineYPosition = this.lineCtx.prevSeriesY[i - 1][0]
Expand All @@ -126,7 +128,7 @@ export default class Helpers {
} else {
// the first value in the current series is null
if (
w.config.chart.stacked &&
stackSeries &&
i > 0 &&
typeof series[i][0] === 'undefined'
) {
Expand Down
26 changes: 16 additions & 10 deletions src/modules/Range.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,17 +530,23 @@ class Range {
let poss = 0
let negs = 0
for (let i = 0; i < gl.series.length; i++) {
if (gl.series[i][j] !== null && Utils.isNumber(gl.series[i][j])) {
// 0.0001 fixes #185 when values are very small
gl.series[i][j] > 0
? (poss = poss + parseFloat(gl.series[i][j]) + 0.0001)
: (negs = negs + parseFloat(gl.series[i][j]))
}
let stackSeries =
!this.w.config.chart.stackOnlyBar ||
(gl.series[i] && gl.series[i].type && gl.series[i].type === 'bar')

if (stackSeries) {
if (gl.series[i][j] !== null && Utils.isNumber(gl.series[i][j])) {
// 0.0001 fixes #185 when values are very small
gl.series[i][j] > 0
? (poss = poss + parseFloat(gl.series[i][j]) + 0.0001)
: (negs = negs + parseFloat(gl.series[i][j]))
}

if (i === gl.series.length - 1) {
// push all the totals to the array for future use
stackedPoss.push(poss)
stackedNegs.push(negs)
if (i === gl.series.length - 1) {
// push all the totals to the array for future use
stackedPoss.push(poss)
stackedNegs.push(negs)
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/modules/settings/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export default class Options {
},
stacked: false,
stackType: 'normal',
stackOnlyBar: true, // mixed chart with stacked bars and line series - incorrect line draw #907
toolbar: {
show: true,
offsetX: 0,
Expand Down Expand Up @@ -917,6 +918,7 @@ export default class Options {
enabled: true,
enabledOnSeries: undefined,
shared: true,
hideEmptyShared: true,
followCursor: false, // when disabled, the tooltip will show on top of the series instead of mouse position
intersect: false, // when enabled, tooltip will only show when user directly hovers over point
inverseOrder: false,
Expand Down
11 changes: 11 additions & 0 deletions src/modules/tooltip/Labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,17 @@ export default class Labels {

if (shared && ttItemsChildren[0]) {
// hide when no Val or series collapsed
if (w.config.tooltip.hideEmptyShared) {
let ttItemMarker = ttItems[t].querySelector('.apexcharts-tooltip-marker');
let ttItemText = ttItems[t].querySelector('.apexcharts-tooltip-text');
if (parseFloat(val) == 0) {
ttItemMarker.style.display = 'none';
ttItemText.style.display = 'none';
} else {
ttItemMarker.style.display = 'block';
ttItemText.style.display = 'block';
}
}
if (
typeof val === 'undefined' ||
val === null ||
Expand Down