From 4705428597a254d2564d8dd969a8c41158194838 Mon Sep 17 00:00:00 2001 From: Steph Ng Date: Sat, 18 Feb 2017 21:47:03 +0800 Subject: [PATCH 1/2] Add crossfade and update UI --- index.html | 186 +++++--------------------------------- light.js | 97 ++++++++++++++++++++ rgb.lua | 35 ++++++- styles/_range-slider.scss | 100 ++++++++++++++++++++ styles/_variables.scss | 9 ++ styles/light.scss | 89 ++++++++++++++++++ 6 files changed, 350 insertions(+), 166 deletions(-) mode change 100644 => 100755 index.html create mode 100755 light.js create mode 100755 styles/_range-slider.scss create mode 100755 styles/_variables.scss create mode 100755 styles/light.scss diff --git a/index.html b/index.html old mode 100644 new mode 100755 index 3376703..5ca2983 --- a/index.html +++ b/index.html @@ -1,166 +1,26 @@ - - DSL lights - - - - - - - -
- - -
- Fork me on GitHub - - + + Helios + + + + + +
+
+

Helios

+ +
+ + +
+
+ +
+ +
+
+ + diff --git a/light.js b/light.js new file mode 100755 index 0000000..f97b73a --- /dev/null +++ b/light.js @@ -0,0 +1,97 @@ +var HOSTS = [ + 'helios2.lan', + 'helios.lan' +]; +var host = HOSTS[0]; + +var canvas = document.getElementById('colorspace'); +var btn1 = document.getElementById('btn-1'); +var btn2 = document.getElementById('btn-2'); +var ctx = canvas.getContext('2d'); + +drawCanvas(); + +function changeHost(id) { + this.host = HOSTS[id]; + if(id) { + btn1.disabled = false; + btn2.disabled = true; + } else { + btn1.disabled = true; + btn2.disabled = false; + } +} + +function sendColour(rgb) { + var params = [ + 'r=' + rgb[0], + 'g=' + rgb[1], + 'b=' + rgb[2] + ].join('&'); + + var req = new XMLHttpRequest(); + console.log(params); + req.open("POST", 'http://' + host + '/rgb.lua?' + params, true); + req.send(); +} + +function colourCorrect(v) { + return Math.round(1023-(v*v)/64); +} + +function handleEvent(clientX, clientY) { + var data = ctx.getImageData(clientX, clientY, 1, 1).data; + var rgb = []; + for(var i=0; i<3; i++) { + rgb[i] = colourCorrect(data[i]); + } + sendColour(rgb); +} + +canvas.addEventListener("touchmove", function(event){ + handleEvent(event.touches[0].clientX, event.touches[0].clientY); +}, false); + +var mouseDown = false; +document.ontouchmove = function(e) {e.preventDefault()}; +canvas.addEventListener('mousedown', function(event) { + if (event.button == 0) { + handleEvent(event.x, event.y); + mouseDown = true; + } +}, false); + +document.addEventListener('mouseup', function(event) { + if (event.button == 0) { + mouseDown = false; + } +}, false); + +canvas.addEventListener('mousemove', function(event) { + if (mouseDown) { + handleEvent(event.x, event.y); + } +}, false); + +function drawCanvas(brightness = 100) { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + var brt = Math.round((brightness / 100) * 255); + var colours = ctx.createLinearGradient(30, 0, canvas.width, 0); + for(var i=0; i <= 360; i+=10) { + colours.addColorStop(i/360, 'hsl(' + i + ', 100%, '+ brightness/2 + '%)'); + } + + ctx.fillStyle = colours; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + var luminance = ctx.createLinearGradient(0, 0, 0, canvas.height); + luminance.addColorStop(0.0, 'rgba(' + brt + ',' + brt + ',' + brt + ',' + brightness/100 + ')'); + luminance.addColorStop(0.5, 'rgba(255,255,255,0)'); + luminance.addColorStop(0.5, 'rgba(0,0,0,0)'); + luminance.addColorStop(1, '#000000'); + + ctx.fillStyle = luminance; + ctx.fillRect(0, 0, canvas.width, canvas.height); +} + diff --git a/rgb.lua b/rgb.lua index 8b7c8e0..2e9e93c 100644 --- a/rgb.lua +++ b/rgb.lua @@ -1,22 +1,51 @@ +PIN_R = 5 +PIN_G = 6 +PIN_B = 7 + +FADE_MS = 100 + return function (connection, req) + local getduty = pwm.getduty local setduty = pwm.setduty local arg = tonumber(req:match("r=([0-9]+)")) if arg then - setduty(5, arg) + -- fade(getduty(PIN_R), arg, FADE_MS, function(val) + setduty(PIN_R, arg) + -- end) end arg = tonumber(req:match("g=([0-9]+)")) if arg then - setduty(6, arg) + -- fade(getduty(PIN_G), arg, FADE_MS, function(val) + var = arg + setduty(PIN_G, arg) + -- end) end arg = tonumber(req:match("b=([0-9]+)")) if arg then - setduty(7, arg) + -- fade(getduty(PIN_B), arg, FADE_MS, function(val) + var = arg + setduty(PIN_B, arg) + -- end) end -- Send back JSON response. connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\nConnection: close\r\n\r\n{'error':0, 'message':'OK'}") connection:close() end + +function fade(a, b, freq, callback) + local inc = 10 + local timer = tmr.create() + timer:alarm(30, tmr.ALARM_AUTO, function(timer) + if a < b then + callback(a) + a = a + inc + else + callback(b) + timer:unregister() + end + end) +end diff --git a/styles/_range-slider.scss b/styles/_range-slider.scss new file mode 100755 index 0000000..2c3223d --- /dev/null +++ b/styles/_range-slider.scss @@ -0,0 +1,100 @@ +// Styling Cross-Browser Compatible Range Inputs with Sass +// Github: https://github.com/darlanrod/input-range-sass +// Author: Darlan Rod https://github.com/darlanrod +// Version 1.3.0 +// MIT License +@import 'variables'; + +$track-color: $dark-gray; +$thumb-color: $light-gray; + +$thumb-radius: 0.7rem; +$thumb-height: 1.3rem; +$thumb-width: 0.2rem; + +$track-radius: 0.2rem; +$track-height: 0.3rem; +$track-width: 100%; +$contrast: 5%; + +@mixin track { + cursor: pointer; + height: $track-height; + transition: all .2s ease; + width: $track-width; +} + +@mixin thumb { + background: $thumb-color; + border-radius: $thumb-radius; + cursor: pointer; + height: $thumb-height; + width: $thumb-width; +} + +[type='range'] { + -webkit-appearance: none; + background: transparent; + width: $track-width; + height: $thumb-height * 4; + + &:focus { + outline: 0; + + &::-webkit-slider-runnable-track { + background: lighten($track-color, $contrast); + } + + &::-ms-fill-lower { + background: $track-color; + } + + &::-ms-fill-upper { + background: lighten($track-color, $contrast); + } + } + + &::-webkit-slider-runnable-track { + @include track; + background: $track-color; + border-radius: $track-radius; + } + + &::-webkit-slider-thumb { + @include thumb; + -webkit-appearance: none; + margin-top: ($track-height - $thumb-height) / 2; + } + + &::-moz-range-track { + @include track; + background: $track-color; + border-radius: $track-radius; + } + + &::-moz-range-thumb { + @include thumb; + } + + &::-ms-track { + @include track; + background: transparent; + border-color: transparent; + color: transparent; + } + + &::-ms-fill-lower { + background: darken($track-color, $contrast); + border-radius: $track-radius * 2; + } + + &::-ms-fill-upper { + background: $track-color; + border-radius: $track-radius * 2; + } + + &::-ms-thumb { + @include thumb; + margin-top: 0; + } +} diff --git a/styles/_variables.scss b/styles/_variables.scss new file mode 100755 index 0000000..5579e8c --- /dev/null +++ b/styles/_variables.scss @@ -0,0 +1,9 @@ +$white-gray: #aaaaaa; +$light-gray: #777777; +$mid-gray: #3a3a3a; +$dark-gray: #171717; + +$heading-font: 'Teko', sans-serif; +$heading-font-size: 4.0rem; +$body-font: sans-serif; +$body-font-size: 1.2rem; diff --git a/styles/light.scss b/styles/light.scss new file mode 100755 index 0000000..118195d --- /dev/null +++ b/styles/light.scss @@ -0,0 +1,89 @@ +@import 'variables'; +@import 'range-slider'; +body { + background: black; + font-family: $body-font; + font-size: $body-font-size; + color: $mid-gray; +} + +h1 { + text-transform: lowercase; + font-family: $heading-font; + font-size: $heading-font-size; + color: $light-gray; + margin: 0; +} + +h2 { + @extend h1; + font-size: 2.0rem; +} + +button { + border: none; + color: $light-gray; + font-family: $body-font; + font-size: $body-font-size; + padding: 0.3em 1.0em; + margin: 0.2em; + &:focus { + outline: none; + } +} + +canvas { + top: 0; + left: 0; + width: 100%; + height: 85%; + position: absolute; +} + +.toolbar { + position: absolute; + bottom: 0; + left: 0; + height: 15%; + width: 100%; + padding-bottom: 0.6rem; +} + +.title-section { + float: left; + width: 20rem; + bottom: 0; + display: inline-block; + & > * { + display: inline-block; + } + + h1 { + padding: 0 1.2rem; + margin-left: 1.2rem; + } +} + +.position-select { + button { + width: 7em; + display: block; + background: $dark-gray; + &:disabled { + color: $white-gray; + background: $mid-gray; + } + } +} + +#btn-1 { + border-radius: 0.5em 0.5em 0 0; +} +#btn-2 { + border-radius: 0 0 0.5em 0.5em; +} + +.slider-section { + padding: 0rem 3rem; + margin-left: 20rem; +} From 301394da2a4ad103de1719ca55ea37eb7f34bf7c Mon Sep 17 00:00:00 2001 From: Stephanie Ng Date: Tue, 4 Apr 2017 17:54:13 +0800 Subject: [PATCH 2/2] Put js code into html and replace old rgb.lua with correct file --- index.html | 138 +++++++++++++++++++++++++++++++++++++++++++++-------- light.js | 97 ------------------------------------- rgb.lua | 65 ++++++++++++------------- 3 files changed, 149 insertions(+), 151 deletions(-) delete mode 100755 light.js diff --git a/index.html b/index.html index 5ca2983..7a4160e 100755 --- a/index.html +++ b/index.html @@ -1,26 +1,126 @@ - - Helios - - - - - -
-
-

