// Generated by CoffeeScript 1.6.3 (function() { "use strict"; var ArcSegment, Board, Chain, FPS, Gear, GearSketch, LineSegment, MIN_GEAR_TEETH, MIN_MOMENTUM, Point, Util, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = {}.hasOwnProperty, __slice = [].slice; Point = window.gearsketch.Point; ArcSegment = window.gearsketch.ArcSegment; LineSegment = window.gearsketch.LineSegment; Util = window.gearsketch.Util; Gear = window.gearsketch.model.Gear; Chain = window.gearsketch.model.Chain; Board = window.gearsketch.model.Board; FPS = 60; MIN_GEAR_TEETH = 8; MIN_MOMENTUM = 0.2; GearSketch = (function() { var AXIS_RADIUS, BUTTON_INFO, MODULE, MovementAction, MovementType; MODULE = Util.MODULE; AXIS_RADIUS = Util.AXIS_RADIUS; BUTTON_INFO = [["gearButton", "GearIcon.png"], ["chainButton", "ChainIcon.png"], ["momentumButton", "MomentumIcon.png"], ["playButton", "PlayIcon.png"], ["clearButton", "ClearIcon.png"], ["cloudButton", "CloudIcon.png"], ["helpButton", "HelpIcon.png"]]; MovementAction = { PEN_DOWN: "penDown", PEN_UP: "penUp", PEN_TAP: "penTap" }; MovementType = { STRAIGHT: "straight", CIRCLE: "circle", LEFT_HALF_CIRCLE: "leftHalfCircle", RIGHT_HALF_CIRCLE: "rightHalfCircle" }; GearSketch.prototype.buttons = {}; GearSketch.prototype.loadedButtons = 0; GearSketch.prototype.areButtonsLoaded = false; GearSketch.prototype.selectedButton = BUTTON_INFO[0][0]; GearSketch.prototype.gearImages = {}; GearSketch.prototype.isPenDown = false; GearSketch.prototype.stroke = []; GearSketch.prototype.offset = new Point(); GearSketch.prototype.message = ""; GearSketch.prototype.messageColor = "black"; GearSketch.prototype.pointerLocation = new Point(); GearSketch.prototype.currentDemoMovement = 0; GearSketch.prototype.movementCompletion = 0; GearSketch.prototype.restTimer = 0; function GearSketch(showButtons) { if (showButtons == null) { showButtons = true; } this.update = __bind(this.update, this); this.updateAndDrawNoRAF = __bind(this.updateAndDrawNoRAF, this); this.updateAndDraw = __bind(this.updateAndDraw, this); this.loadButtons(); this.showButtons = showButtons; this.loadDemoPointer(); this.loadBoard(); this.canvas = document.getElementById("gearsketch_canvas"); this.canvasOffsetX = this.canvas.getBoundingClientRect().left; this.canvasOffsetY = this.canvas.getBoundingClientRect().top; this.isDemoPlaying = false; this.updateCanvasSize(); this.addCanvasListeners(); this.lastUpdateTime = new Date().getTime(); this.updateAndDrawNoRAF(); } GearSketch.prototype.buttonLoaded = function() { this.loadedButtons++; if (this.loadedButtons === BUTTON_INFO.length) { return this.areButtonsLoaded = true; } }; GearSketch.prototype.loadButtons = function() { var button, file, name, x, y, _i, _len, _ref, _results, _this = this; x = y = 20; _results = []; for (_i = 0, _len = BUTTON_INFO.length; _i < _len; _i++) { _ref = BUTTON_INFO[_i], name = _ref[0], file = _ref[1]; button = new Image(); button.name = name; button.onload = function() { return _this.buttonLoaded(); }; button.src = "img/" + file; button.location = new Point(x, y); button.padding = 3; this.buttons[name] = button; _results.push(x += 80); } return _results; }; GearSketch.prototype.loadDemoPointer = function() { var image, _this = this; image = new Image(); image.onload = function() { return _this.pointerImage = image; }; return image.src = "img/hand.png"; }; GearSketch.prototype.loadBoard = function() { var boardJSON, error, gear, hash, id, _ref, _results; this.board = (function() { if (parent.location.hash.length > 1) { try { hash = parent.location.hash.substr(1); boardJSON = Util.sendGetRequest("boards/" + hash + ".txt"); return Board.fromObject(JSON.parse(boardJSON)); } catch (_error) { error = _error; this.displayMessage("Error: could not load board", "red", 2000); return new Board(); } } else { return new Board(); } }).call(this); _ref = this.board.getGears(); _results = []; for (id in _ref) { gear = _ref[id]; _results.push(this.addGearImage(gear)); } return _results; }; GearSketch.prototype.displayMessage = function(message, color, time) { var _this = this; if (color == null) { color = "black"; } if (time == null) { time = 0; } this.message = message; this.messageColor = color; if (time > 0) { return setTimeout((function() { return _this.clearMessage(); }), time); } }; GearSketch.prototype.clearMessage = function() { return this.message = ""; }; GearSketch.prototype.selectButton = function(buttonName) { return this.selectedButton = buttonName; }; GearSketch.prototype.shouldShowButtons = function() { return this.showButtons || this.isDemoPlaying; }; GearSketch.prototype.addCanvasListeners = function() { var canvasEventHandler, _this = this; canvasEventHandler = Hammer(this.canvas, { drag_min_distance: 1 }); canvasEventHandler.on("touch", (function(e) { return _this.forwardPenDownEvent.call(_this, e); })); canvasEventHandler.on("drag", (function(e) { return _this.forwardPenMoveEvent.call(_this, e); })); return canvasEventHandler.on("release", (function(e) { return _this.forwardPenUpEvent.call(_this, e); })); }; GearSketch.prototype.forwardPenDownEvent = function(event) { var x, y; event.gesture.preventDefault(); if (this.isDemoPlaying) { return this.stopDemo(); } else { x = event.gesture.center.pageX - this.canvasOffsetX; y = event.gesture.center.pageY - this.canvasOffsetY; return this.handlePenDown(x, y); } }; GearSketch.prototype.forwardPenMoveEvent = function(event) { var x, y; event.gesture.preventDefault(); if (!this.isDemoPlaying) { x = event.gesture.center.pageX - this.canvasOffsetX; y = event.gesture.center.pageY - this.canvasOffsetY; return this.handlePenMove(x, y); } }; GearSketch.prototype.forwardPenUpEvent = function(event) { if (!this.isDemoPlaying) { return this.handlePenUp(); } }; GearSketch.prototype.handlePenDown = function(x, y) { var button, point; point = new Point(x, y); if (this.isPenDown) { return this.handlePenUp(); } else { button = this.getButtonAt(x, y); if (button) { if (button.name === "clearButton") { parent.location.hash = ""; return this.board.clear(); } else if (button.name === "cloudButton") { return this.uploadBoard(); } else if (button.name === "helpButton") { return this.playDemo(); } else { return this.selectButton(button.name); } } else if (this.selectedButton === "gearButton") { this.selectedGear = this.board.getTopLevelGearAt(point); if (this.selectedGear != null) { this.offset = point.minus(this.selectedGear.location); } else if (this.board.getGearAt(point) == null) { this.stroke.push(point); } return this.isPenDown = true; } else if (this.selectedButton === "chainButton") { this.stroke.push(point); return this.isPenDown = true; } else if (this.selectedButton === "momentumButton") { this.selectedGear = this.board.getGearAt(point); if (this.selectedGear) { this.selectedGear.momentum = 0; this.selectedGearMomentum = this.calculateMomentumFromCoords(this.selectedGear, x, y); } return this.isPenDown = true; } } }; GearSketch.prototype.handlePenMove = function(x, y) { var canPlaceGear, goalLocation, point; point = new Point(x, y); if (this.isPenDown) { if (this.selectedButton === "gearButton") { if (this.selectedGear) { goalLocation = point.minus(this.offset); canPlaceGear = this.board.placeGear(this.selectedGear, goalLocation); if (canPlaceGear) { return this.goalLocationGear = null; } else { return this.goalLocationGear = new Gear(goalLocation, this.selectedGear.rotation, this.selectedGear.numberOfTeeth, this.selectedGear.id, this.selectedGear.hue); } } else if (this.stroke.length > 0) { return this.stroke.push(point); } } else if (this.selectedButton === "chainButton") { return this.stroke.push(point); } else if (this.selectedButton === "momentumButton") { if (this.selectedGear) { return this.selectedGearMomentum = this.calculateMomentumFromCoords(this.selectedGear, x, y); } } } }; GearSketch.prototype.handlePenUp = function() { if (this.isPenDown) { if (this.selectedButton === "gearButton") { if (!((this.selectedGear != null) || this.stroke.length === 0)) { this.processGearStroke(); } } else if (this.selectedButton === "chainButton") { this.processChainStroke(); } else if (this.selectedButton === "momentumButton") { if (this.selectedGear) { if (Math.abs(this.selectedGearMomentum) > MIN_MOMENTUM) { this.selectedGear.momentum = this.selectedGearMomentum; } else { this.selectedGear.momentum = 0; } } this.selectedGearMomentum = 0; } this.selectedGear = null; this.goalLocationGear = null; return this.isPenDown = false; } }; GearSketch.prototype.isButtonAt = function(x, y, button) { return x > button.location.x && x < button.location.x + button.width + 2 * button.padding && y > button.location.y && y < button.location.y + button.height + 2 * button.padding; }; GearSketch.prototype.getButtonAt = function(x, y) { var button, buttonName, _ref; if (!this.shouldShowButtons()) { return null; } _ref = this.buttons; for (buttonName in _ref) { if (!__hasProp.call(_ref, buttonName)) continue; button = _ref[buttonName]; if (this.isButtonAt(x, y, button)) { return button; } } return null; }; GearSketch.prototype.normalizeStroke = function(stroke) { var MIN_POINT_DISTANCE, normalizedStroke, p1, p2, strokeTail, _i, _len; MIN_POINT_DISTANCE = 10; normalizedStroke = []; if (stroke.length > 0) { p1 = stroke[0], strokeTail = 2 <= stroke.length ? __slice.call(stroke, 1) : []; normalizedStroke.push(p1); for (_i = 0, _len = strokeTail.length; _i < _len; _i++) { p2 = strokeTail[_i]; if (p1.distance(p2) > MIN_POINT_DISTANCE) { normalizedStroke.push(p2); p1 = p2; } } } return normalizedStroke; }; GearSketch.prototype.createGearFromStroke = function(stroke) { var area, doubleArea, height, i, idealTrueAreaRatio, j, maxX, maxY, minX, minY, numberOfPoints, p, radius, sumX, sumY, t, width, x, y, _i, _j, _len; numberOfPoints = stroke.length; if (numberOfPoints > 0) { sumX = 0; sumY = 0; minX = Number.MAX_VALUE; maxX = Number.MIN_VALUE; minY = Number.MAX_VALUE; maxY = Number.MIN_VALUE; for (_i = 0, _len = stroke.length; _i < _len; _i++) { p = stroke[_i]; sumX += p.x; sumY += p.y; minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x); minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y); } width = maxX - minX; height = maxY - minY; t = Math.floor(0.5 * (width + height) / MODULE); doubleArea = 0; for (i = _j = 0; 0 <= numberOfPoints ? _j < numberOfPoints : _j > numberOfPoints; i = 0 <= numberOfPoints ? ++_j : --_j) { j = (i + 1) % numberOfPoints; doubleArea += stroke[i].x * stroke[j].y; doubleArea -= stroke[i].y * stroke[j].x; } area = Math.abs(doubleArea) / 2; radius = 0.25 * ((maxX - minX) + (maxY - minY)); idealTrueAreaRatio = (Math.PI * Math.pow(radius, 2)) / area; if (idealTrueAreaRatio > 0.80 && idealTrueAreaRatio < 1.20 && t > MIN_GEAR_TEETH) { x = sumX / numberOfPoints; y = sumY / numberOfPoints; return new Gear(new Point(x, y), 0, t); } } return null; }; GearSketch.prototype.removeStrokedGears = function(stroke) { var gear, id, _ref, _results; _ref = this.board.getTopLevelGears(); _results = []; for (id in _ref) { if (!__hasProp.call(_ref, id)) continue; gear = _ref[id]; if (Util.pointPathDistance(gear.location, stroke, false) < gear.innerRadius) { _results.push(this.board.removeGear(gear)); } else { _results.push(void 0); } } return _results; }; GearSketch.prototype.processGearStroke = function() { var gear, isGearAdded, normalizedStroke; normalizedStroke = this.normalizeStroke(this.stroke); gear = this.createGearFromStroke(normalizedStroke); if (gear != null) { isGearAdded = this.board.addGear(gear); if (isGearAdded && !(gear.numberOfTeeth in this.gearImages)) { this.addGearImage(gear); } } else { this.removeStrokedGears(normalizedStroke); } return this.stroke = []; }; GearSketch.prototype.gearImageLoaded = function(numberOfTeeth, image) { return this.gearImages[numberOfTeeth] = image; }; GearSketch.prototype.addGearImage = function(gear) { var ctx, gearCanvas, gearCopy, image, size, _this = this; gearCanvas = document.createElement("canvas"); size = 2 * (gear.outerRadius + MODULE); gearCanvas.height = size; gearCanvas.width = size; ctx = gearCanvas.getContext("2d"); gearCopy = new Gear(new Point(0.5 * size, 0.5 * size), 0, gear.numberOfTeeth, gear.id, null, null, null, null, gear.hue); this.drawGear(ctx, gearCopy); image = new Image(); image.onload = function() { return _this.gearImageLoaded(gear.numberOfTeeth, image); }; return image.src = gearCanvas.toDataURL("image/png"); }; GearSketch.prototype.removeStrokedChains = function(stroke) { var chain, id, _ref, _results; _ref = this.board.getChains(); _results = []; for (id in _ref) { if (!__hasProp.call(_ref, id)) continue; chain = _ref[id]; if (chain.intersectsPath(stroke)) { _results.push(this.board.removeChain(chain)); } else { _results.push(void 0); } } return _results; }; GearSketch.prototype.processChainStroke = function() { var chain, gearsInChain, normalizedStroke; normalizedStroke = this.normalizeStroke(this.stroke); this.stroke = []; gearsInChain = Util.findGearsInsidePolygon(normalizedStroke, this.board.getGears()); if (normalizedStroke.length >= 3 && gearsInChain.length > 0) { chain = new Chain(normalizedStroke); return this.board.addChain(chain); } else if (normalizedStroke.length >= 2) { return this.removeStrokedChains(normalizedStroke); } }; GearSketch.prototype.calculateMomentumFromCoords = function(gear, x, y) { var angle, angleFromTop; angle = Math.atan2(y - gear.location.y, x - gear.location.x); angleFromTop = angle + 0.5 * Math.PI; if (angleFromTop < Math.PI) { return angleFromTop; } else { return angleFromTop - 2 * Math.PI; } }; GearSketch.prototype.updateAndDraw = function() { var _this = this; return setTimeout((function() { requestAnimationFrame(_this.updateAndDraw); _this.update(); return _this.draw(); }), 1000 / FPS); }; GearSketch.prototype.updateAndDrawNoRAF = function() { var _this = this; this.update(); this.draw(); return setTimeout((function() { return _this.updateAndDrawNoRAF(); }), 1000 / FPS); }; GearSketch.prototype.update = function() { var delta, updateTime; updateTime = new Date().getTime(); delta = updateTime - this.lastUpdateTime; if (this.selectedButton === "playButton") { this.board.rotateAllTurningObjects(delta); } if (this.isDemoPlaying) { this.updateDemo(delta); } return this.lastUpdateTime = updateTime; }; GearSketch.prototype.drawGear = function(ctx, gear, color) { var angleStep, gearImage, i, innerPoints, numberOfTeeth, outerPoints, r, rotation, x, y, _i, _j, _k, _ref, _ref1; if (color == null) { color = "black"; } _ref = gear.location, x = _ref.x, y = _ref.y; rotation = gear.rotation; numberOfTeeth = gear.numberOfTeeth; gearImage = this.gearImages[gear.numberOfTeeth]; if (color === "black" && (gearImage != null)) { gearImage = this.gearImages[gear.numberOfTeeth]; ctx.save(); ctx.translate(x, y); ctx.rotate(rotation); ctx.drawImage(gearImage, -0.5 * gearImage.width, -0.5 * gearImage.height); ctx.restore(); return; } angleStep = 2 * Math.PI / numberOfTeeth; innerPoints = []; outerPoints = []; for (i = _i = 0; 0 <= numberOfTeeth ? _i < numberOfTeeth : _i > numberOfTeeth; i = 0 <= numberOfTeeth ? ++_i : --_i) { for (r = _j = 0; _j < 4; r = ++_j) { if (r === 0 || r === 3) { innerPoints.push(Point.polar((i + 0.25 * r) * angleStep, gear.innerRadius)); } else { outerPoints.push(Point.polar((i + 0.25 * r) * angleStep, gear.outerRadius)); } } } ctx.save(); if (color === "black") { if (!gear.hue) { gear.hue = Math.floor(Math.random()*360); } ctx.fillStyle = "hsla(" + gear.hue + ", 85%, 60%, 0.8)"; } else { ctx.fillStyle = "hsla(0, 0%, 90%, 0.2)"; } ctx.strokeStyle = color; ctx.lineWidth = 2; ctx.translate(x, y); ctx.rotate(rotation); ctx.beginPath(); ctx.moveTo(gear.innerRadius, 0); for (i = _k = 0, _ref1 = numberOfTeeth * 2; 0 <= _ref1 ? _k < _ref1 : _k > _ref1; i = 0 <= _ref1 ? ++_k : --_k) { if (i % 2 === 0) { ctx.lineTo(innerPoints[i].x, innerPoints[i].y); ctx.lineTo(outerPoints[i].x, outerPoints[i].y); } else { ctx.lineTo(outerPoints[i].x, outerPoints[i].y); ctx.lineTo(innerPoints[i].x, innerPoints[i].y); } } ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(AXIS_RADIUS, 0); ctx.arc(0, 0, AXIS_RADIUS, 0, 2 * Math.PI, true); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(AXIS_RADIUS, 0); ctx.lineTo(gear.innerRadius, 0); ctx.closePath(); ctx.stroke(); return ctx.restore(); }; GearSketch.prototype.drawButton = function(ctx, button) { var height, padding, radius, width, x, y, _ref; _ref = button.location, x = _ref.x, y = _ref.y; padding = button.padding; ctx.save(); ctx.translate(x, y); ctx.beginPath(); radius = 10; width = button.width + 2 * padding; height = button.height + 2 * padding; ctx.moveTo(radius, 0); ctx.lineTo(width - radius, 0); ctx.quadraticCurveTo(width, 0, width, radius); ctx.lineTo(width, height - radius); ctx.quadraticCurveTo(width, height, width - radius, height); ctx.lineTo(radius, height); ctx.quadraticCurveTo(0, height, 0, height - radius); ctx.lineTo(0, radius); ctx.quadraticCurveTo(0, 0, radius, 0); if (button.name === this.selectedButton) { ctx.fillStyle = "rgba(50, 150, 255, 0.8)"; } else { ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; } ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = "black"; ctx.stroke(); ctx.drawImage(button, padding, padding); return ctx.restore(); }; GearSketch.prototype.drawMomentum = function(ctx, gear, momentum, color) { var angle, head, headX, headY, length, p1, p2, pitchRadius, sign, top; if (color == null) { color = "red"; } pitchRadius = gear.pitchRadius; top = new Point(gear.location.x, gear.location.y - pitchRadius); ctx.save(); ctx.lineWidth = 5; ctx.lineCap = "round"; ctx.strokeStyle = color; ctx.translate(top.x, top.y); ctx.beginPath(); ctx.arc(0, pitchRadius, pitchRadius, -0.5 * Math.PI, momentum - 0.5 * Math.PI, momentum < 0); ctx.stroke(); length = 15; angle = 0.2 * Math.PI; headX = -Math.cos(momentum + 0.5 * Math.PI) * pitchRadius; headY = pitchRadius - Math.sin(momentum + 0.5 * Math.PI) * pitchRadius; head = new Point(headX, headY); sign = Util.sign(momentum); p1 = head.minus(Point.polar(momentum + angle, sign * length)); ctx.beginPath(); ctx.moveTo(headX, headY); ctx.lineTo(p1.x, p1.y); ctx.stroke(); p2 = head.minus(Point.polar(momentum - angle, sign * length)); ctx.beginPath(); ctx.moveTo(headX, headY); ctx.lineTo(p2.x, p2.y); ctx.stroke(); return ctx.restore(); }; GearSketch.prototype.drawChain = function(ctx, chain) { var isCounterClockwise, point, segment, _i, _j, _len, _len1, _ref, _ref1; ctx.save(); ctx.lineWidth = Chain.WIDTH; ctx.lineCap = "round"; ctx.strokeStyle = "rgb(0, 0, 255)"; ctx.moveTo(chain.segments[0].start.x, chain.segments[0].start.y); _ref = chain.segments; for (_i = 0, _len = _ref.length; _i < _len; _i++) { segment = _ref[_i]; if (segment instanceof ArcSegment) { isCounterClockwise = segment.direction === Util.Direction.COUNTER_CLOCKWISE; ctx.beginPath(); ctx.arc(segment.center.x, segment.center.y, segment.radius, segment.startAngle, segment.endAngle, isCounterClockwise); ctx.stroke(); } else { ctx.beginPath(); ctx.moveTo(segment.start.x, segment.start.y); ctx.lineTo(segment.end.x, segment.end.y); ctx.stroke(); } } ctx.fillStyle = "white"; _ref1 = chain.findPointsOnChain(25); for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { point = _ref1[_j]; ctx.beginPath(); ctx.arc(point.x, point.y, 3, 0, 2 * Math.PI, true); ctx.fill(); } return ctx.restore(); }; GearSketch.prototype.drawDemoPointer = function(ctx, location) { return ctx.drawImage(this.pointerImage, location.x - 0.5 * this.pointerImage.width, location.y); }; GearSketch.prototype.draw = function() { var arrow, arrowsToDraw, buttonName, chain, ctx, gear, i, momentum, shouldDrawChainsAndArrows, sortedGears, _i, _j, _k, _l, _len, _len1, _ref, _ref1, _ref2, _ref3; if (this.canvas.getContext != null) { this.updateCanvasSize(); ctx = this.canvas.getContext("2d"); ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); sortedGears = this.board.getGearsSortedByGroupAndLevel(); arrowsToDraw = []; for (i = _i = 0, _ref = sortedGears.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { gear = sortedGears[i]; momentum = gear.momentum; if (gear === this.selectedGear && this.goalLocationGear) { this.drawGear(ctx, gear, "grey"); if (momentum) { arrowsToDraw.push([gear, momentum, "grey"]); } } else { this.drawGear(ctx, gear); if (momentum) { arrowsToDraw.push([gear, momentum, "red"]); } } shouldDrawChainsAndArrows = (i === sortedGears.length - 1) || (this.board.getLevelScore(gear) !== this.board.getLevelScore(sortedGears[i + 1])); if (shouldDrawChainsAndArrows) { _ref1 = this.board.getChainsInGroupOnLevel(gear.group, gear.level); for (_j = 0, _len = _ref1.length; _j < _len; _j++) { chain = _ref1[_j]; this.drawChain(ctx, chain); } for (_k = 0, _len1 = arrowsToDraw.length; _k < _len1; _k++) { arrow = arrowsToDraw[_k]; this.drawMomentum(ctx, arrow[0], arrow[1], arrow[2]); } arrowsToDraw = []; } } if (this.goalLocationGear) { this.drawGear(ctx, this.goalLocationGear, "red"); } if ((this.selectedGear != null) && this.selectedGearMomentum) { this.drawMomentum(ctx, this.selectedGear, this.selectedGearMomentum); } if (this.stroke.length > 0) { ctx.save(); if (this.selectedButton === "gearButton") { ctx.strokeStyle = "black"; ctx.lineWidth = 2; } else { ctx.strokeStyle = "blue"; ctx.lineWidth = 4; } ctx.beginPath(); ctx.moveTo(this.stroke[0].x, this.stroke[0].y); for (i = _l = 1, _ref2 = this.stroke.length; 1 <= _ref2 ? _l < _ref2 : _l > _ref2; i = 1 <= _ref2 ? ++_l : --_l) { ctx.lineTo(this.stroke[i].x, this.stroke[i].y); } ctx.stroke(); ctx.restore(); } if (this.areButtonsLoaded && this.shouldShowButtons()) { _ref3 = this.buttons; for (buttonName in _ref3) { if (!__hasProp.call(_ref3, buttonName)) continue; this.drawButton(ctx, this.buttons[buttonName]); } } if (this.message.length > 0) { ctx.save(); ctx.fillStyle = this.messageColor; ctx.font = "bold 20px Arial"; ctx.fillText(this.message, 20, 120); ctx.restore(); } if (this.isDemoPlaying && this.pointerImage) { return this.drawDemoPointer(ctx, this.pointerLocation); } } }; GearSketch.prototype.updateCanvasSize = function() { this.canvas.width = this.canvas.parentElement.getBoundingClientRect().width; this.canvas.height = this.canvas.parentElement.getBoundingClientRect().height; this.buttons["clearButton"].location.x = Math.max(this.canvas.width - 260, this.buttons["playButton"].location.x + 80); this.buttons["cloudButton"].location.x = this.buttons["clearButton"].location.x + 80; return this.buttons["helpButton"].location.x = this.buttons["cloudButton"].location.x + 80; }; GearSketch.prototype.loadDemoMovements = function() { return this.demoMovements = [ { from: this.getButtonCenter("helpButton"), to: this.getButtonCenter("gearButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 2000 }, { to: new Point(300, 200), type: MovementType.STRAIGHT, duration: 1500 }, { atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.CIRCLE, radius: 100, duration: 1500 }, { to: new Point(500, 200), type: MovementType.STRAIGHT, duration: 1000 }, { atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.CIRCLE, radius: 40, duration: 1000 }, { to: new Point(500, 240), type: MovementType.STRAIGHT, duration: 500 }, { to: new Point(300, 300), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(100, 180), type: MovementType.STRAIGHT, duration: 1000 }, { atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.CIRCLE, radius: 90, duration: 1000 }, { to: new Point(100, 260), type: MovementType.STRAIGHT, duration: 500 }, { to: new Point(180, 260), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(550, 220), type: MovementType.STRAIGHT, duration: 1500 }, { atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.CIRCLE, radius: 80, duration: 1000 }, { to: this.getButtonCenter("chainButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(280, 150), type: MovementType.STRAIGHT, duration: 1500 }, { atStart: MovementAction.PEN_DOWN, type: MovementType.LEFT_HALF_CIRCLE, radius: 140, duration: 1500, pause: 0 }, { to: new Point(600, 400), type: MovementType.STRAIGHT, duration: 1000, pause: 0 }, { type: MovementType.RIGHT_HALF_CIRCLE, radius: 110, duration: 1000, pause: 0 }, { to: new Point(280, 150), atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1000 }, { to: this.getButtonCenter("momentumButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(185, 180), type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(150, 190), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1000 }, { to: this.getButtonCenter("playButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 1500 }, { to: this.getButtonCenter("chainButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 3000 }, { to: new Point(425, 250), type: MovementType.STRAIGHT, duration: 1000 }, { to: new Point(525, 150), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1000 }, { to: this.getButtonCenter("gearButton"), atEnd: MovementAction.PEN_TAP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(20, 250), type: MovementType.STRAIGHT, duration: 1000 }, { to: new Point(650, 300), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1500 }, { to: new Point(425, 200), type: MovementType.STRAIGHT, duration: 1000 }, { to: new Point(200, 400), atStart: MovementAction.PEN_DOWN, atEnd: MovementAction.PEN_UP, type: MovementType.STRAIGHT, duration: 1500 } ]; }; GearSketch.prototype.getButtonCenter = function(buttonName) { var button, buttonCorner; button = this.buttons[buttonName]; buttonCorner = new Point(button.location.x, button.location.y); return buttonCorner.plus(new Point(0.5 * button.width + button.padding, 0.5 * button.height + button.padding)); }; GearSketch.prototype.updateDemo = function(delta) { var movement; if (this.restTimer > 0) { this.restTimer = Math.max(this.restTimer - delta, 0); return; } else if (this.currentDemoMovement === this.demoMovements.length) { this.stopDemo(); return; } movement = this.demoMovements[this.currentDemoMovement]; if (this.movementCompletion === 0) { if (movement.from == null) { movement.from = this.pointerLocation; } if (movement.pause == null) { movement.pause = 500; } this.pointerLocation = movement.from.clone(); if (movement.atStart === MovementAction.PEN_DOWN) { this.handlePenDown(this.pointerLocation.x, this.pointerLocation.y); } } if (this.movementCompletion < 1) { this.movementCompletion = Math.min(1, this.movementCompletion + delta / movement.duration); this.updatePointerLocation(movement, this.movementCompletion); this.handlePenMove(this.pointerLocation.x, this.pointerLocation.y); } if (this.movementCompletion === 1) { if (movement.atEnd === MovementAction.PEN_TAP) { this.handlePenDown(this.pointerLocation.x, this.pointerLocation.y); this.handlePenUp(); } else if (movement.atEnd === MovementAction.PEN_UP) { this.handlePenUp(); } this.restTimer = movement.pause; this.movementCompletion = 0; return this.currentDemoMovement++; } }; GearSketch.prototype.updatePointerLocation = function(movement, movementCompletion) { var angle, center, delta; if (movement.type === MovementType.STRAIGHT) { delta = movement.to.minus(movement.from); return this.pointerLocation = movement.from.plus(delta.times(movementCompletion)); } else if (movement.type === MovementType.CIRCLE) { center = new Point(movement.from.x, movement.from.y + movement.radius); return this.pointerLocation = center.plus(Point.polar(Math.PI - (movementCompletion - 0.25) * 2 * Math.PI, movement.radius)); } else if (movement.type === MovementType.LEFT_HALF_CIRCLE) { center = new Point(movement.from.x, movement.from.y + movement.radius); angle = 1.5 * Math.PI - movementCompletion * Math.PI; return this.pointerLocation = center.plus(Point.polar(angle, movement.radius)); } else if (movement.type === MovementType.RIGHT_HALF_CIRCLE) { center = new Point(movement.from.x, movement.from.y - movement.radius); angle = 0.5 * Math.PI - movementCompletion * Math.PI; return this.pointerLocation = center.plus(Point.polar(angle, movement.radius)); } }; GearSketch.prototype.playDemo = function() { this.loadDemoMovements(); this.boardBackup = this.board.clone(); this.board.clear(); this.currentDemoMovement = 0; this.movementCompletion = 0; this.isDemoPlaying = true; return this.displayMessage("click anywhere to stop the demo"); }; GearSketch.prototype.stopDemo = function() { this.isDemoPlaying = false; this.restTimer = 0; this.stroke = []; this.selectedGear = null; this.selectedIcon = "gearIcon"; this.board.restoreAfterDemo(this.boardBackup); return this.clearMessage(); }; GearSketch.prototype.boardUploaded = function(event) { parent.location.hash = event.target.responseText.trim(); return this.displayMessage("Board saved. Share it by copying the text in your address bar.", "black", 4000); }; GearSketch.prototype.uploadBoard = function() { var boardJSON, _this = this; boardJSON = JSON.stringify(this.board); return Util.sendPostRequest(boardJSON, "upload_board.php", (function(event) { return _this.boardUploaded(event); })); }; return GearSketch; })(); window.gearsketch.GearSketch = GearSketch; }).call(this); /* //@ sourceMappingURL=gearsketch_main.map */