我想用画布制作速度计动画。但是我需要速度计指针是三角形的,当值改变时,它指向所需的值,但它的底部始终保持在中心。告诉我你需要申请什么公式或算法。代码如下所示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
// general settings
middleX = canvas.width / 2,
middleY = canvas.height / 2,
radius = 240,
counterClockwise = false,
// ticks settings
tickWidth = canvas.width / 100,
// tickColor = "#746845";
tickOffsetFromArc = canvas.width / 40,
// Center circle settings
centerCircleRadius = canvas.width / 20,
centerCircleColor = "#ccc",
centerCircleBorderWidth = canvas.width / 100,
// Arrow settings
arrowValueIndex = .73,
arrowColor = "#464646",
arrowWidth = canvas.width / 50,
// numbers
digits = [0, 20, 40, 50, 60, 70, 80, 90, 100],
digitsColor = "#0a0a0a",
digitsFont = "bold 20px Tahoma",
digitsOffsetFromArc = canvas.width / 15,
//zones
zonesCount = digits.length - 1;
// beginning and ending of our arc. Sets by radius*pi
let startAngleIndex = .75,
endAngleIndex = 2.25,
step = (endAngleIndex - startAngleIndex) / zonesCount;
/*draw zones*/
let DrawZones = function () {
const greyZonesCount = zonesCount / 1.6;
greenZonesCount = zonesCount - greyZonesCount,
startAngle = (startAngleIndex - 0.02) * Math.PI,
endGreyAngle = (startAngleIndex + greyZonesCount * step) * Math.PI,
endGreenAngle = (endAngleIndex + 0.02) * Math.PI,
//zones' options
sectionOptions = [
{
startAngle: startAngle,
endAngle: endGreyAngle,
color: "#e7e7e7",
zoneLineWidth: 2
},
{
startAngle: endGreyAngle,
endAngle: endGreenAngle,
color: "#13b74b",
zoneLineWidth: 5
},
];
this.DrawZone = function (options) {
ctx.beginPath();
ctx.arc(middleX, middleY, radius, options.startAngle, options.endAngle, counterClockwise);
ctx.lineWidth = options.zoneLineWidth;
ctx.strokeStyle = options.color;
ctx.lineCap = "round";
ctx.stroke();
};
sectionOptions.forEach(options => this.DrawZone(options));
};
/*draw dots*/
let DrawTicks = function () {
startAngleIndex = .73,
endAngleIndex = 2.27,
step = (endAngleIndex - startAngleIndex) / zonesCount;
this.DrawTick = function (angle,count) {
let fromX = middleX + (radius - tickOffsetFromArc) * Math.cos(angle),
fromY = middleY + (radius - tickOffsetFromArc) * Math.sin(angle),
toX = middleX + (radius + tickOffsetFromArc) * Math.cos(angle),
toY = middleY + (radius + tickOffsetFromArc) * Math.sin(angle),
centerOfDotX=(fromX+toX)/2,
centerOfDotY=(fromY+toY)/2;
ctx.beginPath();
ctx.arc(centerOfDotX,centerOfDotY,6,0,Math.PI*2,true);
if (count<6){
switch (count) {
case 1:
case 2:
case 3:
ctx.fillStyle="#FF0000";
break;
default:
ctx.fillStyle="#F9AF00";
break;
}
}else{
ctx.fillStyle="#FFF";
ctx.strokeStyle="#13B74B";
ctx.shadowColor = "#a8bbaa";
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.stroke();
}
ctx.fill();
ctx.closePath();
ctx.shadowBlur =0;
};
let count=0;
for (let i = startAngleIndex; i <= endAngleIndex; i += step) {
let angle = i * Math.PI;
count++;
this.DrawTick(angle,count);
}
};
//draw numbers
let DrawDigits = function () {
let angleIndex = startAngleIndex;
digits.forEach(function (digit) {
let angle = angleIndex * Math.PI,
x = middleX + (radius - digitsOffsetFromArc) * Math.cos(angle),
y = middleY + (radius - digitsOffsetFromArc) * Math.sin(angle);
angleIndex += step;
ctx.font = digitsFont;
ctx.fillStyle = digitsColor;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(digit, x, y);
});
};
/*draw arrow РИСОВАНИЕ СТРЕЛКИ*/
let DrawArrow = function () {
let arrowAngle = arrowValueIndex * Math.PI;
let toX = middleX + (radius) * Math.cos(arrowAngle)+50;
let toY = middleY + (radius) * Math.sin(arrowAngle)-50;
ctx.beginPath();
ctx.moveTo(middleX, middleY);
ctx.lineTo(toX, toY);
ctx.strokeStyle = arrowColor;
ctx.lineWidth = arrowWidth;
ctx.stroke();
ctx.closePath();
};
window.onload=()=>{
DrawZones();
DrawTicks();
DrawDigits();
DrawArrow();
};
</script>
</body>
</html>
这里是另一种选择,老的不破坏,让有第二个答案:
可惜尺度分布不均匀,如果均匀的话可以这样
没有使用画布,但查看实现数据,它可能会有所帮助: http ://www.knowstack.com/html5-canvas-speedometer/
https://github.com/vjt/canvas-speedometer