Skip to content

Commit

Permalink
Added autofit button (#44)
Browse files Browse the repository at this point in the history
* Added autofit button

You can now pass a callback function to the command parser and command executors to be invoked after a command is executed (to access the updated position of the turtle)
This mechanism is used to expand an Axis-Aligned Bounding Box every time the turtle moves with the pen down.

* Autofit when selecting from dropdown

Automatically autofit the drawing when selecting an example from the dropdown menu.
  • Loading branch information
TheTastefulToastie authored and shiffman committed Nov 11, 2018
1 parent 03c2f78 commit 92411fe
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 9 deletions.
4 changes: 2 additions & 2 deletions assets/tests.json

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions bounding_box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class BoundingBox {

constructor() {
this.reset();
}

reset() {
// By default it's positioned with top-left corner at [0,0] with a width and height of 1.
// The x and y values are always the center
this.left = this.top = 0;
this.right = this.bottom = 1;
this.width = this.height = 1;
this.x = this.y = .5;
}

move(x, y) {
this.left += x;
this.right += x;
this.x += x;
this.top += y;
this.bottom += y;
this.y += y;
}

includePoint(x, y) {
this.left = Math.min(this.left, x);
this.right = Math.max(this.right, x);
this.top = Math.min(this.top, y);
this.bottom = Math.max(this.bottom, y);
this.width = this.right - this.left;
this.height = this.bottom - this.top;
this.x = this.left + this.width * .5;
this.y = this.top + this.height * .5;
}

}
10 changes: 8 additions & 2 deletions command.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class Command {
}

class CommandExecutor {
constructor(command, values) {
constructor(command, values, callback) {
this.callback = callback
this.command = command;
this.values = [];

Expand All @@ -40,7 +41,9 @@ class CommandExecutor {
case COMMAND_TYPES.FLOAT:
this.values.push(parseFloat(value));
case COMMAND_TYPES.COMMANDS:
this.values.push(new Parser(value).parse());
this.values.push(
new Parser(value, this.callback).parse()
);
break;
case COMMAND_TYPES.PARAMETERS: // Example
this.values.push(value.split(" "));
Expand All @@ -54,6 +57,9 @@ class CommandExecutor {

execute() {
this.command.func.apply(this, this.values);
if (this.callback) {
this.callback();
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
<script src="turtle.js"></script>
<script src="parser.js"></script>
<script src="command.js"></script>
<script src="bounding_box.js"></script>
<script src="sketch.js"></script>
</head>

<body>
<select id="testdata" style="width: 150px;"></select>
<button id="button_autofit">Autofit</button>
<br />
<textarea id="code" cols="40" rows="5" autocomplete="false" spellcheck="false" autofocus></textarea>
<br />
Expand Down
5 changes: 3 additions & 2 deletions parser.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

class Parser {
constructor(text) {
constructor(text, afterCmdCallback) {
if (!text) text = '';

this.text = text.trim();
this.index = 0;
this.afterCmdCallback = afterCmdCallback
}

remainingTokens() {
Expand Down Expand Up @@ -58,7 +59,7 @@ class Parser {
args.push(this.nextToken());
}

cmdsExecutors.push(new CommandExecutor(cmd, args));
cmdsExecutors.push(new CommandExecutor(cmd, args, this.afterCmdCallback));
}
}

Expand Down
48 changes: 45 additions & 3 deletions sketch.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ let startX = 100;
let startY = 100;
let allCases;

// Used for scaling drawings to fit the canvas
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

function preload() {
loadJSON("./assets/tests.json", createTestDataView);
}
Expand All @@ -18,26 +26,59 @@ function setup() {
angleMode(DEGREES);
background(0);

select("#button_autofit").mousePressed(() => {
scaleToFitBoundingBox(drawing_bounds);
})

startX = width/2;
startY = height/2;
editor = select("#code");
editor.input(goTurtle);
goTurtle();
}

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 = (drawing_bounds.x * scale - width * .5);
canvasScrollY = (drawing_bounds.y * scale - height * .5);
goTurtle();
}

function afterCommandExecuted() {
if (turtle.pen) {
drawing_bounds.includePoint(turtle.x, turtle.y);
}
}

function goTurtle() {
console.log({startX:startX,startY:startY});
turtle = new Turtle(startX, startY, 0);
turtle = new Turtle(startX / canvasScaleX, startY / canvasScaleY, 0);
drawing_bounds.reset();
drawing_bounds.move(turtle.x, turtle.y);
background(0);

push();
translate(-canvasScrollX, -canvasScrollY);

push();
scale(canvasScaleX, canvasScaleY);
turtle.reset();
let code = editor.value();
let parser = new Parser(code);
let parser = new Parser(code, afterCommandExecuted);
let commands = parser.parse();
for (let cmd of commands) {
cmd.execute();
}
pop();

pop();
}

function createTestDataView(cases) {
Expand Down Expand Up @@ -75,7 +116,8 @@ function createTestDataView(cases) {
turtle.x = width / 2;
turtle.y = height / 2;

goTurtle();
canvasScrollX = canvasScrollY = 0;
scaleToFitBoundingBox(drawing_bounds);
});
}

Expand Down
3 changes: 3 additions & 0 deletions turtle.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ class Turtle {
line(0, 0, amt, 0);
}
translate(amt, 0);
this.x += Math.cos(this.dir * Math.PI / 180) * amt;
this.y += Math.sin(this.dir * Math.PI / 180) * amt;
}

right(angle) {
rotate(angle);
this.dir += angle;
}

home() {
Expand Down

0 comments on commit 92411fe

Please sign in to comment.