diff --git a/command.js b/command.js index 69d8492..be8bf2e 100644 --- a/command.js +++ b/command.js @@ -47,13 +47,13 @@ class CommandArg { this.validator = (str) => { return /^[-+]?[0-9]*\.?[0-9]*$/.test(str); } - + break; case ARGUMENT_TYPES.EXPRESSION: this.validator = (str) => { let res = /^[-+]?([0-9]+\.?[0-9]?|[0-9]*\.?[0-9]+)(\s[+-/*]{1}\s[-+]?([0-9]+\.?[0-9]?|[0-9]*\.?[0-9]+))*$/.test(str); return res; } - + break; } } else this.validator = validator; @@ -117,16 +117,15 @@ class CommandExecutor { break; case ARGUMENT_TYPES.FLOAT: this.values.push(parseFloat(value)); + break; case ARGUMENT_TYPES.COMMANDS: this.values.push( new Parser(value, this.callback).parse() ); break; - case ARGUMENT_TYPES.EXPRESSION: - //console.log(this.parseExpression(value)) - this.values.push(this.parseExpression(value).eval()) - + this.values.push(this.parseExpression(value).eval()); + break; case ARGUMENT_TYPES.PARAMETERS: // Example this.values.push(value.split(" ")); break; @@ -147,7 +146,6 @@ class CommandExecutor { e = new Expression(next,new Expression('$',token), right); } else return new Expression('$', token); - //console.log(right); if (right.lvl() > e.lvl()) { let new_left = new Expression(next, new Expression('$',token), right.left); e = new Expression(right.type, new_left, right.right); diff --git a/commandList.js b/commandList.js index b15358b..73eb84a 100644 --- a/commandList.js +++ b/commandList.js @@ -9,33 +9,25 @@ const commandLookUp = new CommandLookUp(); * and then the function to execute. */ commandLookUp.add( - new Command("fd", [new CommandArg("value", ARGUMENT_TYPES.EXPRESSION)], value => { - turtle.forward(value); }) ); commandLookUp.add( - new Command("bd", [new CommandArg("value", ARGUMENT_TYPES.EXPRESSION)], value => { - turtle.forward(-value); }) ); commandLookUp.add( - new Command("rt", [new CommandArg("value", ARGUMENT_TYPES.EXPRESSION)], value => { - turtle.right(value); }) ); commandLookUp.add( - new Command("lt", [new CommandArg("value", ARGUMENT_TYPES.EXPRESSION)], value => { - turtle.right(-value); }) ); @@ -55,9 +47,7 @@ commandLookUp.add( commandLookUp.add( new Command( "pensize", - [new CommandArg("size", ARGUMENT_TYPES.EXPRESSION)], - size => { turtle.strokeWeight = size; } @@ -68,10 +58,8 @@ commandLookUp.add( new Command( "setxy", [ - new CommandArg("x", ARGUMENT_TYPES.EXPRESSION), new CommandArg("y", ARGUMENT_TYPES.EXPRESSION) - ], (x, y) => { turtle.x = x; @@ -81,17 +69,13 @@ commandLookUp.add( ); commandLookUp.add( - new Command("setx", [new CommandArg("x", ARGUMENT_TYPES.EXPRESSION)], x => { - turtle.x = x; }) ); commandLookUp.add( - new Command("sety", [new CommandArg("y", ARGUMENT_TYPES.EXPRESSION)], y => { - turtle.y = y; }) ); diff --git a/expression.js b/expression.js index ff79632..e4d2e12 100644 --- a/expression.js +++ b/expression.js @@ -7,8 +7,8 @@ class Expression { eval() { if(this.type == '$') { - return parseFloat(this.left); - } else if(this.type == '/') { + return parseFloat(this.left); + } else if(this.type == '/') { return this.left.eval() / this.right.eval(); } else if(this.type == '*') { return this.left.eval() * this.right.eval(); diff --git a/index.html b/index.html index 7483bc6..caf21c9 100644 --- a/index.html +++ b/index.html @@ -34,22 +34,18 @@ - +
- + - + Icons made by Turtle from www.flaticon.com is licensed by CC 3.0 BY - - - + diff --git a/parser.js b/parser.js index f6ac1f0..27f663f 100644 --- a/parser.js +++ b/parser.js @@ -91,26 +91,21 @@ class Parser { parse() { let cmdsExecutors = []; while (this.remainingTokens()) { - let token = this.nextToken(); let cmd = commandLookUp.get(token);; let args = []; - if (cmd) { for (let i = 0; i < cmd.argsTemplate.length; i++) { let startIndex = this.index; let arg = cmd.argsTemplate[i]; - let theArgToken = this.getArgs(); if (arg.validator !== undefined) { if (!arg.validator(theArgToken)) - console.error(`Argument number ${i} (${theArgToken}) is invalid for command ${token}`); args.push(theArgToken); } else { args.push(theArgToken); - console.warn(`A validator is missing for argument ${theArgToken}`); } } cmdsExecutors.push(new CommandExecutor(cmd, args, this.afterCmdCallback)); diff --git a/sketch.js b/sketch.js index d9c975a..e7937df 100644 --- a/sketch.js +++ b/sketch.js @@ -7,10 +7,8 @@ let turtle; let recentreBtn; let bgcolorBtn; -let xOffset = 0; -let yOffset = 0; -let startX = 100; -let startY = 100; +let dragStartMousePos = new p5.Vector(); +let dragStartCanvasOffset = new p5.Vector(); let allCases; let bgcolor = "#6040e6"; @@ -19,8 +17,8 @@ let canvasScrollX = 0; let canvasScrollY = 0; let canvasScaleX = 1; let canvasScaleY = 1; -let drawing_bounds = new BoundingBox(); -let drawingPadding = 50; // Padding round the edge of the drawing when autofit +let drawingBounds = new BoundingBox(); +let drawingPadding = 100; // Padding round the edge of the drawing when autofit function preload() { loadJSON("./assets/tests.json", createTestDataView); @@ -34,16 +32,16 @@ function setup() { angleMode(DEGREES); background(bgcolor); - + canvas.mousePressed(function () { - xOffset = mouseX-startX; - yOffset = mouseY-startY; + dragStartMousePos = new p5.Vector(mouseX, mouseY); + dragStartCanvasOffset = new p5.Vector(canvasScrollX, canvasScrollY); }); canvas.mouseMoved(function () { if (mouseIsPressed) { - startX = mouseX-xOffset; - startY = mouseY-yOffset; + canvasScrollX = dragStartCanvasOffset.x + dragStartMousePos.x - mouseX; + canvasScrollY = dragStartCanvasOffset.y + dragStartMousePos.y - mouseY; goTurtle(); } }); @@ -52,9 +50,7 @@ function setup() { bgcolorBtn = document.querySelector("#bgcolor"); recentreBtn.onclick = function () { - startX = width/2; - startY = height/2; - goTurtle(); + scaleToFitBoundingBox(drawingBounds); } bgcolorBtn.onclick = function () { @@ -65,47 +61,42 @@ function setup() { let col = `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`; bgcolor = col; goTurtle(); - - console.log(bgcolor); } - startX = width/2; - startY = height/2; editor = select("#code"); + setDefaultDrawing(); editor.input(goTurtle); - goTurtle(); + scaleToFitBoundingBox(drawingBounds); // This also redraws (it has to in order to measure the size of the drawing) } - + function scaleToFitBoundingBox(boundingBox) { - startX = 0; - startY = 0; goTurtle(); let scale = Math.min((width - drawingPadding) / (boundingBox.width), (height - drawingPadding) / (boundingBox.height)); canvasScaleX = canvasScaleY = scale; - canvasScrollX = (drawing_bounds.x * scale - width * .5); - canvasScrollY = (drawing_bounds.y * scale - height * .5); + canvasScrollX = (drawingBounds.x * scale - width * .5); + canvasScrollY = (drawingBounds.y * scale - height * .5); goTurtle(); } function afterCommandExecuted() { if (turtle.pen) { - drawing_bounds.includePoint(turtle.x, turtle.y); + drawingBounds.includePoint(turtle.x, turtle.y); } } function goTurtle() { - console.log({startX:startX,startY:startY}); - - turtle = new Turtle(startX / canvasScaleX, startY / canvasScaleY, 0); + turtle = new Turtle(0, 0, 0); + drawingBounds.reset(); + drawingBounds.move(turtle.x, turtle.y); background(bgcolor); - + push(); translate(-canvasScrollX, -canvasScrollY); + scale(canvasScaleX, canvasScaleY); push(); - scale(canvasScaleX, canvasScaleY); turtle.reset(); let code = editor.value(); let parser = new Parser(code, afterCommandExecuted); @@ -113,14 +104,23 @@ function goTurtle() { for (let cmd of commands) { cmd.execute(); } + pop(); pop(); } +/** + * Writes the Logo code for the default drawing to the textarea + * Called on page load + * Also called when selecting the default item from the #testdata dropdown + */ +function setDefaultDrawing() { + editor.value("pu lt 90 fd 100 lt 90 fd 250 rt 90 rt 90 pd fd 500 rt 90 fd 150 rt 90 fd 500 rt 90 fd 150"); +} + function createTestDataView(cases) { let selector = select("#testdata"); - allCases = cases; selector.option("Logo Default", -1); @@ -132,31 +132,26 @@ function createTestDataView(cases) { selector.changed(function() { let val = parseInt(selector.value()); if (val < 0) { - turtle.strokeColor = 255; - turtle.dir = 0; - turtle.x = width / 2; - turtle.y = height / 2; - xOffset = 0; - yOffset = 0; - startX = 100; - startY = 100; - canvasScrollX = 0; - canvasScrollY = 0; - canvasScaleX = 1; - canvasScaleY = 1; - - goTurtle(); - return; + // Use the default drawing + setDefaultDrawing(); + } else { + // Use a drawing from tests.json + editor.value(cases[val].code); } - editor.value(allCases[val].code); - + // Reset default parameters for turtle turtle.strokeColor = 255; turtle.dir = 0; - turtle.x = width / 2; - turtle.y = height / 2; + turtle.x = 0; + turtle.y = 0; + + // Reset default parameters for camera + canvasScrollX = 0; + canvasScrollY = 0; + canvasScaleX = 1; + canvasScaleY = 1; - canvasScrollX = canvasScrollY = 0; - scaleToFitBoundingBox(drawing_bounds); + // Move and scale the drawing to fit on-screen + scaleToFitBoundingBox(drawingBounds); }); } diff --git a/turtle.js b/turtle.js index 9238c94..e826ce3 100644 --- a/turtle.js +++ b/turtle.js @@ -11,7 +11,6 @@ class Turtle { } reset() { - console.log(this.x, this.y, this.dir); translate(this.x, this.y); rotate(this.dir); this.pen = true; @@ -35,6 +34,6 @@ class Turtle { home() { this.x = this.homeX; - this.y = this.homey; + this.y = this.homeY; } }