每個瀏覽器都有自己的特點(diǎn),比如今天要做的colorpicker就是,一千個瀏覽器,一千個哈姆雷特,一千個colorpicker。今天canvas系列就用canvas做一個colorpicker。

 **********************************************************************

效果圖和demo

突然翻到了之前用js和dom寫的一個colorpicker,比較挫,扔張圖就好(old)

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

這個真的很挫,性能很差,因為每一個可選的顏色值都是一個dom,如果要實現(xiàn)256*256,那瀏覽器就爆了~~~~~

 

好,回到今天的demo(new)

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

demo鏈接: https://win7killer.github.io/can_ps/src/demo/color_picker.html

 

沒錯,就是照著PS的顏色選擇器的樣子仿的。

**********************************************************************

實現(xiàn)

 

首先我們來看效果圖分析怎么做:

1.左側(cè)colorbar

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)    左側(cè)提供一系列過渡色,不難看出,這個是“紅黃綠青藍(lán)紫”這六種顏色,然后加以過渡色處理來的。最后紫色還要過渡回到紅色。

 

另外換成環(huán)狀的可能更加好識別,如下圖:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

那么,我們就可以用canvas的過渡色來實現(xiàn)左側(cè)這個區(qū)域,

代碼如下:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 function colorBar() { 2     var gradientBar = ctx.createLinearGradient(0, 0, 0, width); 3     gradientBar.addColorStop(0, '#f00'); 4     gradientBar.addColorStop(1 / 6, '#f0f'); 5     gradientBar.addColorStop(2 / 6, '#00f'); 6     gradientBar.addColorStop(3 / 6, '#0ff'); 7     gradientBar.addColorStop(4 / 6, '#0f0'); 8     gradientBar.addColorStop(5 / 6, '#ff0'); 9     gradientBar.addColorStop(1, '#f00');10 11     ctx.fillStyle = gradientBar;12     ctx.fillRect(0, 0, 20, width);13 }

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

這里涉及到canvas的fillStyle或者strokenStyle的填充對象,可以使用過渡色對象(自己瞎叫的名字),了解更多可以去w3cschool。

 

 2.中間顏色區(qū)

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 

中間這塊乍看很簡單,再看有點(diǎn)蒙bi,三看才搞清楚怎么搞。

乍看:其實就是左側(cè)選中的那個顏色(比如A),然后進(jìn)行過渡處理,不還是過渡么。

再看:恩,顏色,然后黑色,白色,三種顏色三個角怎么過渡~~~~(如果有快捷的過渡實現(xiàn)方式請留言告知我,THX)。

三看:那么,拆解一下,比如紅色到白色過渡,然后加一層黑色到透明過渡?是滴,就是這么個方案。(我自己之前彎路到了紅色到黑色,白色到透明)

那么就是借助兩次過渡色的填充,實現(xiàn)中間色塊區(qū)域。

