diff --git a/samples/vanilla-js/column/border-radius-test.html b/samples/vanilla-js/column/border-radius-test.html
new file mode 100644
index 000000000..e17ed7263
--- /dev/null
+++ b/samples/vanilla-js/column/border-radius-test.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+ Border Radius Test - Stacked Column
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/apexcharts.css b/src/assets/apexcharts.css
index a558fc854..52b837a9e 100644
--- a/src/assets/apexcharts.css
+++ b/src/assets/apexcharts.css
@@ -681,3 +681,14 @@ rect.legend-mouseover-inactive,
.apexcharts-rangebar-goals-markers {
pointer-events: none
}
+
+.apexcharts-flip-y {
+ transform: scaleY(-1) translateY(-100%);
+ transform-origin: top;
+ transform-box: fill-box;
+}
+.apexcharts-flip-x {
+ transform: scaleX(-1);
+ transform-origin: center;
+ transform-box: fill-box;
+}
\ No newline at end of file
diff --git a/src/charts/Bar.js b/src/charts/Bar.js
index 976170156..f2911fb89 100644
--- a/src/charts/Bar.js
+++ b/src/charts/Bar.js
@@ -318,6 +318,7 @@ class Bar {
elBarShadows,
visibleSeries,
type,
+ classes,
}) {
const w = this.w
const graphics = new Graphics(this.ctx)
@@ -379,7 +380,7 @@ class Bar {
animationDelay: delay,
initialSpeed: w.config.chart.animations.speed,
dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
- className: `apexcharts-${type}-area`,
+ className: `apexcharts-${type}-area ${classes}`,
chartType: type,
})
diff --git a/src/charts/BarStacked.js b/src/charts/BarStacked.js
index b6ba8c55f..4cd1dae6b 100644
--- a/src/charts/BarStacked.js
+++ b/src/charts/BarStacked.js
@@ -119,10 +119,8 @@ class BarStacked extends Bar {
}
for (let j = 0; j < w.globals.dataPoints; j++) {
- const strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex)
const commonPathOpts = {
indexes: { i, j, realIndex, translationsIndex, bc },
- strokeWidth,
x,
y,
elSeries,
@@ -169,6 +167,23 @@ class BarStacked extends Bar {
let pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex)
+ let classes = ''
+
+ if (w.globals.isBarHorizontal) {
+ if (
+ this.barHelpers.arrBorderRadius[realIndex][j] === 'bottom' &&
+ w.globals.series[realIndex][j] > 0
+ ) {
+ classes = 'apexcharts-flip-x'
+ }
+ } else {
+ if (
+ this.barHelpers.arrBorderRadius[realIndex][j] === 'bottom' &&
+ w.globals.series[realIndex][j] > 0
+ ) {
+ classes = 'apexcharts-flip-y'
+ }
+ }
elSeries = this.renderSeries({
realIndex,
pathFill,
@@ -177,7 +192,7 @@ class BarStacked extends Bar {
columnGroupIndex,
pathFrom: paths.pathFrom,
pathTo: paths.pathTo,
- strokeWidth,
+ strokeWidth: this.barHelpers.getStrokeWidth(i, j, realIndex),
elSeries,
x,
y,
@@ -188,6 +203,7 @@ class BarStacked extends Bar {
elGoalsMarkers,
type: 'bar',
visibleSeries: columnGroupIndex,
+ classes,
})
}
@@ -291,7 +307,6 @@ class BarStacked extends Bar {
drawStackedBarPaths({
indexes,
barHeight,
- strokeWidth,
zeroW,
x,
y,
@@ -355,7 +370,6 @@ class BarStacked extends Bar {
barHeight,
x1: barXPosition,
x2: x,
- strokeWidth,
series: this.series,
realIndex: indexes.realIndex,
seriesGroup,
@@ -518,7 +532,6 @@ class BarStacked extends Bar {
y1: barYPosition,
y2: y,
yRatio: this.yRatio[translationsIndex],
- strokeWidth: this.strokeWidth,
series: this.series,
seriesGroup,
realIndex: indexes.realIndex,
diff --git a/src/charts/Line.js b/src/charts/Line.js
index b56c5dc16..9e1172477 100644
--- a/src/charts/Line.js
+++ b/src/charts/Line.js
@@ -953,8 +953,8 @@ class Line {
// Check for single isolated point
if (series[i][j + 1] === null) {
- linePaths.push(linePath);
- areaPaths.push(areaPath);
+ linePaths.push(linePath)
+ areaPaths.push(areaPath)
// Stay in pathState = 0;
break
}
@@ -1042,8 +1042,8 @@ class Line {
// Check for single isolated point
if (series[i][j + 1] === null) {
- linePaths.push(linePath);
- areaPaths.push(areaPath);
+ linePaths.push(linePath)
+ areaPaths.push(areaPath)
// Stay in pathState = 0
break
}
diff --git a/src/charts/common/bar/Helpers.js b/src/charts/common/bar/Helpers.js
index e098fea44..242667ac1 100644
--- a/src/charts/common/bar/Helpers.js
+++ b/src/charts/common/bar/Helpers.js
@@ -37,7 +37,7 @@ export default class Helpers {
}
}
- this.arrBorderRadius = this.createBorderRadiusArr(w.globals.seriesPercent)
+ this.arrBorderRadius = this.createBorderRadiusArr(w.globals.series)
if (this.barCtx.seriesLen === 0) {
// A small adjustment when combo charts are used
@@ -227,10 +227,7 @@ export default class Helpers {
let strokeWidth = 0
const w = this.w
- if (
- typeof this.barCtx.series[i][j] === 'undefined' ||
- this.barCtx.series[i][j] === null
- ) {
+ if (!this.barCtx.series[i][j]) {
this.barCtx.isNullValue = true
} else {
this.barCtx.isNullValue = false
@@ -245,7 +242,7 @@ export default class Helpers {
return strokeWidth
}
- createBorderRadiusArr(seriesPercent) {
+ createBorderRadiusArr(series) {
const w = this.w
const alwaysApplyRadius =
@@ -253,29 +250,97 @@ export default class Helpers {
w.config.plotOptions.bar.borderRadiusWhenStacked !== 'last' ||
w.config.plotOptions.bar.borderRadius <= 0
- const numRows = seriesPercent.length
- const numCols = seriesPercent[0].length
-
- const resultArr = Array.from({ length: numRows }, () =>
- Array.from({ length: numCols }, () => alwaysApplyRadius)
+ const numSeries = series.length
+ const numColumns = series[0].length
+ const output = Array.from({ length: numSeries }, () =>
+ Array(numColumns).fill(alwaysApplyRadius ? 'top' : 'none')
)
- if (alwaysApplyRadius) return resultArr
+ if (alwaysApplyRadius) return output
+
+ for (let j = 0; j < numColumns; j++) {
+ let positiveIndices = []
+ let negativeIndices = []
+ let nonZeroCount = 0
+
+ // Collect positive and negative indices
+ for (let i = 0; i < numSeries; i++) {
+ const value = series[i][j]
+ if (value > 0) {
+ positiveIndices.push(i)
+ nonZeroCount++
+ } else if (value < 0) {
+ negativeIndices.push(i)
+ nonZeroCount++
+ }
+ }
- // For each column
- for (let j = 0; j < numCols; j++) {
- // Iterate from the last row upwards
- for (let i = numRows - 1, found = false; i >= 0; i--) {
- if (!found && seriesPercent[i][j] !== 0) {
- resultArr[i][j] = true
- found = true
+ if (positiveIndices.length > 0 && negativeIndices.length === 0) {
+ // Only positive values in this column
+ if (positiveIndices.length === 1) {
+ // Single positive value
+ output[positiveIndices[0]][j] = 'both'
} else {
- resultArr[i][j] = false
+ // Multiple positive values
+ const firstPositiveIndex = positiveIndices[0]
+ const lastPositiveIndex = positiveIndices[positiveIndices.length - 1]
+ for (let i of positiveIndices) {
+ if (i === firstPositiveIndex) {
+ output[i][j] = 'bottom'
+ } else if (i === lastPositiveIndex) {
+ output[i][j] = 'top'
+ } else {
+ output[i][j] = 'none'
+ }
+ }
+ }
+ } else if (negativeIndices.length > 0 && positiveIndices.length === 0) {
+ // Only negative values in this column
+ if (negativeIndices.length === 1) {
+ // Single negative value
+ output[negativeIndices[0]][j] = 'both'
+ } else {
+ // Multiple negative values
+ const firstNegativeIndex = negativeIndices[0]
+ const lastNegativeIndex = negativeIndices[negativeIndices.length - 1]
+ for (let i of negativeIndices) {
+ if (i === firstNegativeIndex) {
+ output[i][j] = 'bottom'
+ } else if (i === lastNegativeIndex) {
+ output[i][j] = 'top'
+ } else {
+ output[i][j] = 'none'
+ }
+ }
}
+ } else if (positiveIndices.length > 0 && negativeIndices.length > 0) {
+ // Mixed positive and negative values
+ // Assign 'top' to the last positive bar
+ const lastPositiveIndex = positiveIndices[positiveIndices.length - 1]
+ for (let i of positiveIndices) {
+ if (i === lastPositiveIndex) {
+ output[i][j] = 'top'
+ } else {
+ output[i][j] = 'none'
+ }
+ }
+ // Assign 'bottom' to the last negative bar (closest to axis)
+ const lastNegativeIndex = negativeIndices[negativeIndices.length - 1]
+ for (let i of negativeIndices) {
+ if (i === lastNegativeIndex) {
+ output[i][j] = 'bottom'
+ } else {
+ output[i][j] = 'none'
+ }
+ }
+ } else if (nonZeroCount === 1) {
+ // Only one non-zero value (either positive or negative)
+ const index = positiveIndices[0] || negativeIndices[0]
+ output[index][j] = 'both'
}
}
- return resultArr
+ return output
}
barBackground({ j, i, x1, x2, y1, y2, elSeries }) {
@@ -313,7 +378,6 @@ export default class Helpers {
barXPosition,
y1,
y2,
- strokeWidth,
seriesGroup,
realIndex,
i,
@@ -321,10 +385,6 @@ export default class Helpers {
w,
}) {
const graphics = new Graphics(this.barCtx.ctx)
- strokeWidth = Array.isArray(strokeWidth)
- ? strokeWidth[realIndex]
- : strokeWidth
- if (!strokeWidth) strokeWidth = 0
let bW = barWidth
let bXP = barXPosition
@@ -335,15 +395,12 @@ export default class Helpers {
bW = barWidth + w.config.series[realIndex].data[j].columnWidthOffset
}
- // Center the stroke on the coordinates
- let strokeCenter = strokeWidth / 2
-
- const x1 = bXP + strokeCenter
- const x2 = bXP + bW - strokeCenter
+ const x1 = bXP
+ const x2 = bXP + bW
// append tiny pixels to avoid exponentials (which cause issues in border-radius)
- y1 += 0.001 - strokeCenter
- y2 += 0.001 + strokeCenter
+ y1 += 0.001
+ y2 += 0.001
let pathTo = graphics.move(x1, y1)
let pathFrom = graphics.move(x1, y1)
@@ -357,8 +414,9 @@ export default class Helpers {
pathTo +
graphics.line(x1, y2) +
graphics.line(x2, y2) +
- graphics.line(x2, y1) +
- (w.config.plotOptions.bar.borderRadiusApplication === 'around'
+ sl +
+ (w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
+ this.arrBorderRadius[realIndex][j] === 'both'
? ' Z'
: ' z')
@@ -373,11 +431,12 @@ export default class Helpers {
sl +
sl +
graphics.line(x1, y1) +
- (w.config.plotOptions.bar.borderRadiusApplication === 'around'
+ (w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
+ this.arrBorderRadius[realIndex][j] === 'both'
? ' Z'
: ' z')
- if (this.arrBorderRadius[realIndex][j]) {
+ if (this.arrBorderRadius[realIndex][j] !== 'none') {
pathTo = graphics.roundPathCorners(
pathTo,
w.config.plotOptions.bar.borderRadius
@@ -387,8 +446,8 @@ export default class Helpers {
if (w.config.chart.stacked) {
let _ctx = this.barCtx
_ctx = this.barCtx[seriesGroup]
- _ctx.yArrj.push(y2 - strokeCenter)
- _ctx.yArrjF.push(Math.abs(y1 - y2 + strokeWidth))
+ _ctx.yArrj.push(y2)
+ _ctx.yArrjF.push(Math.abs(y1 - y2))
_ctx.yArrjVal.push(this.barCtx.series[i][j])
}
@@ -403,7 +462,6 @@ export default class Helpers {
barHeight,
x1,
x2,
- strokeWidth,
seriesGroup,
realIndex,
i,
@@ -411,10 +469,6 @@ export default class Helpers {
w,
}) {
const graphics = new Graphics(this.barCtx.ctx)
- strokeWidth = Array.isArray(strokeWidth)
- ? strokeWidth[realIndex]
- : strokeWidth
- if (!strokeWidth) strokeWidth = 0
let bYP = barYPosition
let bH = barHeight
@@ -425,15 +479,12 @@ export default class Helpers {
bH = barHeight + w.config.series[realIndex].data[j].barHeightOffset
}
- // Center the stroke on the coordinates
- let strokeCenter = strokeWidth / 2
-
- const y1 = bYP + strokeCenter
- const y2 = bYP + bH - strokeCenter
+ const y1 = bYP
+ const y2 = bYP + bH
// append tiny pixels to avoid exponentials (which cause issues in border-radius)
- x1 += 0.001 - strokeCenter
- x2 += 0.001 + strokeCenter
+ x1 += 0.001
+ x2 += 0.001
let pathTo = graphics.move(x1, y1)
let pathFrom = graphics.move(x1, y1)
@@ -448,7 +499,8 @@ export default class Helpers {
graphics.line(x2, y1) +
graphics.line(x2, y2) +
sl +
- (w.config.plotOptions.bar.borderRadiusApplication === 'around'
+ (w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
+ this.arrBorderRadius[realIndex][j] === 'both'
? ' Z'
: ' z')
@@ -461,11 +513,12 @@ export default class Helpers {
sl +
sl +
graphics.line(x1, y1) +
- (w.config.plotOptions.bar.borderRadiusApplication === 'around'
+ (w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
+ this.arrBorderRadius[realIndex][j] === 'both'
? ' Z'
: ' z')
- if (this.arrBorderRadius[realIndex][j]) {
+ if (this.arrBorderRadius[realIndex][j] !== 'none') {
pathTo = graphics.roundPathCorners(
pathTo,
w.config.plotOptions.bar.borderRadius
@@ -475,7 +528,7 @@ export default class Helpers {
if (w.config.chart.stacked) {
let _ctx = this.barCtx
_ctx = this.barCtx[seriesGroup]
- _ctx.xArrj.push(x2 + strokeCenter)
+ _ctx.xArrj.push(x2)
_ctx.xArrjF.push(Math.abs(x1 - x2))
_ctx.xArrjVal.push(this.barCtx.series[i][j])
}
@@ -666,7 +719,8 @@ export default class Helpers {
graphics.line(currX2, currY1) +
graphics.line(currX1, currY1) +
graphics.line(prevX1, prevY2) +
- (w.config.plotOptions.bar.borderRadiusApplication === 'around'
+ (w.config.plotOptions.bar.borderRadiusApplication === 'around' ||
+ this.arrBorderRadius[realIndex][j] === 'both'
? ' Z'
: ' z')
diff --git a/src/modules/Range.js b/src/modules/Range.js
index f744967ce..2c2966383 100644
--- a/src/modules/Range.js
+++ b/src/modules/Range.js
@@ -279,7 +279,10 @@ class Range {
gl.minY = lowestYInAllSeries
}
} else {
- gl.minY = minYMaxY.minY
+ gl.minY =
+ gl.minY !== Number.MIN_VALUE
+ ? Math.min(minYMaxY.minY, gl.minY)
+ : minYMaxY.minY
}
cnf.yaxis.forEach((yaxe, index) => {