jak wyświetlić wartości danych w Chart.js


118

Chciałbym zapytać, czy jest to możliwe przy użyciu Chart.js. wyświetlić wartości danych? Chcę wydrukować wykres.

Dzięki za każdą radę.


mój wykres działa idealnie ... chcę tylko wyświetlić wartości danych na moim wykresie liniowym ... wtedy mogę wydrukować moje wykresy ... ponieważ teraz mogę wyświetlać wartości danych tylko przez zdarzenie myszy
FuSsA

Odpowiedzi:


138

Późna edycja: istnieje oficjalna wtyczka do Chart.js, 2.7.0+aby to zrobić: https://github.com/chartjs/chartjs-plugin-datalabels

Oryginalna odpowiedź:

Możesz przechodzić przez punkty / słupki onAnimationComplete i wyświetlać wartości


Zapowiedź

wprowadź opis obrazu tutaj


HTML

<canvas id="myChart1" height="300" width="500"></canvas>
<canvas id="myChart2" height="300" width="500"></canvas>

Scenariusz

var chartData = {
    labels: ["January", "February", "March", "April", "May", "June"],
    datasets: [
        {
            fillColor: "#79D1CF",
            strokeColor: "#79D1CF",
            data: [60, 80, 81, 56, 55, 40]
        }
    ]
};

var ctx = document.getElementById("myChart1").getContext("2d");
var myLine = new Chart(ctx).Line(chartData, {
    showTooltips: false,
    onAnimationComplete: function () {

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) {
            dataset.points.forEach(function (points) {
                ctx.fillText(points.value, points.x, points.y - 10);
            });
        })
    }
});

var ctx = document.getElementById("myChart2").getContext("2d");
var myBar = new Chart(ctx).Bar(chartData, {
    showTooltips: false,
    onAnimationComplete: function () {

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) {
            dataset.bars.forEach(function (bar) {
                ctx.fillText(bar.value, bar.x, bar.y - 5);
            });
        })
    }
});

Fiddle - http://jsfiddle.net/uh9vw0ao/


Co jeśli mam dwa wykresy liniowe na tym samym wykresie?
FuSsA

1
Z powyższym nadal będzie pokazywać wartości, ale możesz zauważyć nakładanie się, jeśli punkty są zbyt blisko siebie. Ale zawsze możesz wprowadzić logikę, aby zmienić pozycję wartości. Na przykład - jsfiddle.net/hh719qex, jeśli masz kolorową drukarkę. Jeśli masz tylko 2 serie, możesz także zrobić takie rzeczy, jak ustawienie textBaseline inaczej, JEŚLI te 2 punkty są 2 blisko siebie.
potatopeelings

4
to było w wersji 1.0.2 jak to zrobić w wersji 2.1.3? Struktura obiektu jest inna w nowszej wersji.
techie_28

2
@potatopeelings Użyłem onCompletetutaj wywołania zwrotnego, ale jest ono również uruchamiane, gdy najechanie kursorem myszy znajduje się na słupku wykresu, powodując migotanie numeru z powodu przerysowania. Czy to samo, jeśli onAnimationComplete? Nie mogę użyć tego wywołania zwrotnego z moim istniejącym kodem wykresu (patrz var chartBarna dole pastebin.com/tT7yTkGh )
techie_28

1
Potrzebuję zarówno podpowiedzi, jak i danych u góry paska na moim wykresie. Kiedy wyświetla się podpowiedź, dane na górze paska są zmieniane na biały kolor, który jest widoczny w mojej przezroczystej podpowiedzi. Jak mogę to naprawić?
LJP

82

Oto zaktualizowana wersja Chart.js 2.3

23 września 2016: Zmodyfikowałem mój kod, aby działał z wersją 2.3 dla obu typów linii / słupków.

Ważne: Nawet jeśli nie potrzebujesz animacji, nie zmieniaj opcji czasu trwania na 0, w przeciwnym razie otrzymasz chartInstance.controller jest niezdefiniowanym błędem.

