簡體   English   中英

如何計算值並將其放在Chart.JS條形圖的最后一個欄中?

[英]How can I calculate a value and place it inside the last bar in a Chart.JS bar chart?

由於在條形圖上最后一個條形圖上方放置標簽似乎不可能或非常困難( 這里沒有工作答案),我現在想知道如何在最后一個條形圖中放置標簽。

我使用以下代碼為水平條形圖的所有條形添加標簽:

Chart.pluginService.register({
    afterDraw: function (chartInstance) {
        if (chartInstance.id !== 1) return; // affect this one only
        var ctx = chartInstance.chart.ctx;
        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(14, 'bold', 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] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
            }
        });
    }
});

該工作圖表如下所示:

在此輸入圖像描述

...但這是一個“常規”(垂直)條形圖,我嘗試將標簽添加到最后一個條形圖中,如下所示:

Chart.pluginService.register({
    afterDraw: function (chartInstance) {
        if (chartInstance.id !== 2) return; // affect this one only
        var ctx = chartInstance.chart.ctx;
        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'center';

        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
        ctx.fillText(dataset.data[dataset.data.length - 1]);
    }
});

...失敗(沒有任何顯示,事實上,它不僅導致其自身外觀問題,而且導致頁面上其他圖表的問題,即使我使用代碼僅將此事件應用於此特定圖表:

在此輸入圖像描述

那么如何計算一個值(基於最后和倒數第二個條形值),然后將計算出的“標簽”放在Chart.JS條形圖的最后一個條形圖內?

使用上面嘗試的代碼,我只是想獲得條形內部條形的原始值; 邏輯的計算部分可以保留到以后。

一種可能性是使它成為一個堆積的條形圖,沒有任何條添加到任何條形而是最后一條,然后使其背景顏色為白色以與圖表背景融合...

UPDATE

我嘗試了最后一個想法; 想想也許我可以通過將我的圖表變成堆積條形圖(來自簡單的條形圖)來完成我想要的東西,添加第二組大多數“零”數據作為堆棧的第二部分,如下所示:

舊代碼摘錄:

var forecastChartData = {
    labels: [
        "Total Sales"
    ],
    datasets: [
    {
        label: "8/28/2016 - 9/3/2016",
        backgroundColor: "rgba(255,0,0,0.75)",
        hoverBackgroundColor: "rgba(255,0,0,1)",
        data: [240]
    },
    {
        label: "9/4/2016 - 9/10/2016",
        backgroundColor: "rgba(255,153,0,0.75)",
        hoverBackgroundColor: "rgba(255,153,0,1)",
        data: [272]
    },
    {
        label: "9/11/2016 - 9/17/2016",
        backgroundColor: "rgba(255,255,0,0.75)",
        hoverBackgroundColor: "rgba(255,255,0,1)",
        data: [250]
    },
    {
        label: "9/18/2016 - 9/24/2016",
        backgroundColor: "rgba(0,255,0,0.75)",
        hoverBackgroundColor: "rgba(0,255,0,1)",
        data: [232]
    },
    {
        label: "9/25/2016 - 10/1/2016",
        backgroundColor: "rgba(0,0,255,0.75)",
        hoverBackgroundColor: "rgba(0,0,255,1)",
        data: [244]
    }],
};

var forecastOptions = {
    tooltips: {
        enabled: true
    }
};

新代碼:

var forecastChartData = {
    labels: [
        "Total Sales"
    ],
    datasets: [
    {
        label: "8/28/2016 - 9/3/2016",
        backgroundColor: "rgba(255,0,0,0.75)",
        hoverBackgroundColor: "rgba(255,0,0,1)",
        data: [240]
    },
    {
        label: "9/4/2016 - 9/10/2016",
        backgroundColor: "rgba(255,153,0,0.75)",
        hoverBackgroundColor: "rgba(255,153,0,1)",
        data: [272]
    },
    {
        label: "9/11/2016 - 9/17/2016",
        backgroundColor: "rgba(255,255,0,0.75)",
        hoverBackgroundColor: "rgba(255,255,0,1)",
        data: [250]
    },
    {
        label: "9/18/2016 - 9/24/2016",
        backgroundColor: "rgba(0,255,0,0.75)",
        hoverBackgroundColor: "rgba(0,255,0,1)",
        data: [232]
    },
    {
        label: "9/25/2016 - 10/1/2016",
        backgroundColor: "rgba(0,0,255,0.75)",
        hoverBackgroundColor: "rgba(0,0,255,1)",
        data: [244]
    }],
    [{
        backgroundColor: "rgba(255, 255, 255, 0.5)",
        hoverBackgroundColor: "rgba(200, 200, 200, 1)",
        data: [0, 0, 0, 0, 5.2]
    }]
};

var forecastOptions = {
    scales: {
        xAxes: [
        {
            stacked: true
        }
        ],
        yAxes: [
        {
            stacked: true
        }
        ]
    },
    tooltips: {
        enabled: true
    }
};

但它根本沒有幫助; 我究竟做錯了什么; 如果一切,我怎么能用我的新代碼追求核選項后繼續?

更新2

從陳英雄的代碼在這里讓我接近。 我現在的選擇是:

var forecastOptions = {
    tooltips: {
        enabled: true
    },
    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);
                }
            });
        }
    }
};

