贝塞尔曲线轨迹运动原理与实战

发表于 2年以前  | 总阅读数:464 次

本次分享大概分为下面几个方面

  • 背景
  • 贝塞尔曲线讲解
  • 实现和探索过程

背景

近期在 X 业务测评报告页有一个需求,用户可以左右拖动滑块来查看各个等级的信息。

在之前的野种中是通过切换图片的方式,会有卡顿的现象。由于 X 业务中等级区分比较少,等级间距更大,所以卡顿感会更大。

所以为了能够体现更丝滑的效果,使用svg画出贝塞尔曲线,动态控制实线和虚线的切换以及空心小球的位置。

svg中的path标签

<svg>
  <path 
      stroke="red" 
      fill="none"  
      d="M 4,130 C 12.85,129.1 45.3,126.7 63,124 C 80.7,121.3 104.3,116.5 122,1                        12 C 139.7,107.5 163.3,100.3 181,94 C 198.7,87.7 222.3,78.10000000000001 240,70 C 257.7,61.9 281.3,49.900000000000006 299,40 C 316.7,30.1 349.15,9.400000000000004 358,4"></path>
</svg>

M- moveto - 从一点移到另一点.(作为起点)

L- lineto -创建一条线.

H- horizontal lineto - 创建一条水平线.

V- vertical lineto - 创建一条竖线.

C- curveto - 创建(三阶)贝塞尔曲线到.

S- smooth curveto - 创建一条平滑曲线

Q- quadratic Bezier curve - 创建一个二次贝塞尔曲线

T- smooth quadratic Bezier curveto - 创建一个平滑二次贝塞尔曲线.

A- elliptical Arc - 创建一个椭圆弧.

Z- closepath - 关闭路径

上述命令使用大写字母,代表绝对路径,如果使用小写字母,则使用相对路径。

d="M 4,130 C 12.85,129.1 45.3,126.7 63,124".

贝塞尔曲线

贝塞尔曲线,由“线段”和节点组成,节点是可拖动的支点,表示曲线的趋向,“线段”像可伸缩的橡皮筋。它抽象了线段和曲线,通过控制路径上的四个点(起始点、终止点、两个中间点)来编辑图形;其中中间点和端点的连线称为控制线,这是一条虚拟的线段;两端的端点用来改变曲线的曲率;移动中间点来改变曲线运动轨迹。

一阶贝塞尔曲线

公式:B(t) = P1 + (P2 − P1)t = P1(1−t)+ P2t, t∈[0,1]

二阶贝塞尔曲线

在平面内选3个不同线的点P1、P2、P3并且依次用线段连接,P1,P3为固定点,P2为支点(控制点)

公式:

M = P1(1-t)+P2t

N = P2(1-t)+P3t

B(t) = M(1-t)+Nt

三阶贝塞尔曲线

公式:

X(t) = P(1)(1 - t) + P(2)t

Y(t) = P(2)(1 - t) + P(3)t

Z(t) = P(3)(1 - t) + P(4)t

M(t) = X(1 - t) + Yt

N(t) = Y(1 - t) + Zt

B(t) = M(1 - t) + Nt

N阶贝塞尔曲线

在三阶贝塞尔曲线中,如何确定控制点

方向:越是高阶可导函数曲线越是光滑,在只要保证曲线函数试一阶导数连续,换句话说只要保证曲线的切线斜率连续,那么我们很容易确定CP(control point)点的所在直线的斜率。

长度: 长度决定了曲线弧度的大小(宽窄),有一种计算方式可以使曲线弧度很自然。

AC的长度 * smoothing, smoothing = 0.15比较光滑

对于第一个点A,和最后一个点D的控制点,可以简单把AB的方向看作是A点的切线方向,长度为AB*smoothing。同理可知道点D附近的控制点

实现动效的难点

  1. 跟手变化的时候,实线和虚线的切换
  2. 空心小球在曲线上跟手移动
  3. 松手后,小球和曲线的动画

