JSFiddle - React, Tailwind, and code Playground
HTML
<div id="controls">
<div id="blocks">
<div class="block b-forward" data-action="forward"></div>
<div class="block b-left" data-action="left"></div>
<div class="block b-right" data-action="right"></div>
<div class="block b-function" data-action="function"></div>
</div>
<div id="board">
<div id="queue" class="func" data-name="main" data-entry="true"></div>
<div id="func" class="func" data-name="f"></div>
<button type="button" onclick="run()" id="run"></button>
<p>inspired by <a href="http://primo.io/" target="_blank">primo.io</a></p>
</div>
</div>
<div id="robot" style="display: none"></div>
CSS
* {
box-sizing: border-box;
}
body {
font-family: Helvetica, sans-serif;
}
#board {
background-color: hsl(37, 50%, 90%);
border-radius: 5px;
padding: 20px 50px;
}
#queue {
border: 5px solid transparent;
}
#func {
border: 5px solid hsl(160, 51%, 37%);
border-radius: 5px;
}
#robot {
width: 100px;
height: 100px;
border: 5px solid hsl(0, 0%, 80%);
border-radius: 5px;
position: absolute;
left: 500px;
top: 200px;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
transition: all 0.95s;
}
#controls {
text-align: center;
width: 300px;
}
.slot {
border: 10px solid hsl(21, 80%, 70%);
border-radius: 13px;
margin: 13px;
display: inline-block;
}
.block {
border: 1px solid transparent;
border-radius: 30px;
margin: 8px;
display: inline-block;
height: 30px;
width: 30px;
cursor: pointer;
}
.b-forward { background-color: hsl(354, 80%, 60%); }
.b-function { background-color: hsl(160, 51%, 37%); }
.b-left { background-color: hsl(200, 90%, 60%); }
.b-right { background-color: hsl(49, 100%, 70%); }
#run {
background-color: hsl(354, 80%, 60%);
border-radius: 10px;
border: 0px none;
margin-top: 20px;
width: 100%;
height: 30px;
outline: none;
cursor: pointer;
}
#run:active {
background-color: hsl(354, 80%, 50%);
}
JavaScript
Math.TAU = 2 * Math.PI;
var ROBOT = {
x: 500, y: 200,
angle: 0, speed: 100,
running: false
};
$(function () {
var q = $('#queue');
var f = $('#func');
var blocks = $('#blocks .block');
blocks.draggable({
revert: true,
revertDuration: 0,
helper: 'clone',
stop: function (ev) {
dropBlock($(this), ev.clientX, ev.clientY);
}
});
for (var i = 0; i < 12; ++i) {
addSlot(q);
}
for (var i = 0; i < 4; ++i) {
addSlot(f);
}
$('#board').on('click', '.slot', function () {
clearSlot($(this));
});
drawRobot(ROBOT);
$('#robot').show();
});
function dropBlock(block, x, y) {
var e = document.elementFromPoint(x, y);
if (!e) {
return;
}
e = $(e);
if (e.is('.slot')) {
clearSlot(e);
setSlot(e, block.data('action'));
}
}
function clearSlot(slot) {
slot.removeClass('b-forward b-left b-right b-function block');
slot.data('action', '');
}
function setSlot(slot, action) {
slot.addClass('block');
slot.addClass('b-' + action);
slot.data('action', action);
}
function addSlot(element) {
var slot = $('<div/>');
slot.addClass('slot');
element.append(slot);
}
function run() {
if (ROBOT.running) {
ROBOT.running = false;
return;
}
ROBOT.running = true;
var code = {};
$.each($('#board .func'), function (i, elm) {
elm = $(elm);
var name = elm.data('name');
code[name] = getActions(elm);
});
var state = {
data: { robot: ROBOT },
code: code,
frames: [{ func: 'main', ip: 0 }]
};
executeStep(state);
}
function executeStep(state) {
if (!state.data.robot.running) {
return;
}
var frame = state.frames[state.frames.length - 1];
if (!frame) {
state.data.robot.running = false;
return...