...它將數據值放在每個條形圖上方。

如上所述,這接近我想要的; 但是,我真正想要的是最后一個值和當前值之間的差異。 例如,使用此圖表:

在此輸入圖像描述

......我想看到的是:

240,272(30),250(-22),232(-18),244(12)

或者也許只是一個高於最后一個柱的值,“ 244(12) ”或“ 12 ”。

這就是他們所說的(后者),但如果他們改變主意並想要所有的val /差異,我也不會感到驚訝。

更新3

該解決方案在條形圖上方沒有添加任何值,並吃掉我的一塊餡餅:

在此輸入圖像描述

更新4

這里幾乎是Index.cshtml中的所有代碼:

    <style>

        .pieLegend li span {
            display: inline-block;
            width: 12px;
            height: 12px;
            margin-right: 5px;
        }

        #piechartlegendleft {
            height: 360px;
            width: 100%;
        }

        #top10Legend {
            display: inline-block;
        }

            #top10Legend > ul {
                list-style: none;
            }

        #container {
            display: inline-block;
            height: 50%;
            width: 50%;
        }
    </style>
    <script>
        $(document).ready(function () {
            $("body").on("click", "#btnGetData",
        . . .
                    });

            Chart.defaults.global.defaultFontFamily = "Candara";
            Chart.defaults.global.defaultFontSize = 16;

            // Top 10 Pie Chart
            var formatter = new Intl.NumberFormat("en-US");

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

                    ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'bottom';
                    ctx.fillStyle = '#666';

                    chartInstance.config.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,
                                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;

                            var x = mid_radius * 1.5 * Math.cos(mid_angle);
                            var y = mid_radius * 1.5 * Math.sin(mid_angle);

                            ctx.fillStyle = '#fff';
                            if (i === 0 || i === 3 || i === 7 || i === 9) { // Darker text color for lighter background
                                ctx.fillStyle = '#000';
                            }
                            var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
                            // this prints the data number
                            // this prints the percentage
                            ctx.fillText(percent, model.x + x, model.y + y);
                        }
                    });
                }
            });

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

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

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

            // Price Compliance Bar Chart
            Chart.pluginService.register({
                afterDraw: function (chartInstance) {
                    if (chartInstance.id !== 1) return; // affect this one only
                    var ctx = chartInstance.chart.ctx;
                    // render the value of the chart above the bar
                    ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'bottom';

                    ctx.fillStyle = "#000";

                    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] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
                        }
                    });
                }
            });

            var ctxBarChart = $("#priceComplianceBarChart").get(0).getContext("2d");
            var priceComplianceData = {
                labels: [
                    "Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce",
                    "Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"
                ],
                datasets: [
                {
                    label: "Price Compliant",
                    backgroundColor: "rgba(34,139,34,0.5)",
                    hoverBackgroundColor: "rgba(34,139,34,1)",
                    data: [99.0, 99.2, 99.4, 98.9, 99.1, 99.5, 99.6, 99.2, 99.7]
                },
                {
                    label: "Non-Compliant",
                    backgroundColor: "rgba(255, 0, 0, 0.5)",
                    hoverBackgroundColor: "rgba(255, 0, 0, 1)",
                    data: [1.0, 0.8, 0.6, 1.1, 0.9, 0.5, 0.4, 0.8, 0.3]
                }
                ]
            }

            var priceComplianceOptions = {
                scales: {
                    xAxes: [
                    {
                        stacked: true
                    }],
                    yAxes: [
                    {
                        stacked: true
                    }]
                },
                tooltips: {
                    enabled: false
                }
            };

            var priceBarChart = new Chart(ctxBarChart,
            {
                type: 'horizontalBar',
                data: priceComplianceData,
                options: priceComplianceOptions
            });
            // </Price Compliance Bar Chart

            // Forecast/Impact Analysis chart
            var ctxForecastChart = $("#forecastLineChart"); //.get(0).getContext("2d");
            // See if the "olde style" makes any diff (used by the Chart.JS Whisperer)
            //var ctxForecastChart = document.getElementById("forecastLineChart"); // no diff

            var forecastChartData = {
                labels: ["Total Sales"],
                datasets: [
                {
                    label: "8/28/2016 - 9/3/2016",
                    backgroundColor: "rgba(255,0,0,0.75)",
                    hoverBackgroundColor: "rgba(255,0,0,1)",
                    data: [240]
                },
                {
                    label: "9/4/2016 - 9/10/2016",
                    backgroundColor: "rgba(255,153,0,0.75)",
                    hoverBackgroundColor: "rgba(255,153,0,1)",
                    data: [272]
                },
                {
                    label: "9/11/2016 - 9/17/2016",
                    backgroundColor: "rgba(255,255,0,0.75)",
                    hoverBackgroundColor: "rgba(255,255,0,1)",
                    data: [250]
                },
                {
                    label: "9/18/2016 - 9/24/2016",
                    backgroundColor: "rgba(0,255,0,0.75)",
                    hoverBackgroundColor: "rgba(0,255,0,1)",
                    data: [232]
                },
                {
                    label: "9/25/2016 - 10/1/2016",
                    backgroundColor: "rgba(0,0,255,0.75)",
                    hoverBackgroundColor: "rgba(0,0,255,1)",
                    data: [244]
                }]
        };

        var forecastOptions = {
            tooltips: {
                enabled: true
            },
            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);
                            }
                        });
                    }
                }
            };

        var forecastBarChart = new Chart(ctxForecastChart, {
            type: 'bar',
            //type: 'line',
            data: forecastChartData,
            options: forecastOptions
        });
        // </ Forecast/Impact Analysis chart

        $('#delperfTable').DataTable({
            "paging": false,
            "info": false,
            "searching": false
        });
        });


    </script>
