SVG是構建XML樹的方式來達到繪制圖形的,canvas是通過調用相關的方法來繪制圖形的。
區別:SVG繪制圖形,通過移除或者更改DOM方式來而使用canvas需要把圖片從新擦除。
繪制的API在繪制上下文中定義。而不在畫布中定義。
需要獲得上下文對象的時候,需要調用畫布的getContext方法,獲得繪畫的上下文。
畫布元素和上下文,屬于兩個不同的對象,其中畫布元素為canvas畫布,而上下文對象為繪制需要的上下文。
關于3D圖形,即,webGL 為封裝了基本的OPENGL,當調用webGL的時候,其瀏覽器會調用OpenGL相關的API
<!DOCTYPE html> <html lang="zh_CN" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div>第一個園</br> <canvas id="square" width="10" height="100"> </canvas> </div> <div> 第二個園 <canvas id="circle" width="10" height="10"> </canvas> </div> <script src="./js/index.js" charset="UTF-8"></script> </body> </html> // 獲取畫布元素 let canvas = document.getElementById("square"); // 獲取繪制2D元素上下文 let context = canvas.getContext("2d"); // 設置填充顏色為紅色 context.fillStyle = "#f00"; // 填充一個正方形 context.fillRect(10,0,10,10);
// 獲取畫布元素
let canvas = document.getElementById("square");
// 獲取繪制2D元素上下文
let context = canvas.getContext("2d");
// 開始一條路徑
context.beginPath();
// 從100,100 開始定義一條新的子路徑
context.moveTo(100,100);
// 從100 100 到 200 200 繪制一條線段
context.lineTo(200,200);
// 從200 200 到 100 200 繪制一條線段
context.lineTo(100,200);
// 從100 200 到 100 100 繪制一條路徑
context.lineTo(100,100);
// 繪制邊
context.stroke();
// 進行填充
context.fill();
以五邊形為例子,
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 繪制一個以100,100為中心,半徑為20的柜子N變形,每個定點均勻分布在圓角上,第一個定點放置在最上下 // 偏轉角度為0 // 開始定義一條子路徑 context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0)); // 計算兩個頂點之間夾角 // 其中2π為一個園,除以邊數,得到需要旋轉的角度 var delta = 2 * Math.PI/5; console.log(delta); // 循環剩余每個頂點 var angle = 0; for(var i = 1; i < 5; i++){ // 角度累加 angle += delta; // 通過旋轉繪制下一個頂點,不斷的旋轉繪制 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle)); } // 最后一個頂點和起點進行連接 context.closePath(); // 從新開始一條新路徑 context.stroke(); context.fill();
同理,畫圓
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 繪制一個以100,100為中心,半徑為20的柜子N變形,每個定點均勻分布在圓角上,第一個定點放置在最上下 // 偏轉角度為0 // 開始定義一條子路徑 context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0)); // 計算兩個頂點之間夾角 // 其中2π為一個園,除以邊數,得到需要旋轉的角度 var delta = 2 * Math.PI/500000; console.log(delta); // 循環剩余每個頂點 var angle = 0; for(var i = 1; i < 500000; i++){ // 角度累加 angle += delta; // 通過旋轉繪制下一個頂點,不斷的旋轉繪制 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle)); } // 最后一個頂點和起點進行連接 context.closePath(); // 從新開始一條新路徑 context.stroke(); context.fill();
非零繞數原則
要檢測一個點p是否在路徑內部,使用非零繞數原則,即,一條從點p出發沿著任意方向無限延伸,或者一直延伸到路徑所在的區域外某點的射線,現在從0開始初始化一個計數器,對穿過這條射線的路徑進行枚舉,每當一條路徑順時針方向穿過射線的時候,計數器加1,逆時針減1,最后,枚舉完所有路徑以后,如果計時器的值不是0,那么就認為p在路徑內,反過來,計數器的值為0,p在路徑外。
js根據非零繞數原則確定那個在路徑內,那個在路徑外,用于進行填充。
可以通過設置畫布上下文的fillStyle等屬性,設置圖形的屬性,例如對畫布上下文的fillStyle的屬性進行設置,即,可以設置出填充時的顏色,漸變,圖案等樣式。
對于canvas來說,每次獲取上下文對象的時候,都會返回同一個上下文對象,即,上下文對象為單例的。
還可以使用save方法,把當前的狀態,壓入已經保存的棧中,調用restore方法,把狀態進行恢復,即彈棧。
畫布的默認的坐標系為左上角的坐標原點(0,0),右邊數值大,下數值大,使用浮點數指定坐標,但不會自動轉換為整數,會用反鋸齒的方式,模擬填充部分元素。
畫布尺寸不能隨意改變,對任意屬性進行操作,都會清空整個畫布。
每一個點的坐標都會映射到css像素上,css像素會映射到一個或多個設備像素。
畫布中的特定操作,屬性使用默認坐標系。
畫布還有當前變換矩陣。
畫布還有當前變換矩陣,當前變換矩陣作為圖形狀態的一部分。矩陣定義了當前畫布的坐標系。
畫布的操作會把該點映射到當前的坐標系中。
坐標變換
當調用c.translate(dx,dy)方法的時候,會進行如下變換
translate會進行坐標的上下移動
x' = x + dy; y' = y + dy;
縮放
如要進行縮放,進行的是如下的變換
x' = sx * x; y' = sy * y;
進行旋轉操作,進行的是如下變換
x' = x * cos(a) - y * sin(a); y' = y * cos(a) - x * sin(a);
如果要先變換再伸縮,進行如下變換
需要先把現有坐標系映射成為坐標系中的點x’, y’ 然后再變換到x‘’ , y‘’
x'' = sx*x + dx; y'' = sy*y + dy;
如果變換順序相反進行如下變換
x'' = sx*(x + dx); y'' = sy*(y + dy);
這種變換稱為仿射變換,并且仿射變換會修改點的距離和線段間的夾角。對于平行線來說,仿射變換也會保持平行。仿射變換用6個參數描述成為如下表述
x' = ax + cy + e; y' = bx + dy + f;
通過傳入參數實現仿射變換
對于坐標變換來說,除非進行刷新,否則,已經繪制的圖形,不會進行消失,所有的變換,都不能對已經繪制的圖形進行更改。栗子如下
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 通過坐標變換實現科赫雪花 // 開始一條路徑 context.beginPath(); // 開始繪制子路徑 context.moveTo(100,100); // 繼續繪制 context.lineTo(200,200); // 繼續繪制 context.lineTo(200,200); // 進行繪制邊 context.stroke(); context.translate(200,200); // 開始一條路徑 context.beginPath(); // 開始繪制子路徑 context.moveTo(100,100); // 繼續繪制 context.lineTo(200,200); // 繼續繪制 context.lineTo(200,200); // 進行繪制邊 context.stroke();
已經繪制的圖形不會進行改變,改變的是已經繪制的圖形
var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 通過坐標變換實現科赫雪花
// 當前狀態入棧
function leg(n) {
// 保存狀態
context.save();
// 遞歸畫
if(n == 0){
context.lineTo(50, 0);
}else{
// 定義為v字型
context.scale(1/2,1/2);
// 遞歸第一條
context.rotate(60 * (Math.PI / 180));
leg(n - 1);
context.rotate(-120 * (Math.PI / 180));
leg(n - 1);
}
// 坐標恢復變換
context.restore();
// 恢復下一個坐標為0,0
context.translate(50, 0);
}
context.save();
context.moveTo(50, 50);
// 繪制第一條
leg(1);
context.stroke();
繪制一些常見的圖形
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 工具函數,角度轉弧度 function rads(x) { return Math.PI * x / 180; } // 繪制園 context.beginPath(); context.arc(100,100,40, 0, rads(360), false); context.stroke(); context.fill();
同理繪制貝塞爾曲線也是同理。
繪制一個漸變
需要使用createLinearGradient獲取一個進行漸變的上下文,對這個上下文進行處理。然后其顏色設置為這個漸變的上下文,即,fillStyle屬性。
封頂
對于線段,有三種封頂方式,即,butt,square,round
在繪制圖形以后,會參數尖角,圓角,平角,三種。
lineCap屬性
和css類似,基線問題。
直接調動clip即可,當前路徑也會被裁剪進入,路徑外的統統不會顯示。
設置shadow屬性即可
畫布API支持位圖圖片,同時也支持canvas導出成為圖片。
// 創建一個img元素 let img = document.createElement("img"); // 設置src屬性 img.src = canvas.toDataURL(); // 追加到文檔后面 document.body.appendChild(img);
一些api不在闡述
調用getImageDate方法返回ImageDate對象
使用createImageDate()可以創建像素容器
進行動態模糊先獲取像素的ImageDate對象,然后再獲取該對象的data屬性,該data為一個數組。為一個維數組。每四個元素代表紅色分量,綠色分量,藍色分量,透明度分量。(Alpha分量)
其色素直為0-1,即,數組元素中保存的數組為色素值。
每四個每四個元素遍歷。然后把其色素值的1/ n + 上一個色塊的m/n 然后賦值給新的色塊,代碼如下
// row為行數 for(var row = 0; row < height; row++){ // 獲得每行第二個元素的偏移量,其中width為行的色素塊。 var i = row * width * 4; // 每4個的色素值進行處理 for(var col = 1; col < width; col++, i+=4){ // 對紅色分量處理 data[i] = (data[i] + data[i - 4] * m) / n; // 對綠色分量處理 data[i + 1] = (data[i + 1] + data[i + 1 - 4] * m) / n; // 對藍色分量處理 data[i + 2] = (data[i + 2] + data[i + 2 - 4] * m) / n; // 對透明度分量處理 data[i + 3] = (data[i + 3] + data[i + 3 - 4] * m) / n; } }
然后把其色素塊進行復制回去即可。
其中每個像素占據一個字節,一個四個字節。
isPointInPath方法用來確定一個點是否落在當前路徑中。
即命中檢測。
命中檢測可以和鼠標事件相互轉化
但是坐標需要進行轉換。
TML5 的 canvas 元素使用 JavaScript 在網頁上繪制圖像。
畫布是一個矩形區域,您可以控制其每一像素。
canvas 擁有多種繪制路徑、矩形、圓形、字符以及添加圖像的方法。
下面是一個用 HTML5 的 canvas 繪制的 3D 玫瑰花。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>3D玫瑰花</title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
</head>
<body>
<div id="demo" style="width:520; height:500px;"><canvas id="c" height="500" width="500"></canvas></div>
<script>
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
document.body.clientWidth;
with(m=Math)C=cos,S=sin,P=pow,R=random;
c.width=c.height=f=500;h=-250;
function p(a,b,c){
if(c>60)
return[S(a*7)*(13+5/(.2+P(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a];
A=a*2-1;
B=b*2-1;
if(A*A+B*B<1){
if(c>37){
n=(j=c&1)?6:4;o=.5/(a+.01)+C(b*125)*3-a*300;
w=b*h;
return[o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0?w:-w))/25),30)*.1*(1-B*B),o/1e3+.7-o*w*3e-6]
}
if(c>32){
c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;
return[o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7]
}
o=A*(2-b)*(80-c*2);
w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))*50+c*2;z=o*S(c)+w*C(c)+700;
return[o*C(c)-w*S(c),B*99-C(P(b, 7))*50-c/3-z/1.35+450,z,(1-b/1.2)*.9+a*.1, P((1-b),20)/4+.05]
}
}
var draw = setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0);
var demo = document.getElementById('demo');
function redraw(){
/*
var d_c = document.createElement("canvas");
d_c.setAttribute("id","c");
d_c.setAttribute("width","520");
d_c.setAttribute("height","500");
demo.appendChild(d_c);
*/
draw = setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0);
//alert(d_c);
}
function clear_canvas()
{
ctx.clearRect(0,0,520,500);
//canvas.parentNode.removeChild(canvas); //刪除
}
function stop_draw(obj){
clearInterval(obj);
}
</script>
</body>
</html>
門可以通過啃書,但書本上的東西很多都已經過時了,在啃書的同時,也要持續關注技術的新動態。這里推幾本不錯的書:
《JavaScript高級編程》:可以作為入門書籍,但同時也是高級書籍,可以快速吸收基礎,等到提升再回來重新看
《JavaScript權威指南》:不太適合入門,但是必備,不理解的地方就去查閱一下,很有幫助
《編寫可維護的JavaScript》和:
《Node.js開發指南》:不錯的Nodejs入門書籍
《深入淺出Node.js》:Nodejs進階書籍,必備
《JavaScript異步編程》:理解JS異步的編程理念
《JavaScript模式》和《JavaScript設計模式》:JavaScript的代碼模式和設計模式,將開發思維轉變到JavaScript,非常好的書
《JavaScript框架設計》:在用輪子同時,應當知道輪子是怎么轉起來的,講解很詳細,從源碼級別講解框架的各個部分的實現,配合一個現有框架閱讀,可以學到很多東西
《Dont make me think》:網頁設計的理念,了解用戶行為,非常不錯
《CSS禪意花園》:經久不衰的一部著作,同樣傳遞了網頁設計中的理念以及設計中需要注意的問題
《高性能JavaScript》和《高性能HTML5》:強調性能的書,其中不只是性能優化,還有很多原理層面的東西值得學習
《HTML5 Canvas核心技術》:我正在讀的一本書,對于canvas的使用,動畫的實現,以及動畫框架的開發都非常有幫助
《HTTP權威指南》:HTTP協議相關必備,前端開發調試的時候也會經常涉及到其中的知識
《響應式Web設計》:技術本身不難,重要的是響應式網頁的設計理念,以及移動先行的思想
《JavaScript語言精粹》:老道的書,也是普及JavaScript的開發思維的一本好書,非常適合入門
一些不錯的網站
github:沒啥好說的,多閱讀別人的源碼,多上傳自己的源碼,向世界各地的大牛學習
codepen:感受前端之美的必選之地,里面有很多酷炫的效果和優秀的插件
echojs:快速了解js新資訊的網站
stackoverflow和segmentfault:基本上各種問題都能在上面獲得解答
google web fundamentals:每篇文章都適合仔細閱讀
static files:開放的CDN,很好用
iconfont:阿里的矢量圖標庫,非常不錯,支持CDN而且支持項目
html5 rocks: 一個不錯的網站,很多瀏覽器的新特性以及前沿的技術,都能在這上面找到文章
css tricks:如何活用CSS,以及了解CSS新特性,這里可以滿足你
JavaScript 秘密花園 JavaScript初學必看,非常不錯
w3cplus:一個前端學習的網站,里面的文章質量都挺不錯的
node school:一個不錯的node學習網站
learn git branch:一個git學習網站,交互很棒
前端亂燉:一個前端文章分享的社區,有很多優秀文章
正則表達式:一個正則表達式入門教程,非常值得一看
喜歡的可以收藏,希望能夠對你有所幫助
切圖網(qietu.com)專業從事web前端開發的公司,專注we前端開發,響應式布局,webapp手機端網頁制作,微信html5頁面制作,bootstrap布局等,關注用戶體驗。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。