diff --git a/app/components/bridge-controls.js b/app/components/bridge-controls.js index 8898105..04e607e 100644 --- a/app/components/bridge-controls.js +++ b/app/components/bridge-controls.js @@ -107,7 +107,7 @@ export default Em.Component.extend({ }, tabList: ["Lights", "Music"], - selectedTab: 0, + selectedTab: 1, tabData: function(){ var tabData = [], selectedTab = this.get('selectedTab'); diff --git a/app/components/color-picker.js b/app/components/color-picker.js new file mode 100644 index 0000000..63c27b0 --- /dev/null +++ b/app/components/color-picker.js @@ -0,0 +1,66 @@ +import Em from 'ember'; + +export default Em.Component.extend({ + classNames:['colorpicker'], + + // https://dzone.com/articles/creating-your-own-html5 + didInsertElement: function(){ + // handle color changes + var self = this, + canvas = Em.$('#picker')[0].getContext('2d'), + image = new Image(); + + image.src ='assets/images/colorwheel.png'; + image.onload = function () { + canvas.drawImage(image, 0, 0, image.width, image.height); // draw the image on the canvas + }; + }, + + // http://www.developers.meethue.com/documentation/color-conversions-rgb-xy + rgbToXy: function(red, green, blue){ + var X, Y, Z, x, y; + + // normalize + red = Number((red/255).toFixed(2)); + green = Number((green/255).toFixed(2)); + blue = Number((blue/255).toFixed(2)); + + // gamma correction + red = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92); + green = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92); + blue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92); + + // RGB to XYZ + X = red * 0.664511 + green * 0.154324 + blue * 0.162028; + Y = red * 0.283881 + green * 0.668433 + blue * 0.047685; + Z = red * 0.000088 + green * 0.072310 + blue * 0.986039; + + x = X / (X + Y + Z); + y = Y / (X + Y + Z); + + return [x,y]; + }, + + xyTorgb: function(x, y){ + var r, g, b, X, Y, Z, activeLights = this.get('activeLights'), lightsData = this.get('lightsData'); + + z = 1 - x - y; + Y = lightsData[activeLights[0]].state.bri; + X = (Y / y) * x; + Z = (Y / y) * z; + + r = X * 1.656492 - Y * 0.354851 - Z * 0.255038; + g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152; + b = X * 0.051713 - Y * 0.121364 + Z * 1.011530; + + r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055; + g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055; + b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055; + + r = Math.floor(r * 255); + g = Math.floor(g * 255); + b = Math.floor(b * 255); + + return [r, g, b]; + } +}); diff --git a/app/components/controls/light-control.js b/app/components/controls/light-control.js index 7b39e79..f2f8c94 100644 --- a/app/components/controls/light-control.js +++ b/app/components/controls/light-control.js @@ -12,18 +12,6 @@ export default Em.Component.extend({ isShowingColorPicker: false, - didInsertElement: function(){ - // handle color changes - var self = this, - canvas = $('#picker')[0].getContext('2d'), - image = new Image(); - - image.src ='assets/images/colorwheel.png'; - image.onload = function () { - canvas.drawImage(image, 0, 0, image.width, image.height); // draw the image on the canvas - }; - }, - actions: { clickLight: function(){ console.log('clickLight'); diff --git a/app/components/light-group.js b/app/components/light-group.js index caebac4..48f694f 100644 --- a/app/components/light-group.js +++ b/app/components/light-group.js @@ -44,6 +44,12 @@ export default Em.Component.extend({ } }, + didInsertElement: function() { + if(this.get('lightsData')){ + this.onLightsDataChange(); + } + }, + // list of all the lights in the hue system onLightsDataChange: function(){ if(!this.get('isHovering')){ diff --git a/app/styles/app.scss b/app/styles/app.scss index b035fab..1c33f6b 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -28,6 +28,10 @@ body { position: static; } +.relative { + position: relative; +} + #settings { cursor: pointer; position: absolute; @@ -62,7 +66,7 @@ body { } .appSettingsItem:hover { - background: darken(white, 10%); + background: darken(white, 20%); } .settingsItem.on md-icon.md-default-theme { @@ -188,20 +192,19 @@ md-list-item .md-no-style { } .colorpicker { - background-color: #222222; - border-radius: 5px 5px 5px 5px; - box-shadow: 2px 2px 2px #444444; + padding: 10px; + background: rgba(0, 0, 0, 0.6); + box-shadow: 5px 10px 15px 5px rgba(0, 0, 0, 0.3); color: #FFFFFF; - font-size: 12px; + z-index: 2; position: absolute; - width: 460px; + width: 220px; + right: 6px; + top: -6px; } #picker { cursor: crosshair; - float: left; - margin: 10px; - border: 0; } // LIGHT GROUP @@ -239,7 +242,8 @@ md-slider.md-default-theme .md-thumb:after { .lightGroup { margin: 0 auto 0 auto; .tooltip.top { - margin-top: 8px; + margin-top: -10px; + margin-left: -3px; } } @@ -271,7 +275,8 @@ md-slider.md-default-theme .md-thumb:after { left: 6px; } .tooltip.top { - margin-top: -10px; + margin-top: 6px; + margin-left: -5px; } } diff --git a/app/templates/components/color-picker.hbs b/app/templates/components/color-picker.hbs new file mode 100644 index 0000000..48e41a2 --- /dev/null +++ b/app/templates/components/color-picker.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/templates/components/controls/light-control.hbs b/app/templates/components/controls/light-control.hbs index 931a95a..a9ee892 100644 --- a/app/templates/components/controls/light-control.hbs +++ b/app/templates/components/controls/light-control.hbs @@ -19,12 +19,12 @@ {{paper-icon icon="color-lens"}}

Color

{{#paper-button raised=true class="color" action="toggleColorpicker"}}{{/paper-button}} - {{#if isShowingColorPicker}} -
- -
- {{/if}} {{/paper-item}} +
+ {{#if isShowingColorPicker}} + {{color-picker lightsData=lightsData activeLights=activeLights}} + {{/if}} +
{{#paper-item class="item"}} {{paper-icon icon="flare"}} diff --git a/ember-cli-build.js b/ember-cli-build.js index cbf157b..f00946c 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,7 +7,6 @@ module.exports = function(defaults) { }); app.import('vendor/dancer.js'); - app.import('vendor/colorpicker.js'); app.import('bower_components/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js'); app.import('bower_components/JavaScript-ID3-Reader/dist/id3-minimized.js'); app.import('bower_components/jquery-mousewheel/jquery.mousewheel.js'); diff --git a/public/assets/images/colorwheel.png b/public/assets/images/colorwheel.png index 7bf9424..3d6d114 100644 Binary files a/public/assets/images/colorwheel.png and b/public/assets/images/colorwheel.png differ diff --git a/tests/integration/components/color-picker-test.js b/tests/integration/components/color-picker-test.js new file mode 100644 index 0000000..fb1d925 --- /dev/null +++ b/tests/integration/components/color-picker-test.js @@ -0,0 +1,26 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('color-picker', 'Integration | Component | color picker', { + integration: true +}); + +test('it renders', function(assert) { + assert.expect(2); + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{color-picker}}`); + + assert.equal(this.$().text().trim(), ''); + + // Template block usage: + this.render(hbs` + {{#color-picker}} + template block text + {{/color-picker}} + `); + + assert.equal(this.$().text().trim(), 'template block text'); +}); diff --git a/vendor/colorpicker.js b/vendor/colorpicker.js deleted file mode 100644 index 71ddc9b..0000000 --- a/vendor/colorpicker.js +++ /dev/null @@ -1,152 +0,0 @@ -//https://github.com/bgrins/colorwheel-1k/tree/gh-pages -(function() { - - // Declare constants and variables to help with minification - // Some of these are inlined (with comments to the side with the actual equation) - var doc = document; - doc.c = doc.createElement; - b.a = b.appendChild; - - var width = c.width = c.height = 400, - label = b.a(doc.c("p")), - input = b.a(doc.c("input")), - imageData = a.createImageData(width, width), - pixels = imageData.data, - oneHundred = input.value = input.max = 100, - circleOffset = 10, - diameter = 380, //width-circleOffset*2, - radius = 190, //diameter / 2, - radiusPlusOffset = 200, //radius + circleOffset - radiusSquared = radius * radius, - two55 = 255, - currentY = oneHundred, - currentX = -currentY, - wheelPixel = 16040; // circleOffset*4*width+circleOffset*4; - - // Math helpers - var math = Math, - PI = math.PI, - PI2 = PI * 2, - sqrt = math.sqrt, - atan2 = math.atan2; - - // Setup DOM properties - b.style.textAlign="center"; - label.style.font = "2em courier"; - input.type = "range"; - - // Load color wheel data into memory. - for (y = input.min = 0; y < width; y++) { - for (x = 0; x < width; x++) { - var rx = x - radius, - ry = y - radius, - d = rx * rx + ry * ry, - rgb = hsvToRgb( - (atan2(ry, rx) + PI) / PI2, // Hue - sqrt(d) / radius, // Saturation - 1 // Value - ); - - // Print current color, but hide if outside the area of the circle - pixels[wheelPixel++] = rgb[0]; - pixels[wheelPixel++] = rgb[1]; - pixels[wheelPixel++] = rgb[2]; - pixels[wheelPixel++] = d > radiusSquared ? 0 : two55; - } - } - - // Bind Event Handlers - input.onchange = redraw; - c.onmousedown = doc.onmouseup = function(e) { - // Unbind mousemove if this is a mouseup event, or bind mousemove if this a mousedown event - doc.onmousemove = /p/.test(e.type) ? 0 : (redraw(e), redraw); - } - - // Handle manual calls + mousemove event handler + input change event handler all in one place. - function redraw(e) { - - // Only process an actual change if it is triggered by the mousemove or mousedown event. - // Otherwise e.pageX will be undefined, which will cause the result to be NaN, so it will fallback to the current value - currentX = e.pageX - c.offsetLeft - radiusPlusOffset || currentX; - currentY = e.pageY - c.offsetTop - radiusPlusOffset || currentY; - - // Scope these locally so the compiler will minify the names. Will manually remove the 'var' keyword in the minified version. - var theta = atan2(currentY, currentX), - d = currentX * currentX + currentY * currentY; - - // If the x/y is not in the circle, find angle between center and mouse point: - // Draw a line at that angle from center with the distance of radius - // Use that point on the circumference as the draggable location - if (d > radiusSquared) { - currentX = radius * math.cos(theta); - currentY = radius * math.sin(theta); - theta = atan2(currentY, currentX); - d = currentX * currentX + currentY * currentY; - } - - label.textContent = b.style.background = hsvToRgb( - (theta + PI) / PI2, // Current hue (how many degrees along the circle) - sqrt(d) / radius, // Current saturation (how close to the middle) - input.value / oneHundred // Current value (input type="range" slider value) - )[3]; - - // Reset to color wheel and draw a spot on the current location. - a.putImageData(imageData, 0, 0); - - // Draw the current spot. - // I have tried a rectangle, circle, and heart shape. - /* - // Rectangle: - a.fillStyle = '#000'; - a.fillRect(currentX+radiusPlusOffset,currentY+radiusPlusOffset, 6, 6); - */ - /* - // Circle: - a.beginPath(); - a.strokeStyle = '#000'; - a.arc(~~currentX+radiusPlusOffset,~~currentY+radiusPlusOffset, 4, 0, PI2); - a.stroke(); - */ - - // Heart: - a.font = "1em arial"; - a.fillText("♥", currentX+radiusPlusOffset-4,currentY+radiusPlusOffset+4); - - } - - // Created a shorter version of the HSV to RGB conversion function in TinyColor - // https://github.com/bgrins/TinyColor/blob/master/tinycolor.js - function hsvToRgb(h, s, v) { - h*=6; - var i = ~~h, - f = h - i, - p = v * (1 - s), - q = v * (1 - f * s), - t = v * (1 - (1 - f) * s), - mod = i % 6, - r = [v, q, p, p, t, v][mod] * two55, - g = [t, v, v, q, p, p][mod] * two55, - b = [p, p, t, v, v, q][mod] * two55; - - return [r, g, b, "rgb("+ ~~r + "," + ~~g + "," + ~~b + ")"]; - } - - // Kick everything off - redraw(0); - - /* - // Just an idea I had to kick everything off with some changing colors… - // Probably no way to squeeze this into 1k, but it could probably be a lot smaller than this: - currentX = currentY = 1; - var interval = setInterval(function() { - currentX--; - currentY*=1.05; - redraw(0) - }, 7); - - setTimeout(function() { - clearInterval(interval) - }, 700) - */ - -})();