简体   繁体   English

使Chart.js雷达标签可点击

[英]Make Chart.js Radar labels clickable

Has anyone managed to make the labels around the Chart.js Radar perimeter clickable? 是否有人设法使Chart.js雷达周界周围的标签可点击?

There doesn't seem to be an immediately obvious solution. 似乎没有立即显而易见的解决方案。

在此处输入图片说明

Thanks Pogrindis. 感谢Pogrindis。 Answer here works for Chart.js v2.1: Chart.js click on labels, using bar chart 这里的答案适用于Chart.js v2.1: Chart.js使用条形图单击标签

To make that work for Chart.js v5.0+, add the following function back into the Chart.js code. 为了使它适用于Chart.js v5.0 +,请将以下函数重新添加到Chart.js代码中。

LinearRadialScale = Chart.LinearScaleBase.extend({...}) LinearRadialScale = Chart.LinearScaleBase.extend({...})

getValueCount: function() {
        return this.chart.data.labels.length;
    }

I came up with a solution for this for version 2.8.0 by copying the label position calculations from the RadialLinear scale into an event handler. 通过将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 here: JSFiddle在这里:

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

The downside of this approach is it that it will break if the core labelling implementation changes in the future. 这种方法的缺点是,如果将来核心标签实现发生更改,它将无法使用。 It would be better if the library separated the calculation of label position from its rendering and started exposing the position info via the API. 如果库将标签位置的计算与其呈现分离,并开始通过API公开位置信息,将会更好。 Then this solution could be greatly simplified and would be more robust to library changes. 然后,可以大大简化此解决方案,并且对库更改更健壮。

I've opened a ticket offering to make that change here: 我已经打开了一张机票,可以在这里进行更改:

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

Please comment on that issue if it would be useful to you. 如果对您有用,请对此问题发表评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM