Chart Js 折线图,单击时填充并包含其图例文本的完整信息
Chart Js Line chart with fill on click with full information of its legend text
我正在使用 chart.js 2.9.3. 我在选项中使用了 onClick
处理程序以及 getElementAtEvent
来实现我的目标想要,但我得到了项目 empty 数组,并且事件没有有关被单击区域的信息。单击每个点都可以正常工作,但是单击整条线的区域并不能提供太多信息。
这是我的图表的代码片段。
var chart_canvas = document.getElementById("myChart");
var stackedLine = new Chart(chart_canvas, {
type: 'line',
data: {
labels: ["0.0", "0.2", "0.4", "0.6", "0.8", "1.0"],
fill: true,
datasets: [{
label: 'One',
pointRadius: 3,
data: [.5, .3, .2, .1, .4, .3],
borderWidth: 1
}, {
label: 'Two',
pointRadius: 3,
data: [.0, .1, .2, .4, .1, .4],
borderWidth: 1
}]
},
options: {
responsive: true,
onClick : (event, items) =>{
console.log("event",event);
},
}
});
最后我尝试使用一些 DOM 操作来解决这个问题,通过单击折线图每个填充区域的区域来获取信息。
示例在这里:
https://codepen.io/amiablesyed/pen/RwKxaqE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.js"></script>
</head>
<body>
<div style="background-color: gainsboro">
Data:<span id="Data"></span>
</div>
<div style="width: 500px; height: 400px">
<canvas id="mainChart" width="700" height="400"> </canvas>
</div>
<script>
var ctx = document.getElementById("mainChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "line",
data: {
labels: [
"Red",
"Blue",
"Yellow",
"Green",
"Purple",
"Orange",
"Pink",
"Black",
"Grey",
],
datasets: [
{
lineTension: 0,
label: "Data A",
data: [11, 12, 1, 3, 1, 1, 3, 5, 2],
backgroundColor: "#ffe8e8",
borderColor: ["#ffe8e8"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data B",
data: [12, 17, 3, 5, 2, 3, 6, 8, 4],
backgroundColor: "#e2ffcb",
borderColor: ["#e2ffcb"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data C",
data: [15, 23, 6, 9, 3, 8, 7, 10, 11],
backgroundColor: "#ffe689",
borderColor: ["#ffe689"],
borderWidth: 1,
},
],
},
});
document
.getElementById("mainChart")
.addEventListener("click", function (e) {
areaClick(e);
});
function areaClick(e) {
if (!myChart.scales["y-axis-0"]._gridLineItems) return;
var gridLineH = myChart.scales["y-axis-0"]._gridLineItems[0];
var lenH = myChart.scales["y-axis-0"]._gridLineItems.length;
var width = gridLineH.x2 - gridLineH.x1;
var yMax = myChart.scales["y-axis-0"].max;
var yMaxPixcel = myChart.scales["y-axis-0"].bottom - gridLineH.y1;
var gridLineV = myChart.scales["x-axis-0"]._gridLineItems[0];
var lenV = myChart.scales["x-axis-0"]._gridLineItems.length;
var height = gridLineV.y2 - gridLineV.y1;
var xMax = myChart.scales["x-axis-0"].maxIndex;
var scaleX = width / (lenV - 1);
var scaleY = height / (lenH - 1);
var yPixcel =
yMaxPixcel - (e.pageY - e.target.offsetTop - gridLineH.y1);
var yVal = yMax * (yPixcel / yMaxPixcel);
console.log(yVal);
var curXPixcel = e.pageX - e.target.offsetLeft - gridLineH.x1;
var xVal = Math.floor(curXPixcel / scaleX);
var xAxis = myChart.scales["x-axis-0"];
var label = "Others";
if (xVal < xAxis.maxIndex && xVal >= xAxis.minIndex) {
var x1x2Pixcels = getx1x2Pixcels(xVal, gridLineH.x1);
document.getElementById("Data").innerText = getDataLable(
xVal,
yVal,
x1x2Pixcels,
curXPixcel
);
}
}
function getx1x2Pixcels(xVal, offset) {
var x1x2 = {};
x1x2.x1 =
myChart.scales["x-axis-0"]._gridLineItems[xVal].x1 - offset + 0.5;
x1x2.x2 =
myChart.scales["x-axis-0"]._gridLineItems[xVal + 1].x1 - offset + 0.5;
return x1x2;
}
function getDataLable(xVal, yVal, x1x2Pixcels, curXPixcel) {
var datasetes = myChart.config.data.datasets;
var dataLable = "";
if (datasetes.length > 1) {
for (var i = datasetes.length; i > 0; i--) {
if (myChart.getDatasetMeta(i - 1).hidden) continue;
var dataA = datasetes[i - 1];
var dataALable = dataA.label;
var y1 = dataA.data[xVal];
var y2 = dataA.data[xVal + 1];
var isBelow = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
y1,
x1x2Pixcels.x2,
y2
);
if (isBelow) {
dataLable = isBelow ? dataALable : dataLable;
if (i == 1) {
var isBelowZeroLine = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
0,
x1x2Pixcels.x2,
0
);
dataLable = isBelowZeroLine ? "" : dataLable;
}
} else break;
}
}
return dataLable;
}
function IsBelowTheLine(x, y, x1, y1, x2, y2) {
var v1 = [x2 - x1, y2 - y1];
var v2 = [x2 - x, y2 - y];
var xp = v1[0] * v2[1] - v1[1] * v2[0];
return xp >= 0;
}
</script>
</body>
</html>
我正在使用 chart.js 2.9.3. 我在选项中使用了 onClick
处理程序以及 getElementAtEvent
来实现我的目标想要,但我得到了项目 empty 数组,并且事件没有有关被单击区域的信息。单击每个点都可以正常工作,但是单击整条线的区域并不能提供太多信息。
这是我的图表的代码片段。
var chart_canvas = document.getElementById("myChart");
var stackedLine = new Chart(chart_canvas, {
type: 'line',
data: {
labels: ["0.0", "0.2", "0.4", "0.6", "0.8", "1.0"],
fill: true,
datasets: [{
label: 'One',
pointRadius: 3,
data: [.5, .3, .2, .1, .4, .3],
borderWidth: 1
}, {
label: 'Two',
pointRadius: 3,
data: [.0, .1, .2, .4, .1, .4],
borderWidth: 1
}]
},
options: {
responsive: true,
onClick : (event, items) =>{
console.log("event",event);
},
}
});
最后我尝试使用一些 DOM 操作来解决这个问题,通过单击折线图每个填充区域的区域来获取信息。 示例在这里:
https://codepen.io/amiablesyed/pen/RwKxaqE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.js"></script>
</head>
<body>
<div style="background-color: gainsboro">
Data:<span id="Data"></span>
</div>
<div style="width: 500px; height: 400px">
<canvas id="mainChart" width="700" height="400"> </canvas>
</div>
<script>
var ctx = document.getElementById("mainChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "line",
data: {
labels: [
"Red",
"Blue",
"Yellow",
"Green",
"Purple",
"Orange",
"Pink",
"Black",
"Grey",
],
datasets: [
{
lineTension: 0,
label: "Data A",
data: [11, 12, 1, 3, 1, 1, 3, 5, 2],
backgroundColor: "#ffe8e8",
borderColor: ["#ffe8e8"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data B",
data: [12, 17, 3, 5, 2, 3, 6, 8, 4],
backgroundColor: "#e2ffcb",
borderColor: ["#e2ffcb"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data C",
data: [15, 23, 6, 9, 3, 8, 7, 10, 11],
backgroundColor: "#ffe689",
borderColor: ["#ffe689"],
borderWidth: 1,
},
],
},
});
document
.getElementById("mainChart")
.addEventListener("click", function (e) {
areaClick(e);
});
function areaClick(e) {
if (!myChart.scales["y-axis-0"]._gridLineItems) return;
var gridLineH = myChart.scales["y-axis-0"]._gridLineItems[0];
var lenH = myChart.scales["y-axis-0"]._gridLineItems.length;
var width = gridLineH.x2 - gridLineH.x1;
var yMax = myChart.scales["y-axis-0"].max;
var yMaxPixcel = myChart.scales["y-axis-0"].bottom - gridLineH.y1;
var gridLineV = myChart.scales["x-axis-0"]._gridLineItems[0];
var lenV = myChart.scales["x-axis-0"]._gridLineItems.length;
var height = gridLineV.y2 - gridLineV.y1;
var xMax = myChart.scales["x-axis-0"].maxIndex;
var scaleX = width / (lenV - 1);
var scaleY = height / (lenH - 1);
var yPixcel =
yMaxPixcel - (e.pageY - e.target.offsetTop - gridLineH.y1);
var yVal = yMax * (yPixcel / yMaxPixcel);
console.log(yVal);
var curXPixcel = e.pageX - e.target.offsetLeft - gridLineH.x1;
var xVal = Math.floor(curXPixcel / scaleX);
var xAxis = myChart.scales["x-axis-0"];
var label = "Others";
if (xVal < xAxis.maxIndex && xVal >= xAxis.minIndex) {
var x1x2Pixcels = getx1x2Pixcels(xVal, gridLineH.x1);
document.getElementById("Data").innerText = getDataLable(
xVal,
yVal,
x1x2Pixcels,
curXPixcel
);
}
}
function getx1x2Pixcels(xVal, offset) {
var x1x2 = {};
x1x2.x1 =
myChart.scales["x-axis-0"]._gridLineItems[xVal].x1 - offset + 0.5;
x1x2.x2 =
myChart.scales["x-axis-0"]._gridLineItems[xVal + 1].x1 - offset + 0.5;
return x1x2;
}
function getDataLable(xVal, yVal, x1x2Pixcels, curXPixcel) {
var datasetes = myChart.config.data.datasets;
var dataLable = "";
if (datasetes.length > 1) {
for (var i = datasetes.length; i > 0; i--) {
if (myChart.getDatasetMeta(i - 1).hidden) continue;
var dataA = datasetes[i - 1];
var dataALable = dataA.label;
var y1 = dataA.data[xVal];
var y2 = dataA.data[xVal + 1];
var isBelow = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
y1,
x1x2Pixcels.x2,
y2
);
if (isBelow) {
dataLable = isBelow ? dataALable : dataLable;
if (i == 1) {
var isBelowZeroLine = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
0,
x1x2Pixcels.x2,
0
);
dataLable = isBelowZeroLine ? "" : dataLable;
}
} else break;
}
}
return dataLable;
}
function IsBelowTheLine(x, y, x1, y1, x2, y2) {
var v1 = [x2 - x1, y2 - y1];
var v2 = [x2 - x, y2 - y];
var xp = v1[0] * v2[1] - v1[1] * v2[0];
return xp >= 0;
}
</script>
</body>
</html>