canvas基礎第二節

一、圖形的組合方式

globalAlpha是一個介于0和1之間的值(包括0和1),用于指定所有繪制的透明度。默認值為0。如果所有后續操作都要基于相同的透明度,就可以先把globalAlpha設置為適當值,然后繪制,最后在把它設置回默認值0.

//繪制一個紅色的矩形

context.fillStyle="red";

context.fillRect(10,10,50,50);

//修改全局透明度

context.globalAlpha=0.5;

//繪制藍色矩形

context.fillStyle="blue";

context.fillRect(30,30,50,50);

//重置全局透明度

context.globalAlpha=0;

//這個例子中藍色矩形會呈現半透明效果,透過它可以看到下面的紅色矩形。

globalCompositionOperation表示繪制后的圖形怎樣與先繪制的圖形結合。這個屬性的值是字符串,可能的值如下:

source-over(默認值):后繪制的圖形位于先繪制的圖形上方。

source-in:后繪制的圖形與先繪制的圖形重疊的部分可見,兩者其他部分完全透明。

source-out:后繪制的圖形與先繪制的圖形不重疊的部分可見,先繪制的圖形完全透明。

source-atop:后繪制的圖形與先繪制的圖形重疊的部分可見,先繪制圖形不受影響。

destination-over:后繪制的圖形位于先繪制的圖形下方,后繪制的圖形只有之前透明像素下的部分才可見,被遮擋的部分不可見。

destination-in:后繪制的圖形位于先繪制的圖形下方,兩者不重疊的部分完全透明。就是顯示重疊的部分的形狀,顯示先繪制的圖形的顏色。

destination-out:后繪制的圖形擦除與先繪制的圖形重疊的部分。

destination-atop:后繪制的圖形位于先繪制的圖形下方,在兩者不重疊的地方,先繪制的圖形會變透明。

lighter:后繪制的圖形與先繪制的圖形重疊部分的值相加,使該部分變亮。(疊加的是顏色額)

copy:后繪制的圖形完全替代與之重疊的先繪制圖形。

xor:后繪制的圖形與先繪制的圖形重疊的部分執行“異或”操作;圖像異或,相異為1,相同為0.即重疊部分不顯示,不重疊部分顯示。

//畫目標圖

context.beginPath();

context.fillStyle="red";

context.fillRect(100,50,100,300);

//畫源圖

context.beginPath();

context.globalCompositeOperation="destination-out";

//context.globalCompositeOperation="xor";

context.fillStyle="blue";

context.arc(250,200,100,0, Math.PI*2);

目標圖像:已經放到畫布中的繪圖

源圖像:打算放置到畫布中的繪圖

在使用globalCompositionOperation的情況下一定要多測一些瀏覽器,因為不同的瀏覽器對這個屬性的實現仍然存在較大的差別。


二、使用圖片

//第一種寫法:第一個參數:圖片對象;第二個參數是開始畫的x坐標;第三個參數:開始畫的y的坐標;

//context.drawImage(img,0,0);

//第二種寫法:第一個參數:圖片對象;第二個參數:是開始畫的x坐標;第三個參數:開始畫的y的坐標;第四個參數:圖片繪制到canvas上的寬度;第五個參數:圖片繪制到canvas上的高度;

//context.drawImage(img,0,0,200,200);

//第三種寫法(裁剪):第一個參數:圖片對象;第二三個參數在原圖上要裁剪的起始x、y的坐標;第四、五個參數:在原圖上要裁剪的寬和高;第六、七個參數:要放到canvas畫布上的起始x、y坐標;第八九個參數:要到canvas畫布上的寬和高;

context.drawImage(img,100,100,100,100,50,50,300,300);

var ?canvas=document.getElementById("myCanvas");

var ? context=canvas.getContext("2d");

var ? img= newImage();

img.src="img/20150821130732_anQeR.jpeg";

img.onload=function(){

context.drawImage(img,100,100,100,100,50,50,300,300);

}

綜合使用drawImage( )和其他方法,可以對圖像進行各種基本操作。而操作的結果可以通過toDataURL( )方法獲得。不過有一個例外,即圖像不能來自其他域。如果圖像來自其它域,調用toDataURL( )會拋出錯誤。

canvas提供了toDataURL的接口,可以方便的將canvas畫布轉化成base64編碼的image。目前支持的最好的是png格式,jpeg格式的現代瀏覽器基本也支持,但是支持的不是很好。

//我們創建一個畫布,在上面做一些繪圖,然后試著把它保存為本地圖片。

var ?can = document.getElementById('canvas');


var ?ctx = can.getContext('2d');

var ? imgA = new Image();

imgA.src ='http://www.html5party.com/wp-content

/uploads/2013/09/css_yangshijiance.png';