SVG基础

stroke-dasharray 和 stroke-dashoffset

  1. stroke-dasharray:用于创建虚线

a . 如:stroke-dasharray = '10, 5' 表示:虚线(Dash)长10,间距(Gap)5,然后重复 虚线长10,间距5

b . 如:stroke-dasharray = '20, 10, 5' 表示:虚线长20,间距10,虚线长5,接着是间距20,虚线10,间距5,之后开始如此循环

2 . stroke-dashoffset:offset:偏移的意思

a . 这个属性是相对于起始点的偏移,正数偏移x值的时候,相当于往左移动了x个长度单位,负数偏移x的时候,相当于往右移动了x个长度单位。需要注意的是,不管偏移的方向是哪边,要记得dasharray 是循环的,也就是 虚线-间隔-虚线-间隔。这个属性要搭配stroke-dasharray才能看得出来效果,非虚线的话,是无法看出偏移的。

如:https://codepen.io/Josh_byte/pen/MWQVWKK[1]

Offset-path和offset-distance css属性

  • 通过css属性offset-path可以指定元素不规则的动画路径
  • offset-distance,是运动的距离,可以是数值或者百分比单位,如果是100%则表示正好把所有的路都跑完了。

如:https://codepen.io/Josh_byte/pen/PoQzjON[2]

参考:https://zhuanlan.zhihu.com/p/31242043[3]

兼容性

实现过程

step1 画贝塞尔曲线图

image.png BC直线的斜率 与x1x2直线的斜率一致

算圆心点坐标&把手坐标

//动态计算出的圆心坐标
const PointArray = [
[4, 130],
[63, 124],
[122, 112],
[181, 94],
[240, 70],
[299, 40],
[358, 4]
]


//算出当前点前一个点和后一个点的角度
const line = (pointA: number[], pointB: number[]) => {
    const lengthX = pointB[0] - pointA[0];
    const lengthY = pointB[1] - pointA[1];
    return {
      length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
      angle: Math.atan2(lengthY, lengthX),
    };
  };

//求每两个圆心坐标之间的两个把手
const controlPoint = (current: number[], previous: number[], next: number[], reverse: boolean) => {
    const p = previous || current;
    const n = next || current;
    const l = this.line(p, n);

    const angle = l.angle + (reverse ? Math.PI : 0);
    const length = l.length * BezierCurveAndCirclePoint.smoothing;
    const x = current[0] + Math.cos(angle) * length;
    const y = current[1] + Math.sin(angle) * length;
    return [x, y];
  };

const getBezierCurvePointArray = () => {
    const array: Point[][] = [];
    pointArray.forEach((item, i) => {
      if (i === 0) {
        return;
      }
      const cps = this.controlPoint(this.pointArray[i - 1], this.pointArray[i - 2], item, false);
      const cpe = this.controlPoint(item, this.pointArray[i - 1], this.pointArray[i + 1], true);
      array.push([
        {
          x: pointArray[i - 1][0],
          y: pointArray[i - 1][1],
        },
        {
          x: cps[0],
          y: cps[1],
        },
        {
          x: cpe[0],
          y: cpe[1],
        },
        {
          x: item[0],
          y: item[1],
        },
      ]);
    });
    return array;
};

绘制三条三阶贝塞尔曲线

观察发现

绿色实线变绿色虚线的过程可以看成,绿色实线往左偏移的过程(stroke-dashoffset)

灰色实线变绿色虚线的过程,可以看成,灰色实线往右偏移的过程。

绿色虚线,在最底层,没有变化。变化的是绿色和灰色实线

案例 https://codepen.io/Josh_byte/pen/bGLvKYM[4]

step2 求曲线弧长

如何判断stroke-dashoffset的距离?跟手移动2px,绿色实线或灰色实线移动多少?

stroke-dasharray的初始值设置为多少?

