├── README.md ├── img └── logo.png ├── LICENSE ├── index.html ├── js ├── index.js └── colorwheel.js └── css └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # LED RGB Guru 2 | RGB LED controller powered by AgnosThings API 3 | -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivafarabi/LED-RGB-Guru/master/img/logo.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Riva Farabi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | RGB LED Guru by Riva Farabi 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | RGB LED Guru 24 |
25 | 29 |
30 |
31 |
32 |
#hex 33 |
34 |
35 |
36 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | var profiles = {}; 2 | var colors; 3 | var r; 4 | var g; 5 | var b; 6 | var yiq; 7 | var status = $(".status"); 8 | 9 | $(document).ready(function () { 10 | loadColorWheel(); 11 | }) 12 | 13 | function loadColorWheel() { 14 | var cw = Raphael.colorwheel($(".colorwheel")[0], 300, 250) 15 | .color("#006eff") 16 | .ondrag(startDrag, stopDrag); 17 | 18 | cw.input($("body")[0]); 19 | 20 | function startDrag() { 21 | $(".status").text("").fadeIn(); 22 | } 23 | 24 | function stopDrag() { 25 | console.log(r, g, b) 26 | sendAPI(r, g, b); 27 | } 28 | 29 | cw.onchange(function (color) { 30 | r = parseInt(color.r); 31 | g = parseInt(color.g); 32 | b = parseInt(color.b); 33 | yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; 34 | $(".textcontrast").css("color", (yiq >= 128) ? 'black' : 'white'); 35 | $("button").css("border-color", (yiq >= 128) ? 'black' : 'white'); 36 | $(".svg-icon").css("fill", (yiq >= 128) ? 'black' : 'white'); 37 | $(".hexcolor").text(color.hex); 38 | }) 39 | } 40 | 41 | function sendAPI(r, g, b) { 42 | var xmlhttp = new XMLHttpRequest(); 43 | xmlhttp.open("GET", "http://agnosthings.com/d0733d1a-08b0-11e6-8001-005056805279/feed?push=red=" + r + ",blue=" + b + ",green=" + g + ",active=" + 1); 44 | xmlhttp.onreadystatechange = function () { 45 | if (xmlhttp.status == 200) { 46 | var data = JSON.parse(xmlhttp.responseText); 47 | console.log(data.value); 48 | $(".status").text("color updated!").fadeOut(2000); 49 | } else { 50 | $(".status").text("error! check your internet connection.").fadeOut(2000); 51 | } 52 | } 53 | xmlhttp.send(); 54 | } 55 | 56 | function showGuid() { 57 | alert("AgnosThings GUID : \n0733d1a-08b0-11e6-8001-005056805279"); 58 | } 59 | 60 | function shareFacebook(){ 61 | window.open("https://www.facebook.com/sharer/sharer.php?u=rgbledguru.droppages.com"); 62 | } -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Lato', sans-serif; 3 | margin: 0; 4 | -webkit-user-select: none; 5 | -moz-user-select: none; 6 | -ms-user-select: none; 7 | } 8 | 9 | button { 10 | height: 50px; 11 | padding: 8px; 12 | border: 1px solid white; 13 | border-radius: 6px; 14 | background-color: transparent; 15 | margin-right: 6px; 16 | margin-left: 6px; 17 | color: white; 18 | font-size: 16px; 19 | cursor: pointer; 20 | font-weight: 300; 21 | } 22 | button:hover{ 23 | background-color: rgba(255,255,255,0.3); 24 | } 25 | 26 | header, 27 | footer, 28 | .hexcolor { 29 | color: white; 30 | } 31 | 32 | header { 33 | height: 60px; 34 | padding-left: 20px; 35 | padding-right: 20px; 36 | padding-top: 20px; 37 | } 38 | 39 | header .title { 40 | float: left; 41 | font-size: 32px; 42 | font-weight: 900; 43 | } 44 | 45 | header .title > span { 46 | font-weight: 300; 47 | } 48 | 49 | header .nav { 50 | position: relative; 51 | float: right; 52 | text-align: right; 53 | } 54 | 55 | i{ 56 | vertical-align: middle; 57 | } 58 | 59 | footer { 60 | position: absolute; 61 | bottom: 0px; 62 | padding-top: 16px; 63 | padding-bottom: 16px; 64 | width: 100%; 65 | text-align: center; 66 | } 67 | 68 | .color-picker { 69 | position: absolute; 70 | margin: auto; 71 | margin-top: 40px; 72 | left: 0; 73 | right: 0; 74 | height: 300px; 75 | width: 300px; 76 | border-radius: 150px; 77 | background-color: white; 78 | border: 5px solid white; 79 | } 80 | 81 | .hexcolor { 82 | margin-top: 20px; 83 | color: white; 84 | font-size: 24pt; 85 | text-align: center; 86 | font-weight: 300; 87 | } 88 | 89 | .status{ 90 | color: white; 91 | font-size: 24pt; 92 | font-weight: 300; 93 | text-align: center; 94 | } 95 | 96 | .sharebutton{ 97 | float: left; 98 | padding: 7px; 99 | border: 1px solid white; 100 | border-radius: 6px; 101 | background-color: transparent; 102 | text-decoration: none; 103 | color: white; 104 | font-size: 18px; 105 | cursor: pointer; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /js/colorwheel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Colorwheel 3 | * Copyright (c) 2010 John Weir (http://famedriver.com) 4 | * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 5 | * 6 | * requires jQuery & Raphael 7 | * http://jquery.com http://raphaeljs.com 8 | * 9 | * see http://jweir.github.com/colorwheel for Usage 10 | * 11 | */ 12 | 13 | Raphael.colorwheel = function(target, color_wheel_size, no_segments){ 14 | var canvas, 15 | current_color, 16 | current_color_hsb, 17 | size, 18 | segments = no_segments || 60, 19 | bs_square = {}, 20 | hue_ring = {}, 21 | tri_size, 22 | cursor = {}, 23 | drag_target, 24 | input_target, 25 | center, 26 | parent, 27 | change_callback, 28 | drag_callbacks = [function(){}, function(){}], 29 | offset, 30 | padding = 2, 31 | sdim; // holds the dimensions for the saturation square 32 | 33 | function point(x, y){ return {x:x, y:y};} 34 | function radians(a){ return a * (Math.PI/180);} 35 | 36 | function angle(x,y){ 37 | var q = x > 0 ? 0 : 180; 38 | return q+Math.atan((0 - y)/(0 - x))*180/(Math.PI); 39 | } 40 | 41 | function create(target, color_wheel_size){ 42 | size = color_wheel_size; 43 | tri_size = size/20; 44 | center = size/2; 45 | parent = $(target); 46 | canvas = Raphael(parent[0],size, size); 47 | // canvas.safari(); 48 | 49 | create_bs_square(); 50 | create_hue_ring(); 51 | hue_ring.cursor = cursor_create(tri_size); 52 | bs_square.cursor = cursor_create(tri_size*0.5); 53 | events_setup(); 54 | parent.css({height:size+"px", width:size+"px"}); 55 | disable_select(parent); 56 | return public_methods(); 57 | } 58 | 59 | function disable_select(target){ 60 | $(target).css({"unselectable": "on","-moz-user-select": "none","-webkit-user-select": "none"}); 61 | } 62 | 63 | function public_methods(){ 64 | return { 65 | input: input, 66 | onchange: onchange, 67 | ondrag : ondrag, 68 | color : public_set_color, 69 | color_hsb : public_set_color_hsb 70 | }; 71 | } 72 | 73 | // Sets a textfield for user input of hex color values 74 | // TODO don't clear the change callback 75 | // TODO allow a null target to unbind the input 76 | function input(target){ 77 | change_callback = null; 78 | input_target = target; 79 | $(target).keyup(function(){ 80 | if(this.value.match(/^#([0-9A-F]){3}$|^#([0-9A-F]){6}$/img)){ 81 | set_color(this.value); 82 | update_color(true); 83 | run_onchange_event(); 84 | } 85 | }); 86 | set_color(target.value); 87 | update_color(true); 88 | 89 | return public_methods(); 90 | } 91 | 92 | function onchange(callback){ 93 | change_callback = callback; 94 | update_color(false); 95 | return public_methods(); 96 | } 97 | 98 | function ondrag(start_callback, end_callback){ 99 | drag_callbacks = [start_callback || function(){}, end_callback || function(){}]; 100 | return public_methods(); 101 | } 102 | 103 | function drag(e){ 104 | var x, y, page; 105 | 106 | e.preventDefault(); // prevents scrolling on touch 107 | 108 | page = e.originalEvent.touches ? e.originalEvent.touches[0] : e; 109 | 110 | x = page.pageX - (parent.offset().left + center); 111 | y = page.pageY - (parent.offset().top + center); 112 | 113 | if(drag_target == hue_ring){ 114 | set_hue_cursor(x,y); 115 | update_color(); 116 | run_onchange_event(); 117 | return true; 118 | } 119 | if(drag_target == bs_square){ 120 | set_bs_cursor(x,y); 121 | update_color(); 122 | run_onchange_event(); 123 | return true; 124 | } 125 | } 126 | 127 | function start_drag(event, target){ 128 | event.preventDefault(); // prevents scrolling on touch 129 | 130 | $(document).on('mouseup touchend',stop_drag); 131 | $(document).on('mousemove touchmove',drag); 132 | drag_target = target; 133 | drag(event); 134 | drag_callbacks[0](current_color); 135 | } 136 | 137 | function stop_drag(event){ 138 | event.preventDefault(); // prevents scrolling on touch 139 | 140 | $(document).off("mouseup touchend",stop_drag); 141 | $(document).off("mousemove touchmove",drag); 142 | drag_callbacks[1](current_color); 143 | run_onchange_event(); 144 | } 145 | 146 | function events_setup(){ 147 | $([hue_ring.event.node,hue_ring.cursor[0].node]).on("mousedown touchstart", 148 | function(e){start_drag(e,hue_ring);}); 149 | $([bs_square.b.node, bs_square.cursor[0].node]).on("mousedown touchstart", 150 | function(e){start_drag(e,bs_square);}); 151 | } 152 | 153 | function cursor_create(size){ 154 | var set = canvas.set().push( 155 | canvas.circle(0, 0, size).attr({"stroke-width":4, stroke:"#333"}), 156 | canvas.circle(0, 0, size+2).attr({"stroke-width":1, stroke:"#FFF", opacity:0.5}) 157 | ); 158 | 159 | set[0].node.style.cursor = "crosshair"; 160 | 161 | return set; 162 | } 163 | 164 | function set_bs_cursor(x,y){ 165 | x = x+center; 166 | y = y+center; 167 | if(x < sdim.x){x = sdim.x} 168 | if(x > sdim.x+sdim.l){x = sdim.x+sdim.l} 169 | if(y < sdim.y){y = sdim.y} 170 | if(y > sdim.y+sdim.l){y = sdim.y + sdim.l} 171 | 172 | bs_square.cursor.attr({cx:x, cy:y}).transform("t0,0"); 173 | } 174 | 175 | 176 | function set_hue(color){ 177 | var hex = Raphael.getRGB(color).hex; 178 | bs_square.h.attr("fill", hex); 179 | } 180 | 181 | function hue(){ 182 | return Raphael.rgb2hsb(bs_square.h.attr("fill")).h; 183 | } 184 | 185 | function public_set_color(value){ 186 | var ret = set_color(value, false); 187 | update_color(false); 188 | return ret; 189 | } 190 | 191 | function public_set_color_hsb(hsb){ 192 | var ret = set_color(hsb, true); 193 | update_color(false); 194 | return ret; 195 | } 196 | 197 | function set_color(value, is_hsb){ 198 | if(value === undefined){ 199 | if(is_hsb){ 200 | return current_color_hsb; 201 | } else { 202 | return current_color; 203 | } 204 | } 205 | 206 | var hsb, hex; 207 | if(is_hsb){ 208 | hsb = value; 209 | // Allow v (value) instead of b (brightness), as v is sometimes 210 | // used by Raphael. 211 | if(hsb.b === undefined){ hsb.b = hsb.v; } 212 | var rgb = canvas.raphael.hsb2rgb(hsb.h, hsb.s, hsb.b); 213 | hex = rgb.hex; 214 | } else { 215 | hex = value; 216 | hsb = canvas.raphael.rgb2hsb(hex); 217 | } 218 | var temp = canvas.rect(1,1,1,1).attr({fill:hex}); 219 | 220 | set_bs_cursor( 221 | (0-sdim.l/2) + (sdim.l*hsb.s), 222 | sdim.l/2 - (sdim.l*hsb.b)); 223 | set_hue_cursor((360*(hsb.h))-90); 224 | temp.remove(); 225 | return public_methods(); 226 | } 227 | 228 | // Could optimize this method 229 | function update_color(dont_replace_input_value){ 230 | var x = bs_square.cursor.items[0].attr("cx"), 231 | y = bs_square.cursor.items[0].attr("cy"), 232 | hsb = { 233 | b: 1-(y-sdim.y)/sdim.l, 234 | s: (x-sdim.x)/sdim.l, 235 | h: hue() 236 | }; 237 | 238 | 239 | current_color_hsb = hsb; 240 | current_color = Raphael.hsb2rgb(hsb.h, hsb.s,hsb.b); 241 | 242 | if(input_target){ 243 | var c = current_color.hex; 244 | if(dont_replace_input_value !== true) { input_target.value = c;} 245 | if(hsb.b < 0.5){ 246 | $(input_target).css("color", "#FFF"); 247 | } else { 248 | $(input_target).css("color", "#000"); 249 | } 250 | input_target.style.background = c; 251 | } 252 | 253 | } 254 | 255 | // accepts either x,y or d (degrees) 256 | function set_hue_cursor(mixed_args){ 257 | var d; 258 | if(arguments.length == 2){ 259 | d = angle(arguments[0],arguments[1]); 260 | } else { 261 | d = arguments[0]; 262 | } 263 | 264 | var x = Math.cos(radians(d)) * (center-tri_size-padding); 265 | var y = Math.sin(radians(d)) * (center-tri_size-padding); 266 | hue_ring.cursor.attr({cx:x+center, cy:y+center}).transform("t0,0"); 267 | set_hue("hsb("+(d+90)/360+",1,1)"); 268 | } 269 | 270 | function bs_square_dim(){ 271 | if(sdim){ return sdim;} 272 | var s = size - (tri_size * 4); 273 | sdim = { 274 | x:(s/6)+tri_size*2+padding, 275 | y:(s/6)+tri_size*2+padding, 276 | l:(s * 2/3)-padding*2 277 | }; 278 | return sdim; 279 | } 280 | 281 | function create_bs_square(){ 282 | bs_square_dim(); 283 | box = [sdim.x, sdim.y, sdim.l, sdim.l]; 284 | 285 | bs_square.h = canvas.rect.apply(canvas, box).attr({ 286 | stroke:"#EEE", gradient: "0-#FFF-#000", opacity:1}); 287 | bs_square.s = canvas.rect.apply(canvas, box).attr({ 288 | stroke:null, gradient: "0-#FFF-#FFF", opacity:0}); 289 | bs_square.b = canvas.rect.apply(canvas, box).attr({ 290 | stroke:null, gradient: "90-#000-#FFF", opacity:0}); 291 | bs_square.b.node.style.cursor = "crosshair"; 292 | } 293 | 294 | function hue_segement_shape(){ 295 | var path = "M -@W 0 L @W 0 L @W @H L -@W @H z"; 296 | return path.replace(/@H/img, tri_size*2).replace(/@W/img,tri_size); 297 | } 298 | 299 | function copy_segment(r, d, k){ 300 | var n = r.clone(); 301 | var hue = d*(255/k); 302 | 303 | var s = size/2, 304 | t = tri_size, 305 | p = padding; 306 | 307 | n.transform("t"+s+","+(s-t)+"r"+(360/k)*d+"t0,-"+(s-t-p)+""); 308 | 309 | n.attr({"stroke-width":0, fill:"hsb("+d*(1/k)+", 1, 0.85)"}); 310 | hue_ring.hues.push(n); 311 | } 312 | 313 | function create_hue_ring(){ 314 | var s = hue_segement_shape(), 315 | tri = canvas.path(s).attr({stroke:"rgba(0,0,0,0)"}).transform("t"+(size/2)+","+padding), 316 | k = segments; // # of segments to use to generate the hues 317 | 318 | hue_ring.hues = canvas.set(); 319 | 320 | for(n=0; n