8

Looking For a method to add onClick handle on the "label" element in chartjs 2.0 As using below method will return "undifined" in console.log whenever clicking on any one of the label attributes in Char.js V2.0 RadarChart.

var data = {
    // below line is the labels 
    labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
    datasets: [
        {
            label: "My First dataset", //this only shows as legend, not label.

            backgroundColor: "rgba(179,181,198,0.2)",
            borderColor: "rgba(179,181,198,1)",
            pointBackgroundColor: "rgba(179,181,198,1)",
            pointBorderColor: "#fff",
            pointHoverBackgroundColor: "#fff",
            pointHoverBorderColor: "rgba(179,181,198,1)",
            data: [65, 59, 90, 81, 56, 55, 40]
        },
       ....

//Below is how to OnClick on chart points in chart.js V2, 
//However, it didn't apply to labels, will return "undifined" .   
$('#ChartV2').click(function(e) {
                var activePoints = myRadarChart.getElementsAtEvent(e);                  
                var firstPoint = activePoints[0];
                console.log(firstPoint);
                if (firstPoint !== undefined){
                   alert(firstPoint._index);                        
                }
 });

4

4 回答 4

11

在 chart.js 2.5(可能更早)中,您可以在选项中放置一个 onClick:

'legend' : {
    'onClick' : function (evt, item) {
                    console.log ('legend onClick', evt, item);
                },
    'display' : true,
    'labels' : ...
于 2017-02-14T13:23:12.923 回答
9

getElementsAtEvent仅检查图表的主要元素(条形、点、扇区...)。如果您也想考虑标签,则必须重新实现标签的功能。

您需要的大部分代码已经在 Chart.js 库代码中以不同的方法提供。只需复制粘贴/清理,如下所示。


脚本

您的点击处理程序应该是

$('#myChart').click(function (e) {
    var helpers = Chart.helpers;

    var eventPosition = helpers.getRelativePosition(e, myRadarChart.chart);
    var mouseX = eventPosition.x;
    var mouseY = eventPosition.y;

    var activePoints = [];
    // loop through all the labels
    helpers.each(myRadarChart.scale.ticks, function (label, index) {
        for (var i = this.getValueCount() - 1; i >= 0; i--) {
            // here we effectively get the bounding box for each label
            var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);

            var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize);
            var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle);
            var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily);
            var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
            ctx.font = pointLabeFont;

            var labelsCount = this.pointLabels.length,
                halfLabelsCount = this.pointLabels.length / 2,
                quarterLabelsCount = halfLabelsCount / 2,
                upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
                exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
            var width = ctx.measureText(this.pointLabels[i]).width;
            var height = pointLabelFontSize;

            var x, y;

            if (i === 0 || i === halfLabelsCount)
                x = pointLabelPosition.x - width / 2;
            else if (i < halfLabelsCount)
                x = pointLabelPosition.x;
            else
                x = pointLabelPosition.x - width;

            if (exactQuarter)
                y = pointLabelPosition.y - height / 2;
            else if (upperHalf)
                y = pointLabelPosition.y - height;
            else
                y = pointLabelPosition.y

            // check if the click was within the bounding box
            if ((mouseY >= y && mouseY <= y + height) && (mouseX >= x && mouseX <= x + width))
                activePoints.push({ index: i, label: this.pointLabels[i] });
        }
    }, myRadarChart.scale);

    var firstPoint = activePoints[0];
    if (firstPoint !== undefined) {
        alert(firstPoint.index + ': ' + firstPoint.label);
    }
});

小提琴 - http://jsfiddle.net/1Lngmtz7/

于 2016-05-05T17:50:04.320 回答
1

通过将标签位置计算从 RadialLinear 比例复制到事件处理程序中,我为 2.8.0 版提出了一个解决方案。

document.getElementById("myChart").onclick = function (e) {
    var helpers = Chart.helpers;
    var scale = myRadarChart.scale;
    var opts = scale.options;
    var tickOpts = opts.ticks;

    // Position of click relative to canvas.
    var mouseX = e.offsetX;
    var mouseY = e.offsetY;

    var labelPadding = 5; // number pixels to expand label bounding box by

    // get the label render position
    // calcs taken from drawPointLabels() in scale.radialLinear.js
    var tickBackdropHeight = (tickOpts.display && opts.display) ?
        helpers.valueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize)
        + 5: 0;
    var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
    for (var i = 0; i < scale.pointLabels.length; i++) {
        // Extra spacing for top value due to axis labels
        var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
        var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);

        // get label size info.
        // TODO fix width=0 calc in Brave?
        // https://github.com/brave/brave-browser/issues/1738
        var plSize = scale._pointLabelSizes[i];

        // get label textAlign info
        var angleRadians = scale.getIndexAngle(i);
        var angle = helpers.toDegrees(angleRadians);
        var textAlign = 'right';
        if (angle == 0 || angle == 180) {
            textAlign = 'center';
        } else if (angle < 180) {
            textAlign = 'left';
        }

        // get label vertical offset info
        // also from drawPointLabels() calcs
        var verticalTextOffset = 0;
        if (angle === 90 || angle === 270) {
            verticalTextOffset = plSize.h / 2;
        } else if (angle > 270 || angle < 90) {
            verticalTextOffset = plSize.h;
        }

        // Calculate bounding box based on textAlign
        var labelTop = pointLabelPosition.y - verticalTextOffset - labelPadding;
        var labelHeight = 2*labelPadding + plSize.h;
        var labelBottom = labelTop + labelHeight;

        var labelWidth = plSize.w + 2*labelPadding;
        var labelLeft;
        switch (textAlign) {
        case 'center':
          var labelLeft = pointLabelPosition.x - labelWidth/2;
          break;
        case 'left':
          var labelLeft = pointLabelPosition.x - labelPadding;

          break;
        case 'right':
          var labelLeft = pointLabelPosition.x - labelWidth + labelPadding;
          break;
        default:
          console.log('ERROR: unknown textAlign '+textAlign);
        }
        var labelRight = labelLeft + labelWidth;

        // Render a rectangle for testing purposes
        ctx.save();
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 1;
        ctx.strokeRect(labelLeft, labelTop, labelWidth, labelHeight);
        ctx.restore();

        // compare to the current click
        if (mouseX >= labelLeft && mouseX <= labelRight && mouseY <= labelBottom && mouseY >= labelTop) {
            alert(scale.pointLabels[i]+' clicked');
            // Break loop to prevent multiple clicks, if they overlap we take the first one.
            break;
        }
    }
};

JSFiddle在这里:

https://jsfiddle.net/simoncoggins/7r08uLk9/

这种方法的缺点是,如果将来核心标签实现发生变化,它就会中断。如果库将标签位置的计算与其渲染分开并开始通过 API 公开位置信息会更好。然后这个解决方案可以大大简化,并且对库的更改更加健壮。

我在这里开了一张票来进行更改:

https://github.com/chartjs/Chart.js/issues/6549

如果对您有用,请评论该问题。

于 2019-10-09T02:29:21.680 回答
1

无法读取未定义 Chartjs 的属性“getDatasetMeta”

如果您从chartjs 的文档示例中收到此错误,则客户端就是问题所在。将其替换为您当前实例的客户端。

就我而言,我正在使用myHorizontalBar

var defaultLegendClickHandler = function(e, legendItem) {
    var index = legendItem.datasetIndex;
    var ci = window.myHorizontalBar; //this.chart;

    var meta = ci.getDatasetMeta(index);

    // See controller.isDatasetVisible comment
    meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;

    // We hid a dataset ... rerender the chart
    ci.update();
}  

我的水平栏

        window.onload = function() {
        var ctx = document.getElementById('canvas').getContext('2d');
        window.myHorizontalBar = new Chart(ctx, {
            type: 'horizontalBar',
            data: horizontalBarChartData,
            options: {
于 2020-03-12T04:16:47.743 回答