</head>

<body>
    <div class="container body-content">
        <div class="jumbotronjr">
            <div class="col-md-3" style="margin-top: 0.6cm">
                <img src="http://www.proactusa.com/wp-content/themes/proact/images/pa_logo_notag.png" height="86" width="133" alt="PRO*ACT usa logo">
            </div>
            <div class="col-md-9">
                <label class="titletext" style="margin-top: 0.2cm;">Customer Dashboard</label>
                <br />
                <label class="titletextjr" style="margin-top: -2.2cm;" id="unitName">SODEXO</label>
                <label class="cccsfont"> for the week of September 25          </label>
                <input class="smalldatepicker" type="date" id="datepickerFrom" value="2016-09-25">
                </input>
                <label class="cccsfont"> to </label>
                <input type="date" class="smalldatepicker" id="datepickerTo" value="2016-10-01">
                </input>
                <span id="newhourglass" class="fa fa-4x fa-refresh fa-spin boxRefresh hide" runat="server"></span>
                <button class="btn btn-success btn-sm green" id="btnGetData"><span class="glyphicon glyphicon-refresh"></span></button>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <hr />
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
            </div>
        </div>

        <div class="row" id="top10Items">
            <div class="col-md-6">
                <div class="topleft">
                    <h2 class="sectiontext">Top 10 Items</h2>
                    <br />
                    <div id="piechartlegendleft">
                        <div id="container">
                            <canvas id="top10ItemsChart" width="800" height="800"></canvas>
                        </div>
                        <div id="top10Legend" class="pieLegend"></div>
                    </div>
                </div>
            </div>

            <div class="col-md-6">
                <div class="topright">
                    <h2 class="sectiontext">Price Compliance</h2>
                    <div class="graph_container">
                        <canvas id="priceComplianceBarChart"></canvas>
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-6">
                <div class="bottomleft">
                    <h2 class="sectiontext">Forecast/Impact Analysis</h2>
                    <div class="graph_container">
                        <canvas id="forecastLineChart"></canvas>
                    </div>
                </div>
            </div>

            <div class="col-md-6">
                <div class="bottomright">
                    <h2 class="sectiontext">Delivery Performance</h2>
                    <table id="delperfTable">
            . . .
                    </table>
                </div>
            </div>
        </div>

    </div>
</body>
</html>

animation.onComplete回調中,您可以使用以下代碼獲取以前的數據集:

// `dataset` here -----------------------------------------┐
// is the current dataset you are working on               |
// (since you loop through all of them in your callback)   V
var previousDataset = chartInstance.config.data.datasets[dataset._meta[Object.keys(dataset._meta)[0]].controller.index - 1];

現在您可以訪問以前的數據集,也可以獲取其值。 按照完整的回調使其更容易理解:

var forecastOptions = {
    tooltips: {
        enabled: true
    },
    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++) {

                    // We get the previous dataset here
                    var previousDataset = dataset._meta[Object.keys(dataset._meta)[0]].controller.chart.config.data.datasets[dataset._meta[Object.keys(dataset._meta)[0]].controller.index - 1];

                    var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                    var scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                    ctx.fillStyle = '#444';
                    var y_pos = model.y - 5;
                    if ((scale_max - model.y) / scale_max >= 0.93)
                        y_pos = model.y + 20;

                    // If the previous dataset is not `undefined` (actually exists) ..
                    if(typeof previousDataset !== "undefined") {
                        // We write the data, with the difference with the previous one
                        ctx.fillText(dataset.data[i] + " (" + (dataset.data[i] - previousDataset.data[i]) + ")", model.x, y_pos);
                    }
                    else {
                        // We only write the data
                        ctx.fillText(dataset.data[i], model.x, y_pos);
                    }
                }
            });
        }
    }
};

你可以在這個jsFiddle上看到這個回調,這是它的結果:

在此輸入圖像描述

注意:如果您需要任何小的更改(例如百分比差異),請隨時發表評論。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM