Skip to content

Commit ae4d027

Browse files
committed
Support color types
1 parent d45c478 commit ae4d027

File tree

4 files changed

+367
-285
lines changed

4 files changed

+367
-285
lines changed

litweb/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ def presets():
9595
def colors():
9696
return jsonify(colors=lit.get_colors())
9797

98+
@app.route("/api/v1/color_types", methods=['GET'])
99+
def color_types():
100+
return jsonify(color_types=lit.get_color_types())
101+
98102
@app.route("/api/v1/ranges", methods=['GET'])
99103
def ranges():
100104
return jsonify(sections=[k for k in lit.get_sections()], zones=[k for k in lit.get_zones()])
101105

102-
@app.route("/api/v1/speeds", methods=['GET'])
103-
def speeds():
104-
return jsonify(speeds=lit.get_speeds())
105-
106106
@app.route("/api/v1/pixels", methods=['GET'])
107107
def pixels():
108108
return jsonify(pixels=lit.get_pixels())

litweb/static/js/script.js

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
let g_selectedRanges = [];
2+
let g_argControls = {};
3+
4+
let g_effectSelector;
5+
let g_speedSlider;
6+
let g_overlayedToggle;
7+
let g_opacityContainer;
8+
let g_opacitySlider;
9+
let g_backButton;
10+
let g_forwardButton;
11+
let g_sendButton;
12+
let g_offButton;
13+
let g_onButton;
14+
15+
function componentToHex(c) {
16+
let hex = c.toString(16);
17+
return hex.length == 1 ? "0" + hex : hex;
18+
}
19+
20+
function rgbToHex(rgb) {
21+
return "#" + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
22+
}
23+
24+
25+
function schemaToComponent(name, schemaElement, argFuncs, colors, colorTypes) {
26+
type = schemaElement.value.type;
27+
mainDiv = $('<div/>', { 'class': 'row' });
28+
mainDiv.append($('<div/>', {'class': 'col-sm-4'}));
29+
controlDiv = $('<div/>', {'class': 'panel panel-default'});
30+
controlDiv.append($('<div/>', {'class': 'panel-heading', text: name}));
31+
mainDiv.append($('<div/>', {'class': 'col-sm-4 centered_hor'}).append(controlDiv));
32+
mainDiv.append($('<div/>', {'class': 'col-sm-4'}));
33+
if (type == 'number') {
34+
slider = $('<input/>', {id: 'input_'+name, type: 'text', 'data-slider-value': schemaElement.value.default, 'data-slider-min': schemaElement.value.min, 'data-slider-max': schemaElement.value.max, 'data-slider-step': 0.1});
35+
controlDiv.append($('<div/>', {'class': 'panel-body'}).append(slider));
36+
slider.slider();
37+
argFuncs[name] = function(s) {
38+
return function() {
39+
return parseInt(s.slider("getValue"))
40+
}
41+
}(slider);
42+
return mainDiv;
43+
}
44+
else if (type == 'color') {
45+
colorTypeSelector = $('<select id="color_type_selector"></select>')
46+
$.each(colorTypes, function() {
47+
colorTypeSelector.append($("<option />").val(JSON.stringify({"name": this.name, "schema": this.schema})).text(this.name));
48+
});
49+
colorArgsDiv = $('<div/>');
50+
controlDiv.append($('<div/>', {'class': 'panel-body'}).append(colorTypeSelector).append(colorArgsDiv));
51+
52+
let colorArgFuncs = {};
53+
54+
colorTypeSelector.change(function() {
55+
colorArgsDiv.empty();
56+
colorArgFuncs = {};
57+
console.log(colorTypeSelector.val());
58+
let schema = $.parseJSON(colorTypeSelector.val()).schema;
59+
for (i in schema) {
60+
component = schemaToComponent(i, schema[i], colorArgFuncs, colors, colorTypes);
61+
colorArgsDiv.append(component);
62+
}
63+
});
64+
argFuncs[name] = function (selector){
65+
return function() {
66+
let args = {};
67+
for (control in colorArgFuncs) {
68+
args[control] = colorArgFuncs[control]();
69+
}
70+
return {type: $.parseJSON(colorTypeSelector.val()).name, args: args};
71+
}
72+
}(colorTypeSelector);
73+
colorTypeSelector.trigger('change');
74+
return mainDiv;
75+
} else if (type == 'rgb') {
76+
let start_color = schemaElement.value.default || [255, 255, 255];
77+
colorSelector = $('<input/>', {id: 'input_'+name, 'class': 'form-control colorpicker-element', type: 'text', 'data-format': 'hex', 'value': rgbToHex(start_color)});
78+
colorSelector.colorpicker({
79+
colorSelectors : colors,
80+
template: '<div class="colorpicker dropdown-menu">' +
81+
'<div class="colorpicker-saturation"><i><b></b></i></div>' +
82+
'<div class="colorpicker-hue"><i></i></div>' +
83+
'<div class="colorpicker-alpha"><i></i></div>' +
84+
'<div class="colorpicker-color"></div></div>' +
85+
'</div>',
86+
});
87+
argFuncs[name] = function (selector){
88+
return function() {
89+
let rgba = selector.data('colorpicker').color.toRGB();
90+
return [rgba['r'], rgba['g'], rgba['b']];
91+
}
92+
}(colorSelector);
93+
controlDiv.append(colorSelector);
94+
return mainDiv;
95+
}
96+
}
97+
98+
function getEffects() {
99+
return $.ajax({
100+
url: "/api/v1/effects",
101+
dataType: "json",
102+
});
103+
}
104+
105+
function getColorTypes() {
106+
return $.ajax({
107+
url: "/api/v1/color_types",
108+
dataType: "json"
109+
});
110+
}
111+
112+
function getColors() {
113+
return $.ajax({
114+
url: "/api/v1/colors",
115+
dataType: "json"
116+
});
117+
}
118+
119+
function getPresets() {
120+
return $.ajax({
121+
url: "/api/v1/presets",
122+
dataType: "json"
123+
});
124+
}
125+
126+
function getRanges() {
127+
return $.ajax({
128+
url: "/api/v1/ranges",
129+
dataType: "json"
130+
});
131+
}
132+
133+
function setupDynamicComponents(ranges, effects, presets, colorTypes, colors) {
134+
console.log("Loaded necessary data. Setting up components");
135+
console.log(effects);
136+
let hex_colors = {};
137+
138+
//Populate the color selector
139+
$.each(colors, function() {
140+
hex_colors[this.name] = rgbToHex(this.rgb);
141+
});
142+
143+
setupRanges(ranges);
144+
setupEffects(effects, hex_colors, colorTypes);
145+
setupPresets(presets);
146+
}
147+
148+
function setupEffects(effects, colors, colorTypes) {
149+
$.each(effects, function() {
150+
g_effectSelector.append($("<option />").val(JSON.stringify({'schema': this.schema, 'defaultSpeed': this.default_speed})).text(this.name));
151+
});
152+
153+
//When a different effect is chosen, hide/show appropriate options
154+
g_effectSelector.change(function() {
155+
$('#controls').empty();
156+
g_argControls = {};
157+
let effectInfo = $.parseJSON(g_effectSelector.val());
158+
g_speedSlider.slider('setValue', effectInfo.defaultSpeed)
159+
controls = effectInfo.schema;
160+
for (i in controls) {
161+
component = schemaToComponent(i, controls[i], g_argControls, colors, colorTypes);
162+
$('#controls').append(component);
163+
}
164+
});
165+
166+
//Update options for initially selected effect
167+
g_effectSelector.trigger("change");
168+
}
169+
170+
function setupPresets(presets) {
171+
$.each(presets, function() {
172+
let button =$("<button />").prop("type", "button").prop("id", "preset_"+this).addClass("btn btn-primary preset-btn").text(this);
173+
$("#presets").append(button);
174+
let preset = this;
175+
button.click(function() {
176+
$.post({
177+
url: `/api/v1/presets/${preset}`,
178+
data: "{}",
179+
contentType: "application/json",
180+
dataType: 'json'
181+
}).done(function(data) {
182+
if ( $(window).width() > 768) {
183+
$("#result").html("")
184+
$.notify({
185+
// options
186+
message: data.message
187+
},{
188+
// settings
189+
type: 'success'
190+
});
191+
}
192+
else {
193+
$("#result").html(data.message);
194+
}
195+
});
196+
});
197+
});
198+
}
199+
200+
function setupRanges(ranges) {
201+
$.each(ranges.sections, function() {
202+
let name = this;
203+
range_input = $("<input type='checkbox' data-toggle='toggle' data-off='" + name + "' data-on='" + name + "' data-width='72' data-height='32' checked>");
204+
g_selectedRanges.push(name);
205+
range_input.change(function(){
206+
if($(this).prop("checked")) {
207+
g_selectedRanges.push(name);
208+
}else {
209+
g_selectedRanges.splice(g_selectedRanges.indexOf(name), 1);
210+
}
211+
});
212+
switch_container = $("<div class='toggle_container'></div>");
213+
range_input.appendTo(switch_container);
214+
switch_container.appendTo("#range_switches");
215+
range_input.bootstrapToggle();
216+
});
217+
}
218+
219+
$(document).ready(function(){
220+
g_effectSelector = $("#effect_selector");
221+
g_speedSlider = $("#speed_slider");
222+
g_speedSlider.slider();
223+
g_overlayedToggle = $("#overlayed_toggle");
224+
g_overlayedToggle.bootstrapToggle("off");
225+
g_opacityContainer = $("#opacity_container");
226+
g_opacitySlider = $("#opacity_slider");
227+
g_opacitySlider.slider();
228+
g_backButton = $("#back");
229+
g_forwardButton = $("#forward");
230+
g_sendButton = $("#send");
231+
g_offButton = $("#off");
232+
g_onButton = $("#on");
233+
234+
$.when(getRanges(), getEffects(), getPresets(), getColorTypes(), getColors()).done(function (ranges, effects, presets, colorTypes, colors) {
235+
setupDynamicComponents(ranges[0], effects[0].effects, presets[0].presets, colorTypes[0].color_types, colors[0].colors);
236+
$("#main_container").fadeIn();
237+
}).fail(console.log);
238+
239+
g_overlayedToggle.change(function(){
240+
if(g_overlayedToggle.prop("checked")) {
241+
g_opacityContainer.fadeIn();
242+
}else {
243+
g_opacityContainer.fadeOut();
244+
}
245+
});
246+
247+
//Send the command
248+
g_sendButton.click(function(){
249+
let effect;
250+
let command;
251+
if(g_selectedRanges.length == 0){
252+
effect = "off";
253+
command = {
254+
effect: {
255+
args: {"ranges": "all"},
256+
properties: {overlayed: false}
257+
}
258+
}
259+
}
260+
else {
261+
let args = {};
262+
for (control in g_argControls) {
263+
args[control] = g_argControls[control]();
264+
}
265+
let overlayed = g_overlayedToggle.prop('checked');
266+
let opacity = overlayed? parseFloat(g_opacitySlider.slider('getValue')) : null;
267+
let speed = parseFloat(g_speedSlider.slider('getValue'));
268+
effect = g_effectSelector.children("option").filter(":selected").text();
269+
command = {
270+
args : args,
271+
properties: {
272+
ranges: g_selectedRanges,
273+
speed: speed,
274+
overlayed: overlayed,
275+
opacity: opacity
276+
}
277+
};
278+
}
279+
$.post({
280+
url: `/api/v1/effects/${effect}`,
281+
data: JSON.stringify(command),
282+
contentType: "application/json",
283+
dataType: 'json'
284+
}).done(function(data) {
285+
if ( $(window).width() > 768) {
286+
$("#result").html("")
287+
$.notify({
288+
// options
289+
message: data.message
290+
},{
291+
// settings
292+
type: 'success'
293+
});
294+
}
295+
else {
296+
$("#result").html(data.message)
297+
}
298+
});
299+
});
300+
301+
g_backButton.click(function() {
302+
let request = {
303+
"back": true
304+
};
305+
$.ajax({
306+
url: '/api/v1/history',
307+
type: 'post',
308+
data: JSON.stringify(request),
309+
contentType: "application/json",
310+
dataType: 'json',
311+
success: function(data) {
312+
if ( $(window).width() > 768) {
313+
$("#result").html("");
314+
$.notify({
315+
// options
316+
message: data.message
317+
},{
318+
// settings
319+
type: 'success'
320+
});
321+
}
322+
else {
323+
$("#result").html(data.message)
324+
}
325+
}
326+
});
327+
});
328+
329+
g_forwardButton.click(function() {
330+
let request = {
331+
"forward": true
332+
};
333+
$.ajax({
334+
url: '/api/v1/history',
335+
type: 'post',
336+
data: JSON.stringify(request),
337+
contentType: "application/json",
338+
dataType: 'json',
339+
success: function(data) {
340+
if ( $(window).width() > 768) {
341+
$("#result").html("")
342+
$.notify({
343+
// options
344+
message: data.message
345+
},{
346+
// settings
347+
type: 'success'
348+
});
349+
}
350+
else {
351+
$("#result").html(data.message)
352+
}
353+
}
354+
});
355+
});
356+
});
357+

0 commit comments

Comments
 (0)