Chart.js - Zeichnen einer beliebigen vertikalen Linie

71

Wie kann ich mit Chart.js eine vertikale Linie an einem bestimmten Punkt auf der x-Achse zeichnen?

Insbesondere möchte ich eine Linie zeichnen, um den aktuellen Tag auf einem LineChart anzuzeigen. Hier ist ein Modell des Diagramms: http://i.stack.imgur.com/VQDWR.png

Geben Sie hier die Bildbeschreibung ein

Fredrik
quelle

Antworten:

90

Update - Diese Antwort gilt für Chart.js 1.x. Wenn Sie nach einer 2.x-Antwort suchen, überprüfen Sie die Kommentare und andere Antworten.

Sie erweitern das Liniendiagramm und fügen der Zeichenfunktion eine Logik zum Zeichnen der Linie hinzu.


Vorschau

Geben Sie hier die Bildbeschreibung ein


HTML

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

Skript

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
});

Die Optionseigenschaft lineAtIndex steuert, an welchem ​​Punkt die Linie gezeichnet werden soll.

Geige - http://jsfiddle.net/dbyze2ga/14/

Kartoffelbäume
quelle
4
Danke @potatopeelings, genau das habe ich gesucht. Ich habe nicht genug Repräsentanten, um dich zu unterstützen, würde es aber natürlich tun, wenn ich könnte.
Fredrik
1
Vielen Dank! Ordentlich und einfach :)
Sebastialonso
3
@ Sheetal - habe das nicht ganz verstanden. Vielleicht möchten Sie ein Bild von dem veröffentlichen, wonach Sie suchen. Prost! Außerdem wird jetzt die neue Version von Chart.js (v2.1.x) veröffentlicht. Die obige Antwort ist für v1.x
Potatopeelings
12
Dies ist eine schöne Lösung. Können Sie dies für Chart JS Version 2.1.6 aktualisieren?
Arun SS
1
@ArunSS Lösung für Chart.js 2.0
Deilan
59

Teilen meiner Lösung für chartjs.org Version 2.5. Ich wollte ein Plugin verwenden, um die Implementierung wiederverwendbar zu machen.

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);

Die Verwendung ist dann einfach:

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

Der obige Code fügt an den Positionen 2,4 und 8 rote vertikale Linien ein, die an diesen Positionen durch die Punkte des ersten Datensatzes verlaufen.

Tomáš Dvořák
quelle
3
Das ist großartig und sehr wiederverwendbar! Tolle Lösung! +1
EoghanTadhg
Wiederbelebung dieses alten Beitrags, aber ist es möglich, für jede vertikale Linie einen anderen Text zu konfigurieren?
Matt
Klar, du musst es nur leicht anpassen. Anstelle des lineAtIndex-Arrays sollten Sie eine Map mit index => text bereitstellen, diese in der afterDatasetsDraw-Methode durchlaufen und den Text aus der Map in der renderVerticalLine-Methode verwenden, in der 'MY TEXT' derzeit gerendert wird.
Tomáš Dvořák
1
Chart.js kann jetzt einen Fehler haben, der einen ReferenceError "Chart ist nicht definiert" verursacht
Silverfin
2
Obwohl ich diese Lösung positiv bewertet habe, gibt es eine ziemlich hässliche Einschränkung, da es nicht möglich ist, Zeilen mit Werten hinzuzufügen, die zwischen Indizes liegen. Aber es stellte sich heraus, dass es ein großartiges Tutorial war.
Daniel F
6

Ich musste mir die Mühe machen, herauszufinden, wie man mit ChartJS 2.0 etwas Ähnliches macht, also dachte ich, ich würde es teilen.

Dies basiert auf der neuen Methode zum Überschreiben eines Diagrammprototyps, wie hier erläutert: 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);
};

Brandon Johnson
quelle
4

Ich würde wärmstens empfehlen, die Chartjs-Plugin-Annotation zu verwenden .

Ein Beispiel finden Sie bei 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"
            }
          }
        ]
      }
    }
  });
};

Weitere Informationen finden Sie hier: https://stackoverflow.com/a/36431041

Phifi
quelle
Es funktioniert für mich - ohne weitere Informationen kann ich Ihnen nicht helfen
Phifi
Ich versuche dies in Ionic Project Mobile hinzuzufügen. Haben Sie dies für das Web erstellt?
Akhilesh Mani
Ja, ich habe es für eine Website erstellt. Vielleicht sollten Sie eine separate Frage mit mehr Informationen zu Ihrem eigentlichen Problem erstellen und einen Quellcode bereitstellen.
Phifi
Gelöst Danke! stackoverflow.com/questions/47655173/…
Akhilesh Mani
Alle Chart.js Plugins sind chaotisch. Das kann erklären, warum sie «Plugins» sind und nicht im Kern enthalten sind. Dies folgt vielen Tests. Chart.js ist in Ordnung, aber benutze keine Plugins, Leute, mach deine.
NVRM
1

Hier ist ein Stift, der einen ähnlichen Effekt erzielt, ohne die Annotation "chartjs-plugin-annotation" oder das Hacken von Chart.js oder andere Plugins zu hacken: https://codepen.io/gkemmey/pen/qBWZbYM

Ansatz

  1. Verwenden Sie ein kombiniertes Balken- / Liniendiagramm und verwenden Sie das Balkendiagramm, um die vertikalen Linien zu zeichnen.
  2. Verwenden Sie zwei y-Achsen: eine für das Balkendiagramm (das nicht angezeigt wird) und eine für alle anderen Liniendiagramm-Datensätze.
  3. Erzwingen Sie die y-Achsen des Balkendiagramms auf min: 0und max: 1. Wenn Sie eine vertikale Linie zeichnen möchten, fügen Sie { x: where_the_line_goes, y: 1 }Ihrem Balkendiagramm-Dataset ein Datenobjekt hinzu .
  4. Der Stift fügt dem Balkendiagramm-Dataset auch einige benutzerdefinierte Daten sowie einen Legendenfilter und einen Beschriftungsrückruf hinzu, um das Balkendiagramm-Dataset von der Legende auszuschließen und die Beschriftung auf der vertikalen Linie zu steuern.

Vorteile

  1. Keine weiteren Abhängigkeiten. Kein benutzerdefiniertes Patchen / Erweitern von Affen.
  2. Das Annotations-Plugin scheint nicht aktiv gepflegt zu sein. Zum Beispiel, atm, geben ihre Ereignishandler einen Fehler über "Verhindern des Standardwerts für passive Ereignisse" aus.
  3. Vielleicht ein Profi: Das Annotations-Plugin zeigt immer die Beschriftungen der gezeichneten Linien an, und Sie müssen deren Ereignisrückrufe verwenden, um einen Show-on-Hover-Effekt zu erzielen. Die QuickInfos von Chart.j werden standardmäßig beim Hover angezeigt.

Nachteile

  1. Wir fügen der Dataset-Konfiguration benutzerdefinierte Daten hinzu und hoffen, dass diese nicht mit den Aktivitäten von Chart.js in Konflikt stehen. Es sind Daten, die Chart.js nicht erwartet, aber ab 2.8 auch nicht kaputt macht.
Grauer Kemmey
quelle
Dieser Ansatz wäre perfekt, wenn wir einen Weg finden könnten, eine lineare Achse für Balkendiagramme anzuwenden, redundante Daten hinzuzufügen, um das Diagramm anzuzeigen, ist nicht wirklich das, was ich erwarten kann
Raphaël VO