创建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>