Initial commit

This commit is contained in:
2026-10-31 23:35:38 -05:00
parent 652d95803b
commit 6833e7acd5
10 changed files with 908 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
ul, li {
list-style: none;
margin: 0em;
padding: 0em;
}
div { padding: 0.5em; }
#header { max-height: 4em; }
#menu { background-color: #FFDAB9; height: -webkit-fill-available; }
#script { background-color: #B0C4DE; height: -webkit-fill-available; }
#menu > .script-block { background-color: #FF7F4F !important; }
#script > .script-block,
.script-nest > .script-block { background-color: #1E90FF !important; }
#script .script-nest { background-color: #B0C4DE !important; }
.flex-parent {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
gap: 2em;
}
.flex-child {
min-height: 12em;
width: auto;
}
.script-block,
.script-nest,
.border {
border: 0.15em solid #000000;
border-radius: 0.6em;
}
.script-block,
.script-nest {
display: block;
margin-top: 0.5em;
margin-bottom: 0.5em;
padding: 0.5em;
}
.script-nest { background-color: #FFDAB9; }
+168
View File
@@ -0,0 +1,168 @@
class BaseScriptElement extends HTMLElement {
get prefix() { return 'BaseScriptElement'; }
constructor() { super(); }
connectedCallback() {
this.innerHTML = `
<li>
<label>${this.prefix}</label>
</li>
`;
}
action(...args) { console.log("Hello, World!"); }
}
class BaseInputScriptElement extends BaseScriptElement {
get prefix() { return 'BaseInputScriptElement'; }
get defaultValue() { return '1'; }
get postfix() { return ''; }
get value() { return this.getElementsByClassName("script-input")[0].value; }
constructor() { super(); }
connectedCallback() {
this.innerHTML = `
<li>
<label>${this.prefix}</label>
<input type="text" class="script-input" value="${this.defaultValue}"/>
<label>${this.postfix}</label>
</li>
`;
}
action() { console.log( this.value ); }
}
class RepeatElement extends BaseInputScriptElement {
get prefix() { return 'Repeat'; }
get defaultValue() { return '10'; }
get children() {
return this.getElementsByClassName("script-nest")[0].children;
}
connectedCallback() {
this.innerHTML = `
<li>
<label>${this.prefix}</label>
<input type="text" class="script-input" value="${this.defaultValue}"/>
<label>${this.postfix}</label>
<ul class="script-nest"
ondrop="dragDropHandler(event)"
ondragover="dragOverHandler(event)"
></ul>
</li>
`;
}
action(Painter) {
for (let i = 0; i < this.value; i++) {
console.log(Painter.rotation)
for (const elm of this.children) {
elm.action(Painter);
}
}
}
}
class LeftElement extends BaseInputScriptElement {
get prefix() { return 'Left'; }
get defaultValue() { return '5'; }
get postfix() { return 'degrees'; }
constructor() { super(); }
action(Painter) { Painter.rotation -= this.value; }
}
class RightElement extends BaseInputScriptElement {
get prefix() { return 'Right'; }
get defaultValue() { return '5'; }
get postfix() { return 'degrees'; }
constructor() { super(); }
action(Painter) { Painter.rotation += this.value; }
}
class ForwardElement extends BaseInputScriptElement {
get prefix() { return 'Forward'; }
get defaultValue() { return '10'; }
get postfix() { return 'steps'; }
constructor() { super(); }
action(Painter) {
let magnitude = this.value
let radians = Painter.rotation * (Math.PI / 180);
const x2 = Painter.x1 + magnitude * Math.cos(radians);
const y2 = Painter.y1 + magnitude * Math.sin(radians);
Painter.x1 = x2
Painter.y1 = y2
if (Painter.isPenLifted) {
Painter.canvasContext.moveTo(x2, y2);
return;
}
Painter.canvasContext.lineTo(x2, y2);
Painter.canvasContext.stroke();
Painter.canvasContext.moveTo(x2, y2);
}
}
class BackElement extends BaseInputScriptElement {
get prefix() { return 'Back'; }
get defaultValue() { return '10'; }
get postfix() { return 'steps'; }
constructor() { super(); }
action(Painter) {
let magnitude = this.value
let radians = (Painter.rotation + 180) % 360;
const x2 = Painter.x1 + magnitude * Math.cos(radians);
const y2 = Painter.y1 + magnitude * Math.sin(radians);
Painter.x1 = x2
Painter.y1 = y2
if (Painter.isPenLifted) {
Painter.canvasContext.moveTo(x2, y2);
return;
}
Painter.canvasContext.lineTo(x2, y2);
Painter.canvasContext.stroke();
Painter.canvasContext.moveTo(x2, y2);
}
}
class CircleElement extends BaseInputScriptElement {
get prefix() { return 'Circle'; }
get defaultValue() { return '20'; }
get postfix() { return 'radius'; }
constructor() { super(); }
action(Painter) {
Painter.canvasContext.beginPath();
Painter.canvasContext.arc(95, 50, 40, 0, 2 * Math.PI);
Painter.canvasContext.stroke();
}
}
class PenUpElement extends BaseScriptElement {
get prefix() { return 'Pen Up'; }
constructor() { super(); }
action(Painter) { Painter.isPenLifted = true; }
}
class PenDownElement extends BaseScriptElement {
get prefix() { return 'Pen Down'; }
constructor() { super(); }
action(Painter) { Painter.isPenLifted = false; }
}
class BackToCenterElement extends BaseScriptElement {
get prefix() { return 'Back to Center'; }
constructor() { super(); }
action(Painter) {
Painter.x1 = Painter.canvas.width / 2
Painter.y1 = Painter.canvas.height / 2
Painter.canvasContext.moveTo( Painter.x1, Painter.y1 );
}
}
class HideTurtleElement extends BaseScriptElement {
get prefix() { return 'Hide Turtle'; }
constructor() { super(); }
}
+24
View File
@@ -0,0 +1,24 @@
window.onload = (eve) => {
setupMenuBlocks();
setupDragAndDrop();
setupScriptRunner();
}
clearBttn.onclick = (eve) => {
console.log("Clear");
}
saveBttn.onclick = (eve) => {
console.log("Save");
}
loadBttn.onclick = (eve) => {
console.log("Load");
}
runBttn.onclick = (eve) => {
console.log("Run");
runScript();
}
+24
View File
@@ -0,0 +1,24 @@
const ScriptElms = {
"repeat-element": RepeatElement,
"left-element": LeftElement,
"right-element": RightElement,
"forward-element": ForwardElement,
"back-element": BackElement,
"circle-element": CircleElement,
"pen-up-element": PenUpElement,
"pen-down-element": PenDownElement,
"back-to-center-element": BackToCenterElement,
"hider-turtle-element": HideTurtleElement
};
let Painter = {
canvas: null,
canvasContext: null,
rotation: 0,
x1: 0,
y1: 0,
isPenLifted: false
}
let draggedElm = null;
@@ -0,0 +1,29 @@
const setupScriptRunner = () => {
canvasContext = canvas.getContext("2d");
Painter.canvas = canvas;
Painter.canvasContext = canvasContext;
}
const runScript = () => {
setToCenter();
resetRotation();
clearCanvas();
for (const elm of script.children) {
elm.action(Painter);
}
}
const setToCenter = () => {
Painter.x1 = Painter.canvas.width / 2
Painter.y1 = Painter.canvas.height / 2
Painter.canvasContext.moveTo( Painter.x1, Painter.y1 );
}
const clearCanvas = () => {
Painter.canvasContext.clearRect(0, 0, canvas.width, canvas.height);
}
const resetRotation = () => {
Painter.rotation = 0;
}
+61
View File
@@ -0,0 +1,61 @@
const setupMenuBlocks = () => {
for (const [key, value] of Object.entries(ScriptElms)) {
customElements.define(key, value);
const elm = document.createElement(key);
elm.className = "script-block";
elm.draggable = true
elm.ondragstart = dragStartHandler
menu.append(elm);
}
}
const setupDragAndDrop = () => {
script.ondrop = dragDropHandler
script.ondragover = dragOverHandler
header.ondrop = dragDropHandler
header.ondragover = dragOverHandler
const flexParents = document.getElementsByClassName("flex-parent");
for (let i = 0; i < flexParents.length; i++) {
flexParents[i].ondrop = dragDropHandler
flexParents[i].ondragover = dragOverHandler
}
}
const dragStartHandler = (eve) => {
draggedElm = eve.target;
console.debug("Node: ", draggedElm);
eve.dataTransfer.setData("text", eve.target.tagName.toLowerCase());
}
const dragOverHandler = (eve) => { eve.preventDefault(); }
const dragDropHandler = (eve) => {
eve.preventDefault();
eve.stopPropagation();
const tagTarget = eve.currentTarget;
if (
eve.currentTarget.id.toLowerCase() === "header" ||
eve.currentTarget.classList.contains("flex-parent")
) {
if ( draggedElm.parentNode.id.toLowerCase() !== "menu" ) {
destroyScriptBlock(draggedElm, tagTarget);
}
return;
}
addBlockToScript(draggedElm, tagTarget);
}
const addBlockToScript = (draggedTarget, tagTarget) => {
const elm = draggedTarget.cloneNode(true);
elm.ondragstart = dragStartHandler
tagTarget.appendChild(elm);
}
const destroyScriptBlock = (draggedTarget, tagTarget) => {
draggedTarget.remove();
}