var chartData = {
    labels: ["January", "February", "March", "April", "May", "June"],
        datasets: [
            {
                fillColor: "#79D1CF",
                strokeColor: "#79D1CF",
                data: [60, 80, 81, 56, 55, 40]
            }
        ]
    };

var opt = {
    events: false,
    tooltips: {
        enabled: false
    },
    hover: {
        animationDuration: 0
    },
    animation: {
        duration: 1,
        onComplete: function () {
            var chartInstance = this.chart,
                ctx = chartInstance.ctx;
            ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
            ctx.textAlign = 'center';
            ctx.textBaseline = 'bottom';

            this.data.datasets.forEach(function (dataset, i) {
                var meta = chartInstance.controller.getDatasetMeta(i);
                meta.data.forEach(function (bar, index) {
                    var data = dataset.data[index];                            
                    ctx.fillText(data, bar._model.x, bar._model.y - 5);
                });
            });
        }
    }
};
 var ctx = document.getElementById("Chart1"),
     myLineChart = new Chart(ctx, {
        type: 'bar',
        data: chartData,
        options: opt
     });
<canvas id="myChart1" height="300" width="500"></canvas>


Podczas próby na wykresach słupkowych pojawia się komunikat „Uncaught TypeError: Cannot read property '0' of undefined”. Czy paski używają czegoś innego niż „dataset.metaData [i] ._ model”?
Chris Ensell

W rzeczywistości jest to var model = dataset._meta [i] .data [0] ._ model;
Flanamacca

To też nie jest pełna prawda. Nadal mam wyjątki. Spróbuję to rozgryźć.
val

var model = dataset._meta [0] .data [i] ._ model; tak właściwie.
brian

2
Wygląda na to, że nie jest to tak proste, jak _meta [0]. W rzeczywistości obiekt _meta nie jest tablicą, ma pojedynczy element z liczbą jako kluczem. Nie mogę znaleźć uzasadnienia tego, jaka będzie liczba, więc po prostu biorę pierwszy element, patrząc na listę kluczy, na przykład: var model = dataset._meta [Object.keys (dataset._meta) [0]] .data [i] ._ model;
IrishDubGuy

34

Ta opcja animacji działa w wersji 2.1.3 na wykresie słupkowym.

Nieznacznie zmodyfikowana odpowiedź @ Ross

animation: {
duration: 0,
onComplete: function () {
    // render the value of the chart above the bar
    var ctx = this.chart.ctx;
    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
    ctx.fillStyle = this.chart.config.options.defaultFontColor;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    this.data.datasets.forEach(function (dataset) {
        for (var i = 0; i < dataset.data.length; i++) {
            var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
            ctx.fillText(dataset.data[i], model.x, model.y - 5);
        }
    });
}}

3
Musiałem również ustawić, hover: {animationDuration: 0}aby zatrzymać
animacje

1
Zwróć też uwagę, że jeśli chcesz ukryć etykiety, gdy ukrywasz coś przed legendą, musisz dodać następujące informacje przed pętlą forEach:.filter(dataset => !dataset._meta[0].hidden)
iamyojimbo

1
Ta metoda powoduje przycinanie wartości, jeśli nad słupkami nie ma wystarczającej ilości miejsca.
Janne Annala

2
Nie mogę uwierzyć, że to taka brzydka ^^ fajna robota
La masse

Wygląda dobrze, ale miga, gdy etykiety narzędzi są ponownie rysowane. Nie przetwarza również kolizji na połączonych wykresach i zbiorczych etykietach danych dla słupków ułożonych w stos - to oczywiście będzie wymagało więcej kodowania.
dma_k,

22

Myślę, że najładniejszą opcją do zrobienia tego w chartJS v2.x jest użycie wtyczki, więc nie masz dużego bloku kodu w opcjach. Ponadto zapobiega znikaniu danych po najechaniu kursorem na słupek.