代碼如下:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 function colorBox(color) { 2     // 底色填充,也就是(舉例紅色)到白色 3     var gradientBase = ctx.createLinearGradient(30, 0, width + 30, 0); 4     gradientBase.addColorStop(1, color); 5     gradientBase.addColorStop(0, 'rgba(255,255,255,1)'); 6     ctx.fillStyle = gradientBase; 7     ctx.fillRect(30, 0, width, width); 8      9     // 第二次填充,黑色到透明10     var my_gradient1 = ctx.createLinearGradient(0, 0, 0, width);11     my_gradient1.addColorStop(0, 'rgba(0,0,0,0)');12     my_gradient1.addColorStop(1, 'rgba(0,0,0,1)');13     ctx.fillStyle = my_gradient1;14     ctx.fillRect(30, 0, width, width);15 }

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

需要注意,第一次填充,是從橫向填充,這時候中間色塊的左邊已經(jīng)不是canvas的原點(diǎn),所以加了偏移量30px

第二次填充縱向,Y軸還是0。

這個在實際應(yīng)用中要注意。

 

到這里,左側(cè)canvas繪制的東西就差不多了。

 

3. 顏色選擇事件處理

首先明確交互事件:

選擇左側(cè)colorbar(比如#ff0),中間base顏色要跟著變化,右上角也要是對應(yīng)顏色(#ff0)【這個時候其實也可以得到選擇的顏色,可以結(jié)束交互】;

選擇中間區(qū)域的顏色,左側(cè)不變,可以獲取到對應(yīng)的顏色值,結(jié)束交互。

最終就是在右側(cè)的dom區(qū)域展示所選到的顏色。

 

canvas中沒有dom對象,所以鼠標(biāo)點(diǎn)擊事件要靠鼠標(biāo)的位置來確定是否進(jìn)行相應(yīng)處理。而且我們繪制的不是path對象,也無法使用inpath之類的方法來判斷。

點(diǎn)擊事件代碼:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 can.addEventListener('click', function(e) { 2     var ePos = { 3         x: e.offsetX || e.layerX, 4         y: e.offsetY || e.layerY 5     } 6     var rgbaStr = '#000'; 7     if (ePos.x >= 0 && ePos.x < 20 && ePos.y >= 0 && ePos.y < width) { 8         // in 9         rgbaStr = getRgbaAtPoint(ePos, 'bar');10         colorBox('rgba(' + rgbaStr + ')');11     } else if (ePos.x >= 30 && ePos.x < 30 + width && ePos.y >= 0 && ePos.y < width) {12         rgbaStr = getRgbaAtPoint(ePos, 'box');13     } else {14         return;15     }16     outColor(rgbaStr.slice(0, 3).join());17     cur.style.left = ePos.x + 'px';18     cur.style.top = ePos.y + 'px';19     cur.style.outlineColor = (rgbaStr[0] > 256 / 2 || rgbaStr[1] > 256 / 2 || rgbaStr[2] > 256 / 2) ? '#000' : '#fff';20 });

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

其中,getRgbaAtPoint是最終的獲取顏色值的方法,需要根據(jù)不同的鼠標(biāo)位置傳參來決定選取左側(cè)還是右側(cè)圖像

 

獲取顏色就比較簡單了,就是拿到對應(yīng)區(qū)域的imageData,然后從顏色數(shù)組中獲取到對應(yīng)位置的顏色值即可。

做過canvas像素處理的同學(xué)會比較明白,不明白的建議先去把getImageData方法看一看,了解一下

獲取顏色代碼:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 function getRgbaAtPoint(pos, area) { 2     if (area == 'bar') { 3         var imgData = ctx.getImageData(0, 0, 20, width); 4     } else { 5         var imgData = ctx.getImageData(0, 0, can.width, can.height); 6     } 7  8     var data = imgData.data; 9     var dataIndex = (pos.y * imgData.width + pos.x) * 4;10     return [11         data[dataIndex],12         data[dataIndex + 1],13         data[dataIndex + 2],14         (data[dataIndex + 3] / 255).toFixed(2),15     ];16 }

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

這時候拿到的就是rgba顏色對應(yīng)的值。

需要注意,最后一個數(shù)據(jù)時alpha通道,canvas的imageData里是0-255【沒記錯的話】,而不是我們平常用的0-1,所以要做轉(zhuǎn)換。

 

顏色輸出&轉(zhuǎn)換:

拿到顏色后就可以輸出到右側(cè)了。

右側(cè)只是用了rgb三通道,所以取數(shù)組前三位就好。

至于hex顏色,則用rgb來轉(zhuǎn)換。

轉(zhuǎn)換代碼如下:

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 function rgb2hex(rgb) { 2     var aRgb = rgb instanceof Array ? rgb : (rgb.split(',') || [0, 0, 0]); 3     var temp; 4     return [ 5         (temp = Number(aRgb[0]).toString(16)).length == 1 ? ('0' + temp) : temp, 6         (temp = Number(aRgb[1]).toString(16)).length == 1 ? ('0' + temp) : temp, 7         (temp = Number(aRgb[2]).toString(16)).length == 1 ? ('0' + temp) : temp, 8     ].join(''); 9 }10 11 function hex2rgb(hex) {12     if (hex.length == 3) {13         hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];14     }15     return [16         parseInt(hex[0] + hex[1], 16),17         parseInt(hex[2] + hex[3], 16),18         parseInt(hex[4] + hex[5], 16),19     ].join();20 }

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

簡單來說,就是10進(jìn)制與16進(jìn)制的轉(zhuǎn)換。

有個點(diǎn),就是rgb的三個值,分別對應(yīng)的是hex的每兩個值,比如rgb(255,0,255)對用到hex則分別是 “ff,00,ff”,綜合起來就是“#ff00ff”,可以簡寫“#f0f”。

 

額外效果:

中間的顏色選擇還有個效果,就是鼠標(biāo)拖拽到哪里,就選中相應(yīng)的顏色。

鼠標(biāo)拖拽事件大家都不陌生,直接上代碼,不廢話

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 1 can.addEventListener('mousedown', function(e) { 2     var ePos = { 3         x: e.layerX || e.offsetX, 4         y: e.layerY || e.offsetY 5     } 6     if (ePos.x >= 30 && ePos.x < 30 + width && ePos.y >= 0 && ePos.y < width) { 7         document.onmousemove = function(e) { 8             var pos = { 9                 x: e.clientX,10                 y: e.clientY11             }12 13             pos.x = pos.x < 30 ? 30 : pos.x && (pos.x > (30 + width - 1) ? (30 + width - 1) : pos.x);14             pos.y = pos.y < 0 ? 0 : pos.y && (pos.y > (width - 1) ? (width - 1) : pos.y);15 16             rgbaStr = getRgbaAtPoint(pos, 'box');17             cur.style.left = pos.x + 'px';18             cur.style.top = pos.y + 'px';19             cur.style.outlineColor = (rgbaStr[0] > 256 / 2 || rgbaStr[1] > 256 / 2 || rgbaStr[2] > 256 / 2) ? '#000' : '#fff';20             outColor(rgbaStr.slice(0, 3).join());21         };22         document.onmouseup = function() {23             // outColor(rgbaStr.slice(0, 3).join());24             document.onmouseup = document.onmousemove = null;25         }26     }27 28 });

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 

 

這樣,每段代碼拼湊起來,就是整體的架子了,附上最終代碼(比較長,折疊了):

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn) View Code

 

**********************************************************************

寫在最后:

最終寫完效果在自己玩耍的過程中,發(fā)現(xiàn)瀏覽器對于canvas的過渡色實現(xiàn)有點(diǎn)問題。chrome很明顯,F(xiàn)F稍微好一點(diǎn)。

移動開發(fā)培訓(xùn),Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),手機(jī)維修培訓(xùn),手機(jī)軟件培訓(xùn)

 

如圖: 按道理來說,最下邊選到的顏色應(yīng)該都是rgb(0,0,0)才對,但是圖上可見,有些地方并不是~~~

大多數(shù)還是000,某些點(diǎn)某個通道有可能會出現(xiàn)1。原因未知。

 

嘗試了email給chrome郵箱,可能我英語比較差人家沒看懂,也可能我問題沒描述清楚,反正后來沒有回復(fù),之后的瀏覽器更新也沒有處理。

相應(yīng)的,css3的過渡色則沒有一丁點(diǎn)問題。

**********************************************************************

圖片、代碼啥的貼了一堆,其中涉及的知識點(diǎn)可能有點(diǎn)多。看到這里的同學(xué),建議回過頭再看一遍哈。需要注意的我盡量特殊顏色標(biāo)出來了。

最后,歡迎留言提建議什么的。

http://www.cnblogs.com/ufex/p/6382982.html