Chart.js:条形图单击事件

时间:2016-05-09 18:03:11

标签: javascript chart.js

我刚刚开始使用Chart.js,我很快就感到非常沮丧。我的堆叠条形图有效,但我无法点击“事件”。

我在Chart.js中找到comment on GitHub by nnnick,表示要使用函数getBarsAtEvent,即使在Chart.js documentation中根本找不到此函数(继续,请进行搜索为了它)。文档确实提到了getElementsAtEvent引用的chart函数,但仅适用于折线图。

我在canvas元素上设置了一个事件监听器(正确的方法):

canv.addEventListener('click', handleClick, false);

...但在我的handleClick函数中,chart.getBarsAtEvent未定义!

现在,在Chart.js文档中,有一个关于为条形图注册click事件的不同方法的声明。这与2年前nnnick对GitHub的评论大不相同。

Global Chart Defaults中,您可以为图表设置onClick功能。我在我的图表配置中添加了一个onClick函数,它没有做任何事......

那么,我如何获得点击回调以适用于我的条形图?!

非常感谢任何帮助。谢谢!

P.S。:我没有使用GitHub的主版本。我试过了,但是它一直在尖叫require is undefined并且我还没准备好包括CommonJS以便我可以使用这个图表库。我宁愿写自己的dang图表。相反,我下载并使用了我直接从Standard Build顶部的链接下载的documentation page版本。

示例:以下是我正在使用的配置示例:

var chart_config = {
    type: 'bar',
    data: {
        labels: ['One', 'Two', 'Three'],
        datasets: [
            {
                label: 'Dataset 1',
                backgroundColor: '#848484',
                data: [4, 2, 6]
            },
            {
                label: 'Dataset 2',
                backgroundColor: '#848484',
                data: [1, 6, 3]
            },
            {
                label: 'Dataset 3',
                backgroundColor: '#848484',
                data: [7, 5, 2]
            }
        ]
    },
    options: {
        title: {
            display: false,
            text: 'Stacked Bars'
        },
        tooltips: {
            mode: 'label'
        },
        responsive: true,
        maintainAspectRatio: false,
        scales: {
            xAxes: [
                {
                    stacked: true
                }
            ],
            yAxes: [
                {
                    stacked: true
                }
            ]
        },
        onClick: handleClick
    }
};

9 个答案:

答案 0 :(得分:42)

通过查看Chart.js source code,我设法找到了问题的答案。

在Chart.js的第3727行提供标准构建,方法为.getElementAtEvent。这个方法返回"图表元素"被点击了。这里有足够的数据来确定在点击的数据集的深入视图中显示哪些数据。

chart.getElementAtEvent返回的数组的第一个索引是值_datasetIndex。此值显示单击的数据集的索引。

我相信,点击的特定栏会以值_index标注。在我的问题示例中,_index会指向One中的chart_config.data.labels

我的handleClick功能现在看起来像这样:

function handleClick(evt)
{
    var activeElement = chart.getElementAtEvent(evt);

..其中chart是chart.js在执行时创建的图表的引用:

chart = new Chart(canv, chart_config);

因此,点击选择的特定数据集可以在以下位置找到:

chart_config.data.datasets[activeElement[0]._datasetIndex].data[activeElement[0]._index];

你有它。我现在有一个数据点,我可以构建一个查询来显示被点击的栏的数据。

答案 1 :(得分:30)

嗨,这是选项下的点击事件,它从x轴和y轴获取值

onClick: function(c,i) {
    e = i[0];
    console.log(e._index)
    var x_value = this.data.labels[e._index];
    var y_value = this.data.datasets[0].data[e._index];
    console.log(x_value);
    console.log(y_value);
}

答案 2 :(得分:6)

我在https://github.com/valor-software/ng2-charts/issues/489

找到了这个解决方案
import UIKit

class LineUp_3_2_1View: UICollectionViewLayout {

    private var center: CGPoint!
    private var itemSize: CGSize!
    private var radiusOfCircleViews: CGFloat!
    private var numberOfItems: Int!

    override func prepare() {
        super.prepare()

        guard let collectionView = collectionView else { return }

        radiusOfCircleViews = CGFloat(30.0)
        itemSize = CGSize(width: radiusOfCircleViews * 2, height: radiusOfCircleViews * 2)
        center = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY)
        numberOfItems = collectionView.numberOfItems(inSection: 0)
    }

    override var collectionViewContentSize: CGSize {
        return collectionView!.bounds.size
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)

        if (indexPath.item == 0) {attributes.center = CGPoint(x: 169, y: 344)}
        if (indexPath.item == 1) {attributes.center = CGPoint(x: 46, y: 250)}
        if (indexPath.item == 2) {attributes.center = CGPoint(x: 169, y: 250)}
        if (indexPath.item == 3) {attributes.center = CGPoint(x: 287, y: 250)}
        if (indexPath.item == 4) {attributes.center = CGPoint(x: 80, y: 156)}
        if (indexPath.item == 5) {attributes.center = CGPoint(x: 253, y: 156)}
        if (indexPath.item == 6) {attributes.center = CGPoint(x: 169, y: 62)}

        attributes.size = itemSize

        return attributes
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return (0 ..< collectionView!.numberOfItems(inSection: 0))
            .flatMap { item -> UICollectionViewLayoutAttributes? in    // `compactMap` in Xcode 9.3
                self.layoutAttributesForItem(at: IndexPath(item: item, section: 0))
        }
    }
}