如何求三阶贝塞尔曲线函数的坐标

P0 是起始点坐标

P1,P2是控制点

P3是终点坐标

t是百分比(在曲线位置的百分比)

const calculateCirclePoint = (t: number, PointArray: Point[]) => {
    const p0 = PointArray[0];
    const p1 = PointArray[1];
    const p2 = PointArray[2];
    const p3 = PointArray[3];
    const temp = 1 - t;
    const x =
      p0.x * temp * temp * temp +
      3 * p1.x * t * temp * temp +
      3 * p2.x * t * t * temp +
      p3.x * t * t * t;
    const y =
      p0.y * temp * temp * temp +
      3 * p1.y * t * temp * temp +
      3 * p2.y * t * t * temp +
      p3.y * t * t * t;
    return {
      x,
      y,
    };
  };
//举个例子,第一段曲线
const curvePoint = 
[{x: 122, y: 112}, //起始点
{x: 139.7, y: 107.5}, //把手一
{x: 163.3, y: 100.3}, //把手二
{x: 181, y: 94}]。//终点
calculateCirclePoint(0.5,curvePoint)

如何求弧长

采样大概估算弧长,一段曲线中等间距采点60个,每两个点计算的间距求和

const cubicBezierLength = (PointArray: Point[], sampleCount?: number) => {
    const ptCount = sampleCount || 40;
    let totDist = 0;
    let lastX = PointArray[0].x;
    let lastY = PointArray[0].y;
    let dx;
    let dy;
    for (let i = 1; i < ptCount; i++) {
      const pt = this.calculateCirclePoint(i / ptCount, PointArray);
      dx = pt.x - lastX;
      dy = pt.y - lastY;
      totDist += Math.sqrt(dx * dx + dy * dy);
      lastX = pt.x;
      lastY = pt.y;
    }
    dx = PointArray[3].x - lastX;
    dy = PointArray[3].y - lastY;
    totDist += Math.sqrt(dx * dx + dy * dy);
    return Math.floor(totDist);
  };

完成以上两步,就可以实现曲线跟手移动的变化还有松手时候的动效了。

step3 实现空心小球跟手移动

由于offset-path属性在ios上不支持,只能实时求空心小球的实时坐标

step4 实现空心小球松手后的吸附动效

SVG SMIL animation

1 . animateMotion/

 <circle
    opacity={circleAnimationPointOpacity ? '1' : '0'}
    r="3"
    fill="#ffffff"
    strokeWidth="2"
    stroke="#43E077"
    >
            <animateMotion
              ref={circleAnimationRef}
              path={cirlceAnimationPath} //运动路径 
              dur="200ms"   //持续时间
              keySplines="0.25 0.1 0.25 1" //动画时间曲线
              fill="freeze".    //结束后在原位置
              begin="indefinit".   //无限等待 开始用circleAnimationRef.current.beginElement()
              repeatCount="1".  //执行一次
            />
 </circle>

案列 https://codepen.io/Josh_byte/pen/oNEYpjO[5]

2 . 有两个空心绿色小球,一个小球是跟手移动的空心小球,还有一个是实现松手后动画的空心小球。

参考资料

[1]https://codepen.io/Josh_byte/pen/MWQVWKK: https://codepen.io/Josh_byte/pen/MWQVWKK

[2]https://codepen.io/Josh_byte/pen/PoQzjON: https://codepen.io/Josh_byte/pen/PoQzjON

[3]https://zhuanlan.zhihu.com/p/31242043: https://zhuanlan.zhihu.com/p/31242043

[4]https://codepen.io/Josh_byte/pen/bGLvKYM: https://codepen.io/Josh_byte/pen/bGLvKYM

[5]https://codepen.io/Josh_byte/pen/oNEYpjO: https://codepen.io/Josh_byte/pen/oNEYpjO

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/ZOY1_GcSGtoeOZWaWfNqHQ

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237227次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录