在悬停时仍显示超集的同时,如何在Chart.JS中显示饼图中的数据子集? [英] How can I show a subset of data on pie pieces in Chart.JS while still displaying the superset when hovering?

查看:109
本文介绍了在悬停时仍显示超集的同时,如何在Chart.JS中显示饼图中的数据子集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当鼠标悬停在一块饼上时,我得到了一个饼图,如下所示:

I've got a pie chart that looks like this when hovering over a piece of pie:

除了需要图例之外<name> (<%val>): <data>.

Except for wanting the legend to the right instead of on top, I'm fairly content with this, but I want just the percentage value to display "all the time" in the pie pieces - and still have the <name> (<%val>): <data> displayed on hover.

换句话说,我希望馅饼看起来像这样:

In other words, I want the pie to look something like this:

我该如何分解一个数据(百分比)并将其绘制到每个饼图上?

How can I break that one piece of data out (the percentage) and draw that onto each piece of pie?

这是到目前为止我正在使用的代码:

Here is the code I'm using so far:

var formatter = new Intl.NumberFormat("en-US");
var data = {
    labels: [
        "Bananas (18%)",
        "Lettuce, Romaine (14%)",
        "Melons, Watermelon (10%)",
        "Pineapple (10%)",
        "Berries (10%)",
        "Lettuce, Spring Mix (9%)",
        "Broccoli (8%)",
        "Melons, Honeydew (7%)",
        "Grapes (7%)",
        "Melons, Cantaloupe (7%)"
    ],
    datasets: [
        {
            data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048],
            backgroundColor: [
                "#FFE135",
                "#3B5323",
                "#fc6c85",
                "#ffec89",
                "#021c3d",
                "#3B5323",
                "#046b00",
                "#cef45a",
                "#421C52",
                "#FEA620"
            ]
        }
    ]
};

var optionsPie = {
    responsive: true,
    scaleBeginAtZero: true,
    tooltips: {
        callbacks: {
            label: function (tooltipItem, data) {
                return data.labels[tooltipItem.index] + ": " +
                    formatter.format(data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]);
            }
        }
    }
};

var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx,
{
    type: 'pie',
    data: data,
    options: optionsPie
});

$("#top10Legend").html(top10PieChart.generateLegend());

我是否需要添加一个afterDraw()事件,如果需要,那么它看起来应该如何实现?

Do I need to add an afterDraw() event and, if so, just how does it need to look to accomplish this?

我尝试将onAnimationComplete()回调添加到图表构造函数中:

I tried adding an onAnimationComplete() callback to the chart constructor:

var top10PieChart = new Chart(ctx,
{
    type: 'pie',
    data: data,
    options: optionsPie,
    onAnimationComplete: function () {
        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor;
        ctx.textAlign = "center";
        ctx.textBaseline = "center";

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

...但是它什么也没做.

...but it does nothing.

我还尝试将以下内容附加到options对象:

I also tried appending the following to the options object:

,
tooltipTemplate: "<%= value %>",
onAnimationComplete: function () {
    this.showTooltip(this.datasets[0].bars, true);
}

...结果相同(不变).

...with the same results (no change).

好的,我希望答案

Okay, I was hopeful that the answer here would work, and ended up with this new code for my pie chart based on the answer there:

已添加到选项饼中:

showTooltips: false,
onAnimationProgress: drawSegmentValues

在检索元素引用后添加:

Added after reference to element is retrieved:

var midX = canvas.width / 2;
var midY = canvas.height / 2

在构造饼图实例之后添加:

Added after pie chart instance is constructed:

var radius = top10PieChart.outerRadius;

添加了函数drawSegmentValues()

Added function drawSegmentValues()

在上下文中(无双关语):

In context (no pun intended):

        // Top 10 Pie Chart
        var formatter = new Intl.NumberFormat("en-US");
        var data = {
            labels: [
                "Bananas (18%)",
                "Lettuce, Romaine (14%)",
                "Melons, Watermelon (10%)",
                "Pineapple (10%)",
                "Berries (10%)",
                "Lettuce, Spring Mix (9%)",
                "Broccoli (8%)",
                "Melons, Honeydew (7%)",
                "Grapes (7%)",
                "Melons, Cantaloupe (7%)"
            ],
            datasets: [
                {
                    data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076
1056, 1048],
                    backgroundColor: [
                        "#FFE135",
                        "#3B5323",
                        "#fc6c85",
                        "#ffec89",
                        "#021c3d",
                        "#3B5323",
                        "#046b00",
                        "#cef45a",
                        "#421C52",
                        "#FEA620"
                    ]
                }
            ]
        };

        var optionsPie = {
            responsive: true,
            scaleBeginAtZero: true,
            legend: {
                display: false
            },
            tooltips: {
                callbacks: {
                    label: function (tooltipItem, data) {
                        return data.labels[tooltipItem.index] + ": " +
                         formatter.format
data.datasets[tooltipItem.datasetIndex].data[
tooltipItem.index]);
                    }
                }
            },
            showTooltips: false,
            onAnimationProgress: drawSegmentValues
        };

        var ctx = $("#top10ItemsChart").get(0).getContext("2d");
        var midX = canvas.width / 2;
        var midY = canvas.height / 2
        var top10PieChart = new Chart(ctx,
        {
            type: 'pie',
            data: data,
            options: optionsPie//,
        });
        var radius = top10PieChart.outerRadius;

        $("#top10Legend").html(top10PieChart.generateLegend());
        // </ Top 10 Pie Chart

        // Price Compliance Bar Chart
        . . . this horizontal bar chart code elided for brevity, bu
unchanged from their working state
        // Forecast/Impact Analysis Bar chart
        . . . this horizontal bar chart code also elided for brevity, bu
unchanged from their working state

    function drawSegmentValues() {
        for (var i = 0; i < top10PieChart.segments.length; i++) {
            ctx.fillStyle = "white";
            var textSize = canvas.width / 10;
            ctx.font = textSize + "px Verdana";
            // Get needed variables
            var value = top10PieChart.segments[i].value;
            var startAngle = top10PieChart.segments[i].startAngle;
            var endAngle = top10PieChart.segments[i].endAngle;
            var middleAngle = startAngle + ((endAngle - startAngle)
2);

            // Compute text location
            var posX = (radius / 2) * Math.cos(middleAngle) + midX;
            var posY = (radius / 2) * Math.sin(middleAngle) + midY;

            // Text offside by middle
            var w_offset = ctx.measureText(value).width / 2;
            var h_offset = textSize / 4;

            ctx.fillText(value, posX - w_offset, posY + h_offset);
        }
    }

...但是它完全淹没了所有三个图表,没有任何可见/绘图.

...but it completely hosed all three charts, leaving nothing visible/drawing.

顺便说一句,我尝试了给定的答案,但是没有结果/更改-它仍然按设计显示悬停数据,但是没有其他内容.

By the way, I tried the given answer, but with no result/change - it still displays data on hover, as designed, but there is nothing otherwise.

此外,相关的小提琴同时显示了值和百分比;由于房地产方面的限制,我希望该百分比始终保持不变-仅在悬停时才能看到整个辣酱玉米饼馅".

Also, the related fiddle shows both the value and the percentage; due to real estate restrictions, I want the percentage only to be "always on" - the "whole enchilada" is only to be seen when hovering.

推荐答案

以下解决方案使用的计算与 lamelemon's ,但使用 Chart.js插件,它带来了其他好处:

The following solution is using the same calculation as lamelemon's but using Chart.js plugins, which brings additional benefits :

  • 不再存在由animation.onComplete引起的眨眼效果,因为它是立即发生的而无需等待麻醉.

  • There is no longer this blink effect caused by the animation.onComplete since it occurs immediatly without waiting for antything.

工具提示位于文本上方,更加自然.

The tooltip is above the text, which is more natural.

关注执行该操作的插件:

Follows the plugin that does it :

Chart.pluginService.register({
    afterDatasetsDraw: function(chartInstance) {

        // We get the canvas context
        var ctx = chartInstance.chart.ctx;

        // And set the properties we need
        ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom';
        ctx.fillStyle = '#666';

        // For ervery dataset ...
        chartInstance.config.data.datasets.forEach(function(dataset) {

            // For every data in the dataset ...
            for (var i = 0; i < dataset.data.length; i++) {

                // We get all the properties & values we need
                var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                    total = dataset._meta[Object.keys(dataset._meta)[0]].total,
                    mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius) / 2,
                    start_angle = model.startAngle,
                    end_angle = model.endAngle,
                    mid_angle = start_angle + (end_angle - start_angle) / 2;

                // We calculate the right positions for our text
                var x = mid_radius * 1.5 * Math.cos(mid_angle);
                var y = mid_radius * 1.5 * Math.sin(mid_angle);

                // We calculate the percentage
                var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
                // And display it
                ctx.fillText(percent, model.x + x, model.y + y);
            }
        });
    }
});


您可以在此jsFiddle上检查正常工作的插件,结果如下:


You can check this plugin working on this jsFiddle, and here is the result :

这篇关于在悬停时仍显示超集的同时,如何在Chart.JS中显示饼图中的数据子集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