我试图使这些点具有不同的颜色:默认情况下它应该是背景:线性渐变(243.46deg,#FFC700 -1%,#F52525 131.66%); 如果下一个值小于前一个值,则应显示为背景: Linear-gradient(55.98deg, #E83C3C 11.73%, #9D3C3C 72.51%);
我在画布上找到了一些关于线性渐变的教程,但我的所有观点仍然是黑色的
var trendPriceArray = [
0,
109119,
103610,
112561,
0,
0,
0,
101852,
0,
99736,
134382,
110018
];
var trendPercentArray = [-5,
8.6, -9.5, -2.1,
34.7, -18.1
];
var monthLabels = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
// Filter out data points with trendPriceArray values of 0
var filteredData = [];
for (var i = 0; i < trendPriceArray.length; i++) {
if (trendPriceArray[i] !== 0) {
filteredData.push({
x: monthLabels[i], // X coordinate as month label
y: trendPriceArray[i], // Y coordinate
label: trendPercentArray[i] + '%', // Display label above the point
});
}
}
// Initialize Chart.js
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: monthLabels, // Use the month labels
datasets: [{
label: 'Price Trend',
data: filteredData, // Use filtered data
fill: false,
borderColor: '#4e4e4e', // Set the line graph color to #4e4e4e
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderWidth: 1,
pointBackgroundColor: [], // Empty array to be filled with point background colors
pointRadius: 13, // Set the point radius to 13 pixels
pointHoverRadius: 13, // Set the point hover radius to 13 pixels
}]
},
options: {
scales: {
x: {
type: 'category', // Use category scale with the month labels
title: {
display: true,
text: 'Month',
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the axis label text color to #4e4e4e
},
ticks: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the tick text color to #4e4e4e
},
},
y: {
display: true,
title: {
display: true,
text: 'Price',
marginBottom: '10px',
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the axis label text color to #4e4e4e
},
ticks: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the tick text color to #4e4e4e
},
}
},
plugins: {
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
},
legend: {
labels: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the legend text color to #4e4e4e
},
},
}
}
});
function createDefaultGradient(ctx) {
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(75, 192, 192, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
return gradient;
}
function createRedGradient(ctx) {
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
return gradient;
}
function createGradientPointStyle(gradient) {
return function(context) {
const chart = context.chart;
const {
ctx,
borderWidth
} = chart;
const {
x,
y
} = context.p0;
const pointRadius = 6; // You can adjust this value as needed
ctx.save();
ctx.beginPath();
ctx.arc(x, y, pointRadius, 0, Math.PI * 2);
ctx.fillStyle = gradient;
ctx.closePath();
ctx.fill();
ctx.restore();
};
}
// Initialize an empty pointStyle array
myChart.data.datasets[0].pointStyle = [];
for (var i = 0; i < filteredData.length; i++) {
var gradient = createDefaultGradient(ctx); // Default gradient
if (i < filteredData.length - 1 && filteredData[i + 1].y < filteredData[i].y) {
gradient = createRedGradient(ctx); // Red gradient for smaller values
}
myChart.data.datasets[0].pointStyle.push(createGradientPointStyle(gradient));
}
myChart.update(); // Update the chart
<!DOCTYPE html>
<html>
<head>
<!-- Include Chart.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
<!-- Include Montserrat font from Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
</head>
<body>
<!-- Create a container for the chart -->
<div>
<canvas id="myChart" width="400" height="200"></canvas>
</div>
</body>
</html>
理论上有两种不同的途径 解决你的问题,但你以错误的方式混合了它们:
afterDraw
功能;否则,你画的任何东西都是
被图表的默认绘图覆盖pointStyle
,您可以将其分配给
新创建的(小)画布或图像,您可以在其中
绘制(可重复使用的)点符号。从第二个开始,标准方法就足够了 您的要求,我们可以忘记第一个,这应该只 在其他情况不涵盖的特殊情况下受聘。
此外,您应该考虑时刻/顺序 当代码的每个部分被执行时。在 特别是,如果您使用的是 可编写脚本
pointStyle
,不需要第二阶段
和 chart.update
电话。最重要的是
可编写脚本的选项是为了让您能够使用
刚刚计算的动态值(就像你过滤的
y
值)以避免重绘整个图表。
事实上,过滤发生在点之前
被绘制,因此通过提供给 pointStyle
的参数 函数,您将找到所需的
y
值。这是代码的更正版本,改动最小:
function createDefaultGradient(ctx, max) {
const gradient = ctx.createLinearGradient(0, 0, 0, max);
gradient.addColorStop(0, 'rgba(75, 192, 192, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
return gradient;
}
function createRedGradient(ctx, max) {
const gradient = ctx.createLinearGradient(0, 0, 0, max);
gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
return gradient;
}
function createGradientPointStyle(gradientCreator, pointRadius) {
const canvas = document.createElement('canvas');
canvas.width = 2*pointRadius+2;
canvas.height = 2*pointRadius+2;
const ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(pointRadius+1, pointRadius+1, pointRadius, 0, Math.PI * 2);
ctx.fillStyle = gradientCreator(ctx, 2*pointRadius+2);
ctx.closePath();
ctx.fill();
return canvas;
}
function pointStyle(context, opt){
var i = context.dataIndex,
data = context.dataset.data;
var gradientCreator = createDefaultGradient;
if (i < data.length - 1 && data[i + 1].y < data[i].y) {
gradientCreator = createRedGradient; // Red gradient for smaller values
}
var radius = context.active ? opt.hoverRadius : opt.radius;
return createGradientPointStyle(gradientCreator, radius)
}
var trendPriceArray = [
0,
109119,
103610,
112561,
0,
0,
0,
101852,
0,
99736,
134382,
110018
];
var trendPercentArray = [-5,
8.6, -9.5, -2.1,
34.7, -18.1
];
var monthLabels = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
// Filter out data points with trendPriceArray values of 0
var filteredData = [];
for (var i = 0; i < trendPriceArray.length; i++) {
if (trendPriceArray[i] !== 0) {
filteredData.push({
x: monthLabels[i], // X coordinate as month label
y: trendPriceArray[i], // Y coordinate
label: trendPercentArray[i] + '%', // Display label above the point
});
}
}
// Initialize Chart.js
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: monthLabels, // Use the month labels
datasets: [{
label: 'Price Trend',
data: filteredData, // Use filtered data
// fill: false,
borderColor: '#4e4e4e', // Set the line graph color to #4e4e4e
//backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderWidth: 1,
// pointBackgroundColor: [], // Empty array to be filled with point background colors
pointRadius: 13, // Set the point radius to 13 pixels
pointHoverRadius: 23, // Set the point hover radius to 13 pixels
pointStyle
}]
},
options: {
scales: {
x: {
type: 'category', // Use category scale with the month labels
title: {
display: true,
text: 'Month',
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the axis label text color to #4e4e4e
},
ticks: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the tick text color to #4e4e4e
},
},
y: {
display: true,
title: {
display: true,
text: 'Price',
marginBottom: '10px',
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the axis label text color to #4e4e4e
},
ticks: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the tick text color to #4e4e4e
},
}
},
plugins: {
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
},
legend: {
labels: {
font: {
family: 'Montserrat', // Set the font family to Montserrat
},
color: '#4e4e4e', // Set the legend text color to #4e4e4e
},
},
}
}
});
<div style="min-height: 60vh">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>