<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端:用canvas繪制一個(gè)煙花動(dòng)畫

          共 6035字,需瀏覽 13分鐘

           ·

          2021-07-16 18:22

          關(guān)注并將「趣談前端」設(shè)為星標(biāo)

          每日定時(shí)推送技術(shù)干貨/優(yōu)秀開源/技術(shù)思維

          前言

          在我們?nèi)粘i_發(fā)中貝塞爾曲線無(wú)處不在:

          1. svg 中的曲線(支持 2階、 3階)
          2. canvas 中繪制貝塞爾曲線
          3. 幾乎所有前端2D或3D圖形圖表庫(kù)(echarts,d3,three.js)都會(huì)使用到貝塞爾曲線

          所以掌握貝塞爾曲線勢(shì)在必得。這篇文章主要是實(shí)戰(zhàn)篇,不會(huì)介紹和貝塞爾相關(guān)的知識(shí), 如果有同學(xué)對(duì)貝塞爾曲線不是很清楚的話:可以查看我往期的文章.

          繪制貝塞爾曲線

          第一步我們先創(chuàng)建ctx, 用ctx 畫一個(gè)二階貝塞爾曲線看下。二階貝塞爾曲線有1個(gè)控制點(diǎn),一個(gè)起點(diǎn),一個(gè)終點(diǎn)。

          const canvas = document.getElementById( 'canvas' );
          const ctx = canvas.getContext( '2d' );
          ctx.beginPath();
          ctx.lineWidth = 2;
          ctx.strokeStyle = '#000';
          ctx.moveTo(100,100)
          ctx.quadraticCurveTo(180,50200,200)
          ctx.stroke();
          image-20210614151914950.png

          這樣我們就畫好了一個(gè)貝塞爾曲線了。

          繪制貝塞爾曲線動(dòng)畫

          畫一條線誰(shuí)不會(huì)哇?接下來(lái)文章的主體內(nèi)容。首先試想一下動(dòng)畫我們肯定一步步畫出曲線?但是這個(gè)ctx給我們?nèi)慨嫵鰜?lái)了是不是有點(diǎn)問題。我們重新看下二階貝塞爾曲線的實(shí)現(xiàn)過程動(dòng)畫,看看是否有思路。

          20170817110550542.gif

          從圖中可以分析得出貝塞爾上的曲線是和t有關(guān)系的, t的區(qū)間是在0-1之間,我們是不是可以通過二階貝塞爾的曲線方程去算出每一個(gè)點(diǎn)呢,這個(gè)專業(yè)術(shù)語(yǔ)叫「離散化」,但是這樣的得出來(lái)的點(diǎn)的信息是不太準(zhǔn)的,我們先這樣實(shí)現(xiàn)。

          先看下方程:

          v2-4a70bb17e8c6ff69d500a51279ad8168_r.png

          我們模擬寫出代碼如如下:

          //這個(gè)就是二階貝塞爾曲線方程
          function twoBezizer(p0, p1, p2, t{
            const k = 1 - t
            return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2
          }

          //離散
          function drawWithDiscrete(ctx, start, control, end,percent{
              for ( let t = 0; t <= percent / 100; t += 0.01 ) {
                  const x = twoBezizer(start[0], control[0], end[0], t)
                  const y = twoBezizer(start[1], control[1], end[1], t)
                  ctx.lineTo(x, y)
              }
          }

          我們看下效果:

          image-20210614154751897.png

          和我們畫的幾乎是一模一樣,接下來(lái)就用requestAnimationFrame 開始我們的動(dòng)畫給出以下代碼:

          let percent = 0
          function animate({
              ctx.clearRect( 00800800 );
              ctx.beginPath();
              ctx.moveTo(100,100)
              drawWithDiscrete(ctx,[100,100],[180,50],[200,200],percent)
              ctx.stroke();
              percent = ( percent + 1 ) % 100;
              id =  requestAnimationFrame(animate)
          }
          animate()

          這里有兩個(gè)要注意的是, 我是是percent 不斷加1 和100 求余,所以呢 percent 會(huì)不斷地從1-100 這樣往復(fù),OK所以我們必須要?jiǎng)赢嬛白鲆淮螀^(qū)域清理,  ctx.clearRect( 0, 0, 800, 800 ); 這樣就可以不斷的從開始到結(jié)束循環(huán)往復(fù),我們看下效果:

          Jun-14-2021 16-47-49.gif

          看著樣子是不是還不錯(cuò)哈哈哈??。

          繪制貝塞爾曲線動(dòng)畫方法2

          你以為這樣就結(jié)束了?當(dāng)然不是難道我們真的沒有辦法畫出某一個(gè)t的貝塞爾曲線了?當(dāng)前不是,這里放一下二階貝塞爾方程的推導(dǎo)過程:

          微信圖片_20210615144706.jpg

          二階貝塞爾曲線上的任意一點(diǎn),都是可以通過同樣比例獲得。在兩點(diǎn)之間的任意一點(diǎn),其實(shí)滿足的一階貝塞爾曲線, 一階貝塞爾曲線滿足的其實(shí)是線性變化。我給出以下方程

           function oneBezizer(p0,p1,t{
                return p0 + (p1-p0) * t
            }

          從我畫的圖可以看出,我們只要 不斷求A點(diǎn) 和C點(diǎn)就可以畫出在某一時(shí)間段的貝塞爾了。

          我給出以下代碼和效果圖:

          function drawWithDiscrete2(ctx, start, control, end,percent{
              const t = percent/ 100;
              // 求出A點(diǎn)
              const A = [];
              const C = [];
              A[0] = oneBezizer(start[0],control[0],t);
              A[1] = oneBezizer(start[1],control[1],t);
              C[0] = twoBezizer(start[0], control[0], end[0], t)
              C[1] = twoBezizer(start[1], control[1], end[1], t)
              ctx.quadraticCurveTo( 
                  A[ 0 ], A [ 1 ],
                  C[ 0 ], C[ 1 ]
              );
          }
          Jun-14-2021 16-47-49.gif

          禮花??動(dòng)畫

          上文我們實(shí)現(xiàn)了一條貝塞爾線,我們將這條貝塞爾的曲線的開始點(diǎn)作為一個(gè)圓的圓心,然后按照某個(gè)次數(shù)求出不同的結(jié)束點(diǎn)。再寫一個(gè)隨機(jī)顏色,禮花效果就成了, 直接上代碼,

          for(let i=0; i<count; i++) {
              const angle = Math.PI * 2 / count * i;
              const x = center[ 0 ] + radius * Math.sin( angle );
              const y = center[ 1 ] + radius * Math.cos( angle );
              ctx.strokeStyle = colors[ i ];
              ctx.beginPath();
              drawWithDiscrete(ctx, center,[180,50],[x,y],percent)
              ctx.stroke();
          }

          function getRandomColor(colors, count{
              // 生成隨機(jī)顏色
              for ( let i = 0; i < count; i++ )  {
                  colors.push( 
                    'rgb( ' + 
                      ( Math.random() * 255 >> 0 ) + ',' +
                      ( Math.random() * 255 >> 0 ) + ',' + 
                      ( Math.random() * 255 >> 0 ) + 
                    ' )'
                  );
              }
          }

          我們看下動(dòng)畫吧:

          端午節(jié)快樂.gif

          結(jié)尾

          本篇文章到這里就結(jié)束了,如果看了對(duì)你有幫助的, 歡迎點(diǎn)個(gè)贊??和關(guān)注。你的支持是我持續(xù)更新的最大動(dòng)力。

          看視頻, 漲芝士啦??


          ?? 看完三件事

          如果你覺得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:

          • 點(diǎn)個(gè)【在看】,或者分享轉(zhuǎn)發(fā),讓更多的人也能看到這篇內(nèi)容
          • 關(guān)注公眾號(hào)【趣談前端】,定期分享 工程化 可視化 / 低代碼 / 優(yōu)秀開源


          從零設(shè)計(jì)可視化大屏搭建引擎

          Dooring可視化搭建平臺(tái)數(shù)據(jù)源設(shè)計(jì)剖析

          可視化搭建的一些思考和實(shí)踐

          基于Koa + React + TS從零開發(fā)全棧文檔編輯器(進(jìn)階實(shí)戰(zhàn))


          點(diǎn)個(gè)在看你最好看

          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩福利一区二区 | 苏畅md一区二区三区在线观看 | 国产色视频在线看 | 国产极品无码AV在线观看 | 国产一级高清无码 |