马黑黑 发表于 2024-6-25 17:36

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>

南无月 发表于 2024-6-25 18:09

语法 cubic-bezier(x1, y1, x2, y2),参数分别为曲线两个控制点的坐标值,x值必须在 0~1 范围内取值(包括0和1),y值允许突破(突破时动画会出现“反弹”效果)。

还会反弹?这事儿比较好玩了。

南无月 发表于 2024-6-25 18:10

小球怎么扯也没超过1,看来需要手工大于1,很期待这个效果。。必定好玩。。

南无月 发表于 2024-6-25 18:11

这个演示看着效果出数据,再抄下来,做贴子的人第一感觉是好用。。
嗯,看了下颜值也挺高,帅。。{:4_173:}

马黑黑 发表于 2024-6-25 18:12

南无月 发表于 2024-6-25 18:11
这个演示看着效果出数据,再抄下来,做贴子的人第一感觉是好用。。
嗯,看了下颜值也挺高,帅。。{:4_173: ...

还是可以再丰富一下,不过算了,还是去喝花酒吧{:4_170:}

红影 发表于 2024-6-25 21:36

这个好,可以直接看到调整两个小球后的效果了{:4_199:}

红影 发表于 2024-6-25 21:38

想得到什么效果,可以到这个帖子里来找了。
这个完全没法根据数字去猜想效果,只能在这里看了{:4_187:}

马黑黑 发表于 2024-6-25 22:11

红影 发表于 2024-6-25 21:36
这个好,可以直接看到调整两个小球后的效果了

{:4_190:}

马黑黑 发表于 2024-6-25 22:11

红影 发表于 2024-6-25 21:38
想得到什么效果,可以到这个帖子里来找了。
这个完全没法根据数字去猜想效果,只能在这里看了

这类工具网上有很多,我这是挑战一下,看做不做得出来

红影 发表于 2024-6-26 12:08

马黑黑 发表于 2024-6-25 22:11


在里面调了好半天,这个太直观了,真的太好了{:4_199:}{:4_199:}{:4_199:}

红影 发表于 2024-6-26 12:08

马黑黑 发表于 2024-6-25 22:11
这类工具网上有很多,我这是挑战一下,看做不做得出来

黑黑不但做出来了,而且特别好{:4_187:}

马黑黑 发表于 2024-6-26 12:09

红影 发表于 2024-6-26 12:08
在里面调了好半天,这个太直观了,真的太好了

工具到处有的,我说过,它们更全面。例如这个:

https://cubic-bezier.com/

马黑黑 发表于 2024-6-26 12:10

红影 发表于 2024-6-26 12:08
黑黑不但做出来了,而且特别好

过得去吧,非专业的

红影 发表于 2024-6-26 16:56

马黑黑 发表于 2024-6-26 12:09
工具到处有的,我说过,它们更全面。例如这个:

https://cubic-bezier.com/

哦,这个还有个作为比较的方块。

红影 发表于 2024-6-26 16:57

马黑黑 发表于 2024-6-26 12:10
过得去吧,非专业的

好用的就好啊,而且原创的,更厉害呢{:4_199:}

南无月 发表于 2024-6-26 17:56

马黑黑 发表于 2024-6-25 18:12
还是可以再丰富一下,不过算了,还是去喝花酒吧

好哒~~去喝吧,
这个已经很好用了。。多喝几次,多出几个小工具{:4_170:}

马黑黑 发表于 2024-6-26 18:23

南无月 发表于 2024-6-26 17:56
好哒~~去喝吧,
这个已经很好用了。。多喝几次,多出几个小工具

{:4_173:}

南无月 发表于 2024-6-26 18:48

马黑黑 发表于 2024-6-26 18:23


{:4_170:}老师去瞧一眼,我跟了一个贴子

马黑黑 发表于 2024-6-26 19:00

南无月 发表于 2024-6-26 18:48
老师去瞧一眼,我跟了一个贴子

好滴

马黑黑 发表于 2024-6-26 19:02

红影 发表于 2024-6-26 16:56
哦,这个还有个作为比较的方块。

是的
页: [1] 2 3 4
查看完整版本: cubic-bezier生成器