整合營銷服務商

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

          免費咨詢熱線:

          HTML5(十)-Canvas 與 SVG 區別

          為一名前端攻城獅,Canvas 和 SVG 對于我們并不陌生,canvas 是 HTML5 提供的新元素,而 svg 存在的時間要比 canvas 長很多,svg 并不屬于 html,最初的 svg 是由 XML 定義的,在 html 5 中 canvas 與 svg 看著相似,其實不同。

          一、基本介紹

          Canvas

          • 通過 js 來繪制 2D圖形。
          • canvas 圖像單位是像素。
          • canvas 圖像繪制完畢之后,瀏覽器將不再關注它,如果位置發生變換,就需要重新繪制。

          SVG

          • svg 使用 XML 描述的2D圖像。
          • svg 是基于 xml 的,所以 svg 中繪制圖形還是使用的元素,js 給元素任意添加事件。
          • svg 繪制的圖像是一個對象,如果對象的屬性發生改變,瀏覽器將重新繪制圖形。

          二、SVG與Canvas比較

          1. svg 是一種矢量圖,而 canvas 依賴于分辨率。所以 svg 放大不會失真,但是 canvas 繪制的圖形會失真。
          2. svg 支持事件處理器,而 canvas 不支持事件處理器。
          3. svg 中的文字獨立于圖像,文字可保留,可編輯和可搜索,canvas 的文本渲染能力弱。
          4. canvas 適合圖像密集型的游戲,頻繁地重繪圖像,svg 繪制的復雜度高時減慢渲染的速度。
          5. canvas 繪制的圖形可以多種格式 (jpg、png) 保存圖片,但是 svg 繪制的只能以 .svg 格式保存,使用時可以引入 html 文件。
          6. canvas 適合開發游戲,svg 不適合游戲應用。

          二、如何應用

          2.1、功能上來說

          canvas 是一個畫布,繪制出來的圖形是位圖,因此 canvas 可以繪制圖片,在實際應用中,由于渲染性能高,所以大型游戲開發都用的 canvas 。除此之外,還有統計中常見的柱狀圖、餅圖、雷達圖等也使用的 canvas 。而 svg 繪制的是矢量圖,放大后不會失真,所以很適合做地圖。

          2.2、操作方面講

          canvas 繪制的圖形,只能給 canvas 整個畫布添加事件,而不能給某個圖形或文件添加事件處理器,但是 svg 支持事件綁定,如果需要添加帶有事件的動畫效果時,就需要選擇 svg。

          TML5 Canvas是HTML5新增的一個元素,它提供了一個可執行JavaScript腳本繪制圖形的區域。Canvas元素通過使用JavaScript API,可以在瀏覽器上繪制圖形、渲染動畫和實現交互效果等。

          使用原理:
          HTML5 Canvas通過使用JavaScript API在瀏覽器中創建一塊畫布(Canvas),然后可以使用腳本語言(通常是JavaScript)在畫布上繪制各種形狀、線條、圖像和文本等。Canvas使用像素渲染,可以直接操作像素數據,因此在性能方面相比其他圖形技術(如SVG)更具優勢。

          場景:
          HTML5 Canvas可以應用于各種需要圖形繪制、動畫渲染和交互效果的場景,例如:

          1. 游戲開發:Canvas可以用來開發2D或3D游戲,通過繪制游戲場景、角色和動畫等實現游戲效果。
          2. 數據可視化:Canvas可以用來繪制各種圖表和圖形,實現數據可視化效果。
          3. 圖像處理:Canvas可以對圖像進行像素級別的操作,實現圖像處理功能,例如濾鏡、裁剪和合成等。
          4. 實時視頻處理:Canvas可以結合WebRTC等技術實現實時視頻處理,例如在視頻通話中添加特效和濾鏡等。

          代碼示例:
          以下是一個簡單的HTML5 Canvas代碼示例,用于在畫布上繪制一個矩形和一個圓形:

          <!DOCTYPE html>  
          <html>  
              <head>  
               			<title>HTML5 Canvas示例</title>  
              </head>  
                <body>  
                     <canvas id="myCanvas" width="400" height="400"></canvas>  
                       <script>  
                           // 獲取Canvas元素和繪圖上下文  
                           var canvas = document.getElementById("myCanvas");  
                           var ctx = canvas.getContext("2d");  
                           // 繪制矩形  
                           ctx.fillStyle = "blue";  
                           ctx.fillRect(50, 50, 100, 100);  
                           // 繪制圓形  
                           ctx.beginPath();  
                           ctx.arc(200, 200, 50, 0, Math.PI * 2);  
                           ctx.fillStyle = "red";  
                           ctx.fill();  
                       </script>  
                </body>  
          </html>

          在上述代碼中,我們首先獲取了Canvas元素和繪圖上下文(Context),然后使用fillRect()方法繪制了一個藍色的矩形,使用arc()方法繪制了一個紅色的圓形。最后,我們使用fill()方法填充了圓形的顏色。

          SVG是構建XML樹的方式來達到繪制圖形的,canvas是通過調用相關的方法來繪制圖形的。

          區別:SVG繪制圖形,通過移除或者更改DOM方式來而使用canvas需要把圖片從新擦除。

          繪制的API在繪制上下文中定義。而不在畫布中定義。

          需要獲得上下文對象的時候,需要調用畫布的getContext方法,獲得繪畫的上下文。

          畫布元素和上下文,屬于兩個不同的對象,其中畫布元素為canvas畫布,而上下文對象為繪制需要的上下文。

          關于3D圖形,即,webGL 為封裝了基本的OPENGL,當調用webGL的時候,其瀏覽器會調用OpenGL相關的API

          繪制圓

          <!DOCTYPE html>
          <html lang="zh_CN" xmlns="http://www.w3.org/1999/html">
          <head>
           <meta charset="UTF-8">
           <title>Title</title>
          </head>
          <body>
          <div>第一個園</br>
           <canvas id="square" width="10" height="100">
           </canvas>
          </div>
          <div>
           第二個園
           <canvas id="circle" width="10" height="10">
           </canvas>
          </div>
          <script src="./js/index.js" charset="UTF-8"></script>
          </body>
          </html>
          // 獲取畫布元素
          let canvas = document.getElementById("square");
          // 獲取繪制2D元素上下文
          let context = canvas.getContext("2d");
          // 設置填充顏色為紅色
          context.fillStyle = "#f00";
          // 填充一個正方形
          context.fillRect(10,0,10,10);
          

          繪制線段,填充多邊形

          // 獲取畫布元素

          let canvas = document.getElementById("square");

          // 獲取繪制2D元素上下文

          let context = canvas.getContext("2d");

          // 開始一條路徑

          context.beginPath();

          // 從100,100 開始定義一條新的子路徑

          context.moveTo(100,100);

          // 從100 100 到 200 200 繪制一條線段

          context.lineTo(200,200);

          // 從200 200 到 100 200 繪制一條線段

          context.lineTo(100,200);

          // 從100 200 到 100 100 繪制一條路徑

          context.lineTo(100,100);

          // 繪制邊

          context.stroke();

          // 進行填充

          context.fill();

          繪制多邊形

          以五邊形為例子,

          var canvas = document.getElementById("square");
          var context = canvas.getContext("2d");
          // 繪制一個以100,100為中心,半徑為20的柜子N變形,每個定點均勻分布在圓角上,第一個定點放置在最上下
          // 偏轉角度為0
          // 開始定義一條子路徑
          context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
          // 計算兩個頂點之間夾角
          // 其中2π為一個園,除以邊數,得到需要旋轉的角度
          var delta = 2 * Math.PI/5;
          console.log(delta);
          // 循環剩余每個頂點
          var angle = 0;
          for(var i = 1; i < 5; i++){
           // 角度累加
           angle += delta;
           // 通過旋轉繪制下一個頂點,不斷的旋轉繪制
           context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
          }
          // 最后一個頂點和起點進行連接
          context.closePath();
          // 從新開始一條新路徑
          context.stroke();
          context.fill();
          

          同理,畫圓

          var canvas = document.getElementById("square");
          var context = canvas.getContext("2d");
          // 繪制一個以100,100為中心,半徑為20的柜子N變形,每個定點均勻分布在圓角上,第一個定點放置在最上下
          // 偏轉角度為0
          // 開始定義一條子路徑
          context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
          // 計算兩個頂點之間夾角
          // 其中2π為一個園,除以邊數,得到需要旋轉的角度
          var delta = 2 * Math.PI/500000;
          console.log(delta);
          // 循環剩余每個頂點
          var angle = 0;
          for(var i = 1; i < 500000; i++){
           // 角度累加
           angle += delta;
           // 通過旋轉繪制下一個頂點,不斷的旋轉繪制
           context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
          }
          // 最后一個頂點和起點進行連接
          context.closePath();
          // 從新開始一條新路徑
          context.stroke();
          context.fill();
          

          非零繞數原則

          要檢測一個點p是否在路徑內部,使用非零繞數原則,即,一條從點p出發沿著任意方向無限延伸,或者一直延伸到路徑所在的區域外某點的射線,現在從0開始初始化一個計數器,對穿過這條射線的路徑進行枚舉,每當一條路徑順時針方向穿過射線的時候,計數器加1,逆時針減1,最后,枚舉完所有路徑以后,如果計時器的值不是0,那么就認為p在路徑內,反過來,計數器的值為0,p在路徑外。

          js根據非零繞數原則確定那個在路徑內,那個在路徑外,用于進行填充。

          圖形屬性

          可以通過設置畫布上下文的fillStyle等屬性,設置圖形的屬性,例如對畫布上下文的fillStyle的屬性進行設置,即,可以設置出填充時的顏色,漸變,圖案等樣式。

          對于canvas來說,每次獲取上下文對象的時候,都會返回同一個上下文對象,即,上下文對象為單例的。

          還可以使用save方法,把當前的狀態,壓入已經保存的棧中,調用restore方法,把狀態進行恢復,即彈棧。

          畫布尺寸坐標

          畫布的默認的坐標系為左上角的坐標原點(0,0),右邊數值大,下數值大,使用浮點數指定坐標,但不會自動轉換為整數,會用反鋸齒的方式,模擬填充部分元素。

          畫布尺寸不能隨意改變,對任意屬性進行操作,都會清空整個畫布。

          坐標系變換

          每一個點的坐標都會映射到css像素上,css像素會映射到一個或多個設備像素。

          畫布中的特定操作,屬性使用默認坐標系。

          畫布還有當前變換矩陣。

          畫布還有當前變換矩陣,當前變換矩陣作為圖形狀態的一部分。矩陣定義了當前畫布的坐標系。

          畫布的操作會把該點映射到當前的坐標系中。

          坐標變換

          當調用c.translate(dx,dy)方法的時候,會進行如下變換

          translate會進行坐標的上下移動

          x' = x + dy;
          y' = y + dy;
          

          縮放

          如要進行縮放,進行的是如下的變換

          x' = sx * x;
          y' = sy * y;
          

          進行旋轉操作,進行的是如下變換

          x' = x * cos(a) - y * sin(a);
          y' = y * cos(a) - x * sin(a);
          

          如果要先變換再伸縮,進行如下變換

          需要先把現有坐標系映射成為坐標系中的點x’, y’ 然后再變換到x‘’ , y‘’

          x'' = sx*x + dx;
          y'' = sy*y + dy;
          

          如果變換順序相反進行如下變換

          x'' = sx*(x + dx);
          y'' = sy*(y + dy);
          

          這種變換稱為仿射變換,并且仿射變換會修改點的距離和線段間的夾角。對于平行線來說,仿射變換也會保持平行。仿射變換用6個參數描述成為如下表述

          x' = ax + cy + e;
          y' = bx + dy + f;
          

          通過傳入參數實現仿射變換

          對于坐標變換來說,除非進行刷新,否則,已經繪制的圖形,不會進行消失,所有的變換,都不能對已經繪制的圖形進行更改。栗子如下

          var canvas = document.getElementById("square");
          var context = canvas.getContext("2d");
          // 通過坐標變換實現科赫雪花
          // 開始一條路徑
          context.beginPath();
          // 開始繪制子路徑
          context.moveTo(100,100);
          // 繼續繪制
          context.lineTo(200,200);
          // 繼續繪制
          context.lineTo(200,200);
          // 進行繪制邊
          context.stroke();
          context.translate(200,200);
          // 開始一條路徑
          context.beginPath();
          // 開始繪制子路徑
          context.moveTo(100,100);
          // 繼續繪制
          context.lineTo(200,200);
          // 繼續繪制
          context.lineTo(200,200);
          // 進行繪制邊
          context.stroke();
          

          已經繪制的圖形不會進行改變,改變的是已經繪制的圖形

          科赫雪花

          var canvas = document.getElementById("square");

          var context = canvas.getContext("2d");

          // 通過坐標變換實現科赫雪花

          // 當前狀態入棧

          function leg(n) {

          // 保存狀態

          context.save();

          // 遞歸畫

          if(n == 0){

          context.lineTo(50, 0);

          }else{

          // 定義為v字型

          context.scale(1/2,1/2);

          // 遞歸第一條

          context.rotate(60 * (Math.PI / 180));

          leg(n - 1);

          context.rotate(-120 * (Math.PI / 180));

          leg(n - 1);

          }

          // 坐標恢復變換

          context.restore();

          // 恢復下一個坐標為0,0

          context.translate(50, 0);

          }

          context.save();

          context.moveTo(50, 50);

          // 繪制第一條

          leg(1);

          context.stroke();

          繪制填充曲線

          繪制一些常見的圖形

          var canvas = document.getElementById("square");
          var context = canvas.getContext("2d");
          // 工具函數,角度轉弧度
          function rads(x) {
           return Math.PI * x / 180;
          }
          // 繪制園
          context.beginPath();
          context.arc(100,100,40, 0, rads(360), false);
          context.stroke();
          context.fill();
          

          同理繪制貝塞爾曲線也是同理。

          顏色,透明度,漸變,圖案

          繪制一個漸變

          需要使用createLinearGradient獲取一個進行漸變的上下文,對這個上下文進行處理。然后其顏色設置為這個漸變的上下文,即,fillStyle屬性。

          線段繪制

          封頂

          對于線段,有三種封頂方式,即,butt,square,round

          在繪制圖形以后,會參數尖角,圓角,平角,三種。

          lineCap屬性

          文本

          和css類似,基線問題。

          裁剪

          直接調動clip即可,當前路徑也會被裁剪進入,路徑外的統統不會顯示。

          陰影

          設置shadow屬性即可

          圖片

          畫布API支持位圖圖片,同時也支持canvas導出成為圖片。

          // 創建一個img元素
          let img = document.createElement("img");
          // 設置src屬性
          img.src = canvas.toDataURL();
          // 追加到文檔后面
          document.body.appendChild(img);
          

          合成

          一些api不在闡述

          像素操作

          調用getImageDate方法返回ImageDate對象

          使用createImageDate()可以創建像素容器

          進行動態模糊先獲取像素的ImageDate對象,然后再獲取該對象的data屬性,該data為一個數組。為一個維數組。每四個元素代表紅色分量,綠色分量,藍色分量,透明度分量。(Alpha分量)

          其色素直為0-1,即,數組元素中保存的數組為色素值。

          每四個每四個元素遍歷。然后把其色素值的1/ n + 上一個色塊的m/n 然后賦值給新的色塊,代碼如下

          // row為行數
          for(var row = 0; row < height; row++){
           // 獲得每行第二個元素的偏移量,其中width為行的色素塊。
           var i = row * width * 4;
           // 每4個的色素值進行處理
           for(var col = 1; col < width; col++, i+=4){
           // 對紅色分量處理
           data[i] = (data[i] + data[i - 4] * m) / n;
           // 對綠色分量處理
           data[i + 1] = (data[i + 1] + data[i + 1 - 4] * m) / n;
           // 對藍色分量處理
           data[i + 2] = (data[i + 2] + data[i + 2 - 4] * m) / n;
           // 對透明度分量處理
           data[i + 3] = (data[i + 3] + data[i + 3 - 4] * m) / n;
           }
          }
          

          然后把其色素塊進行復制回去即可。

          其中每個像素占據一個字節,一個四個字節。

          命中檢測

          isPointInPath方法用來確定一個點是否落在當前路徑中。

          即命中檢測。

          命中檢測可以和鼠標事件相互轉化

          但是坐標需要進行轉換。


          主站蜘蛛池模板: 老熟妇高潮一区二区三区| 国产一区二区在线观看麻豆| 亚洲成在人天堂一区二区| 国产一区二区精品久久岳| 久久久国产一区二区三区| 国产AV一区二区三区无码野战| www亚洲精品少妇裸乳一区二区| 国产美女av在线一区| 亚洲AV无码一区二区二三区软件| 无码人妻久久一区二区三区免费 | 亚洲日韩AV一区二区三区四区| 99精品一区二区三区无码吞精 | 在线观看免费视频一区| 天堂国产一区二区三区| 海角国精产品一区一区三区糖心| 香蕉久久AⅤ一区二区三区| 亚洲熟女少妇一区二区| 精品人妻无码一区二区三区蜜桃一| 国产精品电影一区二区三区| 亲子乱AV视频一区二区| 中文乱码人妻系列一区二区| 亚洲av成人一区二区三区在线观看| 国产精品无码一区二区三区电影| 亚洲变态另类一区二区三区| 国产精品99无码一区二区| 中文字幕一区二区三区视频在线 | 久久精品道一区二区三区| 国产福利视频一区二区| 中文字幕av无码一区二区三区电影| 精品乱码一区二区三区在线| 日韩一区二区在线观看| 一区二区三区免费高清视频| 中文字幕在线一区二区三区| 中文字幕久久亚洲一区| 久久国产精品亚洲一区二区| 精品一区二区三区免费毛片爱 | 综合无码一区二区三区四区五区| 国产微拍精品一区二区| 精品久久久久久中文字幕一区| 在线精品自拍亚洲第一区| 国产成人久久精品麻豆一区|