' + status.message;\n\t if (status.commit) {\n\t html += '';\n\t }\n\t html += '
';\n\t el.innerHTML = html;\n\t }\n\t\n\t el.style.display = status ? 'inline' : 'none';\n\t },\n\t\n\t //----------------------------------------------------------------\n\t\n\t\n\t // [TODO] Plugin.Tooltip, only used by the Head Up Display, move this there\n\t //----------------------------------------------------------------\n\t\n\t initTooltip: function () {\n\t var tooltipId = this.container.id + \"_tooltip\";\n\t _util.g$.append(this.container, '');\n\t this._tooltipEl = (0, _util.g$)(\"#\" + tooltipId);\n\t },\n\t showTooltip: function (message, point) {\n\t var tel = this._tooltipEl;\n\t if (tel) {\n\t this.hideTooltip();\n\t var cp = point.x < 300 ? _cdl.Point.add(point, new _cdl.Point(20, 10)) : _cdl.Point.add(point, new _cdl.Point(-message.length * 6 - 18, 0));\n\t if (point.y > 400) {\n\t cp.y -= 40;\n\t }\n\t tel.innerHTML = message;\n\t\n\t (0, _lodash.assign)(tel.style, {\n\t 'left': cp.x + 'px',\n\t 'top': cp.y + 'px',\n\t 'display': 'block'\n\t });\n\t\n\t this._tooltipVisible = true;\n\t }\n\t },\n\t hideTooltip: function () {\n\t if (this._tooltipVisible) {\n\t var tel = this._tooltipEl;\n\t if (tel) {\n\t tel.style.display = 'none';\n\t this._tooltipVisible = false;\n\t }\n\t }\n\t }\n\t};\n\n/***/ },\n\n/***/ 102:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar _colorShowthrough = __webpack_require__(103);\n\t\n\t_view.Plugin.ActiveRenderer = _view.Plugin.extend({ typeName: 'ActiveRendererPlugin',\n\t name: 'renderer',\n\t\n\t target: 'document',\n\t\n\t drawTo_color: ['background', 'document', 'foreground'],\n\t\n\t redrawFigure: function (view, figure) {\n\t if ((0, _lodash.includes)(view._activeFigures, figure)) {\n\t view.redraw('document');\n\t } else {\n\t if (figure.document === view._mainDocument) {\n\t view.redraw('document');\n\t } else {\n\t view.redraw('background');\n\t }\n\t }\n\t },\n\t\n\t\n\t // Draw everything that is behind the first active figure\n\t draw_background: function (_ref) {\n\t var view = _ref.view;\n\t var context = _ref.context;\n\t var transform = _ref.transform;\n\t\n\t view.fillWithBackgroundColor(context);\n\t\n\t var firstActiveFigure = view._activeFigures[0];\n\t var lastFigure = firstActiveFigure || 'doc';\n\t\n\t this.drawFigures(view, context, transform, {\n\t until: lastFigure\n\t });\n\t },\n\t\n\t\n\t // draw active figures, or current document\n\t draw_document: function (_ref2) {\n\t var view = _ref2.view;\n\t var context = _ref2.context;\n\t var transform = _ref2.transform;\n\t\n\t var activeFigures = view._activeFigures;\n\t if (activeFigures.length > 0) {\n\t var alpha = this._activeAlpha;\n\t if (alpha === 0) {\n\t return;\n\t }\n\t if (alpha !== undefined && alpha < 1) {\n\t context.globalAlpha *= alpha;\n\t }\n\t }\n\t\n\t var firstActiveFigure = activeFigures[0] || 'doc';\n\t var lastActiveFigure = (0, _lodash.last)(activeFigures);\n\t\n\t (0, _colorShowthrough.draw_colorShowthrough_gl)(view, context, transform, this, firstActiveFigure, lastActiveFigure);\n\t\n\t if (activeFigures.length === 0) {\n\t this.drawSpecialPens(view, context, transform);\n\t }\n\t },\n\t\n\t\n\t // In case there are active figures, draw everything above them\n\t draw_foreground: function (_ref3) {\n\t var view = _ref3.view;\n\t var context = _ref3.context;\n\t var transform = _ref3.transform;\n\t\n\t var activeFigures = view._activeFigures;\n\t if (activeFigures.length === 0) {\n\t // clearContext(context);\n\t return;\n\t }\n\t\n\t var lastActiveFigure = (0, _lodash.last)(activeFigures);\n\t var firstFigure = lastActiveFigure || 'doc';\n\t\n\t this.drawFigures(view, context, transform, {\n\t from: firstFigure, skipFirst: true\n\t });\n\t\n\t this.drawSpecialPens(view, context, transform);\n\t },\n\t drawSpecialPens: function (view, context, transform) {\n\t var specialPens = view.specialPens;\n\t\n\t if (specialPens) {\n\t specialPens.drawForPage(view._mainDocument.activePage, context, transform);\n\t }\n\t },\n\t drawFigures: function (view, context, transform, span) {\n\t var clearBuffer = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];\n\t var drawShowthroughMask = arguments.length <= 5 || arguments[5] === undefined ? false : arguments[5];\n\t var from = span.from;\n\t\n\t var drawing = { start: !from || from === 'doc', end: false };\n\t var config = { editingContent: view._mainDocument.editingContent() };\n\t\n\t var page = view._mainDocument.activePage;\n\t\n\t var backgroundPage = view.backgroundPageFor(page);\n\t if (backgroundPage && from !== 'doc') {\n\t this.drawPage(view, backgroundPage, context, transform, config, span, drawing, clearBuffer, drawShowthroughMask);\n\t }\n\t\n\t if (drawing.end || span.until === 'doc') {\n\t return false;\n\t }\n\t\n\t this.drawPage(view, page, context, transform, config, span, drawing, clearBuffer, drawShowthroughMask);\n\t },\n\t drawPage: function (view, page, context, transform, config, _ref4, drawing) {\n\t var from = _ref4.from;\n\t var skipFirst = _ref4.skipFirst;\n\t var until = _ref4.until;\n\t var includeLast = _ref4.includeLast;\n\t var clearBuffer = arguments.length <= 7 || arguments[7] === undefined ? false : arguments[7];\n\t var drawShowthroughMask = arguments.length <= 8 || arguments[8] === undefined ? false : arguments[8];\n\t\n\t\n\t config = (0, _lodash.assign)({ wireframe: view.wireframe }, config);\n\t config = (0, _lodash.assign)({ showthroughColor: view.showThroughColor }, config);\n\t (0, _lodash.forEach)(page.layers, function (layer) {\n\t\n\t // This is not the best for this pattern, but we may remove the\n\t // isolated figures pattern soon.\n\t layer.beforeDraw(context, config);\n\t\n\t (0, _lodash.forEach)(layer.figures, function (figure) {\n\t if (!skipFirst && from === figure) {\n\t drawing.start = true;\n\t }\n\t if (!includeLast && until === figure) {\n\t drawing.end = true;\n\t }\n\t\n\t if (drawing.start && !drawing.end) {\n\t\n\t var figureView = view.figureView(figure);\n\t if (figureView) {\n\t figureView.draw(context, transform, config, clearBuffer, drawShowthroughMask);\n\t } else {\n\t console.log('[Error] FigureView is undefined');\n\t }\n\t\n\t if (view._showPin) {\n\t (0, _gear.dot)(context, figure.pin, 3, transform, '#ffffff', '#222222', 4);\n\t }\n\t }\n\t\n\t if (skipFirst && from === figure) {\n\t drawing.start = true;\n\t }\n\t if (includeLast && until === figure) {\n\t drawing.end = true;\n\t }\n\t\n\t if (drawing.end) {\n\t return false;\n\t }\n\t });\n\t\n\t layer.afterDraw(context, config); // [TODO]\n\t\n\t if (drawing.end) {\n\t return false;\n\t }\n\t });\n\t }\n\t});\n\n/***/ },\n\n/***/ 103:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.draw_colorShowthrough_gl = undefined;\n\t\n\tvar _config = __webpack_require__(2);\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _geometry = __webpack_require__(21);\n\t\n\tvar _color = __webpack_require__(31);\n\t\n\tvar _figure = __webpack_require__(35);\n\t\n\tvar _replaceST = __webpack_require__(104);\n\t\n\tfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\t\n\t// values between 0...255\n\t// map :: function(r,g,b,a){ return [ r*, g*, b*, a* ]; }\n\t\n\tvar modifyImageDataRGBA = function (imageData, map) {\n\t var extended = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];\n\t\n\t var data = imageData.data,\n\t width = imageData.width,\n\t height = imageData.height;\n\t var y = void 0,\n\t x = void 0,\n\t inpos = void 0,\n\t outpos = void 0,\n\t r = void 0,\n\t g = void 0,\n\t b = void 0,\n\t a = void 0;\n\t\n\t for (y = 0; y < height; ++y) {\n\t inpos = y * width * 4; // *4 for 4 ints per pixel\n\t outpos = inpos;\n\t for (x = 0; x < width; ++x) {\n\t\n\t r = data[inpos++];\n\t g = data[inpos++];\n\t b = data[inpos++];\n\t a = data[inpos++]; // alpha\n\t\n\t // http://www.w3.org/TR/AERT#color-contrast\n\t var c = map(r, g, b, a);\n\t\n\t data[outpos++] = c[0];\n\t data[outpos++] = c[1];\n\t data[outpos++] = c[2];\n\t data[outpos++] = c[3];\n\t\n\t if (extended && !(c[0] == 10 && c[1] == 10 && c[2] == 10 && c[3] == 0)) {\n\t var currentPos = outpos - 4;\n\t var done = false;\n\t\n\t for (var i = 1; i < 3; ++i) {\n\t if (x < width - i) {\n\t var c2 = map(data[inpos++], data[inpos++], data[inpos++], data[inpos++]);\n\t if (c2[0] == 10 && c2[1] == 10 && c2[2] == 10 && c2[3] == 0) {\n\t outpos -= 4;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t done = true;\n\t break;\n\t }\n\t }\n\t }for (var _i = 1; _i < 3; ++_i) {\n\t if (!done && x >= _i) {\n\t inpos = currentPos - 4 * _i;\n\t var c3 = map(data[inpos++], data[inpos++], data[inpos++], data[inpos++]);\n\t if (c3[0] == 10 && c3[1] == 10 && c3[2] == 10 && c3[3] == 0) {\n\t outpos -= 4;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t break;\n\t }\n\t }\n\t }for (var _i2 = 1; _i2 < 3; ++_i2) {\n\t if (y < height - _i2) {\n\t inpos = currentPos + 4 * _i2 * width;\n\t var _c = map(data[inpos++], data[inpos++], data[inpos++], data[inpos++]);\n\t if (_c[0] == 10 && _c[1] == 10 && _c[2] == 10 && _c[3] == 0) {\n\t outpos -= 4;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t done = true;\n\t break;\n\t }\n\t }\n\t }for (var _i3 = 1; _i3 < 3; ++_i3) {\n\t if (y >= _i3) {\n\t inpos = currentPos - 4 * _i3 * width;\n\t var _c2 = map(data[inpos++], data[inpos++], data[inpos++], data[inpos++]);\n\t if (_c2[0] == 10 && _c2[1] == 10 && _c2[2] == 10 && _c2[3] == 0) {\n\t outpos -= 4;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t data[outpos++] = 0;\n\t done = true;\n\t break;\n\t }\n\t }\n\t }outpos = currentPos + 4;\n\t inpos = currentPos + 4;\n\t }\n\t }\n\t }\n\t};\n\t\n\t// ColorShowthrough\n\t//======================================================================================\n\tvar draw_colorShowthrough = function (view, context, transform, renderer, firstActiveFigure, lastActiveFigure) {\n\t var _this = this;\n\t\n\t var lAvoidSlowST = _config.Config.avoidRenderingShowThroughNoGL;\n\t\n\t var lSTColors = [];\n\t\n\t if (!lAvoidSlowST) {\n\t var page = view._mainDocument.activePage;\n\t (0, _lodash.forEach)(page.layers, function (layer) {\n\t _figure.Figures.forEachColor(layer.figures, function (c) {\n\t if (c && c.showThrough && !lSTColors.indexOf(c) >= 0) {\n\t lSTColors.push(c);\n\t }\n\t });\n\t });\n\t }\n\t\n\t if (lSTColors.length > 0 && !lAvoidSlowST) {\n\t var canvas = document.createElement('canvas');\n\t canvas.width = view.width;\n\t canvas.height = view.height;\n\t var ctx = canvas.getContext('2d');\n\t\n\t renderer.drawFigures(view, ctx, transform, {\n\t from: firstActiveFigure,\n\t until: lastActiveFigure, includeLast: true\n\t });\n\t\n\t var lImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\t\n\t modifyImageDataRGBA(lImageData, function (r, g, b, a) {\n\t var lRet = [r, g, b, a];\n\t lSTColors.forEach(function (c) {\n\t if (c.r() == r && c.g() == g && c.b() == b) lRet = [10, 10, 10, 0];\n\t }, _this);\n\t return lRet;\n\t }, true);\n\t\n\t context.putImageData(lImageData, 0, 0);\n\t } else {\n\t renderer.drawFigures(view, context, transform, {\n\t from: firstActiveFigure,\n\t until: lastActiveFigure, includeLast: true\n\t });\n\t }\n\t};\n\t\n\t// ColorShowthrough\n\t//======================================================================================\n\tvar mGlCanvas = null;\n\tvar mGlCtx = null;\n\tvar mEffect = null;\n\tvar mCanvasST = null;\n\tvar mCanvasNormal = null;\n\t\n\tvar draw_colorShowthrough_gl = exports.draw_colorShowthrough_gl = function (view, context, transform, renderer, firstActiveFigure, lastActiveFigure) {\n\t var lHasST = false;\n\t var lNeedsBufferClear = false;\n\t var page = view._mainDocument.activePage;\n\t\n\t var lNrLayers = page.layers.length;\n\t\n\t for (var iLayer = 0; !lHasST && iLayer < lNrLayers; iLayer++) {\n\t var lLayer = page.layers[iLayer];\n\t var lFigures = lLayer.figures;\n\t var lNrFigures = lFigures.length;\n\t for (var k = 0; !lHasST && k < lNrFigures; k++) {\n\t var lColors = lFigures[k].getColors();\n\t var lNrColors = lColors.length;\n\t for (var i = 0; !lHasST && i < lNrColors; i++) {\n\t if (lColors[i].showThrough) {\n\t lHasST = true;\n\t }\n\t }\n\t }\n\t }\n\t\n\t var lShowThroughColor = view.showThroughColor;\n\t if (lShowThroughColor.alpha != 0.0) {\n\t lNeedsBufferClear = true;\n\t lHasST = false;\n\t }\n\t\n\t if (lHasST) {\n\t if (mGlCanvas == null) {\n\t mCanvasST = document.createElement('canvas');\n\t mCanvasNormal = document.createElement('canvas');\n\t mGlCanvas = document.createElement('canvas');\n\t mGlCtx = mGlCanvas.getContext('webgl', { premultipliedAlpha: false });\n\t\n\t if (mGlCtx != null) {\n\t mGlCtx.pixelStorei(mGlCtx.UNPACK_ALIGNMENT, 1);\n\t mEffect = new _replaceST.ReplaceSTEffect(mGlCtx);\n\t\n\t //pass in clipspace coordiantes to vertex shader\n\t var lPositionsBuffer = mGlCtx.createBuffer();\n\t mGlCtx.bindBuffer(mGlCtx.ARRAY_BUFFER, lPositionsBuffer);\n\t mGlCtx.bufferData(mGlCtx.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]), mGlCtx.STATIC_DRAW);\n\t\n\t //pass in texture coordinates to vertext shader\n\t var lTexCoordBuffer = mGlCtx.createBuffer();\n\t mGlCtx.bindBuffer(mGlCtx.ARRAY_BUFFER, lTexCoordBuffer);\n\t mGlCtx.bufferData(mGlCtx.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), mGlCtx.STATIC_DRAW);\n\t\n\t //pass in clipspace coordiantes to vertex shader\n\t mGlCtx.bindBuffer(mGlCtx.ARRAY_BUFFER, lPositionsBuffer);\n\t mGlCtx.enableVertexAttribArray(mEffect.a_position);\n\t mGlCtx.vertexAttribPointer(mEffect.a_position, 2, mGlCtx.FLOAT, false, 0, 0);\n\t\n\t //pass in texture coordinates to vertext shader\n\t mGlCtx.bindBuffer(mGlCtx.ARRAY_BUFFER, lTexCoordBuffer);\n\t mGlCtx.enableVertexAttribArray(mEffect.a_texCoord);\n\t mGlCtx.vertexAttribPointer(mEffect.a_texCoord, 2, mGlCtx.FLOAT, false, 0, 0);\n\t }\n\t }\n\t\n\t if (mGlCtx == null) {\n\t return draw_colorShowthrough(view, context, transform, renderer, firstActiveFigure, lastActiveFigure); //Fallback to slow implementation\n\t }\n\t var firstSemiTransparent = null;\n\t for (var _iLayer = 0; _iLayer < lNrLayers; _iLayer++) {\n\t var _lLayer = page.layers[_iLayer];\n\t var _lFigures = _lLayer.figures;\n\t var _lNrFigures = _lFigures.length;\n\t for (var _k = 0; _k < _lNrFigures; _k++) {\n\t var lFigure = _lFigures[_k];\n\t deepRasterOff(lFigure);\n\t\n\t if (firstSemiTransparent == null) {\n\t var _lColors = lFigure.getColors();\n\t _lColors = [].concat(_toConsumableArray(new Set(_lColors))); //remove duplicates\n\t var _lNrColors = _lColors.length;\n\t for (var _i4 = 0; _i4 < _lNrColors; _i4++) {\n\t if (_lColors[_i4].alpha > 0 && _lColors[_i4].alpha < 1) {\n\t firstSemiTransparent = lFigure;\n\t }\n\t }\n\t }\n\t }\n\t }\n\t var includeLast = firstSemiTransparent != null;\n\t var lastFigure = firstSemiTransparent != null ? firstSemiTransparent : lastActiveFigure;\n\t mCanvasST.width = view.width;\n\t mCanvasST.height = view.height;\n\t var ctxST = mCanvasST.getContext('2d');\n\t renderer.drawFigures(view, ctxST, transform, {\n\t from: firstActiveFigure,\n\t until: lastFigure, includeLast: includeLast\n\t }, true, true);\n\t\n\t for (var _iLayer2 = 0; _iLayer2 < lNrLayers; _iLayer2++) {\n\t var _lLayer2 = page.layers[_iLayer2];\n\t var _lFigures2 = _lLayer2.figures;\n\t var _lNrFigures2 = _lFigures2.length;\n\t for (var _k2 = 0; _k2 < _lNrFigures2; _k2++) {\n\t var _lFigure = _lFigures2[_k2];\n\t deepRasterOn(_lFigure);\n\t }\n\t }\n\t\n\t mCanvasNormal.width = view.width;\n\t mCanvasNormal.height = view.height;\n\t var ctx = mCanvasNormal.getContext('2d');\n\t ctx.imageSmoothingEnabled = false;\n\t renderer.drawFigures(view, ctx, transform, {\n\t from: firstActiveFigure,\n\t until: lastFigure, includeLast: includeLast\n\t }, true, false);\n\t\n\t ctx.imageSmoothingEnabled = true;\n\t\n\t mGlCanvas.width = view.width;\n\t mGlCanvas.height = view.height;\n\t mGlCtx.viewport(0, 0, mGlCanvas.width, mGlCanvas.height);\n\t\n\t var texture = mGlCtx.createTexture();\n\t mGlCtx.activeTexture(mGlCtx.TEXTURE0);\n\t mGlCtx.bindTexture(mGlCtx.TEXTURE_2D, texture);\n\t mGlCtx.texImage2D(mGlCtx.TEXTURE_2D, 0, mGlCtx.RGBA, mGlCtx.RGBA, mGlCtx.UNSIGNED_BYTE, mCanvasNormal);\n\t if (mGlCtx.getError() != mGlCtx.NO_ERROR) {\n\t return draw_colorShowthrough(view, context, transform, renderer, firstActiveFigure, lastActiveFigure); //Fallback to slow implementation\n\t }\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_WRAP_S, mGlCtx.CLAMP_TO_EDGE);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_WRAP_T, mGlCtx.CLAMP_TO_EDGE);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_MIN_FILTER, mGlCtx.NEAREST);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_MAG_FILTER, mGlCtx.NEAREST);\n\t\n\t var textureST = mGlCtx.createTexture();\n\t mGlCtx.activeTexture(mGlCtx.TEXTURE1);\n\t mGlCtx.bindTexture(mGlCtx.TEXTURE_2D, textureST);\n\t mGlCtx.texImage2D(mGlCtx.TEXTURE_2D, 0, mGlCtx.RGBA, mGlCtx.RGBA, mGlCtx.UNSIGNED_BYTE, mCanvasST);\n\t if (mGlCtx.getError() != mGlCtx.NO_ERROR) {\n\t return draw_colorShowthrough(view, context, transform, renderer, firstActiveFigure, lastActiveFigure); //Fallback to slow implementation\n\t }\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_WRAP_S, mGlCtx.CLAMP_TO_EDGE);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_WRAP_T, mGlCtx.CLAMP_TO_EDGE);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_MIN_FILTER, mGlCtx.NEAREST);\n\t mGlCtx.texParameteri(mGlCtx.TEXTURE_2D, mGlCtx.TEXTURE_MAG_FILTER, mGlCtx.NEAREST);\n\t\n\t mGlCtx.uniform2f(mEffect.u_textureSize, mGlCanvas.width, mGlCanvas.height);\n\t\n\t mGlCtx.drawArrays(mGlCtx.TRIANGLES, 0, 6);\n\t\n\t context.drawImage(mGlCanvas, 0, 0);\n\t\n\t //draw remaining semi transparent\n\t if (firstSemiTransparent != null) {\n\t renderer.drawFigures(view, context, transform, {\n\t from: firstSemiTransparent,\n\t until: lastActiveFigure, includeLast: true\n\t }, true, false);\n\t }\n\t\n\t if (view.figureAnnotations) {\n\t view.figureAnnotations.update$();\n\t }\n\t // Uncomment this for debugging intermediate steps\n\t // context.drawImage(mCanvasST, 0, 0);\n\t // context.drawImage(mCanvasNormal, 300, 0);\n\t // context.drawImage(mGlCanvas, 600, 0);\n\t } else {\n\t renderer.drawFigures(view, context, transform, {\n\t from: firstActiveFigure,\n\t until: lastActiveFigure, includeLast: true\n\t }, lNeedsBufferClear);\n\t if (lShowThroughColor.alpha != 0.0) {\n\t if (view.figureAnnotations) {\n\t view.figureAnnotations.update$();\n\t }\n\t }\n\t }\n\t};\n\t\n\tvar deepRasterOff = function (aFigure) {\n\t if (aFigure.isGroup) {\n\t for (var k = 0, kEnd = aFigure.figures.length; k < kEnd; ++k) {\n\t var f = aFigure.figures[k];\n\t deepRasterOff(f);\n\t }\n\t } else if (aFigure.isRaster && !aFigure.isMonochrome) {\n\t aFigure.oldLightShift = aFigure.lightShift;\n\t aFigure.lightShift = -1;\n\t } else if (aFigure.isMonochrome) {\n\t var lColors = aFigure.getColors();\n\t lColors = [].concat(_toConsumableArray(new Set(lColors))); //remove duplicates\n\t var lNrColors = lColors.length;\n\t for (var i = 0; i < lNrColors; i++) {\n\t lColors[i].oldRgb = lColors[i].rgb;\n\t if (lColors[i].showThrough) {\n\t lColors[i].rgb = 'FFFFFF';\n\t } else {\n\t lColors[i].rgb = '000000';\n\t }\n\t }\n\t }\n\t if (aFigure._powerClipContents.length > 0) {\n\t var pFigures = aFigure._powerClipContents[0]._figures;\n\t for (var _k3 = 0, _kEnd = pFigures.length; _k3 < _kEnd; ++_k3) {\n\t deepRasterOff(pFigures[_k3]);\n\t }\n\t }\n\t};\n\t\n\tvar deepRasterOn = function (aFigure) {\n\t if (aFigure.isGroup) {\n\t for (var k = 0, kEnd = aFigure.figures.length; k < kEnd; ++k) {\n\t var f = aFigure.figures[k];\n\t deepRasterOn(f);\n\t }\n\t } else if (aFigure.isRaster && !aFigure.isMonochrome) {\n\t aFigure.lightShift = aFigure.oldLightShift;\n\t } else if (aFigure.isMonochrome) {\n\t var lColors = aFigure.getColors();\n\t lColors = [].concat(_toConsumableArray(new Set(lColors))); //remove duplicates\n\t var lNrColors = lColors.length;\n\t for (var i = 0; i < lNrColors; i++) {\n\t lColors[i].rgb = lColors[i].oldRgb;\n\t }\n\t }\n\t if (aFigure._powerClipContents.length > 0) {\n\t var pFigures = aFigure._powerClipContents[0]._figures;\n\t for (var _k4 = 0, _kEnd2 = pFigures.length; _k4 < _kEnd2; ++_k4) {\n\t deepRasterOn(pFigures[_k4]);\n\t }\n\t }\n\t};\n\n/***/ },\n\n/***/ 104:\n/***/ function(module, exports, __webpack_require__) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.ReplaceSTEffect = undefined;\n\t\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\t\n\tvar _effect = __webpack_require__(64);\n\t\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\t\n\tfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\t\n\tfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\t\n\tvar ReplaceSTEffect = exports.ReplaceSTEffect = function (_Effect) {\n\t _inherits(ReplaceSTEffect, _Effect);\n\t\n\t function ReplaceSTEffect(aGl) {\n\t _classCallCheck(this, ReplaceSTEffect);\n\t\n\t var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(ReplaceSTEffect).call(this, aGl));\n\t\n\t _this.fragmentShader = \"\\n precision mediump float;\\n\\n uniform sampler2D u_image0;\\n uniform sampler2D u_image1;\\n uniform vec2 u_textureSize;\\n\\n // the texCoords passed in from the vertex shader.\\n varying vec2 v_texCoord;\\n \\n\\n void main() {\\n vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;\\n\\n vec4 bg = texture2D(u_image0, v_texCoord);\\n vec4 st = texture2D(u_image1, v_texCoord);\\n float alpha = st.b;\\n\\n if (alpha==1.0)\\n gl_FragColor = vec4( 0.0, 0.0, 0.0 , 0.0 );\\n else\\n gl_FragColor = vec4( bg.r, bg.g, bg.b , bg.a*(1.0-alpha) );\\n }\\n \";\n\t\n\t _this.vertexShader = \"\\n attribute vec2 a_position;\\n attribute vec2 a_texCoord;\\n varying vec2 v_texCoord;\\n void main() {\\n gl_Position = vec4(a_position * vec2(1,-1), 0, 1);\\n v_texCoord = a_texCoord;\\n }\\n \";\n\t\n\t _this.addShader(_this.vertexShader, _this.gl.VERTEX_SHADER);\n\t _this.addShader(_this.fragmentShader, _this.gl.FRAGMENT_SHADER);\n\t\n\t //link the program\n\t _this.gl.linkProgram(_this.program);\n\t\n\t //throw exception if program doesn't link\n\t if (!_this.gl.getProgramParameter(_this.program, _this.gl.LINK_STATUS)) {\n\t var lastError = _this.gl.getProgramInfoLog(_this.program);\n\t _this.gl.deleteProgram(_this.program);\n\t throw lastError;\n\t }\n\t\n\t _this.u_image0 = _this.gl.getUniformLocation(_this.program, \"u_image0\");\n\t _this.u_image1 = _this.gl.getUniformLocation(_this.program, \"u_image1\");\n\t _this.u_textureSize = _this.gl.getUniformLocation(_this.program, \"u_textureSize\");\n\t\n\t _this.a_position = _this.gl.getAttribLocation(_this.program, \"a_position\");\n\t _this.a_texCoord = _this.gl.getAttribLocation(_this.program, \"a_texCoord\");\n\t\n\t _this.activate();\n\t _this.gl.uniform1i(_this.u_image0, 0); // texture unit image\n\t _this.gl.uniform1i(_this.u_image1, 1); // texture unit image\n\t\n\t return _this;\n\t }\n\t\n\t _createClass(ReplaceSTEffect, [{\n\t key: \"update\",\n\t value: function update() {\n\t this.activate();\n\t }\n\t }]);\n\n\t return ReplaceSTEffect;\n\t}(_effect.Effect);\n\n/***/ },\n\n/***/ 105:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tfunction displayStroke(context) {\n\t (0, _gear.setLineDash)(context, [4, 4]);\n\t context.strokeStyle = 'rgba(0,0,0,1)';\n\t context.stroke();\n\t (0, _gear.setLineDash)(context, [0, 4, 4, 0]);\n\t context.strokeStyle = 'rgba(255,255,255,1)';\n\t context.stroke();\n\t}\n\t\n\t_view.Plugin.SpecialPens = _view.Plugin.extend({ typeName: 'SpecialPensPlugin',\n\t name: 'specialPens',\n\t drawTo: ['mask'],\n\t\n\t Properties: {\n\t // Show solid mask to get the exact mask color selected\n\t maskSolid: { type: 'boolean', def: true, onChange: _view.redraw_this },\n\t maskColor: { type: 'Color', def: _cdl.Color.Gray(), onChange: _view.redraw_this },\n\t maskAlpha: { type: 'number', def: '0.8', onChange: _view.redraw_this },\n\t maskVisible: { type: 'boolean', def: true, onChange: _view.redraw_this }\n\t },\n\t\n\t initPlugin: function () {\n\t this._maskDraw = false;\n\t },\n\t prepareMask: function () {\n\t if (this._maskDraw) {\n\t var maskCanvas = this.view.canvas('mask');\n\t (0, _gear.clearCanvas)(maskCanvas);\n\t }\n\t },\n\t drawForPage: function (page, context, transform) {\n\t var maskVisible = this._maskVisible;\n\t\n\t if (maskVisible) {\n\t this.prepareMask();\n\t }\n\t\n\t this.drawSpecialPensForPage(page, context, transform);\n\t\n\t if (maskVisible) {\n\t this.blitMask(context);\n\t }\n\t },\n\t drawMask: function (maskPolyregions, context, transform, box) {\n\t var maskContext = this.view.getContext('mask', '2d');\n\t if (maskPolyregions.length > 0) {\n\t maskContext.save();\n\t\n\t if (box) {\n\t maskContext.rect(box.lx, box.ly, box.width, box.height);\n\t maskContext.clip();\n\t }\n\t\n\t maskContext.fillStyle = this._maskColor.svgColor();\n\t\n\t (0, _lodash.forEach)(maskPolyregions, function (polyregion) {\n\t polyregion.draw(maskContext, transform, { customDraw: function (c) {\n\t return c.fill();\n\t } });\n\t });\n\t\n\t maskContext.restore();\n\t\n\t this._maskDraw = true;\n\t } else if (box === undefined && this._maskDraw) {\n\t this._maskDraw = false;\n\t (0, _gear.clearContext)(maskContext);\n\t }\n\t },\n\t drawSpecialPensForPage: function (page, context, transform, box) {\n\t var specialPensPolyregions = this.gatherSpecialPenPolyregionsFor(page);\n\t if (this._maskVisible) {\n\t this.drawMask(specialPensPolyregions.mask, context, transform, box);\n\t }\n\t this.drawDisplayPens(specialPensPolyregions.display, context, transform);\n\t },\n\t gatherSpecialPenPolyregionsFor: function (page) {\n\t var specialPenPolyregions = { mask: [], display: [] };\n\t page.forEachFigure(function (figure) {\n\t // We need to check if there are MaskPen or DisplayPen to collect them\n\t var output = figure._outputFigure;\n\t if (output) {\n\t output.deepForEachPolyregion(function (p) {\n\t var pen = p._pen;\n\t if (pen._type === 'DisplayPen') {\n\t specialPenPolyregions.display.push(p);\n\t } else if (pen._type === 'MaskPen') {\n\t specialPenPolyregions.mask.push(p);\n\t }\n\t });\n\t }\n\t });\n\t return specialPenPolyregions;\n\t },\n\t drawDisplayPens: function (displayPolyregions, context, transform) {\n\t if (displayPolyregions.length > 0) {\n\t\n\t context.save();\n\t\n\t context.lineWidth = 0;\n\t\n\t (0, _lodash.forEach)(displayPolyregions, function (polyregion) {\n\t polyregion.draw(context, transform, { customDraw: displayStroke });\n\t });\n\t\n\t context.restore();\n\t }\n\t },\n\t blitMask: function (context /*,transform*/) {\n\t if (this._maskDraw) {\n\t var maskContext = this.view.getContext('mask', '2d');\n\t maskContext.save();\n\t maskContext.fillStyle = this._maskColor.svgColor();\n\t maskContext.globalCompositeOperation = 'xor';\n\t (0, _gear.fillContext)(maskContext);\n\t maskContext.restore();\n\t\n\t context.save();\n\t context.globalAlpha = this._maskAlpha;\n\t context.drawImage(maskContext.canvas, 0, 0);\n\t context.restore();\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 106:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.UserLine = undefined;\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar UserLine = exports.UserLine = _gear.OwnedObject.extend({ typeName: 'UserLine',\n\t Properties: {\n\t snap: { type: 'boolean', def: true },\n\t position: { type: 'number', def: 0, onChange: _view.redraw_this },\n\t color: { type: 'Color', def: new _cdl.Color({ rgb: '805633', alpha: 0.75 }), onChange: _view.redraw_this }\n\t },\n\t clone: function () {\n\t return UserLine(this);\n\t },\n\t redraw: function () {\n\t var owner = this._owner;\n\t if (owner) {\n\t owner.redraw();\n\t }\n\t }\n\t});\n\t\n\t_view.Plugin.UserLines = _view.Plugin.extend({ typeName: 'UserLinesPlugin',\n\t\n\t drawTo: ['plugins'],\n\t\n\t name: 'userLines',\n\t\n\t Properties: {\n\t horizontalLines: { type: 'UserLine[]', def: [], onChange: _view.redraw_this },\n\t verticalLines: { type: 'UserLine[]', def: [], onChange: _view.redraw_this }\n\t },\n\t\n\t clone: function () {\n\t return _view.Plugin.UserLines(this);\n\t },\n\t draw: function (_ref) {\n\t var view = _ref.view;\n\t var context = _ref.context;\n\t var transformModel = _ref.transformModel;\n\t var _view$bounds = view.bounds;\n\t var lx = _view$bounds.lx;\n\t var ly = _view$bounds.ly;\n\t var hx = _view$bounds.hx;\n\t var hy = _view$bounds.hy;\n\t\n\t\n\t context.lineWidth = 1;\n\t\n\t (0, _lodash.forEach)(this._horizontalLines, function (userLine) {\n\t context.strokeStyle = userLine._color.rgba;\n\t var x = userLine.position;\n\t (0, _view.strokePixelCenterSegment)(context, new _cdl.Point(x, ly), new _cdl.Point(x, hy), transformModel);\n\t });\n\t\n\t (0, _lodash.forEach)(this._verticalLines, function (userLine) {\n\t context.strokeStyle = userLine._color.rgba;\n\t var y = userLine.position;\n\t (0, _view.strokePixelCenterSegment)(context, new _cdl.Point(lx, y), new _cdl.Point(hx, y), transformModel);\n\t });\n\t }\n\t});\n\t\n\t_view.Plugin.AlignmentLines = _view.Plugin.extend({ typeName: 'AlignmentLinesPlugin',\n\t\n\t drawTo: ['plugins'],\n\t name: 'alignmentLines',\n\t Properties: {\n\t snap: { type: 'boolean', def: false, onChange: _view.redraw_this }\n\t },\n\t clone: function () {\n\t return new _view.Plugin.AlignmentLines(this);\n\t },\n\t draw: function () /*{ view, context, transform }*/{\n\t // ... currently in Select Handles\n\t }\n\t});\n\n/***/ },\n\n/***/ 107:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\t_view.Plugin.FigureAnnotations = _view.Plugin.extend({ typeName: 'FigureAnnotationsPlugin',\n\t\n\t name: 'figureAnnotations',\n\t drawTo: ['plugins'],\n\t\n\t target: 'document',\n\t\n\t clone: function () {\n\t return _view.Plugin.FigureAnnotations(this);\n\t },\n\t initPlugin: function (view) {\n\t this._annotations = [];\n\t this._annotationsAreDraw = false;\n\t view.addEvents('annotationsupdated');\n\t\n\t // Forward functions, should we allow this?\n\t var _this = this;\n\t (0, _lodash.assign)(view, {\n\t annotate: function () /* ...params */{\n\t return _this.annotate.apply(_this, arguments);\n\t },\n\t unannotate: function () /* ...params */{\n\t return _this.unannotate.apply(_this, arguments);\n\t },\n\t clearAnnotations: function () /* ...params */{\n\t return _this.clearAnnotations.apply(_this, arguments);\n\t }\n\t });\n\t },\n\t link: function (view) {\n\t view.on('commit', this.generate_, this);\n\t },\n\t unlink: function (view) {\n\t view.un(this);\n\t },\n\t\n\t\n\t // annotate( figure, { message: 'Message', pen: ... } );\n\t // annotate( figures, { grouped: true, message: ... } );\n\t // annotate( function( figure ) { }, { message( figure ) {}, ... });\n\t // annotate( function( figure ) { }, function( figure ) {} );\n\t // annotate( function( figure ) { }, function( figure ) {} );\n\t //\n\t // view.unannotate( annotation );\n\t // view.clearAnnotations();\n\t\n\t annotate: function (figures, config) {\n\t var ann = { figures: figures, config: config };\n\t this._annotations.push(ann);\n\t this.update$();\n\t return ann;\n\t },\n\t unannotate: function (annotation) {\n\t var i = this._annotations.indexOf(annotation);\n\t if (i >= 0) {\n\t this._annotations.splice(i, 1);\n\t }\n\t this.update$();\n\t return this;\n\t },\n\t clearAnnotations: function () {\n\t this._annotations = [];\n\t this.update$();\n\t return this;\n\t },\n\t update$: function () {\n\t var _this2 = this;\n\t\n\t return this.view.doc.update$().then(function () {\n\t _this2.generate_();\n\t });\n\t },\n\t\n\t\n\t // Called after each commit$, or triggered by the user using update$\n\t\n\t addAnnotation: function (ann) {\n\t var _this3 = this;\n\t\n\t ann.ready = false;\n\t this._processedAnnotations.push(ann);\n\t (0, _gear.whenAll)([ann.text, ann.color, ann.pen, ann.brush]).then(function () {\n\t ann.ready = true;\n\t _this3.redraw();\n\t });\n\t },\n\t generate_: function () {\n\t var _this4 = this;\n\t\n\t var view = this.view,\n\t mainDocument = view._mainDocument || view.doc,\n\t backgroundDocument = view._background;\n\t this._processedAnnotations = [];\n\t (0, _lodash.forEach)(this._annotations, function (ann) {\n\t var c = ann.config;\n\t var textIsFunc = (0, _lodash.isFunction)(c.text);\n\t var colorIsFunc = (0, _lodash.isFunction)(c.color);\n\t var penIsFunc = (0, _lodash.isFunction)(c.pen);\n\t var brushIsFunc = (0, _lodash.isFunction)(c.brush);\n\t var boxStyle = c.boxStyle || 'Rect';\n\t\n\t var figures = ann.figures;\n\t var background = c.backgroundFigures;\n\t\n\t if (figures === 'all') {\n\t figures = mainDocument.activePageFigures;\n\t if (background) {\n\t figures = (0, _lodash.concat)(backgroundDocument.activePageFigures, figures);\n\t }\n\t } else if ((0, _lodash.isFunction)(figures)) {\n\t var func = figures;\n\t figures = (0, _lodash.filter)(mainDocument.activePageFigures, func);\n\t if (background) {\n\t figures = (0, _lodash.concat)((0, _lodash.filter)(backgroundDocument.activePageFigures, func), figures);\n\t }\n\t } else if (figures.isFigure) {\n\t figures = [figures];\n\t background = true;\n\t } else {\n\t ann.figures = (0, _gear.clone)(figures);\n\t background = true;\n\t }\n\t\n\t if (ann.grouped) {\n\t _this4.addAnnotation({\n\t figures: figures,\n\t text: textIsFunc ? c.text(figures) : c.text,\n\t color: colorIsFunc ? c.color(figures) : c.color,\n\t pen: penIsFunc ? c.pen(figures) : c.pen,\n\t brush: brushIsFunc ? c.brush(figures) : c.brush,\n\t boxStyle: boxStyle,\n\t background: background\n\t });\n\t } else {\n\t (0, _lodash.forEach)(figures, function (figure) {\n\t _this4.addAnnotation({\n\t figures: [figure],\n\t text: textIsFunc ? c.text(figure) : c.text,\n\t color: colorIsFunc ? c.color(figure) : c.color,\n\t pen: penIsFunc ? c.pen(figure) : c.pen,\n\t brush: brushIsFunc ? c.brush(figure) : c.brush,\n\t boxStyle: boxStyle,\n\t background: background\n\t });\n\t });\n\t }\n\t });\n\t this.redraw();\n\t },\n\t drawAnnotation: function (context, transform, ann, current, info) {\n\t var figures = ann.figures;\n\t var text = ann.text;\n\t var color = ann.color;\n\t var pen = ann.pen;\n\t var brush = ann.brush;\n\t var boxStyle = ann.boxStyle;\n\t\n\t var updated = false;\n\t\n\t var ready = (0, _lodash.every)(figures, function (figure) {\n\t return !figure.invalidated();\n\t });\n\t\n\t if (ready) {\n\t var bounds = _cdl.Figures.globalBounds_(figures).scalingTransformed(transform).inflated(1 + (pen ? pen.width : 0));\n\t if (pen || brush) {\n\t context.beginPath();\n\t if (boxStyle === 'Clean') {\n\t var lx = bounds.lx,\n\t ly = bounds.ly,\n\t hx = bounds.hx,\n\t hy = bounds.hy;\n\t var w = Math.min(10, bounds.width);\n\t\n\t context.moveTo(lx, ly + w);context.lineTo(lx, ly);context.lineTo(lx + w, ly);\n\t context.moveTo(hx - w, ly);context.lineTo(hx, ly);context.lineTo(hx, ly + w);\n\t context.moveTo(lx, hy - w);context.lineTo(lx, hy);context.lineTo(lx + w, hy);\n\t context.moveTo(hx, hy - w);context.lineTo(hx, hy);context.lineTo(hx - w, hy);\n\t } else {\n\t bounds.draw(context);\n\t }\n\t }\n\t if (pen) {\n\t pen.setupContext(context);\n\t context.stroke();\n\t }\n\t if (brush) {\n\t context.fillStyle = brush.color.rgba;\n\t context.fill();\n\t }\n\t if (text) {\n\t context.textBaseline = \"bottom\";\n\t context.textAlign = \"end\";\n\t context.fillStyle = color ? color.rgba : pen ? pen.color.rgba : '#000000';\n\t\n\t if (figures.length === 1) {\n\t // Allow several annotations per figure\n\t var figure = figures[0];\n\t var fa = current[figure._localId];\n\t if (!fa) {\n\t fa = current[figure._localId] = { count: 0 };\n\t }\n\t fa.count++;\n\t context.fillText(text, bounds.hx, bounds.ly - 2 * fa.count - (fa.count - 1) * 12, bounds.width);\n\t } else {\n\t context.fillText(text, bounds.hx, bounds.ly - 2, bounds.width);\n\t }\n\t\n\t updated = true;\n\t info.push({ annotation: ann, bounds: bounds, context: context });\n\t }\n\t }\n\t\n\t return updated;\n\t },\n\t draw: function (_ref) {\n\t var _this5 = this;\n\t\n\t var view = _ref.view;\n\t var context = _ref.context;\n\t var transform = _ref.transform;\n\t var docIsland = _ref.docIsland;\n\t\n\t\n\t var info = [];\n\t var current = {};\n\t\n\t var tool = view.tool;\n\t var doc = view.doc;\n\t\n\t // [TODO] transform context, so we can draw annotations in any surface\n\t\n\t // Do not show the annotations while dragging the figures around\n\t\n\t if (!doc._previewing && !(tool && tool.type === 'Final')) {\n\t\n\t context.font = view.viewDeltaToTexture(10) * (view.is3D ? 0.65 : 1) + \"pt Calibri\";\n\t (0, _lodash.forEach)(this.readyAnnotations(), function (ann) {\n\t if (!(docIsland && !_this5.needsToDrawAnnotation(ann, docIsland))) {\n\t _this5.drawAnnotation(context, transform, ann, current, info);\n\t }\n\t });\n\t\n\t view.fireEvent('annotationsupdated', view, info);\n\t }\n\t },\n\t readyAnnotations: function () {\n\t return (0, _lodash.filter)(this._processedAnnotations, 'ready');\n\t },\n\t somethingToDraw: function () {\n\t return this._annotationsAreDraw || this._annotations.length > 0;\n\t },\n\t\n\t\n\t // For 3D\n\t\n\t needsToDrawAnnotation: function (ann, docIsland) {\n\t var figures = ann.figures;\n\t\n\t var ready = (0, _lodash.every)(figures, function (figure) {\n\t return !figure.invalidated();\n\t });\n\t if (ready) {\n\t if (figures[0].page === docIsland.page) {\n\t var bounds = _cdl.Figures.bounds_(figures);\n\t return _cdl.Frame.areOverlapping(docIsland.frame_(), _cdl.Frame.fromBounds(bounds));\n\t }\n\t }\n\t return false;\n\t },\n\t needsToDrawFor: function (docIsland) {\n\t var _this6 = this;\n\t\n\t return (0, _lodash.some)(this.readyAnnotations(), function (ann) {\n\t return _this6.needsToDrawAnnotation(ann, docIsland);\n\t });\n\t }\n\t});\n\n/***/ },\n\n/***/ 109:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _viewControls = __webpack_require__(110);\n\t\n\tObject.keys(_viewControls).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _viewControls[key];\n\t }\n\t });\n\t});\n\t\n\tvar _alignmentLines = __webpack_require__(106);\n\t\n\tObject.keys(_alignmentLines).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _alignmentLines[key];\n\t }\n\t });\n\t});\n\t\n\tvar _grid = __webpack_require__(113);\n\t\n\tObject.keys(_grid).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _grid[key];\n\t }\n\t });\n\t});\n\t\n\tvar _keyShortcuts = __webpack_require__(114);\n\t\n\tObject.keys(_keyShortcuts).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _keyShortcuts[key];\n\t }\n\t });\n\t});\n\t\n\tvar _wheelShortcuts = __webpack_require__(115);\n\t\n\tObject.keys(_wheelShortcuts).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _wheelShortcuts[key];\n\t }\n\t });\n\t});\n\t\n\tvar _pagesSelector = __webpack_require__(116);\n\t\n\tObject.keys(_pagesSelector).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _pagesSelector[key];\n\t }\n\t });\n\t});\n\t\n\tvar _toolHelp = __webpack_require__(117);\n\t\n\tObject.keys(_toolHelp).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _toolHelp[key];\n\t }\n\t });\n\t});\n\t\n\tvar _figureAnnotations = __webpack_require__(107);\n\t\n\tObject.keys(_figureAnnotations).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _figureAnnotations[key];\n\t }\n\t });\n\t});\n\t\n\tvar _specialPens = __webpack_require__(105);\n\t\n\tObject.keys(_specialPens).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _specialPens[key];\n\t }\n\t });\n\t});\n\t\n\tvar _activeRenderer = __webpack_require__(102);\n\t\n\tObject.keys(_activeRenderer).forEach(function (key) {\n\t if (key === \"default\") return;\n\t Object.defineProperty(exports, key, {\n\t enumerable: true,\n\t get: function () {\n\t return _activeRenderer[key];\n\t }\n\t });\n\t});\n\n/***/ },\n\n/***/ 110:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar _zoom = __webpack_require__(111);\n\t\n\tvar _pan = __webpack_require__(112);\n\t\n\t_view.Plugin.ViewControls = _view.Plugin.extend({ typeName: 'ViewControls',\n\t\n\t target: 'view',\n\t name: 'controls',\n\t drawTo: ['plugins'],\n\t\n\t on_pointerdown: function (_ref) {\n\t var view = _ref.view;\n\t var event = _ref.event;\n\t var cmdKey = _ref.cmdKey;\n\t var shiftKey = _ref.shiftKey;\n\t var docPoint = _ref.docPoint;\n\t var pointers = _ref.pointers;\n\t\n\t\n\t if (pointers.length === 2) {\n\t this.helper = new _zoom.TouchZoomHelper(event);\n\t } else if (cmdKey) {\n\t if (shiftKey) {\n\t this.helper = new _zoom.ZoomHelper(event);\n\t } else if (cmdKey) {\n\t this.helper = new _pan.PanHelper(event);\n\t }\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 111:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.ZoomTool = exports.ZoomHelper = exports.TouchZoomHelper = undefined;\n\t\n\tvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar _pan = __webpack_require__(112);\n\t\n\tfunction twoFingersTransform(sp1, cp1, sp2, cp2, center) {\n\t\n\t // Adapted from https://github.com/erica/iphone-3.0-cookbook-/blob/master/C08-Gestures/14-Resize%20And%20Rotate/main.m\n\t var cx = center.x,\n\t cy = center.y;\n\t\n\t var x1 = sp1.x - cx,\n\t y1 = sp1.y - cy,\n\t x2 = sp2.x - cx,\n\t y2 = sp2.y - cy,\n\t x3 = cp1.x - cx,\n\t y3 = cp1.y - cy,\n\t x4 = cp2.x - cx,\n\t y4 = cp2.y - cy;\n\t\n\t // Solve the system:\n\t // [a b t1, -b a t2, 0 0 1] * [x1, y1, 1] = [x3, y3, 1]\n\t // [a b t1, -b a t2, 0 0 1] * [x2, y2, 1] = [x4, y4, 1]\n\t\n\t var d = (y1 - y2) * (y1 - y2) + (x1 - x2) * (x1 - x2);\n\t if (d < 0.1) {\n\t return _cdl.Matrix.translate(x3 - x1, y3 - y1);\n\t }\n\t\n\t var a = (y1 - y2) * (y3 - y4) + (x1 - x2) * (x3 - x4),\n\t b = (y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4),\n\t tx = (y1 * x2 - x1 * y2) * (y4 - y3) - (x1 * x2 + y1 * y2) * (x3 + x4) + x3 * (y2 * y2 + x2 * x2) + x4 * (y1 * y1 + x1 * x1),\n\t ty = (x1 * x2 + y1 * y2) * (-y4 - y3) + (y1 * x2 - x1 * y2) * (x3 - x4) + y3 * (y2 * y2 + x2 * x2) + y4 * (y1 * y1 + x1 * x1);\n\t\n\t return new _cdl.Matrix({ s00: a / d, s01: b / d, s10: -b / d, s11: a / d, dx: tx / d, dy: ty / d });\n\t}\n\t\n\tvar TouchZoomHelper = exports.TouchZoomHelper = function (_ref) {\n\t var view = _ref.view;\n\t var pointers = _ref.pointers;\n\t\n\t this._s = false; // [TODO]\n\t\n\t var _pointers = _slicedToArray(pointers, 2);\n\t\n\t var touch1 = _pointers[0];\n\t var touch2 = _pointers[1];\n\t\n\t view.redraw('tools');\n\t this._d = {\n\t t1: touch1, t2: touch2, transform: new _cdl.Matrix(),\n\t center: view.viewToDoc(_cdl.Point.interpolate(touch1.start, touch2.start, 0.5)),\n\t vt: view.viewTransform.clone() // We need a better abstraction here\n\t };\n\t};\n\tTouchZoomHelper.prototype = {\n\t move: function (_ref2) {\n\t var view = _ref2.view;\n\t\n\t\n\t this._s = true;\n\t\n\t // this.toolhelp('Zoom and pan with two touches movement');\n\t\n\t var td = this._d;\n\t var touch1 = td.t1,\n\t touch2 = td.t2,\n\t center = td.center,\n\t vt = td.vt;\n\t var sp1 = vt.viewToDoc(view, touch1.start);\n\t var cp1 = vt.viewToDoc(view, touch1.current);\n\t var sp2 = vt.viewToDoc(view, touch2.start);\n\t var cp2 = vt.viewToDoc(view, touch2.current);\n\t var transform = twoFingersTransform(sp1, cp1, sp2, cp2, center);\n\t\n\t var scale = transform.scaleFactor();\n\t view.center = _cdl.Matrix.transformAround(center, transform.inverted()).apply(vt.center);\n\t view.zoom = vt.zoom * scale;\n\t view.update$().then(function () {\n\t setTimeout(function () {\n\t view.render$();\n\t }, 40);\n\t });\n\t },\n\t end: function (_ref3) {\n\t var view = _ref3.view;\n\t\n\t view.redraw('tools');\n\t }\n\t};\n\t\n\tvar ZoomHelper = exports.ZoomHelper = function (_ref4) {\n\t var modelPoint = _ref4.modelPoint;\n\t\n\t this.from = modelPoint;\n\t this.to = modelPoint;\n\t this.rectLimit = 0.1 * 96;\n\t};\n\t\n\tZoomHelper.prototype = {\n\t\n\t get bounds() {\n\t return _cdl.Bounds.ofPoints([this.from, this.to]);\n\t },\n\t\n\t draw: function (_ref5) {\n\t var context = _ref5.context;\n\t var transformModel = _ref5.transformModel;\n\t var bounds = this.bounds;\n\t\n\t\n\t context.save();\n\t context.strokeStyle = '#0055FF';\n\t bounds.scalingTransformed(transformModel).draw(context);\n\t context.stroke();\n\t context.restore();\n\t },\n\t move: function (_ref6) {\n\t var modelPoint = _ref6.modelPoint;\n\t\n\t this.to = modelPoint;\n\t },\n\t end: function (_ref7) {\n\t var view = _ref7.view;\n\t var shiftKey = _ref7.shiftKey;\n\t var bounds = this.bounds;\n\t\n\t var limit = view.viewDeltaToDoc(this.rectLimit) * _view.padScaling;\n\t if (bounds.width > limit && bounds.height > limit) {\n\t view.zoomAround(bounds);\n\t } else {\n\t // clicking\n\t if (shiftKey) {\n\t view.zoom /= 2;\n\t } else {\n\t view.zoom *= 2;\n\t }\n\t }\n\t view.update$().then(function () {\n\t setTimeout(function () {\n\t view.render$();\n\t }, 40);\n\t });\n\t }\n\t};\n\t\n\tvar ZoomTool = exports.ZoomTool = _view.Tool.extend({ typeName: 'ZoomTool',\n\t\n\t type: 'View',\n\t\n\t toolbarName: 'zoomTool',\n\t\n\t target: 'model',\n\t\n\t initTool: function () {\n\t this.toolhelp('Draw rectangle to zoom', 'Shift Click to zoom out', 'Hold Ctrl to pan');\n\t },\n\t link: function (view) {\n\t view.cursor = 'zoom-in';\n\t },\n\t unlink: function (view) {\n\t view.cursor = 'default';\n\t },\n\t on_pointerdown: function (_ref8) {\n\t var view = _ref8.view;\n\t var event = _ref8.event;\n\t var which = _ref8.which;\n\t var cmdKey = _ref8.cmdKey;\n\t var pointers = _ref8.pointers;\n\t\n\t\n\t if (pointers.length === 2) {\n\t this.helper = new TouchZoomHelper(event);\n\t return;\n\t }\n\t\n\t var leftClick = which === 1;\n\t\n\t if (leftClick) {\n\t if (cmdKey) {\n\t this.helper = new _pan.PanHelper(event);\n\t } else {\n\t // Bounds based zoom\n\t this.helper = new ZoomHelper(event);\n\t }\n\t } else {\n\t view.zoom /= 2;\n\t view.update$().then(function () {\n\t setTimeout(function () {\n\t view.render$();\n\t }, 40);\n\t });\n\t }\n\t }\n\t});\n\t\n\t_view.Tool.Zoom = ZoomTool;\n\n/***/ },\n\n/***/ 112:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\texports.PanTool = exports.PanHelper = undefined;\n\t\n\tvar _gear = __webpack_require__(8);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar PanHelper = exports.PanHelper = function (_ref) {\n\t var view = _ref.view;\n\t var viewPoint = _ref.viewPoint;\n\t\n\t this.viewPoint = viewPoint;\n\t this.viewPointDown = viewPoint;\n\t this.centerDown = view.center.clone();\n\t view.redraw('tools');\n\t};\n\tPanHelper.prototype = {\n\t draw: function (_ref2) {\n\t var context = _ref2.context;\n\t\n\t context.save();\n\t context.strokeStyle = '#0055FF';\n\t (0, _gear.strokeDot)(context, this.viewPoint, 8);\n\t context.restore();\n\t },\n\t\n\t\n\t move: (0, _view.fastThrottle)(function (_ref3) {\n\t var view = _ref3.view;\n\t var event = _ref3.event;\n\t var viewPoint = _ref3.viewPoint;\n\t var isPrimary = _ref3.isPrimary;\n\t\n\t if (!isPrimary) {\n\t return;\n\t }\n\t\n\t this.viewPoint = viewPoint;\n\t\n\t var zoom = view.zoom;\n\t var offset = viewPoint.minus(this.viewPointDown);\n\t view.center = this.centerDown.minus_(offset.x / zoom, -offset.y / zoom);\n\t view.update$();\n\t }, 20),\n\t\n\t end: function (_ref4) {\n\t var view = _ref4.view;\n\t\n\t view.redraw('tools');\n\t }\n\t};\n\t\n\tvar PanTool = exports.PanTool = _view.Tool.extend({ typeName: 'PanTool',\n\t type: 'View',\n\t toolbarName: 'panTool',\n\t\n\t initTool: function () {\n\t this.toolhelp('Click and drag to pan');\n\t },\n\t link: function (view) {\n\t view.cursor = 'pointer';\n\t },\n\t unlink: function (view) {\n\t view.cursor = 'default';\n\t },\n\t on_pointerdown: function (_ref5) {\n\t var event = _ref5.event;\n\t var which = _ref5.which;\n\t var isPrimary = _ref5.isPrimary;\n\t\n\t if (!isPrimary) {\n\t return; // ignore multitouch\n\t }\n\t var leftClick = which === 1;\n\t if (leftClick) {\n\t this.helper = new PanHelper(event);\n\t }\n\t },\n\t on_pointerup: function (event) {\n\t event.view.render$();\n\t }\n\t});\n\t\n\t_view.Tool.Pan = PanTool;\n\n/***/ },\n\n/***/ 113:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar floor = Math.floor;\n\t\n\tvar snapValue = function (x, step) {\n\t return floor(x / step) * step;\n\t};\n\t\n\t_view.Plugin.Grid = _view.Plugin.extend({ typeName: 'GridPlugin',\n\t\n\t drawTo: ['plugins'],\n\t name: 'grid',\n\t target: 'model',\n\t\n\t Properties: {\n\t color: { type: 'Color', def: new _cdl.Color({ rgb: '5680CC', alpha: 0.5 }), owned: true, onChange: _view.redraw_this },\n\t step: { type: 'number', def: 25.4, onChange: _view.redraw_this }\n\t },\n\t\n\t clone: function () {\n\t return _view.Plugin.Grid(this);\n\t },\n\t draw: function (_ref) {\n\t var view = _ref.view;\n\t var context = _ref.context;\n\t var transform = _ref.transform;\n\t\n\t var bounds = view.bounds,\n\t step = this._step,\n\t lx = snapValue(bounds.lx, step),\n\t ly = snapValue(bounds.ly, step),\n\t hx = snapValue(bounds.hx, step) + step,\n\t hy = snapValue(bounds.hy, step) + step;\n\t\n\t context.lineWidth = 1;\n\t context.strokeStyle = this._color.rgba;\n\t\n\t for (var x = lx; x <= hx; x += step) {\n\t (0, _view.strokePixelCenterSegment)(context, new _cdl.Point(x, ly), new _cdl.Point(x, hy), transform);\n\t }\n\t\n\t for (var y = ly; y <= hy; y += step) {\n\t (0, _view.strokePixelCenterSegment)(context, new _cdl.Point(lx, y), new _cdl.Point(hx, y), transform);\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 114:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar _config = __webpack_require__(2);\n\t\n\tfunction preventDefault(event) {\n\t event.preventDefault();\n\t}\n\tfunction bump(e, canvas, figures, x, y) {\n\t preventDefault(e);\n\t canvas.bump(figures, x, y);\n\t canvas.commit$();\n\t}\n\t\n\t_view.Plugin.KeyShortcuts = _view.Plugin.extend({ typeName: 'KeyShortcutsPlugin',\n\t\n\t name: 'keyShortcuts',\n\t\n\t target: 'view',\n\t\n\t link: function (view) {\n\t view.on({ 'selectionchanged': this.onSelectionChanged }, this);\n\t },\n\t clone: function () {\n\t return _view.Plugin.KeyShortcuts(this);\n\t },\n\t on_keyup: function (_ref) {\n\t var view = _ref.view;\n\t var event = _ref.event;\n\t var altKey = _ref.altKey;\n\t\n\t if (!altKey) {\n\t preventDefault(event);\n\t return this.on_keyup_alt(event);\n\t }\n\t },\n\t\n\t\n\t // [TODO] This should be part of the view API\n\t startTransparentMode: function () {\n\t var _this = this;\n\t\n\t if (!this._transparentMode) {\n\t (function () {\n\t var view = _this.view;\n\t\n\t var tf = _this._transparentFigureViews = (0, _lodash.map)(view.selectedFigures, function (figure) {\n\t return view.figureView(figure);\n\t });\n\t (0, _lodash.invokeMap)(tf, 'mask');\n\t _this._transparentMode = true;\n\t view.render$();\n\t })();\n\t }\n\t },\n\t endTransparentMode: function () {\n\t if (this._transparentMode) {\n\t (0, _lodash.forEach)(this._transparentFigureViews, function (fv) {\n\t fv.hideMask();\n\t });\n\t this._transparentFigureViews = null;\n\t this._transparentMode = false;\n\t this.view.render$();\n\t }\n\t },\n\t on_keydown_alt: function () {\n\t this.startTransparentMode();\n\t },\n\t on_focusout: function () {\n\t this.endTransparentMode();\n\t },\n\t on_keyup_alt: function () {\n\t this.endTransparentMode();\n\t },\n\t onSelectionChanged: function () {\n\t if (this._transparentMode) {\n\t this.endTransparentMode();\n\t this.startTransparentMode();\n\t }\n\t },\n\t on_keydown: function (_ref2) {\n\t var view = _ref2.view;\n\t var event = _ref2.event;\n\t var which = _ref2.which;\n\t var char = _ref2.char;\n\t var shiftKey = _ref2.shiftKey;\n\t var altKey = _ref2.altKey;\n\t var cmdKey = _ref2.cmdKey;\n\t\n\t\n\t // console.log('keyShortcuts - keydown');\n\t\n\t if (altKey) {\n\t preventDefault(event);\n\t return this.on_keydown_alt(event);\n\t }\n\t\n\t char = char.toLowerCase();\n\t\n\t if (cmdKey && !altKey && !shiftKey) {\n\t var lKeyValues = Array.from(_config.Config.hotKeys.values());\n\t switch (char) {\n\t case 'z':\n\t if (!lKeyValues.includes('Undo')) {\n\t preventDefault(event);\n\t if (view.canUndo()) {\n\t view.undo();\n\t }\n\t return;\n\t }\n\t case 'y':\n\t if (!lKeyValues.includes('Redo')) {\n\t preventDefault(event);\n\t if (view.canRedo()) {\n\t view.redo();\n\t }\n\t return;\n\t }\n\t }\n\t }\n\t\n\t var hk_char = (cmdKey ? 'CTRL+' : '') + (altKey ? 'ALT+' : '') + (shiftKey ? 'SHIFT+' : '') + char;\n\t var hk = _config.Config.hotKeys.get(hk_char);\n\t\n\t switch (hk) {\n\t case 'Undo':\n\t preventDefault(event);\n\t if (view.canUndo()) {\n\t view.undo();\n\t }\n\t return;\n\t case 'Redo':\n\t preventDefault(event);\n\t if (view.canRedo()) {\n\t view.redo();\n\t }\n\t return;\n\t case 'Pan':\n\t view.tool = view.tool == _view.Tool.Pan() ? 'Select' : _view.Tool.Pan();\n\t break;\n\t case 'Select':\n\t view.tool = 'Select';\n\t break;\n\t case 'ZoomIn':\n\t view.tool = view.tool == _view.Tool.Zoom() ? 'Select' : _view.Tool.Zoom();\n\t view.zoom *= 1.10;\n\t break;\n\t case 'ZoomOut':\n\t view.tool = view.tool == _view.Tool.Zoom() ? 'Select' : _view.Tool.Zoom();\n\t view.zoom /= 1.10;\n\t break;\n\t default:\n\t break;\n\t }\n\t\n\t var tool = view.tool;\n\t\n\t if (tool && tool.isCommitable) {\n\t switch (which) {\n\t case 13: // Enter\n\t case 27:\n\t // Esc\n\t preventDefault(event);\n\t tool.commit$();\n\t break;\n\t }\n\t } else if (!tool || tool.allowKeyShortcuts) {\n\t\n\t var selectedFigures = view.selectedFigures;\n\t\n\t if (cmdKey) {\n\t\n\t switch (char) {\n\t\n\t // Select all\n\t //========================================================\n\t case 'a':\n\t preventDefault(event);\n\t view.selectAll();\n\t return view.render$();\n\t\n\t // Duplicate\n\t //========================================================\n\t case 'd':\n\t preventDefault(event);\n\t if (view.canDuplicate(selectedFigures)) {\n\t view.duplicate(selectedFigures);\n\t view.commit$();\n\t }\n\t break;\n\t\n\t // Copy\n\t //========================================================\n\t case 'c':\n\t preventDefault(event);\n\t if (view.canCopy(selectedFigures)) {\n\t view.copy(selectedFigures);\n\t }\n\t break;\n\t\n\t // Cut\n\t //========================================================\n\t case 'x':\n\t preventDefault(event);\n\t if (view.canCut(selectedFigures)) {\n\t view.cut(selectedFigures);\n\t return view.commit$();\n\t }\n\t break;\n\t\n\t // Paste\n\t //========================================================\n\t case 'v':\n\t preventDefault(event);\n\t if (view.canPaste()) {\n\t view.pasteAt$(view.center).then(function () {\n\t return view.commit$();\n\t });\n\t }\n\t break;\n\t\n\t // Group\n\t //========================================================\n\t case 'g':\n\t preventDefault(event);\n\t if (view.canGroup(selectedFigures)) {\n\t view.group(selectedFigures);\n\t return view.commit$();\n\t }\n\t break;\n\t\n\t // Ungroup\n\t //========================================================\n\t case 'u':\n\t preventDefault(event);\n\t if (view.canUngroup(selectedFigures)) {\n\t view.ungroup(selectedFigures);\n\t return view.commit$();\n\t }\n\t break;\n\t\n\t default:\n\t // Undo/redo are managed directly by Canvas\n\t }\n\t }\n\t\n\t // console.log(which);\n\t switch (which) {\n\t case 46:\n\t // Del\n\t preventDefault(event);\n\t if (view.canRemove(selectedFigures)) {\n\t view.remove(selectedFigures);\n\t return view.commit$();\n\t }\n\t break;\n\t\n\t case 8:\n\t // Backspace (Mac) => Del\n\t if (/Mac/.test(navigator.platform)) {\n\t preventDefault(event);\n\t if (view.canRemove(selectedFigures)) {\n\t view.remove(selectedFigures);\n\t return view.commit$();\n\t }\n\t }\n\t break;\n\t\n\t case 9:\n\t // Tab\n\t preventDefault(event);\n\t view.selectNext(shiftKey ? -1 : 1);\n\t return view.render$();\n\t\n\t case 32: // Space\n\t case 113:\n\t // F2\n\t preventDefault(event);\n\t if (selectedFigures.length === 1) {\n\t var figure = selectedFigures[0];\n\t if (view.canEditContent(figure)) {\n\t return view.editContent(figure);\n\t }\n\t }\n\t break;\n\t\n\t case 27:\n\t // Esc\n\t preventDefault(event);\n\t if (view.editingContent()) {\n\t return view.commitContent$();\n\t } else if (selectedFigures.length > 0) {\n\t selectedFigures.clear();\n\t view.render$();\n\t }\n\t break;\n\t\n\t case 13:\n\t // Enter\n\t preventDefault(event);\n\t if (view.editingContent()) {\n\t return view.commitContent$();\n\t }\n\t break;\n\t }\n\t\n\t if (view.canBump(selectedFigures)) {\n\t switch (which) {\n\t case 40:\n\t // Down\n\t return bump(event, view, selectedFigures, 0, -1);\n\t case 37:\n\t // Left\n\t return bump(event, view, selectedFigures, -1, 0);\n\t case 39:\n\t // Right\n\t return bump(event, view, selectedFigures, 1, 0);\n\t case 38:\n\t // Up\n\t return bump(event, view, selectedFigures, 0, 1);\n\t }\n\t }\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 115:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar _config = __webpack_require__(2);\n\t\n\tfunction preventDefault(event) {\n\t event.preventDefault();\n\t}\n\tfunction bump(e, canvas, figures, x, y) {\n\t preventDefault(e);\n\t canvas.bump(figures, x, y);\n\t canvas.commit$();\n\t}\n\t\n\t_view.Plugin.WheelShortcuts = _view.Plugin.extend({ typeName: 'WheelShortcutsPlugin',\n\t\n\t name: 'wheelShortcuts',\n\t\n\t target: 'view',\n\t speed: 0.002,\n\t zoomMin: 1,\n\t zoomMax: 10,\n\t\n\t clone: function () {\n\t return _view.Plugin.WheelShortcuts(this);\n\t },\n\t on_mousewheel: function (_ref) {\n\t var view = _ref.view;\n\t var event = _ref.event;\n\t var wheelDelta = _ref.wheelDelta;\n\t var detail = _ref.detail;\n\t\n\t var delta = 0;\n\t\n\t if (wheelDelta !== undefined) {\n\t // WebKit / Opera / Explorer 9\n\t delta = event.wheelDelta;\n\t } else if (detail !== undefined) {\n\t // Firefox\n\t delta = -event.detail;\n\t }\n\t\n\t var lZoom = view.zoom;\n\t\n\t if (delta > 0) lZoom *= 1 + this.speed * wheelDelta;else lZoom /= 1 - this.speed * wheelDelta;\n\t\n\t if (lZoom < this.zoomMin) lZoom = this.zoomMin;\n\t if (lZoom > this.zoomMax) lZoom = this.zoomMax;\n\t\n\t view.zoom = lZoom;\n\t }\n\t});\n\n/***/ },\n\n/***/ 116:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar ceil = Math.ceil;\n\tvar floor = Math.floor;\n\tvar sqrt = Math.sqrt;\n\t\n\t\n\t_view.Plugin.PagesSelector = _view.Plugin.extend({ typeName: 'PagesSelectorPlugin',\n\t\n\t name: 'pagesSelector',\n\t\n\t drawTo: ['plugins'],\n\t\n\t target: 'view',\n\t\n\t init: function (config) {\n\t this.callParent(config);\n\t this._visible = false;\n\t },\n\t clone: function () {\n\t return new _view.Plugin.PagesSelector();\n\t },\n\t show$: function () {\n\t var view = this.view;\n\t if (view._mainDocument._pages.length > 1) {\n\t view._stateChanged = true;\n\t view.selectedFigures.clear();\n\t this.takeControl();\n\t }\n\t return view.render$();\n\t },\n\t on_click: function (_ref) {\n\t var view = _ref.view;\n\t var event = _ref.event;\n\t var viewPoint = _ref.viewPoint;\n\t\n\t event.preventDefault();\n\t var doc = view._mainDocument;\n\t var _view$scene = view.scene;\n\t var width = _view$scene.width;\n\t var height = _view$scene.height;\n\t var pages = doc.pages;\n\t\n\t\n\t var columns = Math.ceil(Math.sqrt(pages.length)),\n\t rows = Math.ceil(pages.length / columns),\n\t columnsWidth = width * (1.0 / columns),\n\t rowsHeight = height * (1.0 / rows),\n\t columnsInLastRow = (pages.length - 1) % columns + 1,\n\t columnsWidthForLastRow = width * (1.0 / columnsInLastRow);\n\t\n\t var x = viewPoint.x;\n\t var y = viewPoint.y;\n\t\n\t\n\t if (x > 0 && x < width && y > 0 && y < height) {\n\t\n\t var selectedRow = floor(y / rowsHeight);\n\t var lastRow = selectedRow === rows - 1;\n\t var selectedColumn = floor(x / (lastRow ? columnsWidthForLastRow : columnsWidth));\n\t\n\t var selectedPage = selectedRow * columns + selectedColumn;\n\t doc.activePage = pages[selectedPage];\n\t\n\t view._stateChanged = true;\n\t\n\t this.visible = false;\n\t view.renderer.visible = true;\n\t\n\t view.redrawAll();\n\t\n\t view._pagesSelector = false;\n\t view._pagesSelectorDraw = false;\n\t\n\t view.render$();\n\t this.releaseControl();\n\t }\n\t\n\t event.stopPropagation();\n\t },\n\t draw: function (_ref2) {\n\t var view = _ref2.view;\n\t var context = _ref2.context;\n\t\n\t\n\t // Support for Mask plugin\n\t var specialPens = view.specialPens;\n\t if (specialPens && specialPens._maskVisible) {\n\t specialPens.prepareMask();\n\t }\n\t\n\t var _context$canvas = context.canvas;\n\t var width = _context$canvas.width;\n\t var height = _context$canvas.height;\n\t\n\t\n\t var pages = view._mainDocument._pages,\n\t length = pages.length,\n\t columns = ceil(sqrt(length)),\n\t rows = ceil(length / columns),\n\t scale = 1 / Math.max(columns, rows),\n\t columnsWidth = width * (1.0 / columns),\n\t rowsHeight = height * (1.0 / rows),\n\t xOffset = (columnsWidth - width * scale) / 2,\n\t yOffset = (rowsHeight - height * scale) / 2,\n\t columnsInLastRow = (length - 1) % columns + 1,\n\t columnsWidthForLastRow = width * (1.0 / columnsInLastRow),\n\t xOffsetForLastRow = (columnsWidthForLastRow - width * scale) / 2;\n\t\n\t (0, _lodash.forEach)(pages, function (page, i) {\n\t\n\t var col = i % columns,\n\t row = floor(i / columns),\n\t lastRow = row === rows - 1,\n\t cWidth = lastRow ? columnsWidthForLastRow : columnsWidth,\n\t rHeight = rowsHeight,\n\t lcx = col * cWidth,\n\t lcy = row * rowsHeight,\n\t lx = lcx + (lastRow ? xOffsetForLastRow : xOffset),\n\t ly = lcy + yOffset;\n\t\n\t context.save();\n\t\n\t context.beginPath();\n\t context.rect(lcx, lcy, cWidth, rHeight);\n\t context.clip();\n\t\n\t var transform = _cdl.Matrix.concat(_cdl.Matrix.translate(lx, ly), _cdl.Matrix.scale(scale), view.pageViewTransform(page).matrixFor(view));\n\t\n\t var backgroundPage = view.backgroundPageFor(page);\n\t\n\t view.drawPage(backgroundPage, context, transform, { viewport: transform });\n\t\n\t view.drawPage(page, context, transform, { wireframe: view._wireframe, viewport: transform });\n\t\n\t if (specialPens) {\n\t specialPens.drawForPage(page, context, transform, { lx: lcx, ly: lcy, width: cWidth, height: rHeight });\n\t }\n\t\n\t context.restore();\n\t });\n\t\n\t if (specialPens && specialPens._maskVisible) {\n\t specialPens.blitMask(context);\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 117:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _config = __webpack_require__(2);\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _cdl = __webpack_require__(15);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\t_view.Plugin.ToolHelp = _view.Plugin.extend({ typeName: 'ToolHelpPlugin',\n\t\n\t drawTo: ['plugins'],\n\t\n\t name: 'toolHelp',\n\t\n\t target: 'view',\n\t\n\t Properties: {\n\t collapsed: { type: 'boolean', def: true, onChange: _view.redraw_this }\n\t },\n\t\n\t on_click: function (_ref) {\n\t var view = _ref.view;\n\t var event = _ref.event;\n\t var viewPoint = _ref.viewPoint;\n\t var height = view.height;\n\t\n\t var toolhelpBounds = new _cdl.Bounds(0, height - (_config.Config.debug ? 60 : 30), 80, height - (_config.Config.debug ? 33 : 0));\n\t if (toolhelpBounds.contains(viewPoint)) {\n\t this.collapsed = !this._collapsed;\n\t event.stopPropagation();\n\t }\n\t },\n\t draw: function (_ref2) {\n\t var _this = this;\n\t\n\t var view = _ref2.view;\n\t var context = _ref2.context;\n\t\n\t\n\t if (view.hasFocus()) {\n\t (function () {\n\t\n\t context.font = 'italic 11pt Calibri';\n\t context.textBaseline = 'bottom';\n\t context.textAlign = 'left';\n\t context.fillStyle = '#333';\n\t\n\t var ls = 16;\n\t var width = view.width;\n\t var height = view.height;\n\t\n\t var hy = height - (_config.Config.debug ? 40 : 6);\n\t\n\t if (_this._visible) {\n\t\n\t var toolhelp = view._toolhelp;\n\t if (toolhelp) {\n\t (function () {\n\t var lines = toolhelp.split('\\n');\n\t var h = hy - (lines.length - 1) * ls;\n\t (0, _lodash.forEach)(lines, function (line) {\n\t context.fillText(line, 6, h, width);\n\t h += ls;\n\t });\n\t })();\n\t } else {\n\t context.fillText('Need help?', 6, hy, width);\n\t }\n\t }\n\t })();\n\t }\n\t }\n\t});\n\n/***/ },\n\n/***/ 167:\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _lodash = __webpack_require__(4);\n\t\n\tvar _view = __webpack_require__(84);\n\t\n\tvar View = _interopRequireWildcard(_view);\n\t\n\tvar _plugin = __webpack_require__(109);\n\t\n\tvar Plugin = _interopRequireWildcard(_plugin);\n\t\n\tfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }\n\t\n\tvar _window = window;\n\tvar Cx = _window.Cx;\n\t\n\t\n\t(0, _lodash.assign)(Cx, View);\n\n/***/ }\n\n})\n});\n;\n\n\n/** WEBPACK FOOTER **\n ** ui.js\n **/","export * from './util';\r\nexport * from './events';\r\nexport * from './plugin';\r\nexport * from './tool';\r\nexport * from './composition';\r\nexport * from './texture-composition';\r\nexport * from './view';\r\nexport * from './view2d';\r\nexport * from './figure-view';\r\nexport * from './synced-figure-views';\r\nexport * from './document-view-mixin';\r\nexport * from './selected-figures-mixin';\r\nexport * from './interactive-view';\r\nexport * from './clipboard';\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/view/index.js\n **/","import { assign, isString, now } from 'lodash';\r\nimport { strokeSegment } from 'gear';\r\nimport { Point } from 'cdl';\r\n\r\nexport function createDomContainer( id ) {\r\n\r\n const container = window.document.createElement('div');\r\n if( id ) {\r\n container.id = id; // This is not needed, maybe just good for debugging\r\n }\r\n assign( container.style, {\r\n width: '100%', height: '100%',\r\n position: 'relative',\r\n overflow: 'hidden'\r\n });\r\n return container;\r\n}\r\n\r\nconst floor = Math.floor;\r\n\r\nexport function pixelCenter(point,t) {\r\n let p = t ? t.apply(point) : point;\r\n return new Point( floor(p.x) + 0.5, floor(p.y) + 0.5 );\r\n}\r\n\r\nexport function strokePixelCenterSegment(context,from,to,transform) {\r\n strokeSegment(context,pixelCenter(from,transform),pixelCenter(to,transform));\r\n}\r\n\r\n// [TODO] We can simplify this, IE10+ supports requestAnimationFrame\r\n\r\nlet requestAnimFrame = (function() {\r\n return window.requestAnimationFrame ||\r\n window.webkitRequestAnimationFrame ||\r\n window.mozRequestAnimationFrame ||\r\n window.oRequestAnimationFrame ||\r\n window.msRequestAnimationFrame ||\r\n function(callback) {\r\n return setTimeout(callback, 1000/60);\r\n };\r\n})();\r\n\r\n// Shared Animation Loop, we may directly eliminate this\r\n// It is adding complexity (and leaks), and it may not be giving as\r\n// anything\r\n// Maybe we do not even need a loop and we can just ask animation frames\r\n// when needed\r\n\r\nlet drawCalls = [];\r\nconst animationLoop = function() {\r\n for( let i = 0, iEnd = drawCalls.length; i < iEnd; ++i ) {\r\n drawCalls[i]();\r\n }\r\n requestAnimFrame( animationLoop );\r\n};\r\nanimationLoop();\r\n\r\nexport const AnimationLoop = {\r\n register( call) {\r\n drawCalls.push( call );\r\n },\r\n unregister( call) {\r\n drawCalls.splice( drawCalls.indexOf(call), 1 );\r\n }\r\n};\r\n\r\n\r\n// A simple throttle that call the function the first time is\r\n// issued and after that only if it is called after a certain timeout\r\n// lo-dash uses setTimeout, clearTimeout for doing the same thing\r\n// Equivalent to _.throttle(func,timeout,{leading:true})\r\nexport const fastThrottle = function(func,timeout) {\r\n const last = { t: 0, r: null };\r\n return function() {\r\n const t = now();\r\n if( last.t < t - timeout ) {\r\n last.r = func.apply(this,arguments);\r\n last.t = t;\r\n }\r\n return last.r;\r\n };\r\n};\r\n\r\n\r\n// Browser like shortcuts and utils from http://youmightnotneedjquery.com/\r\n//=============================================================================\r\n\r\nexport const g$ = function(selector) {\r\n return document.querySelector(selector);\r\n};\r\n\r\nexport const g$$ = function(selector) {\r\n return document.querySelectorAll(selector);\r\n};\r\n\r\n// [TODO] Use offsetWidth, offsetHeight\r\n\r\nconst dim = function(d) {\r\n return function(el,value) {\r\n if( value === undefined ) {\r\n return el.getBoundingClientRect()[d];\r\n }\r\n else {\r\n el.style[d] = value+'px';\r\n }\r\n };\r\n};\r\n\r\n\r\nassign( g$, {\r\n\r\n addClass( el, className ) {\r\n if( el.classList ) {\r\n el.classList.add(className);\r\n }\r\n else {\r\n el.className += ' ' + className;\r\n }\r\n },\r\n\r\n append( el, child ) {\r\n if( isString(child) ) {\r\n\r\n //Ensure we are working with a Node and then we can always just use appendChild\r\n //Cross browser trick (except old IE) to get DOM element from string\r\n const tempDiv = document.createElement('div');\r\n tempDiv.innerHTML = child;\r\n child = tempDiv.firstChild;\r\n }\r\n\r\n el.appendChild(child);\r\n },\r\n\r\n remove( el ) {\r\n if(el) {\r\n el.parentNode.removeChild(el);\r\n }\r\n },\r\n\r\n show( el ) {\r\n el.style.display = '';\r\n },\r\n\r\n hide( el ) {\r\n el.style.display = 'none';\r\n },\r\n\r\n width : dim('width'),\r\n height: dim('height'),\r\n\r\n setSize( el, width, height ) {\r\n el.style.width = width+'px';\r\n el.style.height = height+'px';\r\n },\r\n\r\n on( el, eventName, handler ) {\r\n el.addEventListener(eventName,handler,false);\r\n },\r\n\r\n off( el, eventName, handler ) {\r\n el.removeEventListener(eventName,handler,false);\r\n },\r\n\r\n focus( el ) {\r\n if( el !== document.activeElement ) {\r\n el.focus();\r\n }\r\n },\r\n\r\n // [TODO] Unused, we can remove this\r\n getBox( el ) {\r\n const rect = el.getBoundingClientRect();\r\n\r\n // retrieve the current position of an element relative to the document\r\n // el.offset();\r\n const top = rect.top + document.body.scrollTop,\r\n left = rect.left + document.body.scrollLeft,\r\n height = rect.height,\r\n width = rect.width;\r\n\r\n return {\r\n x: left, y: top,\r\n width: width, height: height,\r\n bottom: height + top,\r\n right: width + left\r\n };\r\n }\r\n});\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/view/util.js\n **/","import { Config } from 'config';\r\n\r\nimport { forEach, map, pull, keys, now, indexOf } from 'lodash';\r\n\r\nimport { Point } from 'cdl';\r\n\r\nimport { g$, fastThrottle } from './util';\r\n\r\nexport let padScaling = 1.0;\r\nexport let usingTouch = false;\r\n\r\nconst specialKeys = [ 'altKey', 'shiftKey', 'ctrlKey', 'metaKey' ];\r\n\r\n// Use view.triggerKeyboard() to get the virtual keyboard in mobile\r\nlet textInputEl, textInputButtonEl;\r\nfunction initGlobalTextInputEl() {\r\n const textInputId = 'grafika-hidden-text-input',\r\n textInputButtonId = textInputId + '-button';\r\n g$.append( g$('body'), ``);\r\n g$.append( g$('body'), `` );\r\n textInputEl = g$(\"#\"+textInputId);\r\n textInputButtonEl = g$(\"#\"+textInputButtonId);\r\n}\r\n\r\n\r\nconst eventBasePrototype = {\r\n\r\n preventDefault() {\r\n return this._e.preventDefault();\r\n },\r\n\r\n get view() {\r\n return this._v;\r\n },\r\n\r\n get event() {\r\n return this;\r\n },\r\n\r\n get type() {\r\n return this._t;\r\n },\r\n\r\n get route() {\r\n return 'on_' + this._t;\r\n },\r\n\r\n get originalEvent() {\r\n return this._e;\r\n },\r\n\r\n get cmdKey() {\r\n const e = this._e;\r\n return e.ctrlKey || e.metaKey;\r\n },\r\n\r\n get stopped() {\r\n return this._s;\r\n },\r\n stopPropagation() {\r\n this._s = true;\r\n }\r\n};\r\n\r\nfunction createEventPrototype( getters, proto ){\r\n return extendProto( forwardEventGetters(specialKeys.concat(getters), proto), eventBasePrototype );\r\n}\r\n\r\n// focus, focusout\r\n\r\nexport const ViewEvent = function(view,type,originalEvent){\r\n this._v = view;\r\n this._t = type;\r\n this._s = false; // stopped\r\n this._e = originalEvent;\r\n};\r\nViewEvent.prototype = createEventPrototype([],{\r\n\r\n});\r\n\r\n// keypress, keydown, keyup\r\n\r\nexport const ViewKeyEvent = function(view,type,originalEvent){\r\n this._v = view;\r\n this._t = type;\r\n this._s = false; // stopped\r\n this._e = originalEvent;\r\n\r\n};\r\nViewKeyEvent.prototype = createEventPrototype([\r\n 'which', 'keyCode', 'key', 'charCode'\r\n],{\r\n get char() {\r\n const { _e } = this, which = _e.which || _e.keyCode;\r\n return which !== undefined ? String.fromCharCode(which) : undefined ;\r\n },\r\n});\r\n\r\n\r\n// keypress, keydown, keyup\r\n\r\nexport const ViewMouseWheelEvent = function(view,type,originalEvent){\r\n this._v = view;\r\n this._t = type;\r\n this._s = false; // stopped\r\n this._e = originalEvent;\r\n\r\n};\r\nViewMouseWheelEvent.prototype = createEventPrototype([],{\r\n get wheelDelta() {\r\n const { _e } = this;\r\n if( _e.wheelDelta !== undefined ) {\r\n // WebKit / Opera / Explorer 9\r\n return _e.wheelDelta;\r\n }\r\n else {\r\n // Firefox\r\n return - _e.detail;\r\n }\r\n },\r\n});\r\n\r\n// 3D views uses a ray tracing tracker\r\n\r\nconst DefaultPointerTracker = function() {\r\n};\r\nDefaultPointerTracker.prototype.track = function({ view, originalEvent }) {\r\n\r\n const modelPoint = view.modelPoint(originalEvent),\r\n docPoint = view.docPoint(originalEvent);\r\n\r\n return {\r\n\r\n modelPoint,\r\n docPoint,\r\n\r\n // In 3D, this points are allowed to jump between texture islands\r\n modelPointRaw: modelPoint,\r\n docPointRaw : docPoint,\r\n };\r\n};\r\n\r\n\r\nconst defaultPointerTracker = new DefaultPointerTracker();\r\n\r\n// pointerdown, pointermove, pointerup, click, dblclick\r\n\r\nexport const ViewPointerEvent = function(view,type,originalEvent,pointers,eventDown,tracker) {\r\n this._v = view;\r\n this._t = type;\r\n this._e = originalEvent;\r\n this._p = pointers;\r\n this._s = false; // stopped\r\n this._vp = view.viewPoint(originalEvent);\r\n this._ed = eventDown || this;\r\n this._target = null;\r\n this._tracker = tracker || defaultPointerTracker;\r\n // Cached properties that doesn't change during retargetting\r\n this._cache = new Map();\r\n};\r\n\r\nViewPointerEvent.prototype = createEventPrototype([\r\n\r\n 'pageX', 'pageY',\r\n 'clientX', 'clientY',\r\n 'screenX', 'screenY',\r\n 'offsetX', 'offsetY',\r\n 'which', 'pointerType',\r\n 'button', 'buttons'\r\n\r\n], forwardTrackerGetters([\r\n\r\n 'modelPoint',\r\n 'docPoint',\r\n 'modelIsland',\r\n 'docIsland',\r\n\r\n 'modelPointRaw',\r\n 'docPointRaw',\r\n 'modelIslandRaw',\r\n 'docIlsandRaw',\r\n\r\n],{\r\n\r\n retarget(eventDown,target) {\r\n const { _v, _t, _e, _p } = this;\r\n const re = new ViewPointerEvent(_v,_t,_e,_p,eventDown,target);\r\n // Copy common properties, that are expensive to recompute\r\n re._cache = this._cache;\r\n return re;\r\n },\r\n\r\n get viewPoint() {\r\n return this._vp;\r\n },\r\n\r\n get figureHit() {\r\n const { _cache } = this;\r\n if( ! _cache.has('figureHit') ) {\r\n _cache.set('figureHit', this._v.figureHitAtEvent(this._e) );\r\n }\r\n return _cache.get('figureHit');\r\n },\r\n get figure() {\r\n const { figureHit } = this;\r\n if( figureHit ) {\r\n return figureHit.figure;\r\n }\r\n },\r\n\r\n get rawFigureHits() {\r\n const { _cache } = this;\r\n if( ! _cache.has('rawFigureHits') ) {\r\n _cache.set( 'rawFigureHits', this._v.rawFigureHitsAtEvent(this._e) );\r\n }\r\n return _cache.get('rawFigureHits');\r\n },\r\n\r\n get rawFigures() {\r\n const { rawFigureHits } = this;\r\n return map(rawFigureHits,'figure');\r\n },\r\n\r\n get clientPoint() {\r\n const event = this._e;\r\n return Point(event.clientX,event.clientY);\r\n },\r\n\r\n get pagePoint() {\r\n const event = this._e;\r\n return Point(event.pageX,event.pageY);\r\n },\r\n\r\n // [CHECK]\r\n // There are offsetX, offsetY properties that seems to be inconsistent\r\n // Maybe we can try them at one point\r\n\r\n // [TODO]\r\n // We may want to clone the points, but users shouldn't be modifiying this\r\n\r\n get offsetPoint() {\r\n return this.viewPoint;\r\n },\r\n\r\n get pointers() {\r\n return this._p;\r\n },\r\n\r\n get pointerId() {\r\n const { _e } = this;\r\n return _e.pointerId || _e.touchId;\r\n },\r\n\r\n get isPrimary() {\r\n const { _e } = this;\r\n return _e.isPrimary === undefined ? true : _e.isPrimary;\r\n },\r\n}));\r\n\r\nexport const interactiveViewEvents = [\r\n 'contextmenu',\r\n 'click',\r\n 'dblclick',\r\n 'keydown',\r\n 'keyup',\r\n 'keypress',\r\n 'focus',\r\n 'focusout',\r\n 'pointerdown',\r\n 'pointermove',\r\n 'pointerup',\r\n 'mousemove',\r\n 'mousewheel',\r\n];\r\n\r\n\r\nexport const InteractiveHelper = function( view, domElement, config = {} ) {\r\n\r\n this.view = view;\r\n\r\n const el = this.el = domElement;\r\n\r\n const captureKey = this.captureKey = config.captureKey; // function(object, event ) { return capture... };\r\n\r\n\r\n this.enabled = true;\r\n this.focused = false;\r\n\r\n const elK = this.elK = captureKey ? document : el;\r\n\r\n this.consume_click = 0;\r\n\r\n this.pointersMap = new Map();\r\n this.pointers = [];\r\n\r\n this.primaryId = null;\r\n\r\n this.mouseisdown = false;\r\n\r\n this.lastClick = { t: 0, x: 0, y: 0 };\r\n\r\n // Keep track of added handlers to remove them on dispose\r\n const unList = this.unList = [];\r\n const on = function( element, event, handler ) {\r\n unList.push({ element, event, handler });\r\n g$.on( element, event, handler );\r\n };\r\n\r\n // Using the container to pick up mouse events\r\n on( el, 'click', this.click.bind(this) );\r\n\r\n // Handling dblclick by hand so we can support touch\r\n on( el, 'dblclick', event => { event.preventDefault(); } );\r\n\r\n // We are going to generate an equivalent but simplified API to PointerEvents\r\n // The polyfills that I found were not good enough to be able to just replace\r\n // listenning to mouse events and touch events, they included timers and other\r\n // things that were just getting in our way.\r\n\r\n if( window.PointerEvent ) { // IE11\r\n\r\n el.style['touch-action'] = 'none';\r\n\r\n on( el, 'pointerdown', this.pointerdown.bind(this) );\r\n on( document, 'pointermove', this.pointermove.bind(this) );\r\n on( document, 'pointerup' , this.pointerup.bind(this) );\r\n\r\n on( el, 'mousedown', event => { event.preventDefault(); } );\r\n // Forward mouse move to provide hover feedback\r\n on( el, 'mousemove', this.mousemove.bind(this) );\r\n }\r\n else if( window.navigator.msPointerEnabled ) { // IE10\r\n\r\n el.style['touch-action'] = 'none';\r\n\r\n on( el, 'MSPointerDown', this.pointerdown.bind(this) );\r\n on( document, 'MSPointerMove', this.pointermove.bind(this) );\r\n on( document, 'MSPointerUp' , this.pointerup.bind(this) );\r\n\r\n on( el, 'mousedown', event => { event.preventDefault(); } );\r\n // Forward mouse move to provide hover feedback\r\n on( el, 'mousemove', this.mousemove.bind(this) );\r\n }\r\n else {\r\n // Mouse + Touch for other cases\r\n\r\n on( el, 'mousedown', this.mousedown.bind(this) );\r\n on( el, 'mousemove', this.mousemove.bind(this) );\r\n\r\n // Mouse move and mouseup attached to the document so we can drag\r\n // even when out of the Canvas\r\n on( document, 'mousemove', this.doc_mousemove.bind(this) );\r\n on( document, 'mouseup' , this.doc_mouseup .bind(this) );\r\n\r\n on( el, 'touchstart' , this.touchstart.bind(this) );\r\n on( el, 'touchmove' , this.touchmove.bind(this) );\r\n on( el, 'touchend' , this.touchend.bind(this) );\r\n on( el, 'touchleave' , this.touchend.bind(this) );\r\n on( el, 'touchcancel', this.touchend.bind(this) );\r\n }\r\n\r\n on( el, 'mousewheel', this.mousewheel.bind(this) );\r\n\ton( el, 'MozMousePixelScroll', this.mousewheel.bind(this) ); // firefox\r\n\r\n // Cancel context menu\r\n g$.on( el, 'contextmenu', event => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n });\r\n\r\n g$.on( elK, 'keydown' , this.keydown.bind(this) );\r\n g$.on( elK, 'keyup' , this.keyup.bind(this) );\r\n g$.on( elK, 'keypress', this.keypress.bind(this) );\r\n\r\n if( textInputEl ) {\r\n // TextInputEl is delayed til needed\r\n this.bindToTextInputEl();\r\n }\r\n\r\n g$.on( el, 'focus' , this.focus.bind(this) );\r\n g$.on( el, 'focusout', this.focusout.bind(this) );\r\n};\r\n\r\nInteractiveHelper.prototype = {\r\n\r\n bindToTextInputEl() {\r\n if( textInputEl ) {\r\n g$.on( textInputEl, 'keydown' , this.keydown.bind(this) );\r\n g$.on( textInputEl, 'keyup' , this.keyup.bind(this) );\r\n g$.on( textInputEl, 'keypress', this.keypress.bind(this) );\r\n\r\n // g$.on( textInputEl, 'keydown' , () => { console.log('...');} );\r\n }\r\n },\r\n\r\n fireViewEvent( type, originalEvent ) {\r\n this.fireDomEvent( type, new ViewEvent( this.view, type, originalEvent ) );\r\n },\r\n\r\n fireKeyEvent( type, originalEvent ) {\r\n this.fireDomEvent( type, new ViewKeyEvent( this.view, type, originalEvent ) );\r\n },\r\n\r\n fireMouseWheelEvent( type, originalEvent ) {\r\n this.fireDomEvent( type, new ViewMouseWheelEvent( this.view, type, originalEvent ) );\r\n },\r\n\r\n firePointerEvent( type, originalEvent ) {\r\n const event = new ViewPointerEvent( this.view, type, originalEvent, this.pointers, this.eventDown );\r\n if( type === 'pointerdown' && event.isPrimary ) {\r\n this.eventDown = event;\r\n }\r\n if( type === 'pointerup' && event.isPrimary ) {\r\n this.eventDown = null;\r\n }\r\n\r\n this.fireDomEvent( type, event );\r\n\r\n if( type === 'pointerdown' && event.stopped ){\r\n this.stopClick();\r\n }\r\n },\r\n\r\n // Keep separate...\r\n\r\n fireMouseMoveEvent: fastThrottle(function( type, originalEvent ){\r\n this.firePointerEvent(type,originalEvent);\r\n },12),\r\n\r\n firePointerMoveEvent: fastThrottle(function( type, originalEvent ){\r\n this.firePointerEvent(type,originalEvent);\r\n },12),\r\n\r\n /*\r\n fireMouseMoveEvent( type, originalEvent ) {\r\n this.firePointerEvent(type,originalEvent);\r\n },\r\n\r\n firePointerMoveEvent( type, originalEvent ) {\r\n this.firePointerEvent(type,originalEvent);\r\n },\r\n */\r\n\r\n fireDomEvent( type, event ) {\r\n const { view } = this;\r\n view.fireEvent(type,event);\r\n if( ! event.stopped ) {\r\n view.on_domEvent(event);\r\n }\r\n },\r\n\r\n triggerKeyboard(event) {\r\n if( Config.mobileKeyboard ) {\r\n\r\n // This is work in progress, the idea is trigger the virtual keyboard\r\n // in mobile. The approach was clicking through a button and showing\r\n // an invisible input. This is disabled at this point, as I couldn't\r\n // make it work.\r\n\r\n if( ! textInputEl ) {\r\n initGlobalTextInputEl();\r\n this.bindToTextInputEl();\r\n }\r\n\r\n if( event ) {\r\n // Avoid jumps\r\n textInputEl.style.left = event.pageX + 'px';\r\n textInputEl.style.top = event.pageY + 'px';\r\n }\r\n\r\n textInputButtonEl.click();\r\n }\r\n },\r\n\r\n dispose() {\r\n forEach( this.unList, ({ element, event, handler }) => {\r\n g$.off( element, event, handler );\r\n });\r\n },\r\n\r\n stopClick() {\r\n this.consume_click = now();\r\n },\r\n\r\n clickConsumed() {\r\n const cc = this.consume_click;\r\n if( cc ) {\r\n if( (now()-cc) < 400 ) {\r\n return true;\r\n }\r\n else {\r\n this.consume_click = 0;\r\n }\r\n }\r\n return false;\r\n },\r\n\r\n focus(event) {\r\n this.focused = true;\r\n this.fireViewEvent('focus',event);\r\n },\r\n\r\n focusout(event) {\r\n this.pointersMap.clear();\r\n this.pointers = [];\r\n\r\n this.focused = false;\r\n this.fireViewEvent('focusout',event);\r\n },\r\n\r\n click( event ) {\r\n if( this.clickConsumed() ) {\r\n event.preventDefault();\r\n return;\r\n }\r\n if( this.enabled ) {\r\n event.preventDefault();\r\n this.firePointerEvent('click',event);\r\n }\r\n },\r\n checkDblclick( event ) {\r\n if( event.isPrimary === false ) {\r\n return; // Ignore multi touch\r\n }\r\n let t = now();\r\n const x = event.clientX, y = event.clientY;\r\n const lc = this.lastClick;\r\n const epsilon = 20;\r\n if( t - lc.t < 300 && Math.abs(x-lc.x) < epsilon && Math.abs(y-lc.y) < epsilon ) {\r\n this.dblclick(event);\r\n t = 0; // avoid firing extra dblclick when clicking several times\r\n }\r\n lc.t = t;\r\n lc.x = x;\r\n lc.y = y;\r\n },\r\n dblclick( event ) {\r\n if( this.enabled ) {\r\n event.preventDefault();\r\n this.firePointerEvent('dblclick',event);\r\n }\r\n },\r\n mousedown( event ) {\r\n if( this.enabled ) {\r\n this.mouseisdown = true;\r\n g$.focus(this.el);\r\n event.preventDefault();\r\n padScaling = 1.0;\r\n this.firePointerEvent('pointerdown',event);\r\n\r\n // if right click then also fire contextmenu event\r\n if( event.which === 3 ) {\r\n this.firePointerEvent('contextmenu',event);\r\n }\r\n }\r\n },\r\n // mousemove\r\n // If the mouse is down, forward events from everywhere in the page\r\n // If the mouse is not being pressed, just use the container events for hover to make the app faster\r\n mousemove( event ) {\r\n if( ( ! this.mouseisdown && this.pointers.length === 0 ) && this.enabled ) {\r\n padScaling = 1.0;\r\n event.preventDefault();\r\n this.firePointerMoveEvent('pointermove',event);\r\n this.fireMouseMoveEvent('mousemove',event);\r\n }\r\n },\r\n\r\n doc_mousemove( event ) {\r\n if( this.mouseisdown && this.enabled ) {\r\n event.preventDefault();\r\n this.fireMouseMoveEvent('pointermove',event);\r\n }\r\n },\r\n\r\n doc_mouseup( event ) {\r\n if( ! this.mouseisdown ) {\r\n return;\r\n }\r\n this.mouseisdown = false;\r\n if( this.enabled ) {\r\n event.preventDefault();\r\n this.firePointerEvent('pointerup',event);\r\n\r\n if( event.which === 1 ) {\r\n this.checkDblclick(event);\r\n }\r\n }\r\n },\r\n\r\n pointerdown( event ) {\r\n // We can not prevent the default here, if not mousedown is not triggered\r\n // We need to call preventDefault directly for mousedown in IE\r\n // event.preventDefault();\r\n this.pointerdown_ongoing(event);\r\n if( this.enabled ) {\r\n g$.focus(this.el);\r\n padScaling = ( event.pointerType === 'touch' || event.pointerType === 2 ) ? 2.2 : 1.0;\r\n this.firePointerEvent('pointerdown',event);\r\n\r\n // if right click then also fire contextmenu event\r\n if( event.which === 3 ) {\r\n this.fireViewEvent('contextmenu',event);\r\n }\r\n }\r\n },\r\n\r\n pointermove( event ) {\r\n if( this.pointermove_ongoing(event) && this.enabled ) {\r\n event.preventDefault();\r\n this.firePointerMoveEvent('pointermove',event);\r\n }\r\n },\r\n\r\n pointerup( event ) {\r\n const valid = this.pointerup_ongoing(event);\r\n if( valid && this.enabled ) {\r\n event.preventDefault();\r\n this.firePointerEvent('pointerup',event);\r\n\r\n // dblclick\r\n this.checkDblclick(event);\r\n }\r\n },\r\n\r\n pointerdown_ongoing( event ) {\r\n const { pointers, pointersMap } = this;\r\n const { pointerId } = event;\r\n\r\n const start = this.view.viewPoint(event);\r\n\r\n const oldPointerInfo = pointersMap.get(pointerId);\r\n if( oldPointerInfo ) {\r\n pull(pointers,oldPointerInfo);\r\n }\r\n\r\n const pointerInfo = { id: pointerId, start, current: start.clone() };\r\n\r\n pointers.push(pointerInfo);\r\n pointersMap.set(pointerId,pointerInfo);\r\n\r\n if( pointers.length >= 2 ) {\r\n // Prevent browser pinch to zoom\r\n // console.log('pointers '+pointers.length);\r\n event.preventDefault();\r\n }\r\n },\r\n\r\n pointermove_ongoing( event ) {\r\n const pointerInfo = this.pointersMap.get( event.pointerId );\r\n if( pointerInfo ) {\r\n\t pointerInfo.current = this.view.viewPoint(event);\r\n return true;\r\n }\r\n else {\r\n return false;\r\n }\r\n },\r\n\r\n pointerup_ongoing( event ) {\r\n const { pointers, pointersMap } = this;\r\n const { pointerId } = event;\r\n\r\n const n = indexOf( pointers, pointersMap.get(pointerId) );\r\n if( n >= 0 ) {\r\n pointers.splice(n,1);\r\n pointersMap.delete(pointerId);\r\n return true;\r\n }\r\n else {\r\n return false;\r\n }\r\n },\r\n\r\n touchstart( event ) {\r\n event.preventDefault();\r\n const touches = event.changedTouches;\r\n for(let i=0, iEnd=touches.length; i < iEnd; ++i) {\r\n const touch = touches.item(i),\r\n id = touch.identifier,\r\n isPrimary = ( this.pointers.length === 0 );\r\n\r\n if( isPrimary ) {\r\n this.primaryId = id;\r\n }\r\n const pointerEvent = simulatePointerEvent(event,touch,id,isPrimary);\r\n this.pointerdown(pointerEvent);\r\n }\r\n },\r\n\r\n touchmove( event ) {\r\n const touches = event.changedTouches;\r\n for(let i=0,iEnd=touches.length; i < iEnd; ++i) {\r\n const touch = touches.item(i);\r\n\t const id = touch.identifier;\r\n if( this.pointersMap.get(id) ) {\r\n event.preventDefault();\r\n const isPrimary = ( id === this.primaryId );\r\n const pointerEvent = simulatePointerEvent(event,touch,id,isPrimary);\r\n this.pointermove(pointerEvent);\r\n }\r\n }\r\n },\r\n\r\n touchend( event ) {\r\n const touches = event.changedTouches;\r\n for(let i=0,iEnd=touches.length; i < iEnd; ++i) {\r\n const touch = touches.item(i);\r\n \t const id = touch.identifier;\r\n const isPrimary = ( id === this.primaryId );\r\n if( isPrimary ) {\r\n this.primaryId = null;\r\n }\r\n if( this.pointersMap.get(id) ) {\r\n event.preventDefault();\r\n const pointerEvent = simulatePointerEvent(event,touch,id,isPrimary);\r\n this.pointerup(pointerEvent);\r\n }\r\n }\r\n },\r\n\r\n mousewheel( event ) {\r\n this.fireMouseWheelEvent('mousewheel',event);\r\n },\r\n\r\n keydown( event ) {\r\n const captureKey = this.captureKey;\r\n if( ( !captureKey || captureKey(this,event) ) && this.enabled ) {\r\n this.fireKeyEvent('keydown', event);\r\n }\r\n },\r\n\r\n keyup( event ) {\r\n const captureKey = this.captureKey;\r\n if( ( !captureKey || captureKey(this,event) ) && this.enabled ) {\r\n this.fireKeyEvent('keyup', event);\r\n }\r\n },\r\n\r\n keypress( event ) {\r\n const captureKey = this.captureKey;\r\n if( ( !captureKey || captureKey(this,event) ) && this.enabled ) {\r\n this.fireKeyEvent('keypress', event);\r\n }\r\n }\r\n};\r\n\r\n// Utilities\r\n//------------------------------------------------------------------------------\r\n\r\nfunction simulatePointerEvent(event,touch,touchId,isPrimary) {\r\n usingTouch = true;\r\n\r\n const pointerEvent = document.createEvent(\"MouseEvents\");\r\n let type = null;\r\n\r\n switch( event.type ) {\r\n case \"touchstart\" : type = \"mousedown\"; break;\r\n case \"touchmove\" : type = \"mousemove\"; break;\r\n case \"touchend\" :\r\n case \"touchleave\" :\r\n case \"touchcancel\": type = \"mouseup\" ; break;\r\n default: type = \"mousedown\";\r\n }\r\n pointerEvent.initMouseEvent(type, true, true, event.target.ownerDocument.defaultView, 0,\r\n touch.screenX, touch.screenY, touch.clientX, touch.clientY,\r\n event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, 0, null);\r\n pointerEvent.pointerType = 'touch';\r\n pointerEvent.pointerId = touchId;\r\n pointerEvent.isPrimary = isPrimary;\r\n return pointerEvent;\r\n}\r\n\r\n\r\nfunction forwardTrackerGetters( getters, proto ) {\r\n forEach( getters, getter => {\r\n Object.defineProperty(proto,getter,{\r\n get() {\r\n if( ! this._target ) {\r\n this._target = this._tracker.track(this);\r\n }\r\n return this._target[getter];\r\n }\r\n });\r\n });\r\n return proto;\r\n}\r\n\r\nfunction forwardEventGetters( getters, proto ) {\r\n forEach( getters, getter => {\r\n Object.defineProperty(proto,getter,{\r\n get() {\r\n return this._e[getter];\r\n }\r\n });\r\n });\r\n return proto;\r\n}\r\n\r\nfunction extendProto( proto, config ){\r\n forEach( keys(config), key => {\r\n const descriptor = Object.getOwnPropertyDescriptor(config,key);\r\n if( descriptor.get || descriptor.set ) {\r\n Object.defineProperty(proto,key,descriptor);\r\n }\r\n else {\r\n proto[key] = config[key];\r\n }\r\n });\r\n return proto;\r\n}\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/view/events.js\n **/","import { forEach } from 'lodash';\r\nimport { OwnedObject } from 'gear';\r\n\r\n// A non interactive plugin that just render\r\nexport const RenderPlugin = OwnedObject.extend({ typeName: 'RenderPlugin',\r\n\r\n drawTo: [],\r\n\r\n target: 'document',\r\n\r\n Properties: {\r\n\r\n visible: { type: 'boolean', def: true, onChange() {\r\n this[ this._visible ? 'show' : 'hide' ](this);\r\n this.redraw();\r\n }}\r\n },\r\n\r\n initPlugin( /*view, ...init params*/ ) { },\r\n\r\n draw( /*{ view, context, transform }*/ ) { },\r\n\r\n show( /*view*/) { },\r\n hide( /*view*/) { },\r\n\r\n link( /*view*/) { },\r\n\r\n unlink( view ) {\r\n view.un(this);\r\n },\r\n\r\n updateSize( /*view,box*/) { },\r\n\r\n // Forward params to initPlugin\r\n init( ...params ) {\r\n this._params = params;\r\n this.view = null;\r\n },\r\n\r\n initView( view ) {\r\n this.view = view;\r\n this.initPlugin(view,...this._params);\r\n this.link(view);\r\n },\r\n\r\n initLayer(/* layer */) {\r\n // Used by 3D to hook a THREE.WebGLRenderer to a layer\r\n },\r\n\r\n dispose() {\r\n this.unlink(this.view);\r\n },\r\n\r\n redraw() {\r\n this.view.redraw(...this.drawTo);\r\n },\r\n\r\n has_try_pointerdown() {\r\n return this.try_pointerdown;\r\n },\r\n has_try_click() {\r\n return this.try_click;\r\n },\r\n has_try_dblclick() {\r\n return this.try_dblclick;\r\n },\r\n has_try_contextmenu() {\r\n return this.try_contextmenu;\r\n }\r\n\r\n});\r\n\r\nexport const Plugin = RenderPlugin.extend({ typeName: 'Plugin',\r\n\r\n isInteractive: true,\r\n\r\n Properties: {\r\n enabled: { type: 'boolean', def: true, onChange() {\r\n this.redraw();\r\n }}\r\n },\r\n\r\n takeControl() {\r\n const state = this._state = {};\r\n forEach( this.view._plugins, plugin => {\r\n state[ plugin.name ] = { visible: plugin._visible, enabled: plugin._enabled };\r\n const isThis = plugin === this;\r\n plugin.visible = isThis;\r\n plugin.enabled = isThis;\r\n });\r\n this.redraw();\r\n },\r\n releaseControl() {\r\n forEach( this.view._plugins, plugin => {\r\n const pluginState = this._state[plugin.name];\r\n if( pluginState ) {\r\n plugin.visible = pluginState.visible;\r\n plugin.enabled = pluginState.enabled;\r\n }\r\n });\r\n this.redraw();\r\n },\r\n\r\n draw( config ) {\r\n const { helper } = this;\r\n if( helper && helper.draw ){\r\n helper.draw(config);\r\n }\r\n },\r\n\r\n somethingToDraw() {\r\n return true;\r\n },\r\n\r\n needsToDrawFor(/* figure */) {\r\n return true;\r\n },\r\n\r\n handleDomEvent({ event, type, route, isPrimary }){\r\n\r\n const { helper } = this;\r\n if( helper ){\r\n if( type === 'pointermove' ) {\r\n helper.move(event);\r\n this.redraw();\r\n }\r\n else if( type === 'pointerup' ) {\r\n helper.end(event);\r\n this.helper = null;\r\n this.redraw();\r\n }\r\n else if( type === 'pointerdown' && isPrimary ) {\r\n console.log('Missing pointerup');\r\n helper.end(event);\r\n this.helper = null;\r\n this.redraw();\r\n }\r\n }\r\n\r\n if( event.stopped ) {\r\n return;\r\n }\r\n\r\n if( this._visible && this._enabled ) {\r\n if( this[route] ) {\r\n this[route](event);\r\n }\r\n this.on_domEvent(event);\r\n }\r\n },\r\n\r\n on_domEvent(/* event */) {},\r\n\r\n /*\r\n on_focus ( event ) { },\r\n on_focusout ( event ) { },\r\n on_click ( event ) { },\r\n on_dblclick ( event ) { },\r\n on_pointerdown ( event ) { },\r\n on_pointerup ( event ) { },\r\n on_pointermove ( event ) { },\r\n on_mousemove ( event ) { },\r\n on_keypress ( event ) { },\r\n on_keyup ( event ) { },\r\n on_keydown ( event ) { },\r\n on_contextmenu ( event ) { },\r\n on_mousewheel ( event ) { }\r\n */\r\n});\r\n\r\nPlugin.PluginsLayer = Plugin.extend({ typeName: 'PluginsLayerPlugin',\r\n name: 'pluginsLayer',\r\n drawTo: [ 'plugins' ],\r\n target: 'view'\r\n});\r\n\r\nexport function redraw_this() {\r\n this.redraw();\r\n}\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/view/plugin.js\n **/","import { forEach, last, flatten, isPlainObject } from 'lodash';\r\n\r\nimport { OwnedObject, Deferred, resolve } from 'gear';\r\n\r\nimport { Brush, Pen } from 'cdl';\r\n\r\nimport { Plugin } from './plugin';\r\n\r\n/*\r\nToolType = [\r\n 'Select', // Special tool used for selecting and transforming figures\r\n 'Flat', // Tools that should forward commits (Zoom,Pan)\r\n 'View', // Tools for changing view properties (Zoom,Pan)\r\n 'Normal', // Tools that allow the use of View tools on top of them (NodeEdit)\r\n 'Final', // Tools that doesn't support any kind of stacking (Draw)\r\n 'Stackable' // Tools that creates an edition context (Deprecated, using ContentLayer now)\r\n]\r\n*/\r\n\r\n//\r\n// Rules\r\n\r\nexport const Tool = OwnedObject.extend({ typeName: 'Tool',\r\n\r\n type: 'Final',\r\n isCommitable: true,\r\n\r\n // initTool( view, ...init params ) {},\r\n\r\n link( /*view*/ ) {},\r\n unlink( /*view*/ ) {},\r\n\r\n start( /*view*/ ) { },\r\n pause( /*view*/ ) { },\r\n resume( /*view*/ ) { },\r\n finish( /*view*/ ) { },\r\n\r\n // _commit$( view ) {},\r\n // _cancel$( view ) {},\r\n\r\n draw( /* config */ ) { },\r\n\r\n commit$() { const view = this.view; const doc = view._document;\r\n if( this._commit$ ) {\r\n return resolve(this._commit$(view,doc)) .then( () => {\r\n return this.stop('commit$');\r\n });\r\n }\r\n else {\r\n return this.stop('commit$');\r\n }\r\n },\r\n\r\n cancel$() {\r\n const { view } = this;\r\n const { doc } = view;\r\n if( this._cancel$ ) {\r\n return resolve( this._cancel$(view,doc) ) .then( () => {\r\n return this.stop('cancel$');\r\n });\r\n }\r\n else {\r\n return this.stop('cancel$');\r\n }\r\n },\r\n\r\n redraw() {\r\n this.view.redraw('tools');\r\n },\r\n\r\n // Forward helper ( move, end, draw ) to the plugin\r\n get helper() {\r\n return this.view.tools.helper;\r\n },\r\n set helper( h ) {\r\n this.view.tools.helper = h;\r\n },\r\n\r\n init( a, b, c ) {\r\n this._sleeping = false;\r\n this._params = {a:a,b:b,c:c};\r\n this._deferred = new Deferred();\r\n\r\n // [TODO] Eliminate this...\r\n const config = isPlainObject(a) ? a\r\n : isPlainObject(b) ? b\r\n : isPlainObject(c) ? c : {};\r\n\r\n if( config !== a ) {\r\n this.initProperties(config);\r\n }\r\n\r\n forEach(['start','finish','pause','resume'], func =>\r\n config[func] && ( this[func] = config[func] )\r\n );\r\n\r\n this._bind('commit$')\r\n ._bind('cancel$')\r\n ._bind('stop' );\r\n },\r\n\r\n initView( view ) {\r\n this.view = view;\r\n const p = this._params;\r\n resolve( this.initTool(view,p.a,p.b,p.c) ).then( () => {\r\n this.link(view);\r\n this.start();\r\n this.redraw();\r\n });\r\n },\r\n\r\n promise() {\r\n return this._deferred.promise;\r\n },\r\n\r\n sleep() {\r\n this.unlink(this.view);\r\n this.pause();\r\n this._sleeping = true;\r\n },\r\n\r\n wakeup() {\r\n this._sleeping = false;\r\n this.link(this.view);\r\n this.resume();\r\n },\r\n\r\n stop( event ) {\r\n const { view } = this;\r\n this._stopped = true;\r\n this._deferred.resolve();\r\n return resolve( view.popTool() ) .then( () => {\r\n if( event && this.type === 'View' ) {\r\n // Forward commit and cancel event to the underlying tool\r\n return view.tool[event]();\r\n }\r\n });\r\n },\r\n\r\n dispose() {\r\n this.unlink(this.view);\r\n this.finish();\r\n },\r\n\r\n get cursor() {\r\n return this.view.cursor;\r\n },\r\n set cursor( cursor_ ) {\r\n this.view.cursor = cursor_;\r\n },\r\n\r\n toolhelp(/* ...params */) {\r\n this.view.toolhelp(...arguments);\r\n },\r\n\r\n triggerKeyboard(event) {\r\n this.view.triggerKeyboard(event);\r\n },\r\n\r\n /*\r\n on_focus( event ) { },\r\n on_focusout( event ) { },\r\n on_click( event ) { },\r\n on_dblclick( event ) { },\r\n on_pointerdown( event ) { },\r\n on_pointerup( event ) { },\r\n on_pointermove( event ) { },\r\n on_mousemove( event ) { },\r\n on_keypress( event ) { },\r\n on_keyup( event ) { },\r\n on_keydown( event ) { },\r\n on_contextmenu( event ) { }\r\n */\r\n\r\n canUndo() {\r\n return false;\r\n },\r\n undo() {},\r\n\r\n canRedo() {\r\n return false;\r\n },\r\n redo() {},\r\n\r\n supportsClipboard() {\r\n return false;\r\n },\r\n\r\n somethingToDraw() {\r\n return true;\r\n },\r\n\r\n needsToDrawFor(/* docIsland */) {\r\n return true;\r\n }\r\n});\r\n\r\nTool.defaultPen = function() {\r\n return Pen({color:{rgb:'000000'},width:2});\r\n};\r\n\r\nTool.defaultBrush = function() {\r\n return Brush({color:{rgb:'2533AA'}});\r\n};\r\n\r\nPlugin.Tools = Plugin.extend({ typeName: 'ToolsPlugin',\r\n\r\n name: 'tools',\r\n\r\n drawTo: [ 'tools' ],\r\n\r\n initPlugin( view ) {\r\n this._tools = [];\r\n this._toolhelp = '';\r\n this._trackPointer = false;\r\n view.on({ 'change' : this.redraw }, this );\r\n },\r\n\r\n toolhelp( string ) {\r\n if( string === null ) {\r\n this._toolhelp = null;\r\n }\r\n else {\r\n const th = flatten(arguments);\r\n this._toolhelp = th[0];\r\n for(let k=1,kEnd=th.length;k'+status.message;\r\n if( status.commit ) {\r\n html += '';\r\n }\r\n html += '
';\r\n el.innerHTML = html;\r\n }\r\n\r\n el.style.display = status ? 'inline' : 'none';\r\n },\r\n //----------------------------------------------------------------\r\n\r\n\r\n // [TODO] Plugin.Tooltip, only used by the Head Up Display, move this there\r\n //----------------------------------------------------------------\r\n\r\n initTooltip() {\r\n const tooltipId = this.container.id+\"_tooltip\";\r\n g$.append( this.container,\r\n ``\r\n );\r\n this._tooltipEl = g$(\"#\"+tooltipId);\r\n },\r\n showTooltip( message, point ) {\r\n const tel = this._tooltipEl;\r\n if( tel ) {\r\n this.hideTooltip();\r\n const cp = point.x < 300 ? Point.add(point,new Point(20,10)) : Point.add(point,new Point(-message.length*6-18,0));\r\n if( point.y > 400 ) {\r\n cp.y -= 40;\r\n }\r\n tel.innerHTML = message;\r\n\r\n assign( tel.style, {\r\n 'left' : cp.x+'px',\r\n 'top' : cp.y+'px',\r\n 'display': 'block'\r\n });\r\n\r\n this._tooltipVisible = true;\r\n }\r\n },\r\n hideTooltip() {\r\n if( this._tooltipVisible ) {\r\n const tel = this._tooltipEl;\r\n if( tel ) {\r\n tel.style.display = 'none';\r\n this._tooltipVisible = false;\r\n }\r\n }\r\n }\r\n};\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/view/interactive-view.js\n **/","import { forEach, includes, last, assign } from 'lodash';\r\n\r\nimport { clearContext, dot } from 'gear';\r\n\r\nimport { Plugin } from '../view';\r\n\r\nimport { draw_colorShowthrough_gl } from '../../cdl/style/color-showthrough';\r\n\r\nPlugin.ActiveRenderer = Plugin.extend({ typeName: 'ActiveRendererPlugin',\r\n name: 'renderer',\r\n\r\n target: 'document',\r\n\r\n drawTo_color: [ 'background', 'document', 'foreground' ],\r\n\r\n redrawFigure( view,figure ) {\r\n if( includes( view._activeFigures, figure ) ) {\r\n view.redraw('document');\r\n }\r\n else {\r\n if( figure.document === view._mainDocument ) {\r\n view.redraw('document');\r\n }\r\n else {\r\n view.redraw('background');\r\n }\r\n }\r\n },\r\n\r\n // Draw everything that is behind the first active figure\r\n draw_background({ view, context, transform }) {\r\n view.fillWithBackgroundColor(context);\r\n\r\n const firstActiveFigure = view._activeFigures[0];\r\n const lastFigure = firstActiveFigure || 'doc';\r\n\r\n this.drawFigures(view,context,transform,{\r\n until: lastFigure\r\n });\r\n },\r\n\r\n // draw active figures, or current document\r\n draw_document({ view, context, transform }) {\r\n const activeFigures = view._activeFigures;\r\n if( activeFigures.length > 0 ) {\r\n const alpha = this._activeAlpha;\r\n if( alpha === 0 ) {\r\n return;\r\n }\r\n if( alpha !== undefined && alpha < 1 ) {\r\n context.globalAlpha *= alpha;\r\n }\r\n }\r\n\r\n const firstActiveFigure = activeFigures[0] || 'doc';\r\n const lastActiveFigure = last(activeFigures);\r\n \r\n draw_colorShowthrough_gl(view, context, transform, this, firstActiveFigure, lastActiveFigure);\r\n\r\n if( activeFigures.length === 0 ) {\r\n this.drawSpecialPens(view,context,transform);\r\n }\r\n },\r\n\r\n // In case there are active figures, draw everything above them\r\n draw_foreground({ view, context, transform }) {\r\n const activeFigures = view._activeFigures;\r\n if( activeFigures.length === 0 ) {\r\n // clearContext(context);\r\n return;\r\n }\r\n\r\n const lastActiveFigure = last(activeFigures);\r\n const firstFigure = lastActiveFigure || 'doc';\r\n\r\n this.drawFigures(view,context,transform,{\r\n from: firstFigure, skipFirst: true\r\n });\r\n\r\n this.drawSpecialPens(view,context,transform);\r\n },\r\n\r\n drawSpecialPens( view, context, transform ) {\r\n const { specialPens } = view;\r\n if( specialPens ) {\r\n specialPens.drawForPage(view._mainDocument.activePage,context,transform);\r\n }\r\n },\r\n\r\n drawFigures( view,context,transform,span,clearBuffer = false, drawShowthroughMask = false) {\r\n const { from } = span;\r\n const drawing = { start: ! from || from === 'doc', end: false };\r\n const config = { editingContent: view._mainDocument.editingContent() };\r\n\r\n const page = view._mainDocument.activePage;\r\n\r\n const backgroundPage = view.backgroundPageFor(page);\r\n if( backgroundPage && from !== 'doc' ) {\r\n this.drawPage( view, backgroundPage,\r\n context, transform, config, span, drawing, clearBuffer, drawShowthroughMask );\r\n }\r\n\r\n if( drawing.end || span.until === 'doc' ) {\r\n return false;\r\n }\r\n\r\n this.drawPage( view, page, context, transform, config, span, drawing, clearBuffer, drawShowthroughMask );\r\n\r\n },\r\n\r\n drawPage( view,page, context, transform, config,\r\n { from, skipFirst, until, includeLast }, drawing, clearBuffer = false, drawShowthroughMask = false ) {\r\n \r\n config = assign( { wireframe: view.wireframe }, config );\r\n config = assign( { showthroughColor: view.showThroughColor }, config);\r\n forEach( page.layers, layer => {\r\n\r\n // This is not the best for this pattern, but we may remove the\r\n // isolated figures pattern soon.\r\n layer.beforeDraw(context,config);\r\n\r\n forEach( layer.figures, figure => {\r\n if( ! skipFirst && from === figure ) {\r\n drawing.start = true;\r\n }\r\n if( ! includeLast && until === figure ) {\r\n drawing.end = true;\r\n }\r\n\r\n if( drawing.start && ! drawing.end ) {\r\n\r\n const figureView = view.figureView(figure);\r\n if( figureView ) {\r\n figureView.draw(context,transform,config,clearBuffer,drawShowthroughMask);\r\n }\r\n else {\r\n console.log('[Error] FigureView is undefined');\r\n }\r\n\r\n if( view._showPin ) {\r\n dot(context,figure.pin,3,transform,'#ffffff','#222222',4);\r\n }\r\n }\r\n\r\n if( skipFirst && from === figure ) {\r\n drawing.start = true;\r\n }\r\n if( includeLast && until === figure ) {\r\n drawing.end = true;\r\n }\r\n\r\n if( drawing.end ) {\r\n return false;\r\n }\r\n });\r\n\r\n layer.afterDraw(context,config); // [TODO]\r\n\r\n if( drawing.end ) {\r\n return false;\r\n }\r\n });\r\n }\r\n});\r\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ui/plugin/active-renderer.js\n **/","import { Config } from 'config';\r\nimport { forEach, map } from 'lodash';\r\nimport { OwnedObject, invalidateOwner } from 'gear';\r\nimport { Point } from '../geometry';\r\nimport { Color } from './color';\r\nimport { Figures } from '../figure';\r\nimport { ReplaceSTEffect } from './glEffects/replaceST';\r\n// values between 0...255\r\n// map :: function(r,g,b,a){ return [ r*, g*, b*, a* ]; }\r\n\r\nconst modifyImageDataRGBA = function(imageData,map, extended = false){\r\n const data = imageData.data, width = imageData.width, height = imageData.height;\r\n let y, x, inpos, outpos, r, g, b, a;\r\n\r\n for(y = 0; y < height; ++y) {\r\n inpos = y * width * 4; // *4 for 4 ints per pixel\r\n outpos = inpos;\r\n for(x = 0; x < width; ++x) {\r\n\r\n r = data[inpos++];\r\n g = data[inpos++];\r\n b = data[inpos++];\r\n a = data[inpos++]; // alpha\r\n\r\n // http://www.w3.org/TR/AERT#color-contrast\r\n const c = map(r,g,b,a);\r\n\r\n data[outpos++] = c[0];\r\n data[outpos++] = c[1];\r\n data[outpos++] = c[2];\r\n data[outpos++] = c[3];\r\n\r\n if (extended && !(c[0]==10 && c[1]==10 && c[2]==10 && c[3]==0))\r\n {\r\n let currentPos = outpos - 4;\r\n let done = false;\r\n \r\n for (let i = 1; i < 3; ++i)\r\n if (x < width - i)\r\n {\r\n const c2 = map(data[inpos++],data[inpos++],data[inpos++],data[inpos++]);\r\n if (c2[0]==10 && c2[1]==10 && c2[2]==10 && c2[3]==0)\r\n {\r\n outpos-=4;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n done = true;\r\n break;\r\n }\r\n }\r\n \r\n for (let i = 1; i < 3; ++i)\r\n if (!done && x >= i)\r\n {\r\n inpos = currentPos - 4*i;\r\n const c3 = map(data[inpos++],data[inpos++],data[inpos++],data[inpos++]);\r\n if (c3[0]==10 && c3[1]==10 && c3[2]==10 && c3[3]==0)\r\n {\r\n outpos-=4;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 1; i < 3; ++i)\r\n if (y < height - i)\r\n {\r\n inpos = currentPos + 4*i*width;\r\n const c2 = map(data[inpos++],data[inpos++],data[inpos++],data[inpos++]);\r\n if (c2[0]==10 && c2[1]==10 && c2[2]==10 && c2[3]==0)\r\n {\r\n outpos-=4;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n done = true;\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 1; i < 3; ++i)\r\n if (y >= i)\r\n {\r\n inpos = currentPos - 4*i*width;\r\n const c2 = map(data[inpos++],data[inpos++],data[inpos++],data[inpos++]);\r\n if (c2[0]==10 && c2[1]==10 && c2[2]==10 && c2[3]==0)\r\n {\r\n outpos-=4;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n data[outpos++] = 0;\r\n done = true;\r\n break;\r\n }\r\n }\r\n outpos = currentPos+4;\r\n inpos = currentPos+4;\r\n }\r\n }\r\n }\r\n};\r\n\r\n// ColorShowthrough\r\n//======================================================================================\r\nconst draw_colorShowthrough = function( view, context, transform, renderer, firstActiveFigure, lastActiveFigure ) {\r\n\r\n const lAvoidSlowST = Config.avoidRenderingShowThroughNoGL;\r\n\r\n const lSTColors = [];\r\n\r\n if (!lAvoidSlowST)\r\n {\r\n const page = view._mainDocument.activePage;\r\n forEach( page.layers, layer => {\r\n Figures.forEachColor( layer.figures, c => {\r\n if( c && c.showThrough && ! lSTColors.indexOf(c)>=0 ) {\r\n lSTColors.push(c);\r\n }\r\n })});\r\n }\r\n\r\n if (lSTColors.length > 0 && !lAvoidSlowST)\r\n {\r\n let canvas = document.createElement('canvas');\r\n canvas.width = view.width;\r\n canvas.height = view.height;\r\n let ctx = canvas.getContext('2d');\r\n\r\n renderer.drawFigures(view,ctx,transform,{\r\n from: firstActiveFigure,\r\n until: lastActiveFigure, includeLast: true,\r\n });\r\n\r\n let lImageData = ctx.getImageData(0,0,canvas.width,canvas.height);\r\n\r\n modifyImageDataRGBA( lImageData, (r,g,b,a) => {\r\n let lRet = [r,g,b,a];\r\n lSTColors.forEach(function(c) {\r\n if (c.r() == r && c.g() == g && c.b() == b )\r\n lRet = [10,10,10,0];\r\n }, this);\r\n return lRet;\r\n }, true);\r\n\r\n context.putImageData(lImageData,0,0);\r\n }\r\n else\r\n {\r\n renderer.drawFigures(view,context,transform,{\r\n from: firstActiveFigure,\r\n until: lastActiveFigure, includeLast: true,\r\n });\r\n }\r\n}\r\n\r\n// ColorShowthrough\r\n//======================================================================================\r\nlet mGlCanvas = null;\r\nlet mGlCtx = null;\r\nlet mEffect = null;\r\nlet mCanvasST = null;\r\nlet mCanvasNormal = null;\r\n\r\nexport const draw_colorShowthrough_gl = function( view, context, transform, renderer, firstActiveFigure, lastActiveFigure ) {\r\n let lHasST = false;\r\n let lNeedsBufferClear = false;\r\n const page = view._mainDocument.activePage;\r\n\r\n let lNrLayers = page.layers.length;\r\n\r\n for(let iLayer = 0; !lHasST && iLayer < lNrLayers; iLayer++) {\r\n let lLayer = page.layers[iLayer];\r\n let lFigures = lLayer.figures;\r\n let lNrFigures = lFigures.length;\r\n for(let k=0;!lHasST && k