Last active
August 29, 2015 14:04
-
-
Save gmamaladze/4a39e45de6d604bb4775 to your computer and use it in GitHub Desktop.
Lego Power Functions Remote Control UI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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