cubic-bezier生成器
本帖最后由 马黑黑 于 2024-6-25 17:41 编辑 <br /><br /><style>#mydiv { margin: 20px auto; width: 100%; font-size: 16px; position: relative; }
#msgbox { margin: 20px; font: normal 24px/30px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; }
.stage { margin: 20px; height: 40px; position: relative; }
#ball, .ball { position: absolute; left: 0; top: 0; width: 40px; height: 40px; border-radius: 50%;}
#ball { cursor: pointer; background: linear-gradient(teal, lightblue); box-shadow: 0 0 3px rgba(0,0,0,.3); }
.ball { border: 1px solid rgba(0,0,0,.1); font-size: 1.2em; text-align: center; line-height: 40px; }
.ball:nth-of-type(2) { left: 700px; }
@keyframes move { to { transform: translateX(700px); } }
</style>
<div id="mydiv">
<p>cubic-bezier() 是CSS三次贝塞尔缓动函数,用以描述CSS关键帧动画从开始到结束变速的过渡效果。语法 cubic-bezier(x1, y1, x2, y2),参数分别为曲线两个控制点的坐标值,x值必须在 0~1 范围内取值(包括0和1),y值允许突破(突破时动画会出现“反弹”效果)。</p>
<p>点击以下大圆球,圆球会依据当下的 cubic-bezier 设置移动。要改变 cubic-bezier 参数,请依次拖曳坐标系的两个小彩球到合适的位置。</p>
<div class="stage">
<div class="ball">起</div>
<div class="ball">终</div>
<div id="ball"></div>
</div>
<canvas id="canv" width="300" height="300"></canvas>
<div id="msgbox"></div>
</div>
<div id="msgwrap">
</div>
<script>
class Circle {
constructor(ctx, x, y, r) {
this.ctx = ctx;
this.x = x;
this.y = y;
this.r = r;
};
draw() {
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.r, 0, 2* Math.PI);
this.ctx.fill();
};
};
const ww = canv.width, hh = canv.height;
const ctx = canv.getContext('2d');
const staticPos = { beginX: 100, beginY: 200, endX: 200, endY: 100};
var candraw = false;
var c1 = {x: 100, y: 200, r: 6}, c2 = {x: 200, y: 100, r: 6};
var cb = '0, 0, 1, 1';
var circle1 = new Circle(ctx, c1.x, c1.y, c1.r, c1.color), circle2 = new Circle(ctx, c2.x, c2.y, c2.r, c2.color);
const innerCircle = (ex,ey,cx,cy,r) => Math.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r;
const draw = () => {
ctx.clearRect(0, 0, ww, hh);
//坐标系
ctx.strokeStyle = 'gray';
ctx.beginPath();
ctx.moveTo(staticPos.beginX, staticPos.endY);
ctx.lineTo(staticPos.beginX, staticPos.beginY);
ctx.lineTo(staticPos.endX, staticPos.beginY);
ctx.stroke();
//辅助线1
ctx.strokeStyle = 'pink';
ctx.beginPath();
ctx.moveTo(circle1.x, circle1.y);
ctx.lineTo(staticPos.beginX, staticPos.beginY);
ctx.stroke();
//辅助线2
ctx.strokeStyle = 'plum';
ctx.beginPath();
ctx.moveTo(circle2.x, circle2.y);
ctx.lineTo(staticPos.endX, staticPos.endY);
ctx.stroke();
//曲线
ctx.strokeStyle = 'green';
ctx.beginPath();
ctx.moveTo(staticPos.beginX, staticPos.beginY);
ctx.bezierCurveTo(circle1.x, circle1.y, circle2.x, circle2.y, staticPos.endX, staticPos.endY);
ctx.stroke();
//控制点1
ctx.fillStyle = 'pink';
circle1.draw();
//控制点2
ctx.fillStyle = 'plum';
circle2.draw();
};
canv.onmousedown = (e) => {
if(innerCircle(e.offsetX, e.offsetY, circle1.x, circle1.y, circle1.r) || innerCircle(e.offsetX, e.offsetY, circle2.x, circle2.y, circle2.r)) candraw = true;
};
canv.onmouseup = document.onmouseup = () => candraw = false;
canv.onmousemove = (e) => {
canv.style.cursor = innerCircle(e.offsetX, e.offsetY, circle1.x, circle1.y, circle1.r) || innerCircle(e.offsetX, e.offsetY, circle2.x, circle2.y, circle2.r) ? 'pointer' : 'default';
if(!candraw) return;
if(innerCircle(e.offsetX, e.offsetY, circle1.x, circle1.y, circle1.r)) {
circle1.x = e.offsetX;
circle1.y = e.offsetY;
}
if(innerCircle(e.offsetX, e.offsetY, circle2.x, circle2.y, circle2.r)) {
circle2.x = e.offsetX;
circle2.y = e.offsetY;
}
//防止x坐标值非法
if(circle1.x - staticPos.beginX > 100) circle1.x = staticPos.beginX + 100;
if(circle1.x - staticPos.beginX < 0) circle1.x = 100;
if(circle2.x - staticPos.beginX > 100) circle2.x = staticPos.beginX + 100;
if(circle2.x - staticPos.beginX < -100) circle2.x = staticPos.beginX + 100;
//避免重叠与消失
if(Math.abs(circle1.x - circle2.x) < circle1.r && Math.abs(circle1.y - circle2.y) < circle1.r) {
circle2.x += circle2.r * 2;
circle2.y += circle2.r * 2;
if(circle2.x > ww - circle2.r) circle2.x -= circle2.r * 2;
if(circle2.y > hh - circle2.r) circle2.y -= circle2.r * 2;
}
//换算为cubic-bezier参数
var x1 = (circle1.x - staticPos.beginX) / 100,
y1 = (staticPos.beginY - circle1.y) / 100,
x2 = (circle2.x - staticPos.beginX) / 100,
y2 = (staticPos.beginY - circle2.y) / 100;
cb = `${x1}, ${y1}, ${x2}, ${y2}`;
msgbox.innerHTML =`cubic-bezier(${cb})`;
draw();
};
ball.onclick = () => {
ball.style.animation = `move 3s cubic-bezier(${cb}) forwards`;
setTimeout(() => {
ball.style.animation = '';
}, 6000);
}
msgbox.innerHTML = `cubic-bezier(${cb})`;
draw();
</script>
语法 cubic-bezier(x1, y1, x2, y2),参数分别为曲线两个控制点的坐标值,x值必须在 0~1 范围内取值(包括0和1),y值允许突破(突破时动画会出现“反弹”效果)。
还会反弹?这事儿比较好玩了。 小球怎么扯也没超过1,看来需要手工大于1,很期待这个效果。。必定好玩。。 这个演示看着效果出数据,再抄下来,做贴子的人第一感觉是好用。。
嗯,看了下颜值也挺高,帅。。{:4_173:} 南无月 发表于 2024-6-25 18:11
这个演示看着效果出数据,再抄下来,做贴子的人第一感觉是好用。。
嗯,看了下颜值也挺高,帅。。{:4_173: ...
还是可以再丰富一下,不过算了,还是去喝花酒吧{:4_170:} 这个好,可以直接看到调整两个小球后的效果了{:4_199:} 想得到什么效果,可以到这个帖子里来找了。
这个完全没法根据数字去猜想效果,只能在这里看了{:4_187:} 红影 发表于 2024-6-25 21:36
这个好,可以直接看到调整两个小球后的效果了
{:4_190:} 红影 发表于 2024-6-25 21:38
想得到什么效果,可以到这个帖子里来找了。
这个完全没法根据数字去猜想效果,只能在这里看了
这类工具网上有很多,我这是挑战一下,看做不做得出来 马黑黑 发表于 2024-6-25 22:11
在里面调了好半天,这个太直观了,真的太好了{:4_199:}{:4_199:}{:4_199:} 马黑黑 发表于 2024-6-25 22:11
这类工具网上有很多,我这是挑战一下,看做不做得出来
黑黑不但做出来了,而且特别好{:4_187:} 红影 发表于 2024-6-26 12:08
在里面调了好半天,这个太直观了,真的太好了
工具到处有的,我说过,它们更全面。例如这个:
https://cubic-bezier.com/ 红影 发表于 2024-6-26 12:08
黑黑不但做出来了,而且特别好
过得去吧,非专业的 马黑黑 发表于 2024-6-26 12:09
工具到处有的,我说过,它们更全面。例如这个:
https://cubic-bezier.com/
哦,这个还有个作为比较的方块。 马黑黑 发表于 2024-6-26 12:10
过得去吧,非专业的
好用的就好啊,而且原创的,更厉害呢{:4_199:} 马黑黑 发表于 2024-6-25 18:12
还是可以再丰富一下,不过算了,还是去喝花酒吧
好哒~~去喝吧,
这个已经很好用了。。多喝几次,多出几个小工具{:4_170:} 南无月 发表于 2024-6-26 17:56
好哒~~去喝吧,
这个已经很好用了。。多喝几次,多出几个小工具
{:4_173:} 马黑黑 发表于 2024-6-26 18:23
{:4_170:}老师去瞧一眼,我跟了一个贴子 南无月 发表于 2024-6-26 18:48
老师去瞧一眼,我跟了一个贴子
好滴 红影 发表于 2024-6-26 16:56
哦,这个还有个作为比较的方块。
是的