Mercurial > code > home > repos > light9
changeset 1607:60b519af3d12
rainbow picker working
Ignore-this: e25735a6e3893e641a2d210cb5bdc6f1
author | drewp@bigasterisk.com |
---|---|
date | Mon, 05 Jun 2017 04:37:23 +0000 |
parents | cb396a0ff04b |
children | faa62d5e84d8 |
files | light9/web/live/index.html |
diffstat | 1 files changed, 138 insertions(+), 20 deletions(-) [+] |
line wrap: on
line diff
--- a/light9/web/live/index.html Mon Jun 05 04:37:07 2017 +0000 +++ b/light9/web/live/index.html Mon Jun 05 04:37:23 2017 +0000 @@ -25,15 +25,18 @@ :host { position: relative; } - #smallRainbow, #largeRainbow { overflow: hidden; position: relative; } + #smallRainbowComp, #largeRainbowComp { + overflow: hidden; + position: relative; + } #smallRainbow { background: url(/colorpick_rainbow_small.png); - width: 150px; + width: 150px; height: 30px; } #largeRainbow { background: url(/colorpick_rainbow_large.png); - width: 400px; + width: 400px; height: 200px; } #smallCrosshair, #largeCrosshair { @@ -41,56 +44,171 @@ left: -60px; top: -62px; pointer-events: none; - } + } #smallCrosshair { background: url(/colorpick_crosshair_small.png); width: 200px; height: 166px; - } #largeCrosshair { background: url(/colorpick_crosshair_large.png); width: 492px; height: 409px; - } - #largeRainbowComp { display: none; position: absolute; - z-index: 10; - left: -50px; + #largeRainbowComp { + display: none; + position: absolute; + z-index: 10; + left: -50px; top: -110px; } </style> - <div id="smallRainbow" on-mouseenter="onEnterSmall"> <div id="smallCrosshair"></div></div> + <div id="smallRainbowComp"> + <div id="smallRainbow" on-mouseenter="onEnterSmall"></div> + <div id="smallCrosshair"></div> + </div> <div id="largeRainbowComp"> - <canvas id="largeRainbow" + <div id="largeRainbow" on-mousemove="onCanvasMove" on-mouseup="onCanvasUp" - on-mouseleave="onCanvasLeave"></canvas> + on-mouseleave="onCanvasLeave"></div> <div id="largeCrosshair"></div> </div> </template> <script> HTMLImports.whenReady(function () { + class RainbowCanvas { + constructor(url, size) { + this.size = size; + var elem = document.createElement('canvas'); + elem.width = size[0]; + elem.height = size[1]; + + this.ctx = elem.getContext('2d'); + + this.colorPos = {} // color: pos + + var img = new Image(); + img.onload = function() { + this.ctx.drawImage(img, 0, 0); + this._readImage(); + }.bind(this); + img.src = url; + } + _readImage() { + var data = this.ctx.getImageData( + 0, 0, this.size[0], this.size[1]).data; + for (var y = 0; y < this.size[1]; y+=1) { + for (var x = 0; x < this.size[0]; x+=1) { + var base = (y * this.size[0] + x) * 4; + var c = this._hexFromRgb(data[base + 0], + data[base + 1], + data[base + 2]); + this.colorPos[c] = [x, y]; + } + } + } + _hexFromRgb(r, g, b) { + var hex = function (x) { + return ('00' + x.toString(16)).slice(-2); + }; + return '#' + hex(r) + hex(g) + hex(b); + } + colorAt(pos) { + var data = this.ctx.getImageData(pos[0], pos[1], 1, 1).data; + return this._hexFromRgb(data[0], data[1], data[2]); + } + posFor(color) { + let r = parseInt(color.substr(1, 2), 16), + g = parseInt(color.substr(3, 2), 16), + b = parseInt(color.substr(5, 2), 16); + + var bright = Math.max(r, g, b); + r = Math.floor(255 * r / bright); + g = Math.floor(255 * g / bright); + b = Math.floor(255 * b / bright); + var ep = 8; + for (var dr = 0; dr < ep; dr = -dr + (dr > 0 ? 0 : 1)) { + for (var dg = 0; dg < ep; dg = -dg + (dg > 0 ? 0 : 1)) { + for (var db = 0; db < ep; db = -db + (db > 0 ? 0 : 1)) { + color = this._hexFromRgb(r + dr, g + dg, b + db); + var pos = this.colorPos[color]; + if (pos !== undefined) { + return pos; + } + } + } + } + throw new Error('no match'); + } + } + Polymer({ is: "light9-color-picker", properties: { + value: { type: String, notify: true }, }, - ready: function() { + observers: ['updateSmall(value)'], + attached: function() { + if (!window.pickerCanvases) { + window.pickerCanvases = { + large: new RainbowCanvas( + '/colorpick_rainbow_large.png', [400, 200]), + small: new RainbowCanvas( + '/colorpick_rainbow_small.png', [150, 30]), + }; + } + this.large = window.pickerCanvases.large; + this.small = window.pickerCanvases.small; + }, + updateSmall: function(value) { + try { + var pos = this.small.posFor(value); + } catch(e) { + this.moveSmallCrosshair([-999, -999]); + return; + } + this.moveSmallCrosshair(pos); + }, + showLarge: function() { + this.$.largeRainbowComp.style.display = 'block'; + try { + this.moveLargeCrosshair(this.large.posFor(this.value)); + } catch(e) { + this.moveLargeCrosshair([-999, -999]); + return; + } + }, + hideLarge: function() { + this.$.largeRainbowComp.style.display = 'none'; }, onEnterSmall: function() { // not if we just closed the large one - this.$.largeRainbowComp.style.display = 'block'; + this.showLarge(); + }, + moveLargeCrosshair: function(pos, _elem) { + _elem = _elem || this.$.largeCrosshair; + _elem.style.left = (pos[0] - _elem.offsetWidth / 2) + 'px'; + _elem.style.top = (pos[1] - _elem.offsetHeight / 2) + 'px'; + }, + moveSmallCrosshair: function(pos) { + this.moveLargeCrosshair(pos, this.$.smallCrosshair); }, onCanvasMove: function(ev) { - console.log('canvasmove'); + if (ev.buttons != 1) { + return; + } + var canvas = this.$.largeRainbow; + var pos = [ev.offsetX - canvas.offsetLeft, + ev.offsetY - canvas.offsetTop]; + this.moveLargeCrosshair(pos); + this.value = this.large.colorAt(pos); }, onCanvasUp: function(ev) { - console.log('canvasup'); - this.$.largeRainbowComp.style.display = 'none'; + this.hideLarge(); }, onCanvasLeave: function(ev) { - console.log('canvasleave'); - this.$.largeRainbowComp.style.display = 'none'; + this.hideLarge(); }, }); }); @@ -133,7 +251,7 @@ value="{{pickedColor}}"> <button on-click="goWhite">white</button> <button on-click="goBlack">black</button> - <light9-color-picker value="{{pickedColor}}"></light9-color-picker> + <light9-color-picker value="{{value}}"></light9-color-picker> </template> <template is="dom-if" if="{{deviceAttr.useChoice}}"> <select size$="{{deviceAttr.choiceSize}}" value="{{pickedChoice::change}}">