Skip to content

Instantly share code, notes, and snippets.

@gmamaladze
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save gmamaladze/4a39e45de6d604bb4775 to your computer and use it in GitHub Desktop.
Save gmamaladze/4a39e45de6d604bb4775 to your computer and use it in GitHub Desktop.
Lego Power Functions Remote Control UI
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Lego Power Functions Remote Control</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
</head>
<body>
<style>
body { font-size: xx-small; }
.circle {
background-color: #ee1111;
border: 2px solid;
border-color: #b91d47;
color: white;
}
.largeCircle {
background-color: #2d89ef;
border: 1px solid;
border-color: #2b5797;
margin: 10px auto;
opacity: 0.7;
}
.container {
background: #eff4ff;
margin: 2px;
}
.list-row {
display: inline-block;
width: 100%;
}
.list-left {
float: left;
padding: 5px;
width: auto;
}
.list-right {
float: right;
padding: 5px;
}
.list-fixed {
float: left;
padding: 5px;
text-align: center;
width: 40%;
}
</style>
<script>
// Options
// +getArrow() : joystick, dial, vertical, horizontal
// +getChannel() : 1,2,3,4
// +getOutput() : red, blue
function Options(channelsContainer, outputsContainer, arrowsContainer, pinsContainer) {
this.createChannels(channelsContainer);
this.createOutputs(outputsContainer);
this.createArrows(arrowsContainer);
this.createPins(pinsContainer);
}
var joystick = "joystick";
var dial = "dial";
var vertical = "vertical";
var horizontal = "horizontal";
Options.prototype.getArrow = function() {
return $('input[name=' + this._arrowsId + ']:checked').val();
};
Options.prototype.getChannel = function() {
return $('input[name=' + this._channelsId + ']:checked').val();
};
Options.prototype.getOutput = function() {
return $('input[name=' + this._outputsId + ']:checked').val();
};
Options.prototype.getPinned = function() {
return $('input[name=' + this._pinsId + ']:checked').val() == "pinned";
};
Options.prototype.change = function(onchange) {
$('input[type=radio][name=' + this._pinsId + ']').change(onchange);
$('input[type=radio][name=' + this._arrowsId + ']').change(onchange);
};
Options.prototype.createChannels = function(container) {
var channel = $("<span></span>").uniqueId();
var id = channel.attr("id");
this._channelsId = id;
for (var i = 1; i < 5; i++) {
var ch = $("<input></input>")
.attr("type", "radio")
.attr("id", id + i)
.attr("name", id)
.attr("value", i);
if (i == 1) ch.attr("checked", "checked");
channel.append(ch);
var label = $("<label></label>")
.attr("for", ch.attr("id"))
.text(i);
channel.append(label);
}
channel.buttonset();
container.append(channel);
};
Options.prototype.createOutputs = function(container) {
var red = "red";
var blue = "blue";
var outputs = $("<span></span>").uniqueId();
var id = outputs.attr("id");
this._outputsId = id;
outputs
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + red)
.attr("name", id)
.attr("value", red)
.attr("checked", "checked"))
.append(
$("<label></label>")
.attr("for", id + red)
.text("red"))
//-----------------------------------
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + blue)
.attr("name", id)
.attr("value", blue))
.append(
$("<label></label>")
.attr("for", id + blue)
.text("blue"));
container.append(outputs);
outputs.buttonset();
};
Options.prototype.createPins = function(container) {
var pinned = "pinned";
var unpinned = "unpinned";
var pins = $("<span></span>").uniqueId();
var id = pins.attr("id");
this._pinsId = id;
pins
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + pinned)
.attr("name", id)
.attr("value", pinned)
.attr("checked", "checked"))
.append(
$("<label></label>")
.attr("for", id + pinned)
.text("Return to center when released"))
//-----------------------------------
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + unpinned)
.attr("name", id)
.attr("value", unpinned))
.append(
$("<label></label>")
.attr("for", id + unpinned)
.text("Remain at position even when released"));
container.append(pins);
$("#" + id + pinned)
.button({
text: false,
icons: { primary: "ui-icon-pin-w" }
});
$("#" + id + unpinned)
.button({
text: false,
icons: { primary: "ui-icon-pin-s" }
});
};
Options.prototype.createArrows = function(container) {
var joystick = "joystick";
var dial = "dial";
var vertical = "vertical";
var horizontal = "horizontal";
var controlType = $("<span></span>").uniqueId();
var id = controlType.attr("id");
this._arrowsId = id;
controlType
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + joystick)
.attr("name", id)
.attr("value", joystick)
.attr("checked", "checked"))
.append(
$("<label></label>")
.attr("for", id + joystick)
.text("Joystick"))
//-----------------------------------
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + dial)
.attr("name", id)
.attr("value", dial))
.append(
$("<label></label>")
.attr("for", id + dial)
.text("Dial"))
//-----------------------------------
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + vertical)
.attr("name", id)
.attr("value", vertical))
.append(
$("<label></label>")
.attr("for", id + vertical)
.text("Vertical"))
//-----------------------------------
.append(
$("<input></input>")
.attr("type", "radio")
.attr("id", id + horizontal)
.attr("name", id)
.attr("value", horizontal))
.append(
$("<label></label>")
.attr("for", id + horizontal)
.text("Horizontal"));
//-----------------------------------
container.append(controlType);
$("#" + id + joystick)
.button({
text: false,
icons: { primary: "ui-icon-arrow-4-diag" }
});
$("#" + id + dial)
.button({
text: false,
icons: { primary: "ui-icon-arrowrefresh-1-w" }
});
$("#" + id + vertical)
.button({
text: false,
icons: { primary: "ui-icon-arrow-2-n-s" }
});
$("#" + id + horizontal)
.button({
text: false,
icons: { primary: "ui-icon-arrow-2-e-w" }
});
};
//-----END Options---
function createControl() {
var container = $("<div></div>").addClass("list-left").addClass("container").button();
container.insertBefore($("#add"));
var row0 = $("<div></div>").addClass("list-row");
container.append(row0);
container.append($("<br></br>"));
var cell00 = $("<div></div>").addClass("list-left");
var cell10 = $("<div></div>").addClass("list-right");
row0.append(cell00);
row0.append(cell10);
var row1 = $("<div></div>").addClass("list-row");
container.append(row1);
container.append($("<br></br>"));
var cell01 = $("<div></div>").addClass("list-left");
var cell11 = $("<div></div>").addClass("list-right");
row1.append(cell01);
row1.append(cell11);
var row2 = $("<div></div>").addClass("list-row");
container.append(row2);
container.append($("<br></br>"));
var row3 = $("<div></div>").addClass("list-row");
container.append(row3);
container.append($("<br></br>"));
var options = new Options(cell00, cell10, cell01, cell11);
var display = new Display(row2);
var stick = new Stick(row3, options, display, 20, 70);
}
function Display(container) {
this._angle = $("<div></div>").addClass("list-fixed");
this._radius = $("<div></div>").addClass("list-fixed");
this.show(0, 0);
container.append(this._angle, this._radius);
}
Display.prototype.show = function(angle, radius) {
this._angle.text(angle + "°");
this._radius.text(radius + "%");
};
function Stick(container, options, display, r1, r2) {
this.r1 = r1;
this.r2 = r2;
var outerCircle = createCircle(r2).addClass("largeCircle");
var circle = createCircle(r1).addClass("circle");
outerCircle.append(circle);
var cx = outerCircle.offset().left + r2;
var cy = outerCircle.offset().top + r2;
circle.offset({ left: (r2 - r1), top: (r2 - r1) });
container.append(outerCircle);
var arrow = options.getArrow();
var isPinned = options.getPinned();
circle
.draggable({
revert: isPinned,
revertDuration: 100,
drag: onDrag,
stop: onStop
});
options.change(function() {
arrow = options.getArrow();
isPinned = options.getPinned();
var center = { top: cy - r1, left: cx - r1 };
circle.css(center);
var position = adjustPosition(center);
circle.css(position);
circle.draggable("option", "revert", isPinned);
});
function onDrag(event, ui) {
var position = adjustPosition(ui.position);
ui.position.left = position.left;
ui.position.top = position.top;
}
function onStop() {
var position = adjustPosition(circle.position());
circle.css(position);
}
function adjustPosition(position) {
var dcx = position.left - cx + r1;
var dcy = position.top - cy + r1;
var angleradinas = Math.atan2(dcx, -dcy);
var distance = Math.sqrt(Math.pow(dcx, 2) + Math.pow(dcy, 2));
var result = limit(arrow, dcx, dcy, r2, distance, angleradinas);
position.left = result.x + cx - r1;
position.top = result.y + cy - r1;
var rangleradinas = Math.atan2(result.x, -result.y);
var rangledegrees = Math.round(rangleradinas * (180 / Math.PI));
var rdistance = Math.sqrt(Math.pow(result.x, 2) + Math.pow(result.y, 2));
var rpercent = Math.round((rdistance / r2) * 100);
if (display) display.show(rangledegrees, rpercent);
return position;
}
}
function createCircle(r) {
var circle = $('<div></div>')
.css("-moz-border-radius", (r + 2) + "px")
.css("-webkit-border-radius", (r + 2) + "px")
.css("border-radius", (r + 2) + "px")
.css("width", 2 * r + "px")
.css("height", 2 * r + "px")
.css("position", "relative");
return circle;
}
function limit(arrow, x, y, r, distance, angle) {
var rx = Math.sin(angle) * r;
var ry = -Math.cos(angle) * r;
switch (arrow) {
case joystick:
return (distance <= r) ? { x: x, y: y } : { x: rx, y: ry };
case dial:
if (x == 0 && y == 0) {
return { x: 0, y: -r };
} else {
return { x: rx, y: ry };
}
case vertical:
return (distance <= r) ? { x: 0, y: y } : { x: 0, y: ry };
case horizontal:
return (distance <= r) ? { x: x, y: 0 } : { x: rx, y: 0 };
default:
return { x: 0, y: 0 };
}
};
$(function() {
var add = $("<div id='add'></div>")
.addClass("list-left")
.addClass("container")
.text("+ add another control")
.button()
.click(function() {
createControl();
});
$("body").append(add);
createControl();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment