整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          canvas-3圓的繪制

          canvas-3圓的繪制


          anvas畫了一個圓


          <!DOCTYPE html>

          <html>

          <head>

          <meta charset="utf-8">

          <title>canvas-3圓的繪制</title>

          </head>

          <body>

          <canvas id="canvas1" width="600" height="600" style="border:1px solid #000000"></canvas>

          <script type="text/javascript">

          var canvas1=document.querySelector("#canvas1") // 1.找到畫布對象

          var ctx=canvas1.getContext("2d") // 2.上下文對象(畫筆)

          // (圓心x:300, 圓心y:300, 半徑r:100, 開始角度:0 , 結束角度:360度, 默認為false(可不寫)是順時針,true為逆時針)

          ctx.arc(300, 300, 100, 0, 2*Math.PI)

          ctx.stroke()

          </script>


          </body>

          </html>


          家好! 歡迎來到本教程,我們將深入了解使用 HTML 畫布和 JavaScript 在代碼中創建有趣的氣泡的世界。 最好的部分? 我們將只使用一點 HTML 和所有 JavaScript,而不是 CSS 來實現所有這一切。

          揭示概念

          今天,我們要掌握以下幾個概念:

          使用畫布上下文的 arc 方法創建圓。

          利用 requestAnimationFrame 函數實現平滑的圓形動畫。

          利用 JavaScript 類的強大功能來創建多個圓圈,而無需重復代碼。

          向我們的圓圈添加描邊樣式和填充樣式以獲得 3D 氣泡效果。

          你可以跟著我一起看,或者如果你想看源代碼,可以使用最終的codepen

          入門

          首先,我們需要一個 HTML5 Canvas 元素。 Canvas 是創建形狀、圖像和圖形的強大元素。 這就是氣泡將產生的地方。 讓我們來設置一下 -

          <canvas id="canvas"></canvas>

          為了使用畫布做任何有意義的事情,我們需要訪問它的上下文。 Context 提供了在畫布上渲染對象和繪制形狀的接口。

          讓我們訪問畫布及其上下文。

          const canvas=document.getElementById('canvas');
          const context=canvas.getContext('2d');

          我們將設置畫布以使用整個窗口的高度和寬度 -

          canvas.width=window.innerWidth;
          canvas.height=window.innerHeight;

          讓我們通過添加一些 css 為畫布提供一個漂亮的舒緩淺藍色背景。 這是我們要使用的唯一 CSS。 如果您愿意,也可以使用 JavaScript 來完成此操作。

          #canvas {
            background: #00b4ff;
          }

          是時候創造泡泡了!

          讓我們進入有趣的部分。 我們將通過單擊畫布來創建氣泡。 為了實現這一點,我們首先創建一個點擊事件處理程序:

          canvas.addEventListener('click', handleDrawCircle);

          由于我們需要知道在畫布上單擊的位置,因此我們將在句柄 DrawCircle 函數中跟蹤它并使用事件的坐標 -

          //We are adding x and y here because we will need it later.
          let x, y
          const handleDrawCircle=(event)=> {
            x=event.pageX;
            y=event.pageY;
          
          // Draw a bubble!
            drawCircle(x, y);
          };

          用圓弧法畫圓

          為了創建圓圈,我們將利用畫布上下文中可用的 arc 方法。 Arc 方法接受 x 和 y - 圓心、半徑、起始角和結束角,對于我們來說,這將是 0 和 2* Math.PI,因為我們正在創建一個完整的圓。

          const drawCircle=(x, y)=> {
            context.beginPath();
            context.arc(x, y, 50, 0, 2 * Math.PI);
            context.strokeStyle='white';
            context.stroke();
          };


          使用 requestAnimationFrame 方法移動圓圈

          現在我們有了圓圈,讓我們讓它們移動,因為……

          GIF



          請記住,當我們創建圓時,我們使用了 arc 方法,它接受 x 和 y 坐標 - 圓的中心。 如果我們快速移動圓的 x 和 y 坐標,就會給人一種圓在移動的印象。 讓我們試試吧!

          //Define a speed by which to increment to the x and y coordinates
          const dx=Math.random() * 3;
          const dy=Math.random() * 7;//Increment the center of the circle with this speed
          x=x + dx;
          y=y - dy;

          我們可以將其移至函數內 -

          let x, y;
          const move=()=> {
            const dx=Math.random() * 3;
            const dy=Math.random() * 7;  x=x + dx;
            y=y - dy;
          };

          為了讓我們的圓圈無縫移動,我們將創建一個動畫函數并使用瀏覽器的 requestAnimationFrame 方法來創建一個移動的圓圈。

          const animate=()=> {
            context.clearRect(0, 0, canvas.width, canvas.height);
            move();
              drawCircle(x,y);  requestAnimationFrame(animate);
          };//Don't forget to call animate at the bottom 
          animate();



          創建粒子:引入粒子類

          現在我們已經創建了一個圓圈,是時候創建多個圓圈了!

          但在我們創建多個圓圈之前,讓我們準備一下我們的代碼。為了避免重復我們的代碼,我們將使用類并引入 Particle 類。 粒子是我們動態藝術作品和動畫的構建塊。 每個氣泡都是一個粒子,具有自己的位置、大小、運動和顏色屬性。 讓我們定義一個 Particle 類來封裝這些屬性:

          class Particle {
            constructor(x=0, y=0) {}
            draw() {
              // Drawing the particle as a colored circle
              // ...
            }  move() {
              // Implementing particle movement
              // ...
            }
          }

          讓我們將一些已設置的常量移至 Particle 類 -

          class Particle {
            constructor(x=0, y=0) {
              this.x=x;
              this.y=y;
              this.radius=Math.random() * 50;
              this.dx=Math.random() * 3;
              this.dy=Math.random() * 7;
            }
            draw() {
              // Drawing the particle as a colored circle
              // ...
            }  move() {
              // Implementing particle movement
              // ...
            }
          }

          draw 方法將負責在畫布上渲染粒子。 我們已經在drawCircle中實現了這個功能,所以讓我們將它移動到我們的類中并將變量更新為類變量

          class Particle {
            constructor(x=0, y=0) {
              this.x=x;
              this.y=y;
              this.radius=Math.random() * 50;
              this.dx=Math.random() * 3;
              this.dy=Math.random() * 7;
              this.color='white';
            }
            draw() {
              context.beginPath();
              context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
              context.strokeStyle=this.color;
              context.stroke();    context.fillStyle=this.color;
              context.fill();
            }  move() {}
          }

          同樣,讓我們在類中移動 move 函數 -

          move() {
              this.x=this.x + this.dx;
              this.y=this.y - this.dy;
          }

          現在,我們需要確保在事件處理程序中調用 Particle 類。

          const handleDrawCircle=(event)=> {
            const x=event.pageX;
            const y=event.pageY;
            const particle=new Particle(x, y);
          };canvas.addEventListener('click', handleDrawCircle);

          由于我們需要在 animate 函數中訪問該粒子,以便調用其 move 方法,因此我們將該粒子存儲在一個名為 molecularArray 的數組中。 當創建大量粒子時,這個數組也會很有幫助。 這是反映這一點的更新代碼 -

          const particleArray=[];
          const handleDrawCircle=(event)=> {
            const x=event.pageX;
            const y=event.pageY;  const particle=new Particle(x, y);
            particleArray.push(particle);
          };canvas.addEventListener('click', handleDrawCircle);

          記得也要更新動畫功能 -

          此時,您將在屏幕上看到這個粒子 -



          驚人的! 現在,到了有趣的部分! 讓我們創建很多圓圈并設計它們的樣式,使它們看起來像氣泡。

          為了創建大量氣泡,我們將使用 for 循環創建粒子并將它們添加到我們在此處創建的粒子數組中。

          const handleDrawCircle=(event)=> {
            const x=event.pageX;
            const y=event.pageY;
            for (let i=0; i < 50; i++) {
              const particle=new Particle(x, y);
              particleArray.push(particle);
            }
          };canvas.addEventListener('click', handleDrawCircle);

          在動畫函數中,我們將通過清除畫布并在新位置重新繪制粒子來不斷更新畫布。 這會給人一種圓圈在移動的錯覺。

          const animate=()=> {
            context.clearRect(0, 0, canvas.width, canvas.height);
            particleArray.forEach((particle)=> {
              particle?.move();
              particle?.draw();
            });  requestAnimationFrame(animate);
          };animate();


          現在我們有了移動的氣泡,是時候給它們添加顏色,使它們看起來像氣泡了!

          我們將通過向氣泡添加漸變填充來實現此目的。 這可以使用 context.createRadialGradient 方法來完成。

          const gradient=context.createRadialGradient(
            this.x,
            this.y,
            1,
            this.x + 0.5,
            this.y + 0.5,
            this.radius
          );
          gradient.addColorStop(0.3, 'rgba(255, 255, 255, 0.3)');
          gradient.addColorStop(0.95, '#e7feff');context.fillStyle=gradient;



          總結

          恭喜! 您剛剛僅使用 HTML Canvas 和 JavaScript 創建了一些超級有趣的東西。 您已經學習了如何使用 arc 方法、利用 requestAnimationFrame、利用 JavaScript 類的強大功能以及使用漸變設計氣泡以實現 3D 氣泡效果。

          請隨意嘗試顏色、速度和大小,使您的動畫真正獨一無二。

          請隨意嘗試顏色、速度和大小,使您的動畫真正獨一無二。

          我希望您在學習本教程時能像我在創建它時一樣獲得樂趣。 現在,輪到你進行實驗了。 我很想看看你是否嘗試過這個以及你創造了什么。 與我分享您的代碼鏈接,我很樂意查看。

          . canvas實現時鐘轉動

          實現以下效果,分為幾步:

          • 1、找到canvas的中心,畫出表心,以及表框
          • 2、獲取當前時間,并根據時間畫出時針,分針,秒針,還有刻度
          • 3、使用定時器,每過一秒獲取新的時間,并重新繪圖,達到時鐘轉動的效果

          1.1 表心,表框

          畫表心,表框有兩個知識點:

          • 1、找到canvas的中心位置
          • 2、繪制圓形
          //html
          <canvas id="canvas" width="600" height="600"></canvas>
          // js
          // 設置中心點,此時300,300變成了坐標的0,0
          ctx.translate(300, 300)
          // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結束角度)
          ctx.arc(0, 0, 100, 0, 2 * Math.PI)
          ctx.arc(0, 0, 5, 0, 2 * Math.PI)
          // 執行畫線段的操作stroke
          ctx.stroke() 
          復制代碼
          

          讓我們來看看效果,發現了,好像不對啊,我們是想畫兩個獨立的圓線,怎么畫出來的兩個圓連到一起了

          原因是:上面代碼畫連個圓時,是連著畫的,所以畫完大圓后,線還沒斬斷,就接著畫小圓,那肯定會大圓小圓連一起,解決辦法就是:beginPath,closePath

          ctx.translate(300, 300) // 設置中心點,此時300,300變成了坐標的0,0
          // 畫大圓
          + ctx.beginPath()
          // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結束角度)
            ctx.arc(0, 0, 100, 0, 2 * Math.PI)
            ctx.stroke() // 執行畫線段的操作
          + ctx.closePath()
          // 畫小圓
          + ctx.beginPath()
            ctx.arc(0, 0, 5, 0, 2 * Math.PI)
            ctx.stroke()
          + ctx.closePath()
          復制代碼
          

          1.2 時針,分針,秒針

          畫這三個指針,有兩個知識點:

          • 1、根據當前時,分,秒計算角度
          • 2、在計算好的角度上去畫出時針,分針,秒針

          如何根據算好的角度去畫線呢,比如算出當前是3點,那么時針就應該以12點為起始點,順時針旋轉2 * Math.PI / 12 * 3=90°,分針和秒針也是同樣的道理,只不過跟時針不同的是比例問題而已,因為時在表上有12份,而分針和秒針都是60份

          這時候又有一個新問題,還是以上面的例子為例,我算出了90°,那我們怎么畫出時針呢?我們可以使用moveTo和lineTo去畫線段。至于90°,我們只需要將x軸順時針旋轉90°,然后再畫出這條線段,那就得到了指定角度的指針了。但是上面說了,是要以12點為起始點,我們的默認x軸確是水平的,所以我們時分秒針算出角度后,每次都要減去90°。可能這有點繞,我們通過下面的圖演示一下,還是以上面3點的例子:

          這樣就得出了3點指針的畫線角度了。

          又又又有新問題了,比如現在我畫完了時針,然后我想畫分針,x軸已經在我畫時針的時候偏轉了,這時候肯定要讓x軸恢復到原來的模樣,我們才能繼續畫分針,否則畫出來的分針是不準的。這時候save和restore就派上用場了,save是把ctx當前的狀態打包壓入棧中,restore是取出棧頂的狀態并賦值給ctxsave可多次,但是restore取狀態的次數必須等于save次數

          懂得了上面所說,剩下畫刻度了,起始刻度的道理跟時分秒針道理一樣,只不過刻度是死的,不需要計算,只需要規則畫出60個小刻度,和12個大刻度就行

          const canvas=document.getElementById('canvas')
          const ctx=canvas.getContext('2d')
          ctx.translate(300, 300) // 設置中心點,此時300,300變成了坐標的0,0
          // 把狀態保存起來
          + ctx.save()
          // 畫大圓
          ctx.beginPath()
          // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結束角度)
          ctx.arc(0, 0, 100, 0, 2 * Math.PI)
          ctx.stroke() // 執行畫線段的操作
          ctx.closePath()
          // 畫小圓
          ctx.beginPath()
          ctx.arc(0, 0, 5, 0, 2 * Math.PI)
          ctx.stroke()
          ctx.closePath()
          ----- 新加代碼  ------
          // 獲取當前 時,分,秒
          let time=new Date()
          let hour=time.getHours() % 12
          let min=time.getMinutes()
          let sec=time.getSeconds()
          // 時針
          ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 * (min / 60) - Math.PI / 2)
          ctx.beginPath()
          // moveTo設置畫線起點
          ctx.moveTo(-10, 0)
          // lineTo設置畫線經過點
          ctx.lineTo(40, 0)
          // 設置線寬
          ctx.lineWidth=10
          ctx.stroke()
          ctx.closePath()
          // 恢復成上一次save的狀態
          ctx.restore()
          // 恢復完再保存一次
          ctx.save()
          // 分針
          ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 60 * (sec / 60) - Math.PI / 2)
          ctx.beginPath()
          ctx.moveTo(-10, 0)
          ctx.lineTo(60, 0)
          ctx.lineWidth=5
          ctx.strokeStyle='blue'
          ctx.stroke()
          ctx.closePath()
          ctx.restore()
          ctx.save()
          //秒針
          ctx.rotate(2 * Math.PI / 60 * sec -  - Math.PI / 2)
          ctx.beginPath()
          ctx.moveTo(-10, 0)
          ctx.lineTo(80, 0)
          ctx.strokeStyle='red'
          ctx.stroke()
          ctx.closePath()
          ctx.restore()
          ctx.save()
          // 繪制刻度,也是跟繪制時分秒針一樣,只不過刻度是死的
          ctx.lineWidth=1
          for (let i=0; i < 60; i++) {
              ctx.rotate(2 * Math.PI / 60)
              ctx.beginPath()
              ctx.moveTo(90, 0)
              ctx.lineTo(100, 0)
              // ctx.strokeStyle='red'
              ctx.stroke()
              ctx.closePath()
          }
          ctx.restore()
          ctx.save()
          ctx.lineWidth=5
          for (let i=0; i < 12; i++) {
              ctx.rotate(2 * Math.PI / 12)
              ctx.beginPath()
              ctx.moveTo(85, 0)
              ctx.lineTo(100, 0)
              ctx.stroke()
              ctx.closePath()
          }
          ctx.restore()
          復制代碼
          

          最后一步就是更新視圖,使時鐘轉動起來,第一想到的肯定是定時器setInterval,但是注意一個問題:每次更新視圖的時候都要把上一次的畫布清除,再開始畫新的視圖,不然就會出現千手觀音的景象

          附上最終代碼:

          const canvas=document.getElementById('canvas')
          const ctx=canvas.getContext('2d')
          setInterval(()=> {
              ctx.save()
              ctx.clearRect(0, 0, 600, 600)
              ctx.translate(300, 300) // 設置中心點,此時300,300變成了坐標的0,0
              ctx.save()
              // 畫大圓
              ctx.beginPath()
              // 畫圓線使用arc(中心點X,中心點Y,半徑,起始角度,結束角度)
              ctx.arc(0, 0, 100, 0, 2 * Math.PI)
              ctx.stroke() // 執行畫線段的操作
              ctx.closePath()
              // 畫小圓
              ctx.beginPath()
              ctx.arc(0, 0, 5, 0, 2 * Math.PI)
              ctx.stroke()
              ctx.closePath()
              // 獲取當前 時,分,秒
              let time=new Date()
              let hour=time.getHours() % 12
              let min=time.getMinutes()
              let sec=time.getSeconds()
              // 時針
              ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 * (min / 60) - Math.PI / 2)
              ctx.beginPath()
              // moveTo設置畫線起點
              ctx.moveTo(-10, 0)
              // lineTo設置畫線經過點
              ctx.lineTo(40, 0)
              // 設置線寬
              ctx.lineWidth=10
              ctx.stroke()
              ctx.closePath()
              ctx.restore()
              ctx.save()
              // 分針
              ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 60 * (sec / 60) - Math.PI / 2)
              ctx.beginPath()
              ctx.moveTo(-10, 0)
              ctx.lineTo(60, 0)
              ctx.lineWidth=5
              ctx.strokeStyle='blue'
              ctx.stroke()
              ctx.closePath()
              ctx.restore()
              ctx.save()
              //秒針
              ctx.rotate(2 * Math.PI / 60 * sec - Math.PI / 2)
              ctx.beginPath()
              ctx.moveTo(-10, 0)
              ctx.lineTo(80, 0)
              ctx.strokeStyle='red'
              ctx.stroke()
              ctx.closePath()
              ctx.restore()
              ctx.save()
              // 繪制刻度,也是跟繪制時分秒針一樣,只不過刻度是死的
              ctx.lineWidth=1
              for (let i=0; i < 60; i++) {
                  ctx.rotate(2 * Math.PI / 60)
                  ctx.beginPath()
                  ctx.moveTo(90, 0)
                  ctx.lineTo(100, 0)
                  // ctx.strokeStyle='red'
                  ctx.stroke()
                  ctx.closePath()
              }
              ctx.restore()
              ctx.save()
              ctx.lineWidth=5
              for (let i=0; i < 12; i++) {
                  ctx.rotate(2 * Math.PI / 12)
                  ctx.beginPath()
                  ctx.moveTo(85, 0)
                  ctx.lineTo(100, 0)
                  // ctx.strokeStyle='red'
                  ctx.stroke()
                  ctx.closePath()
              }
              ctx.restore()
              ctx.restore()
          }, 1000)
          復制代碼
          

          效果 very good啊:

          2. canvas實現刮刮卡

          小時候很多人都買過充值卡把,懂的都懂啊哈,用指甲刮開這層灰皮,就能看底下的答案了。

          思路是這樣的:

          • 1、底下答案是一個div,頂部灰皮是一個canvascanvas一開始蓋住div
          • 2、鼠標事件,點擊時并移動時,鼠標經過的路徑都畫圓形開路,并且設置globalCompositeOperationdestination-out,使鼠標經過的路徑都變成透明,一透明,自然就顯示出下方的答案信息。

          關于fill這個方法,其實是對標stroke的,fill是把圖形填充,stroke只是畫出邊框線

          // html
          <canvas id="canvas" width="400" height="100"></canvas>
          <div class="text">恭喜您獲得100w</div>
          <style>
                  * {
                      margin: 0;
                      padding: 0;
                  }
                  .text {
                      position: absolute;
                      left: 130px;
                      top: 35px;
                      z-index: -1;
                  }
          </style>
          // js
          const canvas=document.getElementById('canvas')
          const ctx=canvas.getContext('2d')
          // 填充的顏色
          ctx.fillStyle='darkgray'
          // 填充矩形 fillRect(起始X,起始Y,終點X,終點Y)
          ctx.fillRect(0, 0, 400, 100)
          ctx.fillStyle='#fff'
          // 繪制填充文字
          ctx.fillText('刮刮卡', 180, 50)
          let isDraw=false
          canvas.onmousedown=function () {
              isDraw=true
          }
          canvas.onmousemove=function (e) {
              if (!isDraw) return
              // 計算鼠標在canvas里的位置
              const x=e.pageX - canvas.offsetLeft
              const y=e.pageY - canvas.offsetTop
              // 設置globalCompositeOperation
              ctx.globalCompositeOperation='destination-out'
              // 畫圓
              ctx.arc(x, y, 10, 0, 2 * Math.PI)
              // 填充圓形
              ctx.fill()
          }
          canvas.onmouseup=function () {
              isDraw=false
          }
          復制代碼
          

          效果如下:

          3. canvas實現畫板和保存

          框架:使用vue + elementUI

          其實很簡單,難點有以下幾點:

          • 1、鼠標拖拽畫正方形和圓形
          • 2、畫完一個保存畫布,下次再畫的時候疊加
          • 3、保存圖片

          第一點,只需要計算出鼠標點擊的點坐標,以及鼠標的當前坐標,就可以計算了,矩形長寬計算:x - beginX, y - beginY,圓形則要利用勾股定理:Math.sqrt((x - beginX) * (x - beginX) + (y - beginY) * (y - beginY))

          第二點,則要利用canvas的getImageDataputImageData方法

          第三點,思路是將canvas生成圖片鏈接,并賦值給具有下載功能的a標簽,并主動點擊a標簽進行圖片下載

          看看效果吧:

          具體代碼我就不過多講解了,說難也不難,只要前面兩個項目理解了,這個項目很容易就懂了:

          <template>
            <div>
              <div style="margin-bottom: 10px; display: flex; align-items: center">
                <el-button @click="changeType('huabi')" type="primary">畫筆</el-button>
                <el-button @click="changeType('rect')" type="success">正方形</el-button>
                <el-button
                  @click="changeType('arc')"
                  type="warning"
                  style="margin-right: 10px"
                  >圓形</el-button
                >
                <div>顏色:</div>
                <el-color-picker v-model="color"></el-color-picker>
                <el-button @click="clear">清空</el-button>
                <el-button @click="saveImg">保存</el-button>
              </div>
              <canvas
                id="canvas"
                width="800"
                height="400"
                @mousedown="canvasDown"
                @mousemove="canvasMove"
                @mouseout="canvasUp"
                @mouseup="canvasUp"
              >
              </canvas>
            </div>
          </template>
          <script>
          export default {
            data() {
              return {
                type: "huabi",
                isDraw: false,
                canvasDom: null,
                ctx: null,
                beginX: 0,
                beginY: 0,
                color: "#000",
                imageData: null,
              };
            },
            mounted() {
              this.canvasDom=document.getElementById("canvas");
              this.ctx=this.canvasDom.getContext("2d");
            },
            methods: {
              changeType(type) {
                this.type=type;
              },
              canvasDown(e) {
                this.isDraw=true;
                const canvas=this.canvasDom;
                this.beginX=e.pageX - canvas.offsetLeft;
                this.beginY=e.pageY - canvas.offsetTop;
              },
              canvasMove(e) {
                if (!this.isDraw) return;
                const canvas=this.canvasDom;
                const ctx=this.ctx;
                const x=e.pageX - canvas.offsetLeft;
                const y=e.pageY - canvas.offsetTop;
                this[`${this.type}Fn`](ctx, x, y);
              },
              canvasUp() {
                this.imageData=this.ctx.getImageData(0, 0, 800, 400);
                this.isDraw=false;
              },
              huabiFn(ctx, x, y) {
                ctx.beginPath();
                ctx.arc(x, y, 5, 0, 2 * Math.PI);
                ctx.fillStyle=this.color;
                ctx.fill();
                ctx.closePath();
              },
              rectFn(ctx, x, y) {
                const beginX=this.beginX;
                const beginY=this.beginY;
                ctx.clearRect(0, 0, 800, 400);
                this.imageData && ctx.putImageData(this.imageData, 0, 0, 0, 0, 800, 400);
                ctx.beginPath();
                ctx.strokeStyle=this.color;
                ctx.rect(beginX, beginY, x - beginX, y - beginY);
                ctx.stroke();
                ctx.closePath();
              },
              arcFn(ctx, x, y) {
                const beginX=this.beginX;
                const beginY=this.beginY;
                this.isDraw && ctx.clearRect(0, 0, 800, 400);
                this.imageData && ctx.putImageData(this.imageData, 0, 0, 0, 0, 800, 400);
                ctx.beginPath();
                ctx.strokeStyle=this.color;
                ctx.arc(
                  beginX,
                  beginY,
                  Math.round(
                    Math.sqrt((x - beginX) * (x - beginX) + (y - beginY) * (y - beginY))
                  ),
                  0,
                  2 * Math.PI
                );
                ctx.stroke();
                ctx.closePath();
              },
              saveImg() {
                const url=this.canvasDom.toDataURL();
                const a=document.createElement("a");
                a.download="sunshine";
                a.href=url;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
              },
              clear() {
                  this.imageData=null
                  this.ctx.clearRect(0, 0, 800, 400)
              }
            },
          };
          </script>
          <style lang="scss" scoped>
          #canvas {
            border: 1px solid black;
          }
          </style>
          復制代碼
          

          結語

          公眾號:小何成長,佛系更文,都是自己曾經踩過的坑或者是學到的東西

          有興趣的小伙伴歡迎關注我哦,我是:何小玍。 大家一起進步鴨


          主站蜘蛛池模板: 无码欧精品亚洲日韩一区| 国产午夜精品一区二区三区小说| 色一情一乱一伦一区二区三欧美| 视频在线一区二区| 中文字幕在线不卡一区二区| 一区二区三区在线观看免费| 日韩精品无码一区二区中文字幕 | 熟女少妇精品一区二区| 午夜视频久久久久一区| 538国产精品一区二区在线| 精品视频一区二区三区| 一区二区三区电影网| 中文字幕久久久久一区| 中文字幕永久一区二区三区在线观看 | 国产99视频精品一区| 91在线看片一区国产| 狠狠综合久久AV一区二区三区| 一区二区三区在线免费| 视频一区二区三区人妻系列| 国产一区二区三区小向美奈子| 黑巨人与欧美精品一区| 亚洲爆乳精品无码一区二区 | 福利一区二区三区视频在线观看| 日韩AV在线不卡一区二区三区| 亚洲一本一道一区二区三区| 亚洲AV无码一区二区三区牛牛| 日韩高清国产一区在线| 日本午夜精品一区二区三区电影| 国产福利一区二区三区在线观看 | 精品人妻少妇一区二区| 精品人妻中文av一区二区三区| 中文字幕乱码亚洲精品一区| 国产精品无码一区二区三区不卡| 精品国产一区二区三区AV | 农村乱人伦一区二区| 亚洲精品伦理熟女国产一区二区 | 国产精品无码一区二区三区免费 | 中文字幕精品一区二区日本| 天美传媒一区二区三区| 内射白浆一区二区在线观看| 中文乱码字幕高清一区二区 |