答案 3 :(得分:3)

干得好!这似乎返回了被绘制的数据值,在许多情况下可能会出现不止一次,因此不清楚点击了什么。

这将返回被点击的栏的实际数据标签。深入研究一个类别时,我发现这更有用。

chart_config.data.labels[activeElement[0]._index]

答案 4 :(得分:2)

您可以像这样使用onClick。

var worstCells3GBoxChart = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: lbls,
                    datasets: [{
                        label: 'Worst Cells by 3G',
                        data: datas,
                        backgroundColor: getColorsUptoArray('bg', datas.length),
                        borderColor: getColorsUptoArray('br', datas.length),
                        borderWidth: 1
                    }]
                },
                options: {
                    legend: {
                        display: false
                    },
                    scales: {
                        yAxes: [{
                            ticks: {
                                beginAtZero: true
                            }
                        }]
                    },
                    onClick: function (e) {
                        debugger;
                        var activePointLabel = this.getElementsAtEvent(e)[0]._model.label;
                        alert(activePointLabel);
                    }
                }
            });

答案 5 :(得分:1)

我能够以另一种方式完成这项工作。 可能不受支持,但有时候,我发现标签和价值都不足以让我获得填写演练的必要信息。

所以我所做的是为数据添加一组自定义属性:

var ctx = document.getElementById("cnvMyChart").getContext("2d");
if(theChart != null) {theChart.destroy();}
theChart = new Chart(ctx, {
type: typ,
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datakeys: ["thefirstone","thesecondone","thethirdone","thefourthone","thefifthone","thesixthone"],
datasets: [{
    label: '# of Votes',
    data: [12, 19, 3, 5, 2, 3],

...等

然后当我需要将钻取键推入另一个ajax调用时,我能够得到它:

var theDrillThroughKey = theChart.config.data.datakeys[activePoints[0]._index];

所以我真的不确定将自定义元素添加到图表的数据中是否合适,但到目前为止它在Chrome,IE和Firefox中都有用。我需要能够将更多信息输入到钻孔中,而不是我真正希望显示的内容。

完整的例子:https://wa.rrdsb.com/chartExamples

思想?

答案 6 :(得分:1)

我对多个数据集有相同的问题,并使用了以下解决方法:

var clickOnChart = function(dataIndex){
    ...
}
var lastHoveredIndex = null;
var chart_options = {
    ...
    tooltips: {
        ...
        callbacks: {
            label: function(tooltipItem, chart) {
                var index = tooltipItem.datasetIndex;
                var value  = chart.datasets[index].data[0];
                var label  = chart.datasets[index].label;

                lastHoveredIndex = index;

                return value + "€";
            }
        }
    },
    onClick:function(e, items){
        if ( items.length == 0 ) return; //Clicked outside any bar.

        clickOnChart(lastHoveredIndex);
    }
}

答案 7 :(得分:0)

假设您使用如下方法声明图表:

  window.myBar = new Chart({chart_name}, {
       type: xxx,
       data: xxx,
       events: ["click"],
       options: {
           ...
       }
  });

声明onclick事件的一种好方法是监听画布点击,如下所示:

({chart_name}.canvas).onclick = function(evt) {
     var activePoints = myBar.getElementsAtEvent(evt);
     // let's say you wanted to perform different actions based on label selected
     if (activePoints[0]._model.label == "label you are looking for") { ... }
}

答案 8 :(得分:0)

Chartjs V3.4.1

在查看旧版本的解决方案后,这对我在 v3 中有用:

const onClick = (event, clickedElements) => {
  if (clickedElements.length === 0) return

  const { dataIndex, raw } = clickedElements[0].element.$context
  const barLabel = event.chart.data.labels[dataIndex]
  ...
}
  • raw 是点击栏的值。
  • barLabel 是点击栏的标签。

您需要将 onClick 传递给条形图配置:

const barConfig = {
  ...
  options: {
    responsive: true,
    onClick,
    ...
  }
}