imgA.onload = function() {

ctx.drawImage(imgA, -25, 0, imgA.width, imgA.height);

ctx.restore();

};

var ? imgB = new Image();

imgB.src = 'http://www.html5party.com/wp-content

/uploads/2013/09/canvas_chroma.png';

imgB.onload = function() {

ctx.globalAlpha = 0.1

ctx.drawImage(imgB, -100, -75, imgB.width, imgB.height);

ctx.restore();

};

function toImage(returnType) {

var dataURL = document.getElementById('canvas').toDataURL("image/png");

// The returnType argument specifies how to get the

// the image. ?'obj' will set the source to an image element.

// 'window' will open a new window and display the image.

// 'download' will prompt the user to save the image.

switch(returnType) {

case 'obj':

var imgObj = new Image();

imgObj.src = dataURL;

document.getElementById('graphics').appendChild(imgObj);

break;

case 'window':

window.open(dataURL, "Canvas Image");

break;

case 'download':

dataURL = dataURL.replace("image/png", "image/octet-stream");

document.location.href = dataURL;

break;

}

}

理想的狀態是頁面上有三個點擊鏈接:

1、Image Tag

點擊會有一張圖片插入在網頁中。

2、New Window

打開一個新的窗口,并顯示一個PNG格式的圖片

3、Download

下載保存一張PNG個格式的圖片

很不幸,點擊并沒有反映,為什么呢?筆者做了許多試驗,原因出在圖片渲染上,canvas上如果添加圖片,toDataURL()將失效,獲取不到canvas信息。通過簡單幾步來驗證這個問題。

把js腳本中圖片渲染的部分去除,A和B圖。為了便于觀察,在畫布上畫一個簡單的矩形,填充顏色:

ctx.fillStyle = 'Red';

ctx.strokeStyle = 'Green';

ctx.beginPath();

ctx.rect(20, 20, 100, 100);

ctx.stroke();

ctx.fill();

這樣畫布上便顯示為一個紅色矩形,格式為PNG



三、裁剪

var ?canvas=document.getElementById("myCanvas");

var ?context=canvas.getContext("2d");

//繪制一個三角形

context.beginPath();

context.moveTo(200,200);

context.lineTo(250,200);

context.lineTo(225,150);

context.closePath();

context.stroke();

//調用裁剪

context.clip();

var ?img= newImage();

img.src="img/20150821130732_anQeR.jpeg";

img.onload=function() {

context.drawImage(img,0,0);

}

//你上面畫的是什么形狀,裁剪出來的就是什么形狀


四、使用圖像數據

var ?canvas=document.getElementById("myCanvas");

var ? context=canvas.getContext("2d");

//getImageData()取的原始圖像數據

//有四個參數:第一二個參數,開始獲取像素的x,y坐標,第三四個參數,獲取像素點的寬高。

//var? ImageData=context.getImageData(0,0, img.width, img.height);

這里返回的對象是getImageData()的實例,每個getImageData()對象都有三個屬性:width、height、data。

width和height表示訪問像素區域大小

//其中data屬性是一個數組,保存著圖像中每一個像素的數據。

//在data數據中,每一個像素用4個元素來保存,分別代表紅、綠、藍和透明度。

//數組中的每個元素都是介于0和255之間的,能夠直接訪問到原始圖像數據,

//就能夠以各種方式來操作這些數據。

var ?img= newImage();

img.src="img/20150821130732_anQeR.jpeg";

img.onload=function() {

context.drawImage(img,0,0);

var ? ImageData=context.getImageData(0,0, img.width, img.height);

var ? data=ImageData.data;

//注意:每次循環控制變量i都遞增4,在取得每個像素的紅、綠、藍顏色值后,

//計算出他們的平均值,再把這個平均值設置為每個顏色的值,

//結果就是去掉了每個像素的顏色,只保留了亮度接近的灰度值.(用彩色變黑白)

for(var i=0; i<data.length; i+=4){

var ?r=data[i];

var ?g=data[i+1];

var ?b=data[i+2];

//求rgb的平均值,

var ?gray=(r+g+b)/2;

//設置顏色值

data[i]=gray;

data[i+1]=gray;

data[i+2]=gray;

}

//putImageData()方法把圖像數據繪制到畫布上,有三個參數

//第一個參數,獲取ImageData,第二三個參數,要放到畫布上的x,y坐標

context.putImageData(ImageData,0,0);

}


五、canvas視頻處理

function animation( ){

//video.ended 屬性返回音頻/視頻是否已結束。返回值:布爾值true|false。如果播放已結束,則返回 true。否則返回 false。

if(!video.ended){

//將視頻的每一幀,繪制在canvas上

context.drawImage(video,0,0,canvas.width,canvas.height);

window.requestAnimationFrame(animate);

}

}

//當視頻可以播放時,進行播放調用循環

