Skip to content

Commit

Permalink
RangeArea fix for straight lines with nulls in data
Browse files Browse the repository at this point in the history
Together with previously merged changes includes curve types:
straight, stepline, linestep, smooth

Refactored the curve-specific branches in Line.createPaths()
  • Loading branch information
rosco54 committed Mar 31, 2024
1 parent b74469d commit b6c4bdd
Showing 1 changed file with 127 additions and 121 deletions.
248 changes: 127 additions & 121 deletions src/charts/Line.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ class Line {
isRangeStart: false,
})

if (w.globals.hasNullValues && w.config.stroke.curve === 'smooth') {
// Path segmented by nulls in data.
if (w.globals.hasNullValues || w.config.forecastDataPoints.count) {
// Path may be segmented by nulls in data.
// paths.linePaths should hold (segments * 2) paths (upper and lower)
// the first n segments belong to the lower and the last n segments
// belong to the upper.
Expand Down Expand Up @@ -787,6 +787,8 @@ class Line {
curve = 'straight'
}

let isLowerRangeAreaPath = (type === 'rangeArea' && isRangeStart)

switch (curve) {
case 'monotoneCubic':
const shouldRenderMonotone =
Expand Down Expand Up @@ -848,148 +850,152 @@ class Line {
break
case 'smooth':
let length = (x - pX) * 0.35
if (w.globals.hasNullValues) {
if (series[i][j] === null) {
pathState = 0
} else {
switch (pathState) {
case 0:
// Beginning of segment
segmentStartX = pX
if (type === 'rangeArea' && isRangeStart) {
linePath =
graphics.move(pX, y2Arrj[j])
+ graphics.line(pX, pY)
} else {
linePath = graphics.move(pX, pY)
}
linePath +=
graphics.curve(pX + length, pY, x - length, y, x, y)
areaPath =
graphics.move(pX + 1, pY)
+ graphics.curve(pX + length, pY, x - length, y, x, y)
pathState = 1
break
case 1:
// Continuing with segment
if (series[i][j + 1] === null) {
// Segment ends here
if (type === 'rangeArea' && isRangeStart) {
linePath += graphics.line(pX, y2)
if (series[i][j] === null) {
pathState = 0
} else {
switch (pathState) {
case 0:
// Beginning of segment
segmentStartX = pX
if (isLowerRangeAreaPath) {
// Need to add path portion that will join to the upper path
linePath =
graphics.move(pX, y2Arrj[j])
+ graphics.line(pX, pY)
} else {
linePath = graphics.move(pX, pY)
}
areaPath = graphics.move(pX, pY)

let p = graphics.curve(pX + length, pY, x - length, y, x, y)
linePath += p
areaPath += p
pathState = 1
break
case 1:
// Continuing with segment
if (series[i][j + 1] === null) {
// Segment ends here
if (isLowerRangeAreaPath) {
linePath += graphics.line(pX, y2)
} else {
linePath += graphics.move(pX, pY)
}
areaPath +=
graphics.line(pX, areaBottomY)
+ graphics.line(segmentStartX, areaBottomY)
+ 'z'
linePaths.push(linePath)
areaPaths.push(areaPath)
} else {
let p = graphics.curve(pX + length, pY, x - length, y, x, y)
linePath += p
areaPath += p
if (j >= series[i].length - 2) {
if (isLowerRangeAreaPath) {
// Need to add path portion that will join to the upper path
linePath +=
graphics.curve(x, y, x, y, x, y2)
+ graphics.move(x, y2)
} else {
linePath += graphics.move(pX, pY)
linePath +=
graphics.move(x, y)
}
areaPath +=
graphics.line(pX, areaBottomY)
graphics.curve(x, y, x, y, x, areaBottomY)
+ graphics.line(segmentStartX, areaBottomY)
+ 'z'
linePaths.push(linePath)
areaPaths.push(areaPath)
} else {
linePath +=
graphics.curve(pX + length, pY, x - length, y, x, y)
areaPath +=
graphics.curve(pX + length, pY, x - length, y, x, y)
if (j >= series[i].length - 2) {
if (type === 'rangeArea' && isRangeStart) {
linePath +=
graphics.curve(x, y, x, y, x, y2)
+ graphics.move(x, y2)
} else {
linePath +=
graphics.move(x, y)
}
areaPath +=
graphics.curve(x, y, x, y, x, areaBottomY)
+ graphics.move(x, y)
+ 'z'
linePaths.push(linePath)
areaPaths.push(areaPath)
}
}
break
}
break
}
} else {
linePath +=
graphics.curve(pX + length, pY, x - length, y, x, y)
areaPath +=
graphics.curve(pX + length, pY, x - length, y, x, y)
}

pX = x
pY = y

if (j === series[i].length - 2) {
// last loop, close path
areaPath +=
graphics.curve(pX, pY, x, y, x, areaBottomY) +
graphics.move(x, y) +
'z'

if (type === 'rangeArea' && isRangeStart) {
linePath +=
graphics.curve(pX, pY, x, y, x, y2) +
graphics.move(x, y2) +
'z'
} else {
if (!w.globals.hasNullValues) {
linePaths.push(linePath)
areaPaths.push(areaPath)
}
}
}
break
default:
if (series[i][j + 1] === null) {
linePath = linePath + graphics.move(x, y)

const numericOrCatX = w.globals.isXNumeric
? (w.globals.seriesX[realIndex][j] - w.globals.minX) / this.xRatio
: x - this.xDivision
areaPath =
areaPath +
graphics.line(numericOrCatX, areaBottomY) +
graphics.move(x, y) +
'z'
let graphPath = (curve, x, y) => {
let path = []
switch (curve) {
case 'stepline':
path = graphics.line(x, null, 'H') + graphics.line(null, y, 'V')
break
case 'linestep':
path = graphics.line(null, y, 'V') + graphics.line(x, null, 'H')
break
case 'straight':
path = graphics.line(x, y)
break
}
return path
}
if (series[i][j] === null) {
linePath = linePath + graphics.move(x, y)
areaPath = areaPath + graphics.move(x, areaBottomY)
}
pathState = 0
} else {
switch (pathState) {
case 0:
// Beginning of segment
segmentStartX = pX
if (isLowerRangeAreaPath) {
// Need to add path portion that will join to the upper path
linePath =
graphics.move(pX, y2Arrj[j])
+ graphics.line(pX, pY)
} else {
linePath = graphics.move(pX, pY)
}
areaPath = graphics.move(pX, pY)

switch (curve) {
case 'stepline':
linePath =
linePath + graphics.line(x, null, 'H') + graphics.line(null, y, 'V')
areaPath =
areaPath + graphics.line(x, null, 'H') + graphics.line(null, y, 'V')
break
case 'linestep':
linePath =
linePath + graphics.line(null, y, 'V') + graphics.line(x, null, 'H')
areaPath =
areaPath + graphics.line(null, y, 'V') + graphics.line(x, null, 'H')
break
case 'straight':
linePath = linePath + graphics.line(x, y)
areaPath = areaPath + graphics.line(x, y)
break
let p = graphPath(curve, x, y)
linePath += p
areaPath += p
pathState = 1
break
case 1:
// Continuing with segment
if (series[i][j + 1] === null) {
// Segment ends here
if (isLowerRangeAreaPath) {
linePath += graphics.line(pX, y2)
} else {
linePath += graphics.move(pX, pY)
}
areaPath +=
graphics.line(pX, areaBottomY)
+ graphics.line(segmentStartX, areaBottomY)
+ 'z'
linePaths.push(linePath)
areaPaths.push(areaPath)
} else {
let p = graphPath(curve, x, y)
linePath += p
areaPath += p
if (j >= series[i].length - 2) {
if (isLowerRangeAreaPath) {
// Need to add path portion that will join to the upper path
linePath += graphics.line(x, y2)
} else {
linePath += graphics.move(x, y)
}
areaPath +=
graphics.line(x, areaBottomY)
+ graphics.line(segmentStartX, areaBottomY)
+ 'z'
linePaths.push(linePath)
areaPaths.push(areaPath)
}
}
break
}
}

if (j === series[i].length - 2) {
// last loop, close path
areaPath =
areaPath + graphics.line(x, areaBottomY) + graphics.move(x, y) + 'z'
pX = x
pY = y

if (type === 'rangeArea' && isRangeStart) {
linePath =
linePath + graphics.line(x, y2) + graphics.move(x, y2) + 'z'
} else {
linePaths.push(linePath)
areaPaths.push(areaPath)
}
}
break
}

Expand Down

0 comments on commit b6c4bdd

Please sign in to comment.