как отображать значения данных на Chart.js


118

Я хотел бы спросить, можно ли использовать Chart.js отображать значения данных? Я хочу распечатать график.

Спасибо за любой совет.


мой график работает отлично ... я просто хочу отобразить значения данных на моем графике LineBar ... тогда я могу распечатать свои графики ... потому что теперь я могу отображать значения данных только по событию мыши
FuSsA

Ответы:


138

Позднее редактирование: для этого есть официальный плагин для Chart.js 2.7.0+: https://github.com/chartjs/chartjs-plugin-datalabels

Оригинальный ответ:

Вы можете перемещаться по точкам / полосам на AnimationComplete и отображать значения


Предварительный просмотр

введите описание изображения здесь


HTML

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

Сценарий

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/


Что, если бы у меня было две линейных диаграммы на одной диаграмме?
FuSsA

1
С указанным выше он все равно будет отображать значения, но вы можете увидеть перекрытие, если точки расположены слишком близко друг к другу. Но вы всегда можете заложить логику, чтобы изменить позицию значения. Например, jsfiddle.net/hh719qex, если у вас цветной принтер. Если у вас есть только 2 серии, вы также можете делать такие вещи, как установка textBaseline по-разному, ЕСЛИ 2 точки находятся на 2 близко друг к другу.
картофельные чистки

4
это было для v1.0.2, как это сделать для v2.1.3? В более поздней версии структура объекта изменилась.
techie_28

2
@potatopeelings Я использовал onCompleteздесь обратный вызов, но он также срабатывает при наведении курсора мыши на полосу диаграммы, в результате чего число мигает из-за перерисовки. Было бы так, если бы onAnimationComplete? Я не могу использовать этот обратный вызов с моим существующим кодом диаграммы (см. var chartBarВнизу pastebin.com/tT7yTkGh )
techie_28,

1
Мне нужна всплывающая подсказка и данные в верхней части полосы на моем графике. Когда отображается всплывающая подсказка, данные в верхней части панели меняются на белый цвет, который виден в моей прозрачной подсказке. Как я могу это исправить?
LJP

82

Вот обновленная версия Chart.js 2.3

23 сентября 2016 г .: Отредактировал мой код для работы с версией 2.3 для типов линий и полос.

Важно: даже если вам не нужна анимация, не меняйте параметр продолжительности на 0, иначе вы получите ошибку chartInstance.controller is undefined .

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>


Я получаю сообщение "Uncaught TypeError: Cannot read property '0' of undefined" при попытке сделать это на гистограммах. Используются ли в столбцах что-то другое, кроме "dataset.metaData [i] ._ model"?
Крис Энселл

На самом деле это var model = dataset._meta [i] .data [0] ._ model;
Flanamacca

Это тоже не вся правда. У меня по-прежнему бывают исключения. Постараюсь разобраться.
val

var model = dataset._meta [0] .data [i] ._ model; фактически.
Брайан

2
Похоже, это не так просто, как _meta [0]. На самом деле объект _meta не является массивом, он состоит из одного элемента с номером в качестве ключа. Я не могу понять логику того, каким будет число, поэтому просто беру первый элемент, просматривая список ключей, например: var model = dataset._meta [Object.keys (dataset._meta) [0]] .data [i] ._ модель;
IrishDubGuy

34

Этот вариант анимации работает в версии 2.1.3 на гистограмме.

Слегка измененный ответ @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
Мне также пришлось установить, hover: {animationDuration: 0}чтобы метки не
отображались

1
Также обратите внимание, что если вы хотите скрыть метки, когда вы что-то скрываете из легенды, вам нужно добавить следующее перед циклом forEach:.filter(dataset => !dataset._meta[0].hidden)
iamyojimbo

1
Этот метод приводит к обрезке значений, если над полосами недостаточно места.
Janne Annala

2
Не могу поверить, что это уродливо ^^ хорошая работа
La masse

Выглядит хорошо, но мигает при перерисовке всплывающих подсказок. Также не обрабатываются коллизии на комбинированных диаграммах и кумулятивные метки данных для столбцов с накоплением - это, конечно, потребует большего количества кода.
dma_k

22

Я думаю, что лучший вариант сделать это в chartJS v2.x - использовать плагин, поэтому у вас нет большого блока кода в параметрах. Кроме того, он предотвращает исчезновение данных при наведении курсора на полосу.

Т.е. просто используйте этот код, который регистрирует плагин, который добавляет текст после рисования диаграммы.

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

Пришлось использовать Chart.defaults.global.tooltips.enabled = false;. Проблема с этим решением заключается в том, что afterDrawфункция вызывается сотни раз, что, вероятно, вызывает накладные расходы ЦП. Тем не менее, это пока единственный ответ без моргания. Если вам нужен лучший рендеринг для horizontalBarдиаграмм, используйте ctx.textAlign = 'left'; ctx.textBaseline = 'middle';и ctx.fillText(dataset.data[i], model.x+5, model.y);.
KrisWebDev

гораздо более чистое и модульное решение.
хадайтуллах

20

