Как я могу нарисовать линию к самой высокой точке данных на графике js? - PullRequest
0 голосов
/ 11 декабря 2018

Я употреблял документацию по Chart JS, но думаю, что это скорее вопрос информатики / математики, основанный на вопросе.Я пытаюсь нарисовать линию, которая проходит от нижней части моего графика к вершине самой высокой точки данных.Вот ссылка на пример рабочего кода: https://stackblitz.com/edit/react-pvzbwc

Идея состоит в том, чтобы диаграмма выглядела примерно так, где точка заканчивается точно в верхней части данных: https://i.stack.imgur.com/L8d0H.jpg

Вот что у меня есть для моего крюка после прорисовки:

// draw a line when someone hovers over a data point
afterDatasetDraw: (chart) => {
          // console.log(chart)
          if (chart.tooltip._active && chart.tooltip._active.length) {
            const activePoint = chart.tooltip._active[0];
            console.log(activePoint.tooltipPosition())
            const ctx = chart.ctx;
            const y_axis = chart.scales['y-axis-0'];
            const x = activePoint.tooltipPosition().x;
            const yData = activePoint._chart.config.data.datasets[activePoint._datasetIndex].data[activePoint._index].y;

            const topY = y_axis.top;
            const bottomY = y_axis.bottom;
            // draw line
            ctx.save();
            ctx.beginPath();
            ctx.moveTo(x, topY);
            ctx.lineTo(x, bottomY);
            ctx.lineWidth = 2;
            ctx.strokeStyle = '#000';
            ctx.stroke();
            ctx.restore();
         }
        }

Это работает довольно хорошо, когда мне нужно нарисовать линию вверх через верх, но не тогда, когда я хочу просто увидеть ее сверхусамого высокого назначения данных.Я заметил, что topY является статическим неизменным числом.Мне интересно, есть ли способ, которым я могу рассчитать верхнюю позицию, основываясь на декартовых точках графика?

Любое понимание определенно приветствуется.

1 Ответ

0 голосов
/ 11 декабря 2018

После некоторой борьбы я ответил на вопрос.Это было намного проще, чем я решил.Оказывается, мне просто нужно было вычислить соотношение между точками данных и графиком в пикселях, а затем реализовать линию в этой точке.

Я поместил это в плагин сAPI:

/// default values
lineHeightAnnotation: {
  // defaults to have line to the highest data point on every tick
  always: true,
  // optionally, only have line draw to the highest datapoint nearest the user's hover position
  hover: false,
  // colors of the line
  color: '#000',
  // name of yAxis
  yAxis: 'y-axis-0',
  // weight of the line
  lineWeight: 1.5,
   /// sets shadow for ALL lines on the canvas
  shadow: {
    // color of the shadow
    color: 'rgba(0,0,0,0.35)',
    // blur of the shadow
    blur: 10,
    /// shadow offset
    offset: {
      // x offset
      x: 0,
      // y offset
      y: 3
    }
  },
  // dash defaults at [10, 10]
  noDash: true,
}

Логика:

/**
 * Vars
 * maxY - the tallest data point on the graph
 * tickMax - the tallest tick on the y axis
 * bottomY - the lowest point of the graph
 * additionalOffsets = dataset.borderWidth * 2
 * 
 *                               bottomY * maxY      
 * highestDataY =   bottomY -  -------------------   + additionOffsets
 *                                   tickMax
 */

Функция:

   afterDatasetDraw: (chart) => {
      // draw a dashed line when someone hovers over a data point
      if (chart.tooltip._active && chart.tooltip._active.length) {
        const activePoint = chart.tooltip._active[0];
        const ctx = chart.ctx;

        const x = activePoint.tooltipPosition().x;
        const yAxis = chart.scales['y-axis-0'];

        const tickMax = yAxis.ticksAsNumbers[0] // first index is always the tallest
        const tickLow = yAxis.ticksAsNumbers[yAxis.ticksAsNumbers.length - 1]
        const topY = yAxis.top; // clientRect.top + chart.padding.y
        const bottomY = yAxis.bottom; // clientRect.bottom

        let maxY = 1;
        let borderWidth = 0;
        const datasets = chart.config.data.datasets
        datasets.forEach((set, i) => {
          // get maximum Y value
          // get borderWidth of that dataset
          let point = set.data[activePoint._index].y
          if(point > maxY) {
            maxY = parseInt(point, 10) - parseInt(set.borderWidth, 10)
            borderWidth = parseInt(set.borderWidth, 10)
          }
        });

        let yBRatio = bottomY * (maxY - tickLow)
        let tMRatio = yBRatio / (tickMax - tickLow)
        let highestDataY = bottomY - tMRatio + (borderWidth * 2)

        // draw line
        ctx.save();
        ctx.beginPath();
        ctx.setLineDash([10, 10]);
        ctx.moveTo(x, highestDataY);
        ctx.lineTo(x, bottomY);
        ctx.lineWidth = 1.5;
        ctx.strokeStyle = '#000';
        ctx.stroke();
        ctx.restore();
      }
...