用canvas画曲线轨迹运动的滑块
思路:根据已有的两点,自己设置参数,算出第三点坐标。根据三点确定圆,得出圈心,半径。 绘制两点的圆弧。用一新的canvas绘制圆弧上的滑块,用定时器每隔一段时间移动滑块。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<style>
.slider {
position: absolute;
top: 0px;
left: 0px;
}
</style>
</head>
<body>
<div id="canvasOut" style="position: relative;">
<canvas id="canvas" width="800" height="800"></canvas>
</div>
</body>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ary = [{
x1: 700,
y1: 100,
x2: 80,
y2: 75
}, {
x1: 80,
y1: 300,
x2: 500,
y2: 400
},
{
x1: 80,
y1: 300,
x2: 80,
y2: 500
},
{
x1: 350,
y1: 500,
x2: 400,
y2: 300
},
]
draw(ary);
function draw(ary) {
clearCanvas(ctx, canvas)
var sliderData = []
ary.forEach(item => {
var {
x1,
y1,
x2,
y2
} = item
var TwoDotLength = getTwoDotLength(x1, y1, x2, y2)
// 因为三点确定圆,根据已有两点自己设置一个第三点
x3 = (x1 + x2) / 2 + TwoDotLength / 10
y3 = (y1 + y2) / 2 + TwoDotLength / 10
var {
Xcenter,
Ycenter,
radius
} = getCenter(x1, y1, x2, y2, x3, y3)
var start = getAngle(Xcenter, Ycenter, x1, y1)
var end = getAngle(Xcenter, Ycenter, x2, y2)
var anticlockwise = start > end ? true : false
ctx.beginPath()
ctx.arc(Xcenter, Ycenter, radius, start, end, anticlockwise)
ctx.stroke();
var angleOnce = 30 / radius // 因为 弧长=弧度*半径 设置弧长为30
start > end ? sliderData.push({
Xcenter,
Ycenter,
radius,
start,
end,
anticlockwise,
startangle: start, //滑块起始弧度
endangle: start - angleOnce,//滑块结束弧度
angleOnce,
}) : sliderData.push({
Xcenter,
Ycenter,
radius,
start,
end,
anticlockwise,
startangle: start,
endangle: start + angleOnce,
angleOnce,
})
})
sliderMove(sliderData)
}
// 绘制滑块
function sliderMove(sliderData) {
// 创建一个专门画滑块的canvas
var slider = document.createElement('canvas')
slider.width = 800
slider.height = 800
slider.className = 'slider';
var sliderCtx = slider.getContext('2d');
document.getElementById('canvasOut').appendChild(slider)
clearCanvas(sliderCtx, slider)
sliderCtx.strokeStyle = 'rgb(255,165,0)'
sliderCtx.lineWidth = 5
setInterval(drawSlider, 500);
function drawSlider() {
clearCanvas(sliderCtx, slider)
sliderData.forEach(item => {
var {
Xcenter,
Ycenter,
radius,
start,
end,
anticlockwise,
angleOnce
} = item
if (start > end) {
if (item.endangle <= end) {
sliderCtx.beginPath()
sliderCtx.arc(Xcenter, Ycenter, radius, item.startangle, end, anticlockwise)
sliderCtx.stroke();
item.startangle = start
item.endangle = start - angleOnce
} else {
sliderCtx.beginPath()
sliderCtx.arc(Xcenter, Ycenter, radius, item.startangle, item.endangle, anticlockwise)
sliderCtx.stroke();
item.startangle -= angleOnce
item.endangle -= angleOnce
}
} else {
if (item.endangle >= end) {
sliderCtx.beginPath()
sliderCtx.arc(Xcenter, Ycenter, radius, item.startangle, end, anticlockwise)
sliderCtx.stroke();
item.startangle = start
item.endangle = start + angleOnce
} else {
sliderCtx.beginPath()
sliderCtx.arc(Xcenter, Ycenter, radius, item.startangle, item.endangle, anticlockwise)
sliderCtx.stroke();
item.startangle += angleOnce
item.endangle += angleOnce
}
}
})
}
}
function clearCanvas(ctx, canvas) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// 计算两点与水平线的弧度
function getAngle(x1, y1, x2, y2) {
var x = x2 - x1,
y = y1 - y2;
if (!x && !y) {
return 0;
}
return 2 * Math.PI - Math.atan2(y, x);
}
// 得出圆心和半径
function getCenter(x1, y1, x2, y2, x3, y3) {
var a, b;
a = (y2 - y1) / (x2 - x1);
b = y1 - a * x1;
var xMiddle = (x1 + x2) / 2;
var yMiddle = (y1 + y2) / 2;
var c, Xcenter, Ycenter;
if (a != 0) {
c = yMiddle - (-1 / a) * xMiddle;
Xcenter = (Math.pow(x1, 2) + Math.pow(y1, 2) - Math.pow(x3, 2) - Math.pow(y3, 2) - 2 * c * y1 + 2 * c * y3) / (2 * ((x1 - x3) - (1 / a) * (y1 - y3)));
Ycenter = (-1 / a) * Xcenter + c;
} else {
Xcenter = c = xMiddle;
Ycenter = (Math.pow(x1, 2) + Math.pow(y1, 2) - Math.pow(x3, 2) - Math.pow(y3, 2) + 2 * Xcenter * (x3 - x1)) / (2 * (y1 - y3));
}
var radius = getTwoDotLength(x1, y1, Xcenter, Ycenter)
return {
Xcenter,
Ycenter,
radius
}
}
// 计算两点距离
function getTwoDotLength(x1, y1, x2, y2) {
return Math.pow(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2), 0.5)
}
</script>
</html>