I'm creating an individual chart based on HTML canvas. I want to draw negative and positive values in other colors but can't achieve it so far.
Here is my actual chart:
Here is what I want to achieve:
I can think of two solutions. Either I can draw it with a gradient that only goes down to zero.
Or each positive and each negative surface is drawn separately. But then I still need the intersections.
Here are my original values:
[
{ "x": 0, "y": 750 },
{ "x": 1, "y": -200 },
{ "x": 2, "y": 60 },
{ "x": 3, "y": 60 },
{ "x": 4, "y": 120 },
{ "x": 5, "y": 505 }
]
Here are my transformed pixel values:
[
{ "x": 0, "y": 236}, // to draw the area
{ "x": 0, "y": 0},
{ "x": 173, "y": 300},
{ "x": 346, "y": 217},
{ "x": 519, "y": 217},
{ "x": 692, "y": 198},
{ "x": 865, "y": 77},
{ "x": 865, "y": 236} // to draw the area
]
Do you have an idea of how the goal can be realized? Thank you!
I had some fun making a basic chart renderer using the canvas. I hope you find the following code useful. (if something is unclear don't hesitate to ask)
const c = document.getElementById("mycanvas");
const cc = c.getContext("2d");
const points = [
750, -200, 60, 60, 120, 505
];
const maxY = Math.max(...points);
const minY = Math.min(...points);
//used to scale and fit the graph into the canvas
const xaxis = (maxY / (maxY - minY)) * c.height;
const yscale = -c.height / (maxY - minY);
const xscale = c.width / (points.length - 1);
const poscolor = "cornflowerblue";
const negcolor = "crimson";
cc.fillStyle = points[0] >= 0 ? poscolor : negcolor;
//start at (0, 0) and line to first point
cc.beginPath();
cc.moveTo(0, xaxis);
cc.lineTo(0, points[0] * yscale + xaxis);
for (let i = 1; i < points.length; i++) {
const a = {
x: i - 1,
y: points[i - 1]
};
const b = {
x: i,
y: points[i]
};
//if a.y and b.y have different sign, the line will intersect the x-axis
if (a.y * b.y < 0) {
//calculate intersection (point on x-axis)
const intersection = -a.y / (b.y - a.y);
const intersectionPoint = (a.x + intersection) * xscale;
//complete the current shape
cc.lineTo(intersectionPoint, xaxis);
cc.fill();
//start a new shape for the other side of the x-axis
cc.fillStyle = b.y >= 0 ? poscolor : negcolor;
cc.beginPath();
cc.moveTo(intersectionPoint, xaxis);
}
//continue the shape to point b
cc.lineTo(b.x * xscale, b.y * yscale + xaxis);
}
//draw a line back to the x-axis and finish the shape
cc.lineTo((points.length - 1) * xscale, xaxis);
cc.fill();
canvas {
background-color: ivory;
border: 2px solid darkgray;
}
<!DOCTYPE html>
<html>
<body>
<canvas id="mycanvas" width=500 height=200></canvas>
</body>
</html>