整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線:

          H5的canvas繪畫(huà)的一個(gè)簡(jiǎn)單時(shí)鐘

          HTML5簡(jiǎn)稱(chēng)H5,現(xiàn)在因?yàn)楹芑穑芏嗳硕荚趯W(xué)。canvas是屬于H5里面的一個(gè)標(biāo)簽,它有很強(qiáng)大的繪畫(huà)功能。當(dāng)然,這些功能不是說(shuō)用HTML標(biāo)簽就能實(shí)現(xiàn),它還要結(jié)合JavaScript一起完成。

          這次是用canvas繪畫(huà)簡(jiǎn)單的時(shí)鐘,整體思路:先畫(huà)框drawBackground,然后把時(shí)針(drawHour),分針(drawMinute),秒針(drawSecond)分別畫(huà)出來(lái). 畫(huà)完之后就開(kāi)始實(shí)現(xiàn)動(dòng)畫(huà)了。動(dòng)畫(huà)實(shí)現(xiàn)是先清除整個(gè)繪畫(huà),然后再重新畫(huà)一遍鐘,每秒執(zhí)行一次。


          //canvas的div結(jié)構(gòu) 內(nèi)容很少

          <div>

          <canvas id="clock" height="600px" width="600px"></canvas>

          </div>


          //先畫(huà)框

          function drawBackground(){

          ctx.save();//保存當(dāng)前環(huán)境狀態(tài)

          ctx.translate(r,r);//重新定義原點(diǎn)坐標(biāo),正方形的正中心

          ctx.beginPath();//起始路徑

          ctx.lineWidth = 10 * em;//加粗10像素

          ctx.arc(0,0,r-5*em,0,2*Math.PI,false);//創(chuàng)建圓

          ctx.stroke();//設(shè)置繪畫(huà)方式,畫(huà)線

          var hours = [3,4,5,6,7,8,9,10,11,12,1,2];//定義時(shí)間數(shù)組

          ctx.font = 16 * em + "px Arial"http://字體和字體大小

          ctx.textAlign = 'center';//數(shù)字相對(duì)圓心左右兩邊居中

          ctx.textBaseline = 'middle';//數(shù)字相對(duì)圓心上線兩邊居中

          //畫(huà)時(shí)刻

          hours.forEach(function(number , i){

          var rad = 2 * Math.PI / 12 * i; //把圓分12個(gè)弧度

          var x = Math.cos(rad) * (r - 30 * em);

          var y = Math.sin(rad) * (r - 30 * em);

          ctx.fillText(number , x, y);

          });

          //畫(huà)點(diǎn)

          for(var i=0;i < 60 ; i++){

          var rad = 2 * Math.PI / 60 *i;

          var x = Math.cos(rad) * (r - 18 * em);

          var y = Math.sin(rad) * (r - 18 * em);

          ctx.beginPath();

          //如果是整時(shí)就實(shí)黑點(diǎn) 不是就虛點(diǎn)

          if(i % 5 === 0){

          ctx.fillStyle = '#000';

          ctx.arc(x, y, 2 * em, 0, 2 * Math.PI, false);

          }else{

          ctx.fillStyle = '#ccc';

          ctx.arc(x, y, 2 * em, 0, 2 * Math.PI, false);

          }

          ctx.fill();//填充

          }

          }


          //畫(huà)時(shí)針

          function drawHour(hour, minute){

          ctx.save();

          var rad = 2 * Math.PI / 12 * hour;

          var mrad = 2 * Math.PI / 12 / 60 * minute;

          ctx.beginPath();

          ctx.rotate(rad + mrad);//旋轉(zhuǎn)角度

          ctx.lineWidth = 6 * em;//時(shí)針寬度

          ctx.lineCap = 'round';//線條的每個(gè)末端添加圓形線帽

          ctx.moveTo(0, 10 * em);

          ctx.lineTo(0, -r / 2);

          ctx.stroke();

          ctx.restore();

          }


          //畫(huà)分針

          function drawMinute(minute){

          ctx.save();

          var rad = 2 * Math.PI / 60 * minute;

          ctx.beginPath();

          ctx.rotate(rad);//旋轉(zhuǎn)角度

          ctx.lineCap = 'round';//線條的每個(gè)末端添加圓形線帽

          ctx.lineWidth = 4 * em;

          ctx.moveTo(0, 10 * em);

          ctx.lineTo(0, -r + 30 * em);

          ctx.stroke();

          ctx.restore();

          }


          //畫(huà)秒針

          function drawSecond(second){

          ctx.save();

          ctx.beginPath();

          ctx.fillStyle = '#c14543';

          var rad = 2 * Math.PI / 60 * second;

          ctx.rotate(rad);

          ctx.moveTo(-2 * em, 20 * em);

          ctx.lineTo(2 * em, 20 * em);

          ctx.lineTo(1, -r + 18 * em);

          ctx.lineTo(-1, -r + 18 * em);

          ctx.fill();

          ctx.restore();

          }


          //畫(huà)中心點(diǎn)

          function drawDot(){

          ctx.beginPath();

          ctx.fillStyle = '#fff';

          ctx.arc(0, 0, 3 * em, 2*Math.PI, false);

          ctx.fill();

          }


          //獲取時(shí)間繪制走向

          function draw(){

          ctx.clearRect(0, 0, width, height);//每秒清除重新畫(huà)

          var now = new Date();//獲取當(dāng)前時(shí)間

          var hour = now.getHours();//獲取小時(shí)數(shù)

          var minute = now.getMinutes();//獲取分鐘數(shù)

          var second = now.getSeconds();//獲取秒鐘數(shù)

          drawBackground();

          drawHour(hour,minute);

          drawMinute(minute);

          drawSecond(second);

          drawDot();

          ctx.restore();//返回之前保存的路徑狀態(tài)和屬性

          }

          draw(); //先執(zhí)行一次繪畫(huà)

          setInterval(draw, 1000);//實(shí)現(xiàn)動(dòng)畫(huà)

          頭條寫(xiě)代碼很不爽,看代碼更不爽。不過(guò)這也沒(méi)辦法,大家將就吧。

          .less

          * {
              margin: 0;
              padding: 0;
              #wrap {
                  width: 600px;
                  height: 800px;
                  background: tomato;
                  border: 2px solid white;
                  border-radius: 5%;
                  //這里不可使用position,會(huì)影響畫(huà)布的坐標(biāo)定位
                  left: 0;
                  top: 0;
                  right: 0;
                  bottom: 0;
                  margin: 5% auto;
                  font: 20px "微軟雅黑";
                  text-align: center;
                  color: white;
                  transition: 2s;
                  &:hover {
                      background: steelblue;
                  }
                  h1 {
                      margin-top: 8%;
                  }
                  h2 {
                      margin-left: 30%;
                      margin-top: 100%;
                  }
                  #wrap-canvas {
                      position: absolute;
                      background: skyblue;
                      left: 0;
                      top: 0;
                      right: 0;
                      bottom: 0;
                      margin: auto;
                  }
              }
          }

          2.css

          * {
            margin: 0;
            padding: 0;
          }
          * #wrap {
            width: 600px;
            height: 800px;
            background: tomato;
            border: 2px solid white;
            border-radius: 5%;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            margin: 5% auto;
            font: 20px "微軟雅黑";
            text-align: center;
            color: white;
            transition: 2s;
          }
          * #wrap:hover {
            background: steelblue;
          }
          * #wrap h1 {
            margin-top: 8%;
          }
          * #wrap h2 {
            margin-left: 30%;
            margin-top: 100%;
          }
          * #wrap #wrap-canvas {
            position: absolute;
            background: skyblue;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            margin: auto;
          }
          

          3.js

          $(function() {
          	var canvasNode = document.querySelector("#wrap-canvas");
          	if(canvasNode.getContext) {
          		var canvasPen = canvasNode.getContext("2d");
          
          		setInterval(function(){
          			canvasPen.clearRect(0,0,canvasNode.width,canvasNode.height);
          			clockMove();
          		}, 1000);
          		clockMove();
          		function clockMove() {
          			/**1.外層表圈**/
          			canvasPen.save();
          			canvasPen.strokeStyle = "cornsilk";
          			canvasPen.lineWidth = 10;
          			canvasPen.lineCap = "round";
          			//更新源點(diǎn)
          			canvasPen.translate(250, 250);
          			//旋轉(zhuǎn)順時(shí)針
          			canvasPen.rotate(-90 * Math.PI / 180);
          			canvasPen.beginPath();
          
          			/**2.外層表盤(pán)**/
          			canvasPen.save();
          			canvasPen.strokeStyle = "#FAEBCC";
          			canvasPen.lineWidth = 15;
          			canvasPen.beginPath();
          			//畫(huà)圓
          			canvasPen.arc(0, 0, 200, 0, 360 * Math.PI / 180);
          			canvasPen.stroke();
          			canvasPen.restore();
          
          			/**3.時(shí)針刻度**/
          			canvasPen.save();
          			canvasPen.strokeStyle = "green";
          			for(var i = 0; i < 12; i++) {
          				//旋轉(zhuǎn):每30度轉(zhuǎn)一針.canvas效果為累加(疊加)不需要帶參數(shù)i
          				canvasPen.rotate(30 * Math.PI / 180);
          				canvasPen.beginPath();
          				//指針下端點(diǎn)到150
          				canvasPen.moveTo(150, 0);
          				//指針上端點(diǎn)到180
          				canvasPen.lineTo(180, 0);
          				canvasPen.stroke();
          			}
          			canvasPen.restore();
          
          			/**4.分針刻度**/
          			canvasPen.save();
          			canvasPen.strokeStyle = "#4CAE4C";
          			canvasPen.lineWidth = 10;
          			for(var i = 0; i < 60; i++) {
          				//旋轉(zhuǎn):如果在這里旋轉(zhuǎn)需要更新if((i+1)%5!=0)
          				canvasPen.rotate(6 * Math.PI / 180);
          				//判斷分鐘不旋轉(zhuǎn)填充
          				//if(i % 5 != 0) {
          				if((i + 1) % 5 != 0) {
          					canvasPen.beginPath();
          					canvasPen.moveTo(155, 0);
          					canvasPen.lineTo(170, 0);
          					canvasPen.stroke();
          				}
          				//旋轉(zhuǎn):每6度轉(zhuǎn)一針,第一個(gè)畫(huà)的度=6,需要在排除時(shí)針的0點(diǎn)先計(jì)算再進(jìn)行旋轉(zhuǎn)。
          				//canvasPen.rotate(6 * Math.PI / 180);
          			}
          			canvasPen.restore();
          
          			var canvasDate = new Date();
          			var seconds = canvasDate.getSeconds();
          			var minutes = canvasDate.getMinutes() + seconds / 60;
          			var hours = canvasDate.getHours() + minutes / 60;
          			//時(shí)間判斷
          			hours > 12 ? hours - 12 : hours;
          			console.log("小時(shí):", hours);
          			/**4.時(shí)針**/
          			canvasPen.save();
          			canvasPen.lineWidth = 20;
          			canvasPen.strokeStyle = "tomato";
          			canvasPen.rotate(hours * 30 * Math.PI / 180);
          			canvasPen.beginPath();
          			canvasPen.moveTo(0, 0);
          			canvasPen.lineTo(120, 0);
          			canvasPen.stroke();
          			canvasPen.restore();
          
          			/**5.分針**/
          			canvasPen.save();
          			canvasPen.lineWidth = 15;
          			canvasPen.strokeStyle = "#E38D13";
          			canvasPen.rotate(minutes * 6 * Math.PI / 180);
          			canvasPen.beginPath();
          			canvasPen.moveTo(0, 0);
          			canvasPen.lineTo(130, 0);
          			canvasPen.stroke();
          			canvasPen.restore();
          
          			/**6.秒針**/
          			canvasPen.save();
          			canvasPen.lineWidth = 10;
          			canvasPen.strokeStyle = "#C12E2A";
          			canvasPen.fillStyle = "#C12E2A";
          			canvasPen.rotate(seconds * 6 * Math.PI / 180);
          			canvasPen.beginPath();
          			canvasPen.moveTo(0, 0);
          			canvasPen.lineTo(130, 0);
          			canvasPen.stroke();
          				//鐘座
          				canvasPen.beginPath();
          				canvasPen.arc(0, 0, 20, 0, 360 * Math.PI / 180);
          				canvasPen.fill();
          				//畫(huà)指針圓環(huán)
          				canvasPen.beginPath();
          				canvasPen.arc(145, 0, 12, 0, 360 * Math.PI / 180);
          				canvasPen.stroke();
          				canvasPen.restore();
          			canvasPen.restore();
          		}
          
          	}
          })

          4.html

          <!DOCTYPE html>
          <html>
          
          	<head>
          		<meta charset="UTF-8">
          		<meta name="viewport" content="width=devide-width,initial-scal=1.0,user-scalable=no" />
          		<title>canvas鐘表組件</title>
          	</head>
          	<link rel="stylesheet" href="../6-bootstrap/css/bootstrap.min.css" />
          	<link rel="stylesheet" href="css/12-canvas-clock.css" />
          
          	<body>
          		<div id="wrap">
          			<h1>canvas鐘表組件</h1>
          			<canvas id="wrap-canvas" width="500px" height="500px"></canvas>
          			<h2>PS:一刀coder</h2>
          		</div>
          	</body>
          	<script type="text/javascript" src="../6-bootstrap/js/jquery.min.js"></script>
          	<script type="text/javascript" src="../6-bootstrap/js/bootstrap.min.js"></script>
          	<script type="text/javascript" src="js/12-canvas-clock.js"></script>
          
          </html>
          1234567891011121314151617181920212223

          5.效果圖

          canvas

          、canvas簡(jiǎn)介

          ? <canvas> 是 HTML5 新增的,一個(gè)可以使用腳本(通常為JavaScript)在其中繪制圖像的 HTML 元素。它可以用來(lái)制作照片集或者制作簡(jiǎn)單(也不是那么簡(jiǎn)單)的動(dòng)畫(huà),甚至可以進(jìn)行實(shí)時(shí)視頻處理和渲染。

          ? 它最初由蘋(píng)果內(nèi)部使用自己MacOS X WebKit推出,供應(yīng)用程序使用像儀表盤(pán)的構(gòu)件和 Safari 瀏覽器使用。 后來(lái),有人通過(guò)Gecko內(nèi)核的瀏覽器 (尤其是Mozilla和Firefox),Opera和Chrome和超文本網(wǎng)絡(luò)應(yīng)用技術(shù)工作組建議為下一代的網(wǎng)絡(luò)技術(shù)使用該元素。

          ? Canvas是由HTML代碼配合高度和寬度屬性而定義出的可繪制區(qū)域。JavaScript代碼可以訪問(wèn)該區(qū)域,類(lèi)似于其他通用的二維API,通過(guò)一套完整的繪圖函數(shù)來(lái)動(dòng)態(tài)生成圖形。

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

          二、Canvas基本使用

          2.1 <canvas>元素

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

          ? <canvas>看起來(lái)和<img>標(biāo)簽一樣,只是 <canvas> 只有兩個(gè)可選的屬性 width、heigth 屬性,而沒(méi)有 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 src="./美女.jpg" alt="">
          </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à)布,會(huì)公開(kāi)一個(gè)或多個(gè) 渲染上下文(畫(huà)筆),使用 渲染上下文來(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 代碼模板

          <html>
          <head>
           <title>Canvas tutorial</title>
           <style type="text/css">
           canvas {
           border: 1px solid black;
           }
           </style>
          </head>
          <canvas id="tutorial" width="300" height="300"></canvas>
          </body>
          <script type="text/javascript">
           function draw(){
           var canvas = document.getElementById('tutorial');
           if(!canvas.getContext) return;
           var ctx = canvas.getContext("2d");
           //開(kāi)始代碼
           
           }
           draw();
          </script>
          </html>
          

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

          繪制兩個(gè)長(zhǎng)方形。

          <html>
          <head>
           <title>Canvas tutorial</title>
           <style type="text/css">
           canvas {
           border: 1px solid black;
           }
           </style>
          </head>
          <canvas id="tutorial" width="300" height="300"></canvas>
          </body>
          <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>
          </html>
          

          三、繪制形狀

          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 提供了三種方法繪制矩形:

          fillRect(x, y, width, height)

          繪制一個(gè)填充的矩形

          strokeRect(x, y, width, height)

          繪制一個(gè)矩形的邊框

          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)

          把畫(huà)筆移動(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); //把畫(huà)筆移動(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沒(méi)有閉合,則fill()會(huì)自動(dòng)閉合路徑。
          }
          draw();
          

          4 繪制圓弧

          有兩個(gè)方法可以繪制圓弧:

          arc(x, y, r, startAngle, endAngle, anticlockwise):

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

          注意:

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

          0弧度是指的x軸正方形

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

          arcTo(x1, y1, x2, y2, radius):

          根據(jù)給定的控制點(diǎn)和半徑畫(huà)一段圓弧,最后再以直線連接兩個(gè)控制點(diǎn)。

          圓弧案例1:

          function draw(){
           var canvas = document.getElementById('tutorial');
           if (!canvas.getContext) return;
           var ctx = canvas.getContext("2d");
           ctx.beginPath();
           ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
           ctx.stroke();
          }
          draw();
          

          圓弧案例2:

          function draw(){
           var canvas = document.getElementById('tutorial');
           if (!canvas.getContext) return;
           var ctx = canvas.getContext("2d");
           ctx.beginPath();
           ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
           ctx.stroke();
           ctx.beginPath();
           ctx.arc(150, 50, 40, 0, -Math.PI / 2, true);
           ctx.closePath();
           ctx.stroke();
           ctx.beginPath();
           ctx.arc(50, 150, 40, -Math.PI / 2, Math.PI / 2, false);
           ctx.fill();
           ctx.beginPath();
           ctx.arc(150, 150, 40, 0, Math.PI, false);
           ctx.fill();
          }
          draw();
          

          圓弧案例3:

          function draw(){
           var canvas = document.getElementById('tutorial');
           if (!canvas.getContext) return;
           var ctx = canvas.getContext("2d");
           ctx.beginPath();
           ctx.moveTo(50, 50);
           //參數(shù)1、2:控制點(diǎn)1坐標(biāo) 參數(shù)3、4:控制點(diǎn)2坐標(biāo) 參數(shù)4:圓弧半徑
           ctx.arcTo(200, 50, 200, 200, 100);
           ctx.lineTo(200, 200)
           ctx.stroke();
           
           ctx.beginPath();
           ctx.rect(50, 50, 10, 10);
           ctx.rect(200, 50, 10, 10)
           ctx.rect(200, 200, 10, 10)
           ctx.fill()
          }
          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),又稱(chēng)貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。

          ? 一般的矢量圖形軟件通過(guò)它來(lái)精確畫(huà)出曲線,貝茲曲線由線段與節(jié)點(diǎn)組成,節(jié)點(diǎn)是可拖動(dòng)的支點(diǎn),線段像可伸縮的皮筋,我們?cè)诶L圖工具上看到的鋼筆工具就是來(lái)做這種矢量曲線的。

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

          ? 貝塞爾曲線于1962,由法國(guó)工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表,他運(yùn)用貝塞爾曲線來(lái)為汽車(chē)的主體進(jìn)行設(shè)計(jì)。貝塞爾曲線最初由Paul de Casteljau于1959年運(yùn)用de Casteljau演算法開(kāi)發(fā),以穩(wěn)定數(shù)值的方法求出貝茲曲線。

          一次貝塞爾曲線(線性貝塞爾曲線)

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

          二次貝塞爾曲線

          三次貝塞爾曲線

          4.5.2 繪制貝塞爾曲線

          繪制二次貝塞爾曲線

          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` 的值。

          1.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();
          

          2.strokeStyle

          <script type="text/javascript">
           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);
           }
          </script>
          

          3.Transparency(透明度)

          globalAlpha = transparencyValue

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

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

          line style

          1. lineWidth = value

          線寬。只能是正值。默認(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, bevel 和 miter:

          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)渲染文本:

          fillText(text, x, y [, maxWidth])

          在指定的(x,y)位置填充指定的文本,繪制的最大寬度是可選的.

          strokeText(text, x, y [, maxWidth])

          在指定的(x,y)位置繪制文本邊框,繪制的最大寬度是可選的.

          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 由零開(kāi)始創(chuàng)建圖片

          創(chuàng)建<img>元素

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

          腳本執(zhí)行后圖片開(kāi)始裝載

          繪制img

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

          ctx.drawImage(img,0,0); 
          

          注意:

          ? 考慮到圖片是從網(wǎng)絡(luò)加載,如果 drawImage 的時(shí)候圖片還沒(méi)有完全加載完成,則什么都不做,個(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 src="./美女.jpg" alt="" width="300"><br>
          <canvas id="tutorial" width="600" height="400"></canvas>
          <script type="text/javascript">
           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();
           }
          </script>
          

          第一張圖片就是頁(yè)面中的<img>標(biāo)簽

          7.3 縮放圖片

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

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

          ? 這個(gè)方法多了2個(gè)參數(shù):width 和 height,這兩個(gè)參數(shù)用來(lái)控制 當(dāng)像canvas畫(huà)入時(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()

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

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

          關(guān)于 save()

          Canvas狀態(tài)存儲(chǔ)在棧中,每當(dāng)save()方法被調(diào)用后,當(dāng)前的狀態(tài)就被推送到棧中保存。一個(gè)繪畫(huà)狀態(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方法。(類(lèi)似數(shù)組的push())

          關(guān)于restore()

          每一次調(diào)用 restore 方法,上一個(gè)保存的狀態(tài)就從棧中彈出,所有設(shè)定都恢復(fù)。(類(lèi)似數(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)中做位移但沒(méi)有保存和恢復(fù)canvas 的狀態(tài),很可能到最后會(huì)發(fā)現(xiàn)怎么有些東西不見(jià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è)较虻模曰《葹閱挝坏闹怠?/p>

          ? 旋轉(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í)什么效果都沒(méi)有。

          ? 默認(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è)圖形畫(huà)在另一個(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. source-over(default)

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

          ##2. source-in

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

          ##3. source-out

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

          ##4. source-atop

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

          ##5. destination-over

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

          ##6. destination-in

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

          ##7. destination-out

          僅僅老圖像與新圖像沒(méi)有重疊的部分。 注意顯示的是老圖像的部分區(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)畫(huà)

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

          清空canvas

          再繪制每一幀動(dòng)畫(huà)之前,需要清空所有。清空所有最簡(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)畫(huà)圖形

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

          恢復(fù)canvas狀態(tài)

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

          控制動(dòng)畫(huà)

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

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

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

          setInterval()

          setTimeout()

          requestAnimationFrame()

          ##案例1:太陽(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);
          }
          

          ##案例2:模擬時(shí)鐘


          主站蜘蛛池模板: 国产精品亚洲高清一区二区| 亚洲av日韩综合一区二区三区| 国产精品香蕉一区二区三区| 动漫精品第一区二区三区| 亚洲视频在线一区| 国产亚洲3p无码一区二区| 中文无码AV一区二区三区| 国产剧情一区二区| 无码精品人妻一区二区三区AV| 亚洲av无一区二区三区| 国产精品夜色一区二区三区| 蜜臀Av午夜一区二区三区| 中文字幕一区二区三区精华液| 日韩毛片一区视频免费| 夜色阁亚洲一区二区三区| 中文字幕久久亚洲一区| 国产精品一区二区av| 少妇无码一区二区三区免费| 看电影来5566一区.二区| 一区二区三区视频在线| 一区二区无码免费视频网站| 久久精品免费一区二区喷潮| 波多野结衣精品一区二区三区| 国产一区二区精品在线观看| 中文字幕日本精品一区二区三区| 久草新视频一区二区三区| 99久久精品午夜一区二区| 制服美女视频一区| 男女久久久国产一区二区三区| 亚洲一区在线免费观看| 色综合一区二区三区| 久久精品一区二区国产| 精品爆乳一区二区三区无码av| 日本不卡在线一区二区三区视频| 亚洲免费一区二区| 亚洲一区二区三区首页 | 亚洲AV无一区二区三区久久| 亚洲愉拍一区二区三区| 国产综合一区二区在线观看| 日本视频一区在线观看免费 | 国产99久久精品一区二区|