原生JS实现 color picker 颜色选择器(canvas)

2019-03-07-15:32于公司:
最近在搞TMS,碰到了颜色选择器,想了解下用原生JS如何实现。记录下:

效果如下:


image.png

先上源码稍后来分析,到时候搞成react版本

<!DOCTYPE html>
<html lang="zh">
 
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            body {
                background: #535353;
                padding: 0;
                margin: 0;
            }
             
            canvas {
                cursor: crosshair;
            }
             
            #cur {
                width: 3px;
                height: 3px;
                outline: 2px solid #535353;
                margin-left: -1px;
                margin-top: -1px;
                position: absolute;
            }
             
            .wrapper {
                position: relative;
            }
             
            #color_show {
                width: 50px;
                height: 50px;
                background: #f00;
            }
             
            .panel {
                width: 200px;
                height: 200px;
                position: fixed;
                top: 20px;
                right: 20px;
                background-color: #fff;
                padding: 10px;
                text-align: center;
                line-height: 2em;
            }
        </style>
    </head>
 
    <body>
        <div class="wrapper">
            <canvas id="canvas" width="600" height="600"></canvas>
            <em id="cur"></em>
            <div class="panel">
                <div id="color_show"></div>
                <label>
            rgb <input type="text"  class="color_input" value="" id="rgb_value">
        </label><br>
                <label>
            hex <input type="text"  class="color_input" value="" id="hex_value">
        </label>
            </div>
        </div>
        <script>
            (function() {
                var width = 256;
                var can = document.getElementById('canvas');
                var ctx = can.getContext('2d');
                var curColor = 'rgba(255,0,0,1)';
                var cur = document.getElementById('cur');
                var rgbValue = document.getElementById('rgb_value');
                var hexValue = document.getElementById('hex_value');
                var colorShow = document.getElementById('color_show');
 
                var aColorInput = document.getElementsByClassName('color_input');
 
                function colorBar() {
                    var gradientBar = ctx.createLinearGradient(0, 0, 0, width);
                    gradientBar.addColorStop(0, '#f00');
                    gradientBar.addColorStop(1 / 6, '#f0f');
                    gradientBar.addColorStop(2 / 6, '#00f');
                    gradientBar.addColorStop(3 / 6, '#0ff');
                    gradientBar.addColorStop(4 / 6, '#0f0');
                    gradientBar.addColorStop(5 / 6, '#ff0');
                    gradientBar.addColorStop(1, '#f00');
 
                    ctx.fillStyle = gradientBar;
                    ctx.fillRect(0, 0, 20, width);
                }
 
                function rgb2hex(rgb) {
                    var aRgb = rgb instanceof Array ? rgb : (rgb.split(',') || [0, 0, 0]);
                    var temp;
                    return [
                        (temp = Number(aRgb[0]).toString(16)).length == 1 ? ('0' + temp) : temp,
                        (temp = Number(aRgb[1]).toString(16)).length == 1 ? ('0' + temp) : temp,
                        (temp = Number(aRgb[2]).toString(16)).length == 1 ? ('0' + temp) : temp,
                    ].join('');
                }
 
                function hex2rgb(hex) {
                    if(hex.length == 3) {
                        hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
                    }
                    return [
                        parseInt(hex[0] + hex[1], 16),
                        parseInt(hex[2] + hex[3], 16),
                        parseInt(hex[4] + hex[5], 16),
                    ].join();
                }
 
                function putCurDom(color) {
                    if(/([0-9a-f]{3}|[0-9a-f]{6})/i.test(color)) {
                        // hex
                        color = hex2rgb(color);
                    } else if(color instanceof Array) {
                        color = color.join(',');
                    } else if(/\d{1,3}(\,\d{1,3}){2}/i.test(color)) {
 
                    } else {
                        return;
                    }
                }
 
                function colorBox(color) {
                    // 底色填充,也就是(举例红色)到白色
                    var gradientBase = ctx.createLinearGradient(30, 0, width + 30, 0);
                    gradientBase.addColorStop(1, color);
                    gradientBase.addColorStop(0, 'rgba(255,255,255,1)');
                    ctx.fillStyle = gradientBase;
                    ctx.fillRect(30, 0, width, width);
                    // 第二次填充,黑色到透明
                    var my_gradient1 = ctx.createLinearGradient(0, 0, 0, width);
                    my_gradient1.addColorStop(0, 'rgba(0,0,0,0)');
                    my_gradient1.addColorStop(1, 'rgba(0,0,0,1)');
                    ctx.fillStyle = my_gradient1;
                    ctx.fillRect(30, 0, width, width);
                }
 
                function init() {
                    colorBar();
                    colorBox(curColor);
                    bind();
                }
 
                function bind() {
                    can.addEventListener('click', function(e) {
                        var ePos = {
                            x: e.offsetX || e.layerX,
                            y: e.offsetY || e.layerY
                        }
                        var rgbaStr = '#000';
                        if(ePos.x >= 0 && ePos.x < 20 && ePos.y >= 0 && ePos.y < width) {
                            // in
                            rgbaStr = getRgbaAtPoint(ePos, 'bar');
                            colorBox('rgba(' + rgbaStr + ')');
                        } else if(ePos.x >= 30 && ePos.x < 30 + width && ePos.y >= 0 && ePos.y < width) {
                            rgbaStr = getRgbaAtPoint(ePos, 'box');
                        } else {
                            return;
                        }
                        outColor(rgbaStr.slice(0, 3).join());
                        cur.style.left = ePos.x + 'px';
                        cur.style.top = ePos.y + 'px';
                        cur.style.outlineColor = (rgbaStr[0] > 256 / 2 || rgbaStr[1] > 256 / 2 || rgbaStr[2] > 256 / 2) ? '#000' : '#fff';
                    });
 
                    can.addEventListener('mousedown', function(e) {
                        var ePos = {
                            x: e.layerX || e.offsetX,
                            y: e.layerY || e.offsetY
                        }
                        if(ePos.x >= 30 && ePos.x < 30 + width && ePos.y >= 0 && ePos.y < width) {
                            document.onmousemove = function(e) {
                                var pos = {
                                    x: e.clientX,
                                    y: e.clientY
                                }
 
                                pos.x = pos.x < 30 ? 30 : pos.x && (pos.x > (30 + width - 1) ? (30 + width - 1) : pos.x);
                                pos.y = pos.y < 0 ? 0 : pos.y && (pos.y > (width - 1) ? (width - 1) : pos.y);
 
                                rgbaStr = getRgbaAtPoint(pos, 'box');
                                cur.style.left = pos.x + 'px';
                                cur.style.top = pos.y + 'px';
                                cur.style.outlineColor = (rgbaStr[0] > 256 / 2 || rgbaStr[1] > 256 / 2 || rgbaStr[2] > 256 / 2) ? '#000' : '#fff';
                                outColor(rgbaStr.slice(0, 3).join());
                            };
                            document.onmouseup = function() {
                                // outColor(rgbaStr.slice(0, 3).join());
                                document.onmouseup = document.onmousemove = null;
                            }
                        }
 
                    });
                }
 
                function outColor(rgb) {
                    rgbValue.value = rgb;
                    hexValue.value = rgb2hex(rgb);
                    colorShow.style.backgroundColor = 'rgb(' + rgb + ')';
                }
 
                function getRgbaAtPoint(pos, area) {
                    if(area == 'bar') {
                        var imgData = ctx.getImageData(0, 0, 20, width);
                    } else {
                        var imgData = ctx.getImageData(0, 0, can.width, can.height);
                    }
 
                    var data = imgData.data;
                    var dataIndex = (pos.y * imgData.width + pos.x) * 4;
                    return [
                        data[dataIndex],
                        data[dataIndex + 1],
                        data[dataIndex + 2],
                        (data[dataIndex + 3] / 255).toFixed(2),
                    ];
                }
 
                init();
            })()
        </script>
    </body>
 
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271