Charts.js工具提示重叠图表上的文字

时间:2016-10-25 15:09:12

标签: javascript tooltip z-index chart.js

由于Charts.js尚不支持注释,因此我在绘制图表后添加了数据点的注释。使用ctx.fillText,如下所示。

; This setting is on by default.
report_zend_debug = 1
zend_extension = C:\Program Files\PHP\v5\ext\php_xdebug-2.4.1-5.6-vc11.dll

[PHP_XDEBUG-2.4.1-5.6-VC11]
xdebug.remote_enable=1
xdebug.remote_autostart = "On"
xdebug.remote_port=9000

除了现在工具提示显示在新添加的文本下方之外,这项工作很有用。这不是那么明显,但有时它会在一个不好的地方重叠,这意味着你无法看到后面的工具提示。

enter image description here

有没有办法设置ctx.fillText或工具提示的z-index,以便我可以正确分层?

4 个答案:

答案 0 :(得分:2)

如果您正在寻找问题中所写代码的紧密解决方案,那么下面是代码:

let ctx2 = document.getElementById("barChart").getContext("2d");

        let chart = new Chart(ctx2, {
            type: 'bar',
            data: {
                labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
                datasets: [{
                    label: 'Months',
                    data: ['20','30','10','15','50','35','25'],
                    backgroundColor: 'rgba(26,179,148,0.5)',
                    borderColor: 'rgba(75, 192, 192, 1)',
                    borderWidth: 1
                }]
            },
            options: {
                legend: {
                    display: false
                },
                responsive: true,
                maintainAspectRatio: true,
                legendCallback: function(chart) {
                    var text = [];
                    for (var i=0; i<chart.data.datasets.length; i++) {
                        text.push(chart.data.labels[i]);
                    }
                    return text.join("");
                },
                tooltips: {
                    mode: 'index',
                    callbacks: {
                        // Use the footer callback to display the sum of the items showing in the tooltip
                        title: function(tooltipItem, data) {
                            let title_str = data['labels'][tooltipItem[0]['index']];
                            let lastIndex = title_str.lastIndexOf(" ");
                            return title_str.substring(0, lastIndex);
                        },
                        label: function(tooltipItem, data) {
                            return 'val: '+data['datasets'][0]['data'][tooltipItem['index']];
                        },
                    },
                },

                scales: {
                    xAxes: [{
                        stacked: false,
                        beginAtZero: true,
                        // scaleLabel: {
                        //     labelString: 'Month'
                        // },
                        ticks: {
                            min: 0,
                            autoSkip: false,
                            maxRotation: 60,
                            callback: function(label, index, labels) {
                                return label;
                            }
                        }
                    }]
                }
            },
            plugins:[{
                afterDatasetsDraw: function(chart,options) {
                    // var chartInstance = chart,
                    let ctx = chart.ctx;
                    ctx.font = Chart.defaults.global.defaultFontStyle;
                    ctx.fillStyle = Chart.defaults.global.textColor;
                    ctx.textAlign = "center";
                    ctx.textBaseline = "bottom";

                    chart.data.datasets.forEach(function (dataset, i) {
                        var meta = chart.controller.getDatasetMeta(i);
                        meta.data.forEach(function (bar, index) {
                            ctx.fillText(Math.round(dataset.data[index]), bar._model.x, bar._model.y - 5);
                        });
                    })
                }
            }]
        });
        document.getElementById('barChart').innerHTML = chart.generateLegend();
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
    <canvas id="barChart" height="140"></canvas>
</div>

在这里,我已经使用了插件afterDatasetDrawhttps://www.chartjs.org/docs/latest/developers/plugins.html?h=afterdatasetsdraw

答案 1 :(得分:1)

对于任何有兴趣的人,我设法解决了这个问题,我最终查看了charts.js中的工具提示绘图功能,并使用此修改版本作为自定义工具提示,从而在添加注释后绘制工具提示。

首先将此添加到您的选项中

config = {
    options: {
        tooltips: {
            enabled: false,
            custom: customTooltips
        }

然后调用下面的自定义工具提示功能。

var currentX = null;
var currentY = null;

var customTooltips = function (tooltip) {

    var helpers = Chart.helpers;
    var ctx = this._chart.ctx;
    var vm = this._view;

    if (vm == null || ctx == null || helpers == null || vm.opacity === 0) {
        return;
    }

    var tooltipSize = this.getTooltipSize(vm);

    var pt = {
        x: vm.x,
        y: vm.y
    };

    if (currentX == vm.x && currentY == vm.y) {
        return;
    }

    currentX = vm.x;
    currentY = vm.y;

   //  IE11/Edge does not like very small opacities, so snap to 0
    var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;

    // Draw Background
    var bgColor = helpers.color(vm.backgroundColor);
    ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
    helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
    ctx.fill();

    // Draw Caret
    this.drawCaret(pt, tooltipSize, opacity);

    // Draw Title, Body, and Footer
    pt.x += vm.xPadding;
    pt.y += vm.yPadding;

    // Titles
    this.drawTitle(pt, vm, ctx, opacity);

    // Body
    this.drawBody(pt, vm, ctx, opacity);

    // Footer
    this.drawFooter(pt, vm, ctx, opacity);
};

答案 2 :(得分:1)

@ user3284707实际上,您要做的是在工具提示之前在条形图上绘制数字,然后绘制onComplete,将它们放在所有内容之上。

我使用以下方法绘制这些数字:

Chart.plugins.register({
  beforeDraw: function(chartInstance) {
    if (chartInstance.config.options.showDatapoints) {
      var helpers = Chart.helpers;
      var ctx = chartInstance.chart.ctx;
      var fontColor = helpers.getValueOrDefault(chartInstance.config.options.showDatapoints.fontColor, chartInstance.config.options.defaultFontColor);

      // 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';
      ctx.fillStyle = fontColor;

      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;
          var scaleMax = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
          var yPos = (scaleMax - model.y) / scaleMax >= 0.93 ? model.y + 20 : model.y - 5;
          var label = dataset.data[i] || '';
          ctx.fillText(label.toLocaleString(), model.x, yPos);
        }
      });
    }
  }
});

注意beforeDraw

希望这可以帮助3年后,我花了最后30分钟尝试解决此问题

答案 3 :(得分:0)

如果有人会寻找解决此问题的方法,则有一种更简便的方法来实现所需的OP。

而不是在onComplete回调中绘制,而在afterDatasetsDraw回调中绘制它。在工具提示被绘制之前就被调用。