摘要:前言本文是接續系列教程的,主要是介紹顏色系統在中的應用。本來是與一起成文的,因為莫名其妙的字數限制只能分割放送了。提供可以獲取畫布上任何一個像素,并可以自由的操作他們。繪制指定的位置繪制對象的內容。
前言
本文是接續系列教程的extra1,主要是介紹顏色系統在canvas中的應用。
本來是與extra1一起成文的,因為segmentfault莫名其妙的字數限制bug只能分割放送了。
你如果認為canvas只是畫圖工具,那接下來的操作會顛覆你的認知。canvas提供api可以獲取畫布上任何一個像素,并可以自由的操作他們。
獲取像素直接訪問像素的功能由canvas上下文中的ImageData對象提供,它提供了以下一組方法,都會返回ImageData對象。
getImageData()接受x軸坐標、y軸坐標、寬度、高度四個參數,獲取畫布上這個矩形區域的像素數據;
createImageData()可憑空創建指定寬高的矩形區域,初始是黑色,也可以輸入一個ImageData對象用于創建一個同樣大小的區域,但注意不會復制像素數據。
context.getImageData(x, y, width, height); context.createImageData(width, height); context.createImageData(anothorImageData);
獲取到的ImageData對象中data屬性是一個一維數組,乍看亂糟糟的,但細看你會發現其實這就是RGBA的顏色數據,也就是數組中每個四位就是一個像素的顏色數據,這里注意一下透明度A也是0~255,不是CSS里簡化過的0~1。
*
舉個例子
現在假定在一個純紅色區域取一塊2*2的矩形,我們得到的像素數據是:
let pixels = [255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255]
他們與圖像的對應關系是從左到右,從上到下,大概就像上面代碼格式化這樣,如圖所示:
根據4對1的對應關系,我們很容易就能寫出遍歷的辦法,offset就相當于指針,每次移動4位,代碼如下:
for (let offset = 0, len = pixels.length; offset < len; offset += 4) { r = pixels[offset]; g = pixels[offset + 1]; b = pixels[offset + 2]; a = pixels[offset + 3]; }
當需要訪問特定坐標的像素時,可以使用如下公式,其中xpos是像素點在該區域的x坐標;ypos是像素點在該區域的y坐標,imagedata.width是指區域橫向有多少像素。
let offset = (xpos + ypos * imagedata.width) * 4; let r = pixels[offset]; let g = pixels[offset + 1]; let b = pixels[offset + 2]; let a = pixels[offset + 3];繪制像素
可以將修改過的ImageData對象重新用上下文的putImageData()方法繪制到指定區域,該方法接受三個參數:ImageData對象、x軸坐標、y軸坐標。繪制指定的位置繪制ImageData對象的內容。直接看下面例子的核心代碼。
先繪制鋪滿畫布的色塊,點擊按鈕觸發change事件處理器可改變顏色,過程見注釋。
完整例子:演示反色變化
【PS】對js了解不深的朋友可能會有疑問,遍歷過程操作的是pixels,imageData怎么會改變呢?
這是因為js中對象都是地址傳遞的特點,也就是pixels = imageData.data操作只是將pixels變量的指向到imageData.data所指向的內存空間,所以操作pixels就是操作imageData.data。
window.onload = function () { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 繪制色塊,每個色塊寬10像素,高等于畫布高,鋪滿畫布 for (let i = 0; i < canvas.width; i += 10) { context.fillStyle = (i % 20 === 0) ? "#f00" : ((i % 30 === 0) ? "#0f0" : "#00f"); context.fillRect(i, 0, 10, canvas.height); } }; function change() { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 獲取整個畫布的ImageData對象 const imageData = context.getImageData(0, 0, canvas.width, canvas.height); // 取出顏色數據 const pixels = imageData.data; // 遍歷顏色數據求每個顏色的反色 for (let offset = 0, len = pixels.length; offset < len; offset += 4) { pixels[offset] = 255 - pixels[offset]; pixels[offset + 1] = 255 - pixels[offset + 1]; pixels[offset + 2] = 255 - pixels[offset + 2]; // 這里沒有操作透明度 } // 將ImageData重新繪制到畫布上 context.putImageData(imageData, 0, 0); }更多有趣的例子
canvas強大的像素操作可以給我們帶來更多的可能,也許你會想開始做一個網頁版的美圖工具了吧(笑)。
這里還有一些有趣的demo可以玩玩:
演示灰度變化
有趣的色彩波紋
綜合案例有關顏色的番外部分到這里就基本完結了,最后有個綜合題,會應用這些技術。
將系列第二篇中的鼠標畫圖工具改造成鼠標噴漆工具,這里建議自己動手實踐一下。
下面例子基本思路就是取得畫布像素數據,每當鼠標點下并移動(執行onMouseMove)就隨機改變鼠標周圍一定范圍的像素點的顏色。
完整案例:鼠標噴漆工具
window.onload = function () { const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); // 獲得整個畫布區域的ImageData對象 const imageData = context.getImageData(0, 0, canvas.width, canvas.height); // 取出像素數據 const pixels = imageData.data; // 設定筆刷大小 const brush_size = 25; // 設定筆刷密度 const brush_density = 80; // 筆刷的顏色變量 let brush_color; function onMouseMove() { // 根據設定的筆刷密度生成隨機像素點 for (let i = 0; i < brush_density; i++) { // 隨機像素點角度相對于鼠標的角度 const angle = Math.random() * Math.PI * 2; // 根據設定的筆刷大小,隨機像素點以鼠標為圓心的半徑 const radius = Math.random() * brush_size; // 計算出像素點的x軸相對坐標 const xpos = (mouse.x + Math.cos(angle) * radius) | 0; // 計算出像素點的y軸相對坐標 const ypos = (mouse.y + Math.sin(angle) * radius) | 0; // 算出該像素點在pixels中的偏移量 const offset = (xpos + ypos * imageData.width) * 4; // 對這個像素點的顏色數據進行操作,將顏色分解成三基色 pixels[offset] = brush_color >> 16 & 0xff; pixels[offset + 1] = brush_color >> 8 & 0xff; pixels[offset + 2] = brush_color & 0xff; pixels[offset + 3] = 255; } // 重新繪制區域 context.putImageData(imageData, 0, 0); } canvas.addEventListener("mousedown", () => { // 隨機一個顏色 brush_color = utils.parseColor(Math.random() * 0xffffff, true); canvas.addEventListener("mousemove", onMouseMove, false); }, false); canvas.addEventListener("mouseup", () => { canvas.removeEventListener("mousemove", onMouseMove, false); }, false); };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/54518.html
摘要:前言本文是接續系列教程的,主要是介紹顏色系統在中的應用。本來是與一起成文的,因為莫名其妙的字數限制只能分割放送了。提供可以獲取畫布上任何一個像素,并可以自由的操作他們。繪制指定的位置繪制對象的內容。 前言 本文是接續系列教程的extra1,主要是介紹顏色系統在canvas中的應用。 本來是與extra1一起成文的,因為segmentfault莫名其妙的字數限制bug只能分割放送了。 ...
摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標準的。基于時間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉變為物體每秒移動距離。 前言 本文雖說是基礎教程,但這是相對動畫/游戲領域來說,在前端領域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎已經十分熟悉,而且有高中水平的數學和物理知識。d...
摘要:所建議的刷新率是秒幀,大部分瀏覽器是遵循這一標準的。基于時間的動畫其實無論是還是定時器,都不能保證以特定速率播放。將物體每幀移動距離,轉變為物體每秒移動距離。 前言 本文雖說是基礎教程,但這是相對動畫/游戲領域來說,在前端領域算是中級教程了,不適合前端小白或萌新。閱讀前請確保自己對前端三大件(JavaScript+CSS+HTML)的基礎已經十分熟悉,而且有高中水平的數學和物理知識。d...
閱讀 1879·2021-09-27 13:35
閱讀 3432·2019-08-30 14:16
閱讀 2489·2019-08-30 10:52
閱讀 867·2019-08-29 16:35
閱讀 1420·2019-08-29 15:22
閱讀 3646·2019-08-23 18:21
閱讀 3138·2019-08-23 18:00
閱讀 3127·2019-08-23 16:50