Основываясь на ответе @ Ross для Chart.js 2.0 и выше, мне пришлось включить небольшую настройку, чтобы не допустить случая, когда высота столбца слишком велика к границе шкалы.

пример

animationАтрибут опции Гистограмма в:

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

Текст мигает при ctx.save()
наведении курсора

onCompleteобратный вызов выполняется , когда я парил на баре, который вызывает перерисовки и текст отображается в blink.Would это то же самое с onAnimationComplete, а? Я не могу использовать onAnimationCompleteвызов обратно с моего существующего кода (см var chartBarв нижней части Pastebin. com / tT7yTkGh
techie_28

Можно ли сделать то же самое на круговой диаграмме
Рави

@RaviKhambhati Да, вы можете проверить это в этом ответе: stackoverflow.com/a/38797604/6402571
Hung Tran,

17

Если вы используете плагин chartjs-plugin-datalabels, следующий объект параметров кода поможет

Убедитесь, что вы импортируете import 'chartjs-plugin-datalabels';файл машинописного текста или добавляете ссылку на него <script src="chartjs-plugin-datalabels.js"></script>в свой файл javascript.

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

1
Ваш ответ настолько прост и сработал для меня. Спасибо. Удачного кодирования.
Бандхам Маниканта

7

После этого хорошего ответа я бы использовал эти параметры для гистограммы:

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

Гистограмма

Он по-прежнему использует систему всплывающих подсказок и его преимущества (автоматическое позиционирование, создание шаблонов, ...), но скрывает украшения (цвет фона, курсор, ...)


Реализация может меняться в зависимости от типа диаграммы. Например, для линейного графика это this.datasets[0].pointsвместо .bars. Я предпочитаю это решение, потому что оно использует систему всплывающих подсказок.
Тельмо Маркес,

1
Это решение для более ранней версии. Как этого добиться для последней версии, т.е. 2.1.3. Я использовал ответы «potatopeelings» и «Huang Trang» в обратном вызове анимации, onCompleteно он срабатывает даже при наведении курсора мыши на столбцы диаграммы, что приводит к перерисовке текста и возникновению нежелательного эффекта мигания. Я также пробовал, afterDrawи это все то же самое. не происходит в скрипке, предоставленной картофелечистками. Любые идеи, пожалуйста?
techie_28

6

Из примеров chart.js (файл Chart.js-2.4.0 / samples / data_labelling.html):

`` `// Определяем плагин для предоставления меток данных

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

`` `


Я добавил к нему линию для выравнивания на горизонтальной гистограмме, выполнив if (chart.config.type == "horizontalBar"), а затем определив настраиваемый вертикальный отступ 10 для выравнивания по центру.
Джефф Бигли

6

Я бы рекомендовал использовать этот плагин: https://github.com/chartjs/chartjs-plugin-datalabels

Ярлыки можно добавлять в ваши диаграммы, просто импортировав плагин в файл js, например:

import 'chartjs-plugin-datalabels'

И его можно точно настроить с помощью этих документов: https://chartjs-plugin-datalabels.netlify.com/options.html


2
Самый простой, не требует «кода», просто настраивается с помощью стандартного объекта «options». Предупреждение: минимально необходимая версия charts.js - 2.7.0 , я ссылался на 2.5.0 из CDN, и на графиках не было никаких изменений ...
GBU

@GBU что такое атрибут option?.
Bhimbim

5

Немного отредактировал ответ @ajhuddy. Только для гистограмм . Моя версия добавляет:

  • Эффект плавной анимации для значений.
  • Предотвратите обрезку, поместив значение внутри полосы, если полоса слишком высока.
  • Не моргать.

пример

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

Конфигурация:

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

Помощники:

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

Янне, спасибо за решение, выглядит отлично. Но у меня есть ситуация, когда мои значения на самом деле довольно большие (5 десятичных чисел), а когда размер экрана небольшой или у меня много диаграмм, числа располагаются друг над другом. Есть ли способ заставить эту работу работать с отзывчивостью? Мол, заставить числа вращаться, когда нет места, как метки под полосой?
Phiter

@PhiterFernandes Я думаю, что можно повернуть, проверив текущий размер экрана в функции modifyCtx и используя ctx.rotate. Однако я не уверен, как сравнить размер значения с доступным пространством, чтобы определить, когда повернуть.
Janne Annala,

Функция modifyCtx работает только один раз, а не при изменении размера, верно? Я посмотрю на исходный код chart.js и посмотрю, где они вращают метки по оси x. Если я что-то увижу, я постараюсь что-нибудь сделать и рассказать вам здесь, хорошо? =)
Phiter

Я нашел кое-что в версии 2.3.0, строка 7075. calculateTickRotation, это внутри функции Scale. Я это проанализирую.
Phiter

5

По моему опыту, после того, как вы включите плагин chartjs-plugin-datalabels (обязательно разместите <script>тег после тега chart.js на своей странице), ваши диаграммы начинают отображать значения.

Если вы затем выберете, вы можете настроить его в соответствии со своими потребностями. Настройка четко задокументирована здесь, но в основном формат похож на этот гипотетический пример:

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);
                }
            }
        }
    }
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.