今天我获得了一个设计,即沿着曲线移动的圆圈。我创建了一个JSBin,其中包含了迄今为止我用纯css取得的进展,但我觉得我的方向错误。我想也许用帆布会更好,但我不知道从哪里开始。这不只是沿着一条线绘制它也填充了条形。
这是设计:
到目前为止,我与CSS有多接近:
答案 0 :(得分:9)
以下是沿着曲线(这是一个Cubic Bezier曲线)为您的圆设置动画的方法。
使用画布的context.bezierCurveTo
方法绘制曲线。
使用一系列画布的context.lineTo
方法关闭彩虹路径。
要仅使用彩虹色填充弯曲路径,可以使用context.clip
限制图纸仅显示在路径内。然后,您可以使用context.fillRect
填充多色乐队。
使用requestAnimationFrame
创建一个动画循环,在您的曲线沿着不断增加的航路点绘制球。
使用De Casteljau's Algorithm
以下是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var colors=[[229,133,50],[251,183,50],[133,206,63],[22,155,116],[26,160,219]];
var points=[35,120,317,511,709,792];
var p0={x:37,y:144};
var p1={x:267,y:143};
var p2={x:651,y:129};
var p3={x:794,y:96};
var waypoints=cubicBezierPoints(p0,p1,p2,p3);
var currentIndex=0;
var radius=10;
//
requestAnimationFrame(animate);
// draw the rainbow curve thing
function drawCurve(){
ctx.save();
ctx.moveTo(37,144);
ctx.bezierCurveTo(267,143,651,129,794,96);
ctx.lineTo(794,158);
ctx.lineTo(37,158);
ctx.closePath();
ctx.fill();
ctx.globalCompositeOperation='source-atop';
for(var i=0;i<points.length-1;i++){
var c=colors[i];
ctx.fillStyle='rgb('+c[0]+','+c[1]+','+c[2]+')';
ctx.fillRect(points[i],0,points[i+1],ch);
}
ctx.restore();
}
//
function drawBall(){
var pt=waypoints[currentIndex];
ctx.beginPath();
ctx.arc(pt.x,pt.y,radius,0,Math.PI*2);
ctx.fillStyle='white';
ctx.fill();
ctx.strokeStyle='black'
ctx.lineWidth=3;
ctx.stroke();
}
// the animation loop
function animate(){
ctx.clearRect(0,0,cw,ch);
drawCurve();
drawBall();
ctx.beginPath();
currentIndex++;
if(currentIndex<waypoints.length){
requestAnimationFrame(animate);
}
}
// calculate the waypoints
function cubicBezierPoints(p0,p1,p2,p3){
var ticksPerSecond=60;
var seconds=4;
var totalTicks=ticksPerSecond*seconds;
var pts=[];
for(var t=0;t<totalTicks;t++){
pts.push(getCubicBezierXYatT(p0,p1,p2,p3,t/totalTicks));
}
return(pts);
}
// De Casteljau's algorithm which calculates points along a cubic Bezier curve
// plot a point at interval T along a bezier curve
// T==0.00 at beginning of curve. T==1.00 at ending of curve
// Calculating 100 T's between 0-1 will usually define the curve sufficiently
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=820 height=200></canvas>
答案 1 :(得分:3)
MarkE给出了很好的答案(他应得的赏金)但是当我看到De Casteljau的算法并仔细观察时,它让我感到震惊的是数学家编写软件,而不是程序员做数学。
在计算中使用传递的参数作为中间体,可以删除一些操作,从而改进算法。它是相同的数学函数,不超过+/- 1e-14(在Javascript浮点数上尽可能接近)
因缺少一个更好的名称cubicQ
function cubicQ(t, a, b, c, d) {
a += (b - a) * t;
b += (c - b) * t;
c += (d - c) * t;
a += (b - a) * t;
b += (c - b) * t;
return a + (b - a) * t;
}
并且需要ctx.quadraticCurveTo
所需的二阶多项式function quadQ(t, a, b, c){
a += (b - a) * t;
b += (c - b) * t;
return a + (b - a) * t;
}
其中a,b,c是曲线上的x或y点,b为控制点。 t是位置0 <= t <= 1
只是为了兴趣线性版
function linearQ(t, a, b){
return a + (b - a) * t;
}
你可以看到它只是一条线。二次曲线由线性插值3(线)组成,立方数为6。
对于这个问题,15%的性能提升是微不足道的,而且无关紧要,但是对于更加强烈的需求,15%非常值得花费额外的代码,更不用说它看起来更好了.LOL