javascript - 如何在 Chart.JS 中显示饼图上的数据子集,同时在悬停时仍显示超集?

标签 javascript drawing chart.js pie-chart chart.js2

我有一个饼图,当鼠标悬停在一 block 饼上时,它看起来像这样:

enter image description here

除了想要图例 to the right instead of on top ,我对此相当满意,但我只想在饼图中“始终”显示百分比值 - 并且仍然有 <name> (<%val>): <data>悬停时显示。

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

enter image description here

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

这是我迄今为止使用的代码:

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() 事件,如果需要,它需要如何实现这一点?

更新

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

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

...但它什么也没做。

更新2

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

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

...结果相同(没有变化)。

更新3

好吧,我希望答案 here会起作用,并最终根据那里的答案为我的饼图提供了这个新代码:

添加到选项Pie:

showTooltips: false,
onAnimationProgress: drawSegmentValues

检索到元素的引用后添加:

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

饼图实例构建后添加:

var radius = top10PieChart.outerRadius;

添加了函数drawSegmentValues()

在上下文中(没有双关语):

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

...但它完全冲洗了所有三个图表,没有留下任何可见/绘图。

更新4

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

此外,相关的 fiddle 显示了值和百分比;由于房地产限制,我希望百分比仅“始终开启” - “整个辣酱 Jade 米饼馅”仅在悬停时才能看到。

最佳答案

以下解决方案使用与 lamelemon's 相同的计算但使用 Chart.js plugins ,这带来了额外的好处:

  • 不再有由 animation.onComplete 引起的闪烁效果,因为它会立即发生,无需等待任何事情。

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

遵循执行此操作的插件:

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

<小时/> 您可以检查此插件是否正常工作 on this jsFiddle ,这是结果:

enter image description here

关于javascript - 如何在 Chart.JS 中显示饼图上的数据子集,同时在悬停时仍显示超集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39646320/

相关文章:

iphone - 在 Quartz (iPhone SDK) 中绘制(打印 - 不是图表)方程

javascript - 如何在堆叠条形顶部显示 "total"总和标签

javascript - 如何使用chart.js在水平条中设置标签左对齐?

javascript - Chart.js 自动调整失败

java - 我应该如何创建一个函数以便在处理 3 中生成规则的 3D 金字塔?

javascript - 在 Jest : "TypeError: admin.firestore is not a function" 中模拟 Firebase 管理员时出错

javascript - 世博会: "auth/operation-not-supported-in-this-enviroment"

javascript - 如何让js中创建的div在点击动态创建的td后填满屏幕?

javascript - 根据地理位置获取最近距离

java - 如何在 Canvas 上用 SWT 画一 strip 箭头的线