Chart.js 从右到左显示 x 轴数据数据、Chart、js、右到左

2023-09-07 11:53:57 作者:此Q已暂停使用

我正在处理chart.js 垂直图表,我想对其显示方式稍作改动.

I am working on the chart.js vertical chart and I want to make a slight change in the way it displays.

基本上第一个数据将从左侧显示,但我想从右侧显示第一个数据.这可能吗?

Basically the first data will be displayed from the left but I want to display first data from right. Is that possible?

这是我目前所拥有的工作版本:

Here is the working version of what I have so far:

https://jsfiddle.net/wxaL6en0/4/

   options: {

      responsive: true,
      maintainAspectRatio: false,

      legend: {
        display: false,
      }
   }

这是我为选项所做的.

我期望的结果是,April 在右侧,第一个栏显示在右侧.

The result I am expecting is, April to be on the right and first bar to display on the right.

我不确定这是否可行,因为我在互联网上没有找到任何解决方案.但我希望以前有人尝试过.

I am not sure this is possible since I didn't find any solution over the internet. But I hope someone tried this before.

推荐答案

不幸的是,Chart.js 2.8.0 似乎只支持 yAxes 的刻度对象的反向布尔参数.

这意味着,如果没有黑客或猴子补丁,它就无法在 Chart.js API 中完成.

This means, that without hacking or monkey patching it cannot be done within Chart.js API.

此外,我想出的这个肮脏的解决方案似乎是过度设计的,因为通过索引引用它来简单地更改 dataset.data 数组项并不能正确触发 Chart.js 动画,因此需要使用拼接.

Also this dirty solution I came up with seems to be over-engineered, because simply changing dataset.data array item by referring to it by its index does not trigger Chart.js animations properly, therefore one needs to use splice.

说明:

其实这个想法很简单:

为了从右到左显示先验已知数量的条形需要首先创建一个长度等于条数的数组并用空值填充它.换句话说,一个包含与要显示的条形一样多的空值的数组.

In order to show bars from right to left for a priori known number of them One needs to first create an array of length equal to number of bars and fill it with nulls. In other words an array containing as many nulls as there are bars to be displayed.

然后每个新值都必须从右侧(数组末尾)插入(使用拼接)在数组项为空的第一个索引处,或者只是在正确的索引处,从 array.length - 1 倒数到0.

Then each new value has to be inserted (using splice) from the right (end of the array) at first index under which array item is null or just simply at correct index, counting down from the array.length - 1 to 0.

可视化":

let value = 1;

const graphData = Array(3).fill(null);
console.log(graphData)

for(let i = graphData.length - 1; i >= 0; --i){
    graphData.splice(i, 1, value++);
    console.log(graphData)
}

示例:

class GraphController {
    size = 0;
    data = [];
    labels = [];
    graphData = [];
    ctx = null;
    chart = null;

    constructor(size, data, labels, canvasId) {
        this.size = size;
        this.data = data;
        this.labels = labels;

        this.ctx = document.getElementById(canvasId).getContext('2d');

        this.graphData = Array(size).fill(null);
    }

    fetchAndDraw(index = 1) {
        const item = this.data[index - 1];
        if (item.TotalReward) {
            this.graphData[this.size - index] = item.TotalReward;
        }

        if (index > 1 && index < this.size) {
            this.chart.data.datasets[0].data.splice(this.size - index, 1, item.TotalReward);
            this.chart.update();
        } else {
            if (this.chart) {
                this.chart.destroy();
            }

            this.chart = new Chart(this.ctx, {
                type: 'bar',
                data: {
                    labels: this.labels,
                    datasets: [{
                        data: [...this.graphData],
                        backgroundColor: '#fff',
                        hoverBackgroundColor: '#d5d5d5',
                        borderWidth: 0
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    legend: {
                        display: false,
                    },
                    title: {
                        display: false,
                    },
                    tooltips: {
                        enabled: false,
                    },
                    scales: {
                        xAxes: [{
                            barPercentage: 1.0,
                            categoryPercentage: 0.55,
                            gridLines: {
                                display: false,
                                color: '#fff',
                                drawBorder: false,
                                zeroLineColor: '#fff'
                            },
                            ticks: {
                                fontFamily: '"Avenir Next", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
                                fontSize: 16,
                                fontColor: '#fff',
                                padding: 15,
                            }
                        }],
                        yAxes: [{
                            categoryPercentage: 0.8,
                            barPercentage: 0.8,
                            gridLines: {
                                display: false,
                                color: '#fff',
                                drawBorder: false,
                                zeroLineColor: '#fff'
                            },
                            ticks: {
                                min: 0,
                                stepSize: 10,
                                fontFamily: '"Avenir Next", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
                                fontSize: 16,
                                fontColor: '#fff',
                                padding: 10,
                                callback: function (value) {
                                    return '$' + value;
                                }
                            }
                        }],
                    },
                },
            });
        }

        index++;
        if (index <= this.size) {
            setTimeout(() => {
                this.fetchAndDraw(index);
            }, 1000);
        }
    }
}



const data = [
    { "Month": "April ‘18", "TotalReward": 10.37 },
    { "Month": "May ‘18", "TotalReward": 18.11 },
    { "Month": "June ‘18", "TotalReward": 25.49 },
    { "Month": "January", "TotalReward": 35.55 },
    { "Month": "February", "TotalReward": 50.25 },
    { "Month": "March", "TotalReward": 59.15 },
]

const rewardLabels = ["April ‘18", "May ‘18", "June ‘18", "January", "February", "March"].reverse();

const graph = new GraphController(6, data, rewardLabels, 'rewardChart');
graph.fetchAndDraw();

.chart-wrap {
  background: #333;
  padding: 20px 10px;
}

<link href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrap">
  <canvas id="rewardChart" width="600" height="165"></canvas>
</div>