[英]How to add OnClick Event on labels in Chart.js v2.0?
尋找一種在chartjs 2.0 中的“標簽”元素上添加onClick 句柄的方法,因為每當單擊Char.js V2.0 RadarChart 中的任何一個標簽屬性時,使用下面的方法都會在console.log 中返回“未定義”。
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); } });
在chart.js 2.5(甚至更早)中,您可以在選項中放置一個onClick:
'legend' : {
'onClick' : function (evt, item) {
console.log ('legend onClick', evt, item);
},
'display' : true,
'labels' : ...
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);
}
});
我通過將標簽位置計算從 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
如果對您有用,請對該問題發表評論。
無法讀取未定義 Chartjs 的屬性“getDatasetMeta”
如果您從chartjs 的 doc example收到此錯誤,則客戶端是問題所在。 將其替換為您當前實例的客戶端。
在我的情況下,我使用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: {
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.