包括:
介紹。
基礎入門。(兼容性。獲取canvas上下文。繪製直線/描邊,填充內容。繪製表格。)
canvas是基於狀態的繪圖。
繪製矩形。
繪製圓形。
繪製文本。
繪製圖片。
陰影。
漸變。
繪製背景圖。
變換。
介紹:
HTML5的新標籤<canvas></canvas>
canvas標籤經過JavaScript在網頁上繪製圖像,自己不具有繪圖功能。
canvas擁有多種繪製路徑,矩形,圓形,字符以及添加圖像的方法。
canvas能夠作遊戲,圖表,廣告等等。
基礎入門。
設置canvas的寬和高是經過canvas標籤的屬性來設置,不要用css設置。 css
<canvas id="canvas" width="400" height="400"></canvas>
還能夠在JS中經過屬性指定。 html
var canvas = document.getElementById('canvas'); //獲取canvas標籤 canvas.width=400; canvas.height=400;
兼容性。
當瀏覽器不支持canvas時,在canvas標籤內編寫提示文字。
web
<canvas>你的瀏覽器不支持canvas,請更換瀏覽器後再試。</canvas>
(當瀏覽器支持canvas時,canvas會執行相關JS代碼)
獲取canvas上下文。
canvas上下文就是繪製工具的集合。
寫在canvas標籤後,或者window.onload = function(){}
json
var canvas = document.getElementById('canvas'); //獲取canvas標籤 var ctx= canvas.getContext('2d'); //獲取canvas的上下文 3D=>'webgl'
獲得canvas上下文後就能夠開始繪製了。
canvas的座標系和瀏覽器的座標系一致。都是左上角爲(0,0)。
繪製直線/描邊,填充內容。 canvas
ctx.moveTo(100,100); //畫筆移動到(100,100) ctx.lineTo(200,100); //畫一條直線到(200,100) ctx.lineTo(100,200); //畫一條直線到(100,200) //到此爲止,只繪製了路徑,還沒描線。 ctx.stroke(); //描線。
將路徑閉合。 瀏覽器
ctx.moveTo(100,100); //畫筆移動到(100,100) ctx.lineTo(200,100); //畫一條直線到(200,100) ctx.lineTo(100,200); //畫一條直線到(100,200) ctx.lineTo(100,100); //畫一條直線到(100,100) ctx.stroke(); //描線。
還可使用ctx.closePath()來閉合路徑。 dom
ctx.moveTo(100,100); //畫筆移動到(100,100) //必需要寫moveTo(),不然畫筆沒有位置。 //沒有寫moveTo()直接寫lineTo()的話,畫筆的位置直接到lineTo()的位置,至關於moveTo() ctx.lineTo(200,100); //畫一條直線到(200,100) ctx.lineTo(100,200); //畫一條直線到(100,200) ctx.closePath() //閉合路徑 ctx.stroke(); //描線。
都是同樣的效果:
修改描邊的樣式。在stroke()描邊以前設置描邊樣式。 工具
ctx.lineWidth = 4; //線寬 ctx.strokeStyle = 'red'; //顏色
填充內容。默認是黑色。修改填充的樣式。 動畫
ctx.fill(); ctx.fillStyle = 'blue'; //顏色
問題:填充後,爲何描邊變細?
答案:描邊是2像素在裏面2像素在外邊。填充後,裏面的2像素被遮蓋住了。
繪製表格。 webgl
var rectH = 10; //行高 var rectW = 10; //列寬 //繪製橫線: for(var i = 0;i< canvas.width / rectH;i++){ ctx.moveTo(0,i*rectH); ctx.lineTo(canvas.width,i*rectH); //繪製豎線 for(var j = 0;j<canvas.height / rectW;j++){ ctx.moveTo(j*rectW,0); ctx.lineTo(j*rectW,canvas.height); } } ctx.lineWidth = 0.5; ctx.strokeStyle = '#ccc'; ctx.stroke();
在這基礎上就能夠繪製折線圖了。
繪製箭頭的思路:
繪製數據的思路:
var x0 = 100,y0 = 500; var maxHeight = 300; var arrowWidth = 10;// 箭頭寬度 // 繪製x軸 ctx.beginPath(); ctx.strokeStyle = "blue"; ctx.moveTo(x0, y0); ctx.lineTo(500, 500); // 箭頭 ctx.lineTo(500-arrowWidth, 500-arrowWidth); ctx.moveTo(500, 500); ctx.lineTo(500-arrowWidth, 500+arrowWidth); ctx.stroke(); //繪製y軸 ctx.beginPath(); ctx.strokeStyle = "purple"; ctx.moveTo(x0, y0); ctx.lineTo(100, 100); // 箭頭 ctx.lineTo(100-arrowWidth, 100+arrowWidth); ctx.moveTo(100, 100); ctx.lineTo(100+arrowWidth, 100+arrowWidth); ctx.stroke(); // 繪製線段 var data = [.4 ,.5 ,.8 ,.7]; var pointWidth = 400 / (data.length + 1); ctx.beginPath(); ctx.strokeStyle = "red"; for(var i=0;i<data.length;i++){ var x =x0 +(i + 1) * pointWidth; var y =y0 - data[i] * maxHeight; ctx.lineTo(x, y); } ctx.stroke();
canvas是基於狀態的繪圖。
好比繪製兩條不一樣顏色的直線。
ctx.strokeStyle = 'red'; ctx.lineWidth=5; //第一條線 ctx.moveTo(100,100); ctx.lineTo(300,100); ctx.stroke(); //第二條線 ctx.strokeStyle = 'blue'; ctx.moveTo(100,200); ctx.lineTo(300,200); ctx.stroke();
問題:兩條線顏色爲何同樣?
解決方法:canvas是基於狀態的繪圖。設置ctx.beginPath()便可。
//第二條線 ctx.beginPath(); ctx.strokeStyle = 'blue'; ctx.moveTo(100,200); ctx.lineTo(300,200); ctx.stroke();
beginPath()至關於開啓新狀態。
繪製第一條線的時候也能夠beginPath(),默認一開始就有狀態。
繪製第二條線的新狀態,能夠繼承以前的狀態的樣式,可是當前的狀態設置的全部樣式,只能做用於當前的狀態。
繪製矩形。
繪製矩形:ctx.rect(x,y,w,h); //左上角座標(x,y),w寬,h高。
ctx.rect(50,50,50,50); ctx.stroke(); ctx.strokeRect(120,120,50,50); //和上面寫法的效果一致。 ctx.fillRect(190,190,50,50); //若是是fill(填充),會自動閉合路徑。
清除矩形:至關於橡皮擦。
ctx.clearRect(x,y,w,h);
ctx.clearRect(195,195,30,30);
繪製圓形。
ctx.arc(x,y,r,startAngle,endAngle,counterclockwise); //圓心座標(x,y),半徑r,開始弧度,結束弧度,順時針/逆時針(默認順時針如圖)
換算公式:rad = deg*Math.PI/180;
繪製0-30°的圓弧。
ctx.arc(100,100,100,0,30*Math.PI/180,false);
加上closePath()會閉合路徑。
若是要鏈接到圓心點。先moveTo(圓心點)便可。
ctx.moveTo(100,100) ctx.arc(100,100,100,0,30*Math.PI/180,false); ctx.closePath(); ctx.stroke();
繪製餅狀圖的其中一個扇形。
ctx.moveTo(200,200); ctx.fillStyle = 'red' ctx.arc(200,200,100,-90*Math.PI/180,-30*Math.PI/180,false); ctx.fill()
假設有這樣一個JSON數據。
var data =[{ "value":.2, "color":"red", "title":"應屆生" },{ "value":.3, "color":"blue", "title":"社會招生" },{ "value":.4, "color":"green", "title":"推薦" },{ "value":.1, "color":"yellow", "title":"公開課" }];
將數據變成餅狀圖。
value表明佔比。從-90°開始繪製。
//先畫扇形。 var tempAngle = -90; //從-90度開始 var x0 = 150,y0 = 150,radius = 100; //圓心和半徑 for(var i=0;i<data.length;i++){ ctx.beginPath(); ctx.moveTo(x0,y0); //圓心 var angle = data[i].value*360; //當前扇形的角度 ctx.fillStyle = data[i].color; var startAngle = tempAngle * Math.PI/180; //開始角度 var endAngle = (tempAngle + angle) * Math.PI/180; //結束角度 ctx.arc(x0,y0,radius,startAngle,endAngle) ctx.fill(); tempAngle+=angle; }
繪製文本。
ctx.strokeText('hello',450,400); //文字,座標
ctx.fillText('hello',150,100);
ctx.moveTo(300,300); ctx.fillStyle = 'purple'; ctx.font = '20px 微軟雅黑'; ctx.textBaseline = "bottom"; //基線 ctx.textAlign = "left"; // ctx.strokeText('hello',450,400); //空心文字 ctx.fillText('hello',100,300); //實體填充文字
行高行距的概念:
對齊方式:
餅狀圖的文字。假設,在角度的一半繪製一條直線出來,寫上XX%,思路如圖。
繪製完餅狀圖後,fill前。繪製文字。
// 繪製文字 var txt = data[i].value * 100 +'%'; var x,y; var textAngle = tempAngle + 1/2 *angle; x=x0+Math.cos(textAngle * Math.PI / 180) * (radius + 20); y=y0+Math.sin(textAngle * Math.PI / 180) * (radius + 20); // 左側文字太長會越過餅狀圖。 if(textAngle>90&&textAngle<270){ ctx.textAlign = "end" } ctx.fillText(txt,x,y);
文字會超過:
文字不會超過:
ctx.measureText() //measure測量;返回文本的寬度
繪製圖片:
ctx.drawImage(img,x,y); //img是圖片的DOM對象。 繪製的座標。
// 建立圖片的dom對象 var img = new Image(); img.src='img.jpg'; //只要設置了src屬性,當前img對象當即去加載圖片。 img.onload = function(){ // 圖片加載完成後,繪製圖片 ctx.drawImage(img,100,100); }
以上的img和如下的方法得到的img是同樣的,都是dom對象。
var img2 = document.getElementById('imagedemo');
惡搞✧(≖ ◡ ≖✿)
for(var i=0;i<10;i++){ ctx.drawImage(img,100+i*10,100+i*10); }
還能夠設置寬高,不設置的時候是圖片的默認寬高。
ctx.drawImage(img,x,y,w,h); //w,h,寬高。
ctx.drawImage(img,100,100,50,50);
被拉伸:
若是要保持寬高比,則 原來的高度 / 原來的寬度 = 繪製的高度 / 繪製的寬度 。
假設已知繪製的寬度,則繪製的高度爲 原來的高度*繪製的寬度/原來的寬度。
var ow = img.width; var oh = img.height; ctx.drawImage(img,100,100,200,200*oh/ow);
繪製圖片裁剪區域。
ctx.drawImage(img,sx,sy,sw,sh,x,y,w,h) //截取的座標。截取的寬高。繪製的座標。繪製的寬高。
好比:網上找的一張圖:截取出第一我的物:
ctx.drawImage(img,195,26,276,377,100,100,200,300);
逐幀動畫/序列幀動畫:定時器。
先作第一行的動做。
var frameIndex = 0; //幀數 setInterval(function(){ // 清除以前的內容 ctx.clearRect(0, 0, canvas.width, canvas.height); // 若是經過代碼從新設置canvas畫布的寬高,canvas畫布裏的全部內容都被清空。(不建議使用) //canvas.width = canvas.width; ctx.drawImage( img, frameIndex*53.25, //截取的座標 0, //截取的座標 53.25, //截取的寬 92.75, //截取的高 200, //繪製的座標 200, //繪製的座標 53.25*2, //繪製的寬 92.75*2 //繪製的高 ) frameIndex++; frameIndex%=4; //取餘 4%4=0 },1000/10); //1秒10幀。
添加四個方向的按鈕。
<button id="btn-left">left</button> <button id="btn-right">right</button> <button id="btn-top">top</button> <button id="btn-down">down</button>
var btnLeft = document.getElementById('btn-left') var btnRight = document.getElementById('btn-right') var btnTop = document.getElementById('btn-top') var btnDown = document.getElementById('btn-down')
在繪製圖片前(new Image()前)。設置方向。至關於圖片的第一行。表明向下走。
var dirIndex = 0;
而後將截取的y座標改成dirIndex*92.75,綁定相關的按鈕事件。
btnLeft.onclick = function(){ dirIndex =1 ; //第2行 } btnRight.onclick = function(){ dirIndex =2 ; //第3行 } btnTop.onclick = function(){ dirIndex =3 ; //第4行 } btnDown.onclick = function(){ dirIndex =0 ; //第1行 }
點擊效果:
陰影
// 設置陰影 ctx.fillStyle = 'red'; ctx.shadowColor = 'teal'; //顏色 ctx.shadowBlur = 10; //模糊 ( 大於1 ) ctx.shadowOffsetX = 10; //偏移 ctx.shadowOffsetY = 10; ctx.fillRect(100,100,100,100);
漸變
// 線性漸變 var grd = ctx.createLinearGradient(0, 0, 170, 0); grd.addColorStop(0,"black"); grd.addColorStop(0.5,"red"); grd.addColorStop(1,'white'); ctx.fillStyle = grd; ctx.fillRect(0, 0, 300, 300);
// 圓形漸變 var rlg = ctx.createRadialGradient(300, 300, 10, 300, 300, 200); rlg.addColorStop(0,"white"); rlg.addColorStop(0.5,"red"); rlg.addColorStop(1,'black'); ctx.fillStyle = rlg; ctx.fillRect(100, 100, 400, 400);
繪製背景圖
var pat = ctx.createPattern(img,repeat); //img是DOM對象 ctx.rect(0, 0, 150, 100); ctx.fillStyle = pat; ctx.fill();
變換
ctx.scale(Scale Width, Scale Height); //縮放當前繪圖 1爲100% ctx.translate(X, Y); //位移畫布 ctx.rotate(Rotate Angle); //旋轉當前繪圖 ctx.save(); //保存當前環境的狀態 ctx.restore(); //返回以前保存過的路徑狀態和屬性 ctx.globalAlpha = "Value between 0 & 1"; //繪製環境的透明度
例子:
// 狀態1 ctx.fillStyle = "red"; ctx.fillRect(10, 10, 100, 100); ctx.save(); //保存狀態 ctx.translate(200, 200); //把當前畫布移動到200,200的位置 ctx.rotate(30* Math.PI / 180); //旋轉 ctx.scale(2, 2); //縮放 ctx.globalAlpha = ".3"; //透明度 ctx.moveTo(0, 0); ctx.lineTo(400, 0); ctx.moveTo(0, 0); ctx.lineTo(0, 400); ctx.stroke(); ctx.fillRect(10, 10, 40, 40); ctx.restore(); //返回以前保存過的路徑狀態和屬性 ctx.fillRect(400, 400, 100, 100);