Chart.js -绘制任意垂直线

cbwuti44  于 2022-11-06  发布在  Chart.js
关注(0)|答案(7)|浏览(261)

如何使用Chart.js在x轴上的特定点绘制垂直线?
特别是,我想要在缐条图上绘制一条缐条来表示当天。以下是图表的模型:http://i.stack.imgur.com/VQDWR.png

oxosxuxt

oxosxuxt1#

更新-此答案适用于Chart.js 1.x,如果您正在寻找2.x版本的答案,请查看评论和其他答案。

您可以扩展折线图,并在draw函数中包含用于绘制折线的逻辑。

预览

HTML格式

<div>
    <canvas id="LineWithLine" width="600" height="400"></canvas>
</div>

脚本

var data = {
    labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
    datasets: [{
        data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
    }]
};

var ctx = document.getElementById("LineWithLine").getContext("2d");

Chart.types.Line.extend({
    name: "LineWithLine",
    draw: function () {
        Chart.types.Line.prototype.draw.apply(this, arguments);

        var point = this.datasets[0].points[this.options.lineAtIndex]
        var scale = this.scale

        // draw line
        this.chart.ctx.beginPath();
        this.chart.ctx.moveTo(point.x, scale.startPoint + 24);
        this.chart.ctx.strokeStyle = '#ff0000';
        this.chart.ctx.lineTo(point.x, scale.endPoint);
        this.chart.ctx.stroke();

        // write TODAY
        this.chart.ctx.textAlign = 'center';
        this.chart.ctx.fillText("TODAY", point.x, scale.startPoint + 12);
    }
});

new Chart(ctx).LineWithLine(data, {
    datasetFill : false,
    lineAtIndex: 2
});

选项属性lineAtIndex控制要在哪一点绘制直线。
小提琴-http://jsfiddle.net/dbyze2ga/14/

ogq8wdun

ogq8wdun2#

分享我的chartjs.org版本2.5的解决方案。我想使用一个插件,使实现可重用。

const verticalLinePlugin = {
  getLinePosition: function (chart, pointIndex) {
      const meta = chart.getDatasetMeta(0); // first dataset is used to discover X coordinate of a point
      const data = meta.data;
      return data[pointIndex]._model.x;
  },
  renderVerticalLine: function (chartInstance, pointIndex) {
      const lineLeftOffset = this.getLinePosition(chartInstance, pointIndex);
      const scale = chartInstance.scales['y-axis-0'];
      const context = chartInstance.chart.ctx;

      // render vertical line
      context.beginPath();
      context.strokeStyle = '#ff0000';
      context.moveTo(lineLeftOffset, scale.top);
      context.lineTo(lineLeftOffset, scale.bottom);
      context.stroke();

      // write label
      context.fillStyle = "#ff0000";
      context.textAlign = 'center';
      context.fillText('MY TEXT', lineLeftOffset, (scale.bottom - scale.top) / 2 + scale.top);
  },

  afterDatasetsDraw: function (chart, easing) {
      if (chart.config.lineAtIndex) {
          chart.config.lineAtIndex.forEach(pointIndex => this.renderVerticalLine(chart, pointIndex));
      }
  }
  };

  Chart.plugins.register(verticalLinePlugin);

用法很简单:

new Chart(ctx, {
     type: 'line',
     data: data,
     label: 'Progress',
     options: options,
     lineAtIndex: [2,4,8],
 })

上面的代码在位置2、4和8处插入红色垂直线,穿过这些位置处的第一个数据集的点。

mbskvtky

mbskvtky3#

我强烈推荐使用Chartjs-Plugin-Annotation
可在CodePen中找到示例

var chartData = {
  labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
  datasets: [
    {
      data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
    }
  ]
};

window.onload = function() {
  var ctx = document.getElementById("canvas").getContext("2d");
  new Chart(ctx, {
    type: "line",
    data: chartData,
    options: {
      annotation: {
        annotations: [
          {
            type: "line",
            mode: "vertical",
            scaleID: "x-axis-0",
            value: "MAR",
            borderColor: "red",
            label: {
              content: "TODAY",
              enabled: true,
              position: "top"
            }
          }
        ]
      }
    }
  });
};

请点击此处了解更多详情:https://stackoverflow.com/a/36431041

0md85ypi

0md85ypi4#

我不得不经历麻烦,弄清楚如何用ChartJS 2. 0做类似的事情,所以我想我会分享。
这是基于重写图表原型的新方法,如下所述:https://github.com/chartjs/Chart.js/issues/2321

var ctx = document.getElementById('income-chart');

var originalDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function (ease) {
    originalDraw.call(this, ease);

    var point = dataValues[vm.incomeCentile];
    var scale = this.chart.scales['x-axis-0'];

    // calculate the portion of the axis and multiply by total axis width
    var left = (point.x / scale.end * (scale.right - scale.left));

    // draw line
    this.chart.chart.ctx.beginPath();
    this.chart.chart.ctx.strokeStyle = '#ff0000';
    this.chart.chart.ctx.moveTo(scale.left + left, 0);
    this.chart.chart.ctx.lineTo(scale.left + left, 1000000);
    this.chart.chart.ctx.stroke();

    // write label
    this.chart.chart.ctx.textAlign = 'center';
    this.chart.chart.ctx.fillText('YOU', scale.left + left, 200);
};
xytpbqjk

