"use strict"; var myglobal = this; myglobal.__tjs = new __TurtleJS(myglobal); function __TurtleJS(myglobal) { var self = this; var svgNamespace = "http://www.w3.org/2000/svg"; var __turtleColor = '#d0d0c0'; var __turtleStrokeWidth = 1; self.stage = myglobal.document.getElementById('__stage'); self.drawTurtle = function (x,y,rotation) { self.turtleTransform = myglobal.document.createElementNS(svgNamespace, 'g'); self.turtleTransform.setAttribute( 'transform', 'translate('+x+', '+y+'), rotate('+rotation+')'); var turtle = self.createSvgLine(); self.turtleTransform.appendChild(turtle); turtle.setAttribute('d', 'M 0 0 L -4 3 L 0 -8 L 4 3 z'); self.stage.appendChild(self.turtleTransform); }; self.createSvgLine = function (lineObject) { lineObject = lineObject || {}; var line = myglobal.document.createElementNS(svgNamespace, 'path'); line.setAttribute('fill', lineObject.fillColor || 'none'); line.setAttribute('opacity', lineObject.opacity || 1); line.setAttribute('stroke', lineObject.color || __turtleColor); line.setAttribute('stroke-width', lineObject.width || __turtleStrokeWidth); line.setAttribute('stroke-linejoin', "miter"); return line; }; self.drawTurtle(0,0,0); self.logs = []; self.logger = { // addLog is defined in the ui.js file log: function(logObject) { logObject.type = 'info'; myglobal.__tjs.addLog(logObject); }, error: function(logObject) { logObject.type = 'error'; myglobal.__tjs.addLog(logObject); } }; self.runTurtleJS = function() { var __turtleJS = self.editor.getValue(); var __oldConsole = myglobal.console; myglobal.console = { log: function() { var position = {}; try { __ExceptionTime(); } catch (ex) { position = __getErrorLineNumber(ex, 1); } var toLog = []; Array.prototype.slice.call(arguments).forEach(function(argument){ if(typeof argument === 'object') { toLog.push(JSON.stringify(argument)); } else { toLog.push(''+argument) } }); self.logger.log({ lineNumber: position.lineNumber, charOffset: position.charOffset, message: "INFO: `" + toLog.join(',') + (position.lineNumber ? '` at line ' + position.lineNumber : '`') }); } }; self.shapeBreak = function () { if(self.turtCurrentLine.points.length > 1) { penUp(); penDown(); } }; self.stage.innerHTML = ''; self.clearTurt(); penDown(); var __turtleJSWithTryCatch = [ 'var exception = null;' ,'try {' ,__turtleJS ,'} catch (ex) {' ,' exception = {' ,' message: ex.message,' ,' name: ex.name,' ,' stack: __getErrorLineNumber(ex)' ,' };' ,'}' ,'exception;'].join('\n'); var error = null; try { error = eval(__turtleJSWithTryCatch); } catch (outerErr) { error = outerErr; } myglobal.console = __oldConsole; if(error) { self.logger.error({ lineNumber: error.stack.lineNumber, charOffset: error.stack.charOffset, message: error.name +': ' + error.message + (error.stack.lineNumber ? ' at line ' + error.stack.lineNumber : '') }); } penUp(); self.turtLines.sort(function (a, b) { if ((a.layer || 0) > (b.layer || 0)) { return 1; } if ((a.layer || 0) < (b.layer || 0)) { return -1; } return 0; }); self.turtLines.forEach(function (lineObject) { var line = self.createSvgLine(lineObject); line.setAttribute('d', lineObject.points.reduce(function (prev, current, i){ return prev + (i == 0 ? 'M ' : 'L ') + current.x.toFixed(2) + ' ' + current.y.toFixed(2) + ' '; }, '')+(lineObject.fillColor && lineObject.fillColor != 'none' ? 'z' : '')); self.stage.appendChild(line); }); self.drawTurtle(self.turt.x, self.turt.y, self.turt.rotation); function forward(px) { self.moveTurt( self.turt.x + (Math.sin(self.turt.rotation*self.deg2Rad)*px), self.turt.y - (Math.cos(self.turt.rotation*self.deg2Rad)*px) ); } function left(deg) { self.turt.rotation -= deg; while(self.turt.rotation < 0) { self.turt.rotation += 360; } } function right(deg) { self.turt.rotation += deg; while(self.turt.rotation > 360) { self.turt.rotation -= 360; } } function penUp() { self.turtLines.push(self.turtCurrentLine); self.turtCurrentLine = { points: [], width: self.turtCurrentLine.width, color: self.turtCurrentLine.color, fillColor: self.turtCurrentLine.fillColor, opacity: self.turtCurrentLine.opacity, layer: self.turtCurrentLine.layer }; self.penIsUp = true; } function penDown() { self.turtCurrentLine.points.push({x: self.turt.x, y: self.turt.y}); self.penIsUp = false; } function pushColor(color) { self.shapeBreak(); self.turtCurrentLine.color = color; self.colorStack.push(color); } function pushFillColor(color) { self.shapeBreak(); self.turtCurrentLine.fillColor = color; self.fillColorStack.push(color); } function pushWidth(width) { self.shapeBreak(); self.turtCurrentLine.width = width; self.widthStack.push(width); } function pushOpacity(opacity) { self.shapeBreak(); self.turtCurrentLine.opacity = opacity; self.opacityStack.push(opacity); } function pushLayer(layer) { self.shapeBreak(); self.turtCurrentLine.layer = layer; self.layerStack.push(layer); } function popColor() { self.colorStack.pop(); self.shapeBreak(); self.turtCurrentLine.color = self.colorStack.length ? self.colorStack[self.colorStack.length-1] : __turtleColor; } function popFillColor() { self.fillColorStack.pop(); self.shapeBreak(); self.turtCurrentLine.fillColor = self.fillColorStack.length ? self.fillColorStack[self.fillColorStack.length-1] : 'none'; } function popWidth() { self.widthStack.pop(); self.shapeBreak(); self.turtCurrentLine.width = self.widthStack.length ? self.widthStack[self.widthStack.length-1] : 1; } function popOpacity(opacity) { self.opacityStack.pop(); self.shapeBreak(); self.turtCurrentLine.opacity = self.opacityStack.length ? self.opacityStack[self.opacityStack.length-1] : 1; } function popLayer(layer) { self.layerStack.pop(); self.shapeBreak(); self.turtCurrentLine.layer = self.layerStack.length ? self.layerStack[self.layerStack.length-1] : 0; } function home() { self.moveTurt(0,0); self.turt.rotation = 0; } }; self.colorStack = []; self.fillColorStack = []; self.widthStack = []; self.opacityStack = []; self.layerStack = []; self.deg2Rad = (Math.PI*2)/360; self.penIsUp = false; self.turt = { x: 0, y: 0, rotation: 0 } self.turtCurrentLine = { points: [{x:0, y:0}] }; self.turtLines = []; self.moveTurt = function (x, y) { self.turt.x = x; self.turt.y = y; if(!self.penIsUp) { self.turtCurrentLine.points.push({x: self.turt.x, y: self.turt.y}); } }; self.clearTurt = function () { self.colorStack = []; self.fillColorStack = []; self.widthStack = []; self.opacityStack = []; self.layerStack = []; self.turt = { x: 0, y: 0, rotation: 0 } self.turtCurrentLine = { points: [{x:0, y:0}] }; self.turtLines = []; }; }; var __lineNumberOffset = 2; function __getErrorLineNumber(ex, stackFramesToSkip) { var result = null; var stackFramesToSkip = stackFramesToSkip || 0; if(ex.stack) { var lines = ex.stack.split('\n'); var lineToParse = null; var browser = 'firefox'; if(lines.length) { var cappedMessage = ex.message.substring(0, Math.max(ex.message.length-1, 20)); if(lines[0].indexOf(ex.name) !== -1 && lines[0].indexOf(cappedMessage) !== -1) { stackFramesToSkip += 1; browser = 'chrome'; } if(lines.length > stackFramesToSkip) { lineToParse = lines[stackFramesToSkip]; } } if(lineToParse) { var values = lineToParse.split(':'); var charOffset = values[values.length - 1].replace(/[^\d]/g,''); var lineNumber = values[values.length - 2].replace(/[^\d]/g,''); result = { charOffset: Number(charOffset), lineNumber: Number(lineNumber)-__lineNumberOffset, }; } } return result; }