色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

HTML5 Canvas繪制圖形從入門到精通

瀏覽:317日期:2022-06-03 08:42:16
目錄
  • 一、canvas 簡(jiǎn)介
  • 二、Canvas基本使用
    • 2.1 <canvas> 元素
    • 2.2 渲染上下文(Thre Rending Context)
    • 2.3 檢測(cè)支持性
    • 2.4 一個(gè)簡(jiǎn)單的例子
  • 三、繪制形狀
    • 3.1 柵格 (grid) 和坐標(biāo)空間
    • 3.2 繪制矩形
  • 四、繪制路徑 (path)
    • 4.1 繪制線段
    • 4.2 繪制三角形邊框
    • 4.3 填充三角形
    • 4.4 繪制圓弧
    • 4.5 繪制貝塞爾曲線
  • 五、添加樣式和顏色
    • fillStyle
    • strokeStyle
    • Transparency(透明度)
    • 1、line style
    • 2. lineCap = type
    • 3. lineJoin = type
    • 4. 虛線
  • 六、繪制文本
    • 繪制文本的兩個(gè)方法
    • 給文本添加樣式
  • 七、繪制圖片
    • 7.1 由零開始創(chuàng)建圖片
    • 7.2 繪制 img 標(biāo)簽元素中的圖片
    • 7.3 縮放圖片
    • 7.4 切片(slice)
  • 八、狀態(tài)的保存和恢復(fù)
    • 九、變形
      • 9.1 translate
      • 9.2 rotate
      • 9.3 scale
      • 9.4 transform (變形矩陣)
    • 十、合成
      • 十一、裁剪路徑
        • 十二、動(dòng)畫
          • 動(dòng)畫的基本步驟
          • 控制動(dòng)畫

        Canvas API(畫布)是在HTML5中新增的標(biāo)簽用于在網(wǎng)頁(yè)實(shí)時(shí)生成圖像,并且可以操作圖像內(nèi)容,基本上它是一個(gè)可以用JavaScript操作的位圖(bitmap)。Canvas 對(duì)象表示一個(gè) HTML 畫布元素 -<canvas>。它沒有自己的行為,但是定義了一個(gè) API 支持腳本化客戶端繪圖操作。它可以用來(lái)制作照片集或者制作簡(jiǎn)單(也不是那么簡(jiǎn)單)的動(dòng)畫,甚至可以進(jìn)行實(shí)時(shí)視頻處理和渲染。

        一、canvas 簡(jiǎn)介

        <canvas> 標(biāo)記由 Apple 在 Safari 1.3 Web 瀏覽器中引入。<canvas> 標(biāo)記和 SVG以及 VML 之間的一個(gè)重要的不同是,<canvas> 有一個(gè)基于 JavaScript 的繪圖 API,而 SVG 和 VML 使用一個(gè) XML 文檔來(lái)描述繪圖。

        Mozilla 程序從 Gecko 1.8 (Firefox 1.5) 開始支持 <canvas>, Internet Explorer 從 IE9 開始 <canvas> 。Chrome 和 Opera 9+ 也支持 <canvas>

        二、Canvas基本使用

        <canvas id="tutorial" width="300" height="300"></canvas>

        2.1 <canvas> 元素

        ?<canvas> 看起來(lái)和 <img> 標(biāo)簽一樣,只是 <canvas> 只有兩個(gè)可選的屬性 width、heigth 屬性,而沒有 src、alt 屬性。

        ?如果不給 <canvas> 設(shè)置 widht、height 屬性時(shí),則默認(rèn) width為300、height 為 150,單位都是 px。也可以使用 css 屬性來(lái)設(shè)置寬高,但是如寬高屬性和初始比例不一致,他會(huì)出現(xiàn)扭曲。所以,建議永遠(yuǎn)不要使用 css 屬性來(lái)設(shè)置 <canvas> 的寬高。

        替換內(nèi)容

        ?由于某些較老的瀏覽器(尤其是 IE9 之前的 IE 瀏覽器)或者瀏覽器不支持 HTML 元素 <canvas>,在這些瀏覽器上你應(yīng)該總是能展示替代內(nèi)容。

        ?支持 <canvas> 的瀏覽器會(huì)只渲染 <canvas> 標(biāo)簽,而忽略其中的替代內(nèi)容。不支持 <canvas> 的瀏覽器則 會(huì)直接渲染替代內(nèi)容。

        用文本替換:

        <canvas>
            你的瀏覽器不支持 canvas,請(qǐng)升級(jí)你的瀏覽器。
        </canvas>

        <img> 替換:

        <canvas>
            <img decoding="async" src="./美女.jpg"> 
        </canvas>

        結(jié)束標(biāo)簽 </canvas> 不可省略。

        <img> 元素不同,<canvas> 元素需要結(jié)束標(biāo)簽(</canvas>)。如果結(jié)束標(biāo)簽不存在,則文檔的其余部分會(huì)被認(rèn)為是替代內(nèi)容,將不會(huì)顯示出來(lái)。

        2.2 渲染上下文(Thre Rending Context)

        ?<canvas> 會(huì)創(chuàng)建一個(gè)固定大小的畫布,會(huì)公開一個(gè)或多個(gè)渲染上下文(畫筆),使用渲染上下文來(lái)繪制和處理要展示的內(nèi)容。

        ? 我們重點(diǎn)研究 2D 渲染上下文。 其他的上下文我們暫不研究,比如, WebGL 使用了基于 OpenGL ES的3D 上下文 ("experimental-webgl") 。

        var canvas = document.getElementById("tutorial");
        //獲得 2d 上下文對(duì)象
        var ctx = canvas.getContext("2d");

        2.3 檢測(cè)支持性

        var canvas = document.getElementById("tutorial");
        
        if (canvas.getContext){
          var ctx = canvas.getContext("2d");
          // drawing code here
        } else {
          // canvas-unsupported code here
        }

        2.4 一個(gè)簡(jiǎn)單的例子

        以下實(shí)例繪制兩個(gè)長(zhǎng)方形:

        <canvas id="tutorial" width="300" height="300"></canvas>
        <script type="text/javascript">
        function draw(){
            var canvas = document.getElementById("tutorial");
            if(!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.fillStyle = "rgb(200,0,0)";
              //繪制矩形
            ctx.fillRect (10, 10, 55, 50);
         
            ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
            ctx.fillRect (30, 30, 55, 50);
        }
        draw();
        </script>
        

        三、繪制形狀

        3.1 柵格 (grid) 和坐標(biāo)空間

        ?如下圖所示,canvas 元素默認(rèn)被網(wǎng)格所覆蓋。通常來(lái)說(shuō)網(wǎng)格中的一個(gè)單元相當(dāng)于 canvas 元素中的一像素。柵格的起點(diǎn)為左上角,坐標(biāo)為 (0,0) 。所有元素的位置都相對(duì)于原點(diǎn)來(lái)定位。所以圖中藍(lán)色方形左上角的坐標(biāo)為距離左邊(X 軸)x 像素,距離上邊(Y 軸)y 像素,坐標(biāo)為 (x,y)。

        ?后面我們會(huì)涉及到坐標(biāo)原點(diǎn)的平移、網(wǎng)格的旋轉(zhuǎn)以及縮放等。

        3.2 繪制矩形

        ?<canvas> 只支持一種原生的圖形繪制:矩形。所有其他圖形都至少需要生成一種路徑 (path)。不過(guò),我們擁有眾多路徑生成的方法讓復(fù)雜圖形的繪制成為了可能。

        canvast 提供了三種方法繪制矩形:

        • 1、fillRect(x, y, width, height):繪制一個(gè)填充的矩形。
        • 2、strokeRect(x, y, width, height):繪制一個(gè)矩形的邊框。
        • 3、clearRect(x, y, widh, height):清除指定的矩形區(qū)域,然后這塊區(qū)域會(huì)變的完全透明。

        說(shuō)明:這 3 個(gè)方法具有相同的參數(shù)。

        • x, y:指的是矩形的左上角的坐標(biāo)。(相對(duì)于canvas的坐標(biāo)原點(diǎn))
        • width, height:指的是繪制的矩形的寬和高。

        function draw(){ var canvas = document.getElementById('tutorial'); if(!canvas.getContext) return; var ctx = canvas.getContext("2d"); ctx.fillRect(10, 10, 100, 50); // 繪制矩形,填充的默認(rèn)顏色為黑色 ctx.strokeRect(10, 70, 100, 50); // 繪制矩形邊框 } draw();

        ctx.clearRect(15, 15, 50, 25);

        四、繪制路徑 (path)

        圖形的基本元素是路徑。

        路徑是通過(guò)不同顏色和寬度的線段或曲線相連形成的不同形狀的點(diǎn)的集合。

        一個(gè)路徑,甚至一個(gè)子路徑,都是閉合的。

        使用路徑繪制圖形需要一些額外的步驟:

        • 創(chuàng)建路徑起始點(diǎn)
        • 調(diào)用繪制方法去繪制出路徑
        • 把路徑封閉
        • 一旦路徑生成,通過(guò)描邊或填充路徑區(qū)域來(lái)渲染圖形。

        下面是需要用到的方法:

        • beginPath()

          新建一條路徑,路徑一旦創(chuàng)建成功,圖形繪制命令被指向到路徑上生成路徑

        • moveTo(x, y)

          把畫筆移動(dòng)到指定的坐標(biāo)(x, y)。相當(dāng)于設(shè)置路徑的起始點(diǎn)坐標(biāo)。

        • closePath()

          閉合路徑之后,圖形繪制命令又重新指向到上下文中

        • stroke()

          通過(guò)線條來(lái)繪制圖形輪廓

        • fill()

          通過(guò)填充路徑的內(nèi)容區(qū)域生成實(shí)心的圖形

        4.1 繪制線段

        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath(); //新建一條path
            ctx.moveTo(50, 50); //把畫筆移動(dòng)到指定的坐標(biāo)
            ctx.lineTo(200, 50);  //繪制一條從當(dāng)前位置到指定坐標(biāo)(200, 50)的直線.
            //閉合路徑。會(huì)拉一條從當(dāng)前點(diǎn)到path起始點(diǎn)的直線。如果當(dāng)前點(diǎn)與起始點(diǎn)重合,則什么都不做
            ctx.closePath();
            ctx.stroke(); //繪制路徑。
        }
        draw();

        4.2 繪制三角形邊框

        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(50, 50);
            ctx.lineTo(200, 50);
            ctx.lineTo(200, 200);
              ctx.closePath(); //雖然我們只繪制了兩條線段,但是closePath會(huì)closePath,仍然是一個(gè)3角形
            ctx.stroke(); //描邊。stroke不會(huì)自動(dòng)closePath()
        }
        draw();

        4.3 填充三角形

        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(50, 50);
            ctx.lineTo(200, 50);
            ctx.lineTo(200, 200);
           
            ctx.fill(); //填充閉合區(qū)域。如果path沒有閉合,則fill()會(huì)自動(dòng)閉合路徑。
        }
        draw();

        4.4 繪制圓弧

        有兩個(gè)方法可以繪制圓?。?/p>

        1、arc(x, y, r, startAngle, endAngle, anticlockwise): 以(x, y) 為圓心,以r 為半徑,從 startAngle 弧度開始到endAngle弧度結(jié)束。anticlosewise 是布爾值,true 表示逆時(shí)針,false 表示順時(shí)針(默認(rèn)是順時(shí)針)。

        注意:

        • 這里的度數(shù)都是弧度。

        • 0 弧度是指的 x 軸正方向。

          radians=(Math.PI/180)*degrees   //角度轉(zhuǎn)換成弧度

        2、arcTo(x1, y1, x2, y2, radius): 根據(jù)給定的控制點(diǎn)和半徑畫一段圓弧,最后再以直線連接兩個(gè)控制點(diǎn)。

        圓弧案例 

        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(50, 50);
            ctx.lineTo(200, 50);
            ctx.lineTo(200, 200);
           
            ctx.fill(); //填充閉合區(qū)域。如果path沒有閉合,則fill()會(huì)自動(dòng)閉合路徑。
        }
        draw();

        arcTo 方法的說(shuō)明:

        這個(gè)方法可以這樣理解。繪制的弧形是由兩條切線所決定。

        第 1 條切線:起始點(diǎn)和控制點(diǎn)1決定的直線。

        第 2 條切線:控制點(diǎn)1 和控制點(diǎn)2決定的直線。

        ?其實(shí)繪制的圓弧就是與這兩條直線相切的圓弧。

        4.5 繪制貝塞爾曲線

        4.5.1 什么是貝塞爾曲線

        貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。一般的矢量圖形軟件通過(guò)它來(lái)精確畫出曲線,貝茲曲線由線段與節(jié)點(diǎn)組成,節(jié)點(diǎn)是可拖動(dòng)的支點(diǎn),線段像可伸縮的皮筋,我們?cè)诶L圖工具上看到的鋼筆工具就是來(lái)做這種矢量曲線的。

        貝塞爾曲線是計(jì)算機(jī)圖形學(xué)中相當(dāng)重要的參數(shù)曲線,在一些比較成熟的位圖軟件中也有貝塞爾曲線工具如 PhotoShop 等。在 Flash4 中還沒有完整的曲線工具,而在 Flash5 里面已經(jīng)提供出貝塞爾曲線工具。

        4.5.2 繪制貝塞爾曲線

        一次貝塞爾曲線其實(shí)是一條直線

        繪制二次貝塞爾曲線:

        quadraticCurveTo(cp1x, cp1y, x, y)

        說(shuō)明:

        • ? 參數(shù) 1 和 2:控制點(diǎn)坐標(biāo)
        • ? 參數(shù) 3 和 4:結(jié)束點(diǎn)坐標(biāo)
        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(10, 200); //起始點(diǎn)
            var cp1x = 40, cp1y = 100;  //控制點(diǎn)
            var x = 200, y = 200; // 結(jié)束點(diǎn)
            //繪制二次貝塞爾曲線
            ctx.quadraticCurveTo(cp1x, cp1y, x, y);
            ctx.stroke();
         
            ctx.beginPath();
            ctx.rect(10, 200, 10, 10);
            ctx.rect(cp1x, cp1y, 10, 10);
            ctx.rect(x, y, 10, 10);
            ctx.fill();
         
        }
        draw();

        繪制三次貝塞爾曲線:

        bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

        說(shuō)明:

        • ? 參數(shù) 1 和 2:控制點(diǎn) 1 的坐標(biāo)
        • ? 參數(shù) 3 和 4:控制點(diǎn) 2 的坐標(biāo)
        • ? 參數(shù) 5 和 6:結(jié)束點(diǎn)的坐標(biāo)
        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(40, 200); //起始點(diǎn)
            var cp1x = 20, cp1y = 100;  //控制點(diǎn)1
            var cp2x = 100, cp2y = 120;  //控制點(diǎn)2
            var x = 200, y = 200; // 結(jié)束點(diǎn)
            //繪制二次貝塞爾曲線
            ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
            ctx.stroke();
         
            ctx.beginPath();
            ctx.rect(40, 200, 10, 10);
            ctx.rect(cp1x, cp1y, 10, 10);
            ctx.rect(cp2x, cp2y, 10, 10);
            ctx.rect(x, y, 10, 10);
            ctx.fill();
         
        }
        draw();

        五、添加樣式和顏色

        ? 在前面的繪制矩形章節(jié)中,只用到了默認(rèn)的線條和顏色。

        ? 如果想要給圖形上色,有兩個(gè)重要的屬性可以做到。

        • fillStyle = color 設(shè)置圖形的填充顏色

        • strokeStyle = color 設(shè)置圖形輪廓的顏色

        備注:

        • 1. color 可以是表示 css 顏色值的字符串、漸變對(duì)象或者圖案對(duì)象。
        • 2. 默認(rèn)情況下,線條和填充顏色都是黑色。
        • 3. 一旦您設(shè)置了 strokeStyle 或者 fillStyle 的值,那么這個(gè)新值就會(huì)成為新繪制的圖形的默認(rèn)值。如果你要給每個(gè)圖形上不同的顏色,你需要重新設(shè)置 fillStyle 或 strokeStyle 的值。

        fillStyle

        function draw(){
          var canvas = document.getElementById("tutorial");
          if (!canvas.getContext) return;
          var ctx = canvas.getContext("2d");
          for (var i = 0; i < 6; i++){
            for (var j = 0; j < 6; j++){
              ctx.fillStyle = "rgb(" + Math.floor(255 - 42.5 * i) + "," +
        Math.floor(255 - 42.5 * j) + ",0)";
              ctx.fillRect(j * 50, i * 50, 50, 50);
            }
          }
        }
        draw();

        strokeStyle

        function draw(){
            var canvas = document.getElementById("tutorial");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
            for (var i = 0; i < 6; i++){
        for (var j = 0; j < 6; j++){
            ctx.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
            ctx.strokeRect(j * 50, i * 50, 40, 40);
        }
            }
        }
        draw();
        /**
         返回隨機(jī)的 [from, to] 之間的整數(shù)(包括from,也包括to)
         */
        function randomInt(from, to){
            return parseInt(Math.random() * (to - from + 1) + from);
        }

        Transparency(透明度)

        globalAlpha = transparencyValue: 這個(gè)屬性影響到 canvas 里所有圖形的透明度,有效的值范圍是 0.0 (完全透明)到 1.0(完全不透明),默認(rèn)是 1.0。

        ? globalAlpha 屬性在需要繪制大量擁有相同透明度的圖形時(shí)候相當(dāng)高效。不過(guò),我認(rèn)為使用rgba()設(shè)置透明度更加好一些。

        1、line style

        線寬。只能是正值。默認(rèn)是 1.0。

        起始點(diǎn)和終點(diǎn)的連線為中心,上下各占線寬的一半

        ctx.beginPath();
        ctx.moveTo(10, 10);
        ctx.lineTo(100, 10);
        ctx.lineWidth = 10;
        ctx.stroke();
         
        ctx.beginPath();
        ctx.moveTo(110, 10);
        ctx.lineTo(160, 10)
        ctx.lineWidth = 20;
        ctx.stroke()

        2. lineCap = type

        線條末端樣式。

        共有 3 個(gè)值:

        • butt:線段末端以方形結(jié)束

        • round:線段末端以圓形結(jié)束

        • square:線段末端以方形結(jié)束,但是增加了一個(gè)寬度和線段相同,高度是線段厚度一半的矩形區(qū)域。

          var lineCaps = ["butt", "round", "square"];
           
          for (var i = 0; i < 3; i++){
              ctx.beginPath();
              ctx.moveTo(20 + 30 * i, 30);
              ctx.lineTo(20 + 30 * i, 100);
              ctx.lineWidth = 20;
              ctx.lineCap = lineCaps[i];
              ctx.stroke();
          }
           
          ctx.beginPath();
          ctx.moveTo(0, 30);
          ctx.lineTo(300, 30);
           
          ctx.moveTo(0, 100);
          ctx.lineTo(300, 100)
           
          ctx.strokeStyle = "red";
          ctx.lineWidth = 1;
          ctx.stroke();

          3. lineJoin = type

          同一個(gè) path 內(nèi),設(shè)定線條與線條間接合處的樣式。

          共有 3 個(gè)值 round, bevelmiter

        • round 通過(guò)填充一個(gè)額外的,圓心在相連部分末端的扇形,繪制拐角的形狀。 圓角的半徑是線段的寬度。

        • bevel 在相連部分的末端填充一個(gè)額外的以三角形為底的區(qū)域, 每個(gè)部分都有各自獨(dú)立的矩形拐角。

        • miter(默認(rèn)) 通過(guò)延伸相連部分的外邊緣,使其相交于一點(diǎn),形成一個(gè)額外的菱形區(qū)域。

        • function draw(){
              var canvas = document.getElementById("tutorial");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
           
              var lineJoin = ["round", "bevel", "miter"];
              ctx.lineWidth = 20;
           
              for (var i = 0; i < lineJoin.length; i++){
          ctx.lineJoin = lineJoin[i];
          ctx.beginPath();
          ctx.moveTo(50, 50 + i * 50);
          ctx.lineTo(100, 100 + i * 50);
          ctx.lineTo(150, 50 + i * 50);
          ctx.lineTo(200, 100 + i * 50);
          ctx.lineTo(250, 50 + i * 50);
          ctx.stroke();
              }
           
          }
          draw();
        • 4. 虛線

          setLineDash 方法和 lineDashOffset 屬性來(lái)制定虛線樣式。 setLineDash 方法接受一個(gè)數(shù)組,來(lái)指定線段與間隙的交替;lineDashOffset屬性設(shè)置起始偏移量。

          function draw(){
              var canvas = document.getElementById("tutorial");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
           
              ctx.setLineDash([20, 5]);  // [實(shí)線長(zhǎng)度, 間隙長(zhǎng)度]
              ctx.lineDashOffset = -0;
              ctx.strokeRect(50, 50, 210, 210);
          }
          draw();

          備注: getLineDash() 返回一個(gè)包含當(dāng)前虛線樣式,長(zhǎng)度為非負(fù)偶數(shù)的數(shù)組。

          六、繪制文本

          繪制文本的兩個(gè)方法

          canvas 提供了兩種方法來(lái)渲染文本:

          round 通過(guò)填充一個(gè)額外的,圓心在相連部分末端的扇形,繪制拐角的形狀。 圓角的半徑是線段的寬度。

          bevel 在相連部分的末端填充一個(gè)額外的以三角形為底的區(qū)域, 每個(gè)部分都有各自獨(dú)立的矩形拐角。

          miter(默認(rèn)) 通過(guò)延伸相連部分的外邊緣,使其相交于一點(diǎn),形成一個(gè)額外的菱形區(qū)域。

          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial");
              if (!canvas.getContext) return;
              ctx = canvas.getContext("2d");
              ctx.font = "100px sans-serif"
              ctx.fillText("天若有情", 10, 100);
              ctx.strokeText("天若有情", 10, 200)
          }
          draw();

          給文本添加樣式

        • font = value 當(dāng)前我們用來(lái)繪制文本的樣式。這個(gè)字符串使用和 CSS font 屬性相同的語(yǔ)法。 默認(rèn)的字體是 10px sans-serif

        • textAlign = value 文本對(duì)齊選項(xiàng)。 可選的值包括:start, end, left, right or center。 默認(rèn)值是 start。

        • textBaseline = value 基線對(duì)齊選項(xiàng),可選的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默認(rèn)值是 alphabetic。。

        • direction = value 文本方向。可能的值包括:ltr, rtl, inherit。默認(rèn)值是 inherit。

        • 七、繪制圖片

          ? 我們也可以在 canvas 上直接繪制圖片。

          7.1 由零開始創(chuàng)建圖片

          var img = new Image();   // 創(chuàng)建一個(gè)<img>元素
          img.src = "myImage.png"; // 設(shè)置圖片源地址

          腳本執(zhí)行后圖片開始裝載。

          繪制 img

          // 參數(shù) 1:要繪制的 img  
          // 參數(shù) 2、3:繪制的 img 在 canvas 中的坐標(biāo)
          ctx.drawImage(img,0,0);

          注意:考慮到圖片是從網(wǎng)絡(luò)加載,如果 drawImage 的時(shí)候圖片還沒有完全加載完成,則什么都不做,個(gè)別瀏覽器會(huì)拋異常。所以我們應(yīng)該保證在 img 繪制完成之后再 drawImage

          var img = new Image();   // 創(chuàng)建img元素
          img.onload = function(){
              ctx.drawImage(img, 0, 0)
          }
          img.src = "myImage.png"; // 設(shè)置圖片源地址

          7.2 繪制 img 標(biāo)簽元素中的圖片

          ?img 可以 new 也可以來(lái)源于我們頁(yè)面的 <img>標(biāo)簽。

          <img decoding="async" src="./美女.jpg" width="300"><br>
          <canvas id="tutorial" width="600" height="400"></canvas>
          function draw(){
              var canvas = document.getElementById("tutorial");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
              var img = document.querySelector("img");
              ctx.drawImage(img, 0, 0);
          }
          document.querySelector("img").onclick = function (){
              draw();
          }

          7.3 縮放圖片

          drawImage() 也可以再添加兩個(gè)參數(shù):

          drawImage(image, x, y, width, height)

          ?這個(gè)方法多了 2 個(gè)參數(shù):widthheight,這兩個(gè)參數(shù)用來(lái)控制 當(dāng)像 canvas 畫入時(shí)應(yīng)該縮放的大小。

          ctx.drawImage(img, 0, 0, 400, 200)

          7.4 切片(slice)

          drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

          第一個(gè)參數(shù)和其它的是相同的,都是一個(gè)圖像或者另一個(gè) canvas 的引用。

          其他 8 個(gè)參數(shù):

          前 4 個(gè)是定義圖像源的切片位置和大小,后 4 個(gè)則是定義切片的目標(biāo)顯示位置和大小。

          八、狀態(tài)的保存和恢復(fù)

          Saving and restoring state 是繪制復(fù)雜圖形時(shí)必不可少的操作。

          save()restore()

          saverestore 方法是用來(lái)保存和恢復(fù) canvas 狀態(tài)的,都沒有參數(shù)。

          ?Canvas 的狀態(tài)就是當(dāng)前畫面應(yīng)用的所有樣式和變形的一個(gè)快照。

          1、關(guān)于 save() :Canvas狀態(tài)存儲(chǔ)在棧中,每當(dāng)save()方法被調(diào)用后,當(dāng)前的狀態(tài)就被推送到棧中保存。

          一個(gè)繪畫狀態(tài)包括:

        • 當(dāng)前應(yīng)用的變形(即移動(dòng),旋轉(zhuǎn)和縮放)

        • strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation 的值

        • 當(dāng)前的裁切路徑(clipping path

          可以調(diào)用任意多次 save方法(類似數(shù)組的 push())。

        • 可以調(diào)用任意多次 save方法(類似數(shù)組的push())。

        • 2、關(guān)于restore():每一次調(diào)用 restore 方法,上一個(gè)保存的狀態(tài)就從棧中彈出,所有設(shè)定都恢復(fù)(類似數(shù)組的 pop())。

          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
           
              ctx.fillRect(0, 0, 150, 150);   // 使用默認(rèn)設(shè)置繪制一個(gè)矩形
              ctx.save();  // 保存默認(rèn)狀態(tài)
           
              ctx.fillStyle = "red"       // 在原有配置基礎(chǔ)上對(duì)顏色做改變
              ctx.fillRect(15, 15, 120, 120); // 使用新的設(shè)置繪制一個(gè)矩形
           
              ctx.save();  // 保存當(dāng)前狀態(tài)
              ctx.fillStyle = "#FFF"       // 再次改變顏色配置
              ctx.fillRect(30, 30, 90, 90);   // 使用新的配置繪制一個(gè)矩形
           
              ctx.restore();       // 重新加載之前的顏色狀態(tài)
              ctx.fillRect(45, 45, 60, 60);   // 使用上一次的配置繪制一個(gè)矩形
           
              ctx.restore();       // 加載默認(rèn)顏色配置
              ctx.fillRect(60, 60, 30, 30);   // 使用加載的配置繪制一個(gè)矩形
          }
          draw();

          九、變形

          9.1 translate

          translate(x, y)

          用來(lái)移動(dòng) canvas原點(diǎn)到指定的位置

          ?translate 方法接受兩個(gè)參數(shù)。x 是左右偏移量,y 是上下偏移量,如右圖所示。

          在做變形之前先保存狀態(tài)是一個(gè)良好的習(xí)慣。大多數(shù)情況下,調(diào)用 restore 方法比手動(dòng)恢復(fù)原先的狀態(tài)要簡(jiǎn)單得多。又如果你是在一個(gè)循環(huán)中做位移但沒有保存和恢復(fù) canvas 的狀態(tài),很可能到最后會(huì)發(fā)現(xiàn)怎么有些東西不見了,那是因?yàn)樗芸赡芤呀?jīng)超出 canvas 范圍以外了。

          ? 注意:translate 移動(dòng)的是 canvas 的坐標(biāo)原點(diǎn)(坐標(biāo)變換)。

          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial1");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
              ctx.save(); //保存坐原點(diǎn)平移之前的狀態(tài)
              ctx.translate(100, 100);
              ctx.strokeRect(0, 0, 100, 100)
              ctx.restore(); //恢復(fù)到最初狀態(tài)
              ctx.translate(220, 220);
              ctx.fillRect(0, 0, 100, 100)
          }
          draw();

          9.2 rotate

          rotate(angle)
           

          旋轉(zhuǎn)坐標(biāo)軸。這個(gè)方法只接受一個(gè)參數(shù):旋轉(zhuǎn)的角度(angle),它是順時(shí)針?lè)较虻模曰《葹閱挝坏闹?。旋轉(zhuǎn)的中心是坐標(biāo)原點(diǎn)。

           
          var ctx;
          function draw(){
            var canvas = document.getElementById("tutorial1");
            if (!canvas.getContext) return;
            var ctx = canvas.getContext("2d");
           
            ctx.fillStyle = "red";
            ctx.save();
           
            ctx.translate(100, 100);
            ctx.rotate(Math.PI / 180 * 45);
            ctx.fillStyle = "blue";
            ctx.fillRect(0, 0, 100, 100);
            ctx.restore();
           
            ctx.save();
            ctx.translate(0, 0);
            ctx.fillRect(0, 0, 50, 50)
            ctx.restore();
          }
          draw();

          9.3 scale

          scale(x, y)

          我們用它來(lái)增減圖形在 canvas 中的像素?cái)?shù)目,對(duì)形狀,位圖進(jìn)行縮小或者放大。

          scale方法接受兩個(gè)參數(shù)。x,y 分別是橫軸和縱軸的縮放因子,它們都必須是正值。值比 1.0 小表示縮 小,比 1.0 大則表示放大,值為 1.0 時(shí)什么效果都沒有。

          ? 默認(rèn)情況下,canvas 的 1 單位就是 1 個(gè)像素。舉例說(shuō),如果我們?cè)O(shè)置縮放因子是 0.5,1 個(gè)單位就變成對(duì)應(yīng) 0.5 個(gè)像素,這樣繪制出來(lái)的形狀就會(huì)是原先的一半。同理,設(shè)置為 2.0 時(shí),1 個(gè)單位就對(duì)應(yīng)變成了 2 像素,繪制的結(jié)果就是圖形放大了 2 倍。

          9.4 transform (變形矩陣)

          transform(a, b, c, d, e, f)
          • a (m11): Horizontal scaling.
          • b (m12): Horizontal skewing.
          • c (m21):? Vertical skewing.
          • d (m22):? Vertical scaling.
          • e (dx):? Horizontal moving.
          • f (dy):? Vertical moving.
          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial1");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
              ctx.transform(1, 1, 0, 1, 0, 0);
              ctx.fillRect(0, 0, 100, 100);
          }
          draw();

          十、合成

          ?

          在前面的所有例子中、,我們總是將一個(gè)圖形畫在另一個(gè)之上,對(duì)于其他更多的情況,僅僅這樣是遠(yuǎn)遠(yuǎn)不夠的。比如,對(duì)合成的圖形來(lái)說(shuō),繪制順序會(huì)有限制。不過(guò),我們可以利用 globalCompositeOperation 屬性來(lái)改變這種狀況。

          globalCompositeOperation = type
          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial1");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
           
              ctx.fillStyle = "blue";
              ctx.fillRect(0, 0, 200, 200);
           
              ctx.globalCompositeOperation = "source-over"; //全局合成操作
              ctx.fillStyle = "red";
              ctx.fillRect(100, 100, 200, 200);
          }
          draw();

          :下面的展示中,藍(lán)色是原有的,紅色是新的。

          type 是下面 13 種字符串值之一:

          1、這是默認(rèn)設(shè)置,新圖像會(huì)覆蓋在原有圖像。

          2. source-in

          僅僅會(huì)出現(xiàn)新圖像與原來(lái)圖像重疊的部分,其他區(qū)域都變成透明的。(包括其他的老圖像區(qū)域也會(huì)透明)

          3. source-out

          僅僅顯示新圖像與老圖像沒有重疊的部分,其余部分全部透明。(老圖像也不顯示)

          4. source-atop

          新圖像僅僅顯示與老圖像重疊區(qū)域。老圖像仍然可以顯示。

          5. destination-over

          新圖像會(huì)在老圖像的下面。

          6. destination-in

          僅僅新老圖像重疊部分的老圖像被顯示,其他區(qū)域全部透明。

          7. destination-out

          僅僅老圖像與新圖像沒有重疊的部分。 注意顯示的是老圖像的部分區(qū)域。

          8. destination-atop

          老圖像僅僅僅僅顯示重疊部分,新圖像會(huì)顯示在老圖像的下面。

          9. lighter

          新老圖像都顯示,但是重疊區(qū)域的顏色做加處理。

          10. darken

          保留重疊部分最黑的像素。(每個(gè)顏色位進(jìn)行比較,得到最小的)

          blue: #0000ff
          red: #ff0000

          所以重疊部分的顏色:#000000。

          11. lighten

          保證重疊部分最量的像素。(每個(gè)顏色位進(jìn)行比較,得到最大的)

          blue: #0000ff
          red: #ff0000

          所以重疊部分的顏色:#ff00ff。

          12. xor

          重疊部分會(huì)變成透明。

          13. copy

          只有新圖像會(huì)被保留,其余的全部被清除(邊透明)。

          十一、裁剪路徑

          clip()
          ?

          把已經(jīng)創(chuàng)建的路徑轉(zhuǎn)換成裁剪路徑。

          ?

          裁剪路徑的作用是遮罩。只顯示裁剪路徑內(nèi)的區(qū)域,裁剪路徑外的區(qū)域會(huì)被隱藏。

          ?

          注意:clip() 只能遮罩在這個(gè)方法調(diào)用之后繪制的圖像,如果是 clip() 方法調(diào)用之前繪制的圖像,則無(wú)法實(shí)現(xiàn)遮罩。

          var ctx;
          function draw(){
              var canvas = document.getElementById("tutorial1");
              if (!canvas.getContext) return;
              var ctx = canvas.getContext("2d");
           
              ctx.beginPath();
              ctx.arc(20,20, 100, 0, Math.PI * 2);
              ctx.clip();
           
              ctx.fillStyle = "pink";
              ctx.fillRect(20, 20, 100,100);
          }
          draw();

          十二、動(dòng)畫

          動(dòng)畫的基本步驟

          清空 canvas 再繪制每一幀動(dòng)畫之前,需要清空所有。清空所有最簡(jiǎn)單的做法就是 clearRect() 方法。

          保存 canvas 狀態(tài) 如果在繪制的過(guò)程中會(huì)更改 canvas 的狀態(tài)(顏色、移動(dòng)了坐標(biāo)原點(diǎn)等),又在繪制每一幀時(shí)都是原始狀態(tài)的話,則最好保存下 canvas 的狀態(tài)

          繪制動(dòng)畫圖形這一步才是真正的繪制動(dòng)畫幀

          恢復(fù) canvas 狀態(tài)如果你前面保存了 canvas 狀態(tài),則應(yīng)該在繪制完成一幀之后恢復(fù) canvas 狀態(tài)。

          控制動(dòng)畫

          我們可用通過(guò) canvas 的方法或者自定義的方法把圖像會(huì)知道到 canvas 上。正常情況,我們能看到繪制的結(jié)果是在腳本執(zhí)行結(jié)束之后。例如,我們不可能在一個(gè) for 循環(huán)內(nèi)部完成動(dòng)畫。

          也就是,為了執(zhí)行動(dòng)畫,我們需要一些可以定時(shí)執(zhí)行重繪的方法。

          一般用到下面三個(gè)方法:

          setInterval()

          setTimeout()

          requestAnimationFrame()

        案例:太陽(yáng)系 

        let sun;
        let earth;
        let moon;
        let ctx;
        function init(){
            sun = new Image();
            earth = new Image();
            moon = new Image();
            sun.src = "sun.png";
            earth.src = "earth.png";
            moon.src = "moon.png";
         
            let canvas = document.querySelector("#solar");
            ctx = canvas.getContext("2d");
         
            sun.onload = function (){
        draw()
            }
         
        }
        init();
        function draw(){
            ctx.clearRect(0, 0, 300, 300); //清空所有的內(nèi)容
            /*繪制 太陽(yáng)*/
            ctx.drawImage(sun, 0, 0, 300, 300);
         
            ctx.save();
            ctx.translate(150, 150);
         
            //繪制earth軌道
            ctx.beginPath();
            ctx.strokeStyle = "rgba(255,255,0,0.5)";
            ctx.arc(0, 0, 100, 0, 2 * Math.PI)
            ctx.stroke()
         
            let time = new Date();
            //繪制地球
            ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds())
            ctx.translate(100, 0);
            ctx.drawImage(earth, -12, -12)
         
            //繪制月球軌道
            ctx.beginPath();
            ctx.strokeStyle = "rgba(255,255,255,.3)";
            ctx.arc(0, 0, 40, 0, 2 * Math.PI);
            ctx.stroke();
         
            //繪制月球
            ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds());
            ctx.translate(40, 0);
            ctx.drawImage(moon, -3.5, -3.5);
            ctx.restore();
         
            requestAnimationFrame(draw);
        }
        標(biāo)簽: CSS HTML
        相關(guān)文章:
        主站蜘蛛池模板: 99在线观看巨臀大臀视频 | 香蕉超级碰碰碰97视频蜜芽 | 成人网18免费网站在线 | 国产网曝手机视频在线观看 | 久久青草国产手机看片福利盒子 | 大伊香蕉精品视频在线天堂 | 日本一级aaaa特黄毛片 | 国产中的精品一区的 | 久久er热这里只有精品23 | 免费特黄一级欧美大片在线看 | 欧美一区二区aa大片 | 成人97| 亚洲艹| 国产综合久久久久影院 | 男女视频免费 | 久久久免费视频观看 | 99久久精品国产9999高清 | 久久精品香蕉视频 | 成年视频国产免费观看 | 日本国产欧美色综合 | 最新欧美精品一区二区三区 | 国产日韩一区二区三区在线播放 | 爆操巨乳美女 | 国产成人精品一区二区秒拍 | 亚洲大片免费 | 国产美女在线一区二区三区 | 国产欧美日韩亚洲精品区2345 | 欧美做爱毛片 | 国产91九色刺激露脸对白 | 九九九九在线视频播放 | 国产一级视频在线观看 | 国产亚洲高清在线精品99 | 久久精品人人爽人人爽快 | 国产欧美视频一区二区三区 | 在线步兵区 | 日韩三级小视频 | 久久亚洲国产视频 | 男女晚上爱爱的视频在线观看 | 久草在线视频新时代视频 | 长腿嫩模打开双腿呻吟 | 国产一区二区影院 |