Created
May 2, 2015 19:24
-
-
Save irskep/414cd1a02e359da1724b to your computer and use it in GitHub Desktop.
Literally Canvas 0.4.2 release candidate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.LC=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | |
| },{}],2:[function(_dereq_,module,exports){ | |
| var INFINITE, JSONToShape, LiterallyCanvas, Pencil, actions, bindEvents, createShape, math, shapeToJSON, util, _ref, | |
| __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | |
| __slice = [].slice; | |
| actions = _dereq_('./actions'); | |
| bindEvents = _dereq_('./bindEvents'); | |
| math = _dereq_('./math'); | |
| _ref = _dereq_('./shapes'), createShape = _ref.createShape, shapeToJSON = _ref.shapeToJSON, JSONToShape = _ref.JSONToShape; | |
| Pencil = _dereq_('../tools/Pencil'); | |
| util = _dereq_('./util'); | |
| INFINITE = 'infinite'; | |
| module.exports = LiterallyCanvas = (function() { | |
| function LiterallyCanvas(containerEl, opts) { | |
| this.containerEl = containerEl; | |
| this.setImageSize = __bind(this.setImageSize, this); | |
| bindEvents(this, this.containerEl, opts.keyboardShortcuts); | |
| this.colors = { | |
| primary: opts.primaryColor || '#000', | |
| secondary: opts.secondaryColor || '#fff', | |
| background: opts.backgroundColor || 'transparent' | |
| }; | |
| this.containerEl.style['background-color'] = this.colors.background; | |
| this.watermarkImage = opts.watermarkImage; | |
| this.watermarkScale = opts.watermarkScale || 1; | |
| this.backgroundCanvas = document.createElement('canvas'); | |
| this.backgroundCtx = this.backgroundCanvas.getContext('2d'); | |
| this.containerEl.appendChild(this.backgroundCanvas); | |
| this.backgroundShapes = opts.backgroundShapes || []; | |
| this.canvas = document.createElement('canvas'); | |
| this.canvas.style['background-color'] = 'transparent'; | |
| this.containerEl.appendChild(this.canvas); | |
| this.buffer = document.createElement('canvas'); | |
| this.buffer.style['background-color'] = 'transparent'; | |
| this.ctx = this.canvas.getContext('2d'); | |
| this.bufferCtx = this.buffer.getContext('2d'); | |
| this.backingScale = util.getBackingScale(this.ctx); | |
| this.shapes = []; | |
| this.undoStack = []; | |
| this.redoStack = []; | |
| this.isDragging = false; | |
| this.position = { | |
| x: 0, | |
| y: 0 | |
| }; | |
| this.scale = 1.0; | |
| this.tool = new Pencil(); | |
| this.width = opts.imageSize.width || INFINITE; | |
| this.height = opts.imageSize.height || INFINITE; | |
| this.setZoom(this.scale); | |
| util.matchElementSize(this.containerEl, [this.backgroundCanvas, this.canvas], this.backingScale, (function(_this) { | |
| return function() { | |
| _this.keepPanInImageBounds(); | |
| return _this.repaintAllLayers(); | |
| }; | |
| })(this)); | |
| if (this.watermarkImage) { | |
| this.watermarkImage.onload = (function(_this) { | |
| return function() { | |
| return _this.repaintLayer('background'); | |
| }; | |
| })(this); | |
| } | |
| } | |
| LiterallyCanvas.prototype.trigger = function(name, data) { | |
| return this.canvas.dispatchEvent(new CustomEvent(name, { | |
| detail: data | |
| })); | |
| }; | |
| LiterallyCanvas.prototype.on = function(name, fn) { | |
| var wrapper; | |
| wrapper = function(e) { | |
| return fn(e.detail); | |
| }; | |
| this.canvas.addEventListener(name, wrapper); | |
| return (function(_this) { | |
| return function() { | |
| return _this.canvas.removeEventListener(name, wrapper); | |
| }; | |
| })(this); | |
| }; | |
| LiterallyCanvas.prototype.getRenderScale = function() { | |
| return this.scale * this.backingScale; | |
| }; | |
| LiterallyCanvas.prototype.clientCoordsToDrawingCoords = function(x, y) { | |
| return { | |
| x: (x * this.backingScale - this.position.x) / this.getRenderScale(), | |
| y: (y * this.backingScale - this.position.y) / this.getRenderScale() | |
| }; | |
| }; | |
| LiterallyCanvas.prototype.drawingCoordsToClientCoords = function(x, y) { | |
| return { | |
| x: x * this.getRenderScale() + this.position.x, | |
| y: y * this.getRenderScale() + this.position.y | |
| }; | |
| }; | |
| LiterallyCanvas.prototype.setImageSize = function(width, height) { | |
| this.width = width || INFINITE; | |
| this.height = height || INFINITE; | |
| this.keepPanInImageBounds(); | |
| this.repaintAllLayers(); | |
| return this.trigger('imageSizeChange', { | |
| width: this.width, | |
| height: this.height | |
| }); | |
| }; | |
| LiterallyCanvas.prototype.setTool = function(tool) { | |
| this.tool = tool; | |
| return this.trigger('toolChange', { | |
| tool: tool | |
| }); | |
| }; | |
| LiterallyCanvas.prototype.begin = function(x, y) { | |
| return util.requestAnimationFrame((function(_this) { | |
| return function() { | |
| var newPos; | |
| newPos = _this.clientCoordsToDrawingCoords(x, y); | |
| _this.tool.begin(newPos.x, newPos.y, _this); | |
| _this.isDragging = true; | |
| return _this.trigger("drawStart", { | |
| tool: _this.tool | |
| }); | |
| }; | |
| })(this)); | |
| }; | |
| LiterallyCanvas.prototype["continue"] = function(x, y) { | |
| return util.requestAnimationFrame((function(_this) { | |
| return function() { | |
| var newPos; | |
| newPos = _this.clientCoordsToDrawingCoords(x, y); | |
| if (_this.isDragging) { | |
| _this.tool["continue"](newPos.x, newPos.y, _this); | |
| return _this.trigger("drawContinue", { | |
| tool: _this.tool | |
| }); | |
| } | |
| }; | |
| })(this)); | |
| }; | |
| LiterallyCanvas.prototype.end = function(x, y) { | |
| return util.requestAnimationFrame((function(_this) { | |
| return function() { | |
| var newPos; | |
| newPos = _this.clientCoordsToDrawingCoords(x, y); | |
| if (_this.isDragging) { | |
| _this.tool.end(newPos.x, newPos.y, _this); | |
| _this.isDragging = false; | |
| return _this.trigger("drawEnd", { | |
| tool: _this.tool | |
| }); | |
| } | |
| }; | |
| })(this)); | |
| }; | |
| LiterallyCanvas.prototype.setColor = function(name, color) { | |
| this.colors[name] = color; | |
| switch (name) { | |
| case 'background': | |
| this.containerEl.style.backgroundColor = this.colors.background; | |
| this.repaintLayer('background'); | |
| break; | |
| case 'primary': | |
| this.repaintLayer('main'); | |
| break; | |
| case 'secondary': | |
| this.repaintLayer('main'); | |
| } | |
| this.trigger("" + name + "ColorChange", this.colors[name]); | |
| if (name === 'background') { | |
| return this.trigger("drawingChange"); | |
| } | |
| }; | |
| LiterallyCanvas.prototype.getColor = function(name) { | |
| return this.colors[name]; | |
| }; | |
| LiterallyCanvas.prototype.saveShape = function(shape, triggerShapeSaveEvent, previousShapeId) { | |
| if (triggerShapeSaveEvent == null) { | |
| triggerShapeSaveEvent = true; | |
| } | |
| if (previousShapeId == null) { | |
| previousShapeId = null; | |
| } | |
| if (!previousShapeId) { | |
| previousShapeId = this.shapes.length ? this.shapes[this.shapes.length - 1].id : null; | |
| } | |
| this.execute(new actions.AddShapeAction(this, shape, previousShapeId)); | |
| if (triggerShapeSaveEvent) { | |
| this.trigger('shapeSave', { | |
| shape: shape, | |
| previousShapeId: previousShapeId | |
| }); | |
| } | |
| return this.trigger('drawingChange'); | |
| }; | |
| LiterallyCanvas.prototype.pan = function(x, y) { | |
| return this.setPan(this.position.x - x, this.position.y - y); | |
| }; | |
| LiterallyCanvas.prototype.keepPanInImageBounds = function() { | |
| var renderScale, x, y, _ref1; | |
| renderScale = this.getRenderScale(); | |
| _ref1 = this.position, x = _ref1.x, y = _ref1.y; | |
| if (this.width !== INFINITE) { | |
| if (this.canvas.width > this.width * renderScale) { | |
| x = (this.canvas.width - this.width * renderScale) / 2; | |
| } else { | |
| x = Math.max(Math.min(0, x), this.canvas.width - this.width * renderScale); | |
| } | |
| } | |
| if (this.height !== INFINITE) { | |
| if (this.canvas.height > this.height * renderScale) { | |
| y = (this.canvas.height - this.height * renderScale) / 2; | |
| } else { | |
| y = Math.max(Math.min(0, y), this.canvas.height - this.height * renderScale); | |
| } | |
| } | |
| return this.position = { | |
| x: x, | |
| y: y | |
| }; | |
| }; | |
| LiterallyCanvas.prototype.setPan = function(x, y) { | |
| this.position = { | |
| x: x, | |
| y: y | |
| }; | |
| this.keepPanInImageBounds(); | |
| this.repaintAllLayers(); | |
| return this.trigger('pan', { | |
| x: this.position.x, | |
| y: this.position.y | |
| }); | |
| }; | |
| LiterallyCanvas.prototype.zoom = function(factor) { | |
| var newScale; | |
| newScale = this.scale + factor; | |
| newScale = Math.max(newScale, 0.6); | |
| newScale = Math.min(newScale, 4.0); | |
| newScale = Math.round(newScale * 100) / 100; | |
| return this.setZoom(newScale); | |
| }; | |
| LiterallyCanvas.prototype.setZoom = function(scale) { | |
| var oldScale; | |
| oldScale = this.scale; | |
| this.scale = scale; | |
| this.position.x = math.scalePositionScalar(this.position.x, this.canvas.width, oldScale, this.scale); | |
| this.position.y = math.scalePositionScalar(this.position.y, this.canvas.height, oldScale, this.scale); | |
| this.keepPanInImageBounds(); | |
| this.repaintAllLayers(); | |
| return this.trigger('zoom', { | |
| oldScale: oldScale, | |
| newScale: this.scale | |
| }); | |
| }; | |
| LiterallyCanvas.prototype.repaintAllLayers = function() { | |
| var key, _i, _len, _ref1; | |
| _ref1 = ['background', 'main']; | |
| for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | |
| key = _ref1[_i]; | |
| this.repaintLayer(key); | |
| } | |
| return null; | |
| }; | |
| LiterallyCanvas.prototype.repaintLayer = function(repaintLayerKey, dirty) { | |
| var retryCallback; | |
| if (dirty == null) { | |
| dirty = repaintLayerKey === 'main'; | |
| } | |
| switch (repaintLayerKey) { | |
| case 'background': | |
| this.backgroundCtx.clearRect(0, 0, this.backgroundCanvas.width, this.backgroundCanvas.height); | |
| if (this.watermarkImage) { | |
| this._renderWatermark(this.backgroundCtx); | |
| } | |
| retryCallback = (function(_this) { | |
| return function() { | |
| return _this.repaintLayer('background'); | |
| }; | |
| })(this); | |
| this.draw(this.backgroundShapes, this.backgroundCtx, retryCallback); | |
| break; | |
| case 'main': | |
| retryCallback = (function(_this) { | |
| return function() { | |
| return _this.repaintLayer('main', true); | |
| }; | |
| })(this); | |
| if (dirty) { | |
| this.buffer.width = this.canvas.width; | |
| this.buffer.height = this.canvas.height; | |
| this.bufferCtx.clearRect(0, 0, this.buffer.width, this.buffer.height); | |
| this.draw(this.shapes, this.bufferCtx, retryCallback); | |
| } | |
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |
| if (this.canvas.width > 0 && this.canvas.height > 0) { | |
| this.ctx.fillStyle = '#ccc'; | |
| this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); | |
| this.clipped(((function(_this) { | |
| return function() { | |
| _this.ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height); | |
| return _this.ctx.drawImage(_this.buffer, 0, 0); | |
| }; | |
| })(this)), this.ctx); | |
| } | |
| } | |
| return this.trigger('repaint', { | |
| layerKey: repaintLayerKey | |
| }); | |
| }; | |
| LiterallyCanvas.prototype._renderWatermark = function(ctx, worryAboutRetina) { | |
| if (worryAboutRetina == null) { | |
| worryAboutRetina = true; | |
| } | |
| ctx.save(); | |
| ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); | |
| ctx.scale(this.watermarkScale, this.watermarkScale); | |
| if (worryAboutRetina) { | |
| ctx.scale(this.backingScale, this.backingScale); | |
| } | |
| ctx.drawImage(this.watermarkImage, -this.watermarkImage.width / 2, -this.watermarkImage.height / 2); | |
| return ctx.restore(); | |
| }; | |
| LiterallyCanvas.prototype.drawShapeInProgress = function(shape) { | |
| this.repaintLayer('main', false); | |
| return this.clipped(((function(_this) { | |
| return function() { | |
| return _this.transformed((function() { | |
| return shape.drawLatest(_this.ctx, _this.bufferCtx); | |
| }), _this.ctx, _this.bufferCtx); | |
| }; | |
| })(this)), this.ctx, this.bufferCtx); | |
| }; | |
| LiterallyCanvas.prototype.draw = function(shapes, ctx, retryCallback) { | |
| var drawShapes; | |
| if (!shapes.length) { | |
| return; | |
| } | |
| drawShapes = (function(_this) { | |
| return function() { | |
| var shape, _i, _len, _results; | |
| _results = []; | |
| for (_i = 0, _len = shapes.length; _i < _len; _i++) { | |
| shape = shapes[_i]; | |
| _results.push(shape.draw(ctx, retryCallback)); | |
| } | |
| return _results; | |
| }; | |
| })(this); | |
| return this.clipped(((function(_this) { | |
| return function() { | |
| return _this.transformed(drawShapes, ctx); | |
| }; | |
| })(this)), ctx); | |
| }; | |
| LiterallyCanvas.prototype.clipped = function() { | |
| var contexts, ctx, fn, height, width, x, y, _i, _j, _len, _len1, _results; | |
| fn = arguments[0], contexts = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | |
| x = this.width === INFINITE ? 0 : this.position.x; | |
| y = this.height === INFINITE ? 0 : this.position.y; | |
| width = (function() { | |
| switch (this.width) { | |
| case INFINITE: | |
| return this.canvas.width; | |
| default: | |
| return this.width * this.getRenderScale(); | |
| } | |
| }).call(this); | |
| height = (function() { | |
| switch (this.height) { | |
| case INFINITE: | |
| return this.canvas.height; | |
| default: | |
| return this.height * this.getRenderScale(); | |
| } | |
| }).call(this); | |
| for (_i = 0, _len = contexts.length; _i < _len; _i++) { | |
| ctx = contexts[_i]; | |
| ctx.save(); | |
| ctx.beginPath(); | |
| ctx.rect(x, y, width, height); | |
| ctx.clip(); | |
| } | |
| fn(); | |
| _results = []; | |
| for (_j = 0, _len1 = contexts.length; _j < _len1; _j++) { | |
| ctx = contexts[_j]; | |
| _results.push(ctx.restore()); | |
| } | |
| return _results; | |
| }; | |
| LiterallyCanvas.prototype.transformed = function() { | |
| var contexts, ctx, fn, scale, _i, _j, _len, _len1, _results; | |
| fn = arguments[0], contexts = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | |
| for (_i = 0, _len = contexts.length; _i < _len; _i++) { | |
| ctx = contexts[_i]; | |
| ctx.save(); | |
| ctx.translate(this.position.x, this.position.y); | |
| scale = this.getRenderScale(); | |
| ctx.scale(scale, scale); | |
| } | |
| fn(); | |
| _results = []; | |
| for (_j = 0, _len1 = contexts.length; _j < _len1; _j++) { | |
| ctx = contexts[_j]; | |
| _results.push(ctx.restore()); | |
| } | |
| return _results; | |
| }; | |
| LiterallyCanvas.prototype.clear = function() { | |
| var newShapes, oldShapes; | |
| oldShapes = this.shapes; | |
| newShapes = []; | |
| this.execute(new actions.ClearAction(this, oldShapes, newShapes)); | |
| this.repaintLayer('main'); | |
| this.trigger('clear', null); | |
| return this.trigger('drawingChange', {}); | |
| }; | |
| LiterallyCanvas.prototype.execute = function(action) { | |
| this.undoStack.push(action); | |
| action["do"](); | |
| return this.redoStack = []; | |
| }; | |
| LiterallyCanvas.prototype.undo = function() { | |
| var action; | |
| if (!this.undoStack.length) { | |
| return; | |
| } | |
| action = this.undoStack.pop(); | |
| action.undo(); | |
| this.redoStack.push(action); | |
| this.trigger('undo', { | |
| action: action | |
| }); | |
| return this.trigger('drawingChange', {}); | |
| }; | |
| LiterallyCanvas.prototype.redo = function() { | |
| var action; | |
| if (!this.redoStack.length) { | |
| return; | |
| } | |
| action = this.redoStack.pop(); | |
| this.undoStack.push(action); | |
| action["do"](); | |
| this.trigger('redo', { | |
| action: action | |
| }); | |
| return this.trigger('drawingChange', {}); | |
| }; | |
| LiterallyCanvas.prototype.canUndo = function() { | |
| return !!this.undoStack.length; | |
| }; | |
| LiterallyCanvas.prototype.canRedo = function() { | |
| return !!this.redoStack.length; | |
| }; | |
| LiterallyCanvas.prototype.getPixel = function(x, y) { | |
| var p, pixel; | |
| p = this.drawingCoordsToClientCoords(x, y); | |
| pixel = this.ctx.getImageData(p.x, p.y, 1, 1).data; | |
| if (pixel[3]) { | |
| return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; | |
| } else { | |
| return null; | |
| } | |
| }; | |
| LiterallyCanvas.prototype.getContentBounds = function() { | |
| return util.getBoundingRect(this.shapes.map(function(s) { | |
| return s.getBoundingRect(); | |
| }), this.width === INFINITE ? 0 : this.width, this.height === INFINITE ? 0 : this.height); | |
| }; | |
| LiterallyCanvas.prototype.getImage = function(opts) { | |
| var watermarkCanvas, watermarkCtx; | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.rect == null) { | |
| opts.rect = this.getContentBounds(); | |
| } | |
| if (!(opts.rect.width && opts.rect.height)) { | |
| return; | |
| } | |
| if (opts.scale == null) { | |
| opts.scale = 1; | |
| } | |
| if (opts.scaleDownRetina == null) { | |
| opts.scaleDownRetina = true; | |
| } | |
| if (opts.includeWatermark == null) { | |
| opts.includeWatermark = this.watermarkImage && true; | |
| } | |
| if (!opts.scaleDownRetina) { | |
| opts.scale *= this.backingScale; | |
| } | |
| this.repaintLayer('main', true); | |
| watermarkCanvas = document.createElement('canvas'); | |
| watermarkCanvas.width = opts.rect.width * opts.scale; | |
| watermarkCanvas.height = opts.rect.height * opts.scale; | |
| watermarkCtx = watermarkCanvas.getContext('2d'); | |
| watermarkCtx.fillStyle = this.colors.background; | |
| watermarkCtx.fillRect(0, 0, watermarkCanvas.width, watermarkCanvas.height); | |
| if (opts.includeWatermark) { | |
| this._renderWatermark(watermarkCtx, false); | |
| } | |
| return util.combineCanvases(watermarkCanvas, util.renderShapes(this.backgroundShapes, opts.rect, opts.scale), util.renderShapes(this.shapes, opts.rect, opts.scale)); | |
| }; | |
| LiterallyCanvas.prototype.canvasForExport = function() { | |
| this.repaintAllLayers(); | |
| return util.combineCanvases(this.backgroundCanvas, this.canvas); | |
| }; | |
| LiterallyCanvas.prototype.canvasWithBackground = function(backgroundImageOrCanvas) { | |
| return util.combineCanvases(backgroundImageOrCanvas, this.canvasForExport()); | |
| }; | |
| LiterallyCanvas.prototype.getSnapshot = function() { | |
| var shape; | |
| return { | |
| shapes: (function() { | |
| var _i, _len, _ref1, _results; | |
| _ref1 = this.shapes; | |
| _results = []; | |
| for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | |
| shape = _ref1[_i]; | |
| _results.push(shapeToJSON(shape)); | |
| } | |
| return _results; | |
| }).call(this), | |
| colors: this.colors | |
| }; | |
| }; | |
| LiterallyCanvas.prototype.getSnapshotJSON = function() { | |
| return JSON.stringify(this.getSnapshot()); | |
| }; | |
| LiterallyCanvas.prototype.getSVGString = function(opts) { | |
| var height, width, x, y, _ref1; | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.rect == null) { | |
| opts.rect = this.getContentBounds(); | |
| } | |
| _ref1 = opts.rect, x = _ref1.x, y = _ref1.y, width = _ref1.width, height = _ref1.height; | |
| return "<svg width='" + width + "' height='" + height + "' viewBox='0 0 " + width + " " + height + "'> <rect width=" + width + " height=" + height + " x=0 y=0 fill='" + this.colors.background + "' /> <g transform='translate(" + (-x) + ", " + (-y) + ")'> " + (this.backgroundShapes.map(function(s) { | |
| return s.toSVG(); | |
| }).join('')) + " " + (this.shapes.map(function(s) { | |
| return s.toSVG(); | |
| }).join('')) + " </g> </svg>"; | |
| }; | |
| LiterallyCanvas.prototype.loadSnapshot = function(snapshot) { | |
| var k, shape, shapeRepr, _i, _j, _len, _len1, _ref1, _ref2; | |
| if (!snapshot) { | |
| return; | |
| } | |
| if (snapshot.colors == null) { | |
| snapshot.colors = this.colors; | |
| } | |
| _ref1 = ['primary', 'secondary', 'background']; | |
| for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | |
| k = _ref1[_i]; | |
| this.setColor(k, snapshot.colors[k]); | |
| } | |
| this.shapes = []; | |
| _ref2 = snapshot.shapes; | |
| for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { | |
| shapeRepr = _ref2[_j]; | |
| shape = JSONToShape(shapeRepr); | |
| if (shape) { | |
| this.execute(new actions.AddShapeAction(this, shape)); | |
| } | |
| } | |
| this.repaintAllLayers(); | |
| this.trigger('snapshotLoad'); | |
| return this.trigger('drawingChange', {}); | |
| }; | |
| LiterallyCanvas.prototype.loadSnapshotJSON = function(str) { | |
| return this.loadSnapshot(JSON.parse(str)); | |
| }; | |
| return LiterallyCanvas; | |
| })(); | |
| },{"../tools/Pencil":32,"./actions":3,"./bindEvents":4,"./math":7,"./shapes":8,"./util":9}],3:[function(_dereq_,module,exports){ | |
| var AddShapeAction, ClearAction; | |
| ClearAction = (function() { | |
| function ClearAction(lc, oldShapes, newShapes) { | |
| this.lc = lc; | |
| this.oldShapes = oldShapes; | |
| this.newShapes = newShapes; | |
| } | |
| ClearAction.prototype["do"] = function() { | |
| this.lc.shapes = this.newShapes; | |
| return this.lc.repaintLayer('main'); | |
| }; | |
| ClearAction.prototype.undo = function() { | |
| this.lc.shapes = this.oldShapes; | |
| return this.lc.repaintLayer('main'); | |
| }; | |
| return ClearAction; | |
| })(); | |
| AddShapeAction = (function() { | |
| function AddShapeAction(lc, shape, previousShapeId) { | |
| this.lc = lc; | |
| this.shape = shape; | |
| this.previousShapeId = previousShapeId != null ? previousShapeId : null; | |
| } | |
| AddShapeAction.prototype["do"] = function() { | |
| var found, newShapes, shape, _i, _len, _ref; | |
| if (!this.lc.shapes.length || this.lc.shapes[this.lc.shapes.length - 1].id === this.previousShapeId || this.previousShapeId === null) { | |
| this.lc.shapes.push(this.shape); | |
| } else { | |
| newShapes = []; | |
| found = false; | |
| _ref = this.lc.shapes; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| shape = _ref[_i]; | |
| newShapes.push(shape); | |
| if (shape.id === this.previousShapeId) { | |
| newShapes.push(this.shape); | |
| found = true; | |
| } | |
| } | |
| if (!found) { | |
| newShapes.push(this.shape); | |
| } | |
| this.lc.shapes = newShapes; | |
| } | |
| return this.lc.repaintLayer('main'); | |
| }; | |
| AddShapeAction.prototype.undo = function() { | |
| var newShapes, shape, _i, _len, _ref; | |
| if (this.lc.shapes[this.lc.shapes.length - 1].id === this.shape.id) { | |
| this.lc.shapes.pop(); | |
| } else { | |
| newShapes = []; | |
| _ref = this.lc.shapes; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| shape = _ref[_i]; | |
| if (shape.id !== this.shape.id) { | |
| newShapes.push(shape); | |
| } | |
| } | |
| lc.shapes = newShapes; | |
| } | |
| return this.lc.repaintLayer('main'); | |
| }; | |
| return AddShapeAction; | |
| })(); | |
| module.exports = { | |
| ClearAction: ClearAction, | |
| AddShapeAction: AddShapeAction | |
| }; | |
| },{}],4:[function(_dereq_,module,exports){ | |
| var bindEvents, buttonIsDown, coordsForTouchEvent, position; | |
| coordsForTouchEvent = function(el, e) { | |
| var p, tx, ty; | |
| tx = e.changedTouches[0].clientX; | |
| ty = e.changedTouches[0].clientY; | |
| p = el.getBoundingClientRect(); | |
| return [tx - p.left, ty - p.top]; | |
| }; | |
| position = function(el, e) { | |
| var p; | |
| p = el.getBoundingClientRect(); | |
| return { | |
| left: e.clientX - p.left, | |
| top: e.clientY - p.top | |
| }; | |
| }; | |
| buttonIsDown = function(e) { | |
| if (e.buttons != null) { | |
| return e.buttons === 1; | |
| } else { | |
| return e.which > 0; | |
| } | |
| }; | |
| module.exports = bindEvents = function(lc, canvas, panWithKeyboard) { | |
| var mouseMoveListener, mouseUpListener, touchEndListener, touchMoveListener; | |
| if (panWithKeyboard == null) { | |
| panWithKeyboard = false; | |
| } | |
| mouseMoveListener = (function(_this) { | |
| return function(e) { | |
| var p; | |
| e.preventDefault(); | |
| p = position(canvas, e); | |
| return lc["continue"](p.left, p.top); | |
| }; | |
| })(this); | |
| mouseUpListener = (function(_this) { | |
| return function(e) { | |
| var p; | |
| e.preventDefault(); | |
| canvas.onselectstart = function() { | |
| return true; | |
| }; | |
| p = position(canvas, e); | |
| lc.end(p.left, p.top); | |
| document.removeEventListener('mousemove', mouseMoveListener); | |
| return document.removeEventListener('mouseup', mouseUpListener); | |
| }; | |
| })(this); | |
| canvas.addEventListener('mousedown', (function(_this) { | |
| return function(e) { | |
| var down, p; | |
| down = true; | |
| e.preventDefault(); | |
| canvas.onselectstart = function() { | |
| return false; | |
| }; | |
| p = position(canvas, e); | |
| lc.begin(p.left, p.top); | |
| document.addEventListener('mousemove', mouseMoveListener); | |
| return document.addEventListener('mouseup', mouseUpListener); | |
| }; | |
| })(this)); | |
| touchMoveListener = function(e) { | |
| e.preventDefault(); | |
| return lc["continue"].apply(lc, coordsForTouchEvent(canvas, e)); | |
| }; | |
| touchEndListener = function(e) { | |
| e.preventDefault(); | |
| lc.end.apply(lc, coordsForTouchEvent(canvas, e)); | |
| document.removeEventListener('touchmove', touchMoveListener); | |
| document.removeEventListener('touchend', touchEndListener); | |
| return document.removeEventListener('touchcancel', touchEndListener); | |
| }; | |
| canvas.addEventListener('touchstart', function(e) { | |
| e.preventDefault(); | |
| if (e.touches.length === 1) { | |
| lc.begin.apply(lc, coordsForTouchEvent(canvas, e)); | |
| document.addEventListener('touchmove', touchMoveListener); | |
| document.addEventListener('touchend', touchEndListener); | |
| return document.addEventListener('touchcancel', touchEndListener); | |
| } else { | |
| return lc["continue"].apply(lc, coordsForTouchEvent(canvas, e)); | |
| } | |
| }); | |
| if (panWithKeyboard) { | |
| return document.addEventListener('keydown', function(e) { | |
| switch (e.keyCode) { | |
| case 37: | |
| lc.pan(-10, 0); | |
| break; | |
| case 38: | |
| lc.pan(0, -10); | |
| break; | |
| case 39: | |
| lc.pan(10, 0); | |
| break; | |
| case 40: | |
| lc.pan(0, 10); | |
| } | |
| return lc.repaintAllLayers(); | |
| }); | |
| } | |
| }; | |
| },{}],5:[function(_dereq_,module,exports){ | |
| module.exports = { | |
| arrow: (function() { | |
| var getPoints; | |
| getPoints = function(x, y, angle, width, length) { | |
| return [ | |
| { | |
| x: x + Math.cos(angle + Math.PI / 2) * width / 2, | |
| y: y + Math.sin(angle + Math.PI / 2) * width / 2 | |
| }, { | |
| x: x + Math.cos(angle) * length, | |
| y: y + Math.sin(angle) * length | |
| }, { | |
| x: x + Math.cos(angle - Math.PI / 2) * width / 2, | |
| y: y + Math.sin(angle - Math.PI / 2) * width / 2 | |
| } | |
| ]; | |
| }; | |
| return { | |
| drawToCanvas: function(ctx, x, y, angle, width, color, length) { | |
| var points; | |
| if (length == null) { | |
| length = 0; | |
| } | |
| length = length || width; | |
| ctx.fillStyle = color; | |
| ctx.lineWidth = 0; | |
| ctx.strokeStyle = 'transparent'; | |
| ctx.beginPath(); | |
| points = getPoints(x, y, angle, width, length); | |
| ctx.moveTo(points[0].x, points[0].y); | |
| ctx.lineTo(points[1].x, points[1].y); | |
| ctx.lineTo(points[2].x, points[2].y); | |
| return ctx.fill(); | |
| }, | |
| svg: function(x, y, angle, width, color, length) { | |
| var points; | |
| if (length == null) { | |
| length = 0; | |
| } | |
| length = length || width; | |
| points = getPoints(x, y, angle, width, length); | |
| return "<polygon fill='" + color + "' stroke='none' points='" + (points.map(function(p) { | |
| return "" + p.x + "," + p.y; | |
| })) + "' />"; | |
| } | |
| }; | |
| })() | |
| }; | |
| },{}],6:[function(_dereq_,module,exports){ | |
| var localize, strings, _; | |
| strings = {}; | |
| localize = function(localStrings) { | |
| return strings = localStrings; | |
| }; | |
| _ = function(string) { | |
| var translation; | |
| translation = strings[string]; | |
| return translation || string; | |
| }; | |
| module.exports = { | |
| localize: localize, | |
| _: _ | |
| }; | |
| },{}],7:[function(_dereq_,module,exports){ | |
| var Point, math, normals, unit, util, _slope; | |
| Point = _dereq_('./shapes').Point; | |
| util = _dereq_('./util'); | |
| math = {}; | |
| math.toPoly = function(line) { | |
| var index, n, point, polyLeft, polyRight, _i, _len; | |
| polyLeft = []; | |
| polyRight = []; | |
| index = 0; | |
| for (_i = 0, _len = line.length; _i < _len; _i++) { | |
| point = line[_i]; | |
| n = normals(point, _slope(line, index)); | |
| polyLeft = polyLeft.concat([n[0]]); | |
| polyRight = [n[1]].concat(polyRight); | |
| index += 1; | |
| } | |
| return polyLeft.concat(polyRight); | |
| }; | |
| _slope = function(line, index) { | |
| var point; | |
| if (line.length < 3) { | |
| point = { | |
| x: 0, | |
| y: 0 | |
| }; | |
| } | |
| if (index === 0) { | |
| point = _slope(line, index + 1); | |
| } else if (index === line.length - 1) { | |
| point = _slope(line, index - 1); | |
| } else { | |
| point = math.diff(line[index - 1], line[index + 1]); | |
| } | |
| return point; | |
| }; | |
| math.diff = function(a, b) { | |
| return { | |
| x: b.x - a.x, | |
| y: b.y - a.y | |
| }; | |
| }; | |
| unit = function(vector) { | |
| var length; | |
| length = math.len(vector); | |
| return { | |
| x: vector.x / length, | |
| y: vector.y / length | |
| }; | |
| }; | |
| normals = function(p, slope) { | |
| slope = unit(slope); | |
| slope.x = slope.x * p.size / 2; | |
| slope.y = slope.y * p.size / 2; | |
| return [ | |
| { | |
| x: p.x - slope.y, | |
| y: p.y + slope.x, | |
| color: p.color | |
| }, { | |
| x: p.x + slope.y, | |
| y: p.y - slope.x, | |
| color: p.color | |
| } | |
| ]; | |
| }; | |
| math.len = function(vector) { | |
| return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2)); | |
| }; | |
| math.scalePositionScalar = function(val, viewportSize, oldScale, newScale) { | |
| var newSize, oldSize; | |
| oldSize = viewportSize * oldScale; | |
| newSize = viewportSize * newScale; | |
| return val + (oldSize - newSize) / 2; | |
| }; | |
| module.exports = math; | |
| },{"./shapes":8,"./util":9}],8:[function(_dereq_,module,exports){ | |
| var JSONToShape, LinePath, bspline, createShape, defineShape, lineEndCapShapes, linePathFuncs, shapeToJSON, shapes, util, _createLinePathFromData, _doAllPointsShareStyle, _dual, _mid, _refine, | |
| __slice = [].slice; | |
| util = _dereq_('./util'); | |
| lineEndCapShapes = _dereq_('../core/lineEndCapShapes.coffee'); | |
| shapes = {}; | |
| defineShape = function(name, props) { | |
| var Shape, k; | |
| Shape = function() { | |
| var args, _ref; | |
| args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | |
| (_ref = props.constructor).call.apply(_ref, [this].concat(__slice.call(args))); | |
| return this; | |
| }; | |
| if (props.toSVG == null) { | |
| props.toSVG = function() { | |
| return ''; | |
| }; | |
| } | |
| Shape.prototype.className = name; | |
| Shape.fromJSON = props.fromJSON; | |
| Shape.prototype.drawLatest = function(ctx, bufferCtx) { | |
| return this.draw(ctx, bufferCtx); | |
| }; | |
| for (k in props) { | |
| if (k !== 'fromJSON') { | |
| Shape.prototype[k] = props[k]; | |
| } | |
| } | |
| shapes[name] = Shape; | |
| return Shape; | |
| }; | |
| createShape = function() { | |
| var args, name, s; | |
| name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | |
| s = (function(func, args, ctor) { | |
| ctor.prototype = func.prototype; | |
| var child = new ctor, result = func.apply(child, args); | |
| return Object(result) === result ? result : child; | |
| })(shapes[name], args, function(){}); | |
| s.id = util.getGUID(); | |
| return s; | |
| }; | |
| JSONToShape = function(_arg) { | |
| var className, data, id, shape; | |
| className = _arg.className, data = _arg.data, id = _arg.id; | |
| if (className in shapes) { | |
| shape = shapes[className].fromJSON(data); | |
| if (shape) { | |
| if (id) { | |
| shape.id = id; | |
| } | |
| return shape; | |
| } else { | |
| console.log('Unreadable shape:', className, data); | |
| return null; | |
| } | |
| } else { | |
| console.log("Unknown shape:", className, data); | |
| return null; | |
| } | |
| }; | |
| shapeToJSON = function(shape) { | |
| return { | |
| className: shape.className, | |
| data: shape.toJSON(), | |
| id: shape.id | |
| }; | |
| }; | |
| bspline = function(points, order) { | |
| if (!order) { | |
| return points; | |
| } | |
| return bspline(_dual(_dual(_refine(points))), order - 1); | |
| }; | |
| _refine = function(points) { | |
| var index, point, refined, _i, _len; | |
| points = [points[0]].concat(points).concat(util.last(points)); | |
| refined = []; | |
| index = 0; | |
| for (_i = 0, _len = points.length; _i < _len; _i++) { | |
| point = points[_i]; | |
| refined[index * 2] = point; | |
| if (points[index + 1]) { | |
| refined[index * 2 + 1] = _mid(point, points[index + 1]); | |
| } | |
| index += 1; | |
| } | |
| return refined; | |
| }; | |
| _dual = function(points) { | |
| var dualed, index, point, _i, _len; | |
| dualed = []; | |
| index = 0; | |
| for (_i = 0, _len = points.length; _i < _len; _i++) { | |
| point = points[_i]; | |
| if (points[index + 1]) { | |
| dualed[index] = _mid(point, points[index + 1]); | |
| } | |
| index += 1; | |
| } | |
| return dualed; | |
| }; | |
| _mid = function(a, b) { | |
| return createShape('Point', { | |
| x: a.x + ((b.x - a.x) / 2), | |
| y: a.y + ((b.y - a.y) / 2), | |
| size: a.size + ((b.size - a.size) / 2), | |
| color: a.color | |
| }); | |
| }; | |
| defineShape('Image', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| return this.image = args.image || null; | |
| }, | |
| draw: function(ctx, retryCallback) { | |
| if (this.image.width) { | |
| return ctx.drawImage(this.image, this.x, this.y); | |
| } else { | |
| return this.image.onload = retryCallback; | |
| } | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| width: this.image.width, | |
| height: this.image.height | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| imageSrc: this.image.src | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| var img; | |
| img = new Image(); | |
| img.src = data.imageSrc; | |
| return createShape('Image', { | |
| x: data.x, | |
| x: data.y, | |
| image: img | |
| }); | |
| }, | |
| toSVG: function() { | |
| return "<image x=" + this.x + " y=" + this.y + " width=" + this.image.naturalWidth + " height=" + this.image.naturalHeight + " xlink:href=" + this.image.src + " />"; | |
| } | |
| }); | |
| defineShape('Rectangle', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| this.width = args.width || 0; | |
| this.height = args.height || 0; | |
| this.strokeWidth = args.strokeWidth || 1; | |
| this.strokeColor = args.strokeColor || 'black'; | |
| return this.fillColor = args.fillColor || 'transparent'; | |
| }, | |
| draw: function(ctx) { | |
| ctx.fillStyle = this.fillColor; | |
| ctx.fillRect(this.x, this.y, this.width, this.height); | |
| ctx.lineWidth = this.strokeWidth; | |
| ctx.strokeStyle = this.strokeColor; | |
| return ctx.strokeRect(this.x, this.y, this.width, this.height); | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this.x - this.strokeWidth / 2, | |
| y: this.y - this.strokeWidth / 2, | |
| width: this.width + this.strokeWidth, | |
| height: this.height + this.strokeWidth | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| width: this.width, | |
| height: this.height, | |
| strokeWidth: this.strokeWidth, | |
| strokeColor: this.strokeColor, | |
| fillColor: this.fillColor | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Rectangle', data); | |
| }, | |
| toSVG: function() { | |
| return "<rect x=" + this.x + " y=" + this.y + " width=" + this.width + " height=" + this.height + " stroke='" + this.strokeColor + "' fill='" + this.fillColor + "' stroke-width=" + this.strokeWidth + " />"; | |
| } | |
| }); | |
| defineShape('Ellipse', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| this.width = args.width || 0; | |
| this.height = args.height || 0; | |
| this.strokeWidth = args.strokeWidth || 1; | |
| this.strokeColor = args.strokeColor || 'black'; | |
| return this.fillColor = args.fillColor || 'transparent'; | |
| }, | |
| draw: function(ctx) { | |
| var centerX, centerY, halfHeight, halfWidth; | |
| ctx.save(); | |
| halfWidth = Math.floor(this.width / 2); | |
| halfHeight = Math.floor(this.height / 2); | |
| centerX = this.x + halfWidth; | |
| centerY = this.y + halfHeight; | |
| ctx.translate(centerX, centerY); | |
| ctx.scale(1, Math.abs(this.height / this.width)); | |
| ctx.beginPath(); | |
| ctx.arc(0, 0, Math.abs(halfWidth), 0, Math.PI * 2); | |
| ctx.closePath(); | |
| ctx.restore(); | |
| ctx.fillStyle = this.fillColor; | |
| ctx.fill(); | |
| ctx.lineWidth = this.strokeWidth; | |
| ctx.strokeStyle = this.strokeColor; | |
| return ctx.stroke(); | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this.x - this.strokeWidth / 2, | |
| y: this.y - this.strokeWidth / 2, | |
| width: this.width + this.strokeWidth, | |
| height: this.height + this.strokeWidth | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| width: this.width, | |
| height: this.height, | |
| strokeWidth: this.strokeWidth, | |
| strokeColor: this.strokeColor, | |
| fillColor: this.fillColor | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Ellipse', data); | |
| }, | |
| toSVG: function() { | |
| var centerX, centerY, halfHeight, halfWidth; | |
| halfWidth = Math.floor(this.width / 2); | |
| halfHeight = Math.floor(this.height / 2); | |
| centerX = this.x + halfWidth; | |
| centerY = this.y + halfHeight; | |
| return "<ellipse cx=" + centerX + " cy=" + centerY + " rx=" + halfWidth + " ry=" + halfHeight + " stroke='" + this.strokeColor + "' fill='" + this.fillColor + "' stroke-width=" + this.strokeWidth + " />"; | |
| } | |
| }); | |
| defineShape('Line', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x1 = args.x1 || 0; | |
| this.y1 = args.y1 || 0; | |
| this.x2 = args.x2 || 0; | |
| this.y2 = args.y2 || 0; | |
| this.strokeWidth = args.strokeWidth || 1; | |
| this.strokeStyle = args.strokeStyle || null; | |
| this.color = args.color || 'black'; | |
| this.capStyle = args.capStyle || 'round'; | |
| this.endCapShapes = args.endCapShapes || [null, null]; | |
| return this.dash = args.dash || null; | |
| }, | |
| draw: function(ctx) { | |
| var arrowWidth; | |
| ctx.lineWidth = this.strokeWidth; | |
| ctx.strokeStyle = this.color; | |
| ctx.lineCap = this.capStyle; | |
| if (this.dash) { | |
| ctx.setLineDash(this.dash); | |
| } | |
| ctx.beginPath(); | |
| ctx.moveTo(this.x1, this.y1); | |
| ctx.lineTo(this.x2, this.y2); | |
| ctx.stroke(); | |
| if (this.dash) { | |
| ctx.setLineDash([]); | |
| } | |
| arrowWidth = Math.max(this.strokeWidth * 2.2, 5); | |
| if (this.endCapShapes[0]) { | |
| lineEndCapShapes[this.endCapShapes[0]].drawToCanvas(ctx, this.x1, this.y1, Math.atan2(this.y1 - this.y2, this.x1 - this.x2), arrowWidth, this.color); | |
| } | |
| if (this.endCapShapes[1]) { | |
| return lineEndCapShapes[this.endCapShapes[1]].drawToCanvas(ctx, this.x2, this.y2, Math.atan2(this.y2 - this.y1, this.x2 - this.x1), arrowWidth, this.color); | |
| } | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: Math.min(this.x1, this.x2) - this.strokeWidth / 2, | |
| y: Math.min(this.y1, this.y2) - this.strokeWidth / 2, | |
| width: Math.abs(this.x2 - this.x1) + this.strokeWidth / 2, | |
| height: Math.abs(this.y2 - this.y1) + this.strokeWidth / 2 | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x1: this.x1, | |
| y1: this.y1, | |
| x2: this.x2, | |
| y2: this.y2, | |
| strokeWidth: this.strokeWidth, | |
| color: this.color, | |
| capStyle: this.capStyle, | |
| dash: this.dash, | |
| endCapShapes: this.endCapShapes | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Line', data); | |
| }, | |
| toSVG: function() { | |
| var arrowWidth, capString, dashString; | |
| dashString = this.dash ? "stroke-dasharray='" + (this.dash.join(', ')) + "'" : ''; | |
| capString = ''; | |
| arrowWidth = Math.max(this.strokeWidth * 2.2, 5); | |
| if (this.endCapShapes[0]) { | |
| capString += lineEndCapShapes[this.endCapShapes[0]].svg(this.x1, this.y1, Math.atan2(this.y1 - this.y2, this.x1 - this.x2), arrowWidth, this.color); | |
| } | |
| if (this.endCapShapes[1]) { | |
| capString += lineEndCapShapes[this.endCapShapes[1]].svg(this.x2, this.y2, Math.atan2(this.y2 - this.y1, this.x2 - this.x1), arrowWidth, this.color); | |
| } | |
| return "<g> <line x1=" + this.x1 + " y1=" + this.y1 + " x2=" + this.x2 + " y2=" + this.y2 + " " + dashString + " stroke-linecap='" + this.capStyle + "' stroke='" + this.color + "'stroke-width=" + this.strokeWidth + " /> " + capString + " <g>"; | |
| } | |
| }); | |
| _doAllPointsShareStyle = function(points) { | |
| var color, point, size, _i, _len; | |
| if (!points.length) { | |
| return false; | |
| } | |
| size = points[0].size; | |
| color = points[0].color; | |
| for (_i = 0, _len = points.length; _i < _len; _i++) { | |
| point = points[_i]; | |
| if (!(point.size === size && point.color === color)) { | |
| console.log(size, color, point.size, point.color); | |
| } | |
| if (!(point.size === size && point.color === color)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| }; | |
| _createLinePathFromData = function(shapeName, data) { | |
| var pointData, points, x, y; | |
| points = null; | |
| if (data.points) { | |
| points = (function() { | |
| var _i, _len, _ref, _results; | |
| _ref = data.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| pointData = _ref[_i]; | |
| _results.push(JSONToShape(pointData)); | |
| } | |
| return _results; | |
| })(); | |
| } else if (data.pointCoordinatePairs) { | |
| points = (function() { | |
| var _i, _len, _ref, _ref1, _results; | |
| _ref = data.pointCoordinatePairs; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| _ref1 = _ref[_i], x = _ref1[0], y = _ref1[1]; | |
| _results.push(JSONToShape({ | |
| className: 'Point', | |
| data: { | |
| x: x, | |
| y: y, | |
| size: data.pointSize, | |
| color: data.pointColor, | |
| smooth: data.smooth | |
| } | |
| })); | |
| } | |
| return _results; | |
| })(); | |
| } | |
| if (!points[0]) { | |
| return null; | |
| } | |
| return createShape(shapeName, { | |
| points: points, | |
| order: data.order, | |
| tailSize: data.tailSize, | |
| smooth: data.smooth | |
| }); | |
| }; | |
| linePathFuncs = { | |
| constructor: function(args) { | |
| var point, points, _i, _len, _results; | |
| if (args == null) { | |
| args = {}; | |
| } | |
| points = args.points || []; | |
| this.order = args.order || 3; | |
| this.tailSize = args.tailSize || 3; | |
| this.smooth = 'smooth' in args ? args.smooth : true; | |
| this.segmentSize = Math.pow(2, this.order); | |
| this.sampleSize = this.tailSize + 1; | |
| this.points = []; | |
| _results = []; | |
| for (_i = 0, _len = points.length; _i < _len; _i++) { | |
| point = points[_i]; | |
| _results.push(this.addPoint(point)); | |
| } | |
| return _results; | |
| }, | |
| getBoundingRect: function() { | |
| return util.getBoundingRect(this.points.map(function(p) { | |
| return { | |
| x: p.x - p.size / 2, | |
| y: p.y - p.size / 2, | |
| width: p.size, | |
| height: p.size | |
| }; | |
| })); | |
| }, | |
| toJSON: function() { | |
| var p, point; | |
| if (_doAllPointsShareStyle(this.points)) { | |
| return { | |
| order: this.order, | |
| tailSize: this.tailSize, | |
| smooth: this.smooth, | |
| pointCoordinatePairs: (function() { | |
| var _i, _len, _ref, _results; | |
| _ref = this.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| point = _ref[_i]; | |
| _results.push([point.x, point.y]); | |
| } | |
| return _results; | |
| }).call(this), | |
| pointSize: this.points[0].size, | |
| pointColor: this.points[0].color | |
| }; | |
| } else { | |
| return { | |
| order: this.order, | |
| tailSize: this.tailSize, | |
| smooth: this.smooth, | |
| points: (function() { | |
| var _i, _len, _ref, _results; | |
| _ref = this.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| p = _ref[_i]; | |
| _results.push(shapeToJSON(p)); | |
| } | |
| return _results; | |
| }).call(this) | |
| }; | |
| } | |
| }, | |
| fromJSON: function(data) { | |
| return _createLinePathFromData('LinePath', data); | |
| }, | |
| toSVG: function() { | |
| return "<polyline fill='none' points='" + (this.smoothedPoints.map(function(p) { | |
| return "" + p.x + "," + p.y; | |
| }).join(' ')) + "' stroke='" + this.points[0].color + "' stroke-width=" + this.points[0].size + " />"; | |
| }, | |
| draw: function(ctx) { | |
| return this.drawPoints(ctx, this.smoothedPoints); | |
| }, | |
| drawLatest: function(ctx, bufferCtx) { | |
| var drawEnd, drawStart, segmentStart; | |
| this.drawPoints(ctx, this.tail ? this.tail : this.smoothedPoints); | |
| if (this.tail) { | |
| segmentStart = this.smoothedPoints.length - this.segmentSize * this.tailSize; | |
| drawStart = segmentStart < this.segmentSize * 2 ? 0 : segmentStart; | |
| drawEnd = segmentStart + this.segmentSize + 1; | |
| return this.drawPoints(bufferCtx, this.smoothedPoints.slice(drawStart, drawEnd)); | |
| } | |
| }, | |
| addPoint: function(point) { | |
| this.points.push(point); | |
| if (!this.smooth) { | |
| return this.smoothedPoints = this.points; | |
| } | |
| if (!this.smoothedPoints || this.points.length < this.sampleSize) { | |
| return this.smoothedPoints = bspline(this.points, this.order); | |
| } else { | |
| this.tail = util.last(bspline(util.last(this.points, this.sampleSize), this.order), this.segmentSize * this.tailSize); | |
| return this.smoothedPoints = this.smoothedPoints.slice(0, this.smoothedPoints.length - this.segmentSize * (this.tailSize - 1)).concat(this.tail); | |
| } | |
| }, | |
| drawPoints: function(ctx, points) { | |
| var point, _i, _len, _ref; | |
| if (!points.length) { | |
| return; | |
| } | |
| ctx.lineCap = 'round'; | |
| ctx.strokeStyle = points[0].color; | |
| ctx.lineWidth = points[0].size; | |
| ctx.beginPath(); | |
| ctx.moveTo(points[0].x, points[0].y); | |
| _ref = points.slice(1); | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| point = _ref[_i]; | |
| ctx.lineTo(point.x, point.y); | |
| } | |
| return ctx.stroke(); | |
| } | |
| }; | |
| LinePath = defineShape('LinePath', linePathFuncs); | |
| defineShape('ErasedLinePath', { | |
| constructor: linePathFuncs.constructor, | |
| toJSON: linePathFuncs.toJSON, | |
| addPoint: linePathFuncs.addPoint, | |
| drawPoints: linePathFuncs.drawPoints, | |
| getBoundingRect: linePathFuncs.getBoundingRect, | |
| draw: function(ctx) { | |
| ctx.save(); | |
| ctx.globalCompositeOperation = "destination-out"; | |
| linePathFuncs.draw.call(this, ctx); | |
| return ctx.restore(); | |
| }, | |
| drawLatest: function(ctx, bufferCtx) { | |
| ctx.save(); | |
| ctx.globalCompositeOperation = "destination-out"; | |
| bufferCtx.save(); | |
| bufferCtx.globalCompositeOperation = "destination-out"; | |
| linePathFuncs.drawLatest.call(this, ctx, bufferCtx); | |
| ctx.restore(); | |
| return bufferCtx.restore(); | |
| }, | |
| fromJSON: function(data) { | |
| return _createLinePathFromData('ErasedLinePath', data); | |
| } | |
| }); | |
| defineShape('Point', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| this.size = args.size || 0; | |
| return this.color = args.color || ''; | |
| }, | |
| lastPoint: function() { | |
| return this; | |
| }, | |
| draw: function(ctx) { | |
| throw "not implemented"; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| size: this.size, | |
| color: this.color | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Point', data); | |
| } | |
| }); | |
| defineShape('Text', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| this.text = args.text || ''; | |
| this.color = args.color || 'black'; | |
| return this.font = args.font || '18px sans-serif'; | |
| }, | |
| draw: function(ctx) { | |
| ctx.font = this.font; | |
| ctx.fillStyle = this.color; | |
| ctx.fillText(this.text, this.x, this.y); | |
| return this.boundingBoxWidth = Math.ceil(ctx.measureText(this.text).width); | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| width: this.boundingBoxWidth, | |
| height: 18 | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| text: this.text, | |
| color: this.color, | |
| font: this.font | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Text', data); | |
| } | |
| }); | |
| module.exports = { | |
| defineShape: defineShape, | |
| createShape: createShape, | |
| JSONToShape: JSONToShape, | |
| shapeToJSON: shapeToJSON | |
| }; | |
| },{"../core/lineEndCapShapes.coffee":5,"./util":9}],9:[function(_dereq_,module,exports){ | |
| var slice, util, | |
| __slice = [].slice; | |
| slice = Array.prototype.slice; | |
| util = { | |
| last: function(array, n) { | |
| if (n == null) { | |
| n = null; | |
| } | |
| if (n) { | |
| return slice.call(array, Math.max(array.length - n, 0)); | |
| } else { | |
| return array[array.length - 1]; | |
| } | |
| }, | |
| matchElementSize: function(elementToMatch, elementsToResize, scale, callback) { | |
| var resize; | |
| if (callback == null) { | |
| callback = function() {}; | |
| } | |
| resize = (function(_this) { | |
| return function() { | |
| var el, _i, _len; | |
| for (_i = 0, _len = elementsToResize.length; _i < _len; _i++) { | |
| el = elementsToResize[_i]; | |
| el.style.width = "" + elementToMatch.offsetWidth + "px"; | |
| el.style.height = "" + elementToMatch.offsetHeight + "px"; | |
| if (el.width != null) { | |
| el.setAttribute('width', el.offsetWidth * scale); | |
| el.setAttribute('height', el.offsetHeight * scale); | |
| } | |
| } | |
| return callback(); | |
| }; | |
| })(this); | |
| elementToMatch.addEventListener('resize', resize); | |
| window.addEventListener('resize', resize); | |
| window.addEventListener('orientationchange', resize); | |
| return resize(); | |
| }, | |
| combineCanvases: function() { | |
| var c, canvas, canvases, ctx, _i, _j, _len, _len1; | |
| canvases = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | |
| c = document.createElement('canvas'); | |
| c.width = canvases[0].width; | |
| c.height = canvases[0].height; | |
| for (_i = 0, _len = canvases.length; _i < _len; _i++) { | |
| canvas = canvases[_i]; | |
| c.width = Math.max(canvas.width, c.width); | |
| c.height = Math.max(canvas.height, c.height); | |
| } | |
| ctx = c.getContext('2d'); | |
| for (_j = 0, _len1 = canvases.length; _j < _len1; _j++) { | |
| canvas = canvases[_j]; | |
| ctx.drawImage(canvas, 0, 0); | |
| ctx.drawImage(canvas, 0, 0); | |
| } | |
| return c; | |
| }, | |
| renderShapes: function(shapes, bounds, scale, canvas) { | |
| var ctx, shape, _i, _len; | |
| if (scale == null) { | |
| scale = 1; | |
| } | |
| if (canvas == null) { | |
| canvas = null; | |
| } | |
| canvas = canvas || document.createElement('canvas'); | |
| canvas.width = bounds.width * scale; | |
| canvas.height = bounds.height * scale; | |
| ctx = canvas.getContext('2d'); | |
| ctx.translate(-bounds.x * scale, -bounds.y * scale); | |
| ctx.scale(scale, scale); | |
| for (_i = 0, _len = shapes.length; _i < _len; _i++) { | |
| shape = shapes[_i]; | |
| shape.draw(ctx); | |
| } | |
| return canvas; | |
| }, | |
| getBoundingRect: function(rects, width, height) { | |
| var maxX, maxY, minX, minY, rect, _i, _len; | |
| if (!rects.length) { | |
| return { | |
| x: 0, | |
| y: 0, | |
| width: 0 || width, | |
| height: 0 || height | |
| }; | |
| } | |
| minX = rects[0].x; | |
| minY = rects[0].y; | |
| maxX = rects[0].x + rects[0].width; | |
| maxY = rects[0].y + rects[0].height; | |
| for (_i = 0, _len = rects.length; _i < _len; _i++) { | |
| rect = rects[_i]; | |
| minX = Math.floor(Math.min(rect.x, minX)); | |
| minY = Math.floor(Math.min(rect.y, minY)); | |
| maxX = Math.ceil(Math.max(maxX, rect.x + rect.width)); | |
| maxY = Math.ceil(Math.max(maxY, rect.y + rect.height)); | |
| } | |
| minX = width ? 0 : minX; | |
| minY = height ? 0 : minY; | |
| maxX = width || maxX; | |
| maxY = height || maxY; | |
| return { | |
| x: minX, | |
| y: minY, | |
| width: maxX - minX, | |
| height: maxY - minY | |
| }; | |
| }, | |
| getBackingScale: function(context) { | |
| if (window.devicePixelRatio == null) { | |
| return 1; | |
| } | |
| if (!(window.devicePixelRatio > 1)) { | |
| return 1; | |
| } | |
| return window.devicePixelRatio; | |
| }, | |
| requestAnimationFrame: (window.requestAnimationFrame || window.setTimeout).bind(window), | |
| getGUID: (function() { | |
| var s4; | |
| s4 = function() { | |
| return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); | |
| }; | |
| return function() { | |
| return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); | |
| }; | |
| })() | |
| }; | |
| module.exports = util; | |
| },{}],10:[function(_dereq_,module,exports){ | |
| var LiterallyCanvas, baseTools, defaultImageURLPrefix, defineOptionsStyle, init, initReact, localize, registerJQueryPlugin, setDefaultImageURLPrefix, shapes, tools, util; | |
| LiterallyCanvas = _dereq_('./core/LiterallyCanvas'); | |
| initReact = _dereq_('./reactGUI/init'); | |
| shapes = _dereq_('./core/shapes'); | |
| util = _dereq_('./core/util'); | |
| localize = _dereq_('./core/localization').localize; | |
| _dereq_('./optionsStyles/font'); | |
| _dereq_('./optionsStyles/stroke-width'); | |
| _dereq_('./optionsStyles/line-options-and-stroke-width'); | |
| _dereq_('./optionsStyles/null'); | |
| defineOptionsStyle = _dereq_('./optionsStyles/optionsStyles').defineOptionsStyle; | |
| baseTools = _dereq_('./tools/base'); | |
| tools = { | |
| Pencil: _dereq_('./tools/Pencil'), | |
| Eraser: _dereq_('./tools/Eraser'), | |
| Line: _dereq_('./tools/Line'), | |
| Rectangle: _dereq_('./tools/Rectangle'), | |
| Ellipse: _dereq_('./tools/Ellipse'), | |
| Text: _dereq_('./tools/Text'), | |
| Pan: _dereq_('./tools/Pan'), | |
| Eyedropper: _dereq_('./tools/Eyedropper'), | |
| Tool: baseTools.Tool, | |
| ToolWithStroke: baseTools.ToolWithStroke | |
| }; | |
| defaultImageURLPrefix = 'lib/img'; | |
| setDefaultImageURLPrefix = function(newDefault) { | |
| return defaultImageURLPrefix = newDefault; | |
| }; | |
| init = function(el, opts) { | |
| var child, drawingViewElement, lc, optionsElement, pickerElement, _i, _len, _ref; | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.imageURLPrefix == null) { | |
| opts.imageURLPrefix = defaultImageURLPrefix; | |
| } | |
| if (opts.primaryColor == null) { | |
| opts.primaryColor = '#000'; | |
| } | |
| if (opts.secondaryColor == null) { | |
| opts.secondaryColor = '#fff'; | |
| } | |
| if (opts.backgroundColor == null) { | |
| opts.backgroundColor = 'transparent'; | |
| } | |
| if (opts.keyboardShortcuts == null) { | |
| opts.keyboardShortcuts = true; | |
| } | |
| if (opts.imageSize == null) { | |
| opts.imageSize = { | |
| width: 'infinite', | |
| height: 'infinite' | |
| }; | |
| } | |
| if (opts.backgroundShapes == null) { | |
| opts.backgroundShapes = []; | |
| } | |
| if (opts.watermarkImage == null) { | |
| opts.watermarkImage = null; | |
| } | |
| if (opts.watermarkScale == null) { | |
| opts.watermarkScale = 1; | |
| } | |
| if (!('tools' in opts)) { | |
| opts.tools = [tools.Pencil, tools.Eraser, tools.Line, tools.Rectangle, tools.Ellipse, tools.Text, tools.Pan, tools.Eyedropper]; | |
| } | |
| /* henceforth, all pre-existing DOM children shall be destroyed */ | |
| _ref = el.children; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| child = _ref[_i]; | |
| el.removeChild(child); | |
| } | |
| /* and now we rebuild the city */ | |
| if ([' ', ' '].join(el.className).indexOf(' literally ') === -1) { | |
| el.className = el.className + ' literally'; | |
| } | |
| pickerElement = document.createElement('div'); | |
| pickerElement.className = 'lc-picker'; | |
| drawingViewElement = document.createElement('div'); | |
| drawingViewElement.className = 'lc-drawing'; | |
| optionsElement = document.createElement('div'); | |
| optionsElement.className = 'lc-options'; | |
| el.appendChild(pickerElement); | |
| el.appendChild(drawingViewElement); | |
| el.appendChild(optionsElement); | |
| /* and get to work */ | |
| lc = new LiterallyCanvas(drawingViewElement, opts); | |
| initReact(pickerElement, optionsElement, lc, opts.tools, opts.imageURLPrefix); | |
| if ('onInit' in opts) { | |
| opts.onInit(lc); | |
| } | |
| return lc; | |
| }; | |
| registerJQueryPlugin = function(_$) { | |
| return _$.fn.literallycanvas = function(opts) { | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| this.each((function(_this) { | |
| return function(ix, el) { | |
| return el.literallycanvas = init(el, opts); | |
| }; | |
| })(this)); | |
| return this; | |
| }; | |
| }; | |
| window.LC = { | |
| init: init | |
| }; | |
| if (window.$) { | |
| registerJQueryPlugin(window.$); | |
| } | |
| module.exports = { | |
| init: init, | |
| registerJQueryPlugin: registerJQueryPlugin, | |
| util: util, | |
| tools: tools, | |
| defineOptionsStyle: defineOptionsStyle, | |
| setDefaultImageURLPrefix: setDefaultImageURLPrefix, | |
| defineShape: shapes.defineShape, | |
| createShape: shapes.createShape, | |
| JSONToShape: shapes.JSONToShape, | |
| shapeToJSON: shapes.shapeToJSON, | |
| localize: localize | |
| }; | |
| },{"./core/LiterallyCanvas":2,"./core/localization":6,"./core/shapes":8,"./core/util":9,"./optionsStyles/font":11,"./optionsStyles/line-options-and-stroke-width":12,"./optionsStyles/null":13,"./optionsStyles/optionsStyles":14,"./optionsStyles/stroke-width":15,"./reactGUI/init":26,"./tools/Ellipse":27,"./tools/Eraser":28,"./tools/Eyedropper":29,"./tools/Line":30,"./tools/Pan":31,"./tools/Pencil":32,"./tools/Rectangle":33,"./tools/Text":34,"./tools/base":35}],11:[function(_dereq_,module,exports){ | |
| var defineOptionsStyle, _; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| _ = _dereq_('../core/localization')._; | |
| defineOptionsStyle('font', React.createClass({ | |
| displayName: 'FontOptions', | |
| getText: function() { | |
| var _ref; | |
| return (_ref = this.props.lc.tool) != null ? _ref.text : void 0; | |
| }, | |
| getInitialState: function() { | |
| return { | |
| text: this.getText(), | |
| isItalic: false, | |
| isBold: false, | |
| fontFamilyIndex: 0, | |
| fontSizeIndex: 4 | |
| }; | |
| }, | |
| getFontSizes: function() { | |
| return [9, 10, 12, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288]; | |
| }, | |
| getFamilies: function() { | |
| var lc; | |
| lc = this.props.lc; | |
| return [ | |
| { | |
| name: _('Sans-serif'), | |
| value: '"Helvetica Neue",Helvetica,Arial,sans-serif' | |
| }, { | |
| name: _('Serif'), | |
| value: ('Garamond,Baskerville,"Baskerville Old Face",', '"Hoefler Text","Times New Roman",serif') | |
| }, { | |
| name: _('Typewriter'), | |
| value: ('"Courier New",Courier,"Lucida Sans Typewriter",', '"Lucida Typewriter",monospace') | |
| } | |
| ]; | |
| }, | |
| updateTool: function(newState) { | |
| var fontSize, items, k; | |
| if (newState == null) { | |
| newState = {}; | |
| } | |
| for (k in this.state) { | |
| if (!(k in newState)) { | |
| newState[k] = this.state[k]; | |
| } | |
| } | |
| fontSize = this.getFontSizes()[newState.fontSizeIndex]; | |
| items = []; | |
| if (newState.isItalic) { | |
| items.push('italic'); | |
| } | |
| if (newState.isBold) { | |
| items.push('bold'); | |
| } | |
| items.push("" + fontSize + "px"); | |
| items.push(this.getFamilies()[newState.fontFamilyIndex].value); | |
| return this.props.lc.tool.font = items.join(' '); | |
| }, | |
| handleText: function(event) { | |
| this.props.lc.tool.text = event.target.value; | |
| return this.setState({ | |
| text: this.getText() | |
| }); | |
| }, | |
| handleFontSize: function(event) { | |
| var newState; | |
| newState = { | |
| fontSizeIndex: event.target.value | |
| }; | |
| this.setState(newState); | |
| return this.updateTool(newState); | |
| }, | |
| handleFontFamily: function(event) { | |
| var newState; | |
| newState = { | |
| fontFamilyIndex: event.target.value | |
| }; | |
| this.setState(newState); | |
| return this.updateTool(newState); | |
| }, | |
| handleItalic: function(event) { | |
| var newState; | |
| newState = { | |
| isItalic: !this.state.isItalic | |
| }; | |
| this.setState(newState); | |
| return this.updateTool(newState); | |
| }, | |
| handleBold: function(event) { | |
| var newState; | |
| newState = { | |
| isBold: !this.state.isBold | |
| }; | |
| this.setState(newState); | |
| return this.updateTool(newState); | |
| }, | |
| componentDidMount: function() { | |
| return this.updateTool(); | |
| }, | |
| render: function() { | |
| var br, div, input, label, lc, option, select, span, _ref; | |
| lc = this.props.lc; | |
| _ref = React.DOM, div = _ref.div, input = _ref.input, select = _ref.select, option = _ref.option, br = _ref.br, label = _ref.label, span = _ref.span; | |
| return div({ | |
| className: 'lc-font-settings' | |
| }, input({ | |
| type: 'text', | |
| placeholder: _('Enter text here'), | |
| value: this.state.text, | |
| onChange: this.handleText | |
| }), span({ | |
| className: 'instructions' | |
| }, _("Click and hold to place text.")), br(), _("Size: "), select({ | |
| value: this.state.fontSizeIndex, | |
| onChange: this.handleFontSize | |
| }, this.getFontSizes().map((function(_this) { | |
| return function(size, ix) { | |
| return option({ | |
| value: ix, | |
| key: ix | |
| }, size); | |
| }; | |
| })(this))), select({ | |
| value: this.state.fontFamilyIndex, | |
| onChange: this.handleFontFamily | |
| }, this.getFamilies().map((function(_this) { | |
| return function(family, ix) { | |
| return option({ | |
| value: ix, | |
| key: ix | |
| }, family.name); | |
| }; | |
| })(this))), label({ | |
| htmlFor: 'italic' | |
| }, input({ | |
| type: 'checkbox', | |
| id: 'italic', | |
| checked: this.state.isItalic, | |
| onChange: this.handleItalic | |
| }, _("italic"))), label({ | |
| htmlFor: 'bold' | |
| }, input({ | |
| type: 'checkbox', | |
| id: 'bold', | |
| checked: this.state.isBold, | |
| onChange: this.handleBold | |
| }, _("bold")))); | |
| } | |
| })); | |
| module.exports = {}; | |
| },{"../core/localization":6,"./optionsStyles":14}],12:[function(_dereq_,module,exports){ | |
| var StrokeWidthPicker, createSetStateOnEventMixin, defineOptionsStyle; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| StrokeWidthPicker = _dereq_('../reactGUI/StrokeWidthPicker'); | |
| createSetStateOnEventMixin = _dereq_('../reactGUI/createSetStateOnEventMixin'); | |
| defineOptionsStyle('line-options-and-stroke-width', React.createClass({ | |
| displayName: 'LineOptionsAndStrokeWidth', | |
| getState: function() { | |
| return { | |
| strokeWidth: this.props.tool.strokeWidth, | |
| isDashed: this.props.tool.isDashed, | |
| hasEndArrow: this.props.tool.hasEndArrow | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('toolChange')], | |
| render: function() { | |
| var arrowButtonClass, dashButtonClass, div, img, li, toggleIsDashed, togglehasEndArrow, ul, _ref; | |
| _ref = React.DOM, div = _ref.div, ul = _ref.ul, li = _ref.li, img = _ref.img; | |
| toggleIsDashed = (function(_this) { | |
| return function() { | |
| _this.props.tool.isDashed = !_this.props.tool.isDashed; | |
| return _this.setState(_this.getState()); | |
| }; | |
| })(this); | |
| togglehasEndArrow = (function(_this) { | |
| return function() { | |
| _this.props.tool.hasEndArrow = !_this.props.tool.hasEndArrow; | |
| return _this.setState(_this.getState()); | |
| }; | |
| })(this); | |
| dashButtonClass = React.addons.classSet({ | |
| 'basic-button square-button': true, | |
| 'selected': this.state.isDashed | |
| }); | |
| arrowButtonClass = React.addons.classSet({ | |
| 'basic-button square-button': true, | |
| 'selected': this.state.hasEndArrow | |
| }); | |
| return div({}, ul({ | |
| className: 'button-row', | |
| style: { | |
| float: 'left', | |
| marginRight: 20 | |
| } | |
| }, li({}, div({ | |
| className: dashButtonClass, | |
| onClick: toggleIsDashed | |
| }, img({ | |
| src: "" + this.props.imageURLPrefix + "/dashed-line.png" | |
| }))), li({}, div({ | |
| className: arrowButtonClass, | |
| onClick: togglehasEndArrow | |
| }, img({ | |
| src: "" + this.props.imageURLPrefix + "/line-with-arrow.png" | |
| })))), StrokeWidthPicker({ | |
| tool: this.props.tool, | |
| lc: this.props.lc | |
| })); | |
| } | |
| })); | |
| module.exports = {}; | |
| },{"../reactGUI/StrokeWidthPicker":21,"../reactGUI/createSetStateOnEventMixin":24,"./optionsStyles":14}],13:[function(_dereq_,module,exports){ | |
| var defineOptionsStyle; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| defineOptionsStyle('null', React.createClass({ | |
| displayName: 'NoOptions', | |
| render: function() { | |
| return React.DOM.div(); | |
| } | |
| })); | |
| module.exports = {}; | |
| },{"./optionsStyles":14}],14:[function(_dereq_,module,exports){ | |
| var defineOptionsStyle, optionsStyles; | |
| optionsStyles = {}; | |
| defineOptionsStyle = function(name, style) { | |
| return optionsStyles[name] = style; | |
| }; | |
| module.exports = { | |
| optionsStyles: optionsStyles, | |
| defineOptionsStyle: defineOptionsStyle | |
| }; | |
| },{}],15:[function(_dereq_,module,exports){ | |
| var StrokeWidthPicker, defineOptionsStyle; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| StrokeWidthPicker = _dereq_('../reactGUI/StrokeWidthPicker'); | |
| defineOptionsStyle('stroke-width', StrokeWidthPicker); | |
| module.exports = {}; | |
| },{"../reactGUI/StrokeWidthPicker":21,"./optionsStyles":14}],16:[function(_dereq_,module,exports){ | |
| var ClearButton, React, createSetStateOnEventMixin, _; | |
| React = _dereq_('./React-shim'); | |
| createSetStateOnEventMixin = _dereq_('./createSetStateOnEventMixin'); | |
| _ = _dereq_('../core/localization')._; | |
| ClearButton = React.createClass({ | |
| displayName: 'ClearButton', | |
| getState: function() { | |
| return { | |
| isEnabled: this.props.lc.canUndo() | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('drawingChange')], | |
| render: function() { | |
| var className, div, lc, onClick; | |
| div = React.DOM.div; | |
| lc = this.props.lc; | |
| className = React.addons.classSet({ | |
| 'lc-clear': true, | |
| 'toolbar-button': true, | |
| 'fat-button': true, | |
| 'disabled': !this.state.isEnabled | |
| }); | |
| onClick = lc.canUndo() ? ((function(_this) { | |
| return function() { | |
| return lc.clear(); | |
| }; | |
| })(this)) : function() {}; | |
| return div({ | |
| className: className, | |
| onClick: onClick | |
| }, _('Clear')); | |
| } | |
| }); | |
| module.exports = ClearButton; | |
| },{"../core/localization":6,"./React-shim":20,"./createSetStateOnEventMixin":24}],17:[function(_dereq_,module,exports){ | |
| var ColorWell, React; | |
| React = _dereq_('./React-shim'); | |
| ColorWell = React.createClass({ | |
| displayName: 'ColorWell', | |
| getState: function() { | |
| return { | |
| color: this.props.lc.colors[this.props.colorName], | |
| isPickerVisible: false | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| componentDidMount: function() { | |
| return this.unsubscribe = this.props.lc.on("" + this.props.colorName + "ColorChange", (function(_this) { | |
| return function() { | |
| return _this.setState({ | |
| color: _this.props.lc.colors[_this.props.colorName] | |
| }); | |
| }; | |
| })(this)); | |
| }, | |
| componentWillUnmount: function() { | |
| return this.unsubscribe(); | |
| }, | |
| togglePicker: function() { | |
| return this.setState({ | |
| isPickerVisible: !this.state.isPickerVisible | |
| }); | |
| }, | |
| closePicker: function() { | |
| return this.setState({ | |
| isPickerVisible: false | |
| }); | |
| }, | |
| setColor: function(c) { | |
| return this.props.lc.setColor(this.props.colorName, c); | |
| }, | |
| render: function() { | |
| var div, label, _ref; | |
| _ref = React.DOM, div = _ref.div, label = _ref.label; | |
| return div({ | |
| className: 'toolbar-button color-well-label', | |
| onMouseLeave: this.closePicker, | |
| onClick: this.togglePicker | |
| }, label({ | |
| style: { | |
| display: 'block', | |
| clear: 'both' | |
| } | |
| }, this.props.label), div({ | |
| className: React.addons.classSet({ | |
| 'color-well-container': true, | |
| 'selected': this.state.isPickerVisible | |
| }), | |
| style: { | |
| backgroundColor: 'white' | |
| } | |
| }, div({ | |
| className: 'color-well-checker' | |
| }), div({ | |
| className: 'color-well-checker', | |
| style: { | |
| left: '50%', | |
| top: '50%' | |
| } | |
| }), div({ | |
| className: 'color-well-color', | |
| style: { | |
| backgroundColor: this.state.color | |
| } | |
| }, " "), this.renderPicker())); | |
| }, | |
| renderPicker: function() { | |
| var div, hue, i, renderTransparentCell, rows, _i, _len, _ref; | |
| div = React.DOM.div; | |
| if (!this.state.isPickerVisible) { | |
| return null; | |
| } | |
| renderTransparentCell = (function(_this) { | |
| return function() { | |
| return div({ | |
| className: 'color-row', | |
| key: 0, | |
| style: { | |
| height: 20 | |
| } | |
| }, div({ | |
| className: React.addons.classSet({ | |
| 'color-cell transparent-cell': true, | |
| 'selected': _this.state.color === 'transparent' | |
| }), | |
| onClick: function() { | |
| return _this.setColor('transparent'); | |
| } | |
| }, 'transparent')); | |
| }; | |
| })(this); | |
| rows = []; | |
| rows.push('transparent'); | |
| rows.push((function() { | |
| var _i, _results; | |
| _results = []; | |
| for (i = _i = 0; _i <= 100; i = _i += 10) { | |
| _results.push("hsl(0, 0%, " + i + "%)"); | |
| } | |
| return _results; | |
| })()); | |
| _ref = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| hue = _ref[_i]; | |
| rows.push((function() { | |
| var _j, _results; | |
| _results = []; | |
| for (i = _j = 10; _j <= 90; i = _j += 8) { | |
| _results.push("hsl(" + hue + ", 100%, " + i + "%)"); | |
| } | |
| return _results; | |
| })()); | |
| } | |
| return div({ | |
| className: 'color-picker-popup' | |
| }, rows.map((function(_this) { | |
| return function(row, ix) { | |
| if (row === 'transparent') { | |
| return renderTransparentCell(); | |
| } | |
| return div({ | |
| className: 'color-row', | |
| key: ix, | |
| style: { | |
| width: 20 * row.length | |
| } | |
| }, row.map(function(cellColor, ix2) { | |
| var className; | |
| className = React.addons.classSet({ | |
| 'color-cell': true, | |
| 'selected': _this.state.color === cellColor | |
| }); | |
| return div({ | |
| className: className, | |
| onClick: function() { | |
| return _this.setColor(cellColor); | |
| }, | |
| style: { | |
| backgroundColor: cellColor | |
| }, | |
| key: ix2 | |
| }); | |
| })); | |
| }; | |
| })(this))); | |
| } | |
| }); | |
| module.exports = ColorWell; | |
| },{"./React-shim":20}],18:[function(_dereq_,module,exports){ | |
| var Options, React, createSetStateOnEventMixin, optionsStyles; | |
| React = _dereq_('./React-shim'); | |
| createSetStateOnEventMixin = _dereq_('./createSetStateOnEventMixin'); | |
| optionsStyles = _dereq_('../optionsStyles/optionsStyles').optionsStyles; | |
| Options = React.createClass({ | |
| displayName: 'Options', | |
| getState: function() { | |
| var _ref; | |
| return { | |
| style: (_ref = this.props.lc.tool) != null ? _ref.optionsStyle : void 0, | |
| tool: this.props.lc.tool | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('toolChange')], | |
| render: function() { | |
| var style; | |
| style = "" + this.state.style; | |
| return optionsStyles[style]({ | |
| lc: this.props.lc, | |
| tool: this.state.tool, | |
| imageURLPrefix: this.props.imageURLPrefix | |
| }); | |
| } | |
| }); | |
| module.exports = Options; | |
| },{"../optionsStyles/optionsStyles":14,"./React-shim":20,"./createSetStateOnEventMixin":24}],19:[function(_dereq_,module,exports){ | |
| var ClearButton, ColorPickers, ColorWell, Picker, React, UndoRedoButtons, ZoomButtons, _; | |
| React = _dereq_('./React-shim'); | |
| ClearButton = _dereq_('./ClearButton'); | |
| ColorWell = _dereq_('./ColorWell'); | |
| UndoRedoButtons = _dereq_('./UndoRedoButtons'); | |
| ZoomButtons = _dereq_('./ZoomButtons'); | |
| _ = _dereq_('../core/localization')._; | |
| ColorPickers = React.createClass({ | |
| displayName: 'ColorPickers', | |
| render: function() { | |
| var div, lc; | |
| lc = this.props.lc; | |
| div = React.DOM.div; | |
| return div({ | |
| className: 'lc-color-pickers' | |
| }, ColorWell({ | |
| lc: lc, | |
| colorName: 'background', | |
| label: _('background') | |
| }), ColorWell({ | |
| lc: lc, | |
| colorName: 'primary', | |
| label: _('stroke') | |
| }), ColorWell({ | |
| lc: lc, | |
| colorName: 'secondary', | |
| label: _('fill') | |
| })); | |
| } | |
| }); | |
| Picker = React.createClass({ | |
| displayName: 'Picker', | |
| getInitialState: function() { | |
| return { | |
| selectedToolIndex: 0 | |
| }; | |
| }, | |
| render: function() { | |
| var div, imageURLPrefix, lc, toolButtonComponents, _ref; | |
| div = React.DOM.div; | |
| _ref = this.props, toolButtonComponents = _ref.toolButtonComponents, lc = _ref.lc, imageURLPrefix = _ref.imageURLPrefix; | |
| return div({ | |
| className: 'lc-picker-contents' | |
| }, toolButtonComponents.map((function(_this) { | |
| return function(component, ix) { | |
| return component({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix, | |
| key: ix, | |
| isSelected: ix === _this.state.selectedToolIndex, | |
| onSelect: function(tool) { | |
| lc.setTool(tool); | |
| return _this.setState({ | |
| selectedToolIndex: ix | |
| }); | |
| } | |
| }); | |
| }; | |
| })(this)), toolButtonComponents.length % 2 !== 0 ? div({ | |
| className: 'toolbar-button thin-button disabled' | |
| }) : void 0, UndoRedoButtons({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), ZoomButtons({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), ClearButton({ | |
| lc: lc | |
| }), ColorPickers({ | |
| lc: lc | |
| })); | |
| } | |
| }); | |
| module.exports = Picker; | |
| },{"../core/localization":6,"./ClearButton":16,"./ColorWell":17,"./React-shim":20,"./UndoRedoButtons":22,"./ZoomButtons":23}],20:[function(_dereq_,module,exports){ | |
| var React; | |
| try { | |
| React = _dereq_('React/addons'); | |
| } catch (_error) { | |
| React = window.React; | |
| } | |
| if ((React != null ? React.addons : void 0) == null) { | |
| throw "Can't find React (you need the version with addons)"; | |
| } | |
| module.exports = React; | |
| },{}],21:[function(_dereq_,module,exports){ | |
| var createSetStateOnEventMixin; | |
| createSetStateOnEventMixin = _dereq_('../reactGUI/createSetStateOnEventMixin'); | |
| module.exports = React.createClass({ | |
| displayName: 'StrokeWidthPicker', | |
| getState: function() { | |
| return { | |
| strokeWidth: this.props.tool.strokeWidth | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('toolChange')], | |
| render: function() { | |
| var circle, div, getItem, li, strokeWidths, svg, ul, _ref; | |
| _ref = React.DOM, ul = _ref.ul, li = _ref.li, svg = _ref.svg, circle = _ref.circle, div = _ref.div; | |
| strokeWidths = [1, 2, 5, 10, 20, 30]; | |
| getItem = (function(_this) { | |
| return function(strokeWidth) {}; | |
| })(this); | |
| return ul({ | |
| className: 'button-row' | |
| }, strokeWidths.map((function(_this) { | |
| return function(strokeWidth, ix) { | |
| var buttonClassName, buttonSize; | |
| buttonClassName = React.addons.classSet({ | |
| 'basic-button': true, | |
| 'selected': strokeWidth === _this.state.strokeWidth | |
| }); | |
| buttonSize = 30; | |
| return li({ | |
| className: 'lc-stroke-width', | |
| key: strokeWidth | |
| }, div({ | |
| className: buttonClassName, | |
| onClick: function() { | |
| _this.props.tool.strokeWidth = strokeWidth; | |
| return _this.setState(_this.getState()); | |
| } | |
| }, svg({ | |
| width: buttonSize, | |
| height: buttonSize, | |
| viewPort: "0 0 " + strokeWidth + " " + strokeWidth, | |
| version: "1.1", | |
| xmlns: "http://www.w3.org/2000/svg" | |
| }, circle({ | |
| cx: Math.ceil(buttonSize / 2), | |
| cy: Math.ceil(buttonSize / 2), | |
| r: strokeWidth / 2 | |
| })))); | |
| }; | |
| })(this))); | |
| } | |
| }); | |
| },{"../reactGUI/createSetStateOnEventMixin":24}],22:[function(_dereq_,module,exports){ | |
| var React, RedoButton, UndoButton, UndoRedoButtons, createSetStateOnEventMixin, createUndoRedoButtonComponent; | |
| React = _dereq_('./React-shim'); | |
| createSetStateOnEventMixin = _dereq_('./createSetStateOnEventMixin'); | |
| createUndoRedoButtonComponent = function(undoOrRedo) { | |
| return React.createClass({ | |
| displayName: undoOrRedo === 'undo' ? 'UndoButton' : 'RedoButton', | |
| getState: function() { | |
| return { | |
| isEnabled: (function() { | |
| switch (false) { | |
| case undoOrRedo !== 'undo': | |
| return this.props.lc.canUndo(); | |
| case undoOrRedo !== 'redo': | |
| return this.props.lc.canRedo(); | |
| } | |
| }).call(this) | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('drawingChange')], | |
| render: function() { | |
| var className, div, imageURLPrefix, img, lc, onClick, title, _ref, _ref1; | |
| _ref = React.DOM, div = _ref.div, img = _ref.img; | |
| _ref1 = this.props, lc = _ref1.lc, imageURLPrefix = _ref1.imageURLPrefix; | |
| title = undoOrRedo === 'undo' ? 'Undo' : 'Redo'; | |
| className = ("lc-" + undoOrRedo + " ") + React.addons.classSet({ | |
| 'toolbar-button': true, | |
| 'thin-button': true, | |
| 'disabled': !this.state.isEnabled | |
| }); | |
| onClick = (function() { | |
| switch (false) { | |
| case !!this.state.isEnabled: | |
| return function() {}; | |
| case undoOrRedo !== 'undo': | |
| return function() { | |
| return lc.undo(); | |
| }; | |
| case undoOrRedo !== 'redo': | |
| return function() { | |
| return lc.redo(); | |
| }; | |
| } | |
| }).call(this); | |
| return div({ | |
| className: className, | |
| onClick: onClick, | |
| title: title | |
| }, img({ | |
| src: "" + imageURLPrefix + "/" + undoOrRedo + ".png" | |
| })); | |
| } | |
| }); | |
| }; | |
| UndoButton = createUndoRedoButtonComponent('undo'); | |
| RedoButton = createUndoRedoButtonComponent('redo'); | |
| UndoRedoButtons = React.createClass({ | |
| displayName: 'UndoRedoButtons', | |
| render: function() { | |
| var div; | |
| div = React.DOM.div; | |
| return div({ | |
| className: 'lc-undo-redo' | |
| }, UndoButton(this.props), RedoButton(this.props)); | |
| } | |
| }); | |
| module.exports = UndoRedoButtons; | |
| },{"./React-shim":20,"./createSetStateOnEventMixin":24}],23:[function(_dereq_,module,exports){ | |
| var React, ZoomButtons, ZoomInButton, ZoomOutButton, createSetStateOnEventMixin, createZoomButtonComponent; | |
| React = _dereq_('./React-shim'); | |
| createSetStateOnEventMixin = _dereq_('./createSetStateOnEventMixin'); | |
| createZoomButtonComponent = function(inOrOut) { | |
| return React.createClass({ | |
| displayName: inOrOut === 'in' ? 'ZoomInButton' : 'ZoomOutButton', | |
| getState: function() { | |
| return { | |
| isEnabled: (function() { | |
| switch (false) { | |
| case inOrOut !== 'in': | |
| return this.props.lc.scale < 4.0; | |
| case inOrOut !== 'out': | |
| return this.props.lc.scale > 0.6; | |
| } | |
| }).call(this) | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('zoom')], | |
| render: function() { | |
| var className, div, imageURLPrefix, img, lc, onClick, title, _ref, _ref1; | |
| _ref = React.DOM, div = _ref.div, img = _ref.img; | |
| _ref1 = this.props, lc = _ref1.lc, imageURLPrefix = _ref1.imageURLPrefix; | |
| title = inOrOut === 'in' ? 'Zoom in' : 'Zoom out'; | |
| className = ("lc-zoom-" + inOrOut + " ") + React.addons.classSet({ | |
| 'toolbar-button': true, | |
| 'thin-button': true, | |
| 'disabled': !this.state.isEnabled | |
| }); | |
| onClick = (function() { | |
| switch (false) { | |
| case !!this.state.isEnabled: | |
| return function() {}; | |
| case inOrOut !== 'in': | |
| return function() { | |
| return lc.zoom(0.2); | |
| }; | |
| case inOrOut !== 'out': | |
| return function() { | |
| return lc.zoom(-0.2); | |
| }; | |
| } | |
| }).call(this); | |
| return div({ | |
| className: className, | |
| onClick: onClick, | |
| title: title | |
| }, img({ | |
| src: "" + imageURLPrefix + "/zoom-" + inOrOut + ".png" | |
| })); | |
| } | |
| }); | |
| }; | |
| ZoomOutButton = createZoomButtonComponent('out'); | |
| ZoomInButton = createZoomButtonComponent('in'); | |
| ZoomButtons = React.createClass({ | |
| displayName: 'ZoomButtons', | |
| render: function() { | |
| var div; | |
| div = React.DOM.div; | |
| return div({ | |
| className: 'lc-zoom' | |
| }, ZoomOutButton(this.props), ZoomInButton(this.props)); | |
| } | |
| }); | |
| module.exports = ZoomButtons; | |
| },{"./React-shim":20,"./createSetStateOnEventMixin":24}],24:[function(_dereq_,module,exports){ | |
| var React, createSetStateOnEventMixin; | |
| React = _dereq_('./React-shim'); | |
| module.exports = createSetStateOnEventMixin = function(eventName) { | |
| return { | |
| componentDidMount: function() { | |
| return this.unsubscribe = this.props.lc.on(eventName, (function(_this) { | |
| return function() { | |
| return _this.setState(_this.getState()); | |
| }; | |
| })(this)); | |
| }, | |
| componentWillUnmount: function() { | |
| return this.unsubscribe(); | |
| } | |
| }; | |
| }; | |
| },{"./React-shim":20}],25:[function(_dereq_,module,exports){ | |
| var React, createToolButton; | |
| React = _dereq_('./React-shim'); | |
| createToolButton = function(_arg) { | |
| var displayName, getTool, imageName, tool; | |
| displayName = _arg.displayName, getTool = _arg.getTool, imageName = _arg.imageName; | |
| tool = getTool(); | |
| return React.createClass({ | |
| displayName: displayName, | |
| getDefaultProps: function() { | |
| return { | |
| isSelected: false, | |
| lc: null | |
| }; | |
| }, | |
| componentWillMount: function() { | |
| if (this.props.isSelected) { | |
| return this.props.lc.setTool(tool); | |
| } | |
| }, | |
| render: function() { | |
| var className, div, imageURLPrefix, img, isSelected, onSelect, _ref, _ref1; | |
| _ref = React.DOM, div = _ref.div, img = _ref.img; | |
| _ref1 = this.props, imageURLPrefix = _ref1.imageURLPrefix, isSelected = _ref1.isSelected, onSelect = _ref1.onSelect; | |
| className = React.addons.classSet({ | |
| 'lc-pick-tool': true, | |
| 'toolbar-button': true, | |
| 'thin-button': true, | |
| 'selected': isSelected | |
| }); | |
| return div({ | |
| className: className, | |
| onClick: (function() { | |
| return onSelect(tool); | |
| }), | |
| title: displayName | |
| }, img({ | |
| className: 'lc-tool-icon', | |
| src: "" + imageURLPrefix + "/" + imageName + ".png" | |
| })); | |
| } | |
| }); | |
| }; | |
| module.exports = createToolButton; | |
| },{"./React-shim":20}],26:[function(_dereq_,module,exports){ | |
| var Options, Picker, React, createToolButton, init; | |
| React = _dereq_('./React-shim'); | |
| createToolButton = _dereq_('./createToolButton'); | |
| Options = _dereq_('./Options'); | |
| Picker = _dereq_('./Picker'); | |
| init = function(pickerElement, optionsElement, lc, tools, imageURLPrefix) { | |
| var toolButtonComponents; | |
| toolButtonComponents = tools.map(function(ToolClass) { | |
| var toolInstance; | |
| toolInstance = new ToolClass(); | |
| return createToolButton({ | |
| displayName: toolInstance.name, | |
| imageName: toolInstance.iconName, | |
| getTool: function() { | |
| return toolInstance; | |
| } | |
| }); | |
| }); | |
| React.renderComponent(Picker({ | |
| lc: lc, | |
| toolButtonComponents: toolButtonComponents, | |
| imageURLPrefix: imageURLPrefix | |
| }), pickerElement); | |
| return React.renderComponent(Options({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), optionsElement); | |
| }; | |
| module.exports = init; | |
| },{"./Options":18,"./Picker":19,"./React-shim":20,"./createToolButton":25}],27:[function(_dereq_,module,exports){ | |
| var Ellipse, ToolWithStroke, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| ToolWithStroke = _dereq_('./base').ToolWithStroke; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Ellipse = (function(_super) { | |
| __extends(Ellipse, _super); | |
| function Ellipse() { | |
| return Ellipse.__super__.constructor.apply(this, arguments); | |
| } | |
| Ellipse.prototype.name = 'Ellipse'; | |
| Ellipse.prototype.iconName = 'ellipse'; | |
| Ellipse.prototype.begin = function(x, y, lc) { | |
| return this.currentShape = createShape('Ellipse', { | |
| x: x, | |
| y: y, | |
| strokeWidth: this.strokeWidth, | |
| strokeColor: lc.getColor('primary'), | |
| fillColor: lc.getColor('secondary') | |
| }); | |
| }; | |
| Ellipse.prototype["continue"] = function(x, y, lc) { | |
| this.currentShape.width = x - this.currentShape.x; | |
| this.currentShape.height = y - this.currentShape.y; | |
| return lc.drawShapeInProgress(this.currentShape); | |
| }; | |
| Ellipse.prototype.end = function(x, y, lc) { | |
| return lc.saveShape(this.currentShape); | |
| }; | |
| return Ellipse; | |
| })(ToolWithStroke); | |
| },{"../core/shapes":8,"./base":35}],28:[function(_dereq_,module,exports){ | |
| var Eraser, Pencil, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| Pencil = _dereq_('./Pencil'); | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Eraser = (function(_super) { | |
| __extends(Eraser, _super); | |
| Eraser.prototype.name = 'Eraser'; | |
| Eraser.prototype.iconName = 'eraser'; | |
| function Eraser() { | |
| this.strokeWidth = 10; | |
| } | |
| Eraser.prototype.makePoint = function(x, y, lc) { | |
| return createShape('Point', { | |
| x: x, | |
| y: y, | |
| size: this.strokeWidth, | |
| color: '#000' | |
| }); | |
| }; | |
| Eraser.prototype.makeShape = function() { | |
| return createShape('ErasedLinePath'); | |
| }; | |
| return Eraser; | |
| })(Pencil); | |
| },{"../core/shapes":8,"./Pencil":32}],29:[function(_dereq_,module,exports){ | |
| var Eyedropper, Tool, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| Tool = _dereq_('./base').Tool; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Eyedropper = (function(_super) { | |
| __extends(Eyedropper, _super); | |
| function Eyedropper() { | |
| return Eyedropper.__super__.constructor.apply(this, arguments); | |
| } | |
| Eyedropper.prototype.name = 'Eyedropper'; | |
| Eyedropper.prototype.iconName = 'eyedropper'; | |
| Eyedropper.prototype.readColor = function(x, y, lc) { | |
| var newColor; | |
| newColor = lc.getPixel(x, y); | |
| return lc.setColor('primary', newColor || lc.getColor('background')); | |
| }; | |
| Eyedropper.prototype.begin = function(x, y, lc) { | |
| return this.readColor(x, y, lc); | |
| }; | |
| Eyedropper.prototype["continue"] = function(x, y, lc) { | |
| return this.readColor(x, y, lc); | |
| }; | |
| return Eyedropper; | |
| })(Tool); | |
| },{"../core/shapes":8,"./base":35}],30:[function(_dereq_,module,exports){ | |
| var Line, Tool, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| Tool = _dereq_('./base').Tool; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Line = (function(_super) { | |
| __extends(Line, _super); | |
| Line.prototype.name = 'Line'; | |
| Line.prototype.iconName = 'line'; | |
| function Line() { | |
| this.strokeWidth = 5; | |
| } | |
| Line.prototype.optionsStyle = 'line-options-and-stroke-width'; | |
| Line.prototype.begin = function(x, y, lc) { | |
| return this.currentShape = createShape('Line', { | |
| x1: x, | |
| y1: y, | |
| x2: x, | |
| y2: y, | |
| strokeWidth: this.strokeWidth, | |
| dash: (function() { | |
| switch (false) { | |
| case !this.isDashed: | |
| return [this.strokeWidth * 2, this.strokeWidth * 4]; | |
| default: | |
| return null; | |
| } | |
| }).call(this), | |
| endCapShapes: this.hasEndArrow ? [null, 'arrow'] : null, | |
| color: lc.getColor('primary') | |
| }); | |
| }; | |
| Line.prototype["continue"] = function(x, y, lc) { | |
| this.currentShape.x2 = x; | |
| this.currentShape.y2 = y; | |
| return lc.drawShapeInProgress(this.currentShape); | |
| }; | |
| Line.prototype.end = function(x, y, lc) { | |
| return lc.saveShape(this.currentShape); | |
| }; | |
| return Line; | |
| })(Tool); | |
| },{"../core/shapes":8,"./base":35}],31:[function(_dereq_,module,exports){ | |
| var Pan, Tool, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| Tool = _dereq_('./base').Tool; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Pan = (function(_super) { | |
| __extends(Pan, _super); | |
| function Pan() { | |
| return Pan.__super__.constructor.apply(this, arguments); | |
| } | |
| Pan.prototype.name = 'Pan'; | |
| Pan.prototype.iconName = 'pan'; | |
| Pan.prototype.begin = function(x, y, lc) { | |
| return this.start = { | |
| x: x, | |
| y: y | |
| }; | |
| }; | |
| Pan.prototype["continue"] = function(x, y, lc) { | |
| lc.pan(this.start.x - x, this.start.y - y); | |
| return lc.repaintAllLayers(); | |
| }; | |
| Pan.prototype.end = function(x, y, lc) { | |
| return lc.repaintAllLayers(); | |
| }; | |
| return Pan; | |
| })(Tool); | |
| },{"../core/shapes":8,"./base":35}],32:[function(_dereq_,module,exports){ | |
| var Pencil, ToolWithStroke, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| ToolWithStroke = _dereq_('./base').ToolWithStroke; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Pencil = (function(_super) { | |
| __extends(Pencil, _super); | |
| function Pencil() { | |
| return Pencil.__super__.constructor.apply(this, arguments); | |
| } | |
| Pencil.prototype.name = 'Pencil'; | |
| Pencil.prototype.iconName = 'pencil'; | |
| Pencil.prototype.eventTimeThreshold = 10; | |
| Pencil.prototype.begin = function(x, y, lc) { | |
| this.color = lc.getColor('primary'); | |
| this.currentShape = this.makeShape(); | |
| this.currentShape.addPoint(this.makePoint(x, y, lc)); | |
| return this.lastEventTime = Date.now(); | |
| }; | |
| Pencil.prototype["continue"] = function(x, y, lc) { | |
| var timeDiff; | |
| timeDiff = Date.now() - this.lastEventTime; | |
| if (timeDiff > this.eventTimeThreshold) { | |
| this.lastEventTime += timeDiff; | |
| this.currentShape.addPoint(this.makePoint(x, y, lc)); | |
| return lc.drawShapeInProgress(this.currentShape); | |
| } | |
| }; | |
| Pencil.prototype.end = function(x, y, lc) { | |
| lc.saveShape(this.currentShape); | |
| return this.currentShape = void 0; | |
| }; | |
| Pencil.prototype.makePoint = function(x, y, lc) { | |
| return createShape('Point', { | |
| x: x, | |
| y: y, | |
| size: this.strokeWidth, | |
| color: this.color | |
| }); | |
| }; | |
| Pencil.prototype.makeShape = function() { | |
| return createShape('LinePath'); | |
| }; | |
| return Pencil; | |
| })(ToolWithStroke); | |
| },{"../core/shapes":8,"./base":35}],33:[function(_dereq_,module,exports){ | |
| var Rectangle, ToolWithStroke, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| ToolWithStroke = _dereq_('./base').ToolWithStroke; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Rectangle = (function(_super) { | |
| __extends(Rectangle, _super); | |
| function Rectangle() { | |
| return Rectangle.__super__.constructor.apply(this, arguments); | |
| } | |
| Rectangle.prototype.name = 'Rectangle'; | |
| Rectangle.prototype.iconName = 'rectangle'; | |
| Rectangle.prototype.begin = function(x, y, lc) { | |
| return this.currentShape = createShape('Rectangle', { | |
| x: x, | |
| y: y, | |
| strokeWidth: this.strokeWidth, | |
| strokeColor: lc.getColor('primary'), | |
| fillColor: lc.getColor('secondary') | |
| }); | |
| }; | |
| Rectangle.prototype["continue"] = function(x, y, lc) { | |
| this.currentShape.width = x - this.currentShape.x; | |
| this.currentShape.height = y - this.currentShape.y; | |
| return lc.drawShapeInProgress(this.currentShape); | |
| }; | |
| Rectangle.prototype.end = function(x, y, lc) { | |
| return lc.saveShape(this.currentShape); | |
| }; | |
| return Rectangle; | |
| })(ToolWithStroke); | |
| },{"../core/shapes":8,"./base":35}],34:[function(_dereq_,module,exports){ | |
| var Text, Tool, createShape, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| Tool = _dereq_('./base').Tool; | |
| createShape = _dereq_('../core/shapes').createShape; | |
| module.exports = Text = (function(_super) { | |
| __extends(Text, _super); | |
| Text.prototype.name = 'Text'; | |
| Text.prototype.iconName = 'text'; | |
| function Text(text, font) { | |
| this.text = text != null ? text : ''; | |
| this.font = font != null ? font : 'bold 18px sans-serif'; | |
| } | |
| Text.prototype.setText = function(text) { | |
| return this.text = text; | |
| }; | |
| Text.prototype.begin = function(x, y, lc) { | |
| this.color = lc.getColor('primary'); | |
| return this.currentShape = createShape('Text', { | |
| x: x, | |
| y: y, | |
| text: this.text, | |
| color: this.color, | |
| font: this.font | |
| }); | |
| }; | |
| Text.prototype["continue"] = function(x, y, lc) { | |
| this.currentShape.x = x; | |
| this.currentShape.y = y; | |
| return lc.drawShapeInProgress(this.currentShape); | |
| }; | |
| Text.prototype.end = function(x, y, lc) { | |
| return lc.saveShape(this.currentShape); | |
| }; | |
| Text.prototype.optionsStyle = 'font'; | |
| return Text; | |
| })(Tool); | |
| },{"../core/shapes":8,"./base":35}],35:[function(_dereq_,module,exports){ | |
| var Tool, ToolWithStroke, tools, | |
| __hasProp = {}.hasOwnProperty, | |
| __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
| tools = {}; | |
| tools.Tool = Tool = (function() { | |
| function Tool() {} | |
| Tool.prototype.name = null; | |
| Tool.prototype.iconName = null; | |
| Tool.prototype.begin = function(x, y, lc) {}; | |
| Tool.prototype["continue"] = function(x, y, lc) {}; | |
| Tool.prototype.end = function(x, y, lc) {}; | |
| Tool.prototype.optionsStyle = null; | |
| return Tool; | |
| })(); | |
| tools.ToolWithStroke = ToolWithStroke = (function(_super) { | |
| __extends(ToolWithStroke, _super); | |
| function ToolWithStroke() { | |
| this.strokeWidth = 5; | |
| } | |
| ToolWithStroke.prototype.optionsStyle = 'stroke-width'; | |
| return ToolWithStroke; | |
| })(Tool); | |
| module.exports = tools; | |
| },{}]},{},[10]) | |
| (10) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment