摘要:關于這兩個的細節直接參考文檔像素操作基于像素的可以實現針對單個像素的操作,這也是畫布底層的,通過調用方法將返回一個對象,該對象表示畫布中原始的像素信息,通過調用方法也可以創建一個空的對象,最后方法將處理后的像素輸出到畫布中。
過個年一下荒廢了個把月。 最近剛接觸canvas,將一些概念點簡單歸納下,canvas是基于像素的圖像API,與svg的最大的區別在于canvas需要重繪(canvas移除圖片時需要重新繪制,而SVG可以通過編輯元素節點來編輯圖片),并且基于基于像素繪制(svg顧名思義是矢量),更詳細的對比mark在此:?SVG 與 HTML5 的 canvas 各有什么優點 而且我個人認為雖然canvas的API也很復雜,但是svg更復雜,囧rz。以下是我將我接觸canvas過程中認為需要厘清的概念點歸納如下。
基礎結構canvas元素本身沒有任何外觀,它就是一塊空白畫板,提供給JS的一套API,最早由Safari引入,IE9之前可以使用一些類庫在IE中模擬canvas,大部分的API都不在canvas元素自身定義,canvas元素自身屬性與常規的HTML元素并沒有多大區別, 它的繪圖API都定義在一個CanvasRenderingContext2D對象上(這里簡單翻譯成上下文對象),該對象通過getContext()方法獲得,代碼示例:
坐標系demo
無任何坐標系變化的圖像繪制:
translate()方法將坐標原定移動到(20,20)后得到當前坐標系后的繪制
了解這點后setTransform()也很容易,該方法影響的是默認坐標系,也就是說它并非將原點移來移去,而是重置當前坐標系,定義一個新的默認坐標系,什么叫影響默認坐標系,比如說前面的translate()所移動的坐標原點(0,0)還是初始的默認坐標系,而現在setTransform()所影響的就是這個原點(0,0)的坐標系,還是之前的demo,當加入ctx.setTransform(1,0.5,-0.5,1,30,10)這條語句后,圖像繪制將變成:
這是因為setTransform()將默認坐標系重新定義了,于是translate()基于新的默認坐標系來得到當前坐標系。理解了這兩個概念也就掌握了canvas中坐標系的變換。
setTransform()與transform()方法setTransform()這個API略復雜, 它所接受的參數與transform()(使用transform()可直接得到一個變換結構,可代替rotate()等方法,并且更為靈活)一樣為6個參數,setTransform(a,b,c,d,e,f) 而坐標系變化的原理就是通過與這6個參數進行以下運算后得出的:
x" = ax + cy +e
y" = bx + dy +f
這種坐標系變換也被稱為仿射變換(affine transform),關于該變換的栗子可參考這兩篇博客:
?Html5 Canvas 變換矩陣與坐標變形之間的關系
路徑是繪制所有圖形的基礎,不同于SVG中path使用屬性M,L,A等控制的XML文檔,canvas調用上下文對象的方法來完成路徑的繪制,調用beginPath()開始一段新路徑,每段路經又有子路徑,正是依靠這些子路徑使得圖形成形。調用beginPath()后調用MoveTo()開始一段子路徑。繪制完成后使用closePath()閉合路徑,從而形成一個閉合區域,這時候就可以使用fill()等方法填充該區域了。每次開始一段新路徑的繪制必須再次調用beginPath(),否則新繪制的路徑將作為之前路徑的子路徑繼續繪制。
類似于lineTo()是最簡單的直線段路徑方法, canvas還提供了bezierCurveTo()和quadraticCurveTo()這些復雜的曲線路徑方法,非常復雜,所以估計一般這種操作還是先找輪子解決。
另外需要注意的是,當一條路徑的兩條子路徑不相交的時候(比如繪制一個鏤空的圖形),畫布將采用“非零繞數原則”判斷某點是在路徑內還是路徑外, 這樣以便于填充的時候區別哪些區域是需要填充的。
有關非零繞數原則的原理可以參考這里:mark? 非零環繞數規則和奇-偶規則
canvas的圖像狀態canvas的屬性與方法與我們面向對象中的屬性方法并沒有太大區別,只是這里涉及到了一個圖像狀態的概念。在canvas中,無法通過getContext()方法獲得多個上下文(context)對象,而圖像屬性都是基于canvas的上下文對象,也就是說無法同時擁有兩個屬性。形象地比喻就是圖像屬性就像畫筆, 粗細,大小,顏色。由于同一時間只能有一個上下文對象所以只能同一時間使用一支畫筆。這時候當需要其它的圖像屬性(另一支畫筆)的時候就只能通過保存當前圖像狀態,然后新建一個圖像狀態來切換。
這時候就需要借助save()和restore()來切換圖像狀態,每次save()都將保存當前圖像狀態,圖像狀態包括當前的圖像屬性,當前坐標系,裁剪區域等信息。比如以下demo以兩種顏色畫線:
直接在demo中修改代碼觀察圖像狀態demo
JS代碼:
var canvas = document.getElementById("square") var ctx = canvas.getContext("2d") ctx.beginPath() ctx.strokeStyle = "red" ctx.moveTo(0,0) ctx.lineTo(100,20) ctx.stroke() ctx.save()//保存當前圖像狀態(畫筆) ctx.beginPath() ctx.strokeStyle = "blue" ctx.moveTo(0,0) ctx.lineTo(100,40) ctx.stroke() ctx.restore()//恢復到最近保存圖像狀態(畫筆) ctx.beginPath() ctx.moveTo(0,0) ctx.lineTo(100,60) ctx.stroke()
輸出如下:
這些圖像屬性包括:
fillStyle
font
globalAlpha
globalCompositeOperation
lineCap
lineJoin
lineWidth
miterLimit
textAlign
textBaseline
shadowBlur
shadowColor
shadowOffsetX
shadowOffsetY
strokeStyle
canvas背景一般的純色背景填充可以使用fillStyle屬性,但是當涉及更復雜的圖片或者漸變色填充就需要CanvasPattern和CanvasGradient對象了,可以通過creatPattern()方法得到CanvasPattern,這里需要注意的是該API不僅可以代入一般的圖片,也可以使用canvas元素,比如畫面外一個不可見的canvas元素用于插入。
關于這兩個API的細節直接參考文檔:
?CanvasPattern
?CanvasGradient
基于像素的canvas可以實現針對單個像素的操作,這也是畫布底層的API,通過調用getImageData()方法將返回一個ImageData對象,該對象表示畫布中原始的RGBA像素信息,通過調用creatImageData()方法也可以創建一個空的ImageData對象,最后putImageData()方法將處理后的像素輸出到畫布中。
微軟有篇不錯的教程(使用 Canvas 將彩色照片變成黑白照片)解釋像素操作,其中的操作是將彩色照片轉成灰白,使用的原理是將RGB三個分量提取出來,經過計算后(關鍵計算語句如下)重新賦值為灰度變量。
myGray = parseInt((myRed + myGreen + myBlue) / 3); // Assign average to red, green, and blue. myImage.data[i] = myGray; myImage.data[i + 1] = myGray; myImage.data[i + 2] = myGray;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78709.html
摘要:注以下所有代碼托管到動畫的數理分析有了前面的基礎知識,現在我們就會想如果我們能夠在每秒幀,內渲染張圖像,并且每一張圖像的內容發生微調,那么在秒鐘整個畫面就會產生動畫效果了。 什么是動畫? 就像思考哲學問題無法回避思維和存在的關系一樣,制作動畫同樣無法逃避的問題是動畫的原理是什么?這里提一句題外話,任何原理的東西通常難以讓你短期拾掇成果,但在隱約的未來會起到難以置信的效果,不信就看接下來...
閱讀 3095·2021-10-13 09:40
閱讀 3945·2021-09-22 15:51
閱讀 1493·2021-09-22 15:48
閱讀 1060·2021-09-06 15:00
閱讀 1790·2019-08-30 15:43
閱讀 2356·2019-08-29 18:35
閱讀 1667·2019-08-29 16:18
閱讀 3612·2019-08-29 12:49