xytpbqjk5#

下面是一个实现类似效果的笔,它不需要chartjs-plugin-annotation,也不需要破解Chart.js的渲染方式,或者任何其他插件:https://codepen.io/gkemmey/pen/qBWZbYM

方法

1.使用组合条形/折线图,并使用条形图绘制垂直线。
1.使用两个y轴:一个用于条形图(我们不显示条形图),一个用于所有其他折线图数据集。
1.将条形图的y轴强制为min: 0max: 1。无论何时要绘制垂直线,都可以向条形图数据集中添加一个数据对象(如{ x: where_the_line_goes, y: 1 })。
1.画笔还向条形图数据集添加一些自定义数据,并添加图例筛选器和标签回调以从图例中排除条形图数据集,并控制垂直线上的标签。

职业玩家

1.没有其他依赖项。没有自定义的monkey修补/扩展。
1.注解插件似乎没有被主动维护。例如,atm,他们的事件处理程序抛出一个关于“防止默认被动事件”的错误。
1.也许是专业人士:注解插件总是显示所画线条的标签,您必须使用它们的事件回调来获得悬停时显示的效果。Chart.js工具提示默认显示悬停时显示。

缺点

1.我们在dataset config中添加了自定义数据,希望它不会与Chart.js正在做的任何事情相冲突。这是Chart.js不希望出现的数据,但从2.8开始,也没有破坏它。

ekqde3dh

ekqde3dh6#

在chart.js3.8.0中,我使用了带有时间轴(x轴)和百分比(y轴)的折线图/条形图组合。请参见docs
数据集配置提供了一个选项,用于设置maxBarThickness(我应用了2),然后在条形图的每个数据条目上应用y轴的最大值。
数据集配置示例:

datasets: [
  {
    type: 'line'
    data: [
      {x: "2022-07-18", y: 10},
      {x: "2022-07-19", y: 60},
      {x: "2022-07-20", y: 30}
    ],
    ....
  },
  {
    type: 'bar',
    data: [
      {x: "2022-07-19", y: 100}
    ],
    maxBarThickness: 2,
    ...
  }
]

输出示例:

xxe27gdn

xxe27gdn7#

@托马斯·德沃夏克答案的增强版

支持:

  • 标签的自定义文本
  • 线+标签的自定义颜色
  • 标签的自定义对齐
  • 标签的自定义X/Y偏移
const verticalLinePlugin = {
      getLinePosition: function (chart, pointIndex) {
          const meta = chart.getDatasetMeta(0); // first dataset is used to discover X coordinate of a point
          const data = meta.data;
          return data[pointIndex]._model.x;
      },
      renderVerticalLine: function (chartInstance, pointIndex, label, color, alignment, xOffset, yOffset) {
          const lineLeftOffset = this.getLinePosition(chartInstance, pointIndex);
          const scale = chartInstance.scales['y-axis-0'];
          const context = chartInstance.chart.ctx;
          if (xOffset == undefined) xOffset = 0;
          if (yOffset == undefined) yOffset = 0;

          // render vertical line
          context.beginPath();
          context.strokeStyle = color;
          context.moveTo(lineLeftOffset, scale.top);
          context.lineTo(lineLeftOffset, scale.bottom);
          context.stroke();

          // write label
          context.fillStyle = color;
          context.textAlign = alignment;
          context.fillText(label, lineLeftOffset + xOffset, (scale.bottom - scale.top) / 2 + scale.top + yOffset);
      },

      afterDatasetsDraw: function (chart, easing) {
          if (chart.config.lineAtIndex) {
                labelIndex = 0;
                chart.config.lineAtIndex.forEach((pointIndex) => {
                    if (chart.config.verticalLinesLabels != undefined) { // if array of labels exists...
                        label = chart.config.verticalLinesLabels[labelIndex]; // chart.config.verticalLinesLabels must contain all elements; use  elements ="" for lines not requiring labels
                        color = chart.config.verticalLinesColors[labelIndex]; // chart.config.verticalLinesColors must contain all elements
                        alignment =  chart.config.verticalLinesAlignments[labelIndex]; // chart.config.verticalLinesAlignments must contain all elements
                        xOff =  chart.config.verticalLinesX[labelIndex]; // chart.config.verticalLinesX must contain all elements
                        yOff =  chart.config.verticalLinesY[labelIndex]; // chart.config.verticalLinesY must contain all elements
                    } else {
                        label = "";
                    }
                    this.renderVerticalLine(chart, pointIndex, label, color, alignment, xOff, yOff)
                    labelIndex++;
              });
          }
      }
      };

      Chart.plugins.register(verticalLinePlugin);

用法:

myChart.config.verticalLinesLabels = ["aaa", "bbb", "ddd"]; 
myChart.config.verticalLinesColors = ["#FF0000", 'rgb(0,255,0)', 'rgba(0,0,255,0.5)']; 
myChart.config.verticalLinesAlignments = ["left", "center", "right"]; // Set label aligment (note: it is inverted because referred to line, not to label)
myChart.config.verticalLinesX = [10,5,0]; // Set label X offset
myChart.config.verticalLinesY = [10,5,0]; // Set label Y offset
myChart.config.lineAtIndex = [10,30,50]; // Mandatory to enable all previous ones
myChart.update()

相关问题