рисовать на html холсте отрицательные и положительные области - PullRequest
1 голос
/ 03 августа 2020

Я создаю индивидуальную диаграмму на основе HTML холста. Я хочу нарисовать отрицательные и положительные значения другими цветами, но пока не могу этого добиться.

Вот моя фактическая диаграмма:

enter image description here

Here is what I want to achieve:

введите описание изображения здесь

Я могу придумать два решения. Либо я могу нарисовать его градиентом, который уменьшается только до нуля.

Либо каждая положительная и каждая отрицательная поверхность рисуется отдельно. Но тогда мне все еще нужны пересечения.

Вот мои исходные значения:

[
  { "x": 0, "y": 750 },
  { "x": 1, "y": -200 },
  { "x": 2, "y": 60 },
  { "x": 3, "y": 60 },
  { "x": 4, "y": 120 },
  { "x": 5, "y": 505 }
]

Вот мои преобразованные значения пикселей:

[
  { "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
]

У вас есть идея как можно реализовать цель? Спасибо!

1 Ответ

2 голосов
/ 03 августа 2020

Я немного повеселился, создав базовый c рендерер диаграмм с использованием холста. Надеюсь, следующий код будет вам полезен. (если что-то непонятно, спрашивайте)

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>
...