成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用Canvas實現一個大氣球送給你

開發 前端
近期在做一個氣球掛件的特效需求,值此契機,來跟大家分享一下如何利用canvas以及對應的數學知識構造一個栩栩如生的氣球。

[[423338]]

一、背景

近期在做一個氣球掛件的特效需求,值此契機,來跟大家分享一下如何利用canvas以及對應的數學知識構造一個栩栩如生的氣球。

二、實現

在實現這個看似是圓鼓鼓的氣球之前,先了解一下其實現思路,主要分為以下幾個部分:

  1. 實現球體部分;
  2. 實現氣球口子部分;
  3. 實現氣球的線部分;
  4. 進行顏色填充;
  5. 實現動畫;

氣球.PNG

2.1 球體部分實現

對于這樣的氣球的球體部分,大家都有什么好的實現思路的?相信大家肯定會有多種多樣的實現方案,我也是在看到某位大佬的效果后,感受到了利用四個三次貝塞爾曲線實現這個效果的妙處。為了看懂后續代碼,先了解一下三次貝塞爾曲線的原理。(注:引用了CSDN上某位大佬的文章,寫的很好,下圖引用于此)

三次貝塞爾曲線.gif

在上圖中P0為起始點、P3為終止點,P1和P2為控制點,其最終的曲線公式如下所示:

  1. B(t)=(1?t)^3 * P0+3t(1?t)^2 * P1+3t ^ 2(1?t) * P2+t ^ 3P3, t∈[0,1] 

上述已經列出了三次貝塞爾曲線的效果圖和公式,但是通過這個怎么跟我們的氣球掛上鉤呢?下面通過幾張圖就理解了:

如上圖所示,就是實現整個氣球球體的思路,具體解釋如下所示:

  1. A圖中起始點為p1,終止點為p2,控制點為c1、c2,讓兩個控制點重合,繪制出的效果并不是很像氣球的一部分,此時就要通過改變控制點來改變其外觀;
  2. 改變控制點c1、c2,c1中y值不變,減小x值;c2中x值不變,增大y值(注意canvas中坐標方向即可),改變后就得到了圖B的效果,此時就跟氣球外觀很像了;
  3. 緊接著按照這個方法就可以實現整個的氣球球體部分的外觀。
  1. function draw() { 
  2.     const canvas = document.getElementById('canvas'); 
  3.     const ctx = canvas.getContext('2d'); 
  4.  
  5.     ctx.translate(250, 250); 
  6.     drawCoordiante(ctx); 
  7.     ctx.save(); 
  8.     ctx.beginPath(); 
  9.     ctx.moveTo(0, -80); 
  10.     ctx.bezierCurveTo(45, -80, 80, -45, 80, 0); 
  11.     ctx.bezierCurveTo(80, 85, 45, 120, 0, 120); 
  12.     ctx.bezierCurveTo(-45, 120, -80, 85, -80, 0); 
  13.     ctx.bezierCurveTo(-80, -45, -45, -80, 0, -80); 
  14.     ctx.stroke(); 
  15.     ctx.restore(); 
  16.  
  17. function drawCoordiante(ctx) { 
  18.     ctx.beginPath(); 
  19.     ctx.moveTo(-120, 0); 
  20.     ctx.lineTo(120, 0); 
  21.     ctx.moveTo(0, -120); 
  22.     ctx.lineTo(0, 120); 
  23.     ctx.closePath(); 
  24.     ctx.stroke(); 

2.2 口子部分實現

口子部分可以簡化為一個三角形,效果如下所示:

  1. function draw() { 
  2.     const canvas = document.getElementById('canvas'); 
  3.     const ctx = canvas.getContext('2d'); 
  4.  
  5.     …… 
  6.  
  7.     ctx.save(); 
  8.     ctx.beginPath(); 
  9.     ctx.moveTo(0, 120); 
  10.     ctx.lineTo(-5, 130); 
  11.     ctx.lineTo(5, 130); 
  12.     ctx.closePath(); 
  13.     ctx.stroke(); 
  14.     ctx.restore(); 

2.3 線部分實現

線實現的比較簡單,就用了一段直線實現

  1. function draw() { 
  2.     const canvas = document.getElementById('canvas'); 
  3.     const ctx = canvas.getContext('2d'); 
  4.  
  5.     …… 
  6.  
  7.     ctx.save(); 
  8.     ctx.beginPath(); 
  9.     ctx.moveTo(0, 120); 
  10.     ctx.lineTo(0, 300); 
  11.     ctx.stroke(); 
  12.     ctx.restore(); 

2.4 進行填充

氣球部分的填充用了圓形漸變效果,相比于純色來說更加漂亮一些。

  1. function draw() { 
  2.     const canvas = document.getElementById('canvas'); 
  3.     const ctx = canvas.getContext('2d'); 
  4.  
  5.     ctx.fillStyle = getBalloonGradient(ctx, 0, 0, 80, 210); 
  6.     …… 
  7.      
  8.  
  9. function getBalloonGradient(ctx, x, y, r, hue) { 
  10.     const grd = ctx.createRadialGradient(x, y, 0, x, y, r); 
  11.     grd.addColorStop(0, 'hsla(' + hue + ', 100%, 65%, .95)'); 
  12.     grd.addColorStop(0.4, 'hsla(' + hue + ', 100%, 45%, .85)'); 
  13.     grd.addColorStop(1, 'hsla(' + hue + ', 100%, 25%, .80)'); 
  14.     return grd; 

2.5 動畫效果及整體代碼

上述流程已經將一個靜態的氣球部分繪制完畢了,要想實現動畫效果只需要利用requestAnimationFrame函數不斷循環調用即可實現。下面直接拋出整體代碼,方便同學們觀察效果進行調試,整體代碼如下所示:

  1. let posX = 225; 
  2. let posY = 300; 
  3. let points = getPoints(); 
  4. draw(); 
  5.  
  6. function draw() { 
  7.     const canvas = document.getElementById('canvas'); 
  8.     const ctx = canvas.getContext('2d'); 
  9.     ctx.clearRect(0, 0, canvas.width, canvas.height); 
  10.     if (posY < -200) { 
  11.         posY = 300; 
  12.         posX += 300 * (Math.random() - 0.5); 
  13.         points = getPoints(); 
  14.     } 
  15.     else { 
  16.         posY -= 2; 
  17.     } 
  18.     ctx.save(); 
  19.     ctx.translate(posX, posY); 
  20.     drawBalloon(ctx, points); 
  21.     ctx.restore(); 
  22.  
  23.     window.requestAnimationFrame(draw); 
  24.  
  25. function drawBalloon(ctx, points) { 
  26.     ctx.scale(points.scale, points.scale); 
  27.     ctx.save(); 
  28.     ctx.fillStyle = getBalloonGradient(ctx, 0, 0, points.R, points.hue); 
  29.     // 繪制球體部分 
  30.     ctx.moveTo(points.p1.x, points.p1.y); 
  31.     ctx.bezierCurveTo(points.pC1to2A.x, points.pC1to2A.y, points.pC1to2B.x, points.pC1to2B.y, points.p2.x, points.p2.y); 
  32.     ctx.bezierCurveTo(points.pC2to3A.x, points.pC2to3A.y, points.pC2to3B.x, points.pC2to3B.y, points.p3.x, points.p3.y); 
  33.     ctx.bezierCurveTo(points.pC3to4A.x, points.pC3to4A.y, points.pC3to4B.x, points.pC3to4B.y, points.p4.x, points.p4.y); 
  34.     ctx.bezierCurveTo(points.pC4to1A.x, points.pC4to1A.y, points.pC4to1B.x, points.pC4to1B.y, points.p1.x, points.p1.y); 
  35.  
  36.     // 繪制氣球鈕部分 
  37.     ctx.moveTo(points.p3.x, points.p3.y); 
  38.     ctx.lineTo(points.knowA.x, points.knowA.y); 
  39.     ctx.lineTo(points.knowB.x, points.knowB.y); 
  40.     ctx.fill(); 
  41.     ctx.restore(); 
  42.  
  43.     // 繪制線部分 
  44.     ctx.save(); 
  45.     ctx.strokeStyle = '#000000'
  46.     ctx.lineWidth = 1; 
  47.     ctx.beginPath(); 
  48.     ctx.moveTo(points.p3.x, points.p3.y); 
  49.     ctx.lineTo(points.lineEnd.x, points.lineEnd.y); 
  50.     ctx.stroke(); 
  51.     ctx.restore(); 
  52.  
  53. function getPoints() { 
  54.     const offset = 35; 
  55.     return { 
  56.         scale: 0.3 + Math.random() / 2, 
  57.         hue: Math.random() * 255, 
  58.         R: 80, 
  59.         p1: { 
  60.             x: 0, 
  61.             y: -80 
  62.         }, 
  63.         pC1to2A: { 
  64.             x: 80 - offset, 
  65.             y: -80 
  66.         }, 
  67.         pC1to2B: { 
  68.             x: 80, 
  69.             y: -80 + offset 
  70.         }, 
  71.         p2: { 
  72.             x: 80, 
  73.             y: 0 
  74.         }, 
  75.         pC2to3A: { 
  76.             x: 80, 
  77.             y: 120 - offset 
  78.         }, 
  79.         pC2to3B: { 
  80.             x: 80 - offset, 
  81.             y: 120 
  82.         }, 
  83.         p3: { 
  84.             x: 0, 
  85.             y: 120 
  86.         }, 
  87.         pC3to4A: { 
  88.             x: -80 + offset, 
  89.             y: 120 
  90.         }, 
  91.         pC3to4B: { 
  92.             x: -80, 
  93.             y: 120 - offset 
  94.         }, 
  95.         p4: { 
  96.             x: -80, 
  97.             y: 0 
  98.         }, 
  99.         pC4to1A: { 
  100.             x: -80, 
  101.             y: -80 + offset 
  102.         }, 
  103.         pC4to1B: { 
  104.             x: -80 + offset, 
  105.             y: -80 
  106.         }, 
  107.         knowA: { 
  108.             x: -5, 
  109.             y: 130 
  110.         }, 
  111.         knowB: { 
  112.             x: 5, 
  113.             y: 130 
  114.         }, 
  115.         lineEnd: { 
  116.             x: 0, 
  117.             y: 250 
  118.         } 
  119.     }; 
  120.  
  121. function getBalloonGradient(ctx, x, y, r, hue) { 
  122.     const grd = ctx.createRadialGradient(x, y, 0, x, y, r); 
  123.     grd.addColorStop(0, 'hsla(' + hue + ', 100%, 65%, .95)'); 
  124.     grd.addColorStop(0.4, 'hsla(' + hue + ', 100%, 45%, .85)'); 
  125.     grd.addColorStop(1, 'hsla(' + hue + ', 100%, 25%, .80)'); 
  126.     return grd; 

 

責任編輯:武曉燕 來源: 前端點線面
相關推薦

2022-12-22 08:22:17

Python圖像圖像處理

2017-08-29 15:34:10

CanvasWASM算法

2017-11-27 13:39:29

Python大數據搜索引擎

2017-12-27 14:51:12

Kotlin谷歌Java

2018-07-03 15:20:36

Promise函數借錢

2020-09-06 22:59:35

Linux文件命令

2021-04-15 11:37:47

NumpyPython代碼

2018-05-04 09:14:09

Git技巧shell命令

2021-05-07 07:59:52

WebFluxSpring5系統

2025-05-12 08:55:00

2012-05-30 09:40:55

Linux鍋爐

2018-06-16 08:35:57

UnixLinux命令

2020-12-20 10:07:57

Canvas圖形驗證碼javascript

2014-04-14 15:54:00

print()Web服務器

2019-02-11 11:16:13

2021-02-14 19:24:45

SpringRegistrar對象

2023-01-30 16:21:24

Linux外觀

2017-06-05 12:06:00

2022-02-28 00:14:30

人工智能數據機器學習

2021-06-25 10:38:05

JavaScript編譯器前端開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 美女艹b | 亚洲精品在线免费播放 | 亚洲日本欧美日韩高观看 | 精品国产乱码久久久久久闺蜜 | 色婷婷av一区二区三区软件 | 欧美日韩在线免费观看 | 久久久婷 | 日韩在线高清 | 成人亚洲性情网站www在线观看 | 色网在线观看 | 成人亚洲一区 | 亚洲aⅴ | 欧美精品久久久久久 | 欧美日韩一卡二卡 | 久久精品国产免费一区二区三区 | 久久一区精品 | 欧美成人激情 | 香蕉久久a毛片 | 男女午夜激情视频 | 国产精品自在线 | 成人精品国产一区二区4080 | 国产99久久久国产精品 | 日韩国产专区 | 一区视频在线播放 | 欧美成人精品一区二区男人看 | 久久成人免费视频 | 精品国产一区二区三区性色 | 色男人的天堂 | 91视频在线 | 可以看黄的视频 | 亚洲激情在线观看 | 精品欧美乱码久久久久久1区2区 | 中文字幕第一页在线 | 成人小视频在线观看 | 亚洲人成人网 | av性色 | 精品无码久久久久久国产 | 亚洲精品白浆高清久久久久久 | 99一级毛片 | 一区视频 | 日本a视频|