To znaczy po prostu użyj tego kodu, który rejestruje wtyczkę, która dodaje tekst po narysowaniu wykresu.

Chart.pluginService.register({
    afterDraw: function(chartInstance) {
        var ctx = chartInstance.chart.ctx;

        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom';

        chartInstance.data.datasets.forEach(function (dataset) {
            for (var i = 0; i < dataset.data.length; i++) {
                var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                ctx.fillText(dataset.data[i], model.x, model.y - 2);
            }
        });
  }
});

Chart.plugins.register ({
hasentopf

Musiałem użyć Chart.defaults.global.tooltips.enabled = false;. Problem z tym rozwiązaniem polega na tym, że afterDrawfunkcja jest wywoływana setki razy, prawdopodobnie generując obciążenie procesora. Mimo wszystko jest to na razie jedyna odpowiedź bez mrugnięcia okiem. Jeśli potrzebujesz lepszego renderowania horizontalBarwykresów, użyj ctx.textAlign = 'left'; ctx.textBaseline = 'middle';i ctx.fillText(dataset.data[i], model.x+5, model.y);.
KrisWebDev

znacznie czystsze i modułowe rozwiązanie.
hadaytullah

20

Opierając się na odpowiedzi @ Rossa dla Chart.js 2.0 i nowszych, musiałem wprowadzić niewielkie poprawki, aby zabezpieczyć się przed przypadkiem, gdy wysokość słupka jest zbyt wybrana do granicy skali.

Przykład

animationAtrybut opcji wykresie słupkowym za:

animation: {
            duration: 500,
            easing: "easeOutQuart",
            onComplete: function () {
                var ctx = this.chart.ctx;
                ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';

                this.data.datasets.forEach(function (dataset) {
                    for (var i = 0; i < dataset.data.length; i++) {
                        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                            scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                        ctx.fillStyle = '#444';
                        var y_pos = model.y - 5;
                        // Make sure data value does not get overflown and hidden
                        // when the bar's value is too close to max value of scale
                        // Note: The y value is reverse, it counts from top down
                        if ((scale_max - model.y) / scale_max >= 0.93)
                            y_pos = model.y + 20; 
                        ctx.fillText(dataset.data[i], model.x, y_pos);
                    }
                });               
            }
        }

Tekst miga po najechaniu kursorem myszy na wykres .. Próbowałem zadzwonić ctx.save()na koniec, ale to nie pomogło
techie_28

onCompletepowrotem połączenie jest wykonywane, kiedy unosiła się na bar, który powoduje, że pojawi się przerysować & tekstowe do blink.Would być to samo onAnimationCompletejak dobrze? Jestem w stanie używać onAnimationCompleteplecy rozmowę z moim istniejącego kodu (patrz var chartBarna dole pastebin. com / tT7yTkGh
techie_28

Czy można zrobić to samo na wykresie kołowym
Ravi Khambhati

@RaviKhambhati Tak, możesz to sprawdzić w tej odpowiedzi: stackoverflow.com/a/38797604/6402571
Hung Tran

17

Jeśli używasz wtyczki chartjs-plugin-datalabels, pomocny będzie następujący obiekt opcji kodu

Upewnij się, że importujesz import 'chartjs-plugin-datalabels';w pliku maszynopisu lub dodajesz odniesienie do <script src="chartjs-plugin-datalabels.js"></script>w pliku javascript.

options: {
    maintainAspectRatio: false,
    responsive: true,
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    },
    plugins: {
      datalabels: {
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: {
          weight: 'bold'
        }
      }
    }
  }

1
Twoja odpowiedź jest taka prosta i zadziałała dla mnie. Dziękuję Ci. Miłego kodowania.
Bandham Manikanta

7

Po tej dobrej odpowiedzi użyłbym następujących opcji dla wykresu słupkowego:

var chartOptions = {
    animation: false,
    responsive : true,
    tooltipTemplate: "<%= value %>",
    tooltipFillColor: "rgba(0,0,0,0)",
    tooltipFontColor: "#444",
    tooltipEvents: [],
    tooltipCaretSize: 0,
    onAnimationComplete: function()
    {
        this.showTooltip(this.datasets[0].bars, true);
    }
};

window.myBar = new Chart(ctx1).Bar(chartData, chartOptions);

Wykres słupkowy

To nadal wykorzystuje system podpowiedzi i jego zalety (automatyczne pozycjonowanie, szablony, ...), ale ukrywa dekoracje (kolor tła, daszek, ...)


Implementacja może się zmieniać w zależności od typu wykresu. Na przykład w przypadku wykresu liniowego jest to this.datasets[0].pointszamiast .bars. Wolę to rozwiązanie, ponieważ korzysta z systemu podpowiedzi.
Telmo Marques

1
To rozwiązanie dla wcześniejszej wersji. Jak to osiągnąć dla najnowszej wersji tj. 2.1.3. Użyłem potatopeelings i odpowiedzi Huang Trang w onCompletewywołaniu zwrotnym animacji, ale jest ono uruchamiane nawet po najechaniu kursorem na słupki wykresu, co powoduje, że tekst przerysowuje się i daje niepożądany efekt mrugnięcia. Także próbowałem afterDrawi wszystko jest takie samo. nie dzieje się na skrzypcach dostarczonych przez potatopeelings.Any Ideas plz?
techie_28

6

Z próbek chart.js (plik Chart.js-2.4.0 / samples / data_labelling.html):

`` `` // Zdefiniuj wtyczkę do dostarczania etykiet danych

    Chart.plugins.register({
        afterDatasetsDraw: function(chartInstance, easing) {
            // To only draw at the end of animation, check for easing === 1
            var ctx = chartInstance.chart.ctx;

            chartInstance.data.datasets.forEach(function (dataset, i) {
                var meta = chartInstance.getDatasetMeta(i);
                if (!meta.hidden) {
                    meta.data.forEach(function(element, index) {
                        // Draw the text in black, with the specified font
                        ctx.fillStyle = 'rgb(0, 0, 0)';

                        var fontSize = 16;
                        var fontStyle = 'normal';
                        var fontFamily = 'Helvetica Neue';
                        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

                        // Just naively convert to string for now
                        var dataString = dataset.data[index].toString();

                        // Make sure alignment settings are correct
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'middle';

                        var padding = 5;
                        var position = element.tooltipPosition();
                        ctx.fillText(dataString, position.x, position.y - (fontSize / 2) - padding);
                    });
                }
            });
        }
    });

`` ''


Dodałem do tego linię w celu wyrównania na wykresie słupkowym poziomym, wykonując if (chart.config.type == "horizontalBar"), a następnie definiując niestandardowe dopełnienie pionowe 10 w celu wyśrodkowania go.
Jeff Beagley,

6

Polecam użycie tej wtyczki: https://github.com/chartjs/chartjs-plugin-datalabels

Etykiety można dodawać do wykresów po prostu importując wtyczkę do pliku js, np .:

import 'chartjs-plugin-datalabels'

Można je precyzyjnie dostroić, korzystając z tych dokumentów: https://chartjs-plugin-datalabels.netlify.com/options.html


2
Najłatwiejszy, nie wymaga "kodu", wystarczy dostosować go za pomocą standardowego obiektu "opcje". Uwaga: minimalna wymagana wersja charts.js to 2.7.0 , odnosiłem się do 2.5.0 z CDN i nie było żadnych zmian na wykresach ...
GBU

@GBU jaki jest atrybut opcji?
Bhimbim

5

Trochę zredagowano odpowiedź @ ajhuddy. Tylko dla wykresów słupkowych . Moja wersja dodaje:

  • Animacja zanikania wartości.
  • Zapobiegaj przycinaniu, umieszczając wartość wewnątrz paska, jeśli słupek jest zbyt wysoki.
  • Bez mrugania.

Przykład

Wada: po najechaniu kursorem na słupek, który ma wartość w środku, wartość może wyglądać na nieco poszarpaną. Nie znalazłem rozwiązania wyłączającego efekty najechania kursorem. Może również wymagać dostosowania w zależności od własnych ustawień.

Konfiguracja:

bar: {
  tooltips: {
    enabled: false
  },
  hover: {
    animationDuration: 0
  },
  animation: {
    onComplete: function() {
      this.chart.controller.draw();
      drawValue(this, 1);
    },
    onProgress: function(state) {
      var animation = state.animationObject;
      drawValue(this, animation.currentStep / animation.numSteps);
    }
  }
}

Pomocnicy:

// Font color for values inside the bar
var insideFontColor = '255,255,255';
// Font color for values above the bar
var outsideFontColor = '0,0,0';
// How close to the top edge bar can be before the value is put inside it
var topThreshold = 20;

var modifyCtx = function(ctx) {
  ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
  ctx.textAlign = 'center';
  ctx.textBaseline = 'bottom';
  return ctx;
};

var fadeIn = function(ctx, obj, x, y, black, step) {
  var ctx = modifyCtx(ctx);
  var alpha = 0;
  ctx.fillStyle = black ? 'rgba(' + outsideFontColor + ',' + step + ')' : 'rgba(' + insideFontColor + ',' + step + ')';
  ctx.fillText(obj, x, y);
};

var drawValue = function(context, step) {
  var ctx = context.chart.ctx;

  context.data.datasets.forEach(function (dataset) {
    for (var i = 0; i < dataset.data.length; i++) {
      var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
      var textY = (model.y > topThreshold) ? model.y - 3 : model.y + 20;
      fadeIn(ctx, dataset.data[i], model.x, textY, model.y > topThreshold, step);
    }
  });
};

Janne dziękuję za rozwiązanie, wygląda świetnie. Ale mam sytuację, w której moje wartości są w rzeczywistości dość duże (5 liczb dziesiętnych), a gdy rozmiar ekranu jest mały lub mam wiele wykresów, liczby znajdują się jeden na drugim. Czy jest jakiś sposób, aby to działało z responsywnością? Na przykład, aby liczby obracały się, gdy nie ma miejsca, tak jak etykiety pod paskiem?
Phiter

@PhiterFernandes Myślę, że powinno być możliwe obracanie, sprawdzając bieżący rozmiar ekranu w funkcji modifiedCtx i używając ctx.rotate. Jednak nie jestem pewien, jak porównać rozmiar wartości z dostępną przestrzenią, aby określić, kiedy obrócić.
Janne Annala

Funkcja modyfikujCtx działa tylko raz, a nie przy zmianie rozmiaru, prawda? Rzucę okiem na kod źródłowy chart.js i zobaczę, gdzie wykonują rotację etykiet na osi x. Jeśli coś zobaczę, spróbuję coś zrobić i powiem ci tutaj, ok? =)
Phiter

Znalazłem coś w wersji 2.3.0 calculateTickRotation, wiersz 7075. , znajduje się w funkcji Scale. Przeanalizuję to.
Phiter

5

Z mojego doświadczenia wynika , że po dołączeniu wtyczki chartjs-plugin-datalabels (pamiętaj, aby umieścić <script>tag po tagu chart.js na stronie), wykresy zaczną wyświetlać wartości.

Jeśli wybierzesz, możesz dostosować go do swoich potrzeb. Dostosowanie jest wyraźnie udokumentowane tutaj, ale zasadniczo format jest podobny do tego hipotetycznego przykładu:

var myBarChart = new Chart(ctx, {
    type: 'bar',
    data: yourDataObject,
    options: {
        // other options
        plugins: {
            datalabels: {
                anchor :'end',
                align :'top',
                // and if you need to format how the value is displayed...
                formatter: function(value, context) {
                    return GetValueFormatted(value);
                }
            }
        }
    }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.