//video的oncanplay事件類似于圖像的onload,加載完成之后

//oncanplay 事件在用戶可以開始播放視頻/音頻(audio/video)時觸發。

//object.oncanplay=function(){myScript};

//object.addEventListener("canplay",myScript);

video.oncanplay=function(e){

video.play( );

window.requestAnimationFrame(animate);

}


六、canvas動畫

最原始的你還可以使用window.setTimout()或者window.setInterval()通過不斷更新元素的狀態位置等來實現動畫,前提是畫面的更新頻率要達到每秒60次才能讓肉眼看到流暢的動畫效果。

window.requestAnimationFrame()通過遞歸調用同一方法來不斷更新畫面以達到動起來的效果,但它優于setTimeout/setInterval的地方在于它是由瀏覽器專門為動畫提供的API,在運行時瀏覽器會自動優化方法的調用,并且如果頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷。

取消該次動畫:可以直接調用,也可以通過window來調用,接收一個函數作為回調,返回一個ID值,通過把這個ID值傳給window.cancelAnimationFrame()可以取消該次動畫。

window.requestAnimationFrame()方法用于告訴瀏覽器,你想在瀏覽器的下個重繪 之前來執行一個動畫或者執行瀏覽器通過調用一個特定的函數來更新動畫的請求。該方法會在下次重回之前執行一個作為參數的回調函數。

window.requestAnimationFrame 是專門為實現高性能的幀動畫而設計的一個API,目前已在多個瀏覽器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移動設備上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,唯一比較遺憾的是目前安卓上的原生瀏覽器并不支持requestAnimationFrame,不過對requestAnimationFrame的支持應該是大勢所趨了,安卓版本的chrome 16+也是支持requestAnimationFrame的。

例子window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;


七、實現多個小球隨機運動,用面向對象的方法

var ? canvas=document.getElementById("myCanvas");

var ? context=canvas.getContext("2d");

//圓是一個類,就是對象只有一個,就是圓

functionCircle(x,y,r,speedX,speedY,color) {

//所有的屬性

this.r=r;

this.x=x;

this.speedX=speedX;

this.speedY=speedY;

this.y=y;

this.color=color;

}

//在原型上寫方法,

//第一個方法,畫圓

Circle.prototype.draw=function() {

context.beginPath();

context.fillStyle=this.color;

context.arc(this.x, this.y, this.r,0, Math.PI*2);

context.fill();

}

//第二個方法,運動

Circle.prototype.move=function() {

//這里改變x遞加的值,可以改變運動速度

this.x+=this.speedX;

this.y+=this.speedY;

if(this.x>=canvas.width-this.r||this.x<=this.r) {

this.speedX*= -1;

}

if(this.y>=canvas.height-this.r||this.y<=this.r) {

this.speedY*= -1;

}

}

//進行實例化操作

//實現同時出現多個小球,需要同時實例化出多個對象

//儲存new出來的實例化對象數組

var ? arr=[ ];

//來很多個小球

for(var ?i=0; i<100; i++) {

//設置一個隨機的半徑

var ? R=randomNum(30,5);

//隨機位置

var ? X=randomNum(canvas.width-R, R);

var ? ?Y=randomNum(canvas.height-R, R);

//隨機速度

var ? speedX=randomNum(8,1);

var ? ?speedY=randomNum(8,1);

//隨機顏色

var ? ? COLOR="rgb("+randomNum(255,0)+","+randomNum(255,0)+","+randomNum(255,0)+")";

//將對像實例化

var ? ?newCircle= newCircle(X, Y, R, speedX, speedY, COLOR);

arr.push(newCircle)

}

moveCircle();

//定義一個執行動畫的函數

function ? ?moveCircle() {

//先清理畫布

context.clearRect(0,0, canvas.width, canvas.height);

//循環執行實例化對象的數組

for(var ?i=0; i<arr.length;i++){

arr[i].draw();

arr[i].move();

}

//執行動畫

window.requestAnimationFrame(moveCircle);

}

//定義一個隨機數的函數

functionrandomNum(max,min) {

returnparseInt(Math.random()*(max-min+1)+min);

}


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標簽 ②:HTML5 ...
    GreenHand1閱讀 4,702評論 2 32
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標簽 Canvas是一個矩形區...
    J_L_L閱讀 1,532評論 0 4
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標簽 Canvas是一個矩形區...
    Looog閱讀 3,946評論 3 40
  • 啥是canvas? HTML5 標簽用于繪制圖像(通過腳本,通常是 JavaScript)。不過, 元素本身...
    kiaizi閱讀 782評論 0 4
  • 最基本的使用創建一個畫布所有的操作都在畫布的context上面canvas是基于狀態而不是基于對象的,比如說顏色都...
    親愛的孟良閱讀 1,666評論 0 4