HTML5 canvas繪圖基礎(電子名片生成器原始碼)
建立canvas
<canvas id="myCanvas" class="canvas"> 您的瀏覽器不支援canvas </canvas>
基礎設定
<script type="text/javascript"> var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); canvas.width=100; canvas.height=100; </script>
畫直線
moveTo(x1, y1)
lineTo(x2, y2)
ctx.moveTo(0, 0); ctx.lineTo(100, 100); ctx.stroke();
畫圓形
ctx.arc(x,y,radius,0,2*Math.PI,true)
ctx.beginPath(); ctx.arc(300,300,50,0,2*Math.PI,true); ctx.strokeStyle = '#000'; ctx.stroke();
畫矩形
ctx.strokeRect(x1, y1,x2, y2)
ctx.strokeRect(300,100,200,100);
beginPath()開始一條新路徑
closePath()使當前路徑閉合
不是成對出現的
ctx.beginPath(); ctx.moveTo(300, 0); ctx.lineTo(200, 100); ctx.lineTo(200, 200); ctx.closePath(); ctx.strokeStyle = '#0F0'; ctx.stroke();
設定樣式
ctx.moveTo(0,0); ctx.lineTo(100,100); ctx.lineTo(100,200); ctx.closePath();//lineWidth 設定描邊的線寬 ctx.lineWidth = 10; //strokeStyle 設定描邊樣式 ctx.strokeStyle = "#F00"; ctx.stroke(); //fillStyle 設定填充樣式 ctx.fillStyle = "rgba(0,255,0,0.5)"; ctx.fill();
繪製矩形與樣式同步
ctx.strokeRect(100,200,100,100);
ctx.fillRect(100,200,100,100);
儲存和恢復上下文環境,一般成對出現
save 儲存當前繪畫環境,包括變換和樣式
restore 恢復當前繪畫環境,包括變換和樣式
ctx.save();
ctx.restore();
圖形變換
//translate 平移變換 ctx.translate(0,100); ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(100,100); ctx.stroke(); //rotate 旋轉變換 ctx.rotate(Math.PI/4); ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(100,100); ctx.lineWidth = 5; ctx.strokeStyle = "#F00"; ctx.stroke(); //scale 縮放變換 ctx.scale(1,0.5); ctx.fillRect(0,-100,100,100);
線性漸變
var linearGradient = ctx.createLinearGradient(0, 0, 200, 0); //給漸變新增顏色 linearGradient.addColorStop(0, 'rgb(255,0,0)'); linearGradient.addColorStop(0.3, 'rgb(0,255,0)'); linearGradient.addColorStop(1, 'rgb(0,0,255)'); //設定漸變作為樣式 ctx.fillStyle = linearGradient; ctx.fillRect(0, 0, 200, 200);
徑向漸變
var radialGradient = ctx.createRadialGradient(400, 50, 0, 400, 150, 100); radialGradient.addColorStop(0, 'rgb(255,255,0)'); radialGradient.addColorStop(1, 'rgb(0,0,0)'); ctx.fillStyle = radialGradient; ctx.beginPath(); ctx.arc(400, 150, 100, 0, Math.PI * 2, true); ctx.fill();
文字
字型若設定了居中,圓心會在文字的中間位置,所以圓心還是要根據畫布大小和文字的寬度進行設定。
var str = "hello world"; //設定文字樣式,比如大小,字型 ctx.font = "50px sans-serif"; //水平對其設定,left center right ctx.textAlign = "center"; //垂直對齊設定,top middle bottom ctx.textBaseline = "top"; //填充文字 ctx.fillText(str,300,0); //描邊文字 ctx.strokeText(str,0,200); //獲取文字寬度 var width = ctx.measureText(str).width; console.log(width);
圖片
ctx.fillRect(0, 0, canvas.width, canvas.height); var img = new Image(); img.src = "logo.png"; //一定要在影象載入完成後的回撥中繪製圖像 img.onload = function () { //在(0,0)點處繪製img影象 // ctx.drawImage(img, 0, 0); //在(0,0)點處繪製img影象,縮放成256*80 // ctx.drawImage(img, 0, 0, 256, 80); //獲取img影象的(0,0)點處的40*40區域,繪製在(100,100)點處,縮放成80*80 ctx.drawImage(img, 0, 0, 40, 40, 100, 100, 80, 80); }
建立影象畫刷ctx.createPattern(image, type)
ctx.fillRect(0, 0, canvas.width, canvas.height); var img = new Image(); img.src = "logo.png"; img.onload = function () { //建立影象畫刷,no-repeat,repeat-x,repeat-y,repeat var pattern = ctx.createPattern(img, "repeat"); ctx.fillStyle = pattern; ctx.fillRect(0, 0, canvas.width, canvas.height); }
陰影繪製
//陰影的X偏移 ctx.shadowOffsetX = 10; //陰影的Y偏移 ctx.shadowOffsetY = 10; //陰影的顏色 ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; //陰影的模糊度 ctx.shadowBlur = 10; ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; ctx.fillRect(100, 100, 100, 100); ctx.font = "50px sans-serif"; ctx.fillText("我是小可愛",200,100);
區域剪輯
//儲存當前環境 ctx.save(); ctx.arc(300, 100, 200, 0, Math.PI*2, true); //進行區域剪輯 ctx.clip(); ctx.fillStyle = "#F00"; ctx.fillRect(100, 100, 200, 200); //恢復環境,釋放了剪輯區域的作用 ctx.restore();
繪製曲線ctx.arc(x, y, startAngle, endAngle ,Math.PI*2, true)
最後一個引數代表是否是逆時針方向
//繪製圓弧 ctx.arc(100, 100, 50, 0 ,Math.PI*2, true); ctx.fill(); //二次樣條曲線ctx.quadraticCurveTo(qcpx,qcpy,qx,qy) ctx.beginPath(); ctx.moveTo(100,355); ctx.quadraticCurveTo(265,145,380,349); ctx.fill(); //貝塞爾曲線ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y) ctx.beginPath(); ctx.moveTo(175,375); ctx.bezierCurveTo(297,182,468,252,517,380); ctx.fill();
canvas繪製曲線生成工具
兩次貝塞爾曲線:
http://blogs.sitepointstatic.com/examples/tech/canvas-curves/quadratic-curve.html
三次貝塞爾曲線:
http://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html
動畫
ctx.clearRect(x, y, width, height) 清除區域,用於重新繪製
var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); var posx = 0, posy = 0, dir = 1, isMouseInRect = false; // 確定動畫範圍 canvas.onmousemove = function(e){ var mouseX = e.offsetX; var mouseY = e.offsetY; if(mouseX > posx && mouseY <posx +50 && mouseY > posy && mouseY < posy+ 50){ isMouseInRect = true; }else{ isMouseInRect = false; } } // 開始動畫 setInterval(function() { if(!isMouseInRect){ posx += 10 * dir; } //clearRect清空畫布的一個矩形區域 ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillRect(posx, posy, 50, 50); if(posx + 50 >= canvas.width){ dir = -1; }else if(posx <= 0){ dir = 1; } },100);
離屏技術
把canvas(sx,sy)處寬sw,高sy的區域,繪製到(dx,dy)處,並縮放為寬dx,高dh
ctx.drawImage(canvas,sx,sy,sw,sh,dx,dy,dw,dh)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>canvas</title> <style type="text/css"> canvas { border: 1px solid red; } #offCanvas{ display: none; } </style> </head> <body> <canvas id="myCanvas" width="600px" height="400px"> 您的瀏覽器不支援canvas </canvas> <!--建立離屏Canvas--> <canvas id="offCanvas" width="600px" height="400px"> 您的瀏覽器不支援canvas </canvas> <script type="text/javascript"> var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); var offCanvas = document.getElementById('offCanvas'); var offCtx = offCanvas.getContext('2d'); var posx = 0, posy = 0, dir = 1, isMouseInRect = false; //把一些複雜的繪畫操作,畫在離屏Canvas上面 var drawALot = function(){ for(var k=0; k<20; k++){ for(var i=0;i<canvas.width;i+=10){ for(var j=0;j<canvas.height;j+=10){ offCtx.beginPath(); offCtx.arc(i,j,5,0,2*Math.PI,true); offCtx.stroke(); } } } } canvas.onmousemove = function(e){ var mouseX = e.offsetX; var mouseY = e.offsetY; if(mouseX > posx && mouseY <posx +50 && mouseY > posy && mouseY < posy + 50){ isMouseInRect = true; }else{ isMouseInRect = false; } } setInterval(function() { if(!isMouseInRect){ posx += 10 * dir; } //clearRect清空畫布的一個矩形區域 ctx.clearRect(0, 0, canvas.width, canvas.height); // drawALot(); //真正要用到複雜的繪畫的時候,直接從離屏Canvas上拷貝過來 ctx.drawImage(offCanvas,0,0,offCanvas.width, offCanvas.height,0,0, canvas.width, canvas.height); ctx.fillRect(posx, posy, 50, 50); if(posx + 50 >= canvas.width){ dir = -1; }else if(posx <= 0){ dir = 1; } },100); drawALot(); </script> </body> </html>
案例:電子名片生成器
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>電子名片生成器</title> <link href="style/style.css" rel="stylesheet" /> </head> <body> <div class="left-div"> <div class="line"> <input id="name" type="text" placeholder="姓名"/> </div> <div class="line"> <input id="address" type="text" placeholder="地址"/> </div> <div class="line"> <input id="job" type="text" placeholder="職業"/> </div> <div class="line"> <input id="slogan" type="text" placeholder="口號" /> </div> <div class="line"> <button id="generateBtn">生成名片</button> </div> </div> <div class="right-div"> <canvas id="cardCanvas"> 您的瀏覽器不支援Canvas,請升級瀏覽器 </canvas> <canvas id="animCanvas"> 您的瀏覽器不支援Canvas,請升級瀏覽器 </canvas> </div> <script src="script/main.js"></script> </body> </html>
style.css
* { margin: 0; padding: 0; } html, body { height: 100%; } .left-div { width: 30%; height: 100%; float: left; background: #a4a296; } .line { text-align: center; margin-top: 30px; } .line:first-child { margin-top: 200px; } .line span { color: white; } .line input { width: 300px; height: 30px; border-radius: 15px; padding-left: 15px; outline: none; border: none; } .line button { width: 100px; height: 30px; outline: none; border: none; background: #222; color: #DDD; cursor: pointer; position: relative; border-radius: 15px; } .line button:hover { background: #000; color: #FFF; } .line button:active { left: 1px; top: 1px; } .right-div { width: 70%; height: 100%; float: left; background: #eee9d3; text-align: center; position: relative; } .right-div canvas { position: absolute; top: 200px; left: 50%; margin-left: -300px; } #cardCanvas { display: none; }
main.js
// 建立和設定cardCanvas,該canvas作為離屏canvas var cardCanvas = document.getElementById('cardCanvas'); var cardCtx = cardCanvas.getContext('2d'); cardCtx.canvas.width = 600; cardCtx.canvas.height = 100; // 載入圖片 var img = new Image(); img.src = "images/logo.png"; img.onload = function() { cardCtx.drawImage(img, 10, 10); } var generateBtn = document.getElementById("generateBtn"); generateBtn.onclick = function() { cardCtx.clearRect(0, 0, cardCtx.canvas.width, cardCtx.canvas.height); // 背景的線性漸變 var linearGradient = cardCtx.createLinearGradient(0, 0, cardCtx.canvas.width, cardCtx.canvas.height); linearGradient.addColorStop(0.5, 'rgb(0,0,0)'); linearGradient.addColorStop(1, 'rgb(133,133,133)'); cardCtx.fillStyle = linearGradient; cardCtx.fillRect(0, 0, cardCtx.canvas.width, cardCtx.canvas.height); // logo影象 cardCtx.drawImage(img, 10, 10); // 獲取姓名、地址、職業,繪製,並計算長度 var name = document.getElementById("name").value || "請輸入姓名"; var address = document.getElementById("address").value || "請輸入地址"; var job = document.getElementById("job").value || "請輸入職業"; var nameWidth, addressWidth, jobWidth, maxWidth = 0; cardCtx.font = "bold 30px sans-serif"; cardCtx.fillStyle = "#fff"; cardCtx.fillText(name, 105, 35); nameWidth = cardCtx.measureText(name).width; cardCtx.font = "bold 20px sans-serif"; cardCtx.fillText(address, 105, 60); cardCtx.fillText(job, 105, 85); addressWidth = cardCtx.measureText(address).width; jobWidth = cardCtx.measureText(job).width; if(maxWidth < nameWidth) { maxWidth = nameWidth; } if(maxWidth < addressWidth) { maxWidth = addressWidth; } if(maxWidth < jobWidth) { maxWidth = jobWidth; } // 繪製口號 var slogan = document.getElementById("slogan").value || "請輸入口號"; cardCtx.save(); // 做圖形變換 cardCtx.rotate(-0.1); cardCtx.translate(0, 50); // 陰影 cardCtx.shadowOffsetX = 10; cardCtx.shadowOffsetY = 10; cardCtx.shadowColor = 'rgba(0, 0, 0, 0.5)'; cardCtx.shadowBlur = 1.5; cardCtx.fillStyle = "#ddd"; // 計算口號位置 var solganWidth; solganWidth = cardCtx.measureText(slogan).width; var offset = (cardCtx.canvas.width - 115 - maxWidth - solganWidth) / 2; cardCtx.fillText(slogan, 115 + maxWidth + offset, 50); // 畫曲線 cardCtx.beginPath(); cardCtx.moveTo(115 + maxWidth + offset, 70); cardCtx.quadraticCurveTo(115 + maxWidth + offset, 50, 115 + solganWidth + maxWidth + offset, 60); cardCtx.strokeStyle = "#ddd"; cardCtx.stroke(); cardCtx.restore(); } // 觸發click事件 generateBtn.click(); // 建立和設定animCanvas,該canvas才是真正的顯示 var animCanvas = document.getElementById('animCanvas'); var animCtx = animCanvas.getContext('2d'); animCtx.canvas.width = 600; animCtx.canvas.height = 100; var circles = []; setInterval(function() { // 擦出畫布 animCtx.clearRect(0, 0, animCtx.canvas.width, animCtx.canvas.height); // 把離屏canvas的內容畫進來 animCtx.drawImage(cardCanvas, 0, 0, animCtx.canvas.width, animCtx.canvas.height, 0, 0, cardCtx.canvas.width, cardCtx.canvas.height); // 繪製下落的圓形 for(var i=0; i<=10; i++) { if(!circles[i]) { circles[i] = {}; circles[i].radius = Math.floor(Math.random() * 5) + 1; circles[i].y = - circles[i].radius - Math.floor(Math.random() * 10); circles[i].x = i * 60 + Math.floor(Math.random() * 10) - 5; circles[i].vy = Math.floor(Math.random() * 5) + 1; } animCtx.beginPath(); animCtx.arc(circles[i].x, circles[i].y, circles[i].radius, 0, Math.PI * 2); animCtx.fillStyle = "rgba(255, 255, 255, 0.5)"; animCtx.fill(); circles[i].y = circles[i].y + circles[i].vy; if(circles[i].y > animCtx.canvas.height + circles[i].radius * 2) { circles[i] = undefined; } } }, 100);
案例:山中明月風景圖
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> <style> canvas{background-color:#000;opacity:0.7} </style> </head> <body> <canvas id="canvas" width="720px" height="600px">您的瀏覽器不支援canvas</canvas> <script> var canvas=document.getElementById("canvas"); var context=canvas.getContext("2d"); // 月亮繪製 context.shadowOffsetX=10; context.shadowOffsetY=10; context.shadowBlur=5; context.shadowColor='rgba(255,255,255,0.2)'; context.fillStyle='yellow'; context.arc(100,100,40,0,Math.PI*2,true); context.fill(); // 文字繪製 context.beginPath(); var str='山高月小'; context.font='50px 宋體'; context.fillStyle='#fff'; context.shadowColor='rgba(255,255,255,0.4)'; context.fillText(str,400,200); // 山峰繪製 context.beginPath(); context.lineWidth=5; context.strokeStyle='lightblue'; context.moveTo(14, 600); context.quadraticCurveTo(60, 193, 123, 600); context.stroke(); context.beginPath(); context.moveTo(298, 600); context.bezierCurveTo(81, 193, 73, 691, 100, 600); context.stroke(); context.beginPath(); context.moveTo(500, 600); context.bezierCurveTo(451, 34, 273, 361, 298, 600); context.stroke(); context.beginPath(); context.moveTo(452, 600); context.bezierCurveTo(569, 210, 695, 426, 715, 600); context.stroke(); </script> </body> </html>