Created
August 16, 2015 17:35
-
-
Save irskep/ef9ae11d4e5df11bfefd to your computer and use it in GitHub Desktop.
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, renderShapeToContext, renderShapeToSVG, 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; | |
| renderShapeToContext = _dereq_('./canvasRenderer').renderShapeToContext; | |
| renderShapeToSVG = _dereq_('./svgRenderer').renderShapeToSVG; | |
| 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.config = { | |
| zoomMin: opts.zoomMin || 0.2, | |
| zoomMax: opts.zoomMax || 4.0, | |
| zoomStep: opts.zoomStep || 0.2 | |
| }; | |
| 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._shapesInProgress = []; | |
| 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.willBecomeInactive(this); | |
| this.tool = tool; | |
| this.trigger('toolChange', { | |
| tool: tool | |
| }); | |
| return tool.didBecomeActive(this); | |
| }; | |
| LiterallyCanvas.prototype.setShapesInProgress = function(newVal) { | |
| return this._shapesInProgress = newVal; | |
| }; | |
| LiterallyCanvas.prototype.pointerDown = function(x, y) { | |
| var p; | |
| p = this.clientCoordsToDrawingCoords(x, y); | |
| if (this.tool.usesSimpleAPI) { | |
| this.tool.begin(p.x, p.y, this); | |
| this.isDragging = true; | |
| return this.trigger("drawStart", { | |
| tool: this.tool | |
| }); | |
| } else { | |
| this.isDragging = true; | |
| return this.trigger("pointerdown", { | |
| tool: this.tool, | |
| x: p.x, | |
| y: p.y, | |
| rawX: x, | |
| rawY: y | |
| }); | |
| } | |
| }; | |
| LiterallyCanvas.prototype.pointerMove = function(x, y) { | |
| return util.requestAnimationFrame((function(_this) { | |
| return function() { | |
| var p; | |
| p = _this.clientCoordsToDrawingCoords(x, y); | |
| if (_this.tool.usesSimpleAPI) { | |
| if (_this.isDragging) { | |
| _this.tool["continue"](p.x, p.y, _this); | |
| return _this.trigger("drawContinue", { | |
| tool: _this.tool | |
| }); | |
| } | |
| } else { | |
| if (_this.isDragging) { | |
| return _this.trigger("pointerdrag", { | |
| tool: _this.tool, | |
| x: p.x, | |
| y: p.y, | |
| rawX: x, | |
| rawY: y | |
| }); | |
| } else { | |
| return _this.trigger("pointermove", { | |
| tool: _this.tool, | |
| x: p.x, | |
| y: p.y, | |
| rawX: x, | |
| rawY: y | |
| }); | |
| } | |
| } | |
| }; | |
| })(this)); | |
| }; | |
| LiterallyCanvas.prototype.pointerUp = function(x, y) { | |
| var p; | |
| p = this.clientCoordsToDrawingCoords(x, y); | |
| if (this.tool.usesSimpleAPI) { | |
| if (this.isDragging) { | |
| this.tool.end(p.x, p.y, this); | |
| this.isDragging = false; | |
| return this.trigger("drawEnd", { | |
| tool: this.tool | |
| }); | |
| } | |
| } else { | |
| this.isDragging = false; | |
| return this.trigger("pointerup", { | |
| tool: this.tool, | |
| x: p.x, | |
| y: p.y, | |
| rawX: x, | |
| rawY: y | |
| }); | |
| } | |
| }; | |
| 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, this.config.zoomMin); | |
| newScale = Math.min(newScale, this.config.zoomMax); | |
| 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); | |
| retryCallback = (function(_this) { | |
| return function() { | |
| return _this.repaintLayer('background'); | |
| }; | |
| })(this); | |
| if (this.watermarkImage) { | |
| this._renderWatermark(this.backgroundCtx, true, retryCallback); | |
| } | |
| 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); | |
| this.clipped(((function(_this) { | |
| return function() { | |
| return _this.transformed((function() { | |
| var shape, _i, _len, _ref1, _results; | |
| _ref1 = _this._shapesInProgress; | |
| _results = []; | |
| for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | |
| shape = _ref1[_i]; | |
| _results.push(renderShapeToContext(_this.ctx, shape, { | |
| bufferCtx: _this.bufferCtx, | |
| shouldOnlyDrawLatest: true | |
| })); | |
| } | |
| return _results; | |
| }), _this.ctx, _this.bufferCtx); | |
| }; | |
| })(this)), this.ctx, this.bufferCtx); | |
| } | |
| } | |
| return this.trigger('repaint', { | |
| layerKey: repaintLayerKey | |
| }); | |
| }; | |
| LiterallyCanvas.prototype._renderWatermark = function(ctx, worryAboutRetina, retryCallback) { | |
| if (worryAboutRetina == null) { | |
| worryAboutRetina = true; | |
| } | |
| if (!this.watermarkImage.width) { | |
| this.watermarkImage.onload = retryCallback; | |
| return; | |
| } | |
| 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 renderShapeToContext(_this.ctx, shape, { | |
| bufferCtx: _this.bufferCtx, | |
| shouldOnlyDrawLatest: true | |
| }); | |
| }), _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(renderShapeToContext(ctx, shape, { | |
| retryCallback: 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.concat(this.backgroundShapes)).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) { | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.rect == null) { | |
| opts.rect = this.getContentBounds(); | |
| } | |
| if (!(opts.rect.width && opts.rect.height)) { | |
| return; | |
| } | |
| return util.renderShapesToSVG(this.backgroundShapes.concat(this.shapes), opts.rect, this.colors.background); | |
| }; | |
| 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":38,"./actions":4,"./bindEvents":5,"./canvasRenderer":6,"./math":10,"./shapes":11,"./svgRenderer":12,"./util":13}],3:[function(_dereq_,module,exports){ | |
| var TextRenderer, getLinesToRender, getNextLine, parseFontString; | |
| _dereq_('./fontmetrics.js'); | |
| parseFontString = function(font) { | |
| var fontFamily, fontItems, fontSize, item, maybeSize, remainingFontString, _i, _len; | |
| fontItems = font.split(' '); | |
| fontSize = 0; | |
| for (_i = 0, _len = fontItems.length; _i < _len; _i++) { | |
| item = fontItems[_i]; | |
| maybeSize = parseInt(item.replace("px", ""), 10); | |
| if (!isNaN(maybeSize)) { | |
| fontSize = maybeSize; | |
| } | |
| } | |
| if (!fontSize) { | |
| throw "Font size not found"; | |
| } | |
| remainingFontString = font.substring(fontItems[0].length + 1).replace('bold ', '').replace('italic ', '').replace('underline ', ''); | |
| fontFamily = remainingFontString; | |
| return { | |
| fontSize: fontSize, | |
| fontFamily: fontFamily | |
| }; | |
| }; | |
| getNextLine = function(ctx, text, forcedWidth) { | |
| var doesSubstringFit, endIndex, isEndOfString, isNonWord, isWhitespace, lastGoodIndex, lastOkayIndex, nextWordStartIndex, textToHere, wasInWord; | |
| if (!text.length) { | |
| return ['', '']; | |
| } | |
| endIndex = 0; | |
| lastGoodIndex = 0; | |
| lastOkayIndex = 0; | |
| wasInWord = false; | |
| while (true) { | |
| endIndex += 1; | |
| isEndOfString = endIndex >= text.length; | |
| isWhitespace = (!isEndOfString) && text[endIndex].match(/\s/); | |
| isNonWord = isWhitespace || isEndOfString; | |
| textToHere = text.substring(0, endIndex); | |
| doesSubstringFit = forcedWidth ? ctx.measureTextWidth(textToHere).width <= forcedWidth : true; | |
| if (doesSubstringFit) { | |
| lastOkayIndex = endIndex; | |
| } | |
| if (isNonWord && wasInWord) { | |
| wasInWord = false; | |
| if (doesSubstringFit) { | |
| lastGoodIndex = endIndex; | |
| } | |
| } | |
| wasInWord = !isWhitespace; | |
| if (isEndOfString || !doesSubstringFit) { | |
| if (doesSubstringFit) { | |
| return [text, '']; | |
| } else if (lastGoodIndex > 0) { | |
| nextWordStartIndex = lastGoodIndex + 1; | |
| while (nextWordStartIndex < text.length && text[nextWordStartIndex].match('/\s/')) { | |
| nextWordStartIndex += 1; | |
| } | |
| return [text.substring(0, lastGoodIndex), text.substring(nextWordStartIndex)]; | |
| } else { | |
| return [text.substring(0, lastOkayIndex), text.substring(lastOkayIndex)]; | |
| } | |
| } | |
| } | |
| }; | |
| getLinesToRender = function(ctx, text, forcedWidth) { | |
| var lines, nextLine, remainingText, textLine, textSplitOnLines, _i, _len, _ref, _ref1; | |
| textSplitOnLines = text.split(/\r\n|\r|\n/g); | |
| lines = []; | |
| for (_i = 0, _len = textSplitOnLines.length; _i < _len; _i++) { | |
| textLine = textSplitOnLines[_i]; | |
| _ref = getNextLine(ctx, textLine, forcedWidth), nextLine = _ref[0], remainingText = _ref[1]; | |
| if (nextLine) { | |
| while (nextLine) { | |
| lines.push(nextLine); | |
| _ref1 = getNextLine(ctx, remainingText, forcedWidth), nextLine = _ref1[0], remainingText = _ref1[1]; | |
| } | |
| } else { | |
| lines.push(textLine); | |
| } | |
| } | |
| return lines; | |
| }; | |
| TextRenderer = (function() { | |
| function TextRenderer(ctx, text, font, forcedWidth, forcedHeight) { | |
| var fontFamily, fontSize, _ref; | |
| this.text = text; | |
| this.font = font; | |
| this.forcedWidth = forcedWidth; | |
| this.forcedHeight = forcedHeight; | |
| _ref = parseFontString(this.font), fontFamily = _ref.fontFamily, fontSize = _ref.fontSize; | |
| ctx.font = this.font; | |
| ctx.textBaseline = 'baseline'; | |
| this.emDashWidth = ctx.measureTextWidth('—', fontSize, fontFamily).width; | |
| this.caratWidth = ctx.measureTextWidth('|', fontSize, fontFamily).width; | |
| this.lines = getLinesToRender(ctx, text, this.forcedWidth); | |
| this.metricses = this.lines.map((function(_this) { | |
| return function(line) { | |
| return ctx.measureText2(line || 'X', fontSize, _this.font); | |
| }; | |
| })(this)); | |
| this.metrics = { | |
| ascent: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var ascent; | |
| ascent = _arg.ascent; | |
| return ascent; | |
| })), | |
| descent: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var descent; | |
| descent = _arg.descent; | |
| return descent; | |
| })), | |
| fontsize: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var fontsize; | |
| fontsize = _arg.fontsize; | |
| return fontsize; | |
| })), | |
| leading: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var leading; | |
| leading = _arg.leading; | |
| return leading; | |
| })), | |
| width: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var width; | |
| width = _arg.width; | |
| return width; | |
| })), | |
| height: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var height; | |
| height = _arg.height; | |
| return height; | |
| })), | |
| bounds: { | |
| minx: Math.min.apply(Math, this.metricses.map(function(_arg) { | |
| var bounds; | |
| bounds = _arg.bounds; | |
| return bounds.minx; | |
| })), | |
| miny: Math.min.apply(Math, this.metricses.map(function(_arg) { | |
| var bounds; | |
| bounds = _arg.bounds; | |
| return bounds.miny; | |
| })), | |
| maxx: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var bounds; | |
| bounds = _arg.bounds; | |
| return bounds.maxx; | |
| })), | |
| maxy: Math.max.apply(Math, this.metricses.map(function(_arg) { | |
| var bounds; | |
| bounds = _arg.bounds; | |
| return bounds.maxy; | |
| })) | |
| } | |
| }; | |
| this.boundingBoxWidth = Math.ceil(this.metrics.width); | |
| } | |
| TextRenderer.prototype.draw = function(ctx, x, y) { | |
| var i, line, _i, _len, _ref, _results; | |
| ctx.textBaseline = 'top'; | |
| ctx.font = this.font; | |
| i = 0; | |
| _ref = this.lines; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| line = _ref[_i]; | |
| ctx.fillText(line, x, y + i * this.metrics.leading); | |
| _results.push(i += 1); | |
| } | |
| return _results; | |
| }; | |
| TextRenderer.prototype.getWidth = function(isEditing) { | |
| if (isEditing == null) { | |
| isEditing = false; | |
| } | |
| if (this.forcedWidth) { | |
| return this.forcedWidth; | |
| } else { | |
| if (isEditing) { | |
| return this.metrics.bounds.maxx + this.caratWidth; | |
| } else { | |
| return this.metrics.bounds.maxx; | |
| } | |
| } | |
| }; | |
| TextRenderer.prototype.getHeight = function() { | |
| return this.forcedHeight || (this.metrics.leading * this.lines.length); | |
| }; | |
| return TextRenderer; | |
| })(); | |
| module.exports = TextRenderer; | |
| },{"./fontmetrics.js":7}],4:[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 | |
| }; | |
| },{}],5:[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.pointerMove(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.pointerUp(p.left, p.top); | |
| document.removeEventListener('mousemove', mouseMoveListener); | |
| document.removeEventListener('mouseup', mouseUpListener); | |
| return canvas.addEventListener('mousemove', mouseMoveListener); | |
| }; | |
| })(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.pointerDown(p.left, p.top); | |
| canvas.removeEventListener('mousemove', mouseMoveListener); | |
| document.addEventListener('mousemove', mouseMoveListener); | |
| return document.addEventListener('mouseup', mouseUpListener); | |
| }; | |
| })(this)); | |
| touchMoveListener = function(e) { | |
| e.preventDefault(); | |
| return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); | |
| }; | |
| touchEndListener = function(e) { | |
| e.preventDefault(); | |
| lc.pointerUp.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.pointerDown.apply(lc, coordsForTouchEvent(canvas, e)); | |
| document.addEventListener('touchmove', touchMoveListener); | |
| document.addEventListener('touchend', touchEndListener); | |
| return document.addEventListener('touchcancel', touchEndListener); | |
| } else { | |
| return lc.pointerMove.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(); | |
| }); | |
| } | |
| }; | |
| },{}],6:[function(_dereq_,module,exports){ | |
| var defineCanvasRenderer, drawErasedLinePath, drawErasedLinePathLatest, drawLinePath, drawLinePathLatest, lineEndCapShapes, noop, renderShapeToCanvas, renderShapeToContext, renderers, _drawRawLinePath; | |
| lineEndCapShapes = _dereq_('./lineEndCapShapes.coffee'); | |
| renderers = {}; | |
| defineCanvasRenderer = function(shapeName, drawFunc, drawLatestFunc) { | |
| return renderers[shapeName] = { | |
| drawFunc: drawFunc, | |
| drawLatestFunc: drawLatestFunc | |
| }; | |
| }; | |
| noop = function() {}; | |
| renderShapeToContext = function(ctx, shape, opts) { | |
| var bufferCtx; | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.shouldIgnoreUnsupportedShapes == null) { | |
| opts.shouldIgnoreUnsupportedShapes = false; | |
| } | |
| if (opts.retryCallback == null) { | |
| opts.retryCallback = noop; | |
| } | |
| if (opts.shouldOnlyDrawLatest == null) { | |
| opts.shouldOnlyDrawLatest = false; | |
| } | |
| if (opts.bufferCtx == null) { | |
| opts.bufferCtx = null; | |
| } | |
| bufferCtx = opts.bufferCtx; | |
| if (renderers[shape.className]) { | |
| if (opts.shouldOnlyDrawLatest && renderers[shape.className].drawLatestFunc) { | |
| return renderers[shape.className].drawLatestFunc(ctx, bufferCtx, shape, opts.retryCallback); | |
| } else { | |
| return renderers[shape.className].drawFunc(ctx, shape, opts.retryCallback); | |
| } | |
| } else if (opts.shouldIgnoreUnsupportedShapes) { | |
| return console.warn("Can't render shape of type " + shape.className + " to canvas"); | |
| } else { | |
| throw "Can't render shape of type " + shape.className + " to canvas"; | |
| } | |
| }; | |
| renderShapeToCanvas = function(canvas, shape, opts) { | |
| return renderShapeToContext(canvas.getContext('2d'), shape, opts); | |
| }; | |
| defineCanvasRenderer('Rectangle', function(ctx, shape) { | |
| var x, y; | |
| x = shape.x; | |
| y = shape.y; | |
| if (shape.strokeWidth % 2 !== 0) { | |
| x += 0.5; | |
| y += 0.5; | |
| } | |
| ctx.fillStyle = shape.fillColor; | |
| ctx.fillRect(x, y, shape.width, shape.height); | |
| ctx.lineWidth = shape.strokeWidth; | |
| ctx.strokeStyle = shape.strokeColor; | |
| return ctx.strokeRect(x, y, shape.width, shape.height); | |
| }); | |
| defineCanvasRenderer('Ellipse', function(ctx, shape) { | |
| var centerX, centerY, halfHeight, halfWidth; | |
| ctx.save(); | |
| halfWidth = Math.floor(shape.width / 2); | |
| halfHeight = Math.floor(shape.height / 2); | |
| centerX = shape.x + halfWidth; | |
| centerY = shape.y + halfHeight; | |
| ctx.translate(centerX, centerY); | |
| ctx.scale(1, Math.abs(shape.height / shape.width)); | |
| ctx.beginPath(); | |
| ctx.arc(0, 0, Math.abs(halfWidth), 0, Math.PI * 2); | |
| ctx.closePath(); | |
| ctx.restore(); | |
| ctx.fillStyle = shape.fillColor; | |
| ctx.fill(); | |
| ctx.lineWidth = shape.strokeWidth; | |
| ctx.strokeStyle = shape.strokeColor; | |
| return ctx.stroke(); | |
| }); | |
| defineCanvasRenderer('SelectionBox', (function() { | |
| var _drawHandle; | |
| _drawHandle = function(ctx, shape, _arg, handleSize) { | |
| var x, y; | |
| x = _arg.x, y = _arg.y; | |
| ctx.fillStyle = '#fff'; | |
| ctx.fillRect(x, y, handleSize, handleSize); | |
| ctx.strokeStyle = '#000'; | |
| return ctx.strokeRect(x, y, handleSize, handleSize); | |
| }; | |
| return function(ctx, shape) { | |
| if (shape.backgroundColor) { | |
| ctx.fillStyle = shape.backgroundColor; | |
| ctx.fillRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); | |
| } | |
| ctx.lineWidth = 1; | |
| ctx.strokeStyle = '#000'; | |
| ctx.setLineDash([2, 4]); | |
| ctx.strokeRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); | |
| ctx.setLineDash([]); | |
| _drawHandle(ctx, shape.getTopLeftHandleRect(), shape.handleSize); | |
| _drawHandle(ctx, shape.getTopRightHandleRect(), shape.handleSize); | |
| _drawHandle(ctx, shape.getBottomLeftHandleRect(), shape.handleSize); | |
| return _drawHandle(ctx, shape.getBottomRightHandleRect(), shape.handleSize); | |
| }; | |
| })()); | |
| defineCanvasRenderer('Image', function(ctx, shape, retryCallback) { | |
| if (shape.image.width) { | |
| return ctx.drawImage(shape.image, shape.x, shape.y); | |
| } else if (retryCallback) { | |
| return shape.image.onload = retryCallback; | |
| } | |
| }); | |
| defineCanvasRenderer('Line', function(ctx, shape) { | |
| var arrowWidth, x1, x2, y1, y2; | |
| if (shape.x1 === shape.x2 && shape.y1 === shape.y2) { | |
| return; | |
| } | |
| x1 = shape.x1; | |
| x2 = shape.x2; | |
| y1 = shape.y1; | |
| y2 = shape.y2; | |
| if (shape.strokeWidth % 2 !== 0) { | |
| x1 += 0.5; | |
| x2 += 0.5; | |
| y1 += 0.5; | |
| y2 += 0.5; | |
| } | |
| ctx.lineWidth = shape.strokeWidth; | |
| ctx.strokeStyle = shape.color; | |
| ctx.lineCap = shape.capStyle; | |
| if (shape.dash) { | |
| ctx.setLineDash(shape.dash); | |
| } | |
| ctx.beginPath(); | |
| ctx.moveTo(x1, y1); | |
| ctx.lineTo(x2, y2); | |
| ctx.stroke(); | |
| if (shape.dash) { | |
| ctx.setLineDash([]); | |
| } | |
| arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); | |
| if (shape.endCapShapes[0]) { | |
| lineEndCapShapes[shape.endCapShapes[0]].drawToCanvas(ctx, x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); | |
| } | |
| if (shape.endCapShapes[1]) { | |
| return lineEndCapShapes[shape.endCapShapes[1]].drawToCanvas(ctx, x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); | |
| } | |
| }); | |
| _drawRawLinePath = function(ctx, points, close, lineCap) { | |
| var point, _i, _len, _ref; | |
| if (close == null) { | |
| close = false; | |
| } | |
| if (lineCap == null) { | |
| lineCap = 'round'; | |
| } | |
| if (!points.length) { | |
| return; | |
| } | |
| ctx.lineCap = lineCap; | |
| ctx.strokeStyle = points[0].color; | |
| ctx.lineWidth = points[0].size; | |
| ctx.beginPath(); | |
| if (points[0].size % 2 === 0) { | |
| ctx.moveTo(points[0].x, points[0].y); | |
| } else { | |
| ctx.moveTo(points[0].x + 0.5, points[0].y + 0.5); | |
| } | |
| _ref = points.slice(1); | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| point = _ref[_i]; | |
| if (points[0].size % 2 === 0) { | |
| ctx.lineTo(point.x, point.y); | |
| } else { | |
| ctx.lineTo(point.x + 0.5, point.y + 0.5); | |
| } | |
| } | |
| if (close) { | |
| return ctx.closePath(); | |
| } | |
| }; | |
| drawLinePath = function(ctx, shape) { | |
| _drawRawLinePath(ctx, shape.smoothedPoints); | |
| return ctx.stroke(); | |
| }; | |
| drawLinePathLatest = function(ctx, bufferCtx, shape) { | |
| var drawEnd, drawStart, segmentStart; | |
| if (shape.tail) { | |
| segmentStart = shape.smoothedPoints.length - shape.segmentSize * shape.tailSize; | |
| drawStart = segmentStart < shape.segmentSize * 2 ? 0 : segmentStart; | |
| drawEnd = segmentStart + shape.segmentSize + 1; | |
| _drawRawLinePath(bufferCtx, shape.smoothedPoints.slice(drawStart, drawEnd)); | |
| return bufferCtx.stroke(); | |
| } else { | |
| _drawRawLinePath(bufferCtx, shape.smoothedPoints); | |
| return bufferCtx.stroke(); | |
| } | |
| }; | |
| defineCanvasRenderer('LinePath', drawLinePath, drawLinePathLatest); | |
| drawErasedLinePath = function(ctx, shape) { | |
| ctx.save(); | |
| ctx.globalCompositeOperation = "destination-out"; | |
| drawLinePath(ctx, shape); | |
| return ctx.restore(); | |
| }; | |
| drawErasedLinePathLatest = function(ctx, bufferCtx, shape) { | |
| ctx.save(); | |
| ctx.globalCompositeOperation = "destination-out"; | |
| bufferCtx.save(); | |
| bufferCtx.globalCompositeOperation = "destination-out"; | |
| drawLinePathLatest(ctx, bufferCtx, shape); | |
| ctx.restore(); | |
| return bufferCtx.restore(); | |
| }; | |
| defineCanvasRenderer('ErasedLinePath', drawErasedLinePath, drawErasedLinePathLatest); | |
| defineCanvasRenderer('Text', function(ctx, shape) { | |
| if (!shape.renderer) { | |
| shape._makeRenderer(ctx); | |
| } | |
| ctx.fillStyle = shape.color; | |
| return shape.renderer.draw(ctx, shape.x, shape.y); | |
| }); | |
| defineCanvasRenderer('Polygon', function(ctx, shape) { | |
| ctx.fillStyle = shape.fillColor; | |
| _drawRawLinePath(ctx, shape.points, shape.isClosed, 'butt'); | |
| ctx.fill(); | |
| return ctx.stroke(); | |
| }); | |
| module.exports = { | |
| defineCanvasRenderer: defineCanvasRenderer, | |
| renderShapeToCanvas: renderShapeToCanvas, | |
| renderShapeToContext: renderShapeToContext | |
| }; | |
| },{"./lineEndCapShapes.coffee":8}],7:[function(_dereq_,module,exports){ | |
| /** | |
| This library rewrites the Canvas2D "measureText" function | |
| so that it returns a more complete metrics object. | |
| This library is licensed under the MIT (Expat) license, | |
| the text for which is included below. | |
| ** ----------------------------------------------------------------------------- | |
| CHANGELOG: | |
| 2012-01-21 - Whitespace handling added by Joe Turner | |
| (https://github.com/oampo) | |
| 2015-06-08 - Various hacks added by Steve Johnson | |
| ** ----------------------------------------------------------------------------- | |
| Copyright (C) 2011 by Mike "Pomax" Kamermans | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software and associated documentation files (the "Software"), to deal | |
| in the Software without restriction, including without limitation the rights | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| copies of the Software, and to permit persons to whom the Software is | |
| furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| THE SOFTWARE. | |
| **/ | |
| (function(){ | |
| var NAME = "FontMetrics Library" | |
| var VERSION = "1-2012.0121.1300"; | |
| // if there is no getComputedStyle, this library won't work. | |
| if(!document.defaultView.getComputedStyle) { | |
| throw("ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values."); | |
| } | |
| // store the old text metrics function on the Canvas2D prototype | |
| CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText; | |
| /** | |
| * shortcut function for getting computed CSS values | |
| */ | |
| var getCSSValue = function(element, property) { | |
| return document.defaultView.getComputedStyle(element,null).getPropertyValue(property); | |
| }; | |
| // debug function | |
| var show = function(canvas, ctx, xstart, w, h, metrics) | |
| { | |
| document.body.appendChild(canvas); | |
| ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; | |
| ctx.beginPath(); | |
| ctx.moveTo(xstart,0); | |
| ctx.lineTo(xstart,h); | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| ctx.beginPath(); | |
| ctx.moveTo(xstart+metrics.bounds.maxx,0); | |
| ctx.lineTo(xstart+metrics.bounds.maxx,h); | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| ctx.beginPath(); | |
| ctx.moveTo(0,h/2-metrics.ascent); | |
| ctx.lineTo(w,h/2-metrics.ascent); | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| ctx.beginPath(); | |
| ctx.moveTo(0,h/2+metrics.descent); | |
| ctx.lineTo(w,h/2+metrics.descent); | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| } | |
| /** | |
| * The new text metrics function | |
| */ | |
| CanvasRenderingContext2D.prototype.measureText2 = function( | |
| textstring, fontSize, fontString) { | |
| var metrics = this.measureTextWidth(textstring), | |
| isSpace = !(/\S/.test(textstring)); | |
| metrics.fontsize = fontSize; | |
| // for text lead values, we meaure a multiline text container. | |
| var leadDiv = document.createElement("div"); | |
| leadDiv.style.position = "absolute"; | |
| leadDiv.style.opacity = 0; | |
| leadDiv.style.font = fontString; | |
| leadDiv.innerHTML = textstring + "<br/>" + textstring; | |
| document.body.appendChild(leadDiv); | |
| // make some initial guess at the text leading (using the standard TeX ratio) | |
| metrics.leading = 1.2 * fontSize; | |
| // then we try to get the real value from the browser | |
| var leadDivHeight = getCSSValue(leadDiv,"height"); | |
| leadDivHeight = leadDivHeight.replace("px",""); | |
| if (leadDivHeight >= fontSize * 2) { metrics.leading = (leadDivHeight/2) | 0; } | |
| document.body.removeChild(leadDiv); | |
| // if we're not dealing with white space, we can compute metrics | |
| if (!isSpace) { | |
| // Have characters, so measure the text | |
| var canvas = document.createElement("canvas"); | |
| var padding = 100; | |
| canvas.width = metrics.width + padding; | |
| canvas.height = 3*fontSize; | |
| canvas.style.opacity = 1; | |
| canvas.style.font = fontString; | |
| var ctx = canvas.getContext("2d"); | |
| ctx.font = fontString; | |
| var w = canvas.width, | |
| h = canvas.height, | |
| baseline = h/2; | |
| // Set all canvas pixeldata values to 255, with all the content | |
| // data being 0. This lets us scan for data[i] != 255. | |
| ctx.fillStyle = "white"; | |
| ctx.fillRect(-1, -1, w+2, h+2); | |
| ctx.fillStyle = "black"; | |
| ctx.fillText(textstring, padding/2, baseline); | |
| var pixelData = ctx.getImageData(0, 0, w, h).data; | |
| // canvas pixel data is w*4 by h*4, because R, G, B and A are separate, | |
| // consecutive values in the array, rather than stored as 32 bit ints. | |
| var i = 0, | |
| w4 = w * 4, | |
| len = pixelData.length; | |
| // Finding the ascent uses a normal, forward scanline | |
| while (++i < len && pixelData[i] === 255) {} | |
| var ascent = (i/w4)|0; | |
| // Finding the descent uses a reverse scanline | |
| i = len - 1; | |
| while (--i > 0 && pixelData[i] === 255) {} | |
| var descent = (i/w4)|0; | |
| // find the min-x coordinate | |
| for(i = 0; i<len && pixelData[i] === 255; ) { | |
| i += w4; | |
| if(i>=len) { i = (i-len) + 4; }} | |
| var minx = ((i%w4)/4) | 0; | |
| // find the max-x coordinate | |
| var step = 1; | |
| for(i = len-3; i>=0 && pixelData[i] === 255; ) { | |
| i -= w4; | |
| if(i<0) { i = (len - 3) - (step++)*4; }} | |
| var maxx = ((i%w4)/4) + 1 | 0; | |
| // set font metrics | |
| metrics.ascent = (baseline - ascent); | |
| metrics.descent = (descent - baseline); | |
| metrics.bounds = { minx: minx - (padding/2), | |
| maxx: maxx - (padding/2), | |
| miny: 0, | |
| maxy: descent-ascent }; | |
| metrics.height = 1+(descent - ascent); | |
| } | |
| // if we ARE dealing with whitespace, most values will just be zero. | |
| else { | |
| // Only whitespace, so we can't measure the text | |
| metrics.ascent = 0; | |
| metrics.descent = 0; | |
| metrics.bounds = { minx: 0, | |
| maxx: metrics.width, // Best guess | |
| miny: 0, | |
| maxy: 0 }; | |
| metrics.height = 0; | |
| } | |
| return metrics; | |
| }; | |
| }()); | |
| },{}],8:[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; | |
| })) + "' />"; | |
| } | |
| }; | |
| })() | |
| }; | |
| },{}],9:[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, | |
| _: _ | |
| }; | |
| },{}],10:[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":11,"./util":13}],11:[function(_dereq_,module,exports){ | |
| var JSONToShape, LinePath, TextRenderer, bspline, createShape, defineCanvasRenderer, defineSVGRenderer, defineShape, lineEndCapShapes, linePathFuncs, renderShapeToContext, renderShapeToSVG, shapeToJSON, shapes, util, _createLinePathFromData, _doAllPointsShareStyle, _dual, _mid, _ref, _ref1, _refine, | |
| __slice = [].slice; | |
| util = _dereq_('./util'); | |
| TextRenderer = _dereq_('./TextRenderer'); | |
| lineEndCapShapes = _dereq_('./lineEndCapShapes.coffee'); | |
| _ref = _dereq_('./canvasRenderer'), defineCanvasRenderer = _ref.defineCanvasRenderer, renderShapeToContext = _ref.renderShapeToContext; | |
| _ref1 = _dereq_('./svgRenderer'), defineSVGRenderer = _ref1.defineSVGRenderer, renderShapeToSVG = _ref1.renderShapeToSVG; | |
| shapes = {}; | |
| defineShape = function(name, props) { | |
| var Shape, drawFunc, drawLatestFunc, k, legacyDrawFunc, legacyDrawLatestFunc, legacySVGFunc, svgFunc; | |
| Shape = function() { | |
| var args, _ref2; | |
| args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | |
| (_ref2 = props.constructor).call.apply(_ref2, [this].concat(__slice.call(args))); | |
| return this; | |
| }; | |
| Shape.prototype.className = name; | |
| Shape.fromJSON = props.fromJSON; | |
| if (props.draw) { | |
| legacyDrawFunc = props.draw; | |
| legacyDrawLatestFunc = props.draw || function(ctx, bufferCtx, retryCallback) { | |
| return this.draw(ctx, bufferCtx, retryCallback); | |
| }; | |
| drawFunc = function(ctx, shape, retryCallback) { | |
| return legacyDrawFunc.call(shape, ctx, retryCallback); | |
| }; | |
| drawLatestFunc = function(ctx, bufferCtx, shape, retryCallback) { | |
| return legacyDrawLatestFunc.call(shape, ctx, bufferCtx, retryCallback); | |
| }; | |
| delete props.draw; | |
| if (props.drawLatest) { | |
| delete props.drawLatest; | |
| } | |
| defineCanvasRenderer(name, drawFunc, drawLatestFunc); | |
| } | |
| if (props.toSVG) { | |
| legacySVGFunc = props.toSVG; | |
| svgFunc = function(shape) { | |
| return legacySVGFunc.call(shape); | |
| }; | |
| delete props.toSVG; | |
| defineSVGRenderer(name, svgFunc); | |
| } | |
| Shape.prototype.draw = function(ctx, retryCallback) { | |
| return renderShapeToContext(ctx, this, { | |
| retryCallback: retryCallback | |
| }); | |
| }; | |
| Shape.prototype.drawLatest = function(ctx, bufferCtx, retryCallback) { | |
| return renderShapeToContext(ctx, this, { | |
| retryCallback: retryCallback, | |
| bufferCtx: bufferCtx, | |
| shouldOnlyDrawLatest: true | |
| }); | |
| }; | |
| Shape.prototype.toSVG = function() { | |
| return renderShapeToSVG(this); | |
| }; | |
| 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; | |
| }, | |
| 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 | |
| }); | |
| } | |
| }); | |
| 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'; | |
| }, | |
| 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); | |
| } | |
| }); | |
| 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'; | |
| }, | |
| 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); | |
| } | |
| }); | |
| 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; | |
| }, | |
| 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); | |
| } | |
| }); | |
| _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, smoothedPoints, x, y; | |
| points = null; | |
| if (data.points) { | |
| points = (function() { | |
| var _i, _len, _ref2, _results; | |
| _ref2 = data.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| pointData = _ref2[_i]; | |
| _results.push(JSONToShape(pointData)); | |
| } | |
| return _results; | |
| })(); | |
| } else if (data.pointCoordinatePairs) { | |
| points = (function() { | |
| var _i, _len, _ref2, _ref3, _results; | |
| _ref2 = data.pointCoordinatePairs; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| _ref3 = _ref2[_i], x = _ref3[0], y = _ref3[1]; | |
| _results.push(JSONToShape({ | |
| className: 'Point', | |
| data: { | |
| x: x, | |
| y: y, | |
| size: data.pointSize, | |
| color: data.pointColor, | |
| smooth: data.smooth | |
| } | |
| })); | |
| } | |
| return _results; | |
| })(); | |
| } | |
| smoothedPoints = null; | |
| if (data.smoothedPointCoordinatePairs) { | |
| smoothedPoints = (function() { | |
| var _i, _len, _ref2, _ref3, _results; | |
| _ref2 = data.smoothedPointCoordinatePairs; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| _ref3 = _ref2[_i], x = _ref3[0], y = _ref3[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, | |
| smoothedPoints: smoothedPoints, | |
| 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; | |
| if (args.smoothedPoints) { | |
| this.points = args.points; | |
| return this.smoothedPoints = args.smoothedPoints; | |
| } else { | |
| 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, _ref2, _results; | |
| _ref2 = this.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| point = _ref2[_i]; | |
| _results.push([point.x, point.y]); | |
| } | |
| return _results; | |
| }).call(this), | |
| smoothedPointCoordinatePairs: (function() { | |
| var _i, _len, _ref2, _results; | |
| _ref2 = this.smoothedPoints; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| point = _ref2[_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, _ref2, _results; | |
| _ref2 = this.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| p = _ref2[_i]; | |
| _results.push(shapeToJSON(p)); | |
| } | |
| return _results; | |
| }).call(this) | |
| }; | |
| } | |
| }, | |
| fromJSON: function(data) { | |
| return _createLinePathFromData('LinePath', data); | |
| }, | |
| addPoint: function(point) { | |
| this.points.push(point); | |
| if (!this.smooth) { | |
| this.smoothedPoints = this.points; | |
| return; | |
| } | |
| 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); | |
| } | |
| } | |
| }; | |
| LinePath = defineShape('LinePath', linePathFuncs); | |
| defineShape('ErasedLinePath', { | |
| constructor: linePathFuncs.constructor, | |
| toJSON: linePathFuncs.toJSON, | |
| addPoint: linePathFuncs.addPoint, | |
| getBoundingRect: linePathFuncs.getBoundingRect, | |
| 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 || ''; | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this.x - this.size / 2, | |
| y: this.y - this.size / 2, | |
| width: this.size, | |
| height: this.size | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| size: this.size, | |
| color: this.color | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Point', data); | |
| } | |
| }); | |
| defineShape('Polygon', { | |
| constructor: function(args) { | |
| var point, _i, _len, _ref2, _results; | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.points = args.points; | |
| this.fillColor = args.fillColor || 'white'; | |
| this.strokeColor = args.strokeColor || 'black'; | |
| this.strokeWidth = args.strokeWidth; | |
| this.dash = args.dash || null; | |
| if (args.isClosed == null) { | |
| args.isClosed = true; | |
| } | |
| this.isClosed = args.isClosed; | |
| _ref2 = this.points; | |
| _results = []; | |
| for (_i = 0, _len = _ref2.length; _i < _len; _i++) { | |
| point = _ref2[_i]; | |
| point.color = this.strokeColor; | |
| _results.push(point.size = this.strokeWidth); | |
| } | |
| return _results; | |
| }, | |
| addPoint: function(x, y) { | |
| return this.points.push(LC.createShape('Point', { | |
| x: x, | |
| y: y | |
| })); | |
| }, | |
| getBoundingRect: function() { | |
| return util.getBoundingRect(this.points.map(function(p) { | |
| return p.getBoundingRect(); | |
| })); | |
| }, | |
| toJSON: function() { | |
| return { | |
| strokeWidth: this.strokeWidth, | |
| fillColor: this.fillColor, | |
| strokeColor: this.strokeColor, | |
| dash: this.dash, | |
| isClosed: this.isClosed, | |
| pointCoordinatePairs: this.points.map(function(p) { | |
| return [p.x, p.y]; | |
| }) | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| data.points = data.pointCoordinatePairs.map(function(_arg) { | |
| var x, y; | |
| x = _arg[0], y = _arg[1]; | |
| return createShape('Point', { | |
| x: x, | |
| y: y, | |
| size: data.strokeWidth, | |
| color: data.strokeColor | |
| }); | |
| }); | |
| return createShape('Polygon', data); | |
| } | |
| }); | |
| defineShape('Text', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.x = args.x || 0; | |
| this.y = args.y || 0; | |
| this.v = args.v || 0; | |
| this.text = args.text || ''; | |
| this.color = args.color || 'black'; | |
| this.font = args.font || '18px sans-serif'; | |
| this.forcedWidth = args.forcedWidth || null; | |
| return this.forcedHeight = args.forcedHeight || null; | |
| }, | |
| _makeRenderer: function(ctx) { | |
| ctx.lineHeight = 1.2; | |
| this.renderer = new TextRenderer(ctx, this.text, this.font, this.forcedWidth, this.forcedHeight); | |
| if (this.v < 1) { | |
| console.log('repairing baseline'); | |
| this.v = 1; | |
| this.x -= this.renderer.metrics.bounds.minx; | |
| return this.y -= this.renderer.metrics.leading - this.renderer.metrics.descent; | |
| } | |
| }, | |
| setText: function(text) { | |
| this.text = text; | |
| return this.renderer = null; | |
| }, | |
| setFont: function(font) { | |
| this.font = font; | |
| return this.renderer = null; | |
| }, | |
| setPosition: function(x, y) { | |
| this.x = x; | |
| return this.y = y; | |
| }, | |
| setSize: function(forcedWidth, forcedHeight) { | |
| this.forcedWidth = Math.max(forcedWidth, 0); | |
| this.forcedHeight = Math.max(forcedHeight, 0); | |
| return this.renderer = null; | |
| }, | |
| enforceMaxBoundingRect: function(lc) { | |
| var br, dx, lcBoundingRect; | |
| br = this.getBoundingRect(lc.ctx); | |
| lcBoundingRect = { | |
| x: -lc.position.x / lc.scale, | |
| y: -lc.position.y / lc.scale, | |
| width: lc.canvas.width / lc.scale, | |
| height: lc.canvas.height / lc.scale | |
| }; | |
| if (br.x + br.width > lcBoundingRect.x + lcBoundingRect.width) { | |
| dx = br.x - lcBoundingRect.x; | |
| this.forcedWidth = lcBoundingRect.width - dx - 10; | |
| return this.renderer = null; | |
| } | |
| }, | |
| getBoundingRect: function(ctx, isEditing) { | |
| if (isEditing == null) { | |
| isEditing = false; | |
| } | |
| if (!this.renderer) { | |
| if (ctx) { | |
| this._makeRenderer(ctx); | |
| } else { | |
| throw "Must pass ctx if text hasn't been rendered yet"; | |
| } | |
| } | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| width: this.renderer.getWidth(true), | |
| height: this.renderer.getHeight() | |
| }; | |
| }, | |
| toJSON: function() { | |
| return { | |
| x: this.x, | |
| y: this.y, | |
| text: this.text, | |
| color: this.color, | |
| font: this.font, | |
| forcedWidth: this.forcedWidth, | |
| forcedHeight: this.forcedHeight, | |
| v: this.v | |
| }; | |
| }, | |
| fromJSON: function(data) { | |
| return createShape('Text', data); | |
| } | |
| }); | |
| defineShape('SelectionBox', { | |
| constructor: function(args) { | |
| if (args == null) { | |
| args = {}; | |
| } | |
| this.shape = args.shape; | |
| this.handleSize = 10; | |
| this.margin = 4; | |
| this.backgroundColor = args.backgroundColor || null; | |
| return this._br = this.shape.getBoundingRect(args.ctx); | |
| }, | |
| getTopLeftHandleRect: function() { | |
| return { | |
| x: this._br.x - this.handleSize - this.margin, | |
| y: this._br.y - this.handleSize - this.margin, | |
| width: this.handleSize, | |
| height: this.handleSize | |
| }; | |
| }, | |
| getBottomLeftHandleRect: function() { | |
| return { | |
| x: this._br.x - this.handleSize - this.margin, | |
| y: this._br.y + this._br.height + this.margin, | |
| width: this.handleSize, | |
| height: this.handleSize | |
| }; | |
| }, | |
| getTopRightHandleRect: function() { | |
| return { | |
| x: this._br.x + this._br.width + this.margin, | |
| y: this._br.y - this.handleSize - this.margin, | |
| width: this.handleSize, | |
| height: this.handleSize | |
| }; | |
| }, | |
| getBottomRightHandleRect: function() { | |
| return { | |
| x: this._br.x + this._br.width + this.margin, | |
| y: this._br.y + this._br.height + this.margin, | |
| width: this.handleSize, | |
| height: this.handleSize | |
| }; | |
| }, | |
| getBoundingRect: function() { | |
| return { | |
| x: this._br.x - this.margin, | |
| y: this._br.y - this.margin, | |
| width: this._br.width + this.margin * 2, | |
| height: this._br.height + this.margin * 2 | |
| }; | |
| } | |
| }); | |
| module.exports = { | |
| defineShape: defineShape, | |
| createShape: createShape, | |
| JSONToShape: JSONToShape, | |
| shapeToJSON: shapeToJSON | |
| }; | |
| },{"./TextRenderer":3,"./canvasRenderer":6,"./lineEndCapShapes.coffee":8,"./svgRenderer":12,"./util":13}],12:[function(_dereq_,module,exports){ | |
| var defineSVGRenderer, lineEndCapShapes, renderShapeToSVG, renderers; | |
| lineEndCapShapes = _dereq_('./lineEndCapShapes.coffee'); | |
| renderers = {}; | |
| defineSVGRenderer = function(shapeName, shapeToSVGFunc) { | |
| return renderers[shapeName] = shapeToSVGFunc; | |
| }; | |
| renderShapeToSVG = function(shape, opts) { | |
| if (opts == null) { | |
| opts = {}; | |
| } | |
| if (opts.shouldIgnoreUnsupportedShapes == null) { | |
| opts.shouldIgnoreUnsupportedShapes = false; | |
| } | |
| if (renderers[shape.className]) { | |
| return renderers[shape.className](shape); | |
| } else if (opts.shouldIgnoreUnsupportedShapes) { | |
| console.warn("Can't render shape of type " + shape.className + " to SVG"); | |
| return ""; | |
| } else { | |
| throw "Can't render shape of type " + shape.className + " to SVG"; | |
| } | |
| }; | |
| defineSVGRenderer('Rectangle', function(shape) { | |
| var x, y; | |
| x = shape.x; | |
| y = shape.y; | |
| if (shape.strokeWidth % 2 !== 0) { | |
| x += 0.5; | |
| y += 0.5; | |
| } | |
| return "<rect x='" + x + "' y='" + y + "' width='" + shape.width + "' height='" + shape.height + "' stroke='" + shape.strokeColor + "' fill='" + shape.fillColor + "' stroke-width='" + shape.strokeWidth + "' />"; | |
| }); | |
| defineSVGRenderer('Ellipse', function(shape) { | |
| var centerX, centerY, halfHeight, halfWidth; | |
| halfWidth = Math.floor(shape.width / 2); | |
| halfHeight = Math.floor(shape.height / 2); | |
| centerX = shape.x + halfWidth; | |
| centerY = shape.y + halfHeight; | |
| return "<ellipse cx='" + centerX + "' cy='" + centerY + "' rx='" + halfWidth + "' ry='" + halfHeight + "' stroke='" + shape.strokeColor + "' fill='" + shape.fillColor + "' stroke-width='" + shape.strokeWidth + "' />"; | |
| }); | |
| defineSVGRenderer('Image', function(shape) { | |
| return "<image x='" + shape.x + "' y='" + shape.y + "' width='" + shape.image.naturalWidth + "' height='" + shape.image.naturalHeight + "' xlink:href='" + shape.image.src + "' />"; | |
| }); | |
| defineSVGRenderer('Line', function(shape) { | |
| var arrowWidth, capString, dashString, x1, x2, y1, y2; | |
| dashString = shape.dash ? "stroke-dasharray='" + (shape.dash.join(', ')) + "'" : ''; | |
| capString = ''; | |
| arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); | |
| x1 = shape.x1; | |
| x2 = shape.x2; | |
| y1 = shape.y1; | |
| y2 = shape.y2; | |
| if (shape.strokeWidth % 2 !== 0) { | |
| x1 += 0.5; | |
| x2 += 0.5; | |
| y1 += 0.5; | |
| y2 += 0.5; | |
| } | |
| if (shape.endCapShapes[0]) { | |
| capString += lineEndCapShapes[shape.endCapShapes[0]].svg(x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); | |
| } | |
| if (shape.endCapShapes[1]) { | |
| capString += lineEndCapShapes[shape.endCapShapes[1]].svg(x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); | |
| } | |
| return "<g> <line x1='" + x1 + "' y1='" + y1 + "' x2='" + x2 + "' y2='" + y2 + "' " + dashString + " stroke-linecap='" + shape.capStyle + "' stroke='" + shape.color + "'stroke-width='" + shape.strokeWidth + "' /> " + capString + " <g>"; | |
| }); | |
| defineSVGRenderer('LinePath', function(shape) { | |
| return "<polyline fill='none' points='" + (shape.smoothedPoints.map(function(p) { | |
| var offset; | |
| offset = p.strokeWidth % 2 === 0 ? 0.0 : 0.5; | |
| return "" + (p.x + offset) + "," + (p.y + offset); | |
| }).join(' ')) + "' stroke='" + shape.points[0].color + "' stroke-width='" + shape.points[0].size + "' />"; | |
| }); | |
| defineSVGRenderer('ErasedLinePath', function(shape) { | |
| return ""; | |
| }); | |
| defineSVGRenderer('Polygon', function(shape) { | |
| if (shape.isClosed) { | |
| return "<polygon fill='" + shape.fillColor + "' points='" + (shape.points.map(function(p) { | |
| var offset; | |
| offset = p.strokeWidth % 2 === 0 ? 0.0 : 0.5; | |
| return "" + (p.x + offset) + "," + (p.y + offset); | |
| }).join(' ')) + "' stroke='" + shape.strokeColor + "' stroke-width='" + shape.strokeWidth + "' />"; | |
| } else { | |
| return "<polyline fill='" + shape.fillColor + "' points='" + (shape.points.map(function(p) { | |
| var offset; | |
| offset = p.strokeWidth % 2 === 0 ? 0.0 : 0.5; | |
| return "" + (p.x + offset) + "," + (p.y + offset); | |
| }).join(' ')) + "' stroke='none' /> <polyline fill='none' points='" + (shape.points.map(function(p) { | |
| var offset; | |
| offset = p.strokeWidth % 2 === 0 ? 0.0 : 0.5; | |
| return "" + (p.x + offset) + "," + (p.y + offset); | |
| }).join(' ')) + "' stroke='" + shape.strokeColor + "' stroke-width='" + shape.strokeWidth + "' />"; | |
| } | |
| }); | |
| defineSVGRenderer('Text', function(shape) { | |
| var heightString, textSplitOnLines, widthString; | |
| widthString = shape.forcedWidth ? "width='" + shape.forcedWidth + "px'" : ""; | |
| heightString = shape.forcedHeight ? "height='" + shape.forcedHeight + "px'" : ""; | |
| textSplitOnLines = shape.text.split(/\r\n|\r|\n/g); | |
| if (shape.renderer) { | |
| textSplitOnLines = shape.renderer.lines; | |
| } | |
| return "<text x='" + shape.x + "' y='" + shape.y + "' " + widthString + " " + heightString + " fill='" + shape.color + "' style='font: " + shape.font + ";'> " + (textSplitOnLines.map((function(_this) { | |
| return function(line, i) { | |
| var dy; | |
| dy = i === 0 ? 0 : '1.2em'; | |
| return "<tspan x='" + shape.x + "' dy='" + dy + "' alignment-baseline='text-before-edge'> " + line + " </tspan>"; | |
| }; | |
| })(this)).join('')) + " </text>"; | |
| }); | |
| module.exports = { | |
| defineSVGRenderer: defineSVGRenderer, | |
| renderShapeToSVG: renderShapeToSVG | |
| }; | |
| },{"./lineEndCapShapes.coffee":8}],13:[function(_dereq_,module,exports){ | |
| var renderShapeToContext, renderShapeToSVG, slice, util, | |
| __slice = [].slice; | |
| slice = Array.prototype.slice; | |
| renderShapeToContext = _dereq_('./canvasRenderer').renderShapeToContext; | |
| renderShapeToSVG = _dereq_('./svgRenderer').renderShapeToSVG; | |
| 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]; | |
| renderShapeToContext(ctx, shape); | |
| } | |
| return canvas; | |
| }, | |
| renderShapesToSVG: function(shapes, _arg, backgroundColor) { | |
| var height, width, x, y; | |
| x = _arg.x, y = _arg.y, width = _arg.width, height = _arg.height; | |
| return ("<svg xmlns='http://www.w3.org/2000/svg' width='" + width + "' height='" + height + "' viewBox='0 0 " + width + " " + height + "'> <rect width='" + width + "' height='" + height + "' x='0' y='0' fill='" + backgroundColor + "' /> <g transform='translate(" + (-x) + ", " + (-y) + ")'> " + (shapes.map(renderShapeToSVG).join('')) + " </g> </svg>").replace(/(\r\n|\n|\r)/gm, ""); | |
| }, | |
| 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; | |
| },{"./canvasRenderer":6,"./svgRenderer":12}],14:[function(_dereq_,module,exports){ | |
| (function () { | |
| function CustomEvent ( event, params ) { | |
| params = params || { bubbles: false, cancelable: false, detail: undefined }; | |
| var evt = document.createEvent( 'CustomEvent' ); | |
| evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); | |
| return evt; | |
| }; | |
| CustomEvent.prototype = window.CustomEvent.prototype; | |
| window.CustomEvent = CustomEvent; | |
| })(); | |
| },{}],15:[function(_dereq_,module,exports){ | |
| var hasWarned = false; | |
| if (!CanvasRenderingContext2D.prototype.setLineDash) { | |
| CanvasRenderingContext2D.prototype.setLineDash = function() { | |
| // no-op | |
| if (!hasWarned) { | |
| console.warn("context2D.setLineDash is a no-op in this browser."); | |
| hasWarned = true; | |
| } | |
| } | |
| } | |
| module.exports = null; | |
| },{}],16:[function(_dereq_,module,exports){ | |
| var LiterallyCanvas, baseTools, canvasRenderer, conversion, defaultImageURLPrefix, defaultTools, defineOptionsStyle, init, initReact, localize, registerJQueryPlugin, setDefaultImageURLPrefix, shapes, svgRenderer, tools, util; | |
| _dereq_('./ie_customevent'); | |
| _dereq_('./ie_setLineDash'); | |
| LiterallyCanvas = _dereq_('./core/LiterallyCanvas'); | |
| initReact = _dereq_('./reactGUI/init'); | |
| canvasRenderer = _dereq_('./core/canvasRenderer'); | |
| svgRenderer = _dereq_('./core/svgRenderer'); | |
| 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; | |
| conversion = { | |
| snapshotToShapes: function(snapshot) { | |
| var shape, _i, _len, _ref, _results; | |
| _ref = snapshot.shapes; | |
| _results = []; | |
| for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
| shape = _ref[_i]; | |
| _results.push(shapes.JSONToShape(shape)); | |
| } | |
| return _results; | |
| }, | |
| snapshotJSONToShapes: function(json) { | |
| return conversion.snapshotToShapes(JSON.parse(json)); | |
| } | |
| }; | |
| 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'), | |
| Polygon: _dereq_('./tools/Polygon'), | |
| Pan: _dereq_('./tools/Pan'), | |
| Eyedropper: _dereq_('./tools/Eyedropper'), | |
| Tool: baseTools.Tool, | |
| ToolWithStroke: baseTools.ToolWithStroke | |
| }; | |
| defaultTools = [tools.Pencil, tools.Eraser, tools.Line, tools.Rectangle, tools.Ellipse, tools.Text, tools.Polygon, tools.Pan, tools.Eyedropper]; | |
| defaultImageURLPrefix = 'lib/img'; | |
| setDefaultImageURLPrefix = function(newDefault) { | |
| return defaultImageURLPrefix = newDefault; | |
| }; | |
| init = function(el, opts) { | |
| var child, drawingViewElement, lc, optionsElement, pickerElement, topOrBottomClassName, _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.toolbarPosition == null) { | |
| opts.toolbarPosition = 'top'; | |
| } | |
| 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 (opts.zoomMin == null) { | |
| opts.zoomMin = 0.2; | |
| } | |
| if (opts.zoomMax == null) { | |
| opts.zoomMax = 4.0; | |
| } | |
| if (opts.zoomStep == null) { | |
| opts.zoomStep = 0.2; | |
| } | |
| if (!('tools' in opts)) { | |
| opts.tools = defaultTools; | |
| } | |
| /* 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'; | |
| } | |
| topOrBottomClassName = opts.toolbarPosition === 'top' ? 'toolbar-at-top' : 'toolbar-at-bottom'; | |
| el.className = el.className + ' ' + topOrBottomClassName; | |
| 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, | |
| defaultTools: defaultTools, | |
| defineShape: shapes.defineShape, | |
| createShape: shapes.createShape, | |
| JSONToShape: shapes.JSONToShape, | |
| shapeToJSON: shapes.shapeToJSON, | |
| defineCanvasRenderer: canvasRenderer.defineCanvasRenderer, | |
| renderShapeToContext: canvasRenderer.renderShapeToContext, | |
| renderShapeToCanvas: canvasRenderer.renderShapeToCanvas, | |
| renderShapesToCanvas: util.renderShapesToCanvas, | |
| defineSVGRenderer: svgRenderer.defineSVGRenderer, | |
| renderShapeToSVG: svgRenderer.renderShapeToSVG, | |
| renderShapesToSVG: util.renderShapesToSVG, | |
| snapshotToShapes: conversion.snapshotToShapes, | |
| snapshotJSONToShapes: conversion.snapshotJSONToShapes, | |
| localize: localize | |
| }; | |
| },{"./core/LiterallyCanvas":2,"./core/canvasRenderer":6,"./core/localization":9,"./core/shapes":11,"./core/svgRenderer":12,"./core/util":13,"./ie_customevent":14,"./ie_setLineDash":15,"./optionsStyles/font":17,"./optionsStyles/line-options-and-stroke-width":18,"./optionsStyles/null":19,"./optionsStyles/optionsStyles":20,"./optionsStyles/stroke-width":21,"./reactGUI/init":32,"./tools/Ellipse":33,"./tools/Eraser":34,"./tools/Eyedropper":35,"./tools/Line":36,"./tools/Pan":37,"./tools/Pencil":38,"./tools/Polygon":39,"./tools/Rectangle":40,"./tools/Text":41,"./tools/base":42}],17:[function(_dereq_,module,exports){ | |
| var defineOptionsStyle, _; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| _ = _dereq_('../core/localization')._; | |
| defineOptionsStyle('font', React.createClass({ | |
| displayName: 'FontOptions', | |
| getInitialState: function() { | |
| return { | |
| 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); | |
| this.props.lc.tool.font = items.join(' '); | |
| return this.props.lc.trigger('setFont', items.join(' ')); | |
| }, | |
| 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' | |
| }, select({ | |
| value: this.state.fontSizeIndex, | |
| onChange: this.handleFontSize | |
| }, this.getFontSizes().map((function(_this) { | |
| return function(size, ix) { | |
| return option({ | |
| value: ix, | |
| key: ix | |
| }, "" + size + "px"); | |
| }; | |
| })(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":9,"./optionsStyles":20}],18:[function(_dereq_,module,exports){ | |
| var StrokeWidthPicker, createSetStateOnEventMixin, defineOptionsStyle; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| StrokeWidthPicker = React.createFactory(_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, style, 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({ | |
| 'square-toolbar-button': true, | |
| 'selected': this.state.isDashed | |
| }); | |
| arrowButtonClass = React.addons.classSet({ | |
| 'square-toolbar-button': true, | |
| 'selected': this.state.hasEndArrow | |
| }); | |
| style = { | |
| float: 'left', | |
| margin: 1 | |
| }; | |
| return div({}, div({ | |
| className: dashButtonClass, | |
| onClick: toggleIsDashed, | |
| style: style | |
| }, img({ | |
| src: "" + this.props.imageURLPrefix + "/dashed-line.png" | |
| })), div({ | |
| className: arrowButtonClass, | |
| onClick: togglehasEndArrow, | |
| style: style | |
| }, img({ | |
| src: "" + this.props.imageURLPrefix + "/line-with-arrow.png" | |
| })), StrokeWidthPicker({ | |
| tool: this.props.tool, | |
| lc: this.props.lc | |
| })); | |
| } | |
| })); | |
| module.exports = {}; | |
| },{"../reactGUI/StrokeWidthPicker":27,"../reactGUI/createSetStateOnEventMixin":30,"./optionsStyles":20}],19:[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":20}],20:[function(_dereq_,module,exports){ | |
| var defineOptionsStyle, optionsStyles; | |
| optionsStyles = {}; | |
| defineOptionsStyle = function(name, style) { | |
| return optionsStyles[name] = React.createFactory(style); | |
| }; | |
| module.exports = { | |
| optionsStyles: optionsStyles, | |
| defineOptionsStyle: defineOptionsStyle | |
| }; | |
| },{}],21:[function(_dereq_,module,exports){ | |
| var StrokeWidthPicker, defineOptionsStyle; | |
| defineOptionsStyle = _dereq_('./optionsStyles').defineOptionsStyle; | |
| StrokeWidthPicker = _dereq_('../reactGUI/StrokeWidthPicker'); | |
| defineOptionsStyle('stroke-width', StrokeWidthPicker); | |
| module.exports = {}; | |
| },{"../reactGUI/StrokeWidthPicker":27,"./optionsStyles":20}],22:[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":9,"./React-shim":26,"./createSetStateOnEventMixin":30}],23:[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({ | |
| onMouseLeave: this.closePicker, | |
| onClick: this.togglePicker, | |
| style: { | |
| float: 'left' | |
| } | |
| }, div({ | |
| className: React.addons.classSet({ | |
| 'square-toolbar-button': true, | |
| 'color-well-container': true, | |
| 'selected': this.state.isPickerVisible | |
| }), | |
| style: { | |
| backgroundColor: 'white', | |
| float: 'left', | |
| margin: 1 | |
| } | |
| }, div({ | |
| className: 'color-well-checker color-well-checker-top-left' | |
| }), div({ | |
| className: 'color-well-checker color-well-checker-bottom-right', | |
| style: { | |
| left: '50%', | |
| top: '50%' | |
| } | |
| }), div({ | |
| className: 'color-well-color', | |
| style: { | |
| backgroundColor: this.state.color | |
| } | |
| }, " "), this.renderPicker()), label({ | |
| float: 'left' | |
| }, this.props.label)); | |
| }, | |
| 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":26}],24:[function(_dereq_,module,exports){ | |
| var ColorPickers, ColorWell, Options, React, createSetStateOnEventMixin, optionsStyles, _; | |
| React = _dereq_('./React-shim'); | |
| createSetStateOnEventMixin = _dereq_('./createSetStateOnEventMixin'); | |
| optionsStyles = _dereq_('../optionsStyles/optionsStyles').optionsStyles; | |
| ColorWell = React.createFactory(_dereq_('./ColorWell')); | |
| _ = _dereq_('../core/localization')._; | |
| ColorPickers = React.createFactory(React.createClass({ | |
| displayName: 'ColorPickers', | |
| render: function() { | |
| var div, lc; | |
| lc = this.props.lc; | |
| div = React.DOM.div; | |
| return div({ | |
| className: 'lc-color-pickers', | |
| style: { | |
| float: 'left', | |
| marginRight: '0.5em' | |
| } | |
| }, ColorWell({ | |
| lc: lc, | |
| colorName: 'background', | |
| label: _('bg') | |
| }), ColorWell({ | |
| lc: lc, | |
| colorName: 'primary', | |
| label: _('stroke') | |
| }), ColorWell({ | |
| lc: lc, | |
| colorName: 'secondary', | |
| label: _('fill') | |
| })); | |
| } | |
| })); | |
| 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 div, style; | |
| div = React.DOM.div; | |
| style = "" + this.state.style; | |
| return div({}, ColorPickers({ | |
| lc: this.props.lc | |
| }), optionsStyles[style]({ | |
| lc: this.props.lc, | |
| tool: this.state.tool, | |
| imageURLPrefix: this.props.imageURLPrefix | |
| })); | |
| } | |
| }); | |
| module.exports = Options; | |
| },{"../core/localization":9,"../optionsStyles/optionsStyles":20,"./ColorWell":23,"./React-shim":26,"./createSetStateOnEventMixin":30}],25:[function(_dereq_,module,exports){ | |
| var ClearButton, Picker, React, UndoRedoButtons, ZoomButtons; | |
| React = _dereq_('./React-shim'); | |
| ClearButton = React.createFactory(_dereq_('./ClearButton')); | |
| UndoRedoButtons = React.createFactory(_dereq_('./UndoRedoButtons')); | |
| ZoomButtons = React.createFactory(_dereq_('./ZoomButtons')); | |
| 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, div({ | |
| style: { | |
| position: 'absolute', | |
| bottom: 0, | |
| left: 0, | |
| right: 0 | |
| } | |
| }, UndoRedoButtons({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), ZoomButtons({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), ClearButton({ | |
| lc: lc | |
| }))); | |
| } | |
| }); | |
| module.exports = Picker; | |
| },{"./ClearButton":22,"./React-shim":26,"./UndoRedoButtons":28,"./ZoomButtons":29}],26:[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; | |
| },{}],27:[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, 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]; | |
| return div({}, strokeWidths.map((function(_this) { | |
| return function(strokeWidth, ix) { | |
| var buttonClassName, buttonSize; | |
| buttonClassName = React.addons.classSet({ | |
| 'square-toolbar-button': true, | |
| 'selected': strokeWidth === _this.state.strokeWidth | |
| }); | |
| buttonSize = 28; | |
| return div({ | |
| key: strokeWidth, | |
| style: { | |
| float: 'left', | |
| width: buttonSize, | |
| height: buttonSize, | |
| margin: 1 | |
| } | |
| }, div({ | |
| className: buttonClassName, | |
| onClick: function() { | |
| _this.props.tool.strokeWidth = strokeWidth; | |
| return _this.setState(_this.getState()); | |
| } | |
| }, svg({ | |
| width: buttonSize - 2, | |
| height: buttonSize - 2, | |
| viewPort: "0 0 " + strokeWidth + " " + strokeWidth, | |
| version: "1.1", | |
| xmlns: "http://www.w3.org/2000/svg" | |
| }, circle({ | |
| cx: Math.ceil(buttonSize / 2 - 1), | |
| cy: Math.ceil(buttonSize / 2 - 1), | |
| r: strokeWidth / 2 | |
| })))); | |
| }; | |
| })(this))); | |
| } | |
| }); | |
| },{"../reactGUI/createSetStateOnEventMixin":30}],28:[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, src, style, 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); | |
| src = "" + imageURLPrefix + "/" + undoOrRedo + ".png"; | |
| style = { | |
| backgroundImage: "url(" + src + ")" | |
| }; | |
| return div({ | |
| className: className, | |
| onClick: onClick, | |
| title: title, | |
| style: style | |
| }); | |
| } | |
| }); | |
| }; | |
| UndoButton = React.createFactory(createUndoRedoButtonComponent('undo')); | |
| RedoButton = React.createFactory(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":26,"./createSetStateOnEventMixin":30}],29:[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 < this.props.lc.config.zoomMax; | |
| case inOrOut !== 'out': | |
| return this.props.lc.scale > this.props.lc.config.zoomMin; | |
| } | |
| }).call(this) | |
| }; | |
| }, | |
| getInitialState: function() { | |
| return this.getState(); | |
| }, | |
| mixins: [createSetStateOnEventMixin('zoom')], | |
| render: function() { | |
| var className, div, imageURLPrefix, img, lc, onClick, src, style, 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(lc.config.zoomStep); | |
| }; | |
| case inOrOut !== 'out': | |
| return function() { | |
| return lc.zoom(-lc.config.zoomStep); | |
| }; | |
| } | |
| }).call(this); | |
| src = "" + imageURLPrefix + "/zoom-" + inOrOut + ".png"; | |
| style = { | |
| backgroundImage: "url(" + src + ")" | |
| }; | |
| return div({ | |
| className: className, | |
| onClick: onClick, | |
| title: title, | |
| style: style | |
| }); | |
| } | |
| }); | |
| }; | |
| ZoomOutButton = React.createFactory(createZoomButtonComponent('out')); | |
| ZoomInButton = React.createFactory(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":26,"./createSetStateOnEventMixin":30}],30:[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":26}],31:[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.createFactory(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, src, _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 | |
| }); | |
| src = "" + imageURLPrefix + "/" + imageName + ".png"; | |
| return div({ | |
| className: className, | |
| style: { | |
| 'backgroundImage': "url(" + src + ")" | |
| }, | |
| onClick: (function() { | |
| return onSelect(tool); | |
| }), | |
| title: displayName | |
| }); | |
| } | |
| })); | |
| }; | |
| module.exports = createToolButton; | |
| },{"./React-shim":26}],32:[function(_dereq_,module,exports){ | |
| var Options, Picker, React, createToolButton, init; | |
| React = _dereq_('./React-shim'); | |
| createToolButton = _dereq_('./createToolButton'); | |
| Options = React.createFactory(_dereq_('./Options')); | |
| Picker = React.createFactory(_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.render(Picker({ | |
| lc: lc, | |
| toolButtonComponents: toolButtonComponents, | |
| imageURLPrefix: imageURLPrefix | |
| }), pickerElement); | |
| return React.render(Options({ | |
| lc: lc, | |
| imageURLPrefix: imageURLPrefix | |
| }), optionsElement); | |
| }; | |
| module.exports = init; | |
| },{"./Options":24,"./Picker":25,"./React-shim":26,"./createToolButton":31}],33:[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":11,"./base":42}],34:[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":11,"./Pencil":38}],35:[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":11,"./base":42}],36:[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":11,"./base":42}],37:[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.usesSimpleAPI = false; | |
| Pan.prototype.didBecomeActive = function(lc) { | |
| var unsubscribeFuncs; | |
| unsubscribeFuncs = []; | |
| this.unsubscribe = (function(_this) { | |
| return function() { | |
| var func, _i, _len, _results; | |
| _results = []; | |
| for (_i = 0, _len = unsubscribeFuncs.length; _i < _len; _i++) { | |
| func = unsubscribeFuncs[_i]; | |
| _results.push(func()); | |
| } | |
| return _results; | |
| }; | |
| })(this); | |
| unsubscribeFuncs.push(lc.on('pointerdown', (function(_this) { | |
| return function(_arg) { | |
| var rawX, rawY; | |
| rawX = _arg.rawX, rawY = _arg.rawY; | |
| _this.oldPosition = lc.position; | |
| return _this.pointerStart = { | |
| x: rawX, | |
| y: rawY | |
| }; | |
| }; | |
| })(this))); | |
| return unsubscribeFuncs.push(lc.on('pointerdrag', (function(_this) { | |
| return function(_arg) { | |
| var dp, rawX, rawY; | |
| rawX = _arg.rawX, rawY = _arg.rawY; | |
| dp = { | |
| x: rawX - _this.pointerStart.x, | |
| y: rawY - _this.pointerStart.y | |
| }; | |
| return lc.setPan(_this.oldPosition.x + dp.x, _this.oldPosition.y + dp.y); | |
| }; | |
| })(this))); | |
| }; | |
| Pan.prototype.willBecomeInactive = function(lc) { | |
| return this.unsubscribe(); | |
| }; | |
| return Pan; | |
| })(Tool); | |
| },{"../core/shapes":11,"./base":42}],38:[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":11,"./base":42}],39:[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 = 'Polygon'; | |
| Pencil.prototype.iconName = 'polygon'; | |
| Pencil.prototype.usesSimpleAPI = false; | |
| Pencil.prototype.didBecomeActive = function(lc) { | |
| var onDown, onMove, onUp, unsubscribeFuncs; | |
| unsubscribeFuncs = []; | |
| this.unsubscribe = (function(_this) { | |
| return function() { | |
| var func, _i, _len, _results; | |
| _results = []; | |
| for (_i = 0, _len = unsubscribeFuncs.length; _i < _len; _i++) { | |
| func = unsubscribeFuncs[_i]; | |
| _results.push(func()); | |
| } | |
| return _results; | |
| }; | |
| })(this); | |
| this.points = null; | |
| this.maybePoint = null; | |
| onUp = (function(_this) { | |
| return function() { | |
| if (_this._getWillFinish()) { | |
| _this._close(lc); | |
| return; | |
| } | |
| if (_this.points) { | |
| _this.points.push(_this.maybePoint); | |
| } else { | |
| _this.points = [_this.maybePoint]; | |
| } | |
| _this.maybePoint = { | |
| x: _this.maybePoint.x, | |
| y: _this.maybePoint.y | |
| }; | |
| lc.setShapesInProgress(_this._getShapes(lc)); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this); | |
| onMove = (function(_this) { | |
| return function(_arg) { | |
| var x, y; | |
| x = _arg.x, y = _arg.y; | |
| if (_this.maybePoint) { | |
| _this.maybePoint.x = x; | |
| _this.maybePoint.y = y; | |
| lc.setShapesInProgress(_this._getShapes(lc)); | |
| return lc.repaintLayer('main'); | |
| } | |
| }; | |
| })(this); | |
| onDown = (function(_this) { | |
| return function(_arg) { | |
| var x, y; | |
| x = _arg.x, y = _arg.y; | |
| _this.maybePoint = { | |
| x: x, | |
| y: y | |
| }; | |
| lc.setShapesInProgress(_this._getShapes(lc)); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this); | |
| unsubscribeFuncs.push(lc.on('pointerdown', onDown)); | |
| unsubscribeFuncs.push(lc.on('pointerdrag', onMove)); | |
| unsubscribeFuncs.push(lc.on('pointermove', onMove)); | |
| return unsubscribeFuncs.push(lc.on('pointerup', onUp)); | |
| }; | |
| Pencil.prototype.willBecomeInactive = function(lc) { | |
| return this.unsubscribe(); | |
| }; | |
| Pencil.prototype._getArePointsClose = function(a, b) { | |
| return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) < 10; | |
| }; | |
| Pencil.prototype._getWillClose = function() { | |
| if (!(this.points && this.points.length > 1)) { | |
| return false; | |
| } | |
| if (!this.maybePoint) { | |
| return false; | |
| } | |
| return this._getArePointsClose(this.points[0], this.maybePoint); | |
| }; | |
| Pencil.prototype._getWillFinish = function() { | |
| if (!(this.points && this.points.length > 1)) { | |
| return false; | |
| } | |
| if (!this.maybePoint) { | |
| return false; | |
| } | |
| return this._getArePointsClose(this.points[0], this.maybePoint) || this._getArePointsClose(this.points[this.points.length - 1], this.maybePoint); | |
| }; | |
| Pencil.prototype._close = function(lc) { | |
| lc.setShapesInProgress([]); | |
| if (this.points.length > 2) { | |
| lc.saveShape(this._getShape(lc, false)); | |
| } | |
| this.maybePoint = null; | |
| return this.points = null; | |
| }; | |
| Pencil.prototype._getShapes = function(lc, isInProgress) { | |
| var shape; | |
| if (isInProgress == null) { | |
| isInProgress = true; | |
| } | |
| shape = this._getShape(lc, isInProgress); | |
| if (shape) { | |
| return [shape]; | |
| } else { | |
| return []; | |
| } | |
| }; | |
| Pencil.prototype._getShape = function(lc, isInProgress) { | |
| var points; | |
| if (isInProgress == null) { | |
| isInProgress = true; | |
| } | |
| points = []; | |
| if (this.points) { | |
| points = points.concat(this.points); | |
| } | |
| if ((!isInProgress) && points.length < 3) { | |
| return null; | |
| } | |
| if (isInProgress && this.maybePoint) { | |
| points.push(this.maybePoint); | |
| } | |
| if (points.length > 1) { | |
| return createShape('Polygon', { | |
| isClosed: this._getWillClose(), | |
| strokeColor: lc.getColor('primary'), | |
| fillColor: lc.getColor('secondary'), | |
| strokeWidth: this.strokeWidth, | |
| points: points.map(function(xy) { | |
| return createShape('Point', xy); | |
| }) | |
| }); | |
| } else { | |
| return null; | |
| } | |
| }; | |
| return Pencil; | |
| })(ToolWithStroke); | |
| },{"../core/shapes":11,"./base":42}],40:[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":11,"./base":42}],41:[function(_dereq_,module,exports){ | |
| var Text, Tool, createShape, getIsPointInBox, | |
| __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; | |
| getIsPointInBox = function(point, box) { | |
| if (point.x < box.x) { | |
| return false; | |
| } | |
| if (point.y < box.y) { | |
| return false; | |
| } | |
| if (point.x > box.x + box.width) { | |
| return false; | |
| } | |
| if (point.y > box.y + box.height) { | |
| return false; | |
| } | |
| return true; | |
| }; | |
| 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'; | |
| this.currentShape = null; | |
| this.currentShapeState = null; | |
| this.initialShapeBoundingRect = null; | |
| this.dragAction = null; | |
| this.didDrag = false; | |
| } | |
| Text.prototype.didBecomeActive = function(lc) { | |
| var switchAway, unsubscribeFuncs, updateInputEl; | |
| unsubscribeFuncs = []; | |
| this.unsubscribe = (function(_this) { | |
| return function() { | |
| var func, _i, _len, _results; | |
| _results = []; | |
| for (_i = 0, _len = unsubscribeFuncs.length; _i < _len; _i++) { | |
| func = unsubscribeFuncs[_i]; | |
| _results.push(func()); | |
| } | |
| return _results; | |
| }; | |
| })(this); | |
| switchAway = (function(_this) { | |
| return function() { | |
| _this._ensureNotEditing(lc); | |
| _this._clearCurrentShape(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this); | |
| updateInputEl = (function(_this) { | |
| return function() { | |
| return _this._updateInputEl(lc); | |
| }; | |
| })(this); | |
| unsubscribeFuncs.push(lc.on('undo', switchAway)); | |
| unsubscribeFuncs.push(lc.on('redo', switchAway)); | |
| unsubscribeFuncs.push(lc.on('zoom', updateInputEl)); | |
| unsubscribeFuncs.push(lc.on('imageSizeChange', updateInputEl)); | |
| unsubscribeFuncs.push(lc.on('snapshotLoad', (function(_this) { | |
| return function() { | |
| _this._clearCurrentShape(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this))); | |
| unsubscribeFuncs.push(lc.on('primaryColorChange', (function(_this) { | |
| return function(newColor) { | |
| if (!_this.currentShape) { | |
| return; | |
| } | |
| _this.currentShape.color = newColor; | |
| _this._updateInputEl(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this))); | |
| return unsubscribeFuncs.push(lc.on('setFont', (function(_this) { | |
| return function(font) { | |
| if (!_this.currentShape) { | |
| return; | |
| } | |
| _this.font = font; | |
| _this.currentShape.setFont(font); | |
| _this._setShapesInProgress(lc); | |
| _this._updateInputEl(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| })(this))); | |
| }; | |
| Text.prototype.willBecomeInactive = function(lc) { | |
| if (this.currentShape) { | |
| this._ensureNotEditing(lc); | |
| this.commit(lc); | |
| } | |
| return this.unsubscribe(); | |
| }; | |
| Text.prototype.setText = function(text) { | |
| return this.text = text; | |
| }; | |
| Text.prototype._ensureNotEditing = function(lc) { | |
| if (this.currentShapeState === 'editing') { | |
| return this._exitEditingState(lc); | |
| } | |
| }; | |
| Text.prototype._clearCurrentShape = function(lc) { | |
| this.currentShape = null; | |
| this.initialShapeBoundingRect = null; | |
| this.currentShapeState = null; | |
| return lc.setShapesInProgress([]); | |
| }; | |
| Text.prototype.commit = function(lc) { | |
| if (this.currentShape.text) { | |
| lc.saveShape(this.currentShape); | |
| } | |
| this._clearCurrentShape(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| Text.prototype._getSelectionShape = function(ctx, backgroundColor) { | |
| if (backgroundColor == null) { | |
| backgroundColor = null; | |
| } | |
| return createShape('SelectionBox', { | |
| shape: this.currentShape, | |
| ctx: ctx, | |
| backgroundColor: backgroundColor | |
| }); | |
| }; | |
| Text.prototype._setShapesInProgress = function(lc) { | |
| switch (this.currentShapeState) { | |
| case 'selected': | |
| return lc.setShapesInProgress([this._getSelectionShape(lc.ctx), this.currentShape]); | |
| case 'editing': | |
| return lc.setShapesInProgress([this._getSelectionShape(lc.ctx, '#fff')]); | |
| default: | |
| return lc.setShapesInProgress([this.currentShape]); | |
| } | |
| }; | |
| Text.prototype.begin = function(x, y, lc) { | |
| var br, point, selectionBox, selectionShape; | |
| this.dragAction = 'none'; | |
| this.didDrag = false; | |
| if (this.currentShapeState === 'selected' || this.currentShapeState === 'editing') { | |
| br = this.currentShape.getBoundingRect(lc.ctx); | |
| selectionShape = this._getSelectionShape(lc.ctx); | |
| selectionBox = selectionShape.getBoundingRect(); | |
| point = { | |
| x: x, | |
| y: y | |
| }; | |
| if (getIsPointInBox(point, br)) { | |
| this.dragAction = 'move'; | |
| } | |
| if (getIsPointInBox(point, selectionShape.getBottomRightHandleRect())) { | |
| this.dragAction = 'resizeBottomRight'; | |
| } | |
| if (getIsPointInBox(point, selectionShape.getTopLeftHandleRect())) { | |
| this.dragAction = 'resizeTopLeft'; | |
| } | |
| if (getIsPointInBox(point, selectionShape.getBottomLeftHandleRect())) { | |
| this.dragAction = 'resizeBottomLeft'; | |
| } | |
| if (getIsPointInBox(point, selectionShape.getTopRightHandleRect())) { | |
| this.dragAction = 'resizeTopRight'; | |
| } | |
| if (this.dragAction === 'none' && this.currentShapeState === 'editing') { | |
| this.dragAction = 'stop-editing'; | |
| this._exitEditingState(lc); | |
| } | |
| } else { | |
| this.color = lc.getColor('primary'); | |
| this.currentShape = createShape('Text', { | |
| x: x, | |
| y: y, | |
| text: this.text, | |
| color: this.color, | |
| font: this.font, | |
| v: 1 | |
| }); | |
| this.dragAction = 'place'; | |
| this.currentShapeState = 'selected'; | |
| } | |
| if (this.dragAction === 'none') { | |
| this.commit(lc); | |
| return; | |
| } | |
| this.initialShapeBoundingRect = this.currentShape.getBoundingRect(lc.ctx); | |
| this.dragOffset = { | |
| x: x - this.initialShapeBoundingRect.x, | |
| y: y - this.initialShapeBoundingRect.y | |
| }; | |
| this._setShapesInProgress(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| Text.prototype["continue"] = function(x, y, lc) { | |
| var br, brBottom, brRight; | |
| if (this.dragAction === 'none') { | |
| return; | |
| } | |
| br = this.initialShapeBoundingRect; | |
| brRight = br.x + br.width; | |
| brBottom = br.y + br.height; | |
| switch (this.dragAction) { | |
| case 'place': | |
| this.currentShape.x = x; | |
| this.currentShape.y = y; | |
| this.didDrag = true; | |
| break; | |
| case 'move': | |
| this.currentShape.x = x - this.dragOffset.x; | |
| this.currentShape.y = y - this.dragOffset.y; | |
| this.didDrag = true; | |
| break; | |
| case 'resizeBottomRight': | |
| this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); | |
| break; | |
| case 'resizeTopLeft': | |
| this.currentShape.setSize(brRight - x + this.dragOffset.x, brBottom - y + this.dragOffset.y); | |
| this.currentShape.setPosition(x - this.dragOffset.x, y - this.dragOffset.y); | |
| break; | |
| case 'resizeBottomLeft': | |
| this.currentShape.setSize(brRight - x + this.dragOffset.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); | |
| this.currentShape.setPosition(x - this.dragOffset.x, this.currentShape.y); | |
| break; | |
| case 'resizeTopRight': | |
| this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, brBottom - y + this.dragOffset.y); | |
| this.currentShape.setPosition(this.currentShape.x, y - this.dragOffset.y); | |
| } | |
| this._setShapesInProgress(lc); | |
| lc.repaintLayer('main'); | |
| return this._updateInputEl(lc); | |
| }; | |
| Text.prototype.end = function(x, y, lc) { | |
| if (!this.currentShape) { | |
| return; | |
| } | |
| this.currentShape.setSize(this.currentShape.forcedWidth, 0); | |
| if (this.currentShapeState === 'selected') { | |
| if (this.dragAction === 'place' || (this.dragAction === 'move' && !this.didDrag)) { | |
| this._enterEditingState(lc); | |
| } | |
| } | |
| this._setShapesInProgress(lc); | |
| lc.repaintLayer('main'); | |
| return this._updateInputEl(lc); | |
| }; | |
| Text.prototype._enterEditingState = function(lc) { | |
| var onChange; | |
| this.currentShapeState = 'editing'; | |
| if (this.inputEl) { | |
| throw "State error"; | |
| } | |
| this.inputEl = document.createElement('textarea'); | |
| this.inputEl.className = 'text-tool-input'; | |
| this.inputEl.style.position = 'absolute'; | |
| this.inputEl.style.transformOrigin = '0px 0px'; | |
| this.inputEl.style.backgroundColor = 'transparent'; | |
| this.inputEl.style.border = 'none'; | |
| this.inputEl.style.outline = 'none'; | |
| this.inputEl.style.margin = '0'; | |
| this.inputEl.style.padding = '4px'; | |
| this.inputEl.style.zIndex = '1000'; | |
| this.inputEl.style.overflow = 'hidden'; | |
| this.inputEl.style.resize = 'none'; | |
| this.inputEl.value = this.currentShape.text; | |
| this.inputEl.addEventListener('mousedown', function(e) { | |
| return e.stopPropagation(); | |
| }); | |
| this.inputEl.addEventListener('touchstart', function(e) { | |
| return e.stopPropagation(); | |
| }); | |
| onChange = (function(_this) { | |
| return function(e) { | |
| _this.currentShape.setText(e.target.value); | |
| _this.currentShape.enforceMaxBoundingRect(lc); | |
| _this._setShapesInProgress(lc); | |
| lc.repaintLayer('main'); | |
| _this._updateInputEl(lc); | |
| return e.stopPropagation(); | |
| }; | |
| })(this); | |
| this.inputEl.addEventListener('keydown', (function(_this) { | |
| return function() { | |
| return _this._updateInputEl(lc, true); | |
| }; | |
| })(this)); | |
| this.inputEl.addEventListener('keyup', onChange); | |
| this.inputEl.addEventListener('change', onChange); | |
| this._updateInputEl(lc); | |
| lc.containerEl.appendChild(this.inputEl); | |
| this.inputEl.focus(); | |
| return this._setShapesInProgress(lc); | |
| }; | |
| Text.prototype._exitEditingState = function(lc) { | |
| this.currentShapeState = 'selected'; | |
| lc.containerEl.removeChild(this.inputEl); | |
| this.inputEl = null; | |
| this._setShapesInProgress(lc); | |
| return lc.repaintLayer('main'); | |
| }; | |
| Text.prototype._updateInputEl = function(lc, withMargin) { | |
| var br, transformString; | |
| if (withMargin == null) { | |
| withMargin = false; | |
| } | |
| if (!this.inputEl) { | |
| return; | |
| } | |
| br = this.currentShape.getBoundingRect(lc.ctx, true); | |
| this.inputEl.style.font = this.currentShape.font; | |
| this.inputEl.style.color = this.currentShape.color; | |
| this.inputEl.style.left = "" + (lc.position.x / lc.backingScale + br.x * lc.scale - 4) + "px"; | |
| this.inputEl.style.top = "" + (lc.position.y / lc.backingScale + br.y * lc.scale - 4) + "px"; | |
| if (withMargin && !this.currentShape.forcedWidth) { | |
| this.inputEl.style.width = "" + (br.width + 10 + this.currentShape.renderer.emDashWidth) + "px"; | |
| } else { | |
| this.inputEl.style.width = "" + (br.width + 12) + "px"; | |
| } | |
| if (withMargin) { | |
| this.inputEl.style.height = "" + (br.height + 10 + this.currentShape.renderer.metrics.leading) + "px"; | |
| } else { | |
| this.inputEl.style.height = "" + (br.height + 10) + "px"; | |
| } | |
| transformString = "scale(" + lc.scale + ")"; | |
| this.inputEl.style.transform = transformString; | |
| this.inputEl.style.webkitTransform = transformString; | |
| this.inputEl.style.MozTransform = transformString; | |
| this.inputEl.style.msTransform = transformString; | |
| return this.inputEl.style.OTransform = transformString; | |
| }; | |
| Text.prototype.optionsStyle = 'font'; | |
| return Text; | |
| })(Tool); | |
| },{"../core/shapes":11,"./base":42}],42:[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.usesSimpleAPI = true; | |
| 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; | |
| Tool.prototype.didBecomeActive = function(lc) {}; | |
| Tool.prototype.willBecomeInactive = function(lc) {}; | |
| 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; | |
| },{}]},{},[16]) | |
| (16) | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment