如何使用ChartJS或D3绘制带标签的水平条?

时间:2015-08-20 22:50:29

标签: d3.js graph chart.js

在ChartJS或D3中为简单折线图绘制多条水平线和标签的最佳方法是什么?我知道我可以将它们作为单独的线条绘制,然后进行文本覆盖,但我想知道是否有更简单的解决方案。理想情况下,我可以将下面的每个标签创建为一个单元并将其移动到任何位置。

如果这在另一个JS图库中更简单,那么请随意提示。

以下示例

Horizontal Labels

1 个答案:

答案 0 :(得分:2)

要使用Chart.js,您必须扩展折线图

Chart.types.Line.extend({
    name: "LineAlt",
    initialize: function (data) {
        // it's easier to programmatically update if you store the raw data in the object (vs. storing the geometric data)
        this.marks = data.marks;
        this.marks.xStart = Number(data.labels[0]);
        this.marks.xStep = data.labels[1] - data.labels[0];

        // make sure all our x labels are uniformly apart
        if (!data.labels.every(function (e, i, arr) { return !i || ((e - arr[i - 1]) === this.marks.xStep); }, this))
            throw "labels must be uniformly spaced";

        Chart.types.Line.prototype.initialize.apply(this, arguments);
    },
    draw: function () {
        Chart.types.Line.prototype.draw.apply(this, arguments);

        // save existing context properties
        var self = this;
        var ctx = self.chart.ctx;
        var scale = self.scale;

        ctx.save();
        // line properties
        ctx.lineWidth = 1;
        ctx.fillStyle = "#666";
        ctx.strokeStyle = "#666";
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";
        ctx.font = scale.font;

        // draw marks
        self.marks.forEach(function (mark) {
            // assuming that the marks are always within the data range
            var y = scale.calculateY(mark.y);
            var x1 = scale.calculateX((mark.x1 - self.marks.xStart) / self.marks.xStep);
            var x2 = scale.calculateX((mark.x2 - self.marks.xStart) / self.marks.xStep);

            // draw line
            ctx.beginPath();
            ctx.moveTo(x1, y);
            ctx.lineTo(x2, y);
            // draw edges
            ctx.moveTo(x1, y + 10);
            ctx.lineTo(x1, y - 10);
            ctx.moveTo(x2, y + 10);
            ctx.lineTo(x2, y - 10);
            ctx.stroke();

            // draw text
            ctx.fillText(mark.label, (x1 + x2) / 2, y + scale.fontSize * 1.5);
        })

        ctx.restore();
    },
});

您传递的数据用于绘制像这样的行

var data = {
    ...
    marks: [
        {
            x1: 1.5,
            x2: 3.5,
            y: 50,
            label: 'Label1'
        },
        {
            x1: 5,
            x2: 7,
            y: 60,
            label: 'Label2'
        }
    ]
};

并使用此扩展图表类型

创建图表
var myLineChart = new Chart(ctx).LineAlt(data);

您可以像这样更新

myLineChart.marks[0].y = 80;
myLineChart.marks[0].x1 = 9;
myLineChart.marks[0].x2 = 10;

然后致电

myLineChart.update();

在画布上反映这些变化

<强>注意事项

  1. (x轴)标签应为数字且均匀分布。
  2. 线条应在y轴的比例范围内(或者您可以执行scaleOverride设置比例参数,以使线条在y比例范围内)
  3. 小提琴 - http://jsfiddle.net/en92k763/2/

    enter image description here