Helios

- -
- - -
-
+ + Helios + + + + + +
+
+

Helios

-
- +
+ +
- + +
+ +
+
+ + diff --git a/light.js b/light.js deleted file mode 100755 index f97b73a..0000000 --- a/light.js +++ /dev/null @@ -1,97 +0,0 @@ -var HOSTS = [ - 'helios2.lan', - 'helios.lan' -]; -var host = HOSTS[0]; - -var canvas = document.getElementById('colorspace'); -var btn1 = document.getElementById('btn-1'); -var btn2 = document.getElementById('btn-2'); -var ctx = canvas.getContext('2d'); - -drawCanvas(); - -function changeHost(id) { - this.host = HOSTS[id]; - if(id) { - btn1.disabled = false; - btn2.disabled = true; - } else { - btn1.disabled = true; - btn2.disabled = false; - } -} - -function sendColour(rgb) { - var params = [ - 'r=' + rgb[0], - 'g=' + rgb[1], - 'b=' + rgb[2] - ].join('&'); - - var req = new XMLHttpRequest(); - console.log(params); - req.open("POST", 'http://' + host + '/rgb.lua?' + params, true); - req.send(); -} - -function colourCorrect(v) { - return Math.round(1023-(v*v)/64); -} - -function handleEvent(clientX, clientY) { - var data = ctx.getImageData(clientX, clientY, 1, 1).data; - var rgb = []; - for(var i=0; i<3; i++) { - rgb[i] = colourCorrect(data[i]); - } - sendColour(rgb); -} - -canvas.addEventListener("touchmove", function(event){ - handleEvent(event.touches[0].clientX, event.touches[0].clientY); -}, false); - -var mouseDown = false; -document.ontouchmove = function(e) {e.preventDefault()}; -canvas.addEventListener('mousedown', function(event) { - if (event.button == 0) { - handleEvent(event.x, event.y); - mouseDown = true; - } -}, false); - -document.addEventListener('mouseup', function(event) { - if (event.button == 0) { - mouseDown = false; - } -}, false); - -canvas.addEventListener('mousemove', function(event) { - if (mouseDown) { - handleEvent(event.x, event.y); - } -}, false); - -function drawCanvas(brightness = 100) { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - var brt = Math.round((brightness / 100) * 255); - var colours = ctx.createLinearGradient(30, 0, canvas.width, 0); - for(var i=0; i <= 360; i+=10) { - colours.addColorStop(i/360, 'hsl(' + i + ', 100%, '+ brightness/2 + '%)'); - } - - ctx.fillStyle = colours; - ctx.fillRect(0, 0, canvas.width, canvas.height); - - var luminance = ctx.createLinearGradient(0, 0, 0, canvas.height); - luminance.addColorStop(0.0, 'rgba(' + brt + ',' + brt + ',' + brt + ',' + brightness/100 + ')'); - luminance.addColorStop(0.5, 'rgba(255,255,255,0)'); - luminance.addColorStop(0.5, 'rgba(0,0,0,0)'); - luminance.addColorStop(1, '#000000'); - - ctx.fillStyle = luminance; - ctx.fillRect(0, 0, canvas.width, canvas.height); -} - diff --git a/rgb.lua b/rgb.lua index 2e9e93c..cf2c1c2 100644 --- a/rgb.lua +++ b/rgb.lua @@ -2,50 +2,45 @@ PIN_R = 5 PIN_G = 6 PIN_B = 7 -FADE_MS = 100 +FADE_MS = 8 +INTERVAL = 5 +getduty = pwm.getduty +setduty = pwm.setduty + +function fade(pin, x, tid) + local a = getduty(pin) + local mult = 1 + if a>x then mult = -1 end + + tmr.alarm(tid, FADE_MS, tmr.ALARM_AUTO, function() + if math.abs(x-a) <= INTERVAL then + setduty(pin, x) + tmr.unregister(tid) + elseif a~=x then + setduty(pin, a) + a = a + (INTERVAL * mult) + end + end) +end return function (connection, req) - local getduty = pwm.getduty - local setduty = pwm.setduty - - local arg = tonumber(req:match("r=([0-9]+)")) - if arg then - -- fade(getduty(PIN_R), arg, FADE_MS, function(val) - setduty(PIN_R, arg) - -- end) + local r = tonumber(req:match("r=([0-9]+)")) + local g = tonumber(req:match("g=([0-9]+)")) + local b = tonumber(req:match("b=([0-9]+)")) + + if r then + fade(PIN_R, r, 0) end - arg = tonumber(req:match("g=([0-9]+)")) - if arg then - -- fade(getduty(PIN_G), arg, FADE_MS, function(val) - var = arg - setduty(PIN_G, arg) - -- end) + if g then + fade(PIN_G, g, 1) end - arg = tonumber(req:match("b=([0-9]+)")) - if arg then - -- fade(getduty(PIN_B), arg, FADE_MS, function(val) - var = arg - setduty(PIN_B, arg) - -- end) + if b then + fade(PIN_B, b, 2) end -- Send back JSON response. connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\nConnection: close\r\n\r\n{'error':0, 'message':'OK'}") connection:close() end - -function fade(a, b, freq, callback) - local inc = 10 - local timer = tmr.create() - timer:alarm(30, tmr.ALARM_AUTO, function(timer) - if a < b then - callback(a) - a = a + inc - else - callback(b) - timer:unregister() - end - end) -end