本文首發於我的個人部落格nikolausliu.top
在MDN上學習canvas相關API時,看到有個demo(下圖)跟平時用的拾色器有點像。於是我想canvas能不能用來做拾色器呢?仔細想了一下,答案是可以的,並做了一個簡單的demo(雙擊拾色)。在這裡把思路簡單記錄一下。
先看MDN上的例子
直接貼程式碼
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
}}複製程式碼
示例程式碼用for套for迴圈定義了6x6共36個小矩形的背景顏色(ctx.fillStyle
),並把這些小矩形繪製了出來(ctx.fillRect
)。
結合fillRect(x, y, width, height)
和ctx.fillRect(j*25,i*25,25,25);
可以推出:for迴圈中的i控制著矩形在y軸方向上的繪製。j控制著巨星在x軸方向上的繪製。這一點很重要,待會往上面示例程式碼中新增程式碼會用到(ps:有好的思維導圖軟體的希望推薦一波,xmind不適合畫下面這樣的,又不想開ps,所以,我用了畫圖軟體...)。
需求分析
現在要實現拾色器的功能,無非就是點選上面的矩形小色塊時,拿到當前點選區域對應的顏色值。再細分一下就是要實現兩點功能:
- 把每一個小矩形的位置資訊和顏色資訊儲存起來。這一點可以用一個二維陣列或者物件陣列(姑且這麼叫吧)來實現。我是用的後者,因為語義會更清晰一點。
- 根據滑鼠點選的位置判斷出點選區域屬於哪個矩形,並從上面儲存的二維陣列/物件陣列中取出相應的顏色值。
開始實現
實現第一點
// 初始化一個陣列用來儲存小矩形的位置資訊和顏色資訊
var arr = [];
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
// 每繪製一個矩形就儲存起來
arr.push({
x1: 25 * j, // 矩形的左上角x座標
y1: 25 * i, // 矩形的左上角y座標
x2: 25 * j + 25, // 矩形的右下角x座標
y2: 25 * i + 25, // 矩形的右下角y座標
// 矩形的顏色
color: 'rgb(' + Math.floor(255 - 42.5 * i) + ',' + Math.floor(255 - 42.5 * j) + ',0)'
});
}
}
}}複製程式碼
這樣每一個矩形的位置資訊和顏色資訊都被包裝成一個物件,並被推送到陣列中了。第一點完成。
實現第二點
滑鼠的位置資訊可以在滑鼠事件物件MouseEvent
上拿到,分別為e.clientX
和e.clientY
。
canvas.addEventListener('dblclick', function (e) {
var x = e.clientX;
var y = e.clientY;
for (var i = 0; i < arr.length; i++) {
if (x >= arr[i].x1
&& x < arr[i].x2
&& y >= arr[i].y1
&& y < arr[i].y2) {
// 拿到顏色啦
console.log(arr[i].color);
}
}
}, true);複製程式碼
為了簡化計算,我設定了body {margin: 0;}
,實際的情況可能不會有這麼理想。
完整程式碼裡有對rgb顏色值和十六進位制顏色值之間轉換的處理。
結語
以上只是簡單記錄一下拾色器實現的思路,真正的拾色器遠不止這麼一點顏色,而且顏色都是漸變過度的,更細粒化,這樣選取範圍的判斷應該要複雜一點。後續如果有整理的話會再更新。