From 85e85838e68fe39ab69556bb895fd95e96e776ba Mon Sep 17 00:00:00 2001 From: Rod Roark Date: Sat, 28 May 2016 11:51:16 -0700 Subject: [PATCH] Added literallycanvas and react libraries. --- library/js/literallycanvas/README.openemr.txt | 6 + library/js/literallycanvas/README.txt | 44 + library/js/literallycanvas/bower.json | 29 + .../literallycanvas/css/literallycanvas.css | 1 + library/js/literallycanvas/img/alpha.png | Bin 0 -> 7224 bytes .../literallycanvas/img/checkerboard-8x8.png | Bin 0 -> 1087 bytes .../js/literallycanvas/img/dashed-line.png | Bin 0 -> 4328 bytes library/js/literallycanvas/img/ellipse.png | Bin 0 -> 4933 bytes library/js/literallycanvas/img/eraser.png | Bin 0 -> 373 bytes library/js/literallycanvas/img/eyedropper.png | Bin 0 -> 468 bytes library/js/literallycanvas/img/hue.png | Bin 0 -> 4201 bytes .../literallycanvas/img/line-with-arrow.png | Bin 0 -> 4312 bytes library/js/literallycanvas/img/line.png | Bin 0 -> 191 bytes library/js/literallycanvas/img/pan.png | Bin 0 -> 384 bytes library/js/literallycanvas/img/pencil.png | Bin 0 -> 302 bytes .../js/literallycanvas/img/polygon-cancel.png | Bin 0 -> 2269 bytes .../js/literallycanvas/img/polygon-closed.png | Bin 0 -> 1954 bytes .../js/literallycanvas/img/polygon-open.png | Bin 0 -> 1907 bytes library/js/literallycanvas/img/polygon.png | Bin 0 -> 1786 bytes library/js/literallycanvas/img/rectangle.png | Bin 0 -> 181 bytes library/js/literallycanvas/img/redo.png | Bin 0 -> 5091 bytes library/js/literallycanvas/img/saturation.png | Bin 0 -> 37098 bytes library/js/literallycanvas/img/screenshot.png | Bin 0 -> 218926 bytes library/js/literallycanvas/img/text.png | Bin 0 -> 4315 bytes library/js/literallycanvas/img/undo.png | Bin 0 -> 1479 bytes library/js/literallycanvas/img/zoom-in.png | Bin 0 -> 1991 bytes library/js/literallycanvas/img/zoom-out.png | Bin 0 -> 1934 bytes .../js/core/LiterallyCanvas.js | 844 + .../literallycanvas/js/core/TextRenderer.js | 201 + library/js/literallycanvas/js/core/actions.js | 80 + .../js/literallycanvas/js/core/bindEvents.js | 131 + .../literallycanvas/js/core/canvasRenderer.js | 258 + .../literallycanvas/js/core/defaultOptions.js | 21 + .../js/literallycanvas/js/core/fontmetrics.js | 197 + .../js/core/lineEndCapShapes.js | 48 + .../literallycanvas/js/core/localization.js | 18 + library/js/literallycanvas/js/core/math.js | 86 + .../js/core/renderSnapshotToImage.js | 96 + .../js/core/renderSnapshotToSVG.js | 72 + library/js/literallycanvas/js/core/shapes.js | 921 + .../js/literallycanvas/js/core/svgRenderer.js | 138 + library/js/literallycanvas/js/core/util.js | 214 + .../js/literallycanvas/js/ie_customevent.js | 14 + .../js/literallycanvas/js/ie_setLineDash.js | 13 + library/js/literallycanvas/js/index.js | 178 + .../js/literallycanvas-core.js | 4745 ++++ .../js/literallycanvas-core.min.js | 3 + .../js/literallycanvas/js/literallycanvas.js | 6418 +++++ .../literallycanvas/js/literallycanvas.min.js | 4 + .../literallycanvas/js/optionsStyles/font.js | 191 + .../line-options-and-stroke-width.js | 72 + .../literallycanvas/js/optionsStyles/null.js | 14 + .../js/optionsStyles/optionsStyles.js | 14 + .../optionsStyles/polygon-and-stroke-width.js | 109 + .../js/optionsStyles/stroke-or-fill.js | 69 + .../js/optionsStyles/stroke-width.js | 9 + .../js/reactGUI/ClearButton.js | 44 + .../literallycanvas/js/reactGUI/ColorWell.js | 364 + .../js/reactGUI/LiterallyCanvas.js | 104 + .../js/literallycanvas/js/reactGUI/Options.js | 40 + .../js/literallycanvas/js/reactGUI/Picker.js | 97 + .../literallycanvas/js/reactGUI/React-shim.js | 13 + .../js/reactGUI/ReactDOM-shim.js | 21 + .../js/reactGUI/StrokeWidthPicker.js | 59 + .../js/reactGUI/UndoRedoButtons.js | 81 + .../js/reactGUI/ZoomButtons.js | 81 + .../js/reactGUI/createSetStateOnEventMixin.js | 18 + .../js/reactGUI/createToolButton.js | 49 + .../js/literallycanvas/js/reactGUI/init.js | 36 + .../js/literallycanvas/js/reactGUI/initDOM.js | 22 + .../js/literallycanvas/js/tools/Ellipse.js | 42 + library/js/literallycanvas/js/tools/Eraser.js | 35 + .../js/literallycanvas/js/tools/Eyedropper.js | 58 + library/js/literallycanvas/js/tools/Line.js | 54 + library/js/literallycanvas/js/tools/Pan.js | 66 + library/js/literallycanvas/js/tools/Pencil.js | 59 + .../js/literallycanvas/js/tools/Polygon.js | 213 + .../js/literallycanvas/js/tools/Rectangle.js | 42 + .../literallycanvas/js/tools/SelectShape.js | 152 + library/js/literallycanvas/js/tools/Text.js | 358 + library/js/literallycanvas/js/tools/base.js | 71 + library/js/react/README.md | 116 + library/js/react/README.openemr.txt | 5 + library/js/react/build/react-dom-server.js | 42 + .../js/react/build/react-dom-server.min.js | 12 + library/js/react/build/react-dom.js | 42 + library/js/react/build/react-dom.min.js | 12 + library/js/react/build/react-with-addons.js | 21792 ++++++++++++++++ .../js/react/build/react-with-addons.min.js | 16 + library/js/react/build/react.js | 19599 ++++++++++++++ library/js/react/build/react.min.js | 16 + 91 files changed, 59089 insertions(+) create mode 100644 library/js/literallycanvas/README.openemr.txt create mode 100644 library/js/literallycanvas/README.txt create mode 100644 library/js/literallycanvas/bower.json create mode 100644 library/js/literallycanvas/css/literallycanvas.css create mode 100644 library/js/literallycanvas/img/alpha.png create mode 100644 library/js/literallycanvas/img/checkerboard-8x8.png create mode 100644 library/js/literallycanvas/img/dashed-line.png create mode 100644 library/js/literallycanvas/img/ellipse.png create mode 100644 library/js/literallycanvas/img/eraser.png create mode 100644 library/js/literallycanvas/img/eyedropper.png create mode 100644 library/js/literallycanvas/img/hue.png create mode 100644 library/js/literallycanvas/img/line-with-arrow.png create mode 100644 library/js/literallycanvas/img/line.png create mode 100644 library/js/literallycanvas/img/pan.png create mode 100644 library/js/literallycanvas/img/pencil.png create mode 100644 library/js/literallycanvas/img/polygon-cancel.png create mode 100644 library/js/literallycanvas/img/polygon-closed.png create mode 100644 library/js/literallycanvas/img/polygon-open.png create mode 100644 library/js/literallycanvas/img/polygon.png create mode 100644 library/js/literallycanvas/img/rectangle.png create mode 100644 library/js/literallycanvas/img/redo.png create mode 100644 library/js/literallycanvas/img/saturation.png create mode 100644 library/js/literallycanvas/img/screenshot.png create mode 100644 library/js/literallycanvas/img/text.png create mode 100644 library/js/literallycanvas/img/undo.png create mode 100644 library/js/literallycanvas/img/zoom-in.png create mode 100644 library/js/literallycanvas/img/zoom-out.png create mode 100644 library/js/literallycanvas/js/core/LiterallyCanvas.js create mode 100644 library/js/literallycanvas/js/core/TextRenderer.js create mode 100644 library/js/literallycanvas/js/core/actions.js create mode 100644 library/js/literallycanvas/js/core/bindEvents.js create mode 100644 library/js/literallycanvas/js/core/canvasRenderer.js create mode 100644 library/js/literallycanvas/js/core/defaultOptions.js create mode 100644 library/js/literallycanvas/js/core/fontmetrics.js create mode 100644 library/js/literallycanvas/js/core/lineEndCapShapes.js create mode 100644 library/js/literallycanvas/js/core/localization.js create mode 100644 library/js/literallycanvas/js/core/math.js create mode 100644 library/js/literallycanvas/js/core/renderSnapshotToImage.js create mode 100644 library/js/literallycanvas/js/core/renderSnapshotToSVG.js create mode 100644 library/js/literallycanvas/js/core/shapes.js create mode 100644 library/js/literallycanvas/js/core/svgRenderer.js create mode 100644 library/js/literallycanvas/js/core/util.js create mode 100644 library/js/literallycanvas/js/ie_customevent.js create mode 100644 library/js/literallycanvas/js/ie_setLineDash.js create mode 100644 library/js/literallycanvas/js/index.js create mode 100644 library/js/literallycanvas/js/literallycanvas-core.js create mode 100644 library/js/literallycanvas/js/literallycanvas-core.min.js create mode 100644 library/js/literallycanvas/js/literallycanvas.js create mode 100644 library/js/literallycanvas/js/literallycanvas.min.js create mode 100644 library/js/literallycanvas/js/optionsStyles/font.js create mode 100644 library/js/literallycanvas/js/optionsStyles/line-options-and-stroke-width.js create mode 100644 library/js/literallycanvas/js/optionsStyles/null.js create mode 100644 library/js/literallycanvas/js/optionsStyles/optionsStyles.js create mode 100644 library/js/literallycanvas/js/optionsStyles/polygon-and-stroke-width.js create mode 100644 library/js/literallycanvas/js/optionsStyles/stroke-or-fill.js create mode 100644 library/js/literallycanvas/js/optionsStyles/stroke-width.js create mode 100644 library/js/literallycanvas/js/reactGUI/ClearButton.js create mode 100644 library/js/literallycanvas/js/reactGUI/ColorWell.js create mode 100644 library/js/literallycanvas/js/reactGUI/LiterallyCanvas.js create mode 100644 library/js/literallycanvas/js/reactGUI/Options.js create mode 100644 library/js/literallycanvas/js/reactGUI/Picker.js create mode 100644 library/js/literallycanvas/js/reactGUI/React-shim.js create mode 100644 library/js/literallycanvas/js/reactGUI/ReactDOM-shim.js create mode 100644 library/js/literallycanvas/js/reactGUI/StrokeWidthPicker.js create mode 100644 library/js/literallycanvas/js/reactGUI/UndoRedoButtons.js create mode 100644 library/js/literallycanvas/js/reactGUI/ZoomButtons.js create mode 100644 library/js/literallycanvas/js/reactGUI/createSetStateOnEventMixin.js create mode 100644 library/js/literallycanvas/js/reactGUI/createToolButton.js create mode 100644 library/js/literallycanvas/js/reactGUI/init.js create mode 100644 library/js/literallycanvas/js/reactGUI/initDOM.js create mode 100644 library/js/literallycanvas/js/tools/Ellipse.js create mode 100644 library/js/literallycanvas/js/tools/Eraser.js create mode 100644 library/js/literallycanvas/js/tools/Eyedropper.js create mode 100644 library/js/literallycanvas/js/tools/Line.js create mode 100644 library/js/literallycanvas/js/tools/Pan.js create mode 100644 library/js/literallycanvas/js/tools/Pencil.js create mode 100644 library/js/literallycanvas/js/tools/Polygon.js create mode 100644 library/js/literallycanvas/js/tools/Rectangle.js create mode 100644 library/js/literallycanvas/js/tools/SelectShape.js create mode 100644 library/js/literallycanvas/js/tools/Text.js create mode 100644 library/js/literallycanvas/js/tools/base.js create mode 100644 library/js/react/README.md create mode 100644 library/js/react/README.openemr.txt create mode 100644 library/js/react/build/react-dom-server.js create mode 100644 library/js/react/build/react-dom-server.min.js create mode 100644 library/js/react/build/react-dom.js create mode 100644 library/js/react/build/react-dom.min.js create mode 100644 library/js/react/build/react-with-addons.js create mode 100644 library/js/react/build/react-with-addons.min.js create mode 100644 library/js/react/build/react.js create mode 100644 library/js/react/build/react.min.js diff --git a/library/js/literallycanvas/README.openemr.txt b/library/js/literallycanvas/README.openemr.txt new file mode 100644 index 00000000000..49f1047fe2f --- /dev/null +++ b/library/js/literallycanvas/README.openemr.txt @@ -0,0 +1,6 @@ +This is the Literally Canvas distribution 0.4.13 obtained from literallycanvas.com +and modified as follows: + + 1. Removed js/.gitignore + 2. Removed js/.npmignore + 3. Added this file diff --git a/library/js/literallycanvas/README.txt b/library/js/literallycanvas/README.txt new file mode 100644 index 00000000000..26d9ef75ae4 --- /dev/null +++ b/library/js/literallycanvas/README.txt @@ -0,0 +1,44 @@ +Literally Canvas v0.4.11 +======================== + +Complete documentation can be found at literallycanvas.com. + +Literally Canvas is an extensible, open source (BSD-licensed), HTML5 drawing +widget. Its only dependency is [React.js](http://facebook.github.io/react/). + +Get help on our mailing list: literallycanvas@librelist.com (just send it a +message to subscribe) + +If you want to modify the source +-------------------------------- + +Please visit github.com/literallycanvas/literallycanvas and work from the +master branch. This distribution does not include the build sources. + +Usage +----- + +1. Add the files under `css/` and `img/` to your project, as well as the +appropriate file from `js/`. + +2. Add some markup and some JavaScript: + +
+ + +
+ + +Developing +---------- + +Setup: `npm install` + +Watching and serving: `gulp dev` + +Browse to `localhost:8000/demo` and modify `demo/index.html` to test code +in progress. diff --git a/library/js/literallycanvas/bower.json b/library/js/literallycanvas/bower.json new file mode 100644 index 00000000000..6cd2e96452c --- /dev/null +++ b/library/js/literallycanvas/bower.json @@ -0,0 +1,29 @@ +{ + "name": "literallycanvas", + "version": "0.4.13", + "homepage": "http://literallycanvas.com", + "authors": [ + "irskep", + "campaul" + ], + "description": "A canvas in your browser. Literally.", + "main": "js/literallycanvas.min.js", + "keywords": [ + "canvas", + "edit", + "sketch", + "draw", + "literally" + ], + "license": "BSD", + "dependencies": { + "react": "0.14.3" + }, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/library/js/literallycanvas/css/literallycanvas.css b/library/js/literallycanvas/css/literallycanvas.css new file mode 100644 index 00000000000..059d504302e --- /dev/null +++ b/library/js/literallycanvas/css/literallycanvas.css @@ -0,0 +1 @@ +.literally .button-style-1{border:2px solid transparent;border-radius:3px}.literally .button-style-1{text-decoration:none;cursor:pointer}.literally .button-style-1.selected:not(.disabled){background-color:#a1d9fe}.literally .button-style-1:hover:not(.disabled){border-color:#a1d9fe}.literally .button-style-1.disabled{cursor:default;opacity:0.3}.literally.toolbar-at-top .lc-drawing{bottom:0;top:31px}.literally.toolbar-at-top .lc-options{top:0;border-bottom:1px solid #555}.literally.toolbar-at-bottom .lc-drawing{bottom:31px;top:0}.literally.toolbar-at-bottom .lc-options{bottom:0;border-top:1px solid #555}.literally.toolbar-hidden .lc-drawing{left:0;right:0;bottom:0;top:0}.literally.toolbar-hidden .lc-options,.literally.toolbar-hidden .lc-picker{display:none}.literally{position:relative;background-color:#ddd;min-height:400px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;-ms-touch-action:none;user-select:none}.literally,.literally *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.literally>*{position:absolute}.literally .lc-picker{top:0;left:0;bottom:0;width:61px;background-color:#e6e6e6}.literally .lc-drawing{right:0;left:0;bottom:0;left:0}.literally .lc-drawing>*{position:absolute;top:0;right:0;bottom:0;left:0}.literally .lc-drawing.with-gui{right:0;left:61px;cursor:default}.literally .lc-drawing.with-gui .polygon-toolbar{top:auto;height:31px}.literally .lc-drawing.with-gui .polygon-toolbar .polygon-toolbar-button{float:left}.literally .lc-drawing.with-gui .text-tool-input:focus{outline:none}.literally .lc-picker{z-index:1001;border-right:1px solid #555}.literally .lc-picker .toolbar-button{width:26px;height:26px;line-height:26px;margin:2px;padding:0;cursor:pointer;text-align:center;border:2px solid transparent;border-radius:3px}.literally .lc-picker .toolbar-button{text-decoration:none;cursor:pointer}.literally .lc-picker .toolbar-button.selected:not(.disabled){background-color:#a1d9fe}.literally .lc-picker .toolbar-button:hover:not(.disabled){border-color:#a1d9fe}.literally .lc-picker .toolbar-button.disabled{cursor:default;opacity:0.3}.literally .lc-picker .thin-button{cursor:pointer;float:left;position:relative}.literally .lc-picker .fat-button{clear:both;width:56px}.literally .lc-picker .lc-pick-tool,.literally .lc-picker .lc-undo,.literally .lc-picker .lc-redo,.literally .lc-picker .lc-zoom-in,.literally .lc-picker .lc-zoom-out{background-size:100% auto;background-repeat:no-repeat;background-position:center center}.literally .color-well{font-size:10px;float:left;width:60px}.literally .color-well.open{background-color:#a1d9fe}.literally .color-well-color-container{border:2px solid transparent;border-radius:3px;border:1px solid #aaa;position:relative;width:28px;height:28px;margin:1px auto;overflow:visible}.literally .color-well-color-container{text-decoration:none;cursor:pointer}.literally .color-well-color-container.selected:not(.disabled){background-color:#a1d9fe}.literally .color-well-color-container:hover:not(.disabled){border-color:#a1d9fe}.literally .color-well-color-container.disabled{cursor:default;opacity:0.3}.literally .color-well-color-container .color-well-checker{position:absolute;width:50%;height:50%;background-color:black}.literally .color-well-color-container .color-well-checker-top-left{border-top-left-radius:3px}.literally .color-well-color-container .color-well-checker-bottom-right{border-bottom-right-radius:3px}.literally .color-well-color-container .color-well-color{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:3px}.literally .color-picker-popup{position:absolute;z-index:1;background-color:white;border:1px solid #555;left:60px;bottom:31px}.literally .color-picker-popup .color-row{clear:both}.literally .color-picker-popup .color-row .color-cell{cursor:pointer;width:20px;height:20px;line-height:20px;float:left}.literally .color-picker-popup .color-row .color-cell:hover,.literally .color-picker-popup .color-row .color-cell.selected{border:1px solid #555;line-height:18px}.literally .color-picker-popup .color-row .color-cell.transparent-cell{width:100%}.literally .horz-toolbar{height:31px;background-color:#e6e6e6}.literally .horz-toolbar .label{line-height:30px;margin:0 0.25em 0 0.25em;font-size:12px}.literally .horz-toolbar span{line-height:30px;margin:0 0.25em 0 0.25em;font-size:12px;float:left}.literally .horz-toolbar .square-toolbar-button{border:2px solid transparent;border-radius:3px;margin:1px;border:1px solid #aaa;width:28px;height:28px;float:left;position:relative}.literally .horz-toolbar .square-toolbar-button{text-decoration:none;cursor:pointer}.literally .horz-toolbar .square-toolbar-button.selected:not(.disabled){background-color:#a1d9fe}.literally .horz-toolbar .square-toolbar-button:hover:not(.disabled){border-color:#a1d9fe}.literally .horz-toolbar .square-toolbar-button.disabled{cursor:default;opacity:0.3}.literally .horz-toolbar .square-toolbar-button img{max-width:100%;max-height:100%}.literally .horz-toolbar .square-toolbar-button label{position:absolute;top:0;right:0;bottom:0;left:0;line-height:26px;margin:auto;float:none;text-align:center}.literally .polygon-toolbar{position:absolute;border-top:1px solid #555;border-bottom:1px solid #555;width:100%}.literally.toolbar-at-bottom .polygon-toolbar{top:-100%}.literally.toolbar-at-top .polygon-toolbar{top:100%}.literally .lc-options{z-index:1;right:0;left:61px}.literally .lc-options .lc-font-settings{height:30px;line-height:31px;padding-left:4px;background-color:#f5f5f5}.literally .lc-options .lc-font-settings input{margin:0 0.5em 0 0}.literally .lc-options .lc-font-settings input[type=checkbox]{margin:0 0.5em 0 0.5em} diff --git a/library/js/literallycanvas/img/alpha.png b/library/js/literallycanvas/img/alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..67e2ad27f243752b926534d310384aa59d964c2e GIT binary patch literal 7224 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 W%=Z%qV~jsP$0*6E%a%!-z5G9nX9aoy literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/checkerboard-8x8.png b/library/js/literallycanvas/img/checkerboard-8x8.png new file mode 100644 index 0000000000000000000000000000000000000000..a2baa7ffa0e4bb7a952c881fff7144a21fb41956 GIT binary patch literal 1087 zcmZ{jF>ljA6vwZC5Ev>z3`G?J%az#dvz>-CC&z-uw2eec6oQltpt#8eEMlK!Ulmtk zKnNrlU|>WrurYOF1EdZen2-&60T0-+`Z96-0EZ#h=M#O}metpBNcx+6 z`&*tvO?ILSLvS69?NpRD* zJDAriMpCA%Iu6sC7AECLKm+oBIrVQ38z;81&M^gcqoXb~g>T>g{A7)(R;;Uyr8Avw zyS;a6cMmL>l}is^?tXqgzq6zMvL6;+y#4yL@aE*lxs}^jo;*GRv^$3`y#FA5;$2<2 Lwr*`Nw;%lj!iG#9 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/dashed-line.png b/library/js/literallycanvas/img/dashed-line.png new file mode 100644 index 0000000000000000000000000000000000000000..c6c390c08f646d1c354c21b56da43fbb72f3d9da GIT binary patch literal 4328 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 Hwh8$UjNGc+ literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/ellipse.png b/library/js/literallycanvas/img/ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..671cb2921898878f63bdc341de6fc9927e374997 GIT binary patch literal 4933 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 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/eyedropper.png b/library/js/literallycanvas/img/eyedropper.png new file mode 100644 index 0000000000000000000000000000000000000000..51c4352d06e6e09902e7a4b2aaa78b99ab280aa7 GIT binary patch literal 468 zcmV;_0W1EAP)E^F0Ei2Kcs~%Y2jT=; zS!4jj0az?Q55)h`@O)ZW{vK+00s+haqp72+%lEHZz1l!qTL-5iF)=ZQUq62`96NUG1CYysCJhps2*fX_?sFKPFmVzrsL`|N zd#D%#JuF8rCkDiFWJe5`<+Mxf!@_c0wP69FtOf!rSFU6z$j?gzG8a(W0Sxr89G3$O z^z`)e>0vq6xHmO3JAd=mExIN+I1m*TU4QEI8M<1|f}HTWy1N5pWo1zmT)ldQVaN6z z3?DyzWSBi`7EOX39Q1Z}cJI-BJb%H0|Kj4}^BL#>0zj4_TV7I93JUH9T3ZZ@0s%fg zelP=Ag)&T?GUdU(eS1N{eSmKLH&9SpSy}CeCNcqrQ9vgE5MThx4KHD1pYaX=0000< KMNUMnLSTY>47`B= literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/hue.png b/library/js/literallycanvas/img/hue.png new file mode 100644 index 0000000000000000000000000000000000000000..4bfa5b237aff87f178f25f7cd7217712ea30a316 GIT binary patch literal 4201 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 G`u`Jt&^tc> literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/line-with-arrow.png b/library/js/literallycanvas/img/line-with-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..981091e7bd9d6b1ed2d0a9529c7a95e7848d4ffc GIT binary patch literal 4312 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 aYz)5FH+?iaRaOGDjKR~@&t;ucLK6V6fJ4*( literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/pan.png b/library/js/literallycanvas/img/pan.png new file mode 100644 index 0000000000000000000000000000000000000000..c091081f8ff3e6f9f60f27ab46b3f7ff8eaf1f76 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@j7pv^jv*Ddu7n@tZ8qTX$z(sVeShBp4x8U8EqxB=C)i4u z-4a;9sO5@>qt{}UBZ`F~-pAP+`RBjo?wQ-oXRy&Jka5*N-EIla&YlTIle}F! zf>p$)J+VG^=cKg%C)rrPyVn_*f=o3!-|4Y@Kdd^b$LH%ltp#r)t#?~Rm;^J~rXOJb zeZf0>$1%l5UcH^$%C~NtZSH-t+SOq_OPWt?P@eT8=8E55cFI<^VquJr#0Eo{6@%(|b{67@W zA4tpT>Ihtx)5Q^lET^d>h_#$1jv&=?syc#P%c?P!a!PXFlzaz z<)fD40`mvTas?`e0NFmDPX$MiWjP4!M=PVraRk|xGe9-}r@#>uSlpi<;HsXMd|v6mX?o9TAa1k)hNzWqeoAIqrAuN-s-2O6p{cHcg|4wdh@rWafrXW& znT;f_?Qgd=aTm@r2V?85?USt(WnnC`s@-NCv1qLuE z80`#g^fAQH)jQ|s78Iox7lYKBLe(RSp{ox{EzZv=1sNZjmsw&5bP?DJG+}gIkqCJ^ zbC@1vL39lf*fbyuB543cgcUfXB3v?aQ}e)nF$UU#RRUe3bAC>KQE)+Gaw;giz*>-m z&{c!2iNs|Mk_1$vjXo$XBc*Lf#sP~0bB-MsFh*gy(2i@*$!b9c29|T4E{-7)oO{D# zGh$pt?26yteUmnO+qR&M67pUAqN_D@xkN)&ut>F}a9`WHZR@QL-G$$Lm)bks>Jo?# zSrIB9;*uoFy1GMmMgLbQh{q>` znmY<58}yw^bONu>PrJlq-LX^pQUk}icr}(Od#Vh#c(Q!i#K_LM^~o}~j|=3CgrDDZ ze4}EK>@)MF#1w@+MeRq#TtjC& zIX%7hZMEv&T|fTR`!XqPe9>UHyJG&ntDKW0N*L~ItZOV0x#<2Pzx9gi@s(D`&U`p? zx4uI|tAo?iG5Zx`ExS^5&!txe7H!8BIC5|4RH7Qd}oA{d4C+b{E&ncL9kx##!IvZ{(n<|l8rb$h=odAJ~Mt3W}Y z$kIcaQoV@>TDH$WxU+Sa-}^Zagq40hFMqgTk?MVUYu_DVC|ut%R#sEbmpB? zSZ0;{)exhaFW4 zY{>yEMw3(?GOusj`Rm82-Ls>g9Z2DC%PHV;ioIbfxPD6b9M?naah#v4K3tq^^Zn7H zzq|CMH`RvSWw2*I9#`1+?v7_H|6bk07L1nc7UD}xLj>}z=Fi%4)4>1fS@jpIqtBc( zPq6!wFD|=Ku$8HJcF4iN6}%SLtKaQ&?o(I4ckYtJ)u~HVy*m8&8e1G^@Rrg%cX8#s z+NxGz6SGZj7x``rtb3)r=Vwmn9dV&OpHgOX7oD7{9{X#Rz3hL$y8XSvpMPn!di%pyiVSxdp3ONv$1|JHf1Y)1%d>rzVz%k`LN($N zcW*ILy8h@z&w(bd6Wg=yO@Dh;VS1$O$KQ$d&hFpen7$X)E)!kA%#>rlSLNFs(D%Q}EJSr7T(fN712Yl7a=5+*O_m!B4cdht+W^yk=c- z*;vg`{=+$yTla+(KC(01=Dg}OUBze8%pWseq%Apn>&exvzIT zn4j-ASb9`-8)uQ@#WVf0-nmYXFZ0{{Sekj8^;g5hbtZc{J~bzcsO7oTJ~dw@^M0|r z-v3v37Oh?I=hq#s4QGDeVPt3g{W>(f;GgtTBcZDY-2*Cq^@MeY&uZz;57bVN`k7px zD{ZsWzKu|588Y%@tD#D&X{EeoaL`O+m61duJW*8`EmZG zNQ%&=gW?AkTk{CbnepSllYZ43P0^&!_69$NW#W%(F3(>3L%#E(%|3-Dn=(+F!_(Ez JWt~$(69C&Dk`Mp@ literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/polygon-closed.png b/library/js/literallycanvas/img/polygon-closed.png new file mode 100644 index 0000000000000000000000000000000000000000..ae0ca4475c082a642989ce4f67e959a02e679322 GIT binary patch literal 1954 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 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/polygon.png b/library/js/literallycanvas/img/polygon.png new file mode 100644 index 0000000000000000000000000000000000000000..04a312863317c640036a727aea13e1f36ae7680a GIT binary patch literal 1786 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}oCO|{#S9GG z!XV7ZFl&wk0|WDl%#etZ2wxwolpi<;HsXMd|v6mX?o9TAa1k)hNzWqeoAIqrAuN-s-2O6p{cHcxvsHch@qL4fw`5r zg^fO%8iWtQx}A$s6HD@oLh|!->;f_?Qgd=aTm@r2V?85?USt(WnnC`s@-NCv1qLuE z80`#g^fAQH)jQ|s78Iox7lYKBLe(RSp{ox{EzZv=1sNZjmsw&5bP?DJG+}gIkqCJ^ zbC@1vL39lf*fbyuB543cgcUfXB3v?aQ}e)nF$UU#RRUe3bAC>KQE)+Gaw;giz*>-m z&{c!2iNs|Mk_1$vjXo$XBc*Lf#sP~0bB-MsFh*gy(2ncp6x|sN3{0;*T^vIqINwh5 zUf~-kaoj(q-{6B(#nSF6K^;MPGYvkRawvD=WNzj0NhxA~t|eK~bHu?*NmDJ)D1c|m zLEZ3);fEAI?UCF0>BQ&n=OcIL*Qc*9{{Ae6`RDcjYw~OF|Nni>s(S6-YkE`vDgPIa zX!#7|3ne(&L79i*zd2%auZ*x zyJPvQ@Xc&>4Q6`3CAXNGepHKS7PFbZK=(t}zmUZ-uOHn?sCx2yuKkrAE%h=r?;Z)i zSia!;TUDOUEc?ShFC+=b{*QVke``;|`@`$c>cli2Twk_s4&yKO?F&Uu#L2R(yE}2= z)}2vo^Q(_NU9-WofA@l}scR41eEhP$vFt*^{iF7mUtYE4Xm)#>X2~3veB;4JffbkM z6zn3Ku9M|hiPrg5Vq)S?B0kAA;-+uV%2i-G=gr8qI=CgtCv|Z!z zFTd3Fxek%hvOz)Ly%G>@wRGw;YaT!AJQ7Hfz85 za_XjP)(Mu7CBnzpt}WliCn;-I+x9i&oA8CgRmrAz7S)>V;CgLl!*&1Q=K{k&-#-X1 XFo>C8$!b{%s*pTg{an^LB{Ts5!G5l@ literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/rectangle.png b/library/js/literallycanvas/img/rectangle.png new file mode 100644 index 0000000000000000000000000000000000000000..13da1d1eb8466b37017cf60172c0372f66a3add6 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&kwITY{Z~_1nsT=|CYTPZ!6Kh{JEM8S(**WHB)P_y6>c z9lK}5^z3b&$R?4YJ7-_^(qH{wSQwr?G|OAQ2B-xB9?V?7W6c9;2ODlDMrQk5aerTs NxTmY1%Q~loCIFkbG{67= literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/redo.png b/library/js/literallycanvas/img/redo.png new file mode 100644 index 0000000000000000000000000000000000000000..960882c47d00d91c62e8d7be82db89c48cda66ec GIT binary patch literal 5091 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 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/screenshot.png b/library/js/literallycanvas/img/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f48ba3024fbfd3e3248b49b7f41cb7519ccc35fd GIT binary patch literal 218926 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 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/text.png b/library/js/literallycanvas/img/text.png new file mode 100644 index 0000000000000000000000000000000000000000..fde4a53eaabf050e437d68b68be0781dbc2c9246 GIT binary patch literal 4315 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 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/zoom-in.png b/library/js/literallycanvas/img/zoom-in.png new file mode 100644 index 0000000000000000000000000000000000000000..465c77614aa6567eff282a0c737c6c48fb28ddfe GIT binary patch literal 1991 zcmbVNeNtpyb#t?CS0|whIijFvj5^ ztVBeeqK2)UWKtMMuMgG>aeVYi9*w8u`gRqYRx)~1hTLk+#m#pKK&d7 zaIFwr!Bs#ClLXV@@kM4VwJ2GoDO#ryXu+4`fLJR^86YrH4Oj`i!Gc?IjQqiDG%{WyQwO(q}V~Do zwWw6i5r||wd9)OPczhV<^Cdiqm=_I8V|a2tjEvcM7FHI`6N^L=1d+=j7?vS?2}H4n zM9X8~7#J3D#;^$n3#m3}ura?l<#!Yd|0foem@zeJG^>n8{a6Pmbw<)?(HTvEB$dm8 z0fkzF8@v*4fu7_m#msmvrM~g*B%xLCv9wO%R#bT)xmUHBC za1^WkKdiB-VA$UF_*c7(iKrg*Zl5+kb$B{Hn1PxZGc_Ek;{Act%-udxm@l4vy}0wUyAMW+{~EdppXp!!&BI5QPQl&Yzg$2_L}+%vr1n72 z<`BJm{qC#fJkJ!5&@;i~=V9(nT{iO|m|h;|X{Wyy>@2E?`fy%l^X6;ll0TzJ{MQdQ z&zu|f^IKxaJ?O3YE(d$-ioxzpYdj~eRSl-~|LL4FKhA!I-*RbMmfO}bqfXx;3Zq*O||SN!hn^?0wF%O>er)dTwInZQoaBNA;&EBQrh@vAm%kYN^>`yS6q%H_ZLz z{86PFTfjSpmnAXLiLAcb!`o!1kTplnC)%50E`^SpX>Uq9=Vu-Vy9x(h%<4RGwD+a% zSqw|a_}_QsWES<-obTSg1E?b$R~4%_s9LZ5;6tn!zp?Qu8>(>(UOM*Kq&R1*VFwody;mXKI}{1<0MaQS=1FhZne;V_-?-d20E$-{7q-C1+;IQm&w1FA0qRQ zvW84t7&7Bto087Bp<5q(%QrXt<_|OQ5AfiglRRQvK|rG|d`fI8!&Y*6fhT)Wm0xwu zgq5MhX z5l4DfP^$dI+KO3Ox{CZ(PxbN(MD7tB1)6}~qs`0De&X9=+cK$qDZgQejNM-9Y}{2z z-+JP^#L}%F(uPdra}!xj}-Jy+)1E_jonUDUt_GvKvoT@HF3gy1{^YrUyzhkrjq7H}YMlf%9 zu>7L9V&W~&p{S~J-^Y!>&h7|N+qx^uBc?7^EwjA%=%K!W|Gj+f?$86B1DRj+cMjzH zlHqh-xT5DY!M|E<8E(#t-`HGrGk^{rW#~mE?PaAw@eW6|$&VhsioRD|A`23TrXVxw w%WZ*-i~)S;owWgX>W`z$*T=i!+#}3ZTG^s+GhBys8t<<)L6$6S5U(lu8)!!pvH$=8 literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/img/zoom-out.png b/library/js/literallycanvas/img/zoom-out.png new file mode 100644 index 0000000000000000000000000000000000000000..7ccd4cc877544484693e42e4c7a3e2d492c63c0d GIT binary patch literal 1934 zcmbVNdsI_(9G^((5Feo!lH&D_8K~QRZ0wa2w_WB&Op#3;sYk|kVS{aV++ElJEgvKc zi9nVQ6kibdC>Jnm>Hciluk#xQ?UN<^hfucdw;+0@Avt9-`{gT zh+nv1Y(QuLgTWZ9R$&SBI^Xw>ewF?nv}AloFH@)(J*6d5D3^i688Q=*j00+$Ar()+ z4W{gj%lKRdW2D)l(^Gm)oWw}jxCS4F>$W*)HiI!Y+U+nH({Tz&##1eJDcFDNEC^Uk zQgB(62G%$fxY?r0A#rWaLY*-u-6%GJ(er@0ZV9cxhEoQ>ZL`{)61Nn5rdLAmea8?8 zJcCf_Qt-J`dQCi_AV?gD;=&vwEI)5?UcdIu{&AA8Zg{x zBrOigLf8SHMnf`@Nl8K4)8`@B92(6F#dhaVqUe-CZi53txG-e1`Qmzpc2WuWKW@Af z?bKyEa3}$H5}Bltu15-Mm`vyHzYY0-v^SDPq=hbu!HN;aOdD>e)R+{cZ@4ClNrEZ) zVp)tp$-_`sAVLt4NFh+j1v~^33X~!Q9oF$uE>9>B!D2D0RKf@ngNhWiAVzsgAtFQ& z8Go3owmT_<-G~p{wfO8l=ZgN5D^ZZRfg(s9L0E@7Al^(+gwsqo0EIS+ivSvf(PH$^Q63OKlhA8<;B{;-2{hzEs zv@?*eJ^s}$!$))v`nE5cpB7$>4{oPthNOpM$IK&n^vpG?F`3SN>(263rX7nXMJJBl zTL>#7D!kWcvAqcceEDeO_}r=40okD}FWl7iWkl|+!XUI_QErG)d1;%n`dDbWE+u$g zY`Rs@UEdv!=-2Opl|JL>9N{?PXX@b)em^`ASs{g$i z4W8+qN1pK>p{EYsyKm}jmc*lI?k^TqB3Be9F-P3IviV%oy<_m6S|?Ysi``oUI#y3w zP&xa4!S87~1Ie@?{i3|@>=R(br3JNHnyn`byU25c6C;-YmLZNVz3#m`=Y#E{ozwLp z?(rETYehjfzj*j{W=>V=Ymp#p#`LBdMs4inj}ElmAT~_EHbMD?-QPer}xHaI7_7-jaoyzuaiWR}}nwB2hsI(Hnh4z$fHPxHWu48>-DY6_|tp60& ze9b<#KeXPpC# z-R!F~dbZtQsb;S{5rF%w{7jUKz1)S&328o3moVFAPA^)PDH! zIced+3qc$DB>Im;yrgBnw-sFQ@3Z!XXS_#{kKYO8WGLR}ZaJkNce`X({yLOvLMqMTZ?}=~*58_)_og`F$r;V`lcR&x>HDh1x>0>}7x}riz(W7ayZKsY<`{@aD}~ z6>-u-^|u)HxtGB3t`()-6`xcdZsP1j2mID_?n|xci!3O1u$$u?OfYE_O=~(a2PW=9QR9fEyEjcDKsJXN*cwO=2 z_&1kz{_F(|+N%e3*x;$yw8Q709=XaHx8^C{7brU|cogvDw4g41kD}z)vL;Gj&z#83 zZkV+wv=amTOB?wp{Gu_KWlNl nCuhm3^2yN~_jW#fIvQs1*qg_cpQ<+d{*daJh1g+v()zyvbGP#F literal 0 HcmV?d00001 diff --git a/library/js/literallycanvas/js/core/LiterallyCanvas.js b/library/js/literallycanvas/js/core/LiterallyCanvas.js new file mode 100644 index 00000000000..7e046999627 --- /dev/null +++ b/library/js/literallycanvas/js/core/LiterallyCanvas.js @@ -0,0 +1,844 @@ +var INFINITE, JSONToShape, LiterallyCanvas, Pencil, actions, bindEvents, createShape, math, ref, renderShapeToContext, renderShapeToSVG, renderSnapshotToImage, renderSnapshotToSVG, shapeToJSON, util, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + slice = [].slice, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +actions = require('./actions'); + +bindEvents = require('./bindEvents'); + +math = require('./math'); + +ref = require('./shapes'), createShape = ref.createShape, shapeToJSON = ref.shapeToJSON, JSONToShape = ref.JSONToShape; + +renderShapeToContext = require('./canvasRenderer').renderShapeToContext; + +renderShapeToSVG = require('./svgRenderer').renderShapeToSVG; + +renderSnapshotToImage = require('./renderSnapshotToImage'); + +renderSnapshotToSVG = require('./renderSnapshotToSVG'); + +Pencil = require('../tools/Pencil'); + +util = require('./util'); + +INFINITE = 'infinite'; + +module.exports = LiterallyCanvas = (function() { + function LiterallyCanvas(arg1, arg2) { + this.setImageSize = bind(this.setImageSize, this); + var containerEl, opts; + opts = null; + containerEl = null; + if (arg1 instanceof HTMLElement) { + containerEl = arg1; + opts = arg2; + } else { + opts = arg1; + } + this.opts = opts || {}; + this.config = { + zoomMin: opts.zoomMin || 0.2, + zoomMax: opts.zoomMax || 4.0, + zoomStep: opts.zoomStep || 0.2 + }; + this.colors = { + primary: opts.primaryColor || '#000', + secondary: opts.secondaryColor || '#fff', + background: opts.backgroundColor || 'transparent' + }; + this.watermarkImage = opts.watermarkImage; + this.watermarkScale = opts.watermarkScale || 1; + this.backgroundCanvas = document.createElement('canvas'); + this.backgroundCtx = this.backgroundCanvas.getContext('2d'); + this.canvas = document.createElement('canvas'); + this.canvas.style['background-color'] = 'transparent'; + this.buffer = document.createElement('canvas'); + this.buffer.style['background-color'] = 'transparent'; + this.ctx = this.canvas.getContext('2d'); + this.bufferCtx = this.buffer.getContext('2d'); + this.backingScale = util.getBackingScale(this.ctx); + this.backgroundShapes = opts.backgroundShapes || []; + this._shapesInProgress = []; + this.shapes = []; + this.undoStack = []; + this.redoStack = []; + this.isDragging = false; + this.position = { + x: 0, + y: 0 + }; + this.scale = 1.0; + this.setTool(new this.opts.tools[0](this)); + this.width = opts.imageSize.width || INFINITE; + this.height = opts.imageSize.height || INFINITE; + this.setZoom(this.scale); + if (opts.snapshot) { + this.loadSnapshot(opts.snapshot); + } + this.isBound = false; + if (containerEl) { + this.bindToElement(containerEl); + } + } + + LiterallyCanvas.prototype.bindToElement = function(containerEl) { + var ref1, repaintAll; + if (this.containerEl) { + console.warn("Trying to bind Literally Canvas to a DOM element more than once is unsupported."); + return; + } + this.containerEl = containerEl; + this._unsubscribeEvents = bindEvents(this, this.containerEl, this.opts.keyboardShortcuts); + this.containerEl.style['background-color'] = this.colors.background; + this.containerEl.appendChild(this.backgroundCanvas); + this.containerEl.appendChild(this.canvas); + this.isBound = true; + repaintAll = (function(_this) { + return function() { + _this.keepPanInImageBounds(); + return _this.repaintAllLayers(); + }; + })(this); + util.matchElementSize(this.containerEl, [this.backgroundCanvas, this.canvas], this.backingScale, repaintAll); + if (this.watermarkImage) { + this.watermarkImage.onload = (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this); + } + if ((ref1 = this.tool) != null) { + ref1.didBecomeActive(this); + } + return repaintAll(); + }; + + LiterallyCanvas.prototype._teardown = function() { + this.tool.willBecomeInactive(this); + if (typeof this._unsubscribeEvents === "function") { + this._unsubscribeEvents(); + } + this.tool = null; + this.containerEl = null; + return this.isBound = false; + }; + + LiterallyCanvas.prototype.trigger = function(name, data) { + this.canvas.dispatchEvent(new CustomEvent(name, { + detail: data + })); + return null; + }; + + LiterallyCanvas.prototype.on = function(name, fn) { + var wrapper; + wrapper = function(e) { + return fn(e.detail); + }; + this.canvas.addEventListener(name, wrapper); + return (function(_this) { + return function() { + return _this.canvas.removeEventListener(name, wrapper); + }; + })(this); + }; + + LiterallyCanvas.prototype.getRenderScale = function() { + return this.scale * this.backingScale; + }; + + LiterallyCanvas.prototype.clientCoordsToDrawingCoords = function(x, y) { + return { + x: (x * this.backingScale - this.position.x) / this.getRenderScale(), + y: (y * this.backingScale - this.position.y) / this.getRenderScale() + }; + }; + + LiterallyCanvas.prototype.drawingCoordsToClientCoords = function(x, y) { + return { + x: x * this.getRenderScale() + this.position.x, + y: y * this.getRenderScale() + this.position.y + }; + }; + + LiterallyCanvas.prototype.setImageSize = function(width, height) { + this.width = width || INFINITE; + this.height = height || INFINITE; + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('imageSizeChange', { + width: this.width, + height: this.height + }); + }; + + LiterallyCanvas.prototype.setTool = function(tool) { + var ref1; + if (this.isBound) { + if ((ref1 = this.tool) != null) { + ref1.willBecomeInactive(this); + } + } + this.tool = tool; + this.trigger('toolChange', { + tool: tool + }); + if (this.isBound) { + return this.tool.didBecomeActive(this); + } + }; + + LiterallyCanvas.prototype.setShapesInProgress = function(newVal) { + return this._shapesInProgress = newVal; + }; + + LiterallyCanvas.prototype.pointerDown = function(x, y) { + var p; + p = this.clientCoordsToDrawingCoords(x, y); + if (this.tool.usesSimpleAPI) { + this.tool.begin(p.x, p.y, this); + this.isDragging = true; + return this.trigger("drawStart", { + tool: this.tool + }); + } else { + this.isDragging = true; + return this.trigger("lc-pointerdown", { + tool: this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + }; + + LiterallyCanvas.prototype.pointerMove = function(x, y) { + return util.requestAnimationFrame((function(_this) { + return function() { + var p, ref1; + p = _this.clientCoordsToDrawingCoords(x, y); + if ((ref1 = _this.tool) != null ? ref1.usesSimpleAPI : void 0) { + if (_this.isDragging) { + _this.tool["continue"](p.x, p.y, _this); + return _this.trigger("drawContinue", { + tool: _this.tool + }); + } + } else { + if (_this.isDragging) { + return _this.trigger("lc-pointerdrag", { + tool: _this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } else { + return _this.trigger("lc-pointermove", { + tool: _this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + } + }; + })(this)); + }; + + LiterallyCanvas.prototype.pointerUp = function(x, y) { + var p; + p = this.clientCoordsToDrawingCoords(x, y); + if (this.tool.usesSimpleAPI) { + if (this.isDragging) { + this.tool.end(p.x, p.y, this); + this.isDragging = false; + return this.trigger("drawEnd", { + tool: this.tool + }); + } + } else { + this.isDragging = false; + return this.trigger("lc-pointerup", { + tool: this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + }; + + LiterallyCanvas.prototype.setColor = function(name, color) { + this.colors[name] = color; + if (!this.isBound) { + return; + } + switch (name) { + case 'background': + this.containerEl.style.backgroundColor = this.colors.background; + this.repaintLayer('background'); + break; + case 'primary': + this.repaintLayer('main'); + break; + case 'secondary': + this.repaintLayer('main'); + } + this.trigger(name + "ColorChange", this.colors[name]); + if (name === 'background') { + return this.trigger("drawingChange"); + } + }; + + LiterallyCanvas.prototype.getColor = function(name) { + return this.colors[name]; + }; + + LiterallyCanvas.prototype.saveShape = function(shape, triggerShapeSaveEvent, previousShapeId) { + if (triggerShapeSaveEvent == null) { + triggerShapeSaveEvent = true; + } + if (previousShapeId == null) { + previousShapeId = null; + } + if (!previousShapeId) { + previousShapeId = this.shapes.length ? this.shapes[this.shapes.length - 1].id : null; + } + this.execute(new actions.AddShapeAction(this, shape, previousShapeId)); + if (triggerShapeSaveEvent) { + this.trigger('shapeSave', { + shape: shape, + previousShapeId: previousShapeId + }); + } + return this.trigger('drawingChange'); + }; + + LiterallyCanvas.prototype.pan = function(x, y) { + return this.setPan(this.position.x - x, this.position.y - y); + }; + + LiterallyCanvas.prototype.keepPanInImageBounds = function() { + var ref1, renderScale, x, y; + renderScale = this.getRenderScale(); + ref1 = this.position, x = ref1.x, y = ref1.y; + if (this.width !== INFINITE) { + if (this.canvas.width > this.width * renderScale) { + x = (this.canvas.width - this.width * renderScale) / 2; + } else { + x = Math.max(Math.min(0, x), this.canvas.width - this.width * renderScale); + } + } + if (this.height !== INFINITE) { + if (this.canvas.height > this.height * renderScale) { + y = (this.canvas.height - this.height * renderScale) / 2; + } else { + y = Math.max(Math.min(0, y), this.canvas.height - this.height * renderScale); + } + } + return this.position = { + x: x, + y: y + }; + }; + + LiterallyCanvas.prototype.setPan = function(x, y) { + this.position = { + x: x, + y: y + }; + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('pan', { + x: this.position.x, + y: this.position.y + }); + }; + + LiterallyCanvas.prototype.zoom = function(factor) { + var newScale; + newScale = this.scale + factor; + newScale = Math.max(newScale, this.config.zoomMin); + newScale = Math.min(newScale, this.config.zoomMax); + newScale = Math.round(newScale * 100) / 100; + return this.setZoom(newScale); + }; + + LiterallyCanvas.prototype.setZoom = function(scale) { + var oldScale; + oldScale = this.scale; + this.scale = scale; + this.position.x = math.scalePositionScalar(this.position.x, this.canvas.width, oldScale, this.scale); + this.position.y = math.scalePositionScalar(this.position.y, this.canvas.height, oldScale, this.scale); + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('zoom', { + oldScale: oldScale, + newScale: this.scale + }); + }; + + LiterallyCanvas.prototype.setWatermarkImage = function(newImage) { + this.watermarkImage = newImage; + util.addImageOnload(newImage, (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this)); + if (newImage.width) { + return this.repaintLayer('background'); + } + }; + + LiterallyCanvas.prototype.repaintAllLayers = function() { + var i, key, len, ref1; + ref1 = ['background', 'main']; + for (i = 0, len = ref1.length; i < len; i++) { + key = ref1[i]; + this.repaintLayer(key); + } + return null; + }; + + LiterallyCanvas.prototype.repaintLayer = function(repaintLayerKey, dirty) { + var retryCallback; + if (dirty == null) { + dirty = repaintLayerKey === 'main'; + } + if (!this.isBound) { + return; + } + switch (repaintLayerKey) { + case 'background': + this.backgroundCtx.clearRect(0, 0, this.backgroundCanvas.width, this.backgroundCanvas.height); + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this); + if (this.watermarkImage) { + this._renderWatermark(this.backgroundCtx, true, retryCallback); + } + this.draw(this.backgroundShapes, this.backgroundCtx, retryCallback); + break; + case 'main': + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('main', true); + }; + })(this); + if (dirty) { + this.buffer.width = this.canvas.width; + this.buffer.height = this.canvas.height; + this.bufferCtx.clearRect(0, 0, this.buffer.width, this.buffer.height); + this.draw(this.shapes, this.bufferCtx, retryCallback); + } + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + if (this.canvas.width > 0 && this.canvas.height > 0) { + this.ctx.fillStyle = '#ccc'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.clipped(((function(_this) { + return function() { + _this.ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height); + return _this.ctx.drawImage(_this.buffer, 0, 0); + }; + })(this)), this.ctx); + this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + var i, len, ref1, results, shape; + ref1 = _this._shapesInProgress; + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + shape = ref1[i]; + results.push(renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + })); + } + return results; + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + } + } + return this.trigger('repaint', { + layerKey: repaintLayerKey + }); + }; + + LiterallyCanvas.prototype._renderWatermark = function(ctx, worryAboutRetina, retryCallback) { + if (worryAboutRetina == null) { + worryAboutRetina = true; + } + if (!this.watermarkImage.width) { + this.watermarkImage.onload = retryCallback; + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(this.watermarkScale, this.watermarkScale); + if (worryAboutRetina) { + ctx.scale(this.backingScale, this.backingScale); + } + ctx.drawImage(this.watermarkImage, -this.watermarkImage.width / 2, -this.watermarkImage.height / 2); + return ctx.restore(); + }; + + LiterallyCanvas.prototype.drawShapeInProgress = function(shape) { + this.repaintLayer('main', false); + return this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + return renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + }); + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + }; + + LiterallyCanvas.prototype.draw = function(shapes, ctx, retryCallback) { + var drawShapes; + if (!shapes.length) { + return; + } + drawShapes = (function(_this) { + return function() { + var i, len, results, shape; + results = []; + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + results.push(renderShapeToContext(ctx, shape, { + retryCallback: retryCallback + })); + } + return results; + }; + })(this); + return this.clipped(((function(_this) { + return function() { + return _this.transformed(drawShapes, ctx); + }; + })(this)), ctx); + }; + + LiterallyCanvas.prototype.clipped = function() { + var contexts, ctx, fn, height, i, j, len, len1, results, width, x, y; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + x = this.width === INFINITE ? 0 : this.position.x; + y = this.height === INFINITE ? 0 : this.position.y; + width = (function() { + switch (this.width) { + case INFINITE: + return this.canvas.width; + default: + return this.width * this.getRenderScale(); + } + }).call(this); + height = (function() { + switch (this.height) { + case INFINITE: + return this.canvas.height; + default: + return this.height * this.getRenderScale(); + } + }).call(this); + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.clip(); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.transformed = function() { + var contexts, ctx, fn, i, j, len, len1, results, scale; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.translate(Math.floor(this.position.x), Math.floor(this.position.y)); + scale = this.getRenderScale(); + ctx.scale(scale, scale); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.clear = function(triggerClearEvent) { + var newShapes, oldShapes; + if (triggerClearEvent == null) { + triggerClearEvent = true; + } + oldShapes = this.shapes; + newShapes = []; + this.setShapesInProgress([]); + this.execute(new actions.ClearAction(this, oldShapes, newShapes)); + this.repaintLayer('main'); + if (triggerClearEvent) { + this.trigger('clear', null); + } + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.execute = function(action) { + this.undoStack.push(action); + action["do"](); + return this.redoStack = []; + }; + + LiterallyCanvas.prototype.undo = function() { + var action; + if (!this.undoStack.length) { + return; + } + action = this.undoStack.pop(); + action.undo(); + this.redoStack.push(action); + this.trigger('undo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.redo = function() { + var action; + if (!this.redoStack.length) { + return; + } + action = this.redoStack.pop(); + this.undoStack.push(action); + action["do"](); + this.trigger('redo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.canUndo = function() { + return !!this.undoStack.length; + }; + + LiterallyCanvas.prototype.canRedo = function() { + return !!this.redoStack.length; + }; + + LiterallyCanvas.prototype.getPixel = function(x, y) { + var p, pixel; + p = this.drawingCoordsToClientCoords(x, y); + pixel = this.ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } + }; + + LiterallyCanvas.prototype.getContentBounds = function() { + return util.getBoundingRect((this.shapes.concat(this.backgroundShapes)).map(function(s) { + return s.getBoundingRect(); + }), this.width === INFINITE ? 0 : this.width, this.height === INFINITE ? 0 : this.height); + }; + + LiterallyCanvas.prototype.getDefaultImageRect = function(explicitSize, margin) { + var s; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + return util.getDefaultImageRect((function() { + var i, len, ref1, results; + ref1 = this.shapes.concat(this.backgroundShapes); + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + s = ref1[i]; + results.push(s.getBoundingRect(this.ctx)); + } + return results; + }).call(this), explicitSize, margin); + }; + + LiterallyCanvas.prototype.getImage = function(opts) { + if (opts == null) { + opts = {}; + } + if (opts.includeWatermark == null) { + opts.includeWatermark = true; + } + if (opts.scaleDownRetina == null) { + opts.scaleDownRetina = true; + } + if (opts.scale == null) { + opts.scale = 1; + } + if (!opts.scaleDownRetina) { + opts.scale *= this.backingScale; + } + if (opts.includeWatermark) { + opts.watermarkImage = this.watermarkImage; + opts.watermarkScale = this.watermarkScale; + if (!opts.scaleDownRetina) { + opts.watermarkScale *= this.backingScale; + } + } + return renderSnapshotToImage(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.canvasForExport = function() { + this.repaintAllLayers(); + return util.combineCanvases(this.backgroundCanvas, this.canvas); + }; + + LiterallyCanvas.prototype.canvasWithBackground = function(backgroundImageOrCanvas) { + return util.combineCanvases(backgroundImageOrCanvas, this.canvasForExport()); + }; + + LiterallyCanvas.prototype.getSnapshot = function(keys) { + var i, k, len, ref1, shape, snapshot; + if (keys == null) { + keys = null; + } + if (keys == null) { + keys = ['shapes', 'imageSize', 'colors', 'position', 'scale', 'backgroundShapes']; + } + snapshot = {}; + ref1 = ['colors', 'position', 'scale']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + if (indexOf.call(keys, k) >= 0) { + snapshot[k] = this[k]; + } + } + if (indexOf.call(keys, 'shapes') >= 0) { + snapshot.shapes = (function() { + var j, len1, ref2, results; + ref2 = this.shapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'backgroundShapes') >= 0) { + snapshot.backgroundShapes = (function() { + var j, len1, ref2, results; + ref2 = this.backgroundShapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'imageSize') >= 0) { + snapshot.imageSize = { + width: this.width, + height: this.height + }; + } + return snapshot; + }; + + LiterallyCanvas.prototype.getSnapshotJSON = function() { + console.warn("lc.getSnapshotJSON() is deprecated. use JSON.stringify(lc.getSnapshot()) instead."); + return JSON.stringify(this.getSnapshot()); + }; + + LiterallyCanvas.prototype.getSVGString = function(opts) { + if (opts == null) { + opts = {}; + } + return renderSnapshotToSVG(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.loadSnapshot = function(snapshot) { + var i, j, k, len, len1, ref1, ref2, s, shape, shapeRepr; + if (!snapshot) { + return; + } + if (snapshot.colors) { + ref1 = ['primary', 'secondary', 'background']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + this.setColor(k, snapshot.colors[k]); + } + } + if (snapshot.shapes) { + this.shapes = []; + ref2 = snapshot.shapes; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shapeRepr = ref2[j]; + shape = JSONToShape(shapeRepr); + if (shape) { + this.execute(new actions.AddShapeAction(this, shape)); + } + } + } + if (snapshot.backgroundShapes) { + this.backgroundShapes = (function() { + var l, len2, ref3, results; + ref3 = snapshot.backgroundShapes; + results = []; + for (l = 0, len2 = ref3.length; l < len2; l++) { + s = ref3[l]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (snapshot.imageSize) { + this.width = snapshot.imageSize.width; + this.height = snapshot.imageSize.height; + } + if (snapshot.position) { + this.position = snapshot.position; + } + if (snapshot.scale) { + this.scale = snapshot.scale; + } + this.repaintAllLayers(); + this.trigger('snapshotLoad'); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.loadSnapshotJSON = function(str) { + console.warn("lc.loadSnapshotJSON() is deprecated. use lc.loadSnapshot(JSON.parse(snapshot)) instead."); + return this.loadSnapshot(JSON.parse(str)); + }; + + return LiterallyCanvas; + +})(); diff --git a/library/js/literallycanvas/js/core/TextRenderer.js b/library/js/literallycanvas/js/core/TextRenderer.js new file mode 100644 index 00000000000..dc5af3bdb6b --- /dev/null +++ b/library/js/literallycanvas/js/core/TextRenderer.js @@ -0,0 +1,201 @@ +var TextRenderer, getLinesToRender, getNextLine, parseFontString; + +require('./fontmetrics.js'); + +parseFontString = function(font) { + var fontFamily, fontItems, fontSize, item, j, len, maybeSize, remainingFontString; + fontItems = font.split(' '); + fontSize = 0; + for (j = 0, len = fontItems.length; j < len; j++) { + item = fontItems[j]; + maybeSize = parseInt(item.replace("px", ""), 10); + if (!isNaN(maybeSize)) { + fontSize = maybeSize; + } + } + if (!fontSize) { + throw "Font size not found"; + } + remainingFontString = font.substring(fontItems[0].length + 1).replace('bold ', '').replace('italic ', '').replace('underline ', ''); + fontFamily = remainingFontString; + return { + fontSize: fontSize, + fontFamily: fontFamily + }; +}; + +getNextLine = function(ctx, text, forcedWidth) { + var doesSubstringFit, endIndex, isEndOfString, isNonWord, isWhitespace, lastGoodIndex, lastOkayIndex, nextWordStartIndex, textToHere, wasInWord; + if (!text.length) { + return ['', '']; + } + endIndex = 0; + lastGoodIndex = 0; + lastOkayIndex = 0; + wasInWord = false; + while (true) { + endIndex += 1; + isEndOfString = endIndex >= text.length; + isWhitespace = (!isEndOfString) && text[endIndex].match(/\s/); + isNonWord = isWhitespace || isEndOfString; + textToHere = text.substring(0, endIndex); + doesSubstringFit = forcedWidth ? ctx.measureTextWidth(textToHere).width <= forcedWidth : true; + if (doesSubstringFit) { + lastOkayIndex = endIndex; + } + if (isNonWord && wasInWord) { + wasInWord = false; + if (doesSubstringFit) { + lastGoodIndex = endIndex; + } + } + wasInWord = !isWhitespace; + if (isEndOfString || !doesSubstringFit) { + if (doesSubstringFit) { + return [text, '']; + } else if (lastGoodIndex > 0) { + nextWordStartIndex = lastGoodIndex + 1; + while (nextWordStartIndex < text.length && text[nextWordStartIndex].match('/\s/')) { + nextWordStartIndex += 1; + } + return [text.substring(0, lastGoodIndex), text.substring(nextWordStartIndex)]; + } else { + return [text.substring(0, lastOkayIndex), text.substring(lastOkayIndex)]; + } + } + } +}; + +getLinesToRender = function(ctx, text, forcedWidth) { + var j, len, lines, nextLine, ref, ref1, remainingText, textLine, textSplitOnLines; + textSplitOnLines = text.split(/\r\n|\r|\n/g); + lines = []; + for (j = 0, len = textSplitOnLines.length; j < len; j++) { + textLine = textSplitOnLines[j]; + ref = getNextLine(ctx, textLine, forcedWidth), nextLine = ref[0], remainingText = ref[1]; + if (nextLine) { + while (nextLine) { + lines.push(nextLine); + ref1 = getNextLine(ctx, remainingText, forcedWidth), nextLine = ref1[0], remainingText = ref1[1]; + } + } else { + lines.push(textLine); + } + } + return lines; +}; + +TextRenderer = (function() { + function TextRenderer(ctx, text1, font1, forcedWidth1, forcedHeight) { + var fontFamily, fontSize, ref; + this.text = text1; + this.font = font1; + this.forcedWidth = forcedWidth1; + this.forcedHeight = forcedHeight; + ref = parseFontString(this.font), fontFamily = ref.fontFamily, fontSize = ref.fontSize; + ctx.font = this.font; + ctx.textBaseline = 'baseline'; + this.emDashWidth = ctx.measureTextWidth('—', fontSize, fontFamily).width; + this.caratWidth = ctx.measureTextWidth('|', fontSize, fontFamily).width; + this.lines = getLinesToRender(ctx, this.text, this.forcedWidth); + this.metricses = this.lines.map((function(_this) { + return function(line) { + return ctx.measureText2(line || 'X', fontSize, _this.font); + }; + })(this)); + this.metrics = { + ascent: Math.max.apply(Math, this.metricses.map(function(arg) { + var ascent; + ascent = arg.ascent; + return ascent; + })), + descent: Math.max.apply(Math, this.metricses.map(function(arg) { + var descent; + descent = arg.descent; + return descent; + })), + fontsize: Math.max.apply(Math, this.metricses.map(function(arg) { + var fontsize; + fontsize = arg.fontsize; + return fontsize; + })), + leading: Math.max.apply(Math, this.metricses.map(function(arg) { + var leading; + leading = arg.leading; + return leading; + })), + width: Math.max.apply(Math, this.metricses.map(function(arg) { + var width; + width = arg.width; + return width; + })), + height: Math.max.apply(Math, this.metricses.map(function(arg) { + var height; + height = arg.height; + return height; + })), + bounds: { + minx: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.minx; + })), + miny: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.miny; + })), + maxx: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxx; + })), + maxy: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxy; + })) + } + }; + this.boundingBoxWidth = Math.ceil(this.metrics.width); + } + + TextRenderer.prototype.draw = function(ctx, x, y) { + var i, j, len, line, ref, results; + ctx.textBaseline = 'top'; + ctx.font = this.font; + i = 0; + ref = this.lines; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + line = ref[j]; + ctx.fillText(line, x, y + i * this.metrics.leading); + results.push(i += 1); + } + return results; + }; + + TextRenderer.prototype.getWidth = function(isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (this.forcedWidth) { + return this.forcedWidth; + } else { + if (isEditing) { + return this.metrics.bounds.maxx + this.caratWidth; + } else { + return this.metrics.bounds.maxx; + } + } + }; + + TextRenderer.prototype.getHeight = function() { + return this.forcedHeight || (this.metrics.leading * this.lines.length); + }; + + return TextRenderer; + +})(); + +module.exports = TextRenderer; diff --git a/library/js/literallycanvas/js/core/actions.js b/library/js/literallycanvas/js/core/actions.js new file mode 100644 index 00000000000..01a3801d0ac --- /dev/null +++ b/library/js/literallycanvas/js/core/actions.js @@ -0,0 +1,80 @@ +var AddShapeAction, ClearAction; + +ClearAction = (function() { + function ClearAction(lc1, oldShapes, newShapes1) { + this.lc = lc1; + this.oldShapes = oldShapes; + this.newShapes = newShapes1; + } + + ClearAction.prototype["do"] = function() { + this.lc.shapes = this.newShapes; + return this.lc.repaintLayer('main'); + }; + + ClearAction.prototype.undo = function() { + this.lc.shapes = this.oldShapes; + return this.lc.repaintLayer('main'); + }; + + return ClearAction; + +})(); + +AddShapeAction = (function() { + function AddShapeAction(lc1, shape1, previousShapeId) { + this.lc = lc1; + this.shape = shape1; + this.previousShapeId = previousShapeId != null ? previousShapeId : null; + } + + AddShapeAction.prototype["do"] = function() { + var found, i, len, newShapes, ref, shape; + if (!this.lc.shapes.length || this.lc.shapes[this.lc.shapes.length - 1].id === this.previousShapeId || this.previousShapeId === null) { + this.lc.shapes.push(this.shape); + } else { + newShapes = []; + found = false; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + newShapes.push(shape); + if (shape.id === this.previousShapeId) { + newShapes.push(this.shape); + found = true; + } + } + if (!found) { + newShapes.push(this.shape); + } + this.lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + AddShapeAction.prototype.undo = function() { + var i, len, newShapes, ref, shape; + if (this.lc.shapes[this.lc.shapes.length - 1].id === this.shape.id) { + this.lc.shapes.pop(); + } else { + newShapes = []; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + if (shape.id !== this.shape.id) { + newShapes.push(shape); + } + } + lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + return AddShapeAction; + +})(); + +module.exports = { + ClearAction: ClearAction, + AddShapeAction: AddShapeAction +}; diff --git a/library/js/literallycanvas/js/core/bindEvents.js b/library/js/literallycanvas/js/core/bindEvents.js new file mode 100644 index 00000000000..d3455284b6f --- /dev/null +++ b/library/js/literallycanvas/js/core/bindEvents.js @@ -0,0 +1,131 @@ +var bindEvents, buttonIsDown, coordsForTouchEvent, position; + +coordsForTouchEvent = function(el, e) { + var p, tx, ty; + tx = e.changedTouches[0].clientX; + ty = e.changedTouches[0].clientY; + p = el.getBoundingClientRect(); + return [tx - p.left, ty - p.top]; +}; + +position = function(el, e) { + var p; + p = el.getBoundingClientRect(); + return { + left: e.clientX - p.left, + top: e.clientY - p.top + }; +}; + +buttonIsDown = function(e) { + if (e.buttons != null) { + return e.buttons === 1; + } else { + return e.which > 0; + } +}; + +module.exports = bindEvents = function(lc, canvas, panWithKeyboard) { + var listener, mouseMoveListener, mouseUpListener, touchEndListener, touchMoveListener, unsubs; + if (panWithKeyboard == null) { + panWithKeyboard = false; + } + unsubs = []; + mouseMoveListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + p = position(canvas, e); + return lc.pointerMove(p.left, p.top); + }; + })(this); + mouseUpListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + canvas.onselectstart = function() { + return true; + }; + p = position(canvas, e); + lc.pointerUp(p.left, p.top); + document.removeEventListener('mousemove', mouseMoveListener); + document.removeEventListener('mouseup', mouseUpListener); + return canvas.addEventListener('mousemove', mouseMoveListener); + }; + })(this); + canvas.addEventListener('mousedown', (function(_this) { + return function(e) { + var down, p; + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + down = true; + e.preventDefault(); + canvas.onselectstart = function() { + return false; + }; + p = position(canvas, e); + lc.pointerDown(p.left, p.top); + canvas.removeEventListener('mousemove', mouseMoveListener); + document.addEventListener('mousemove', mouseMoveListener); + return document.addEventListener('mouseup', mouseUpListener); + }; + })(this)); + touchMoveListener = function(e) { + e.preventDefault(); + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + }; + touchEndListener = function(e) { + e.preventDefault(); + lc.pointerUp.apply(lc, coordsForTouchEvent(canvas, e)); + document.removeEventListener('touchmove', touchMoveListener); + document.removeEventListener('touchend', touchEndListener); + return document.removeEventListener('touchcancel', touchEndListener); + }; + canvas.addEventListener('touchstart', function(e) { + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + e.preventDefault(); + if (e.touches.length === 1) { + lc.pointerDown.apply(lc, coordsForTouchEvent(canvas, e)); + document.addEventListener('touchmove', touchMoveListener); + document.addEventListener('touchend', touchEndListener); + return document.addEventListener('touchcancel', touchEndListener); + } else { + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + } + }); + if (panWithKeyboard) { + console.warn("Keyboard panning is deprecated."); + listener = function(e) { + switch (e.keyCode) { + case 37: + lc.pan(-10, 0); + break; + case 38: + lc.pan(0, -10); + break; + case 39: + lc.pan(10, 0); + break; + case 40: + lc.pan(0, 10); + } + return lc.repaintAllLayers(); + }; + document.addEventListener('keydown', listener); + unsubs.push(function() { + return document.removeEventListener(listener); + }); + } + return function() { + var f, i, len, results; + results = []; + for (i = 0, len = unsubs.length; i < len; i++) { + f = unsubs[i]; + results.push(f()); + } + return results; + }; +}; diff --git a/library/js/literallycanvas/js/core/canvasRenderer.js b/library/js/literallycanvas/js/core/canvasRenderer.js new file mode 100644 index 00000000000..943f27bfa7d --- /dev/null +++ b/library/js/literallycanvas/js/core/canvasRenderer.js @@ -0,0 +1,258 @@ +var _drawRawLinePath, defineCanvasRenderer, drawErasedLinePath, drawErasedLinePathLatest, drawLinePath, drawLinePathLatest, lineEndCapShapes, noop, renderShapeToCanvas, renderShapeToContext, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineCanvasRenderer = function(shapeName, drawFunc, drawLatestFunc) { + return renderers[shapeName] = { + drawFunc: drawFunc, + drawLatestFunc: drawLatestFunc + }; +}; + +noop = function() {}; + +renderShapeToContext = function(ctx, shape, opts) { + var bufferCtx; + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (opts.retryCallback == null) { + opts.retryCallback = noop; + } + if (opts.shouldOnlyDrawLatest == null) { + opts.shouldOnlyDrawLatest = false; + } + if (opts.bufferCtx == null) { + opts.bufferCtx = null; + } + bufferCtx = opts.bufferCtx; + if (renderers[shape.className]) { + if (opts.shouldOnlyDrawLatest && renderers[shape.className].drawLatestFunc) { + return renderers[shape.className].drawLatestFunc(ctx, bufferCtx, shape, opts.retryCallback); + } else { + return renderers[shape.className].drawFunc(ctx, shape, opts.retryCallback); + } + } else if (opts.shouldIgnoreUnsupportedShapes) { + return console.warn("Can't render shape of type " + shape.className + " to canvas"); + } else { + throw "Can't render shape of type " + shape.className + " to canvas"; + } +}; + +renderShapeToCanvas = function(canvas, shape, opts) { + return renderShapeToContext(canvas.getContext('2d'), shape, opts); +}; + +defineCanvasRenderer('Rectangle', function(ctx, shape) { + var x, y; + x = shape.x; + y = shape.y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + ctx.fillStyle = shape.fillColor; + ctx.fillRect(x, y, shape.width, shape.height); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.strokeRect(x, y, shape.width, shape.height); +}); + +defineCanvasRenderer('Ellipse', function(ctx, shape) { + var centerX, centerY, halfHeight, halfWidth; + ctx.save(); + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + ctx.translate(centerX, centerY); + ctx.scale(1, Math.abs(shape.height / shape.width)); + ctx.beginPath(); + ctx.arc(0, 0, Math.abs(halfWidth), 0, Math.PI * 2); + ctx.closePath(); + ctx.restore(); + ctx.fillStyle = shape.fillColor; + ctx.fill(); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.stroke(); +}); + +defineCanvasRenderer('SelectionBox', (function() { + var _drawHandle; + _drawHandle = function(ctx, arg, handleSize) { + var x, y; + x = arg.x, y = arg.y; + if (handleSize === 0) { + return; + } + ctx.fillStyle = '#fff'; + ctx.fillRect(x, y, handleSize, handleSize); + ctx.strokeStyle = '#000'; + return ctx.strokeRect(x, y, handleSize, handleSize); + }; + return function(ctx, shape) { + _drawHandle(ctx, shape.getTopLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getTopRightHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomRightHandleRect(), shape.handleSize); + if (shape.backgroundColor) { + ctx.fillStyle = shape.backgroundColor; + ctx.fillRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + } + ctx.lineWidth = 1; + ctx.strokeStyle = '#000'; + ctx.setLineDash([2, 4]); + ctx.strokeRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + return ctx.setLineDash([]); + }; +})()); + +defineCanvasRenderer('Image', function(ctx, shape, retryCallback) { + if (shape.image.width) { + if (shape.scale === 1) { + return ctx.drawImage(shape.image, shape.x, shape.y); + } else { + return ctx.drawImage(shape.image, shape.x, shape.y, shape.image.width * shape.scale, shape.image.height * shape.scale); + } + } else if (retryCallback) { + return shape.image.onload = retryCallback; + } +}); + +defineCanvasRenderer('Line', function(ctx, shape) { + var arrowWidth, x1, x2, y1, y2; + if (shape.x1 === shape.x2 && shape.y1 === shape.y2) { + return; + } + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.color; + ctx.lineCap = shape.capStyle; + if (shape.dash) { + ctx.setLineDash(shape.dash); + } + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + if (shape.dash) { + ctx.setLineDash([]); + } + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + if (shape.endCapShapes[0]) { + lineEndCapShapes[shape.endCapShapes[0]].drawToCanvas(ctx, x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + return lineEndCapShapes[shape.endCapShapes[1]].drawToCanvas(ctx, x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } +}); + +_drawRawLinePath = function(ctx, points, close, lineCap) { + var i, len, point, ref; + if (close == null) { + close = false; + } + if (lineCap == null) { + lineCap = 'round'; + } + if (!points.length) { + return; + } + ctx.lineCap = lineCap; + ctx.strokeStyle = points[0].color; + ctx.lineWidth = points[0].size; + ctx.beginPath(); + if (points[0].size % 2 === 0) { + ctx.moveTo(points[0].x, points[0].y); + } else { + ctx.moveTo(points[0].x + 0.5, points[0].y + 0.5); + } + ref = points.slice(1); + for (i = 0, len = ref.length; i < len; i++) { + point = ref[i]; + if (points[0].size % 2 === 0) { + ctx.lineTo(point.x, point.y); + } else { + ctx.lineTo(point.x + 0.5, point.y + 0.5); + } + } + if (close) { + return ctx.closePath(); + } +}; + +drawLinePath = function(ctx, shape) { + _drawRawLinePath(ctx, shape.smoothedPoints); + return ctx.stroke(); +}; + +drawLinePathLatest = function(ctx, bufferCtx, shape) { + var drawEnd, drawStart, segmentStart; + if (shape.tail) { + segmentStart = shape.smoothedPoints.length - shape.segmentSize * shape.tailSize; + drawStart = segmentStart < shape.segmentSize * 2 ? 0 : segmentStart; + drawEnd = segmentStart + shape.segmentSize + 1; + _drawRawLinePath(bufferCtx, shape.smoothedPoints.slice(drawStart, drawEnd)); + return bufferCtx.stroke(); + } else { + _drawRawLinePath(bufferCtx, shape.smoothedPoints); + return bufferCtx.stroke(); + } +}; + +defineCanvasRenderer('LinePath', drawLinePath, drawLinePathLatest); + +drawErasedLinePath = function(ctx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + drawLinePath(ctx, shape); + return ctx.restore(); +}; + +drawErasedLinePathLatest = function(ctx, bufferCtx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + bufferCtx.save(); + bufferCtx.globalCompositeOperation = "destination-out"; + drawLinePathLatest(ctx, bufferCtx, shape); + ctx.restore(); + return bufferCtx.restore(); +}; + +defineCanvasRenderer('ErasedLinePath', drawErasedLinePath, drawErasedLinePathLatest); + +defineCanvasRenderer('Text', function(ctx, shape) { + if (!shape.renderer) { + shape._makeRenderer(ctx); + } + ctx.fillStyle = shape.color; + return shape.renderer.draw(ctx, shape.x, shape.y); +}); + +defineCanvasRenderer('Polygon', function(ctx, shape) { + ctx.fillStyle = shape.fillColor; + _drawRawLinePath(ctx, shape.points, shape.isClosed, 'butt'); + ctx.fill(); + return ctx.stroke(); +}); + +module.exports = { + defineCanvasRenderer: defineCanvasRenderer, + renderShapeToCanvas: renderShapeToCanvas, + renderShapeToContext: renderShapeToContext +}; diff --git a/library/js/literallycanvas/js/core/defaultOptions.js b/library/js/literallycanvas/js/core/defaultOptions.js new file mode 100644 index 00000000000..ac6e010e233 --- /dev/null +++ b/library/js/literallycanvas/js/core/defaultOptions.js @@ -0,0 +1,21 @@ +'use strict'; + +module.exports = { + imageURLPrefix: 'lib/img', + primaryColor: 'hsla(0, 0%, 0%, 1)', + secondaryColor: 'hsla(0, 0%, 100%, 1)', + backgroundColor: 'transparent', + strokeWidths: [1, 2, 5, 10, 20, 30], + defaultStrokeWidth: 5, + toolbarPosition: 'top', + keyboardShortcuts: false, + imageSize: { width: 'infinite', height: 'infinite' }, + backgroundShapes: [], + watermarkImage: null, + watermarkScale: 1, + zoomMin: 0.2, + zoomMax: 4.0, + zoomStep: 0.2, + snapshot: null, + tools: [require('../tools/Pencil'), require('../tools/Eraser'), require('../tools/Line'), require('../tools/Rectangle'), require('../tools/Ellipse'), require('../tools/Text'), require('../tools/Polygon'), require('../tools/Pan'), require('../tools/Eyedropper')] +}; \ No newline at end of file diff --git a/library/js/literallycanvas/js/core/fontmetrics.js b/library/js/literallycanvas/js/core/fontmetrics.js new file mode 100644 index 00000000000..1f2e7e22961 --- /dev/null +++ b/library/js/literallycanvas/js/core/fontmetrics.js @@ -0,0 +1,197 @@ +"use strict"; + +/** + This library rewrites the Canvas2D "measureText" function + so that it returns a more complete metrics object. + This library is licensed under the MIT (Expat) license, + the text for which is included below. + +** ----------------------------------------------------------------------------- + + CHANGELOG: + + 2012-01-21 - Whitespace handling added by Joe Turner + (https://github.com/oampo) + + 2015-06-08 - Various hacks added by Steve Johnson + +** ----------------------------------------------------------------------------- + + Copyright (C) 2011 by Mike "Pomax" Kamermans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +**/ +(function () { + var NAME = "FontMetrics Library"; + var VERSION = "1-2012.0121.1300"; + + // if there is no getComputedStyle, this library won't work. + if (!document.defaultView.getComputedStyle) { + throw "ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values."; + } + + // store the old text metrics function on the Canvas2D prototype + CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText; + + /** + * shortcut function for getting computed CSS values + */ + var getCSSValue = function getCSSValue(element, property) { + return document.defaultView.getComputedStyle(element, null).getPropertyValue(property); + }; + + // debug function + var show = function show(canvas, ctx, xstart, w, h, metrics) { + document.body.appendChild(canvas); + ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; + + ctx.beginPath(); + ctx.moveTo(xstart, 0); + ctx.lineTo(xstart, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(xstart + metrics.bounds.maxx, 0); + ctx.lineTo(xstart + metrics.bounds.maxx, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 - metrics.ascent); + ctx.lineTo(w, h / 2 - metrics.ascent); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 + metrics.descent); + ctx.lineTo(w, h / 2 + metrics.descent); + ctx.closePath(); + ctx.stroke(); + }; + + /** + * The new text metrics function + */ + CanvasRenderingContext2D.prototype.measureText2 = function (textstring, fontSize, fontString) { + var metrics = this.measureTextWidth(textstring), + isSpace = !/\S/.test(textstring); + metrics.fontsize = fontSize; + + // for text lead values, we meaure a multiline text container. + var leadDiv = document.createElement("div"); + leadDiv.style.position = "absolute"; + leadDiv.style.opacity = 0; + leadDiv.style.font = fontString; + leadDiv.innerHTML = textstring + "
" + textstring; + document.body.appendChild(leadDiv); + + // make some initial guess at the text leading (using the standard TeX ratio) + metrics.leading = 1.2 * fontSize; + + // then we try to get the real value from the browser + var leadDivHeight = getCSSValue(leadDiv, "height"); + leadDivHeight = leadDivHeight.replace("px", ""); + if (leadDivHeight >= fontSize * 2) { + metrics.leading = leadDivHeight / 2 | 0; + } + document.body.removeChild(leadDiv); + + // if we're not dealing with white space, we can compute metrics + if (!isSpace) { + // Have characters, so measure the text + var canvas = document.createElement("canvas"); + var padding = 100; + canvas.width = metrics.width + padding; + canvas.height = 3 * fontSize; + canvas.style.opacity = 1; + canvas.style.font = fontString; + var ctx = canvas.getContext("2d"); + ctx.font = fontString; + + var w = canvas.width, + h = canvas.height, + baseline = h / 2; + + // Set all canvas pixeldata values to 255, with all the content + // data being 0. This lets us scan for data[i] != 255. + ctx.fillStyle = "white"; + ctx.fillRect(-1, -1, w + 2, h + 2); + ctx.fillStyle = "black"; + ctx.fillText(textstring, padding / 2, baseline); + var pixelData = ctx.getImageData(0, 0, w, h).data; + + // canvas pixel data is w*4 by h*4, because R, G, B and A are separate, + // consecutive values in the array, rather than stored as 32 bit ints. + var i = 0, + w4 = w * 4, + len = pixelData.length; + + // Finding the ascent uses a normal, forward scanline + while (++i < len && pixelData[i] === 255) {} + var ascent = i / w4 | 0; + + // Finding the descent uses a reverse scanline + i = len - 1; + while (--i > 0 && pixelData[i] === 255) {} + var descent = i / w4 | 0; + + // find the min-x coordinate + for (i = 0; i < len && pixelData[i] === 255;) { + i += w4; + if (i >= len) { + i = i - len + 4; + } + } + var minx = i % w4 / 4 | 0; + + // find the max-x coordinate + var step = 1; + for (i = len - 3; i >= 0 && pixelData[i] === 255;) { + i -= w4; + if (i < 0) { + i = len - 3 - step++ * 4; + } + } + var maxx = i % w4 / 4 + 1 | 0; + + // set font metrics + metrics.ascent = baseline - ascent; + metrics.descent = descent - baseline; + metrics.bounds = { minx: minx - padding / 2, + maxx: maxx - padding / 2, + miny: 0, + maxy: descent - ascent }; + metrics.height = 1 + (descent - ascent); + } + + // if we ARE dealing with whitespace, most values will just be zero. + else { + // Only whitespace, so we can't measure the text + metrics.ascent = 0; + metrics.descent = 0; + metrics.bounds = { minx: 0, + maxx: metrics.width, // Best guess + miny: 0, + maxy: 0 }; + metrics.height = 0; + } + return metrics; + }; +})(); \ No newline at end of file diff --git a/library/js/literallycanvas/js/core/lineEndCapShapes.js b/library/js/literallycanvas/js/core/lineEndCapShapes.js new file mode 100644 index 00000000000..c3885f89357 --- /dev/null +++ b/library/js/literallycanvas/js/core/lineEndCapShapes.js @@ -0,0 +1,48 @@ +module.exports = { + arrow: (function() { + var getPoints; + getPoints = function(x, y, angle, width, length) { + return [ + { + x: x + Math.cos(angle + Math.PI / 2) * width / 2, + y: y + Math.sin(angle + Math.PI / 2) * width / 2 + }, { + x: x + Math.cos(angle) * length, + y: y + Math.sin(angle) * length + }, { + x: x + Math.cos(angle - Math.PI / 2) * width / 2, + y: y + Math.sin(angle - Math.PI / 2) * width / 2 + } + ]; + }; + return { + drawToCanvas: function(ctx, x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + ctx.fillStyle = color; + ctx.lineWidth = 0; + ctx.strokeStyle = 'transparent'; + ctx.beginPath(); + points = getPoints(x, y, angle, width, length); + ctx.moveTo(points[0].x, points[0].y); + ctx.lineTo(points[1].x, points[1].y); + ctx.lineTo(points[2].x, points[2].y); + return ctx.fill(); + }, + svg: function(x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + points = getPoints(x, y, angle, width, length); + return ""; + } + }; + })() +}; diff --git a/library/js/literallycanvas/js/core/localization.js b/library/js/literallycanvas/js/core/localization.js new file mode 100644 index 00000000000..737d6226c61 --- /dev/null +++ b/library/js/literallycanvas/js/core/localization.js @@ -0,0 +1,18 @@ +var _, localize, strings; + +strings = {}; + +localize = function(localStrings) { + return strings = localStrings; +}; + +_ = function(string) { + var translation; + translation = strings[string]; + return translation || string; +}; + +module.exports = { + localize: localize, + _: _ +}; diff --git a/library/js/literallycanvas/js/core/math.js b/library/js/literallycanvas/js/core/math.js new file mode 100644 index 00000000000..bf6c0ab7dda --- /dev/null +++ b/library/js/literallycanvas/js/core/math.js @@ -0,0 +1,86 @@ +var Point, _slope, math, normals, unit, util; + +Point = require('./shapes').Point; + +util = require('./util'); + +math = {}; + +math.toPoly = function(line) { + var i, index, len, n, point, polyLeft, polyRight; + polyLeft = []; + polyRight = []; + index = 0; + for (i = 0, len = line.length; i < len; i++) { + point = line[i]; + n = normals(point, _slope(line, index)); + polyLeft = polyLeft.concat([n[0]]); + polyRight = [n[1]].concat(polyRight); + index += 1; + } + return polyLeft.concat(polyRight); +}; + +_slope = function(line, index) { + var point; + if (line.length < 3) { + point = { + x: 0, + y: 0 + }; + } + if (index === 0) { + point = _slope(line, index + 1); + } else if (index === line.length - 1) { + point = _slope(line, index - 1); + } else { + point = math.diff(line[index - 1], line[index + 1]); + } + return point; +}; + +math.diff = function(a, b) { + return { + x: b.x - a.x, + y: b.y - a.y + }; +}; + +unit = function(vector) { + var length; + length = math.len(vector); + return { + x: vector.x / length, + y: vector.y / length + }; +}; + +normals = function(p, slope) { + slope = unit(slope); + slope.x = slope.x * p.size / 2; + slope.y = slope.y * p.size / 2; + return [ + { + x: p.x - slope.y, + y: p.y + slope.x, + color: p.color + }, { + x: p.x + slope.y, + y: p.y - slope.x, + color: p.color + } + ]; +}; + +math.len = function(vector) { + return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2)); +}; + +math.scalePositionScalar = function(val, viewportSize, oldScale, newScale) { + var newSize, oldSize; + oldSize = viewportSize * oldScale; + newSize = viewportSize * newScale; + return val + (oldSize - newSize) / 2; +}; + +module.exports = math; diff --git a/library/js/literallycanvas/js/core/renderSnapshotToImage.js b/library/js/literallycanvas/js/core/renderSnapshotToImage.js new file mode 100644 index 00000000000..c9ab84120ae --- /dev/null +++ b/library/js/literallycanvas/js/core/renderSnapshotToImage.js @@ -0,0 +1,96 @@ +var INFINITE, JSONToShape, renderWatermark, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +renderWatermark = function(ctx, image, scale) { + if (!image.width) { + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(scale, scale); + ctx.drawImage(image, -image.width / 2, -image.height / 2); + return ctx.restore(); +}; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, imageSize, s, shapes, watermarkCanvas, watermarkCtx; + if (opts == null) { + opts = {}; + } + if (opts.scale == null) { + opts.scale = 1; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + watermarkCanvas = document.createElement('canvas'); + watermarkCtx = watermarkCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(watermarkCtx)); + } + return results; + })(), imageSize, opts.margin); + } + watermarkCanvas.width = opts.rect.width * opts.scale; + watermarkCanvas.height = opts.rect.height * opts.scale; + watermarkCtx.fillStyle = colors.background; + watermarkCtx.fillRect(0, 0, watermarkCanvas.width, watermarkCanvas.height); + if (!(opts.rect.width && opts.rect.height)) { + return null; + } + if (opts.watermarkImage) { + renderWatermark(watermarkCtx, opts.watermarkImage, opts.watermarkScale); + } + return util.combineCanvases(watermarkCanvas, util.renderShapes(backgroundShapes, opts.rect, opts.scale), util.renderShapes(shapes, opts.rect, opts.scale)); +}; diff --git a/library/js/literallycanvas/js/core/renderSnapshotToSVG.js b/library/js/literallycanvas/js/core/renderSnapshotToSVG.js new file mode 100644 index 00000000000..aa21a540336 --- /dev/null +++ b/library/js/literallycanvas/js/core/renderSnapshotToSVG.js @@ -0,0 +1,72 @@ +var INFINITE, JSONToShape, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, ctx, dummyCanvas, imageSize, s, shapes; + if (opts == null) { + opts = {}; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + dummyCanvas = document.createElement('canvas'); + ctx = dummyCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(ctx)); + } + return results; + })(), imageSize, opts.margin); + } + return LC.renderShapesToSVG(backgroundShapes.concat(shapes), opts.rect, colors.background); +}; diff --git a/library/js/literallycanvas/js/core/shapes.js b/library/js/literallycanvas/js/core/shapes.js new file mode 100644 index 00000000000..d1051e51607 --- /dev/null +++ b/library/js/literallycanvas/js/core/shapes.js @@ -0,0 +1,921 @@ +var JSONToShape, LinePath, TextRenderer, _createLinePathFromData, _doAllPointsShareStyle, _dual, _mid, _refine, bspline, createShape, defineCanvasRenderer, defineSVGRenderer, defineShape, lineEndCapShapes, linePathFuncs, ref, ref1, renderShapeToContext, renderShapeToSVG, shapeToJSON, shapes, util; + +util = require('./util'); + +TextRenderer = require('./TextRenderer'); + +lineEndCapShapes = require('./lineEndCapShapes'); + +ref = require('./canvasRenderer'), defineCanvasRenderer = ref.defineCanvasRenderer, renderShapeToContext = ref.renderShapeToContext; + +ref1 = require('./svgRenderer'), defineSVGRenderer = ref1.defineSVGRenderer, renderShapeToSVG = ref1.renderShapeToSVG; + +shapes = {}; + +defineShape = function(name, props) { + var Shape, drawFunc, drawLatestFunc, k, legacyDrawFunc, legacyDrawLatestFunc, legacySVGFunc, svgFunc; + Shape = function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + props.constructor.call(this, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + return this; + }; + Shape.prototype.className = name; + Shape.fromJSON = props.fromJSON; + if (props.draw) { + legacyDrawFunc = props.draw; + legacyDrawLatestFunc = props.draw || function(ctx, bufferCtx, retryCallback) { + return this.draw(ctx, bufferCtx, retryCallback); + }; + drawFunc = function(ctx, shape, retryCallback) { + return legacyDrawFunc.call(shape, ctx, retryCallback); + }; + drawLatestFunc = function(ctx, bufferCtx, shape, retryCallback) { + return legacyDrawLatestFunc.call(shape, ctx, bufferCtx, retryCallback); + }; + delete props.draw; + if (props.drawLatest) { + delete props.drawLatest; + } + defineCanvasRenderer(name, drawFunc, drawLatestFunc); + } + if (props.toSVG) { + legacySVGFunc = props.toSVG; + svgFunc = function(shape) { + return legacySVGFunc.call(shape); + }; + delete props.toSVG; + defineSVGRenderer(name, svgFunc); + } + Shape.prototype.draw = function(ctx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback + }); + }; + Shape.prototype.drawLatest = function(ctx, bufferCtx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback, + bufferCtx: bufferCtx, + shouldOnlyDrawLatest: true + }); + }; + Shape.prototype.toSVG = function() { + return renderShapeToSVG(this); + }; + for (k in props) { + if (k !== 'fromJSON') { + Shape.prototype[k] = props[k]; + } + } + shapes[name] = Shape; + return Shape; +}; + +createShape = function(name, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + var s; + s = new shapes[name](a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + s.id = util.getGUID(); + return s; +}; + +JSONToShape = function(arg) { + var className, data, id, shape; + className = arg.className, data = arg.data, id = arg.id; + if (className in shapes) { + shape = shapes[className].fromJSON(data); + if (shape) { + if (id) { + shape.id = id; + } + return shape; + } else { + console.log('Unreadable shape:', className, data); + return null; + } + } else { + console.log("Unknown shape:", className, data); + return null; + } +}; + +shapeToJSON = function(shape) { + return { + className: shape.className, + data: shape.toJSON(), + id: shape.id + }; +}; + +bspline = function(points, order) { + if (!order) { + return points; + } + return bspline(_dual(_dual(_refine(points))), order - 1); +}; + +_refine = function(points) { + var index, len, point, q, refined; + points = [points[0]].concat(points).concat(util.last(points)); + refined = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + refined[index * 2] = point; + if (points[index + 1]) { + refined[index * 2 + 1] = _mid(point, points[index + 1]); + } + index += 1; + } + return refined; +}; + +_dual = function(points) { + var dualed, index, len, point, q; + dualed = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (points[index + 1]) { + dualed[index] = _mid(point, points[index + 1]); + } + index += 1; + } + return dualed; +}; + +_mid = function(a, b) { + return createShape('Point', { + x: a.x + ((b.x - a.x) / 2), + y: a.y + ((b.y - a.y) / 2), + size: a.size + ((b.size - a.size) / 2), + color: a.color + }); +}; + +defineShape('Image', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.scale = args.scale || 1; + return this.image = args.image || null; + }, + getBoundingRect: function() { + return { + x: this.x, + y: this.y, + width: this.image.width * this.scale, + height: this.image.height * this.scale + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + imageSrc: this.image.src, + imageObject: this.image, + scale: this.scale + }; + }, + fromJSON: function(data) { + var img, ref2; + img = null; + if ((ref2 = data.imageObject) != null ? ref2.width : void 0) { + img = data.imageObject; + } else { + img = new Image(); + img.src = data.imageSrc; + } + return createShape('Image', { + x: data.x, + y: data.y, + image: img, + scale: data.scale + }); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Rectangle', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Rectangle', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Ellipse', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Ellipse', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Line', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x1 = args.x1 || 0; + this.y1 = args.y1 || 0; + this.x2 = args.x2 || 0; + this.y2 = args.y2 || 0; + this.strokeWidth = args.strokeWidth || 1; + this.color = args.color || 'black'; + this.capStyle = args.capStyle || 'round'; + this.endCapShapes = args.endCapShapes || [null, null]; + return this.dash = args.dash || null; + }, + getBoundingRect: function() { + return { + x: Math.min(this.x1, this.x2) - this.strokeWidth / 2, + y: Math.min(this.y1, this.y2) - this.strokeWidth / 2, + width: Math.abs(this.x2 - this.x1) + this.strokeWidth / 2, + height: Math.abs(this.y2 - this.y1) + this.strokeWidth / 2 + }; + }, + toJSON: function() { + return { + x1: this.x1, + y1: this.y1, + x2: this.x2, + y2: this.y2, + strokeWidth: this.strokeWidth, + color: this.color, + capStyle: this.capStyle, + dash: this.dash, + endCapShapes: this.endCapShapes + }; + }, + fromJSON: function(data) { + return createShape('Line', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x1 = this.x1 - moveInfo.xDiff; + this.y1 = this.y1 - moveInfo.yDiff; + this.x2 = this.x2 - moveInfo.xDiff; + return this.y2 = this.y2 - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +_doAllPointsShareStyle = function(points) { + var color, len, point, q, size; + if (!points.length) { + return false; + } + size = points[0].size; + color = points[0].color; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (!(point.size === size && point.color === color)) { + console.log(size, color, point.size, point.color); + } + if (!(point.size === size && point.color === color)) { + return false; + } + } + return true; +}; + +_createLinePathFromData = function(shapeName, data) { + var pointData, points, smoothedPoints, x, y; + points = null; + if (data.points) { + points = (function() { + var len, q, ref2, results; + ref2 = data.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pointData = ref2[q]; + results.push(JSONToShape(pointData)); + } + return results; + })(); + } else if (data.pointCoordinatePairs) { + points = (function() { + var len, q, ref2, ref3, results; + ref2 = data.pointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + smoothedPoints = null; + if (data.smoothedPointCoordinatePairs) { + smoothedPoints = (function() { + var len, q, ref2, ref3, results; + ref2 = data.smoothedPointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + if (!points[0]) { + return null; + } + return createShape(shapeName, { + points: points, + smoothedPoints: smoothedPoints, + order: data.order, + tailSize: data.tailSize, + smooth: data.smooth + }); +}; + +linePathFuncs = { + constructor: function(args) { + var len, point, points, q, results; + if (args == null) { + args = {}; + } + points = args.points || []; + this.order = args.order || 3; + this.tailSize = args.tailSize || 3; + this.smooth = 'smooth' in args ? args.smooth : true; + this.segmentSize = Math.pow(2, this.order); + this.sampleSize = this.tailSize + 1; + if (args.smoothedPoints) { + this.points = args.points; + return this.smoothedPoints = args.smoothedPoints; + } else { + this.points = []; + results = []; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + results.push(this.addPoint(point)); + } + return results; + } + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return { + x: p.x - p.size / 2, + y: p.y - p.size / 2, + width: p.size, + height: p.size + }; + })); + }, + toJSON: function() { + var p, point; + if (_doAllPointsShareStyle(this.points)) { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + pointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + smoothedPointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.smoothedPoints; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + pointSize: this.points[0].size, + pointColor: this.points[0].color + }; + } else { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + points: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + p = ref2[q]; + results.push(shapeToJSON(p)); + } + return results; + }).call(this) + }; + } + }, + fromJSON: function(data) { + return _createLinePathFromData('LinePath', data); + }, + addPoint: function(point) { + this.points.push(point); + if (!this.smooth) { + this.smoothedPoints = this.points; + return; + } + if (!this.smoothedPoints || this.points.length < this.sampleSize) { + return this.smoothedPoints = bspline(this.points, this.order); + } else { + this.tail = util.last(bspline(util.last(this.points, this.sampleSize), this.order), this.segmentSize * this.tailSize); + return this.smoothedPoints = this.smoothedPoints.slice(0, this.smoothedPoints.length - this.segmentSize * (this.tailSize - 1)).concat(this.tail); + } + }, + move: function(moveInfo) { + var len, pt, pts, q; + if (moveInfo == null) { + moveInfo = {}; + } + if (!this.smooth) { + pts = this.points; + } else { + pts = this.smoothedPoints; + } + for (q = 0, len = pts.length; q < len; q++) { + pt = pts[q]; + pt.move(moveInfo); + } + return this.points = this.smoothedPoints; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}; + +LinePath = defineShape('LinePath', linePathFuncs); + +defineShape('ErasedLinePath', { + constructor: linePathFuncs.constructor, + toJSON: linePathFuncs.toJSON, + addPoint: linePathFuncs.addPoint, + getBoundingRect: linePathFuncs.getBoundingRect, + fromJSON: function(data) { + return _createLinePathFromData('ErasedLinePath', data); + } +}); + +defineShape('Point', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.size = args.size || 0; + return this.color = args.color || ''; + }, + getBoundingRect: function() { + return { + x: this.x - this.size / 2, + y: this.y - this.size / 2, + width: this.size, + height: this.size + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + size: this.size, + color: this.color + }; + }, + fromJSON: function(data) { + return createShape('Point', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Polygon', { + constructor: function(args) { + var len, point, q, ref2, results; + if (args == null) { + args = {}; + } + this.points = args.points; + this.fillColor = args.fillColor || 'white'; + this.strokeColor = args.strokeColor || 'black'; + this.strokeWidth = args.strokeWidth; + this.dash = args.dash || null; + if (args.isClosed == null) { + args.isClosed = true; + } + this.isClosed = args.isClosed; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + point.color = this.strokeColor; + results.push(point.size = this.strokeWidth); + } + return results; + }, + addPoint: function(x, y) { + return this.points.push(LC.createShape('Point', { + x: x, + y: y + })); + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return p.getBoundingRect(); + })); + }, + toJSON: function() { + return { + strokeWidth: this.strokeWidth, + fillColor: this.fillColor, + strokeColor: this.strokeColor, + dash: this.dash, + isClosed: this.isClosed, + pointCoordinatePairs: this.points.map(function(p) { + return [p.x, p.y]; + }) + }; + }, + fromJSON: function(data) { + data.points = data.pointCoordinatePairs.map(function(arg) { + var x, y; + x = arg[0], y = arg[1]; + return createShape('Point', { + x: x, + y: y, + size: data.strokeWidth, + color: data.strokeColor + }); + }); + return createShape('Polygon', data); + }, + move: function(moveInfo) { + var len, pt, q, ref2, results; + if (moveInfo == null) { + moveInfo = {}; + } + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pt = ref2[q]; + results.push(pt.move(moveInfo)); + } + return results; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +defineShape('Text', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.v = args.v || 0; + this.text = args.text || ''; + this.color = args.color || 'black'; + this.font = args.font || '18px sans-serif'; + this.forcedWidth = args.forcedWidth || null; + return this.forcedHeight = args.forcedHeight || null; + }, + _makeRenderer: function(ctx) { + ctx.lineHeight = 1.2; + this.renderer = new TextRenderer(ctx, this.text, this.font, this.forcedWidth, this.forcedHeight); + if (this.v < 1) { + console.log('repairing baseline'); + this.v = 1; + this.x -= this.renderer.metrics.bounds.minx; + return this.y -= this.renderer.metrics.leading - this.renderer.metrics.descent; + } + }, + setText: function(text) { + this.text = text; + return this.renderer = null; + }, + setFont: function(font) { + this.font = font; + return this.renderer = null; + }, + setPosition: function(x, y) { + this.x = x; + return this.y = y; + }, + setSize: function(forcedWidth, forcedHeight) { + this.forcedWidth = Math.max(forcedWidth, 0); + this.forcedHeight = Math.max(forcedHeight, 0); + return this.renderer = null; + }, + enforceMaxBoundingRect: function(lc) { + var br, dx, lcBoundingRect; + br = this.getBoundingRect(lc.ctx); + lcBoundingRect = { + x: -lc.position.x / lc.scale, + y: -lc.position.y / lc.scale, + width: lc.canvas.width / lc.scale, + height: lc.canvas.height / lc.scale + }; + if (br.x + br.width > lcBoundingRect.x + lcBoundingRect.width) { + dx = br.x - lcBoundingRect.x; + this.forcedWidth = lcBoundingRect.width - dx - 10; + return this.renderer = null; + } + }, + getBoundingRect: function(ctx, isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (!this.renderer) { + if (ctx) { + this._makeRenderer(ctx); + } else { + throw "Must pass ctx if text hasn't been rendered yet"; + } + } + return { + x: Math.floor(this.x), + y: Math.floor(this.y), + width: Math.ceil(this.renderer.getWidth(true)), + height: Math.ceil(this.renderer.getHeight()) + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + text: this.text, + color: this.color, + font: this.font, + forcedWidth: this.forcedWidth, + forcedHeight: this.forcedHeight, + v: this.v + }; + }, + fromJSON: function(data) { + return createShape('Text', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('SelectionBox', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.shape = args.shape; + if (args.handleSize != null) { + this.handleSize = args.handleSize; + } else { + this.handleSize = 10; + } + this.margin = 4; + this.backgroundColor = args.backgroundColor || null; + return this._br = this.shape.getBoundingRect(args.ctx); + }, + toJSON: function() { + return { + shape: shapeToJSON(this.shape), + backgroundColor: this.backgroundColor + }; + }, + fromJSON: function(arg) { + var backgroundColor, handleSize, margin, shape; + shape = arg.shape, handleSize = arg.handleSize, margin = arg.margin, backgroundColor = arg.backgroundColor; + return createShape('SelectionBox', { + shape: JSONToShape(shape), + backgroundColor: backgroundColor + }); + }, + getTopLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getTopRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBoundingRect: function() { + return { + x: this._br.x - this.margin, + y: this._br.y - this.margin, + width: this._br.width + this.margin * 2, + height: this._br.height + this.margin * 2 + }; + } +}); + +module.exports = { + defineShape: defineShape, + createShape: createShape, + JSONToShape: JSONToShape, + shapeToJSON: shapeToJSON +}; diff --git a/library/js/literallycanvas/js/core/svgRenderer.js b/library/js/literallycanvas/js/core/svgRenderer.js new file mode 100644 index 00000000000..d17b6f0e6a5 --- /dev/null +++ b/library/js/literallycanvas/js/core/svgRenderer.js @@ -0,0 +1,138 @@ +var defineSVGRenderer, lineEndCapShapes, renderShapeToSVG, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineSVGRenderer = function(shapeName, shapeToSVGFunc) { + return renderers[shapeName] = shapeToSVGFunc; +}; + +renderShapeToSVG = function(shape, opts) { + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (renderers[shape.className]) { + return renderers[shape.className](shape); + } else if (opts.shouldIgnoreUnsupportedShapes) { + console.warn("Can't render shape of type " + shape.className + " to SVG"); + return ""; + } else { + throw "Can't render shape of type " + shape.className + " to SVG"; + } +}; + +defineSVGRenderer('Rectangle', function(shape) { + var height, width, x, x1, x2, y, y1, y2; + x1 = shape.x; + y1 = shape.y; + x2 = shape.x + shape.width; + y2 = shape.y + shape.height; + x = Math.min(x1, x2); + y = Math.min(y1, y2); + width = Math.max(x1, x2) - x; + height = Math.max(y1, y2) - y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + return ""; +}); + +defineSVGRenderer('SelectionBox', function(shape) { + return ""; +}); + +defineSVGRenderer('Ellipse', function(shape) { + var centerX, centerY, halfHeight, halfWidth; + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + return ""; +}); + +defineSVGRenderer('Image', function(shape) { + return ""; +}); + +defineSVGRenderer('Line', function(shape) { + var arrowWidth, capString, dashString, x1, x2, y1, y2; + dashString = shape.dash ? "stroke-dasharray='" + (shape.dash.join(', ')) + "'" : ''; + capString = ''; + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + if (shape.endCapShapes[0]) { + capString += lineEndCapShapes[shape.endCapShapes[0]].svg(x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + capString += lineEndCapShapes[shape.endCapShapes[1]].svg(x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } + return " " + capString + " "; +}); + +defineSVGRenderer('LinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('ErasedLinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('Polygon', function(shape) { + if (shape.isClosed) { + return ""; + } else { + return " "; + } +}); + +defineSVGRenderer('Text', function(shape) { + var heightString, textSplitOnLines, widthString; + widthString = shape.forcedWidth ? "width='" + shape.forcedWidth + "px'" : ""; + heightString = shape.forcedHeight ? "height='" + shape.forcedHeight + "px'" : ""; + textSplitOnLines = shape.text.split(/\r\n|\r|\n/g); + if (shape.renderer) { + textSplitOnLines = shape.renderer.lines; + } + return " " + (textSplitOnLines.map((function(_this) { + return function(line, i) { + var dy; + dy = i === 0 ? 0 : '1.2em'; + return " " + line + " "; + }; + })(this)).join('')) + " "; +}); + +module.exports = { + defineSVGRenderer: defineSVGRenderer, + renderShapeToSVG: renderShapeToSVG +}; diff --git a/library/js/literallycanvas/js/core/util.js b/library/js/literallycanvas/js/core/util.js new file mode 100644 index 00000000000..46b49f5f954 --- /dev/null +++ b/library/js/literallycanvas/js/core/util.js @@ -0,0 +1,214 @@ +var renderShapeToContext, renderShapeToSVG, slice, util, + slice1 = [].slice; + +slice = Array.prototype.slice; + +renderShapeToContext = require('./canvasRenderer').renderShapeToContext; + +renderShapeToSVG = require('./svgRenderer').renderShapeToSVG; + +util = { + addImageOnload: function(img, fn) { + var oldOnload; + oldOnload = img.onload; + img.onload = function() { + if (typeof oldOnload === "function") { + oldOnload(); + } + return fn(); + }; + return img; + }, + last: function(array, n) { + if (n == null) { + n = null; + } + if (n) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }, + classSet: function(classNameToIsPresent) { + var classNames, key; + classNames = []; + for (key in classNameToIsPresent) { + if (classNameToIsPresent[key]) { + classNames.push(key); + } + } + return classNames.join(' '); + }, + matchElementSize: function(elementToMatch, elementsToResize, scale, callback) { + var resize; + if (callback == null) { + callback = function() {}; + } + resize = (function(_this) { + return function() { + var el, i, len; + for (i = 0, len = elementsToResize.length; i < len; i++) { + el = elementsToResize[i]; + el.style.width = elementToMatch.offsetWidth + "px"; + el.style.height = elementToMatch.offsetHeight + "px"; + if (el.width != null) { + el.setAttribute('width', el.offsetWidth * scale); + el.setAttribute('height', el.offsetHeight * scale); + } + } + return callback(); + }; + })(this); + elementToMatch.addEventListener('resize', resize); + window.addEventListener('resize', resize); + window.addEventListener('orientationchange', resize); + return resize(); + }, + combineCanvases: function() { + var c, canvas, canvases, ctx, i, j, len, len1; + canvases = 1 <= arguments.length ? slice1.call(arguments, 0) : []; + c = document.createElement('canvas'); + c.width = canvases[0].width; + c.height = canvases[0].height; + for (i = 0, len = canvases.length; i < len; i++) { + canvas = canvases[i]; + c.width = Math.max(canvas.width, c.width); + c.height = Math.max(canvas.height, c.height); + } + ctx = c.getContext('2d'); + for (j = 0, len1 = canvases.length; j < len1; j++) { + canvas = canvases[j]; + ctx.drawImage(canvas, 0, 0); + } + return c; + }, + renderShapes: function(shapes, bounds, scale, canvas) { + var ctx, i, len, shape; + if (scale == null) { + scale = 1; + } + if (canvas == null) { + canvas = null; + } + canvas = canvas || document.createElement('canvas'); + canvas.width = bounds.width * scale; + canvas.height = bounds.height * scale; + ctx = canvas.getContext('2d'); + ctx.translate(-bounds.x * scale, -bounds.y * scale); + ctx.scale(scale, scale); + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + renderShapeToContext(ctx, shape); + } + return canvas; + }, + renderShapesToSVG: function(shapes, arg, backgroundColor) { + var height, width, x, y; + x = arg.x, y = arg.y, width = arg.width, height = arg.height; + return (" " + (shapes.map(renderShapeToSVG).join('')) + " ").replace(/(\r\n|\n|\r)/gm, ""); + }, + getBoundingRect: function(rects, width, height) { + var i, len, maxX, maxY, minX, minY, rect; + if (!rects.length) { + return { + x: 0, + y: 0, + width: 0 || width, + height: 0 || height + }; + } + minX = rects[0].x; + minY = rects[0].y; + maxX = rects[0].x + rects[0].width; + maxY = rects[0].y + rects[0].height; + for (i = 0, len = rects.length; i < len; i++) { + rect = rects[i]; + minX = Math.floor(Math.min(rect.x, minX)); + minY = Math.floor(Math.min(rect.y, minY)); + maxX = Math.ceil(Math.max(maxX, rect.x + rect.width)); + maxY = Math.ceil(Math.max(maxY, rect.y + rect.height)); + } + minX = width ? 0 : minX; + minY = height ? 0 : minY; + maxX = width || maxX; + maxY = height || maxY; + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY + }; + }, + getDefaultImageRect: function(shapeBoundingRects, explicitSize, margin) { + var height, rect, width; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + width = explicitSize.width, height = explicitSize.height; + rect = util.getBoundingRect(shapeBoundingRects, width === 'infinite' ? 0 : width, height === 'infinite' ? 0 : height); + rect.x -= margin.left; + rect.y -= margin.top; + rect.width += margin.left + margin.right; + rect.height += margin.top + margin.bottom; + return rect; + }, + getBackingScale: function(context) { + if (window.devicePixelRatio == null) { + return 1; + } + if (!(window.devicePixelRatio > 1)) { + return 1; + } + return window.devicePixelRatio; + }, + requestAnimationFrame: (window.requestAnimationFrame || window.setTimeout).bind(window), + getGUID: (function() { + var s4; + s4 = function() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); + }; + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + }; + })(), + requestAnimationFrame: function(f) { + if (window.webkitRequestAnimationFrame) { + return window.webkitRequestAnimationFrame(f); + } + if (window.requestAnimationFrame) { + return window.requestAnimationFrame(f); + } + if (window.mozRequestAnimationFrame) { + return window.mozRequestAnimationFrame(f); + } + return setTimeout(f, 0); + }, + cancelAnimationFrame: function(f) { + if (window.webkitCancelRequestAnimationFrame) { + return window.webkitCancelRequestAnimationFrame(f); + } + if (window.webkitCancelAnimationFrame) { + return window.webkitCancelAnimationFrame(f); + } + if (window.cancelAnimationFrame) { + return window.cancelAnimationFrame(f); + } + if (window.mozCancelAnimationFrame) { + return window.mozCancelAnimationFrame(f); + } + return clearTimeout(f); + } +}; + +module.exports = util; diff --git a/library/js/literallycanvas/js/ie_customevent.js b/library/js/literallycanvas/js/ie_customevent.js new file mode 100644 index 00000000000..8cf1bc1b232 --- /dev/null +++ b/library/js/literallycanvas/js/ie_customevent.js @@ -0,0 +1,14 @@ +'use strict'; + +(function () { + function CustomEvent(event, params) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + }; + + CustomEvent.prototype = window.CustomEvent.prototype; + + window.CustomEvent = CustomEvent; +})(); \ No newline at end of file diff --git a/library/js/literallycanvas/js/ie_setLineDash.js b/library/js/literallycanvas/js/ie_setLineDash.js new file mode 100644 index 00000000000..60a5806e27e --- /dev/null +++ b/library/js/literallycanvas/js/ie_setLineDash.js @@ -0,0 +1,13 @@ +"use strict"; + +var hasWarned = false; +if (!CanvasRenderingContext2D.prototype.setLineDash) { + CanvasRenderingContext2D.prototype.setLineDash = function () { + // no-op + if (!hasWarned) { + console.warn("context2D.setLineDash is a no-op in this browser."); + hasWarned = true; + } + }; +} +module.exports = null; \ No newline at end of file diff --git a/library/js/literallycanvas/js/index.js b/library/js/literallycanvas/js/index.js new file mode 100644 index 00000000000..815b119f323 --- /dev/null +++ b/library/js/literallycanvas/js/index.js @@ -0,0 +1,178 @@ +var LiterallyCanvasModel, LiterallyCanvasReactComponent, baseTools, canvasRenderer, conversion, defaultImageURLPrefix, defaultOptions, defaultTools, defineOptionsStyle, init, initReactDOM, initWithoutGUI, localize, registerJQueryPlugin, renderSnapshotToImage, renderSnapshotToSVG, setDefaultImageURLPrefix, shapes, svgRenderer, tools, util; + +require('./ie_customevent'); + +require('./ie_setLineDash'); + +LiterallyCanvasModel = require('./core/LiterallyCanvas'); + +defaultOptions = require('./core/defaultOptions'); + +canvasRenderer = require('./core/canvasRenderer'); + +svgRenderer = require('./core/svgRenderer'); + +shapes = require('./core/shapes'); + +util = require('./core/util'); + +renderSnapshotToImage = require('./core/renderSnapshotToImage'); + +renderSnapshotToSVG = require('./core/renderSnapshotToSVG'); + +localize = require('./core/localization').localize; + +LiterallyCanvasReactComponent = require('./reactGUI/LiterallyCanvas'); + +initReactDOM = require('./reactGUI/initDOM'); + +require('./optionsStyles/font'); + +require('./optionsStyles/stroke-width'); + +require('./optionsStyles/line-options-and-stroke-width'); + +require('./optionsStyles/polygon-and-stroke-width'); + +require('./optionsStyles/stroke-or-fill'); + +require('./optionsStyles/null'); + +defineOptionsStyle = require('./optionsStyles/optionsStyles').defineOptionsStyle; + +conversion = { + snapshotToShapes: function(snapshot) { + var i, len, ref, results, shape; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + results.push(shapes.JSONToShape(shape)); + } + return results; + }, + snapshotJSONToShapes: function(json) { + return conversion.snapshotToShapes(JSON.parse(json)); + } +}; + +baseTools = require('./tools/base'); + +tools = { + Pencil: require('./tools/Pencil'), + Eraser: require('./tools/Eraser'), + Line: require('./tools/Line'), + Rectangle: require('./tools/Rectangle'), + Ellipse: require('./tools/Ellipse'), + Text: require('./tools/Text'), + Polygon: require('./tools/Polygon'), + Pan: require('./tools/Pan'), + Eyedropper: require('./tools/Eyedropper'), + SelectShape: require('./tools/SelectShape'), + Tool: baseTools.Tool, + ToolWithStroke: baseTools.ToolWithStroke +}; + +defaultTools = defaultOptions.tools; + +defaultImageURLPrefix = defaultOptions.imageURLPrefix; + +setDefaultImageURLPrefix = function(newDefault) { + defaultImageURLPrefix = newDefault; + return defaultOptions.imageURLPrefix = newDefault; +}; + +init = function(el, opts) { + var child, i, len, opt, ref; + if (opts == null) { + opts = {}; + } + for (opt in defaultOptions) { + if (!(opt in opts)) { + opts[opt] = defaultOptions[opt]; + } + } + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return require('./reactGUI/initDOM')(el, opts); +}; + +initWithoutGUI = function(el, opts) { + var drawingViewElement, lc, originalClassName; + originalClassName = el.className; + if ([' ', ' '].join(el.className).indexOf(' literally ') === -1) { + el.className = el.className + ' literally'; + } + el.className = el.className + ' toolbar-hidden'; + drawingViewElement = document.createElement('div'); + drawingViewElement.className = 'lc-drawing'; + el.appendChild(drawingViewElement); + lc = new LiterallyCanvasModel(drawingViewElement, opts); + lc.teardown = function() { + var child, i, len, ref; + lc._teardown(); + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return el.className = originalClassName; + }; + if ('onInit' in opts) { + opts.onInit(lc); + } + return lc; +}; + +registerJQueryPlugin = function(_$) { + return _$.fn.literallycanvas = function(opts) { + if (opts == null) { + opts = {}; + } + this.each((function(_this) { + return function(ix, el) { + return el.literallycanvas = init(el, opts); + }; + })(this)); + return this; + }; +}; + +if (typeof window !== 'undefined') { + window.LC = { + init: init + }; + if (window.$) { + registerJQueryPlugin(window.$); + } +} + +module.exports = { + init: init, + registerJQueryPlugin: registerJQueryPlugin, + util: util, + tools: tools, + setDefaultImageURLPrefix: setDefaultImageURLPrefix, + defaultTools: defaultTools, + defineOptionsStyle: defineOptionsStyle, + LiterallyCanvasReactComponent: LiterallyCanvasReactComponent, + defineShape: shapes.defineShape, + createShape: shapes.createShape, + JSONToShape: shapes.JSONToShape, + shapeToJSON: shapes.shapeToJSON, + defineCanvasRenderer: canvasRenderer.defineCanvasRenderer, + renderShapeToContext: canvasRenderer.renderShapeToContext, + renderShapeToCanvas: canvasRenderer.renderShapeToCanvas, + renderShapesToCanvas: util.renderShapes, + defineSVGRenderer: svgRenderer.defineSVGRenderer, + renderShapeToSVG: svgRenderer.renderShapeToSVG, + renderShapesToSVG: util.renderShapesToSVG, + snapshotToShapes: conversion.snapshotToShapes, + snapshotJSONToShapes: conversion.snapshotJSONToShapes, + renderSnapshotToImage: renderSnapshotToImage, + renderSnapshotToSVG: renderSnapshotToSVG, + localize: localize +}; diff --git a/library/js/literallycanvas/js/literallycanvas-core.js b/library/js/literallycanvas/js/literallycanvas-core.js new file mode 100644 index 00000000000..00696bded5b --- /dev/null +++ b/library/js/literallycanvas/js/literallycanvas-core.js @@ -0,0 +1,4745 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.LC = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o this.width * renderScale) { + x = (this.canvas.width - this.width * renderScale) / 2; + } else { + x = Math.max(Math.min(0, x), this.canvas.width - this.width * renderScale); + } + } + if (this.height !== INFINITE) { + if (this.canvas.height > this.height * renderScale) { + y = (this.canvas.height - this.height * renderScale) / 2; + } else { + y = Math.max(Math.min(0, y), this.canvas.height - this.height * renderScale); + } + } + return this.position = { + x: x, + y: y + }; + }; + + LiterallyCanvas.prototype.setPan = function(x, y) { + this.position = { + x: x, + y: y + }; + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('pan', { + x: this.position.x, + y: this.position.y + }); + }; + + LiterallyCanvas.prototype.zoom = function(factor) { + var newScale; + newScale = this.scale + factor; + newScale = Math.max(newScale, this.config.zoomMin); + newScale = Math.min(newScale, this.config.zoomMax); + newScale = Math.round(newScale * 100) / 100; + return this.setZoom(newScale); + }; + + LiterallyCanvas.prototype.setZoom = function(scale) { + var oldScale; + oldScale = this.scale; + this.scale = scale; + this.position.x = math.scalePositionScalar(this.position.x, this.canvas.width, oldScale, this.scale); + this.position.y = math.scalePositionScalar(this.position.y, this.canvas.height, oldScale, this.scale); + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('zoom', { + oldScale: oldScale, + newScale: this.scale + }); + }; + + LiterallyCanvas.prototype.setWatermarkImage = function(newImage) { + this.watermarkImage = newImage; + util.addImageOnload(newImage, (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this)); + if (newImage.width) { + return this.repaintLayer('background'); + } + }; + + LiterallyCanvas.prototype.repaintAllLayers = function() { + var i, key, len, ref1; + ref1 = ['background', 'main']; + for (i = 0, len = ref1.length; i < len; i++) { + key = ref1[i]; + this.repaintLayer(key); + } + return null; + }; + + LiterallyCanvas.prototype.repaintLayer = function(repaintLayerKey, dirty) { + var retryCallback; + if (dirty == null) { + dirty = repaintLayerKey === 'main'; + } + if (!this.isBound) { + return; + } + switch (repaintLayerKey) { + case 'background': + this.backgroundCtx.clearRect(0, 0, this.backgroundCanvas.width, this.backgroundCanvas.height); + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this); + if (this.watermarkImage) { + this._renderWatermark(this.backgroundCtx, true, retryCallback); + } + this.draw(this.backgroundShapes, this.backgroundCtx, retryCallback); + break; + case 'main': + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('main', true); + }; + })(this); + if (dirty) { + this.buffer.width = this.canvas.width; + this.buffer.height = this.canvas.height; + this.bufferCtx.clearRect(0, 0, this.buffer.width, this.buffer.height); + this.draw(this.shapes, this.bufferCtx, retryCallback); + } + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + if (this.canvas.width > 0 && this.canvas.height > 0) { + this.ctx.fillStyle = '#ccc'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.clipped(((function(_this) { + return function() { + _this.ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height); + return _this.ctx.drawImage(_this.buffer, 0, 0); + }; + })(this)), this.ctx); + this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + var i, len, ref1, results, shape; + ref1 = _this._shapesInProgress; + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + shape = ref1[i]; + results.push(renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + })); + } + return results; + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + } + } + return this.trigger('repaint', { + layerKey: repaintLayerKey + }); + }; + + LiterallyCanvas.prototype._renderWatermark = function(ctx, worryAboutRetina, retryCallback) { + if (worryAboutRetina == null) { + worryAboutRetina = true; + } + if (!this.watermarkImage.width) { + this.watermarkImage.onload = retryCallback; + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(this.watermarkScale, this.watermarkScale); + if (worryAboutRetina) { + ctx.scale(this.backingScale, this.backingScale); + } + ctx.drawImage(this.watermarkImage, -this.watermarkImage.width / 2, -this.watermarkImage.height / 2); + return ctx.restore(); + }; + + LiterallyCanvas.prototype.drawShapeInProgress = function(shape) { + this.repaintLayer('main', false); + return this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + return renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + }); + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + }; + + LiterallyCanvas.prototype.draw = function(shapes, ctx, retryCallback) { + var drawShapes; + if (!shapes.length) { + return; + } + drawShapes = (function(_this) { + return function() { + var i, len, results, shape; + results = []; + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + results.push(renderShapeToContext(ctx, shape, { + retryCallback: retryCallback + })); + } + return results; + }; + })(this); + return this.clipped(((function(_this) { + return function() { + return _this.transformed(drawShapes, ctx); + }; + })(this)), ctx); + }; + + LiterallyCanvas.prototype.clipped = function() { + var contexts, ctx, fn, height, i, j, len, len1, results, width, x, y; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + x = this.width === INFINITE ? 0 : this.position.x; + y = this.height === INFINITE ? 0 : this.position.y; + width = (function() { + switch (this.width) { + case INFINITE: + return this.canvas.width; + default: + return this.width * this.getRenderScale(); + } + }).call(this); + height = (function() { + switch (this.height) { + case INFINITE: + return this.canvas.height; + default: + return this.height * this.getRenderScale(); + } + }).call(this); + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.clip(); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.transformed = function() { + var contexts, ctx, fn, i, j, len, len1, results, scale; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.translate(Math.floor(this.position.x), Math.floor(this.position.y)); + scale = this.getRenderScale(); + ctx.scale(scale, scale); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.clear = function(triggerClearEvent) { + var newShapes, oldShapes; + if (triggerClearEvent == null) { + triggerClearEvent = true; + } + oldShapes = this.shapes; + newShapes = []; + this.setShapesInProgress([]); + this.execute(new actions.ClearAction(this, oldShapes, newShapes)); + this.repaintLayer('main'); + if (triggerClearEvent) { + this.trigger('clear', null); + } + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.execute = function(action) { + this.undoStack.push(action); + action["do"](); + return this.redoStack = []; + }; + + LiterallyCanvas.prototype.undo = function() { + var action; + if (!this.undoStack.length) { + return; + } + action = this.undoStack.pop(); + action.undo(); + this.redoStack.push(action); + this.trigger('undo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.redo = function() { + var action; + if (!this.redoStack.length) { + return; + } + action = this.redoStack.pop(); + this.undoStack.push(action); + action["do"](); + this.trigger('redo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.canUndo = function() { + return !!this.undoStack.length; + }; + + LiterallyCanvas.prototype.canRedo = function() { + return !!this.redoStack.length; + }; + + LiterallyCanvas.prototype.getPixel = function(x, y) { + var p, pixel; + p = this.drawingCoordsToClientCoords(x, y); + pixel = this.ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } + }; + + LiterallyCanvas.prototype.getContentBounds = function() { + return util.getBoundingRect((this.shapes.concat(this.backgroundShapes)).map(function(s) { + return s.getBoundingRect(); + }), this.width === INFINITE ? 0 : this.width, this.height === INFINITE ? 0 : this.height); + }; + + LiterallyCanvas.prototype.getDefaultImageRect = function(explicitSize, margin) { + var s; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + return util.getDefaultImageRect((function() { + var i, len, ref1, results; + ref1 = this.shapes.concat(this.backgroundShapes); + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + s = ref1[i]; + results.push(s.getBoundingRect(this.ctx)); + } + return results; + }).call(this), explicitSize, margin); + }; + + LiterallyCanvas.prototype.getImage = function(opts) { + if (opts == null) { + opts = {}; + } + if (opts.includeWatermark == null) { + opts.includeWatermark = true; + } + if (opts.scaleDownRetina == null) { + opts.scaleDownRetina = true; + } + if (opts.scale == null) { + opts.scale = 1; + } + if (!opts.scaleDownRetina) { + opts.scale *= this.backingScale; + } + if (opts.includeWatermark) { + opts.watermarkImage = this.watermarkImage; + opts.watermarkScale = this.watermarkScale; + if (!opts.scaleDownRetina) { + opts.watermarkScale *= this.backingScale; + } + } + return renderSnapshotToImage(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.canvasForExport = function() { + this.repaintAllLayers(); + return util.combineCanvases(this.backgroundCanvas, this.canvas); + }; + + LiterallyCanvas.prototype.canvasWithBackground = function(backgroundImageOrCanvas) { + return util.combineCanvases(backgroundImageOrCanvas, this.canvasForExport()); + }; + + LiterallyCanvas.prototype.getSnapshot = function(keys) { + var i, k, len, ref1, shape, snapshot; + if (keys == null) { + keys = null; + } + if (keys == null) { + keys = ['shapes', 'imageSize', 'colors', 'position', 'scale', 'backgroundShapes']; + } + snapshot = {}; + ref1 = ['colors', 'position', 'scale']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + if (indexOf.call(keys, k) >= 0) { + snapshot[k] = this[k]; + } + } + if (indexOf.call(keys, 'shapes') >= 0) { + snapshot.shapes = (function() { + var j, len1, ref2, results; + ref2 = this.shapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'backgroundShapes') >= 0) { + snapshot.backgroundShapes = (function() { + var j, len1, ref2, results; + ref2 = this.backgroundShapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'imageSize') >= 0) { + snapshot.imageSize = { + width: this.width, + height: this.height + }; + } + return snapshot; + }; + + LiterallyCanvas.prototype.getSnapshotJSON = function() { + console.warn("lc.getSnapshotJSON() is deprecated. use JSON.stringify(lc.getSnapshot()) instead."); + return JSON.stringify(this.getSnapshot()); + }; + + LiterallyCanvas.prototype.getSVGString = function(opts) { + if (opts == null) { + opts = {}; + } + return renderSnapshotToSVG(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.loadSnapshot = function(snapshot) { + var i, j, k, len, len1, ref1, ref2, s, shape, shapeRepr; + if (!snapshot) { + return; + } + if (snapshot.colors) { + ref1 = ['primary', 'secondary', 'background']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + this.setColor(k, snapshot.colors[k]); + } + } + if (snapshot.shapes) { + this.shapes = []; + ref2 = snapshot.shapes; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shapeRepr = ref2[j]; + shape = JSONToShape(shapeRepr); + if (shape) { + this.execute(new actions.AddShapeAction(this, shape)); + } + } + } + if (snapshot.backgroundShapes) { + this.backgroundShapes = (function() { + var l, len2, ref3, results; + ref3 = snapshot.backgroundShapes; + results = []; + for (l = 0, len2 = ref3.length; l < len2; l++) { + s = ref3[l]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (snapshot.imageSize) { + this.width = snapshot.imageSize.width; + this.height = snapshot.imageSize.height; + } + if (snapshot.position) { + this.position = snapshot.position; + } + if (snapshot.scale) { + this.scale = snapshot.scale; + } + this.repaintAllLayers(); + this.trigger('snapshotLoad'); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.loadSnapshotJSON = function(str) { + console.warn("lc.loadSnapshotJSON() is deprecated. use lc.loadSnapshot(JSON.parse(snapshot)) instead."); + return this.loadSnapshot(JSON.parse(str)); + }; + + return LiterallyCanvas; + +})(); + + +},{"../tools/Pencil":24,"./actions":3,"./bindEvents":4,"./canvasRenderer":5,"./math":10,"./renderSnapshotToImage":11,"./renderSnapshotToSVG":12,"./shapes":13,"./svgRenderer":14,"./util":15}],2:[function(require,module,exports){ +var TextRenderer, getLinesToRender, getNextLine, parseFontString; + +require('./fontmetrics.js'); + +parseFontString = function(font) { + var fontFamily, fontItems, fontSize, item, j, len, maybeSize, remainingFontString; + fontItems = font.split(' '); + fontSize = 0; + for (j = 0, len = fontItems.length; j < len; j++) { + item = fontItems[j]; + maybeSize = parseInt(item.replace("px", ""), 10); + if (!isNaN(maybeSize)) { + fontSize = maybeSize; + } + } + if (!fontSize) { + throw "Font size not found"; + } + remainingFontString = font.substring(fontItems[0].length + 1).replace('bold ', '').replace('italic ', '').replace('underline ', ''); + fontFamily = remainingFontString; + return { + fontSize: fontSize, + fontFamily: fontFamily + }; +}; + +getNextLine = function(ctx, text, forcedWidth) { + var doesSubstringFit, endIndex, isEndOfString, isNonWord, isWhitespace, lastGoodIndex, lastOkayIndex, nextWordStartIndex, textToHere, wasInWord; + if (!text.length) { + return ['', '']; + } + endIndex = 0; + lastGoodIndex = 0; + lastOkayIndex = 0; + wasInWord = false; + while (true) { + endIndex += 1; + isEndOfString = endIndex >= text.length; + isWhitespace = (!isEndOfString) && text[endIndex].match(/\s/); + isNonWord = isWhitespace || isEndOfString; + textToHere = text.substring(0, endIndex); + doesSubstringFit = forcedWidth ? ctx.measureTextWidth(textToHere).width <= forcedWidth : true; + if (doesSubstringFit) { + lastOkayIndex = endIndex; + } + if (isNonWord && wasInWord) { + wasInWord = false; + if (doesSubstringFit) { + lastGoodIndex = endIndex; + } + } + wasInWord = !isWhitespace; + if (isEndOfString || !doesSubstringFit) { + if (doesSubstringFit) { + return [text, '']; + } else if (lastGoodIndex > 0) { + nextWordStartIndex = lastGoodIndex + 1; + while (nextWordStartIndex < text.length && text[nextWordStartIndex].match('/\s/')) { + nextWordStartIndex += 1; + } + return [text.substring(0, lastGoodIndex), text.substring(nextWordStartIndex)]; + } else { + return [text.substring(0, lastOkayIndex), text.substring(lastOkayIndex)]; + } + } + } +}; + +getLinesToRender = function(ctx, text, forcedWidth) { + var j, len, lines, nextLine, ref, ref1, remainingText, textLine, textSplitOnLines; + textSplitOnLines = text.split(/\r\n|\r|\n/g); + lines = []; + for (j = 0, len = textSplitOnLines.length; j < len; j++) { + textLine = textSplitOnLines[j]; + ref = getNextLine(ctx, textLine, forcedWidth), nextLine = ref[0], remainingText = ref[1]; + if (nextLine) { + while (nextLine) { + lines.push(nextLine); + ref1 = getNextLine(ctx, remainingText, forcedWidth), nextLine = ref1[0], remainingText = ref1[1]; + } + } else { + lines.push(textLine); + } + } + return lines; +}; + +TextRenderer = (function() { + function TextRenderer(ctx, text1, font1, forcedWidth1, forcedHeight) { + var fontFamily, fontSize, ref; + this.text = text1; + this.font = font1; + this.forcedWidth = forcedWidth1; + this.forcedHeight = forcedHeight; + ref = parseFontString(this.font), fontFamily = ref.fontFamily, fontSize = ref.fontSize; + ctx.font = this.font; + ctx.textBaseline = 'baseline'; + this.emDashWidth = ctx.measureTextWidth('—', fontSize, fontFamily).width; + this.caratWidth = ctx.measureTextWidth('|', fontSize, fontFamily).width; + this.lines = getLinesToRender(ctx, this.text, this.forcedWidth); + this.metricses = this.lines.map((function(_this) { + return function(line) { + return ctx.measureText2(line || 'X', fontSize, _this.font); + }; + })(this)); + this.metrics = { + ascent: Math.max.apply(Math, this.metricses.map(function(arg) { + var ascent; + ascent = arg.ascent; + return ascent; + })), + descent: Math.max.apply(Math, this.metricses.map(function(arg) { + var descent; + descent = arg.descent; + return descent; + })), + fontsize: Math.max.apply(Math, this.metricses.map(function(arg) { + var fontsize; + fontsize = arg.fontsize; + return fontsize; + })), + leading: Math.max.apply(Math, this.metricses.map(function(arg) { + var leading; + leading = arg.leading; + return leading; + })), + width: Math.max.apply(Math, this.metricses.map(function(arg) { + var width; + width = arg.width; + return width; + })), + height: Math.max.apply(Math, this.metricses.map(function(arg) { + var height; + height = arg.height; + return height; + })), + bounds: { + minx: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.minx; + })), + miny: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.miny; + })), + maxx: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxx; + })), + maxy: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxy; + })) + } + }; + this.boundingBoxWidth = Math.ceil(this.metrics.width); + } + + TextRenderer.prototype.draw = function(ctx, x, y) { + var i, j, len, line, ref, results; + ctx.textBaseline = 'top'; + ctx.font = this.font; + i = 0; + ref = this.lines; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + line = ref[j]; + ctx.fillText(line, x, y + i * this.metrics.leading); + results.push(i += 1); + } + return results; + }; + + TextRenderer.prototype.getWidth = function(isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (this.forcedWidth) { + return this.forcedWidth; + } else { + if (isEditing) { + return this.metrics.bounds.maxx + this.caratWidth; + } else { + return this.metrics.bounds.maxx; + } + } + }; + + TextRenderer.prototype.getHeight = function() { + return this.forcedHeight || (this.metrics.leading * this.lines.length); + }; + + return TextRenderer; + +})(); + +module.exports = TextRenderer; + + +},{"./fontmetrics.js":7}],3:[function(require,module,exports){ +var AddShapeAction, ClearAction; + +ClearAction = (function() { + function ClearAction(lc1, oldShapes, newShapes1) { + this.lc = lc1; + this.oldShapes = oldShapes; + this.newShapes = newShapes1; + } + + ClearAction.prototype["do"] = function() { + this.lc.shapes = this.newShapes; + return this.lc.repaintLayer('main'); + }; + + ClearAction.prototype.undo = function() { + this.lc.shapes = this.oldShapes; + return this.lc.repaintLayer('main'); + }; + + return ClearAction; + +})(); + +AddShapeAction = (function() { + function AddShapeAction(lc1, shape1, previousShapeId) { + this.lc = lc1; + this.shape = shape1; + this.previousShapeId = previousShapeId != null ? previousShapeId : null; + } + + AddShapeAction.prototype["do"] = function() { + var found, i, len, newShapes, ref, shape; + if (!this.lc.shapes.length || this.lc.shapes[this.lc.shapes.length - 1].id === this.previousShapeId || this.previousShapeId === null) { + this.lc.shapes.push(this.shape); + } else { + newShapes = []; + found = false; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + newShapes.push(shape); + if (shape.id === this.previousShapeId) { + newShapes.push(this.shape); + found = true; + } + } + if (!found) { + newShapes.push(this.shape); + } + this.lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + AddShapeAction.prototype.undo = function() { + var i, len, newShapes, ref, shape; + if (this.lc.shapes[this.lc.shapes.length - 1].id === this.shape.id) { + this.lc.shapes.pop(); + } else { + newShapes = []; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + if (shape.id !== this.shape.id) { + newShapes.push(shape); + } + } + lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + return AddShapeAction; + +})(); + +module.exports = { + ClearAction: ClearAction, + AddShapeAction: AddShapeAction +}; + + +},{}],4:[function(require,module,exports){ +var bindEvents, buttonIsDown, coordsForTouchEvent, position; + +coordsForTouchEvent = function(el, e) { + var p, tx, ty; + tx = e.changedTouches[0].clientX; + ty = e.changedTouches[0].clientY; + p = el.getBoundingClientRect(); + return [tx - p.left, ty - p.top]; +}; + +position = function(el, e) { + var p; + p = el.getBoundingClientRect(); + return { + left: e.clientX - p.left, + top: e.clientY - p.top + }; +}; + +buttonIsDown = function(e) { + if (e.buttons != null) { + return e.buttons === 1; + } else { + return e.which > 0; + } +}; + +module.exports = bindEvents = function(lc, canvas, panWithKeyboard) { + var listener, mouseMoveListener, mouseUpListener, touchEndListener, touchMoveListener, unsubs; + if (panWithKeyboard == null) { + panWithKeyboard = false; + } + unsubs = []; + mouseMoveListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + p = position(canvas, e); + return lc.pointerMove(p.left, p.top); + }; + })(this); + mouseUpListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + canvas.onselectstart = function() { + return true; + }; + p = position(canvas, e); + lc.pointerUp(p.left, p.top); + document.removeEventListener('mousemove', mouseMoveListener); + document.removeEventListener('mouseup', mouseUpListener); + return canvas.addEventListener('mousemove', mouseMoveListener); + }; + })(this); + canvas.addEventListener('mousedown', (function(_this) { + return function(e) { + var down, p; + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + down = true; + e.preventDefault(); + canvas.onselectstart = function() { + return false; + }; + p = position(canvas, e); + lc.pointerDown(p.left, p.top); + canvas.removeEventListener('mousemove', mouseMoveListener); + document.addEventListener('mousemove', mouseMoveListener); + return document.addEventListener('mouseup', mouseUpListener); + }; + })(this)); + touchMoveListener = function(e) { + e.preventDefault(); + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + }; + touchEndListener = function(e) { + e.preventDefault(); + lc.pointerUp.apply(lc, coordsForTouchEvent(canvas, e)); + document.removeEventListener('touchmove', touchMoveListener); + document.removeEventListener('touchend', touchEndListener); + return document.removeEventListener('touchcancel', touchEndListener); + }; + canvas.addEventListener('touchstart', function(e) { + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + e.preventDefault(); + if (e.touches.length === 1) { + lc.pointerDown.apply(lc, coordsForTouchEvent(canvas, e)); + document.addEventListener('touchmove', touchMoveListener); + document.addEventListener('touchend', touchEndListener); + return document.addEventListener('touchcancel', touchEndListener); + } else { + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + } + }); + if (panWithKeyboard) { + console.warn("Keyboard panning is deprecated."); + listener = function(e) { + switch (e.keyCode) { + case 37: + lc.pan(-10, 0); + break; + case 38: + lc.pan(0, -10); + break; + case 39: + lc.pan(10, 0); + break; + case 40: + lc.pan(0, 10); + } + return lc.repaintAllLayers(); + }; + document.addEventListener('keydown', listener); + unsubs.push(function() { + return document.removeEventListener(listener); + }); + } + return function() { + var f, i, len, results; + results = []; + for (i = 0, len = unsubs.length; i < len; i++) { + f = unsubs[i]; + results.push(f()); + } + return results; + }; +}; + + +},{}],5:[function(require,module,exports){ +var _drawRawLinePath, defineCanvasRenderer, drawErasedLinePath, drawErasedLinePathLatest, drawLinePath, drawLinePathLatest, lineEndCapShapes, noop, renderShapeToCanvas, renderShapeToContext, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineCanvasRenderer = function(shapeName, drawFunc, drawLatestFunc) { + return renderers[shapeName] = { + drawFunc: drawFunc, + drawLatestFunc: drawLatestFunc + }; +}; + +noop = function() {}; + +renderShapeToContext = function(ctx, shape, opts) { + var bufferCtx; + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (opts.retryCallback == null) { + opts.retryCallback = noop; + } + if (opts.shouldOnlyDrawLatest == null) { + opts.shouldOnlyDrawLatest = false; + } + if (opts.bufferCtx == null) { + opts.bufferCtx = null; + } + bufferCtx = opts.bufferCtx; + if (renderers[shape.className]) { + if (opts.shouldOnlyDrawLatest && renderers[shape.className].drawLatestFunc) { + return renderers[shape.className].drawLatestFunc(ctx, bufferCtx, shape, opts.retryCallback); + } else { + return renderers[shape.className].drawFunc(ctx, shape, opts.retryCallback); + } + } else if (opts.shouldIgnoreUnsupportedShapes) { + return console.warn("Can't render shape of type " + shape.className + " to canvas"); + } else { + throw "Can't render shape of type " + shape.className + " to canvas"; + } +}; + +renderShapeToCanvas = function(canvas, shape, opts) { + return renderShapeToContext(canvas.getContext('2d'), shape, opts); +}; + +defineCanvasRenderer('Rectangle', function(ctx, shape) { + var x, y; + x = shape.x; + y = shape.y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + ctx.fillStyle = shape.fillColor; + ctx.fillRect(x, y, shape.width, shape.height); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.strokeRect(x, y, shape.width, shape.height); +}); + +defineCanvasRenderer('Ellipse', function(ctx, shape) { + var centerX, centerY, halfHeight, halfWidth; + ctx.save(); + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + ctx.translate(centerX, centerY); + ctx.scale(1, Math.abs(shape.height / shape.width)); + ctx.beginPath(); + ctx.arc(0, 0, Math.abs(halfWidth), 0, Math.PI * 2); + ctx.closePath(); + ctx.restore(); + ctx.fillStyle = shape.fillColor; + ctx.fill(); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.stroke(); +}); + +defineCanvasRenderer('SelectionBox', (function() { + var _drawHandle; + _drawHandle = function(ctx, arg, handleSize) { + var x, y; + x = arg.x, y = arg.y; + if (handleSize === 0) { + return; + } + ctx.fillStyle = '#fff'; + ctx.fillRect(x, y, handleSize, handleSize); + ctx.strokeStyle = '#000'; + return ctx.strokeRect(x, y, handleSize, handleSize); + }; + return function(ctx, shape) { + _drawHandle(ctx, shape.getTopLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getTopRightHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomRightHandleRect(), shape.handleSize); + if (shape.backgroundColor) { + ctx.fillStyle = shape.backgroundColor; + ctx.fillRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + } + ctx.lineWidth = 1; + ctx.strokeStyle = '#000'; + ctx.setLineDash([2, 4]); + ctx.strokeRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + return ctx.setLineDash([]); + }; +})()); + +defineCanvasRenderer('Image', function(ctx, shape, retryCallback) { + if (shape.image.width) { + if (shape.scale === 1) { + return ctx.drawImage(shape.image, shape.x, shape.y); + } else { + return ctx.drawImage(shape.image, shape.x, shape.y, shape.image.width * shape.scale, shape.image.height * shape.scale); + } + } else if (retryCallback) { + return shape.image.onload = retryCallback; + } +}); + +defineCanvasRenderer('Line', function(ctx, shape) { + var arrowWidth, x1, x2, y1, y2; + if (shape.x1 === shape.x2 && shape.y1 === shape.y2) { + return; + } + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.color; + ctx.lineCap = shape.capStyle; + if (shape.dash) { + ctx.setLineDash(shape.dash); + } + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + if (shape.dash) { + ctx.setLineDash([]); + } + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + if (shape.endCapShapes[0]) { + lineEndCapShapes[shape.endCapShapes[0]].drawToCanvas(ctx, x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + return lineEndCapShapes[shape.endCapShapes[1]].drawToCanvas(ctx, x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } +}); + +_drawRawLinePath = function(ctx, points, close, lineCap) { + var i, len, point, ref; + if (close == null) { + close = false; + } + if (lineCap == null) { + lineCap = 'round'; + } + if (!points.length) { + return; + } + ctx.lineCap = lineCap; + ctx.strokeStyle = points[0].color; + ctx.lineWidth = points[0].size; + ctx.beginPath(); + if (points[0].size % 2 === 0) { + ctx.moveTo(points[0].x, points[0].y); + } else { + ctx.moveTo(points[0].x + 0.5, points[0].y + 0.5); + } + ref = points.slice(1); + for (i = 0, len = ref.length; i < len; i++) { + point = ref[i]; + if (points[0].size % 2 === 0) { + ctx.lineTo(point.x, point.y); + } else { + ctx.lineTo(point.x + 0.5, point.y + 0.5); + } + } + if (close) { + return ctx.closePath(); + } +}; + +drawLinePath = function(ctx, shape) { + _drawRawLinePath(ctx, shape.smoothedPoints); + return ctx.stroke(); +}; + +drawLinePathLatest = function(ctx, bufferCtx, shape) { + var drawEnd, drawStart, segmentStart; + if (shape.tail) { + segmentStart = shape.smoothedPoints.length - shape.segmentSize * shape.tailSize; + drawStart = segmentStart < shape.segmentSize * 2 ? 0 : segmentStart; + drawEnd = segmentStart + shape.segmentSize + 1; + _drawRawLinePath(bufferCtx, shape.smoothedPoints.slice(drawStart, drawEnd)); + return bufferCtx.stroke(); + } else { + _drawRawLinePath(bufferCtx, shape.smoothedPoints); + return bufferCtx.stroke(); + } +}; + +defineCanvasRenderer('LinePath', drawLinePath, drawLinePathLatest); + +drawErasedLinePath = function(ctx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + drawLinePath(ctx, shape); + return ctx.restore(); +}; + +drawErasedLinePathLatest = function(ctx, bufferCtx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + bufferCtx.save(); + bufferCtx.globalCompositeOperation = "destination-out"; + drawLinePathLatest(ctx, bufferCtx, shape); + ctx.restore(); + return bufferCtx.restore(); +}; + +defineCanvasRenderer('ErasedLinePath', drawErasedLinePath, drawErasedLinePathLatest); + +defineCanvasRenderer('Text', function(ctx, shape) { + if (!shape.renderer) { + shape._makeRenderer(ctx); + } + ctx.fillStyle = shape.color; + return shape.renderer.draw(ctx, shape.x, shape.y); +}); + +defineCanvasRenderer('Polygon', function(ctx, shape) { + ctx.fillStyle = shape.fillColor; + _drawRawLinePath(ctx, shape.points, shape.isClosed, 'butt'); + ctx.fill(); + return ctx.stroke(); +}); + +module.exports = { + defineCanvasRenderer: defineCanvasRenderer, + renderShapeToCanvas: renderShapeToCanvas, + renderShapeToContext: renderShapeToContext +}; + + +},{"./lineEndCapShapes":8}],6:[function(require,module,exports){ +'use strict'; + +module.exports = { + imageURLPrefix: 'lib/img', + primaryColor: 'hsla(0, 0%, 0%, 1)', + secondaryColor: 'hsla(0, 0%, 100%, 1)', + backgroundColor: 'transparent', + strokeWidths: [1, 2, 5, 10, 20, 30], + defaultStrokeWidth: 5, + toolbarPosition: 'top', + keyboardShortcuts: false, + imageSize: { width: 'infinite', height: 'infinite' }, + backgroundShapes: [], + watermarkImage: null, + watermarkScale: 1, + zoomMin: 0.2, + zoomMax: 4.0, + zoomStep: 0.2, + snapshot: null, + tools: [require('../tools/Pencil'), require('../tools/Eraser'), require('../tools/Line'), require('../tools/Rectangle'), require('../tools/Ellipse'), require('../tools/Text'), require('../tools/Polygon'), require('../tools/Pan'), require('../tools/Eyedropper')] +}; + +},{"../tools/Ellipse":19,"../tools/Eraser":20,"../tools/Eyedropper":21,"../tools/Line":22,"../tools/Pan":23,"../tools/Pencil":24,"../tools/Polygon":25,"../tools/Rectangle":26,"../tools/Text":28}],7:[function(require,module,exports){ +"use strict"; + +/** + This library rewrites the Canvas2D "measureText" function + so that it returns a more complete metrics object. + This library is licensed under the MIT (Expat) license, + the text for which is included below. + +** ----------------------------------------------------------------------------- + + CHANGELOG: + + 2012-01-21 - Whitespace handling added by Joe Turner + (https://github.com/oampo) + + 2015-06-08 - Various hacks added by Steve Johnson + +** ----------------------------------------------------------------------------- + + Copyright (C) 2011 by Mike "Pomax" Kamermans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +**/ +(function () { + var NAME = "FontMetrics Library"; + var VERSION = "1-2012.0121.1300"; + + // if there is no getComputedStyle, this library won't work. + if (!document.defaultView.getComputedStyle) { + throw "ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values."; + } + + // store the old text metrics function on the Canvas2D prototype + CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText; + + /** + * shortcut function for getting computed CSS values + */ + var getCSSValue = function getCSSValue(element, property) { + return document.defaultView.getComputedStyle(element, null).getPropertyValue(property); + }; + + // debug function + var show = function show(canvas, ctx, xstart, w, h, metrics) { + document.body.appendChild(canvas); + ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; + + ctx.beginPath(); + ctx.moveTo(xstart, 0); + ctx.lineTo(xstart, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(xstart + metrics.bounds.maxx, 0); + ctx.lineTo(xstart + metrics.bounds.maxx, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 - metrics.ascent); + ctx.lineTo(w, h / 2 - metrics.ascent); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 + metrics.descent); + ctx.lineTo(w, h / 2 + metrics.descent); + ctx.closePath(); + ctx.stroke(); + }; + + /** + * The new text metrics function + */ + CanvasRenderingContext2D.prototype.measureText2 = function (textstring, fontSize, fontString) { + var metrics = this.measureTextWidth(textstring), + isSpace = !/\S/.test(textstring); + metrics.fontsize = fontSize; + + // for text lead values, we meaure a multiline text container. + var leadDiv = document.createElement("div"); + leadDiv.style.position = "absolute"; + leadDiv.style.opacity = 0; + leadDiv.style.font = fontString; + leadDiv.innerHTML = textstring + "
" + textstring; + document.body.appendChild(leadDiv); + + // make some initial guess at the text leading (using the standard TeX ratio) + metrics.leading = 1.2 * fontSize; + + // then we try to get the real value from the browser + var leadDivHeight = getCSSValue(leadDiv, "height"); + leadDivHeight = leadDivHeight.replace("px", ""); + if (leadDivHeight >= fontSize * 2) { + metrics.leading = leadDivHeight / 2 | 0; + } + document.body.removeChild(leadDiv); + + // if we're not dealing with white space, we can compute metrics + if (!isSpace) { + // Have characters, so measure the text + var canvas = document.createElement("canvas"); + var padding = 100; + canvas.width = metrics.width + padding; + canvas.height = 3 * fontSize; + canvas.style.opacity = 1; + canvas.style.font = fontString; + var ctx = canvas.getContext("2d"); + ctx.font = fontString; + + var w = canvas.width, + h = canvas.height, + baseline = h / 2; + + // Set all canvas pixeldata values to 255, with all the content + // data being 0. This lets us scan for data[i] != 255. + ctx.fillStyle = "white"; + ctx.fillRect(-1, -1, w + 2, h + 2); + ctx.fillStyle = "black"; + ctx.fillText(textstring, padding / 2, baseline); + var pixelData = ctx.getImageData(0, 0, w, h).data; + + // canvas pixel data is w*4 by h*4, because R, G, B and A are separate, + // consecutive values in the array, rather than stored as 32 bit ints. + var i = 0, + w4 = w * 4, + len = pixelData.length; + + // Finding the ascent uses a normal, forward scanline + while (++i < len && pixelData[i] === 255) {} + var ascent = i / w4 | 0; + + // Finding the descent uses a reverse scanline + i = len - 1; + while (--i > 0 && pixelData[i] === 255) {} + var descent = i / w4 | 0; + + // find the min-x coordinate + for (i = 0; i < len && pixelData[i] === 255;) { + i += w4; + if (i >= len) { + i = i - len + 4; + } + } + var minx = i % w4 / 4 | 0; + + // find the max-x coordinate + var step = 1; + for (i = len - 3; i >= 0 && pixelData[i] === 255;) { + i -= w4; + if (i < 0) { + i = len - 3 - step++ * 4; + } + } + var maxx = i % w4 / 4 + 1 | 0; + + // set font metrics + metrics.ascent = baseline - ascent; + metrics.descent = descent - baseline; + metrics.bounds = { minx: minx - padding / 2, + maxx: maxx - padding / 2, + miny: 0, + maxy: descent - ascent }; + metrics.height = 1 + (descent - ascent); + } + + // if we ARE dealing with whitespace, most values will just be zero. + else { + // Only whitespace, so we can't measure the text + metrics.ascent = 0; + metrics.descent = 0; + metrics.bounds = { minx: 0, + maxx: metrics.width, // Best guess + miny: 0, + maxy: 0 }; + metrics.height = 0; + } + return metrics; + }; +})(); + +},{}],8:[function(require,module,exports){ +module.exports = { + arrow: (function() { + var getPoints; + getPoints = function(x, y, angle, width, length) { + return [ + { + x: x + Math.cos(angle + Math.PI / 2) * width / 2, + y: y + Math.sin(angle + Math.PI / 2) * width / 2 + }, { + x: x + Math.cos(angle) * length, + y: y + Math.sin(angle) * length + }, { + x: x + Math.cos(angle - Math.PI / 2) * width / 2, + y: y + Math.sin(angle - Math.PI / 2) * width / 2 + } + ]; + }; + return { + drawToCanvas: function(ctx, x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + ctx.fillStyle = color; + ctx.lineWidth = 0; + ctx.strokeStyle = 'transparent'; + ctx.beginPath(); + points = getPoints(x, y, angle, width, length); + ctx.moveTo(points[0].x, points[0].y); + ctx.lineTo(points[1].x, points[1].y); + ctx.lineTo(points[2].x, points[2].y); + return ctx.fill(); + }, + svg: function(x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + points = getPoints(x, y, angle, width, length); + return ""; + } + }; + })() +}; + + +},{}],9:[function(require,module,exports){ +var _, localize, strings; + +strings = {}; + +localize = function(localStrings) { + return strings = localStrings; +}; + +_ = function(string) { + var translation; + translation = strings[string]; + return translation || string; +}; + +module.exports = { + localize: localize, + _: _ +}; + + +},{}],10:[function(require,module,exports){ +var Point, _slope, math, normals, unit, util; + +Point = require('./shapes').Point; + +util = require('./util'); + +math = {}; + +math.toPoly = function(line) { + var i, index, len, n, point, polyLeft, polyRight; + polyLeft = []; + polyRight = []; + index = 0; + for (i = 0, len = line.length; i < len; i++) { + point = line[i]; + n = normals(point, _slope(line, index)); + polyLeft = polyLeft.concat([n[0]]); + polyRight = [n[1]].concat(polyRight); + index += 1; + } + return polyLeft.concat(polyRight); +}; + +_slope = function(line, index) { + var point; + if (line.length < 3) { + point = { + x: 0, + y: 0 + }; + } + if (index === 0) { + point = _slope(line, index + 1); + } else if (index === line.length - 1) { + point = _slope(line, index - 1); + } else { + point = math.diff(line[index - 1], line[index + 1]); + } + return point; +}; + +math.diff = function(a, b) { + return { + x: b.x - a.x, + y: b.y - a.y + }; +}; + +unit = function(vector) { + var length; + length = math.len(vector); + return { + x: vector.x / length, + y: vector.y / length + }; +}; + +normals = function(p, slope) { + slope = unit(slope); + slope.x = slope.x * p.size / 2; + slope.y = slope.y * p.size / 2; + return [ + { + x: p.x - slope.y, + y: p.y + slope.x, + color: p.color + }, { + x: p.x + slope.y, + y: p.y - slope.x, + color: p.color + } + ]; +}; + +math.len = function(vector) { + return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2)); +}; + +math.scalePositionScalar = function(val, viewportSize, oldScale, newScale) { + var newSize, oldSize; + oldSize = viewportSize * oldScale; + newSize = viewportSize * newScale; + return val + (oldSize - newSize) / 2; +}; + +module.exports = math; + + +},{"./shapes":13,"./util":15}],11:[function(require,module,exports){ +var INFINITE, JSONToShape, renderWatermark, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +renderWatermark = function(ctx, image, scale) { + if (!image.width) { + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(scale, scale); + ctx.drawImage(image, -image.width / 2, -image.height / 2); + return ctx.restore(); +}; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, imageSize, s, shapes, watermarkCanvas, watermarkCtx; + if (opts == null) { + opts = {}; + } + if (opts.scale == null) { + opts.scale = 1; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + watermarkCanvas = document.createElement('canvas'); + watermarkCtx = watermarkCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(watermarkCtx)); + } + return results; + })(), imageSize, opts.margin); + } + watermarkCanvas.width = opts.rect.width * opts.scale; + watermarkCanvas.height = opts.rect.height * opts.scale; + watermarkCtx.fillStyle = colors.background; + watermarkCtx.fillRect(0, 0, watermarkCanvas.width, watermarkCanvas.height); + if (!(opts.rect.width && opts.rect.height)) { + return null; + } + if (opts.watermarkImage) { + renderWatermark(watermarkCtx, opts.watermarkImage, opts.watermarkScale); + } + return util.combineCanvases(watermarkCanvas, util.renderShapes(backgroundShapes, opts.rect, opts.scale), util.renderShapes(shapes, opts.rect, opts.scale)); +}; + + +},{"./shapes":13,"./util":15}],12:[function(require,module,exports){ +var INFINITE, JSONToShape, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, ctx, dummyCanvas, imageSize, s, shapes; + if (opts == null) { + opts = {}; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + dummyCanvas = document.createElement('canvas'); + ctx = dummyCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(ctx)); + } + return results; + })(), imageSize, opts.margin); + } + return LC.renderShapesToSVG(backgroundShapes.concat(shapes), opts.rect, colors.background); +}; + + +},{"./shapes":13,"./util":15}],13:[function(require,module,exports){ +var JSONToShape, LinePath, TextRenderer, _createLinePathFromData, _doAllPointsShareStyle, _dual, _mid, _refine, bspline, createShape, defineCanvasRenderer, defineSVGRenderer, defineShape, lineEndCapShapes, linePathFuncs, ref, ref1, renderShapeToContext, renderShapeToSVG, shapeToJSON, shapes, util; + +util = require('./util'); + +TextRenderer = require('./TextRenderer'); + +lineEndCapShapes = require('./lineEndCapShapes'); + +ref = require('./canvasRenderer'), defineCanvasRenderer = ref.defineCanvasRenderer, renderShapeToContext = ref.renderShapeToContext; + +ref1 = require('./svgRenderer'), defineSVGRenderer = ref1.defineSVGRenderer, renderShapeToSVG = ref1.renderShapeToSVG; + +shapes = {}; + +defineShape = function(name, props) { + var Shape, drawFunc, drawLatestFunc, k, legacyDrawFunc, legacyDrawLatestFunc, legacySVGFunc, svgFunc; + Shape = function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + props.constructor.call(this, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + return this; + }; + Shape.prototype.className = name; + Shape.fromJSON = props.fromJSON; + if (props.draw) { + legacyDrawFunc = props.draw; + legacyDrawLatestFunc = props.draw || function(ctx, bufferCtx, retryCallback) { + return this.draw(ctx, bufferCtx, retryCallback); + }; + drawFunc = function(ctx, shape, retryCallback) { + return legacyDrawFunc.call(shape, ctx, retryCallback); + }; + drawLatestFunc = function(ctx, bufferCtx, shape, retryCallback) { + return legacyDrawLatestFunc.call(shape, ctx, bufferCtx, retryCallback); + }; + delete props.draw; + if (props.drawLatest) { + delete props.drawLatest; + } + defineCanvasRenderer(name, drawFunc, drawLatestFunc); + } + if (props.toSVG) { + legacySVGFunc = props.toSVG; + svgFunc = function(shape) { + return legacySVGFunc.call(shape); + }; + delete props.toSVG; + defineSVGRenderer(name, svgFunc); + } + Shape.prototype.draw = function(ctx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback + }); + }; + Shape.prototype.drawLatest = function(ctx, bufferCtx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback, + bufferCtx: bufferCtx, + shouldOnlyDrawLatest: true + }); + }; + Shape.prototype.toSVG = function() { + return renderShapeToSVG(this); + }; + for (k in props) { + if (k !== 'fromJSON') { + Shape.prototype[k] = props[k]; + } + } + shapes[name] = Shape; + return Shape; +}; + +createShape = function(name, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + var s; + s = new shapes[name](a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + s.id = util.getGUID(); + return s; +}; + +JSONToShape = function(arg) { + var className, data, id, shape; + className = arg.className, data = arg.data, id = arg.id; + if (className in shapes) { + shape = shapes[className].fromJSON(data); + if (shape) { + if (id) { + shape.id = id; + } + return shape; + } else { + console.log('Unreadable shape:', className, data); + return null; + } + } else { + console.log("Unknown shape:", className, data); + return null; + } +}; + +shapeToJSON = function(shape) { + return { + className: shape.className, + data: shape.toJSON(), + id: shape.id + }; +}; + +bspline = function(points, order) { + if (!order) { + return points; + } + return bspline(_dual(_dual(_refine(points))), order - 1); +}; + +_refine = function(points) { + var index, len, point, q, refined; + points = [points[0]].concat(points).concat(util.last(points)); + refined = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + refined[index * 2] = point; + if (points[index + 1]) { + refined[index * 2 + 1] = _mid(point, points[index + 1]); + } + index += 1; + } + return refined; +}; + +_dual = function(points) { + var dualed, index, len, point, q; + dualed = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (points[index + 1]) { + dualed[index] = _mid(point, points[index + 1]); + } + index += 1; + } + return dualed; +}; + +_mid = function(a, b) { + return createShape('Point', { + x: a.x + ((b.x - a.x) / 2), + y: a.y + ((b.y - a.y) / 2), + size: a.size + ((b.size - a.size) / 2), + color: a.color + }); +}; + +defineShape('Image', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.scale = args.scale || 1; + return this.image = args.image || null; + }, + getBoundingRect: function() { + return { + x: this.x, + y: this.y, + width: this.image.width * this.scale, + height: this.image.height * this.scale + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + imageSrc: this.image.src, + imageObject: this.image, + scale: this.scale + }; + }, + fromJSON: function(data) { + var img, ref2; + img = null; + if ((ref2 = data.imageObject) != null ? ref2.width : void 0) { + img = data.imageObject; + } else { + img = new Image(); + img.src = data.imageSrc; + } + return createShape('Image', { + x: data.x, + y: data.y, + image: img, + scale: data.scale + }); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Rectangle', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Rectangle', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Ellipse', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Ellipse', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Line', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x1 = args.x1 || 0; + this.y1 = args.y1 || 0; + this.x2 = args.x2 || 0; + this.y2 = args.y2 || 0; + this.strokeWidth = args.strokeWidth || 1; + this.color = args.color || 'black'; + this.capStyle = args.capStyle || 'round'; + this.endCapShapes = args.endCapShapes || [null, null]; + return this.dash = args.dash || null; + }, + getBoundingRect: function() { + return { + x: Math.min(this.x1, this.x2) - this.strokeWidth / 2, + y: Math.min(this.y1, this.y2) - this.strokeWidth / 2, + width: Math.abs(this.x2 - this.x1) + this.strokeWidth / 2, + height: Math.abs(this.y2 - this.y1) + this.strokeWidth / 2 + }; + }, + toJSON: function() { + return { + x1: this.x1, + y1: this.y1, + x2: this.x2, + y2: this.y2, + strokeWidth: this.strokeWidth, + color: this.color, + capStyle: this.capStyle, + dash: this.dash, + endCapShapes: this.endCapShapes + }; + }, + fromJSON: function(data) { + return createShape('Line', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x1 = this.x1 - moveInfo.xDiff; + this.y1 = this.y1 - moveInfo.yDiff; + this.x2 = this.x2 - moveInfo.xDiff; + return this.y2 = this.y2 - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +_doAllPointsShareStyle = function(points) { + var color, len, point, q, size; + if (!points.length) { + return false; + } + size = points[0].size; + color = points[0].color; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (!(point.size === size && point.color === color)) { + console.log(size, color, point.size, point.color); + } + if (!(point.size === size && point.color === color)) { + return false; + } + } + return true; +}; + +_createLinePathFromData = function(shapeName, data) { + var pointData, points, smoothedPoints, x, y; + points = null; + if (data.points) { + points = (function() { + var len, q, ref2, results; + ref2 = data.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pointData = ref2[q]; + results.push(JSONToShape(pointData)); + } + return results; + })(); + } else if (data.pointCoordinatePairs) { + points = (function() { + var len, q, ref2, ref3, results; + ref2 = data.pointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + smoothedPoints = null; + if (data.smoothedPointCoordinatePairs) { + smoothedPoints = (function() { + var len, q, ref2, ref3, results; + ref2 = data.smoothedPointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + if (!points[0]) { + return null; + } + return createShape(shapeName, { + points: points, + smoothedPoints: smoothedPoints, + order: data.order, + tailSize: data.tailSize, + smooth: data.smooth + }); +}; + +linePathFuncs = { + constructor: function(args) { + var len, point, points, q, results; + if (args == null) { + args = {}; + } + points = args.points || []; + this.order = args.order || 3; + this.tailSize = args.tailSize || 3; + this.smooth = 'smooth' in args ? args.smooth : true; + this.segmentSize = Math.pow(2, this.order); + this.sampleSize = this.tailSize + 1; + if (args.smoothedPoints) { + this.points = args.points; + return this.smoothedPoints = args.smoothedPoints; + } else { + this.points = []; + results = []; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + results.push(this.addPoint(point)); + } + return results; + } + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return { + x: p.x - p.size / 2, + y: p.y - p.size / 2, + width: p.size, + height: p.size + }; + })); + }, + toJSON: function() { + var p, point; + if (_doAllPointsShareStyle(this.points)) { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + pointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + smoothedPointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.smoothedPoints; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + pointSize: this.points[0].size, + pointColor: this.points[0].color + }; + } else { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + points: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + p = ref2[q]; + results.push(shapeToJSON(p)); + } + return results; + }).call(this) + }; + } + }, + fromJSON: function(data) { + return _createLinePathFromData('LinePath', data); + }, + addPoint: function(point) { + this.points.push(point); + if (!this.smooth) { + this.smoothedPoints = this.points; + return; + } + if (!this.smoothedPoints || this.points.length < this.sampleSize) { + return this.smoothedPoints = bspline(this.points, this.order); + } else { + this.tail = util.last(bspline(util.last(this.points, this.sampleSize), this.order), this.segmentSize * this.tailSize); + return this.smoothedPoints = this.smoothedPoints.slice(0, this.smoothedPoints.length - this.segmentSize * (this.tailSize - 1)).concat(this.tail); + } + }, + move: function(moveInfo) { + var len, pt, pts, q; + if (moveInfo == null) { + moveInfo = {}; + } + if (!this.smooth) { + pts = this.points; + } else { + pts = this.smoothedPoints; + } + for (q = 0, len = pts.length; q < len; q++) { + pt = pts[q]; + pt.move(moveInfo); + } + return this.points = this.smoothedPoints; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}; + +LinePath = defineShape('LinePath', linePathFuncs); + +defineShape('ErasedLinePath', { + constructor: linePathFuncs.constructor, + toJSON: linePathFuncs.toJSON, + addPoint: linePathFuncs.addPoint, + getBoundingRect: linePathFuncs.getBoundingRect, + fromJSON: function(data) { + return _createLinePathFromData('ErasedLinePath', data); + } +}); + +defineShape('Point', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.size = args.size || 0; + return this.color = args.color || ''; + }, + getBoundingRect: function() { + return { + x: this.x - this.size / 2, + y: this.y - this.size / 2, + width: this.size, + height: this.size + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + size: this.size, + color: this.color + }; + }, + fromJSON: function(data) { + return createShape('Point', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Polygon', { + constructor: function(args) { + var len, point, q, ref2, results; + if (args == null) { + args = {}; + } + this.points = args.points; + this.fillColor = args.fillColor || 'white'; + this.strokeColor = args.strokeColor || 'black'; + this.strokeWidth = args.strokeWidth; + this.dash = args.dash || null; + if (args.isClosed == null) { + args.isClosed = true; + } + this.isClosed = args.isClosed; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + point.color = this.strokeColor; + results.push(point.size = this.strokeWidth); + } + return results; + }, + addPoint: function(x, y) { + return this.points.push(LC.createShape('Point', { + x: x, + y: y + })); + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return p.getBoundingRect(); + })); + }, + toJSON: function() { + return { + strokeWidth: this.strokeWidth, + fillColor: this.fillColor, + strokeColor: this.strokeColor, + dash: this.dash, + isClosed: this.isClosed, + pointCoordinatePairs: this.points.map(function(p) { + return [p.x, p.y]; + }) + }; + }, + fromJSON: function(data) { + data.points = data.pointCoordinatePairs.map(function(arg) { + var x, y; + x = arg[0], y = arg[1]; + return createShape('Point', { + x: x, + y: y, + size: data.strokeWidth, + color: data.strokeColor + }); + }); + return createShape('Polygon', data); + }, + move: function(moveInfo) { + var len, pt, q, ref2, results; + if (moveInfo == null) { + moveInfo = {}; + } + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pt = ref2[q]; + results.push(pt.move(moveInfo)); + } + return results; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +defineShape('Text', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.v = args.v || 0; + this.text = args.text || ''; + this.color = args.color || 'black'; + this.font = args.font || '18px sans-serif'; + this.forcedWidth = args.forcedWidth || null; + return this.forcedHeight = args.forcedHeight || null; + }, + _makeRenderer: function(ctx) { + ctx.lineHeight = 1.2; + this.renderer = new TextRenderer(ctx, this.text, this.font, this.forcedWidth, this.forcedHeight); + if (this.v < 1) { + console.log('repairing baseline'); + this.v = 1; + this.x -= this.renderer.metrics.bounds.minx; + return this.y -= this.renderer.metrics.leading - this.renderer.metrics.descent; + } + }, + setText: function(text) { + this.text = text; + return this.renderer = null; + }, + setFont: function(font) { + this.font = font; + return this.renderer = null; + }, + setPosition: function(x, y) { + this.x = x; + return this.y = y; + }, + setSize: function(forcedWidth, forcedHeight) { + this.forcedWidth = Math.max(forcedWidth, 0); + this.forcedHeight = Math.max(forcedHeight, 0); + return this.renderer = null; + }, + enforceMaxBoundingRect: function(lc) { + var br, dx, lcBoundingRect; + br = this.getBoundingRect(lc.ctx); + lcBoundingRect = { + x: -lc.position.x / lc.scale, + y: -lc.position.y / lc.scale, + width: lc.canvas.width / lc.scale, + height: lc.canvas.height / lc.scale + }; + if (br.x + br.width > lcBoundingRect.x + lcBoundingRect.width) { + dx = br.x - lcBoundingRect.x; + this.forcedWidth = lcBoundingRect.width - dx - 10; + return this.renderer = null; + } + }, + getBoundingRect: function(ctx, isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (!this.renderer) { + if (ctx) { + this._makeRenderer(ctx); + } else { + throw "Must pass ctx if text hasn't been rendered yet"; + } + } + return { + x: Math.floor(this.x), + y: Math.floor(this.y), + width: Math.ceil(this.renderer.getWidth(true)), + height: Math.ceil(this.renderer.getHeight()) + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + text: this.text, + color: this.color, + font: this.font, + forcedWidth: this.forcedWidth, + forcedHeight: this.forcedHeight, + v: this.v + }; + }, + fromJSON: function(data) { + return createShape('Text', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('SelectionBox', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.shape = args.shape; + if (args.handleSize != null) { + this.handleSize = args.handleSize; + } else { + this.handleSize = 10; + } + this.margin = 4; + this.backgroundColor = args.backgroundColor || null; + return this._br = this.shape.getBoundingRect(args.ctx); + }, + toJSON: function() { + return { + shape: shapeToJSON(this.shape), + backgroundColor: this.backgroundColor + }; + }, + fromJSON: function(arg) { + var backgroundColor, handleSize, margin, shape; + shape = arg.shape, handleSize = arg.handleSize, margin = arg.margin, backgroundColor = arg.backgroundColor; + return createShape('SelectionBox', { + shape: JSONToShape(shape), + backgroundColor: backgroundColor + }); + }, + getTopLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getTopRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBoundingRect: function() { + return { + x: this._br.x - this.margin, + y: this._br.y - this.margin, + width: this._br.width + this.margin * 2, + height: this._br.height + this.margin * 2 + }; + } +}); + +module.exports = { + defineShape: defineShape, + createShape: createShape, + JSONToShape: JSONToShape, + shapeToJSON: shapeToJSON +}; + + +},{"./TextRenderer":2,"./canvasRenderer":5,"./lineEndCapShapes":8,"./svgRenderer":14,"./util":15}],14:[function(require,module,exports){ +var defineSVGRenderer, lineEndCapShapes, renderShapeToSVG, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineSVGRenderer = function(shapeName, shapeToSVGFunc) { + return renderers[shapeName] = shapeToSVGFunc; +}; + +renderShapeToSVG = function(shape, opts) { + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (renderers[shape.className]) { + return renderers[shape.className](shape); + } else if (opts.shouldIgnoreUnsupportedShapes) { + console.warn("Can't render shape of type " + shape.className + " to SVG"); + return ""; + } else { + throw "Can't render shape of type " + shape.className + " to SVG"; + } +}; + +defineSVGRenderer('Rectangle', function(shape) { + var height, width, x, x1, x2, y, y1, y2; + x1 = shape.x; + y1 = shape.y; + x2 = shape.x + shape.width; + y2 = shape.y + shape.height; + x = Math.min(x1, x2); + y = Math.min(y1, y2); + width = Math.max(x1, x2) - x; + height = Math.max(y1, y2) - y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + return ""; +}); + +defineSVGRenderer('SelectionBox', function(shape) { + return ""; +}); + +defineSVGRenderer('Ellipse', function(shape) { + var centerX, centerY, halfHeight, halfWidth; + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + return ""; +}); + +defineSVGRenderer('Image', function(shape) { + return ""; +}); + +defineSVGRenderer('Line', function(shape) { + var arrowWidth, capString, dashString, x1, x2, y1, y2; + dashString = shape.dash ? "stroke-dasharray='" + (shape.dash.join(', ')) + "'" : ''; + capString = ''; + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + if (shape.endCapShapes[0]) { + capString += lineEndCapShapes[shape.endCapShapes[0]].svg(x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + capString += lineEndCapShapes[shape.endCapShapes[1]].svg(x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } + return " " + capString + " "; +}); + +defineSVGRenderer('LinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('ErasedLinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('Polygon', function(shape) { + if (shape.isClosed) { + return ""; + } else { + return " "; + } +}); + +defineSVGRenderer('Text', function(shape) { + var heightString, textSplitOnLines, widthString; + widthString = shape.forcedWidth ? "width='" + shape.forcedWidth + "px'" : ""; + heightString = shape.forcedHeight ? "height='" + shape.forcedHeight + "px'" : ""; + textSplitOnLines = shape.text.split(/\r\n|\r|\n/g); + if (shape.renderer) { + textSplitOnLines = shape.renderer.lines; + } + return " " + (textSplitOnLines.map((function(_this) { + return function(line, i) { + var dy; + dy = i === 0 ? 0 : '1.2em'; + return " " + line + " "; + }; + })(this)).join('')) + " "; +}); + +module.exports = { + defineSVGRenderer: defineSVGRenderer, + renderShapeToSVG: renderShapeToSVG +}; + + +},{"./lineEndCapShapes":8}],15:[function(require,module,exports){ +var renderShapeToContext, renderShapeToSVG, slice, util, + slice1 = [].slice; + +slice = Array.prototype.slice; + +renderShapeToContext = require('./canvasRenderer').renderShapeToContext; + +renderShapeToSVG = require('./svgRenderer').renderShapeToSVG; + +util = { + addImageOnload: function(img, fn) { + var oldOnload; + oldOnload = img.onload; + img.onload = function() { + if (typeof oldOnload === "function") { + oldOnload(); + } + return fn(); + }; + return img; + }, + last: function(array, n) { + if (n == null) { + n = null; + } + if (n) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }, + classSet: function(classNameToIsPresent) { + var classNames, key; + classNames = []; + for (key in classNameToIsPresent) { + if (classNameToIsPresent[key]) { + classNames.push(key); + } + } + return classNames.join(' '); + }, + matchElementSize: function(elementToMatch, elementsToResize, scale, callback) { + var resize; + if (callback == null) { + callback = function() {}; + } + resize = (function(_this) { + return function() { + var el, i, len; + for (i = 0, len = elementsToResize.length; i < len; i++) { + el = elementsToResize[i]; + el.style.width = elementToMatch.offsetWidth + "px"; + el.style.height = elementToMatch.offsetHeight + "px"; + if (el.width != null) { + el.setAttribute('width', el.offsetWidth * scale); + el.setAttribute('height', el.offsetHeight * scale); + } + } + return callback(); + }; + })(this); + elementToMatch.addEventListener('resize', resize); + window.addEventListener('resize', resize); + window.addEventListener('orientationchange', resize); + return resize(); + }, + combineCanvases: function() { + var c, canvas, canvases, ctx, i, j, len, len1; + canvases = 1 <= arguments.length ? slice1.call(arguments, 0) : []; + c = document.createElement('canvas'); + c.width = canvases[0].width; + c.height = canvases[0].height; + for (i = 0, len = canvases.length; i < len; i++) { + canvas = canvases[i]; + c.width = Math.max(canvas.width, c.width); + c.height = Math.max(canvas.height, c.height); + } + ctx = c.getContext('2d'); + for (j = 0, len1 = canvases.length; j < len1; j++) { + canvas = canvases[j]; + ctx.drawImage(canvas, 0, 0); + } + return c; + }, + renderShapes: function(shapes, bounds, scale, canvas) { + var ctx, i, len, shape; + if (scale == null) { + scale = 1; + } + if (canvas == null) { + canvas = null; + } + canvas = canvas || document.createElement('canvas'); + canvas.width = bounds.width * scale; + canvas.height = bounds.height * scale; + ctx = canvas.getContext('2d'); + ctx.translate(-bounds.x * scale, -bounds.y * scale); + ctx.scale(scale, scale); + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + renderShapeToContext(ctx, shape); + } + return canvas; + }, + renderShapesToSVG: function(shapes, arg, backgroundColor) { + var height, width, x, y; + x = arg.x, y = arg.y, width = arg.width, height = arg.height; + return (" " + (shapes.map(renderShapeToSVG).join('')) + " ").replace(/(\r\n|\n|\r)/gm, ""); + }, + getBoundingRect: function(rects, width, height) { + var i, len, maxX, maxY, minX, minY, rect; + if (!rects.length) { + return { + x: 0, + y: 0, + width: 0 || width, + height: 0 || height + }; + } + minX = rects[0].x; + minY = rects[0].y; + maxX = rects[0].x + rects[0].width; + maxY = rects[0].y + rects[0].height; + for (i = 0, len = rects.length; i < len; i++) { + rect = rects[i]; + minX = Math.floor(Math.min(rect.x, minX)); + minY = Math.floor(Math.min(rect.y, minY)); + maxX = Math.ceil(Math.max(maxX, rect.x + rect.width)); + maxY = Math.ceil(Math.max(maxY, rect.y + rect.height)); + } + minX = width ? 0 : minX; + minY = height ? 0 : minY; + maxX = width || maxX; + maxY = height || maxY; + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY + }; + }, + getDefaultImageRect: function(shapeBoundingRects, explicitSize, margin) { + var height, rect, width; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + width = explicitSize.width, height = explicitSize.height; + rect = util.getBoundingRect(shapeBoundingRects, width === 'infinite' ? 0 : width, height === 'infinite' ? 0 : height); + rect.x -= margin.left; + rect.y -= margin.top; + rect.width += margin.left + margin.right; + rect.height += margin.top + margin.bottom; + return rect; + }, + getBackingScale: function(context) { + if (window.devicePixelRatio == null) { + return 1; + } + if (!(window.devicePixelRatio > 1)) { + return 1; + } + return window.devicePixelRatio; + }, + requestAnimationFrame: (window.requestAnimationFrame || window.setTimeout).bind(window), + getGUID: (function() { + var s4; + s4 = function() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); + }; + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + }; + })(), + requestAnimationFrame: function(f) { + if (window.webkitRequestAnimationFrame) { + return window.webkitRequestAnimationFrame(f); + } + if (window.requestAnimationFrame) { + return window.requestAnimationFrame(f); + } + if (window.mozRequestAnimationFrame) { + return window.mozRequestAnimationFrame(f); + } + return setTimeout(f, 0); + }, + cancelAnimationFrame: function(f) { + if (window.webkitCancelRequestAnimationFrame) { + return window.webkitCancelRequestAnimationFrame(f); + } + if (window.webkitCancelAnimationFrame) { + return window.webkitCancelAnimationFrame(f); + } + if (window.cancelAnimationFrame) { + return window.cancelAnimationFrame(f); + } + if (window.mozCancelAnimationFrame) { + return window.mozCancelAnimationFrame(f); + } + return clearTimeout(f); + } +}; + +module.exports = util; + + +},{"./canvasRenderer":5,"./svgRenderer":14}],16:[function(require,module,exports){ +'use strict'; + +(function () { + function CustomEvent(event, params) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + }; + + CustomEvent.prototype = window.CustomEvent.prototype; + + window.CustomEvent = CustomEvent; +})(); + +},{}],17:[function(require,module,exports){ +"use strict"; + +var hasWarned = false; +if (!CanvasRenderingContext2D.prototype.setLineDash) { + CanvasRenderingContext2D.prototype.setLineDash = function () { + // no-op + if (!hasWarned) { + console.warn("context2D.setLineDash is a no-op in this browser."); + hasWarned = true; + } + }; +} +module.exports = null; + +},{}],18:[function(require,module,exports){ +var LiterallyCanvasModel, baseTools, canvasRenderer, conversion, defaultImageURLPrefix, defaultOptions, defaultTools, init, initWithoutGUI, localize, registerJQueryPlugin, renderSnapshotToImage, renderSnapshotToSVG, setDefaultImageURLPrefix, shapes, svgRenderer, tools, util; + +require('./ie_customevent'); + +require('./ie_setLineDash'); + +LiterallyCanvasModel = require('./core/LiterallyCanvas'); + +defaultOptions = require('./core/defaultOptions'); + +canvasRenderer = require('./core/canvasRenderer'); + +svgRenderer = require('./core/svgRenderer'); + +shapes = require('./core/shapes'); + +util = require('./core/util'); + +renderSnapshotToImage = require('./core/renderSnapshotToImage'); + +renderSnapshotToSVG = require('./core/renderSnapshotToSVG'); + +localize = require('./core/localization').localize; + +conversion = { + snapshotToShapes: function(snapshot) { + var i, len, ref, results, shape; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + results.push(shapes.JSONToShape(shape)); + } + return results; + }, + snapshotJSONToShapes: function(json) { + return conversion.snapshotToShapes(JSON.parse(json)); + } +}; + +baseTools = require('./tools/base'); + +tools = { + Pencil: require('./tools/Pencil'), + Eraser: require('./tools/Eraser'), + Line: require('./tools/Line'), + Rectangle: require('./tools/Rectangle'), + Ellipse: require('./tools/Ellipse'), + Text: require('./tools/Text'), + Polygon: require('./tools/Polygon'), + Pan: require('./tools/Pan'), + Eyedropper: require('./tools/Eyedropper'), + SelectShape: require('./tools/SelectShape'), + Tool: baseTools.Tool, + ToolWithStroke: baseTools.ToolWithStroke +}; + +defaultTools = defaultOptions.tools; + +defaultImageURLPrefix = defaultOptions.imageURLPrefix; + +setDefaultImageURLPrefix = function(newDefault) { + defaultImageURLPrefix = newDefault; + return defaultOptions.imageURLPrefix = newDefault; +}; + +init = function(el, opts) { + var child, i, len, opt, ref; + if (opts == null) { + opts = {}; + } + for (opt in defaultOptions) { + if (!(opt in opts)) { + opts[opt] = defaultOptions[opt]; + } + } + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return initWithoutGUI(el, opts); +}; + +initWithoutGUI = function(el, opts) { + var drawingViewElement, lc, originalClassName; + originalClassName = el.className; + if ([' ', ' '].join(el.className).indexOf(' literally ') === -1) { + el.className = el.className + ' literally'; + } + el.className = el.className + ' toolbar-hidden'; + drawingViewElement = document.createElement('div'); + drawingViewElement.className = 'lc-drawing'; + el.appendChild(drawingViewElement); + lc = new LiterallyCanvasModel(drawingViewElement, opts); + lc.teardown = function() { + var child, i, len, ref; + lc._teardown(); + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return el.className = originalClassName; + }; + if ('onInit' in opts) { + opts.onInit(lc); + } + return lc; +}; + +registerJQueryPlugin = function(_$) { + return _$.fn.literallycanvas = function(opts) { + if (opts == null) { + opts = {}; + } + this.each((function(_this) { + return function(ix, el) { + return el.literallycanvas = init(el, opts); + }; + })(this)); + return this; + }; +}; + +if (typeof window !== 'undefined') { + window.LC = { + init: init + }; + if (window.$) { + registerJQueryPlugin(window.$); + } +} + +module.exports = { + init: init, + registerJQueryPlugin: registerJQueryPlugin, + util: util, + tools: tools, + setDefaultImageURLPrefix: setDefaultImageURLPrefix, + defaultTools: defaultTools, + defineShape: shapes.defineShape, + createShape: shapes.createShape, + JSONToShape: shapes.JSONToShape, + shapeToJSON: shapes.shapeToJSON, + defineCanvasRenderer: canvasRenderer.defineCanvasRenderer, + renderShapeToContext: canvasRenderer.renderShapeToContext, + renderShapeToCanvas: canvasRenderer.renderShapeToCanvas, + renderShapesToCanvas: util.renderShapes, + defineSVGRenderer: svgRenderer.defineSVGRenderer, + renderShapeToSVG: svgRenderer.renderShapeToSVG, + renderShapesToSVG: util.renderShapesToSVG, + snapshotToShapes: conversion.snapshotToShapes, + snapshotJSONToShapes: conversion.snapshotJSONToShapes, + renderSnapshotToImage: renderSnapshotToImage, + renderSnapshotToSVG: renderSnapshotToSVG, + localize: localize +}; + + +},{"./core/LiterallyCanvas":1,"./core/canvasRenderer":5,"./core/defaultOptions":6,"./core/localization":9,"./core/renderSnapshotToImage":11,"./core/renderSnapshotToSVG":12,"./core/shapes":13,"./core/svgRenderer":14,"./core/util":15,"./ie_customevent":16,"./ie_setLineDash":17,"./tools/Ellipse":19,"./tools/Eraser":20,"./tools/Eyedropper":21,"./tools/Line":22,"./tools/Pan":23,"./tools/Pencil":24,"./tools/Polygon":25,"./tools/Rectangle":26,"./tools/SelectShape":27,"./tools/Text":28,"./tools/base":29}],19:[function(require,module,exports){ +var Ellipse, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Ellipse = (function(superClass) { + extend(Ellipse, superClass); + + function Ellipse() { + return Ellipse.__super__.constructor.apply(this, arguments); + } + + Ellipse.prototype.name = 'Ellipse'; + + Ellipse.prototype.iconName = 'ellipse'; + + Ellipse.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Ellipse', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Ellipse.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Ellipse.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Ellipse; + +})(ToolWithStroke); + + +},{"../core/shapes":13,"./base":29}],20:[function(require,module,exports){ +var Eraser, Pencil, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Pencil = require('./Pencil'); + +createShape = require('../core/shapes').createShape; + +module.exports = Eraser = (function(superClass) { + extend(Eraser, superClass); + + function Eraser() { + return Eraser.__super__.constructor.apply(this, arguments); + } + + Eraser.prototype.name = 'Eraser'; + + Eraser.prototype.iconName = 'eraser'; + + Eraser.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: '#000' + }); + }; + + Eraser.prototype.makeShape = function() { + return createShape('ErasedLinePath'); + }; + + return Eraser; + +})(Pencil); + + +},{"../core/shapes":13,"./Pencil":24}],21:[function(require,module,exports){ +var Eyedropper, Tool, getPixel, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +getPixel = function(ctx, arg) { + var pixel, x, y; + x = arg.x, y = arg.y; + pixel = ctx.getImageData(x, y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } +}; + +module.exports = Eyedropper = (function(superClass) { + extend(Eyedropper, superClass); + + Eyedropper.prototype.name = 'Eyedropper'; + + Eyedropper.prototype.iconName = 'eyedropper'; + + Eyedropper.prototype.optionsStyle = 'stroke-or-fill'; + + function Eyedropper(lc) { + Eyedropper.__super__.constructor.call(this, lc); + this.strokeOrFill = 'stroke'; + } + + Eyedropper.prototype.readColor = function(x, y, lc) { + var canvas, color, newColor, offset; + offset = lc.getDefaultImageRect(); + canvas = lc.getImage(); + newColor = getPixel(canvas.getContext('2d'), { + x: x - offset.x, + y: y - offset.y + }); + color = newColor || lc.getColor('background'); + if (this.strokeOrFill === 'stroke') { + return lc.setColor('primary', newColor); + } else { + return lc.setColor('secondary', newColor); + } + }; + + Eyedropper.prototype.begin = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + Eyedropper.prototype["continue"] = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + return Eyedropper; + +})(Tool); + + +},{"./base":29}],22:[function(require,module,exports){ +var Line, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Line = (function(superClass) { + extend(Line, superClass); + + function Line() { + return Line.__super__.constructor.apply(this, arguments); + } + + Line.prototype.name = 'Line'; + + Line.prototype.iconName = 'line'; + + Line.prototype.optionsStyle = 'line-options-and-stroke-width'; + + Line.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Line', { + x1: x, + y1: y, + x2: x, + y2: y, + strokeWidth: this.strokeWidth, + dash: (function() { + switch (false) { + case !this.isDashed: + return [this.strokeWidth * 2, this.strokeWidth * 4]; + default: + return null; + } + }).call(this), + endCapShapes: this.hasEndArrow ? [null, 'arrow'] : null, + color: lc.getColor('primary') + }); + }; + + Line.prototype["continue"] = function(x, y, lc) { + this.currentShape.x2 = x; + this.currentShape.y2 = y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Line.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Line; + +})(ToolWithStroke); + + +},{"../core/shapes":13,"./base":29}],23:[function(require,module,exports){ +var Pan, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = Pan = (function(superClass) { + extend(Pan, superClass); + + function Pan() { + return Pan.__super__.constructor.apply(this, arguments); + } + + Pan.prototype.name = 'Pan'; + + Pan.prototype.iconName = 'pan'; + + Pan.prototype.usesSimpleAPI = false; + + Pan.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + unsubscribeFuncs.push(lc.on('lc-pointerdown', (function(_this) { + return function(arg) { + var rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + _this.oldPosition = lc.position; + return _this.pointerStart = { + x: rawX, + y: rawY + }; + }; + })(this))); + return unsubscribeFuncs.push(lc.on('lc-pointerdrag', (function(_this) { + return function(arg) { + var dp, rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + dp = { + x: (rawX - _this.pointerStart.x) * lc.backingScale, + y: (rawY - _this.pointerStart.y) * lc.backingScale + }; + return lc.setPan(_this.oldPosition.x + dp.x, _this.oldPosition.y + dp.y); + }; + })(this))); + }; + + Pan.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return Pan; + +})(Tool); + + +},{"../core/shapes":13,"./base":29}],24:[function(require,module,exports){ +var Pencil, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Pencil = (function(superClass) { + extend(Pencil, superClass); + + function Pencil() { + return Pencil.__super__.constructor.apply(this, arguments); + } + + Pencil.prototype.name = 'Pencil'; + + Pencil.prototype.iconName = 'pencil'; + + Pencil.prototype.eventTimeThreshold = 10; + + Pencil.prototype.begin = function(x, y, lc) { + this.color = lc.getColor('primary'); + this.currentShape = this.makeShape(); + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return this.lastEventTime = Date.now(); + }; + + Pencil.prototype["continue"] = function(x, y, lc) { + var timeDiff; + timeDiff = Date.now() - this.lastEventTime; + if (timeDiff > this.eventTimeThreshold) { + this.lastEventTime += timeDiff; + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return lc.drawShapeInProgress(this.currentShape); + } + }; + + Pencil.prototype.end = function(x, y, lc) { + lc.saveShape(this.currentShape); + return this.currentShape = void 0; + }; + + Pencil.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: this.color + }); + }; + + Pencil.prototype.makeShape = function() { + return createShape('LinePath'); + }; + + return Pencil; + +})(ToolWithStroke); + + +},{"../core/shapes":13,"./base":29}],25:[function(require,module,exports){ +var Polygon, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Polygon = (function(superClass) { + extend(Polygon, superClass); + + function Polygon() { + return Polygon.__super__.constructor.apply(this, arguments); + } + + Polygon.prototype.name = 'Polygon'; + + Polygon.prototype.iconName = 'polygon'; + + Polygon.prototype.usesSimpleAPI = false; + + Polygon.prototype.didBecomeActive = function(lc) { + var onDown, onMove, onUp, polygonCancel, polygonFinishClosed, polygonFinishOpen, polygonUnsubscribeFuncs; + Polygon.__super__.didBecomeActive.call(this, lc); + polygonUnsubscribeFuncs = []; + this.polygonUnsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = polygonUnsubscribeFuncs.length; i < len; i++) { + func = polygonUnsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + this.points = null; + this.maybePoint = null; + onUp = (function(_this) { + return function() { + if (_this._getWillFinish()) { + return _this._close(lc); + } + lc.trigger('lc-polygon-started'); + if (_this.points) { + _this.points.push(_this.maybePoint); + } else { + _this.points = [_this.maybePoint]; + } + _this.maybePoint = { + x: _this.maybePoint.x, + y: _this.maybePoint.y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + onMove = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.maybePoint) { + _this.maybePoint.x = x; + _this.maybePoint.y = y; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + } + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + _this.maybePoint = { + x: x, + y: y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + polygonFinishOpen = (function(_this) { + return function() { + _this.maybePoint = { + x: Infinity, + y: Infinity + }; + return _this._close(lc); + }; + })(this); + polygonFinishClosed = (function(_this) { + return function() { + _this.maybePoint = _this.points[0]; + return _this._close(lc); + }; + })(this); + polygonCancel = (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this); + polygonUnsubscribeFuncs.push(lc.on('drawingChange', (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this))); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointermove', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishopen', polygonFinishOpen)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishclosed', polygonFinishClosed)); + return polygonUnsubscribeFuncs.push(lc.on('lc-polygon-cancel', polygonCancel)); + }; + + Polygon.prototype.willBecomeInactive = function(lc) { + Polygon.__super__.willBecomeInactive.call(this, lc); + if (this.points || this.maybePoint) { + this._cancel(lc); + } + return this.polygonUnsubscribe(); + }; + + Polygon.prototype._getArePointsClose = function(a, b) { + return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) < 10; + }; + + Polygon.prototype._getWillClose = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint); + }; + + Polygon.prototype._getWillFinish = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint) || this._getArePointsClose(this.points[this.points.length - 1], this.maybePoint); + }; + + Polygon.prototype._cancel = function(lc) { + lc.trigger('lc-polygon-stopped'); + this.maybePoint = null; + this.points = null; + lc.setShapesInProgress([]); + return lc.repaintLayer('main'); + }; + + Polygon.prototype._close = function(lc) { + lc.trigger('lc-polygon-stopped'); + lc.setShapesInProgress([]); + if (this.points.length > 2) { + lc.saveShape(this._getShape(lc, false)); + } + this.maybePoint = null; + return this.points = null; + }; + + Polygon.prototype._getShapes = function(lc, isInProgress) { + var shape; + if (isInProgress == null) { + isInProgress = true; + } + shape = this._getShape(lc, isInProgress); + if (shape) { + return [shape]; + } else { + return []; + } + }; + + Polygon.prototype._getShape = function(lc, isInProgress) { + var points; + if (isInProgress == null) { + isInProgress = true; + } + points = []; + if (this.points) { + points = points.concat(this.points); + } + if ((!isInProgress) && points.length < 3) { + return null; + } + if (isInProgress && this.maybePoint) { + points.push(this.maybePoint); + } + if (points.length > 1) { + return createShape('Polygon', { + isClosed: this._getWillClose(), + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary'), + strokeWidth: this.strokeWidth, + points: points.map(function(xy) { + return createShape('Point', xy); + }) + }); + } else { + return null; + } + }; + + Polygon.prototype.optionsStyle = 'polygon-and-stroke-width'; + + return Polygon; + +})(ToolWithStroke); + + +},{"../core/shapes":13,"./base":29}],26:[function(require,module,exports){ +var Rectangle, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Rectangle = (function(superClass) { + extend(Rectangle, superClass); + + function Rectangle() { + return Rectangle.__super__.constructor.apply(this, arguments); + } + + Rectangle.prototype.name = 'Rectangle'; + + Rectangle.prototype.iconName = 'rectangle'; + + Rectangle.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Rectangle', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Rectangle.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Rectangle.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Rectangle; + +})(ToolWithStroke); + + +},{"../core/shapes":13,"./base":29}],27:[function(require,module,exports){ +var SelectShape, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = SelectShape = (function(superClass) { + extend(SelectShape, superClass); + + SelectShape.prototype.name = 'SelectShape'; + + SelectShape.prototype.usesSimpleAPI = false; + + function SelectShape(lc) { + this.selectCanvas = document.createElement('canvas'); + this.selectCanvas.style['background-color'] = 'transparent'; + this.selectCtx = this.selectCanvas.getContext('2d'); + } + + SelectShape.prototype.didBecomeActive = function(lc) { + var onDown, onDrag, onUp, selectShapeUnsubscribeFuncs; + selectShapeUnsubscribeFuncs = []; + this._selectShapeUnsubscribe = (function(_this) { + return function() { + var func, j, len, results; + results = []; + for (j = 0, len = selectShapeUnsubscribeFuncs.length; j < len; j++) { + func = selectShapeUnsubscribeFuncs[j]; + results.push(func()); + } + return results; + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var br, shapeIndex, x, y; + x = arg.x, y = arg.y; + _this.didDrag = false; + shapeIndex = _this._getPixel(x, y, lc, _this.selectCtx); + _this.selectedShape = lc.shapes[shapeIndex]; + if (_this.selectedShape != null) { + lc.trigger('shapeSelected', { + selectedShape: _this.selectedShape + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + lc.repaintLayer('main'); + br = _this.selectedShape.getBoundingRect(); + return _this.dragOffset = { + x: x - br.x, + y: y - br.y + }; + } + }; + })(this); + onDrag = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.selectedShape != null) { + _this.didDrag = true; + _this.selectedShape.setUpperLeft({ + x: x - _this.dragOffset.x, + y: y - _this.dragOffset.y + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + return lc.repaintLayer('main'); + } + }; + })(this); + onUp = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.didDrag) { + _this.didDrag = false; + lc.trigger('shapeMoved', { + shape: _this.selectedShape + }); + lc.trigger('drawingChange', {}); + lc.repaintLayer('main'); + return _this._drawSelectCanvas(lc); + } + }; + })(this); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onDrag)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + return this._drawSelectCanvas(lc); + }; + + SelectShape.prototype.willBecomeInactive = function(lc) { + this._selectShapeUnsubscribe(); + return lc.setShapesInProgress([]); + }; + + SelectShape.prototype._drawSelectCanvas = function(lc) { + var shapes; + this.selectCanvas.width = lc.canvas.width; + this.selectCanvas.height = lc.canvas.height; + this.selectCtx.clearRect(0, 0, this.selectCanvas.width, this.selectCanvas.height); + shapes = lc.shapes.map((function(_this) { + return function(shape, index) { + return createShape('SelectionBox', { + shape: shape, + handleSize: 0, + backgroundColor: "#" + (_this._intToHex(index)) + }); + }; + })(this)); + return lc.draw(shapes, this.selectCtx); + }; + + SelectShape.prototype._intToHex = function(i) { + return ("000000" + (i.toString(16))).slice(-6); + }; + + SelectShape.prototype._getPixel = function(x, y, lc, ctx) { + var p, pixel; + p = lc.drawingCoordsToClientCoords(x, y); + pixel = ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return parseInt(this._rgbToHex(pixel[0], pixel[1], pixel[2]), 16); + } else { + return null; + } + }; + + SelectShape.prototype._componentToHex = function(c) { + var hex; + hex = c.toString(16); + return ("0" + hex).slice(-2); + }; + + SelectShape.prototype._rgbToHex = function(r, g, b) { + return "" + (this._componentToHex(r)) + (this._componentToHex(g)) + (this._componentToHex(b)); + }; + + return SelectShape; + +})(Tool); + + +},{"../core/shapes":13,"./base":29}],28:[function(require,module,exports){ +var Text, Tool, createShape, getIsPointInBox, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +getIsPointInBox = function(point, box) { + if (point.x < box.x) { + return false; + } + if (point.y < box.y) { + return false; + } + if (point.x > box.x + box.width) { + return false; + } + if (point.y > box.y + box.height) { + return false; + } + return true; +}; + +module.exports = Text = (function(superClass) { + extend(Text, superClass); + + Text.prototype.name = 'Text'; + + Text.prototype.iconName = 'text'; + + function Text() { + this.text = ''; + this.font = 'bold 18px sans-serif'; + this.currentShape = null; + this.currentShapeState = null; + this.initialShapeBoundingRect = null; + this.dragAction = null; + this.didDrag = false; + } + + Text.prototype.didBecomeActive = function(lc) { + var switchAway, unsubscribeFuncs, updateInputEl; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + switchAway = (function(_this) { + return function() { + _this._ensureNotEditing(lc); + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this); + updateInputEl = (function(_this) { + return function() { + return _this._updateInputEl(lc); + }; + })(this); + unsubscribeFuncs.push(lc.on('drawingChange', switchAway)); + unsubscribeFuncs.push(lc.on('zoom', updateInputEl)); + unsubscribeFuncs.push(lc.on('imageSizeChange', updateInputEl)); + unsubscribeFuncs.push(lc.on('snapshotLoad', (function(_this) { + return function() { + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this))); + unsubscribeFuncs.push(lc.on('primaryColorChange', (function(_this) { + return function(newColor) { + if (!_this.currentShape) { + return; + } + _this.currentShape.color = newColor; + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + return unsubscribeFuncs.push(lc.on('setFont', (function(_this) { + return function(font) { + if (!_this.currentShape) { + return; + } + _this.font = font; + _this.currentShape.setFont(font); + _this._setShapesInProgress(lc); + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + }; + + Text.prototype.willBecomeInactive = function(lc) { + if (this.currentShape) { + this._ensureNotEditing(lc); + this.commit(lc); + } + return this.unsubscribe(); + }; + + Text.prototype.setText = function(text) { + return this.text = text; + }; + + Text.prototype._ensureNotEditing = function(lc) { + if (this.currentShapeState === 'editing') { + return this._exitEditingState(lc); + } + }; + + Text.prototype._clearCurrentShape = function(lc) { + this.currentShape = null; + this.initialShapeBoundingRect = null; + this.currentShapeState = null; + return lc.setShapesInProgress([]); + }; + + Text.prototype.commit = function(lc) { + if (this.currentShape.text) { + lc.saveShape(this.currentShape); + } + this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._getSelectionShape = function(ctx, backgroundColor) { + if (backgroundColor == null) { + backgroundColor = null; + } + return createShape('SelectionBox', { + shape: this.currentShape, + ctx: ctx, + backgroundColor: backgroundColor + }); + }; + + Text.prototype._setShapesInProgress = function(lc) { + switch (this.currentShapeState) { + case 'selected': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx), this.currentShape]); + case 'editing': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx, '#fff')]); + default: + return lc.setShapesInProgress([this.currentShape]); + } + }; + + Text.prototype.begin = function(x, y, lc) { + var br, point, selectionBox, selectionShape; + this.dragAction = 'none'; + this.didDrag = false; + if (this.currentShapeState === 'selected' || this.currentShapeState === 'editing') { + br = this.currentShape.getBoundingRect(lc.ctx); + selectionShape = this._getSelectionShape(lc.ctx); + selectionBox = selectionShape.getBoundingRect(); + point = { + x: x, + y: y + }; + if (getIsPointInBox(point, br)) { + this.dragAction = 'move'; + } + if (getIsPointInBox(point, selectionShape.getBottomRightHandleRect())) { + this.dragAction = 'resizeBottomRight'; + } + if (getIsPointInBox(point, selectionShape.getTopLeftHandleRect())) { + this.dragAction = 'resizeTopLeft'; + } + if (getIsPointInBox(point, selectionShape.getBottomLeftHandleRect())) { + this.dragAction = 'resizeBottomLeft'; + } + if (getIsPointInBox(point, selectionShape.getTopRightHandleRect())) { + this.dragAction = 'resizeTopRight'; + } + if (this.dragAction === 'none' && this.currentShapeState === 'editing') { + this.dragAction = 'stop-editing'; + this._exitEditingState(lc); + } + } else { + this.color = lc.getColor('primary'); + this.currentShape = createShape('Text', { + x: x, + y: y, + text: this.text, + color: this.color, + font: this.font, + v: 1 + }); + this.dragAction = 'place'; + this.currentShapeState = 'selected'; + } + if (this.dragAction === 'none') { + this.commit(lc); + return; + } + this.initialShapeBoundingRect = this.currentShape.getBoundingRect(lc.ctx); + this.dragOffset = { + x: x - this.initialShapeBoundingRect.x, + y: y - this.initialShapeBoundingRect.y + }; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype["continue"] = function(x, y, lc) { + var br, brBottom, brRight; + if (this.dragAction === 'none') { + return; + } + br = this.initialShapeBoundingRect; + brRight = br.x + br.width; + brBottom = br.y + br.height; + switch (this.dragAction) { + case 'place': + this.currentShape.x = x; + this.currentShape.y = y; + this.didDrag = true; + break; + case 'move': + this.currentShape.x = x - this.dragOffset.x; + this.currentShape.y = y - this.dragOffset.y; + this.didDrag = true; + break; + case 'resizeBottomRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + break; + case 'resizeTopLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(x - this.dragOffset.x, y - this.dragOffset.y); + break; + case 'resizeBottomLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + this.currentShape.setPosition(x - this.dragOffset.x, this.currentShape.y); + break; + case 'resizeTopRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(this.currentShape.x, y - this.dragOffset.y); + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype.end = function(x, y, lc) { + if (!this.currentShape) { + return; + } + this.currentShape.setSize(this.currentShape.forcedWidth, 0); + if (this.currentShapeState === 'selected') { + if (this.dragAction === 'place' || (this.dragAction === 'move' && !this.didDrag)) { + this._enterEditingState(lc); + } + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype._enterEditingState = function(lc) { + var onChange; + this.currentShapeState = 'editing'; + if (this.inputEl) { + throw "State error"; + } + this.inputEl = document.createElement('textarea'); + this.inputEl.className = 'text-tool-input'; + this.inputEl.style.position = 'absolute'; + this.inputEl.style.transformOrigin = '0px 0px'; + this.inputEl.style.backgroundColor = 'transparent'; + this.inputEl.style.border = 'none'; + this.inputEl.style.outline = 'none'; + this.inputEl.style.margin = '0'; + this.inputEl.style.padding = '4px'; + this.inputEl.style.zIndex = '1000'; + this.inputEl.style.overflow = 'hidden'; + this.inputEl.style.resize = 'none'; + this.inputEl.value = this.currentShape.text; + this.inputEl.addEventListener('mousedown', function(e) { + return e.stopPropagation(); + }); + this.inputEl.addEventListener('touchstart', function(e) { + return e.stopPropagation(); + }); + onChange = (function(_this) { + return function(e) { + _this.currentShape.setText(e.target.value); + _this.currentShape.enforceMaxBoundingRect(lc); + _this._setShapesInProgress(lc); + lc.repaintLayer('main'); + _this._updateInputEl(lc); + return e.stopPropagation(); + }; + })(this); + this.inputEl.addEventListener('keydown', (function(_this) { + return function() { + return _this._updateInputEl(lc, true); + }; + })(this)); + this.inputEl.addEventListener('keyup', onChange); + this.inputEl.addEventListener('change', onChange); + this._updateInputEl(lc); + lc.containerEl.appendChild(this.inputEl); + this.inputEl.focus(); + return this._setShapesInProgress(lc); + }; + + Text.prototype._exitEditingState = function(lc) { + this.currentShapeState = 'selected'; + lc.containerEl.removeChild(this.inputEl); + this.inputEl = null; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._updateInputEl = function(lc, withMargin) { + var br, transformString; + if (withMargin == null) { + withMargin = false; + } + if (!this.inputEl) { + return; + } + br = this.currentShape.getBoundingRect(lc.ctx, true); + this.inputEl.style.font = this.currentShape.font; + this.inputEl.style.color = this.currentShape.color; + this.inputEl.style.left = (lc.position.x / lc.backingScale + br.x * lc.scale - 4) + "px"; + this.inputEl.style.top = (lc.position.y / lc.backingScale + br.y * lc.scale - 4) + "px"; + if (withMargin && !this.currentShape.forcedWidth) { + this.inputEl.style.width = (br.width + 10 + this.currentShape.renderer.emDashWidth) + "px"; + } else { + this.inputEl.style.width = (br.width + 12) + "px"; + } + if (withMargin) { + this.inputEl.style.height = (br.height + 10 + this.currentShape.renderer.metrics.leading) + "px"; + } else { + this.inputEl.style.height = (br.height + 10) + "px"; + } + transformString = "scale(" + lc.scale + ")"; + this.inputEl.style.transform = transformString; + this.inputEl.style.webkitTransform = transformString; + this.inputEl.style.MozTransform = transformString; + this.inputEl.style.msTransform = transformString; + return this.inputEl.style.OTransform = transformString; + }; + + Text.prototype.optionsStyle = 'font'; + + return Text; + +})(Tool); + + +},{"../core/shapes":13,"./base":29}],29:[function(require,module,exports){ +var Tool, ToolWithStroke, tools, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +tools = {}; + +tools.Tool = Tool = (function() { + function Tool() {} + + Tool.prototype.name = null; + + Tool.prototype.iconName = null; + + Tool.prototype.usesSimpleAPI = true; + + Tool.prototype.begin = function(x, y, lc) {}; + + Tool.prototype["continue"] = function(x, y, lc) {}; + + Tool.prototype.end = function(x, y, lc) {}; + + Tool.prototype.optionsStyle = null; + + Tool.prototype.didBecomeActive = function(lc) {}; + + Tool.prototype.willBecomeInactive = function(lc) {}; + + return Tool; + +})(); + +tools.ToolWithStroke = ToolWithStroke = (function(superClass) { + extend(ToolWithStroke, superClass); + + function ToolWithStroke(lc) { + this.strokeWidth = lc.opts.defaultStrokeWidth; + } + + ToolWithStroke.prototype.optionsStyle = 'stroke-width'; + + ToolWithStroke.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + return unsubscribeFuncs.push(lc.on('setStrokeWidth', (function(_this) { + return function(strokeWidth) { + _this.strokeWidth = strokeWidth; + return lc.trigger('toolDidUpdateOptions'); + }; + })(this))); + }; + + ToolWithStroke.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return ToolWithStroke; + +})(Tool); + +module.exports = tools; + + +},{}]},{},[18])(18) +}); \ No newline at end of file diff --git a/library/js/literallycanvas/js/literallycanvas-core.min.js b/library/js/literallycanvas/js/literallycanvas-core.min.js new file mode 100644 index 00000000000..ef5d6265b28 --- /dev/null +++ b/library/js/literallycanvas/js/literallycanvas-core.min.js @@ -0,0 +1,3 @@ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.LC=t()}}(function(){return function t(e,n,i){function r(s,a){if(!n[s]){if(!e[s]){var h="function"==typeof require&&require;if(!a&&h)return h(s,!0);if(o)return o(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return r(n?n:t)},c,c.exports,t,e,n,i)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;se;e++)if(e in this&&this[e]===t)return e;return-1};a=t("./actions"),h=t("./bindEvents"),c=t("./math"),l=t("./shapes"),u=l.createShape,y=l.shapeToJSON,r=l.JSONToShape,p=t("./canvasRenderer").renderShapeToContext,d=t("./svgRenderer").renderShapeToSVG,f=t("./renderSnapshotToImage"),g=t("./renderSnapshotToSVG"),s=t("../tools/Pencil"),m=t("./util"),i="infinite",e.exports=o=function(){function t(t,e){this.setImageSize=S(this.setImageSize,this);var n,r;r=null,n=null,t instanceof HTMLElement?(n=t,r=e):r=t,this.opts=r||{},this.config={zoomMin:r.zoomMin||.2,zoomMax:r.zoomMax||4,zoomStep:r.zoomStep||.2},this.colors={primary:r.primaryColor||"#000",secondary:r.secondaryColor||"#fff",background:r.backgroundColor||"transparent"},this.watermarkImage=r.watermarkImage,this.watermarkScale=r.watermarkScale||1,this.backgroundCanvas=document.createElement("canvas"),this.backgroundCtx=this.backgroundCanvas.getContext("2d"),this.canvas=document.createElement("canvas"),this.canvas.style["background-color"]="transparent",this.buffer=document.createElement("canvas"),this.buffer.style["background-color"]="transparent",this.ctx=this.canvas.getContext("2d"),this.bufferCtx=this.buffer.getContext("2d"),this.backingScale=m.getBackingScale(this.ctx),this.backgroundShapes=r.backgroundShapes||[],this._shapesInProgress=[],this.shapes=[],this.undoStack=[],this.redoStack=[],this.isDragging=!1,this.position={x:0,y:0},this.scale=1,this.setTool(new this.opts.tools[0](this)),this.width=r.imageSize.width||i,this.height=r.imageSize.height||i,this.setZoom(this.scale),r.snapshot&&this.loadSnapshot(r.snapshot),this.isBound=!1,n&&this.bindToElement(n)}return t.prototype.bindToElement=function(t){var e,n;return this.containerEl?void console.warn("Trying to bind Literally Canvas to a DOM element more than once is unsupported."):(this.containerEl=t,this._unsubscribeEvents=h(this,this.containerEl,this.opts.keyboardShortcuts),this.containerEl.style["background-color"]=this.colors.background,this.containerEl.appendChild(this.backgroundCanvas),this.containerEl.appendChild(this.canvas),this.isBound=!0,n=function(t){return function(){return t.keepPanInImageBounds(),t.repaintAllLayers()}}(this),m.matchElementSize(this.containerEl,[this.backgroundCanvas,this.canvas],this.backingScale,n),this.watermarkImage&&(this.watermarkImage.onload=function(t){return function(){return t.repaintLayer("background")}}(this)),null!=(e=this.tool)&&e.didBecomeActive(this),n())},t.prototype._teardown=function(){return this.tool.willBecomeInactive(this),"function"==typeof this._unsubscribeEvents&&this._unsubscribeEvents(),this.tool=null,this.containerEl=null,this.isBound=!1},t.prototype.trigger=function(t,e){return this.canvas.dispatchEvent(new CustomEvent(t,{detail:e})),null},t.prototype.on=function(t,e){var n;return n=function(t){return e(t.detail)},this.canvas.addEventListener(t,n),function(e){return function(){return e.canvas.removeEventListener(t,n)}}(this)},t.prototype.getRenderScale=function(){return this.scale*this.backingScale},t.prototype.clientCoordsToDrawingCoords=function(t,e){return{x:(t*this.backingScale-this.position.x)/this.getRenderScale(),y:(e*this.backingScale-this.position.y)/this.getRenderScale()}},t.prototype.drawingCoordsToClientCoords=function(t,e){return{x:t*this.getRenderScale()+this.position.x,y:e*this.getRenderScale()+this.position.y}},t.prototype.setImageSize=function(t,e){return this.width=t||i,this.height=e||i,this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("imageSizeChange",{width:this.width,height:this.height})},t.prototype.setTool=function(t){var e;return this.isBound&&null!=(e=this.tool)&&e.willBecomeInactive(this),this.tool=t,this.trigger("toolChange",{tool:t}),this.isBound?this.tool.didBecomeActive(this):void 0},t.prototype.setShapesInProgress=function(t){return this._shapesInProgress=t},t.prototype.pointerDown=function(t,e){var n;return n=this.clientCoordsToDrawingCoords(t,e),this.tool.usesSimpleAPI?(this.tool.begin(n.x,n.y,this),this.isDragging=!0,this.trigger("drawStart",{tool:this.tool})):(this.isDragging=!0,this.trigger("lc-pointerdown",{tool:this.tool,x:n.x,y:n.y,rawX:t,rawY:e}))},t.prototype.pointerMove=function(t,e){return m.requestAnimationFrame(function(n){return function(){var i,r;return i=n.clientCoordsToDrawingCoords(t,e),(null!=(r=n.tool)?r.usesSimpleAPI:0)?n.isDragging?(n.tool["continue"](i.x,i.y,n),n.trigger("drawContinue",{tool:n.tool})):void 0:n.isDragging?n.trigger("lc-pointerdrag",{tool:n.tool,x:i.x,y:i.y,rawX:t,rawY:e}):n.trigger("lc-pointermove",{tool:n.tool,x:i.x,y:i.y,rawX:t,rawY:e})}}(this))},t.prototype.pointerUp=function(t,e){var n;return n=this.clientCoordsToDrawingCoords(t,e),this.tool.usesSimpleAPI?this.isDragging?(this.tool.end(n.x,n.y,this),this.isDragging=!1,this.trigger("drawEnd",{tool:this.tool})):void 0:(this.isDragging=!1,this.trigger("lc-pointerup",{tool:this.tool,x:n.x,y:n.y,rawX:t,rawY:e}))},t.prototype.setColor=function(t,e){if(this.colors[t]=e,this.isBound){switch(t){case"background":this.containerEl.style.backgroundColor=this.colors.background,this.repaintLayer("background");break;case"primary":this.repaintLayer("main");break;case"secondary":this.repaintLayer("main")}return this.trigger(t+"ColorChange",this.colors[t]),"background"===t?this.trigger("drawingChange"):void 0}},t.prototype.getColor=function(t){return this.colors[t]},t.prototype.saveShape=function(t,e,n){return null==e&&(e=!0),null==n&&(n=null),n||(n=this.shapes.length?this.shapes[this.shapes.length-1].id:null),this.execute(new a.AddShapeAction(this,t,n)),e&&this.trigger("shapeSave",{shape:t,previousShapeId:n}),this.trigger("drawingChange")},t.prototype.pan=function(t,e){return this.setPan(this.position.x-t,this.position.y-e)},t.prototype.keepPanInImageBounds=function(){var t,e,n,r;return e=this.getRenderScale(),t=this.position,n=t.x,r=t.y,this.width!==i&&(n=this.canvas.width>this.width*e?(this.canvas.width-this.width*e)/2:Math.max(Math.min(0,n),this.canvas.width-this.width*e)),this.height!==i&&(r=this.canvas.height>this.height*e?(this.canvas.height-this.height*e)/2:Math.max(Math.min(0,r),this.canvas.height-this.height*e)),this.position={x:n,y:r}},t.prototype.setPan=function(t,e){return this.position={x:t,y:e},this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("pan",{x:this.position.x,y:this.position.y})},t.prototype.zoom=function(t){var e;return e=this.scale+t,e=Math.max(e,this.config.zoomMin),e=Math.min(e,this.config.zoomMax),e=Math.round(100*e)/100,this.setZoom(e)},t.prototype.setZoom=function(t){var e;return e=this.scale,this.scale=t,this.position.x=c.scalePositionScalar(this.position.x,this.canvas.width,e,this.scale),this.position.y=c.scalePositionScalar(this.position.y,this.canvas.height,e,this.scale),this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("zoom",{oldScale:e,newScale:this.scale})},t.prototype.setWatermarkImage=function(t){return this.watermarkImage=t,m.addImageOnload(t,function(t){return function(){return t.repaintLayer("background")}}(this)),t.width?this.repaintLayer("background"):void 0},t.prototype.repaintAllLayers=function(){var t,e,n,i;for(i=["background","main"],t=0,n=i.length;n>t;t++)e=i[t],this.repaintLayer(e);return null},t.prototype.repaintLayer=function(t,e){var n;if(null==e&&(e="main"===t),this.isBound){switch(t){case"background":this.backgroundCtx.clearRect(0,0,this.backgroundCanvas.width,this.backgroundCanvas.height),n=function(t){return function(){return t.repaintLayer("background")}}(this),this.watermarkImage&&this._renderWatermark(this.backgroundCtx,!0,n),this.draw(this.backgroundShapes,this.backgroundCtx,n);break;case"main":n=function(t){return function(){return t.repaintLayer("main",!0)}}(this),e&&(this.buffer.width=this.canvas.width,this.buffer.height=this.canvas.height,this.bufferCtx.clearRect(0,0,this.buffer.width,this.buffer.height),this.draw(this.shapes,this.bufferCtx,n)),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width>0&&this.canvas.height>0&&(this.ctx.fillStyle="#ccc",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height),this.clipped(function(t){return function(){return t.ctx.clearRect(0,0,t.canvas.width,t.canvas.height),t.ctx.drawImage(t.buffer,0,0)}}(this),this.ctx),this.clipped(function(t){return function(){return t.transformed(function(){var e,n,i,r,o;for(i=t._shapesInProgress,r=[],e=0,n=i.length;n>e;e++)o=i[e],r.push(p(t.ctx,o,{bufferCtx:t.bufferCtx,shouldOnlyDrawLatest:!0}));return r},t.ctx,t.bufferCtx)}}(this),this.ctx,this.bufferCtx))}return this.trigger("repaint",{layerKey:t})}},t.prototype._renderWatermark=function(t,e,n){return null==e&&(e=!0),this.watermarkImage.width?(t.save(),t.translate(t.canvas.width/2,t.canvas.height/2),t.scale(this.watermarkScale,this.watermarkScale),e&&t.scale(this.backingScale,this.backingScale),t.drawImage(this.watermarkImage,-this.watermarkImage.width/2,-this.watermarkImage.height/2),t.restore()):void(this.watermarkImage.onload=n)},t.prototype.drawShapeInProgress=function(t){return this.repaintLayer("main",!1),this.clipped(function(e){return function(){return e.transformed(function(){return p(e.ctx,t,{bufferCtx:e.bufferCtx,shouldOnlyDrawLatest:!0})},e.ctx,e.bufferCtx)}}(this),this.ctx,this.bufferCtx)},t.prototype.draw=function(t,e,n){var i;if(t.length)return i=function(i){return function(){var i,r,o,s;for(o=[],i=0,r=t.length;r>i;i++)s=t[i],o.push(p(e,s,{retryCallback:n}));return o}}(this),this.clipped(function(t){return function(){return t.transformed(i,e)}}(this),e)},t.prototype.clipped=function(){var t,e,n,r,o,s,a,h,u,c,l,p;for(n=arguments[0],t=2<=arguments.length?x.call(arguments,1):[],l=this.width===i?0:this.position.x,p=this.height===i?0:this.position.y,c=function(){switch(this.width){case i:return this.canvas.width;default:return this.width*this.getRenderScale()}}.call(this),r=function(){switch(this.height){case i:return this.canvas.height;default:return this.height*this.getRenderScale()}}.call(this),o=0,a=t.length;a>o;o++)e=t[o],e.save(),e.beginPath(),e.rect(l,p,c,r),e.clip();for(n(),u=[],s=0,h=t.length;h>s;s++)e=t[s],u.push(e.restore());return u},t.prototype.transformed=function(){var t,e,n,i,r,o,s,a,h;for(n=arguments[0],t=2<=arguments.length?x.call(arguments,1):[],i=0,o=t.length;o>i;i++)e=t[i],e.save(),e.translate(Math.floor(this.position.x),Math.floor(this.position.y)),h=this.getRenderScale(),e.scale(h,h);for(n(),a=[],r=0,s=t.length;s>r;r++)e=t[r],a.push(e.restore());return a},t.prototype.clear=function(t){var e,n;return null==t&&(t=!0),n=this.shapes,e=[],this.setShapesInProgress([]),this.execute(new a.ClearAction(this,n,e)),this.repaintLayer("main"),t&&this.trigger("clear",null),this.trigger("drawingChange",{})},t.prototype.execute=function(t){return this.undoStack.push(t),t["do"](),this.redoStack=[]},t.prototype.undo=function(){var t;if(this.undoStack.length)return t=this.undoStack.pop(),t.undo(),this.redoStack.push(t),this.trigger("undo",{action:t}),this.trigger("drawingChange",{})},t.prototype.redo=function(){var t;if(this.redoStack.length)return t=this.redoStack.pop(),this.undoStack.push(t),t["do"](),this.trigger("redo",{action:t}),this.trigger("drawingChange",{})},t.prototype.canUndo=function(){return!!this.undoStack.length},t.prototype.canRedo=function(){return!!this.redoStack.length},t.prototype.getPixel=function(t,e){var n,i;return n=this.drawingCoordsToClientCoords(t,e),i=this.ctx.getImageData(n.x,n.y,1,1).data,i[3]?"rgb("+i[0]+", "+i[1]+", "+i[2]+")":null},t.prototype.getContentBounds=function(){return m.getBoundingRect(this.shapes.concat(this.backgroundShapes).map(function(t){return t.getBoundingRect()}),this.width===i?0:this.width,this.height===i?0:this.height)},t.prototype.getDefaultImageRect=function(t,e){var n;return null==t&&(t={width:0,height:0}),null==e&&(e={top:0,right:0,bottom:0,left:0}),m.getDefaultImageRect(function(){var t,e,i,r;for(i=this.shapes.concat(this.backgroundShapes),r=[],t=0,e=i.length;e>t;t++)n=i[t],r.push(n.getBoundingRect(this.ctx));return r}.call(this),t,e)},t.prototype.getImage=function(t){return null==t&&(t={}),null==t.includeWatermark&&(t.includeWatermark=!0),null==t.scaleDownRetina&&(t.scaleDownRetina=!0),null==t.scale&&(t.scale=1),t.scaleDownRetina||(t.scale*=this.backingScale),t.includeWatermark&&(t.watermarkImage=this.watermarkImage,t.watermarkScale=this.watermarkScale,t.scaleDownRetina||(t.watermarkScale*=this.backingScale)),f(this.getSnapshot(),t)},t.prototype.canvasForExport=function(){return this.repaintAllLayers(),m.combineCanvases(this.backgroundCanvas,this.canvas)},t.prototype.canvasWithBackground=function(t){return m.combineCanvases(t,this.canvasForExport())},t.prototype.getSnapshot=function(t){var e,n,i,r,o,s;for(null==t&&(t=null),null==t&&(t=["shapes","imageSize","colors","position","scale","backgroundShapes"]),s={},r=["colors","position","scale"],e=0,i=r.length;i>e;e++)n=r[e],v.call(t,n)>=0&&(s[n]=this[n]);return v.call(t,"shapes")>=0&&(s.shapes=function(){var t,e,n,i;for(n=this.shapes,i=[],t=0,e=n.length;e>t;t++)o=n[t],i.push(y(o));return i}.call(this)),v.call(t,"backgroundShapes")>=0&&(s.backgroundShapes=function(){var t,e,n,i;for(n=this.backgroundShapes,i=[],t=0,e=n.length;e>t;t++)o=n[t],i.push(y(o));return i}.call(this)),v.call(t,"imageSize")>=0&&(s.imageSize={width:this.width,height:this.height}),s},t.prototype.getSnapshotJSON=function(){return console.warn("lc.getSnapshotJSON() is deprecated. use JSON.stringify(lc.getSnapshot()) instead."),JSON.stringify(this.getSnapshot())},t.prototype.getSVGString=function(t){return null==t&&(t={}),g(this.getSnapshot(),t)},t.prototype.loadSnapshot=function(t){var e,n,i,o,s,h,u,c,l,p;if(t){if(t.colors)for(h=["primary","secondary","background"],e=0,o=h.length;o>e;e++)i=h[e],this.setColor(i,t.colors[i]);if(t.shapes)for(this.shapes=[],u=t.shapes,n=0,s=u.length;s>n;n++)p=u[n],l=r(p),l&&this.execute(new a.AddShapeAction(this,l));return t.backgroundShapes&&(this.backgroundShapes=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}()),t.imageSize&&(this.width=t.imageSize.width,this.height=t.imageSize.height),t.position&&(this.position=t.position),t.scale&&(this.scale=t.scale),this.repaintAllLayers(),this.trigger("snapshotLoad"),this.trigger("drawingChange",{})}},t.prototype.loadSnapshotJSON=function(t){return console.warn("lc.loadSnapshotJSON() is deprecated. use lc.loadSnapshot(JSON.parse(snapshot)) instead."),this.loadSnapshot(JSON.parse(t))},t}()},{"../tools/Pencil":24,"./actions":3,"./bindEvents":4,"./canvasRenderer":5,"./math":10,"./renderSnapshotToImage":11,"./renderSnapshotToSVG":12,"./shapes":13,"./svgRenderer":14,"./util":15}],2:[function(t,e,n){var i,r,o,s;t("./fontmetrics.js"),s=function(t){var e,n,i,r,o,s,a,h;for(n=t.split(" "),i=0,o=0,s=n.length;s>o;o++)r=n[o],a=parseInt(r.replace("px",""),10),isNaN(a)||(i=a);if(!i)throw"Font size not found";return h=t.substring(n[0].length+1).replace("bold ","").replace("italic ","").replace("underline ",""),e=h,{fontSize:i,fontFamily:e}},o=function(t,e,n){var i,r,o,s,a,h,u,c,l,p;if(!e.length)return["",""];for(r=0,h=0,u=0,p=!1;;)if(r+=1,o=r>=e.length,a=!o&&e[r].match(/\s/),s=a||o,l=e.substring(0,r),i=n?t.measureTextWidth(l).width<=n:!0,i&&(u=r),s&&p&&(p=!1,i&&(h=r)),p=!a,o||!i){if(i)return[e,""];if(h>0){for(c=h+1;ci;i++)if(l=p[i],h=o(t,l,n),a=h[0],c=h[1],a)for(;a;)s.push(a),u=o(t,c,n),a=u[0],c=u[1];else s.push(l);return s},i=function(){function t(t,e,n,i,o){var a,h,u;this.text=e,this.font=n,this.forcedWidth=i,this.forcedHeight=o,u=s(this.font),a=u.fontFamily,h=u.fontSize,t.font=this.font,t.textBaseline="baseline",this.emDashWidth=t.measureTextWidth("—",h,a).width,this.caratWidth=t.measureTextWidth("|",h,a).width,this.lines=r(t,this.text,this.forcedWidth),this.metricses=this.lines.map(function(e){return function(n){return t.measureText2(n||"X",h,e.font)}}(this)),this.metrics={ascent:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.ascent})),descent:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.descent})),fontsize:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.fontsize})),leading:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.leading})),width:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.width})),height:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.height})),bounds:{minx:Math.min.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.minx})),miny:Math.min.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.miny})),maxx:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.maxx})),maxy:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.maxy}))}},this.boundingBoxWidth=Math.ceil(this.metrics.width)}return t.prototype.draw=function(t,e,n){var i,r,o,s,a,h;for(t.textBaseline="top",t.font=this.font,i=0,a=this.lines,h=[],r=0,o=a.length;o>r;r++)s=a[r],t.fillText(s,e,n+i*this.metrics.leading),h.push(i+=1);return h},t.prototype.getWidth=function(t){return null==t&&(t=!1),this.forcedWidth?this.forcedWidth:t?this.metrics.bounds.maxx+this.caratWidth:this.metrics.bounds.maxx},t.prototype.getHeight=function(){return this.forcedHeight||this.metrics.leading*this.lines.length},t}(),e.exports=i},{"./fontmetrics.js":7}],3:[function(t,e,n){var i,r;r=function(){function t(t,e,n){this.lc=t,this.oldShapes=e,this.newShapes=n}return t.prototype["do"]=function(){return this.lc.shapes=this.newShapes,this.lc.repaintLayer("main")},t.prototype.undo=function(){return this.lc.shapes=this.oldShapes,this.lc.repaintLayer("main")},t}(),i=function(){function t(t,e,n){this.lc=t,this.shape=e,this.previousShapeId=null!=n?n:null}return t.prototype["do"]=function(){var t,e,n,i,r,o;if(this.lc.shapes.length&&this.lc.shapes[this.lc.shapes.length-1].id!==this.previousShapeId&&null!==this.previousShapeId){for(i=[],t=!1,r=this.lc.shapes,e=0,n=r.length;n>e;e++)o=r[e],i.push(o),o.id===this.previousShapeId&&(i.push(this.shape),t=!0);t||i.push(this.shape),this.lc.shapes=i}else this.lc.shapes.push(this.shape);return this.lc.repaintLayer("main")},t.prototype.undo=function(){var t,e,n,i,r;if(this.lc.shapes[this.lc.shapes.length-1].id===this.shape.id)this.lc.shapes.pop();else{for(n=[],i=this.lc.shapes,t=0,e=i.length;e>t;t++)r=i[t],r.id!==this.shape.id&&n.push(r);lc.shapes=n}return this.lc.repaintLayer("main")},t}(),e.exports={ClearAction:r,AddShapeAction:i}},{}],4:[function(t,e,n){var i,r,o,s;o=function(t,e){var n,i,r;return i=e.changedTouches[0].clientX,r=e.changedTouches[0].clientY,n=t.getBoundingClientRect(),[i-n.left,r-n.top]},s=function(t,e){var n;return n=t.getBoundingClientRect(),{left:e.clientX-n.left,top:e.clientY-n.top}},r=function(t){return null!=t.buttons?1===t.buttons:t.which>0},e.exports=i=function(t,e,n){var i,r,a,h,u,c;return null==n&&(n=!1),c=[],r=function(n){return function(n){var i;return n.preventDefault(),i=s(e,n),t.pointerMove(i.left,i.top)}}(this),a=function(n){return function(n){var i;return n.preventDefault(),e.onselectstart=function(){return!0},i=s(e,n),t.pointerUp(i.left,i.top),document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",a),e.addEventListener("mousemove",r)}}(this),e.addEventListener("mousedown",function(n){return function(n){var i,o;if("canvas"===n.target.tagName.toLowerCase())return i=!0,n.preventDefault(),e.onselectstart=function(){return!1},o=s(e,n),t.pointerDown(o.left,o.top),e.removeEventListener("mousemove",r),document.addEventListener("mousemove",r),document.addEventListener("mouseup",a)}}(this)),u=function(n){return n.preventDefault(),t.pointerMove.apply(t,o(e,n))},h=function(n){return n.preventDefault(),t.pointerUp.apply(t,o(e,n)),document.removeEventListener("touchmove",u),document.removeEventListener("touchend",h),document.removeEventListener("touchcancel",h)},e.addEventListener("touchstart",function(n){return"canvas"===n.target.tagName.toLowerCase()?(n.preventDefault(),1===n.touches.length?(t.pointerDown.apply(t,o(e,n)),document.addEventListener("touchmove",u),document.addEventListener("touchend",h),document.addEventListener("touchcancel",h)):t.pointerMove.apply(t,o(e,n))):void 0}),n&&(console.warn("Keyboard panning is deprecated."),i=function(e){switch(e.keyCode){case 37:t.pan(-10,0);break;case 38:t.pan(0,-10);break;case 39:t.pan(10,0);break;case 40:t.pan(0,10)}return t.repaintAllLayers()},document.addEventListener("keydown",i),c.push(function(){return document.removeEventListener(i)})),function(){var t,e,n,i;for(i=[],e=0,n=c.length;n>e;e++)t=c[e],i.push(t());return i}}},{}],5:[function(t,e,n){var i,r,o,s,a,h,u,c,l,p,d;u=t("./lineEndCapShapes"),d={},r=function(t,e,n){return d[t]={drawFunc:e,drawLatestFunc:n}},c=function(){},p=function(t,e,n){var i;if(null==n&&(n={}),null==n.shouldIgnoreUnsupportedShapes&&(n.shouldIgnoreUnsupportedShapes=!1),null==n.retryCallback&&(n.retryCallback=c),null==n.shouldOnlyDrawLatest&&(n.shouldOnlyDrawLatest=!1),null==n.bufferCtx&&(n.bufferCtx=null),i=n.bufferCtx,d[e.className])return n.shouldOnlyDrawLatest&&d[e.className].drawLatestFunc?d[e.className].drawLatestFunc(t,i,e,n.retryCallback):d[e.className].drawFunc(t,e,n.retryCallback);if(n.shouldIgnoreUnsupportedShapes)return console.warn("Can't render shape of type "+e.className+" to canvas");throw"Can't render shape of type "+e.className+" to canvas"},l=function(t,e,n){return p(t.getContext("2d"),e,n)},r("Rectangle",function(t,e){var n,i;return n=e.x,i=e.y,e.strokeWidth%2!==0&&(n+=.5,i+=.5),t.fillStyle=e.fillColor,t.fillRect(n,i,e.width,e.height),t.lineWidth=e.strokeWidth,t.strokeStyle=e.strokeColor,t.strokeRect(n,i,e.width,e.height)}),r("Ellipse",function(t,e){var n,i,r,o;return t.save(),o=Math.floor(e.width/2),r=Math.floor(e.height/2),n=e.x+o,i=e.y+r,t.translate(n,i),t.scale(1,Math.abs(e.height/e.width)),t.beginPath(),t.arc(0,0,Math.abs(o),0,2*Math.PI),t.closePath(),t.restore(),t.fillStyle=e.fillColor,t.fill(),t.lineWidth=e.strokeWidth,t.strokeStyle=e.strokeColor,t.stroke()}),r("SelectionBox",function(){var t;return t=function(t,e,n){var i,r;return i=e.x,r=e.y,0!==n?(t.fillStyle="#fff",t.fillRect(i,r,n,n),t.strokeStyle="#000",t.strokeRect(i,r,n,n)):void 0},function(e,n){return t(e,n.getTopLeftHandleRect(),n.handleSize),t(e,n.getTopRightHandleRect(),n.handleSize),t(e,n.getBottomLeftHandleRect(),n.handleSize),t(e,n.getBottomRightHandleRect(),n.handleSize),n.backgroundColor&&(e.fillStyle=n.backgroundColor,e.fillRect(n._br.x-n.margin,n._br.y-n.margin,n._br.width+2*n.margin,n._br.height+2*n.margin)),e.lineWidth=1,e.strokeStyle="#000",e.setLineDash([2,4]),e.strokeRect(n._br.x-n.margin,n._br.y-n.margin,n._br.width+2*n.margin,n._br.height+2*n.margin),e.setLineDash([])}}()),r("Image",function(t,e,n){return e.image.width?1===e.scale?t.drawImage(e.image,e.x,e.y):t.drawImage(e.image,e.x,e.y,e.image.width*e.scale,e.image.height*e.scale):n?e.image.onload=n:void 0}),r("Line",function(t,e){var n,i,r,o,s;if(e.x1!==e.x2||e.y1!==e.y2)return i=e.x1,r=e.x2,o=e.y1,s=e.y2,e.strokeWidth%2!==0&&(i+=.5,r+=.5,o+=.5,s+=.5),t.lineWidth=e.strokeWidth,t.strokeStyle=e.color,t.lineCap=e.capStyle,e.dash&&t.setLineDash(e.dash),t.beginPath(),t.moveTo(i,o),t.lineTo(r,s),t.stroke(),e.dash&&t.setLineDash([]),n=Math.max(2.2*e.strokeWidth,5),e.endCapShapes[0]&&u[e.endCapShapes[0]].drawToCanvas(t,i,o,Math.atan2(o-s,i-r),n,e.color),e.endCapShapes[1]?u[e.endCapShapes[1]].drawToCanvas(t,r,s,Math.atan2(s-o,r-i),n,e.color):void 0}),i=function(t,e,n,i){var r,o,s,a;if(null==n&&(n=!1),null==i&&(i="round"),e.length){for(t.lineCap=i,t.strokeStyle=e[0].color,t.lineWidth=e[0].size,t.beginPath(),e[0].size%2===0?t.moveTo(e[0].x,e[0].y):t.moveTo(e[0].x+.5,e[0].y+.5),a=e.slice(1),r=0,o=a.length;o>r;r++)s=a[r],e[0].size%2===0?t.lineTo(s.x,s.y):t.lineTo(s.x+.5,s.y+.5);return n?t.closePath():void 0}},a=function(t,e){return i(t,e.smoothedPoints),t.stroke()},h=function(t,e,n){var r,o,s;return n.tail?(s=n.smoothedPoints.length-n.segmentSize*n.tailSize,o=s<2*n.segmentSize?0:s,r=s+n.segmentSize+1,i(e,n.smoothedPoints.slice(o,r)),e.stroke()):(i(e,n.smoothedPoints),e.stroke())},r("LinePath",a,h),o=function(t,e){return t.save(),t.globalCompositeOperation="destination-out",a(t,e),t.restore()},s=function(t,e,n){return t.save(),t.globalCompositeOperation="destination-out",e.save(),e.globalCompositeOperation="destination-out",h(t,e,n),t.restore(),e.restore()},r("ErasedLinePath",o,s),r("Text",function(t,e){return e.renderer||e._makeRenderer(t),t.fillStyle=e.color,e.renderer.draw(t,e.x,e.y)}),r("Polygon",function(t,e){return t.fillStyle=e.fillColor,i(t,e.points,e.isClosed,"butt"),t.fill(),t.stroke()}),e.exports={defineCanvasRenderer:r,renderShapeToCanvas:l,renderShapeToContext:p}},{"./lineEndCapShapes":8}],6:[function(t,e,n){"use strict";e.exports={imageURLPrefix:"lib/img",primaryColor:"hsla(0, 0%, 0%, 1)",secondaryColor:"hsla(0, 0%, 100%, 1)",backgroundColor:"transparent",strokeWidths:[1,2,5,10,20,30],defaultStrokeWidth:5,toolbarPosition:"top",keyboardShortcuts:!1,imageSize:{width:"infinite",height:"infinite"},backgroundShapes:[],watermarkImage:null,watermarkScale:1,zoomMin:.2,zoomMax:4,zoomStep:.2,snapshot:null,tools:[t("../tools/Pencil"),t("../tools/Eraser"),t("../tools/Line"),t("../tools/Rectangle"),t("../tools/Ellipse"),t("../tools/Text"),t("../tools/Polygon"),t("../tools/Pan"),t("../tools/Eyedropper")]}},{"../tools/Ellipse":19,"../tools/Eraser":20,"../tools/Eyedropper":21,"../tools/Line":22,"../tools/Pan":23,"../tools/Pencil":24,"../tools/Polygon":25,"../tools/Rectangle":26,"../tools/Text":28}],7:[function(t,e,n){"use strict";!function(){if(!document.defaultView.getComputedStyle)throw"ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.";CanvasRenderingContext2D.prototype.measureTextWidth=CanvasRenderingContext2D.prototype.measureText;var t=function(t,e){return document.defaultView.getComputedStyle(t,null).getPropertyValue(e)};CanvasRenderingContext2D.prototype.measureText2=function(e,n,i){var r=this.measureTextWidth(e),o=!/\S/.test(e);r.fontsize=n;var s=document.createElement("div");s.style.position="absolute",s.style.opacity=0,s.style.font=i,s.innerHTML=e+"
"+e,document.body.appendChild(s),r.leading=1.2*n;var a=t(s,"height");if(a=a.replace("px",""),a>=2*n&&(r.leading=a/2|0),document.body.removeChild(s),o)r.ascent=0,r.descent=0,r.bounds={minx:0,maxx:r.width,miny:0,maxy:0},r.height=0;else{var h=document.createElement("canvas"),u=100;h.width=r.width+u,h.height=3*n,h.style.opacity=1,h.style.font=i;var c=h.getContext("2d");c.font=i;var l=h.width,p=h.height,d=p/2;c.fillStyle="white",c.fillRect(-1,-1,l+2,p+2),c.fillStyle="black",c.fillText(e,u/2,d);for(var f=c.getImageData(0,0,l,p).data,g=0,y=4*l,m=f.length;++g0&&255===f[g];);var x=g/y|0;for(g=0;m>g&&255===f[g];)g+=y,g>=m&&(g=g-m+4);var v=g%y/4|0,w=1;for(g=m-3;g>=0&&255===f[g];)g-=y,0>g&&(g=m-3-4*w++);var b=g%y/4+1|0;r.ascent=d-S,r.descent=x-d,r.bounds={minx:v-u/2,maxx:b-u/2,miny:0,maxy:x-S},r.height=1+(x-S)}return r}}()},{}],8:[function(t,e,n){e.exports={arrow:function(){var t;return t=function(t,e,n,i,r){return[{x:t+Math.cos(n+Math.PI/2)*i/2,y:e+Math.sin(n+Math.PI/2)*i/2},{x:t+Math.cos(n)*r,y:e+Math.sin(n)*r},{x:t+Math.cos(n-Math.PI/2)*i/2,y:e+Math.sin(n-Math.PI/2)*i/2}]},{drawToCanvas:function(e,n,i,r,o,s,a){var h;return null==a&&(a=0),a=a||o,e.fillStyle=s,e.lineWidth=0,e.strokeStyle="transparent",e.beginPath(),h=t(n,i,r,o,a),e.moveTo(h[0].x,h[0].y),e.lineTo(h[1].x,h[1].y),e.lineTo(h[2].x,h[2].y),e.fill()},svg:function(e,n,i,r,o,s){var a;return null==s&&(s=0),s=s||r,a=t(e,n,i,r,s),""}}}()}},{}],9:[function(t,e,n){var i,r,o;o={},r=function(t){return o=t},i=function(t){var e;return e=o[t],e||t},e.exports={localize:r,_:i}},{}],10:[function(t,e,n){var i,r,o,s,a,h;i=t("./shapes").Point,h=t("./util"),o={},o.toPoly=function(t){var e,n,i,o,a,h,u;for(h=[],u=[],n=0,e=0,i=t.length;i>e;e++)a=t[e],o=s(a,r(t,n)),h=h.concat([o[0]]),u=[o[1]].concat(u),n+=1;return h.concat(u)},r=function(t,e){var n;return t.length<3&&(n={x:0,y:0}),n=0===e?r(t,e+1):e===t.length-1?r(t,e-1):o.diff(t[e-1],t[e+1])},o.diff=function(t,e){return{x:e.x-t.x,y:e.y-t.y}},a=function(t){var e;return e=o.len(t),{x:t.x/e,y:t.y/e}},s=function(t,e){return e=a(e),e.x=e.x*t.size/2,e.y=e.y*t.size/2,[{x:t.x-e.y,y:t.y+e.x,color:t.color},{x:t.x+e.y,y:t.y-e.x,color:t.color}]},o.len=function(t){return Math.sqrt(Math.pow(t.x,2)+Math.pow(t.y,2))},o.scalePositionScalar=function(t,e,n,i){var r,o;return o=e*n,r=e*i,t+(o-r)/2},e.exports=o},{"./shapes":13,"./util":15}],11:[function(t,e,n){var i,r,o,s;s=t("./util"),r=t("./shapes").JSONToShape,i="infinite",o=function(t,e,n){return e.width?(t.save(),t.translate(t.canvas.width/2,t.canvas.height/2),t.scale(n,n),t.drawImage(e,-e.width/2,-e.height/2),t.restore()):void 0},e.exports=function(t,e){var n,a,h,u,c,l,p,d;return null==e&&(e={}),null==e.scale&&(e.scale=1),l=function(){var e,n,i,o;for(i=t.shapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}(),a=[],t.backgroundShapes&&(a=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}()),null==e.margin&&(e.margin={top:0,right:0,bottom:0,left:0}),u=t.imageSize||{width:i,height:i},h=t.colors||{background:"transparent"},n=l.concat(a),p=document.createElement("canvas"),d=p.getContext("2d"),e.rect?(e.rect.x-=e.margin.left,e.rect.y-=e.margin.top,e.rect.width+=e.margin.left+e.margin.right,e.rect.height+=e.margin.top+e.margin.bottom):e.rect=s.getDefaultImageRect(function(){var t,e,i;for(i=[],t=0,e=n.length;e>t;t++)c=n[t],i.push(c.getBoundingRect(d));return i}(),u,e.margin),p.width=e.rect.width*e.scale,p.height=e.rect.height*e.scale,d.fillStyle=h.background,d.fillRect(0,0,p.width,p.height),e.rect.width&&e.rect.height?(e.watermarkImage&&o(d,e.watermarkImage,e.watermarkScale),s.combineCanvases(p,s.renderShapes(a,e.rect,e.scale),s.renderShapes(l,e.rect,e.scale))):null}},{"./shapes":13,"./util":15}],12:[function(t,e,n){var i,r,o;o=t("./util"),r=t("./shapes").JSONToShape,i="infinite",e.exports=function(t,e){var n,s,a,h,u,c,l,p;return null==e&&(e={}),p=function(){var e,n,i,o;for(i=t.shapes,o=[],e=0,n=i.length;n>e;e++)l=i[e],o.push(r(l));return o}(),s=[],t.backgroundShapes&&(s=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)l=i[e],o.push(r(l));return o}()),null==e.margin&&(e.margin={top:0,right:0,bottom:0,left:0}),c=t.imageSize||{width:i,height:i},a=t.colors||{background:"transparent"},n=p.concat(s),u=document.createElement("canvas"),h=u.getContext("2d"),e.rect?(e.rect.x-=e.margin.left,e.rect.y-=e.margin.top,e.rect.width+=e.margin.left+e.margin.right,e.rect.height+=e.margin.top+e.margin.bottom):e.rect=o.getDefaultImageRect(function(){var t,e,i;for(i=[],t=0,e=n.length;e>t;t++)l=n[t],i.push(l.getBoundingRect(h));return i}(),c,e.margin),LC.renderShapesToSVG(s.concat(p),e.rect,a.background); +}},{"./shapes":13,"./util":15}],13:[function(t,e,n){var i,r,o,s,a,h,u,c,l,p,d,f,g,y,m,S,x,v,w,b,k,C;C=t("./util"),o=t("./TextRenderer"),y=t("./lineEndCapShapes"),S=t("./canvasRenderer"),d=S.defineCanvasRenderer,v=S.renderShapeToContext,x=t("./svgRenderer"),f=x.defineSVGRenderer,w=x.renderShapeToSVG,k={},g=function(t,e){var n,i,r,o,s,a,h,u;n=function(t,n,i,r,o,s,a,h,u,c,l,p,d,f,g,y){return e.constructor.call(this,t,n,i,r,o,s,a,h,u,c,l,p,d,f,g,y),this},n.prototype.className=t,n.fromJSON=e.fromJSON,e.draw&&(s=e.draw,a=e.draw||function(t,e,n){return this.draw(t,e,n)},i=function(t,e,n){return s.call(e,t,n)},r=function(t,e,n,i){return a.call(n,t,e,i)},delete e.draw,e.drawLatest&&delete e.drawLatest,d(t,i,r)),e.toSVG&&(h=e.toSVG,u=function(t){return h.call(t)},delete e.toSVG,f(t,u)),n.prototype.draw=function(t,e){return v(t,this,{retryCallback:e})},n.prototype.drawLatest=function(t,e,n){return v(t,this,{retryCallback:n,bufferCtx:e,shouldOnlyDrawLatest:!0})},n.prototype.toSVG=function(){return w(this)};for(o in e)"fromJSON"!==o&&(n.prototype[o]=e[o]);return k[t]=n,n},p=function(t,e,n,i,r,o,s,a,h,u,c,l,p,d,f,g,y){var m;return m=new k[t](e,n,i,r,o,s,a,h,u,c,l,p,d,f,g,y),m.id=C.getGUID(),m},i=function(t){var e,n,i,r;return e=t.className,n=t.data,i=t.id,e in k?(r=k[e].fromJSON(n),r?(i&&(r.id=i),r):(console.log("Unreadable shape:",e,n),null)):(console.log("Unknown shape:",e,n),null)},b=function(t){return{className:t.className,data:t.toJSON(),id:t.id}},l=function(t,e){return e?l(h(h(c(t))),e-1):t},c=function(t){var e,n,i,r,o;for(t=[t[0]].concat(t).concat(C.last(t)),o=[],e=0,r=0,n=t.length;n>r;r++)i=t[r],o[2*e]=i,t[e+1]&&(o[2*e+1]=u(i,t[e+1])),e+=1;return o},h=function(t){var e,n,i,r,o;for(e=[],n=0,o=0,i=t.length;i>o;o++)r=t[o],t[n+1]&&(e[n]=u(r,t[n+1])),n+=1;return e},u=function(t,e){return p("Point",{x:t.x+(e.x-t.x)/2,y:t.y+(e.y-t.y)/2,size:t.size+(e.size-t.size)/2,color:t.color})},g("Image",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.scale=t.scale||1,this.image=t.image||null},getBoundingRect:function(){return{x:this.x,y:this.y,width:this.image.width*this.scale,height:this.image.height*this.scale}},toJSON:function(){return{x:this.x,y:this.y,imageSrc:this.image.src,imageObject:this.image,scale:this.scale}},fromJSON:function(t){var e,n;return e=null,(null!=(n=t.imageObject)?n.width:void 0)?e=t.imageObject:(e=new Image,e.src=t.imageSrc),p("Image",{x:t.x,y:t.y,image:e,scale:t.scale})},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Rectangle",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.width=t.width||0,this.height=t.height||0,this.strokeWidth=t.strokeWidth||1,this.strokeColor=t.strokeColor||"black",this.fillColor=t.fillColor||"transparent"},getBoundingRect:function(){return{x:this.x-this.strokeWidth/2,y:this.y-this.strokeWidth/2,width:this.width+this.strokeWidth,height:this.height+this.strokeWidth}},toJSON:function(){return{x:this.x,y:this.y,width:this.width,height:this.height,strokeWidth:this.strokeWidth,strokeColor:this.strokeColor,fillColor:this.fillColor}},fromJSON:function(t){return p("Rectangle",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Ellipse",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.width=t.width||0,this.height=t.height||0,this.strokeWidth=t.strokeWidth||1,this.strokeColor=t.strokeColor||"black",this.fillColor=t.fillColor||"transparent"},getBoundingRect:function(){return{x:this.x-this.strokeWidth/2,y:this.y-this.strokeWidth/2,width:this.width+this.strokeWidth,height:this.height+this.strokeWidth}},toJSON:function(){return{x:this.x,y:this.y,width:this.width,height:this.height,strokeWidth:this.strokeWidth,strokeColor:this.strokeColor,fillColor:this.fillColor}},fromJSON:function(t){return p("Ellipse",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Line",{constructor:function(t){return null==t&&(t={}),this.x1=t.x1||0,this.y1=t.y1||0,this.x2=t.x2||0,this.y2=t.y2||0,this.strokeWidth=t.strokeWidth||1,this.color=t.color||"black",this.capStyle=t.capStyle||"round",this.endCapShapes=t.endCapShapes||[null,null],this.dash=t.dash||null},getBoundingRect:function(){return{x:Math.min(this.x1,this.x2)-this.strokeWidth/2,y:Math.min(this.y1,this.y2)-this.strokeWidth/2,width:Math.abs(this.x2-this.x1)+this.strokeWidth/2,height:Math.abs(this.y2-this.y1)+this.strokeWidth/2}},toJSON:function(){return{x1:this.x1,y1:this.y1,x2:this.x2,y2:this.y2,strokeWidth:this.strokeWidth,color:this.color,capStyle:this.capStyle,dash:this.dash,endCapShapes:this.endCapShapes}},fromJSON:function(t){return p("Line",t)},move:function(t){return null==t&&(t={}),this.x1=this.x1-t.xDiff,this.y1=this.y1-t.yDiff,this.x2=this.x2-t.xDiff,this.y2=this.y2-t.yDiff},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}}),a=function(t){var e,n,i,r,o;if(!t.length)return!1;for(o=t[0].size,e=t[0].color,r=0,n=t.length;n>r;r++)if(i=t[r],(i.size!==o||i.color!==e)&&console.log(o,e,i.size,i.color),i.size!==o||i.color!==e)return!1;return!0},s=function(t,e){var n,r,o,s,a;return r=null,e.points?r=function(){var t,r,o,s;for(o=e.points,s=[],r=0,t=o.length;t>r;r++)n=o[r],s.push(i(n));return s}():e.pointCoordinatePairs&&(r=function(){var t,n,r,o,h;for(r=e.pointCoordinatePairs,h=[],n=0,t=r.length;t>n;n++)o=r[n],s=o[0],a=o[1],h.push(i({className:"Point",data:{x:s,y:a,size:e.pointSize,color:e.pointColor,smooth:e.smooth}}));return h}()),o=null,e.smoothedPointCoordinatePairs&&(o=function(){var t,n,r,o,h;for(r=e.smoothedPointCoordinatePairs,h=[],n=0,t=r.length;t>n;n++)o=r[n],s=o[0],a=o[1],h.push(i({className:"Point",data:{x:s,y:a,size:e.pointSize,color:e.pointColor,smooth:e.smooth}}));return h}()),r[0]?p(t,{points:r,smoothedPoints:o,order:e.order,tailSize:e.tailSize,smooth:e.smooth}):null},m={constructor:function(t){var e,n,i,r,o;if(null==t&&(t={}),i=t.points||[],this.order=t.order||3,this.tailSize=t.tailSize||3,this.smooth="smooth"in t?t.smooth:!0,this.segmentSize=Math.pow(2,this.order),this.sampleSize=this.tailSize+1,t.smoothedPoints)return this.points=t.points,this.smoothedPoints=t.smoothedPoints;for(this.points=[],o=[],r=0,e=i.length;e>r;r++)n=i[r],o.push(this.addPoint(n));return o},getBoundingRect:function(){return C.getBoundingRect(this.points.map(function(t){return{x:t.x-t.size/2,y:t.y-t.size/2,width:t.size,height:t.size}}))},toJSON:function(){var t,e;return a(this.points)?{order:this.order,tailSize:this.tailSize,smooth:this.smooth,pointCoordinatePairs:function(){var t,n,i,r;for(i=this.points,r=[],n=0,t=i.length;t>n;n++)e=i[n],r.push([e.x,e.y]);return r}.call(this),smoothedPointCoordinatePairs:function(){var t,n,i,r;for(i=this.smoothedPoints,r=[],n=0,t=i.length;t>n;n++)e=i[n],r.push([e.x,e.y]);return r}.call(this),pointSize:this.points[0].size,pointColor:this.points[0].color}:{order:this.order,tailSize:this.tailSize,smooth:this.smooth,points:function(){var e,n,i,r;for(i=this.points,r=[],n=0,e=i.length;e>n;n++)t=i[n],r.push(b(t));return r}.call(this)}},fromJSON:function(t){return s("LinePath",t)},addPoint:function(t){return this.points.push(t),this.smooth?!this.smoothedPoints||this.points.lengthr;r++)n=i[r],n.move(t);return this.points=this.smoothedPoints},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}},r=g("LinePath",m),g("ErasedLinePath",{constructor:m.constructor,toJSON:m.toJSON,addPoint:m.addPoint,getBoundingRect:m.getBoundingRect,fromJSON:function(t){return s("ErasedLinePath",t)}}),g("Point",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.size=t.size||0,this.color=t.color||""},getBoundingRect:function(){return{x:this.x-this.size/2,y:this.y-this.size/2,width:this.size,height:this.size}},toJSON:function(){return{x:this.x,y:this.y,size:this.size,color:this.color}},fromJSON:function(t){return p("Point",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Polygon",{constructor:function(t){var e,n,i,r,o;for(null==t&&(t={}),this.points=t.points,this.fillColor=t.fillColor||"white",this.strokeColor=t.strokeColor||"black",this.strokeWidth=t.strokeWidth,this.dash=t.dash||null,null==t.isClosed&&(t.isClosed=!0),this.isClosed=t.isClosed,r=this.points,o=[],i=0,e=r.length;e>i;i++)n=r[i],n.color=this.strokeColor,o.push(n.size=this.strokeWidth);return o},addPoint:function(t,e){return this.points.push(LC.createShape("Point",{x:t,y:e}))},getBoundingRect:function(){return C.getBoundingRect(this.points.map(function(t){return t.getBoundingRect()}))},toJSON:function(){return{strokeWidth:this.strokeWidth,fillColor:this.fillColor,strokeColor:this.strokeColor,dash:this.dash,isClosed:this.isClosed,pointCoordinatePairs:this.points.map(function(t){return[t.x,t.y]})}},fromJSON:function(t){return t.points=t.pointCoordinatePairs.map(function(e){var n,i;return n=e[0],i=e[1],p("Point",{x:n,y:i,size:t.strokeWidth,color:t.strokeColor})}),p("Polygon",t)},move:function(t){var e,n,i,r,o;for(null==t&&(t={}),r=this.points,o=[],i=0,e=r.length;e>i;i++)n=r[i],o.push(n.move(t));return o},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}}),g("Text",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.v=t.v||0,this.text=t.text||"",this.color=t.color||"black",this.font=t.font||"18px sans-serif",this.forcedWidth=t.forcedWidth||null,this.forcedHeight=t.forcedHeight||null},_makeRenderer:function(t){return t.lineHeight=1.2,this.renderer=new o(t,this.text,this.font,this.forcedWidth,this.forcedHeight),this.v<1?(console.log("repairing baseline"),this.v=1,this.x-=this.renderer.metrics.bounds.minx,this.y-=this.renderer.metrics.leading-this.renderer.metrics.descent):void 0},setText:function(t){return this.text=t,this.renderer=null},setFont:function(t){return this.font=t,this.renderer=null},setPosition:function(t,e){return this.x=t,this.y=e},setSize:function(t,e){return this.forcedWidth=Math.max(t,0),this.forcedHeight=Math.max(e,0),this.renderer=null},enforceMaxBoundingRect:function(t){var e,n,i;return e=this.getBoundingRect(t.ctx),i={x:-t.position.x/t.scale,y:-t.position.y/t.scale,width:t.canvas.width/t.scale,height:t.canvas.height/t.scale},e.x+e.width>i.x+i.width?(n=e.x-i.x,this.forcedWidth=i.width-n-10,this.renderer=null):void 0},getBoundingRect:function(t,e){if(null==e&&(e=!1),!this.renderer){if(!t)throw"Must pass ctx if text hasn't been rendered yet";this._makeRenderer(t)}return{x:Math.floor(this.x),y:Math.floor(this.y),width:Math.ceil(this.renderer.getWidth(!0)),height:Math.ceil(this.renderer.getHeight())}},toJSON:function(){return{x:this.x,y:this.y,text:this.text,color:this.color,font:this.font,forcedWidth:this.forcedWidth,forcedHeight:this.forcedHeight,v:this.v}},fromJSON:function(t){return p("Text",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("SelectionBox",{constructor:function(t){return null==t&&(t={}),this.shape=t.shape,null!=t.handleSize?this.handleSize=t.handleSize:this.handleSize=10,this.margin=4,this.backgroundColor=t.backgroundColor||null,this._br=this.shape.getBoundingRect(t.ctx)},toJSON:function(){return{shape:b(this.shape),backgroundColor:this.backgroundColor}},fromJSON:function(t){var e,n,r,o;return o=t.shape,n=t.handleSize,r=t.margin,e=t.backgroundColor,p("SelectionBox",{shape:i(o),backgroundColor:e})},getTopLeftHandleRect:function(){return{x:this._br.x-this.handleSize-this.margin,y:this._br.y-this.handleSize-this.margin,width:this.handleSize,height:this.handleSize}},getBottomLeftHandleRect:function(){return{x:this._br.x-this.handleSize-this.margin,y:this._br.y+this._br.height+this.margin,width:this.handleSize,height:this.handleSize}},getTopRightHandleRect:function(){return{x:this._br.x+this._br.width+this.margin,y:this._br.y-this.handleSize-this.margin,width:this.handleSize,height:this.handleSize}},getBottomRightHandleRect:function(){return{x:this._br.x+this._br.width+this.margin,y:this._br.y+this._br.height+this.margin,width:this.handleSize,height:this.handleSize}},getBoundingRect:function(){return{x:this._br.x-this.margin,y:this._br.y-this.margin,width:this._br.width+2*this.margin,height:this._br.height+2*this.margin}}}),e.exports={defineShape:g,createShape:p,JSONToShape:i,shapeToJSON:b}},{"./TextRenderer":2,"./canvasRenderer":5,"./lineEndCapShapes":8,"./svgRenderer":14,"./util":15}],14:[function(t,e,n){var i,r,o,s;r=t("./lineEndCapShapes"),s={},i=function(t,e){return s[t]=e},o=function(t,e){if(null==e&&(e={}),null==e.shouldIgnoreUnsupportedShapes&&(e.shouldIgnoreUnsupportedShapes=!1),s[t.className])return s[t.className](t);if(e.shouldIgnoreUnsupportedShapes)return console.warn("Can't render shape of type "+t.className+" to SVG"),"";throw"Can't render shape of type "+t.className+" to SVG"},i("Rectangle",function(t){var e,n,i,r,o,s,a,h;return r=t.x,a=t.y,o=t.x+t.width,h=t.y+t.height,i=Math.min(r,o),s=Math.min(a,h),n=Math.max(r,o)-i,e=Math.max(a,h)-s,t.strokeWidth%2!==0&&(i+=.5,s+=.5),""}),i("SelectionBox",function(t){return""}),i("Ellipse",function(t){var e,n,i,r;return r=Math.floor(t.width/2),i=Math.floor(t.height/2),e=t.x+r,n=t.y+i,""}),i("Image",function(t){return""}),i("Line",function(t){var e,n,i,o,s,a,h;return i=t.dash?"stroke-dasharray='"+t.dash.join(", ")+"'":"",n="",e=Math.max(2.2*t.strokeWidth,5),o=t.x1,s=t.x2,a=t.y1,h=t.y2,t.strokeWidth%2!==0&&(o+=.5,s+=.5,a+=.5,h+=.5),t.endCapShapes[0]&&(n+=r[t.endCapShapes[0]].svg(o,a,Math.atan2(a-h,o-s),e,t.color)),t.endCapShapes[1]&&(n+=r[t.endCapShapes[1]].svg(s,h,Math.atan2(h-a,s-o),e,t.color))," "+n+" "}),i("LinePath",function(t){return""}),i("ErasedLinePath",function(t){return""}),i("Polygon",function(t){return t.isClosed?"":" "}),i("Text",function(t){var e,n,i;return i=t.forcedWidth?"width='"+t.forcedWidth+"px'":"",e=t.forcedHeight?"height='"+t.forcedHeight+"px'":"",n=t.text.split(/\r\n|\r|\n/g),t.renderer&&(n=t.renderer.lines)," "+n.map(function(e){return function(e,n){var i;return i=0===n?0:"1.2em"," "+e+" "}}(this)).join("")+" "}),e.exports={defineSVGRenderer:i,renderShapeToSVG:o}},{"./lineEndCapShapes":8}],15:[function(t,e,n){var i,r,o,s,a=[].slice;o=Array.prototype.slice,i=t("./canvasRenderer").renderShapeToContext,r=t("./svgRenderer").renderShapeToSVG,s={addImageOnload:function(t,e){var n;return n=t.onload,t.onload=function(){return"function"==typeof n&&n(),e()},t},last:function(t,e){return null==e&&(e=null),e?o.call(t,Math.max(t.length-e,0)):t[t.length-1]},classSet:function(t){var e,n;e=[];for(n in t)t[n]&&e.push(n);return e.join(" ")},matchElementSize:function(t,e,n,i){var r;return null==i&&(i=function(){}),r=function(r){return function(){var r,o,s;for(o=0,s=e.length;s>o;o++)r=e[o],r.style.width=t.offsetWidth+"px",r.style.height=t.offsetHeight+"px",null!=r.width&&(r.setAttribute("width",r.offsetWidth*n),r.setAttribute("height",r.offsetHeight*n));return i()}}(this),t.addEventListener("resize",r),window.addEventListener("resize",r),window.addEventListener("orientationchange",r),r()},combineCanvases:function(){var t,e,n,i,r,o,s,h;for(n=1<=arguments.length?a.call(arguments,0):[],t=document.createElement("canvas"),t.width=n[0].width,t.height=n[0].height,r=0,s=n.length;s>r;r++)e=n[r],t.width=Math.max(e.width,t.width),t.height=Math.max(e.height,t.height);for(i=t.getContext("2d"),o=0,h=n.length;h>o;o++)e=n[o],i.drawImage(e,0,0);return t},renderShapes:function(t,e,n,r){var o,s,a,h;for(null==n&&(n=1),null==r&&(r=null),r=r||document.createElement("canvas"),r.width=e.width*n,r.height=e.height*n,o=r.getContext("2d"),o.translate(-e.x*n,-e.y*n),o.scale(n,n),s=0,a=t.length;a>s;s++)h=t[s],i(o,h);return r},renderShapesToSVG:function(t,e,n){var i,o,s,a;return s=e.x,a=e.y,o=e.width,i=e.height,(" "+t.map(r).join("")+" ").replace(/(\r\n|\n|\r)/gm,"")},getBoundingRect:function(t,e,n){var i,r,o,s,a,h,u;if(!t.length)return{x:0,y:0,width:e,height:n};for(a=t[0].x,h=t[0].y,o=t[0].x+t[0].width,s=t[0].y+t[0].height,i=0,r=t.length;r>i;i++)u=t[i],a=Math.floor(Math.min(u.x,a)),h=Math.floor(Math.min(u.y,h)),o=Math.ceil(Math.max(o,u.x+u.width)),s=Math.ceil(Math.max(s,u.y+u.height));return a=e?0:a,h=n?0:h,o=e||o,s=n||s,{x:a,y:h,width:o-a,height:s-h}},getDefaultImageRect:function(t,e,n){var i,r,o;return null==e&&(e={width:0,height:0}),null==n&&(n={top:0,right:0,bottom:0,left:0}),o=e.width,i=e.height,r=s.getBoundingRect(t,"infinite"===o?0:o,"infinite"===i?0:i),r.x-=n.left,r.y-=n.top,r.width+=n.left+n.right,r.height+=n.top+n.bottom,r},getBackingScale:function(t){return null==window.devicePixelRatio?1:window.devicePixelRatio>1?window.devicePixelRatio:1},requestAnimationFrame:(window.requestAnimationFrame||window.setTimeout).bind(window),getGUID:function(){var t;return t=function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)},function(){return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}}(),requestAnimationFrame:function(t){return window.webkitRequestAnimationFrame?window.webkitRequestAnimationFrame(t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.mozRequestAnimationFrame?window.mozRequestAnimationFrame(t):setTimeout(t,0)},cancelAnimationFrame:function(t){return window.webkitCancelRequestAnimationFrame?window.webkitCancelRequestAnimationFrame(t):window.webkitCancelAnimationFrame?window.webkitCancelAnimationFrame(t):window.cancelAnimationFrame?window.cancelAnimationFrame(t):window.mozCancelAnimationFrame?window.mozCancelAnimationFrame(t):clearTimeout(t)}},e.exports=s},{"./canvasRenderer":5,"./svgRenderer":14}],16:[function(t,e,n){"use strict";!function(){function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n}t.prototype=window.CustomEvent.prototype,window.CustomEvent=t}()},{}],17:[function(t,e,n){"use strict";var i=!1;CanvasRenderingContext2D.prototype.setLineDash||(CanvasRenderingContext2D.prototype.setLineDash=function(){i||(console.warn("context2D.setLineDash is a no-op in this browser."),i=!0)}),e.exports=null},{}],18:[function(t,e,n){var i,r,o,s,a,h,u,c,l,p,d,f,g,y,m,S,x,v;t("./ie_customevent"),t("./ie_setLineDash"),i=t("./core/LiterallyCanvas"),h=t("./core/defaultOptions"),o=t("./core/canvasRenderer"),S=t("./core/svgRenderer"),m=t("./core/shapes"),v=t("./core/util"),f=t("./core/renderSnapshotToImage"),g=t("./core/renderSnapshotToSVG"),p=t("./core/localization").localize,s={snapshotToShapes:function(t){var e,n,i,r,o;for(i=t.shapes,r=[],e=0,n=i.length;n>e;e++)o=i[e],r.push(m.JSONToShape(o));return r},snapshotJSONToShapes:function(t){return s.snapshotToShapes(JSON.parse(t))}},r=t("./tools/base"),x={Pencil:t("./tools/Pencil"),Eraser:t("./tools/Eraser"),Line:t("./tools/Line"),Rectangle:t("./tools/Rectangle"),Ellipse:t("./tools/Ellipse"),Text:t("./tools/Text"),Polygon:t("./tools/Polygon"),Pan:t("./tools/Pan"),Eyedropper:t("./tools/Eyedropper"),SelectShape:t("./tools/SelectShape"),Tool:r.Tool,ToolWithStroke:r.ToolWithStroke},u=h.tools,a=h.imageURLPrefix,y=function(t){return a=t,h.imageURLPrefix=t},c=function(t,e){var n,i,r,o,s;null==e&&(e={});for(o in h)o in e||(e[o]=h[o]);for(s=t.children,i=0,r=s.length;r>i;i++)n=s[i],t.removeChild(n);return l(t,e)},l=function(t,e){var n,r,o;return o=t.className,-1===[" "," "].join(t.className).indexOf(" literally ")&&(t.className=t.className+" literally"),t.className=t.className+" toolbar-hidden",n=document.createElement("div"),n.className="lc-drawing",t.appendChild(n),r=new i(n,e),r.teardown=function(){var e,n,i,s;for(r._teardown(),s=t.children,n=0,i=s.length;i>n;n++)e=s[n],t.removeChild(e);return t.className=o},"onInit"in e&&e.onInit(r),r},d=function(t){return t.fn.literallycanvas=function(t){return null==t&&(t={}),this.each(function(e){return function(e,n){return n.literallycanvas=c(n,t)}}(this)),this}},"undefined"!=typeof window&&(window.LC={init:c},window.$&&d(window.$)),e.exports={init:c,registerJQueryPlugin:d,util:v,tools:x,setDefaultImageURLPrefix:y,defaultTools:u,defineShape:m.defineShape,createShape:m.createShape,JSONToShape:m.JSONToShape,shapeToJSON:m.shapeToJSON,defineCanvasRenderer:o.defineCanvasRenderer,renderShapeToContext:o.renderShapeToContext,renderShapeToCanvas:o.renderShapeToCanvas,renderShapesToCanvas:v.renderShapes,defineSVGRenderer:S.defineSVGRenderer,renderShapeToSVG:S.renderShapeToSVG,renderShapesToSVG:v.renderShapesToSVG,snapshotToShapes:s.snapshotToShapes,snapshotJSONToShapes:s.snapshotJSONToShapes,renderSnapshotToImage:f,renderSnapshotToSVG:g,localize:p}},{"./core/LiterallyCanvas":1,"./core/canvasRenderer":5,"./core/defaultOptions":6,"./core/localization":9,"./core/renderSnapshotToImage":11,"./core/renderSnapshotToSVG":12,"./core/shapes":13,"./core/svgRenderer":14,"./core/util":15,"./ie_customevent":16,"./ie_setLineDash":17,"./tools/Ellipse":19,"./tools/Eraser":20,"./tools/Eyedropper":21,"./tools/Line":22,"./tools/Pan":23,"./tools/Pencil":24,"./tools/Polygon":25,"./tools/Rectangle":26,"./tools/SelectShape":27,"./tools/Text":28,"./tools/base":29}],19:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Ellipse",e.prototype.iconName="ellipse",e.prototype.begin=function(t,e,n){return this.currentShape=o("Ellipse",{x:t,y:e,strokeWidth:this.strokeWidth,strokeColor:n.getColor("primary"),fillColor:n.getColor("secondary")})},e.prototype["continue"]=function(t,e,n){return this.currentShape.width=t-this.currentShape.x,this.currentShape.height=e-this.currentShape.y,n.drawShapeInProgress(this.currentShape)},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape)},e}(r)},{"../core/shapes":13,"./base":29}],20:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./Pencil"),o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Eraser",e.prototype.iconName="eraser",e.prototype.makePoint=function(t,e,n){return o("Point",{x:t,y:e,size:this.strokeWidth,color:"#000"})},e.prototype.makeShape=function(){return o("ErasedLinePath")},e}(r)},{"../core/shapes":13,"./Pencil":24}],21:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").Tool,o=function(t,e){var n,i,r;return i=e.x,r=e.y,n=t.getImageData(i,r,1,1).data,n[3]?"rgb("+n[0]+", "+n[1]+", "+n[2]+")":null},e.exports=i=function(t){function e(t){e.__super__.constructor.call(this,t),this.strokeOrFill="stroke"}return s(e,t),e.prototype.name="Eyedropper",e.prototype.iconName="eyedropper",e.prototype.optionsStyle="stroke-or-fill",e.prototype.readColor=function(t,e,n){var i,r,s,a;return a=n.getDefaultImageRect(),i=n.getImage(),s=o(i.getContext("2d"),{x:t-a.x,y:e-a.y}),r=s||n.getColor("background"),"stroke"===this.strokeOrFill?n.setColor("primary",s):n.setColor("secondary",s)},e.prototype.begin=function(t,e,n){return this.readColor(t,e,n)},e.prototype["continue"]=function(t,e,n){return this.readColor(t,e,n)},e}(r)},{"./base":29}],22:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Line",e.prototype.iconName="line",e.prototype.optionsStyle="line-options-and-stroke-width",e.prototype.begin=function(t,e,n){return this.currentShape=o("Line",{x1:t,y1:e,x2:t,y2:e,strokeWidth:this.strokeWidth,dash:function(){switch(!1){case!this.isDashed:return[2*this.strokeWidth,4*this.strokeWidth];default:return null}}.call(this),endCapShapes:this.hasEndArrow?[null,"arrow"]:null,color:n.getColor("primary")})},e.prototype["continue"]=function(t,e,n){return this.currentShape.x2=t,this.currentShape.y2=e,n.drawShapeInProgress(this.currentShape)},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape)},e}(r)},{"../core/shapes":13,"./base":29}],23:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").Tool,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Pan",e.prototype.iconName="pan",e.prototype.usesSimpleAPI=!1,e.prototype.didBecomeActive=function(t){var e;return e=[],this.unsubscribe=function(t){return function(){var t,n,i,r;for(r=[],n=0,i=e.length;i>n;n++)t=e[n],r.push(t());return r}}(this),e.push(t.on("lc-pointerdown",function(e){return function(n){var i,r;return i=n.rawX,r=n.rawY,e.oldPosition=t.position,e.pointerStart={x:i,y:r}}}(this))),e.push(t.on("lc-pointerdrag",function(e){return function(n){var i,r,o;return r=n.rawX,o=n.rawY,i={x:(r-e.pointerStart.x)*t.backingScale,y:(o-e.pointerStart.y)*t.backingScale},t.setPan(e.oldPosition.x+i.x,e.oldPosition.y+i.y)}}(this)))},e.prototype.willBecomeInactive=function(t){return this.unsubscribe()},e}(r)},{"../core/shapes":13,"./base":29}],24:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Pencil",e.prototype.iconName="pencil",e.prototype.eventTimeThreshold=10,e.prototype.begin=function(t,e,n){return this.color=n.getColor("primary"),this.currentShape=this.makeShape(),this.currentShape.addPoint(this.makePoint(t,e,n)),this.lastEventTime=Date.now()},e.prototype["continue"]=function(t,e,n){var i;return i=Date.now()-this.lastEventTime,i>this.eventTimeThreshold?(this.lastEventTime+=i,this.currentShape.addPoint(this.makePoint(t,e,n)),n.drawShapeInProgress(this.currentShape)):void 0},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape),this.currentShape=void 0},e.prototype.makePoint=function(t,e,n){return o("Point",{x:t,y:e,size:this.strokeWidth,color:this.color})},e.prototype.makeShape=function(){return o("LinePath")},e}(r)},{"../core/shapes":13,"./base":29}],25:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Polygon",e.prototype.iconName="polygon",e.prototype.usesSimpleAPI=!1,e.prototype.didBecomeActive=function(t){var n,i,r,o,s,a,h;return e.__super__.didBecomeActive.call(this,t),h=[],this.polygonUnsubscribe=function(t){return function(){var t,e,n,i;for(i=[],e=0,n=h.length;n>e;e++)t=h[e],i.push(t());return i}}(this),this.points=null,this.maybePoint=null,r=function(e){return function(){return e._getWillFinish()?e._close(t):(t.trigger("lc-polygon-started"),e.points?e.points.push(e.maybePoint):e.points=[e.maybePoint],e.maybePoint={x:e.maybePoint.x,y:e.maybePoint.y},t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main"))}}(this),i=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.maybePoint?(e.maybePoint.x=i,e.maybePoint.y=r,t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main")):void 0}}(this),n=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.maybePoint={x:i,y:r},t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main")}}(this),a=function(e){return function(){return e.maybePoint={x:1/0,y:1/0},e._close(t)}}(this),s=function(e){return function(){return e.maybePoint=e.points[0],e._close(t)}}(this),o=function(e){return function(){return e._cancel(t)}}(this),h.push(t.on("drawingChange",function(e){return function(){return e._cancel(t)}}(this))),h.push(t.on("lc-pointerdown",n)),h.push(t.on("lc-pointerdrag",i)),h.push(t.on("lc-pointermove",i)),h.push(t.on("lc-pointerup",r)),h.push(t.on("lc-polygon-finishopen",a)),h.push(t.on("lc-polygon-finishclosed",s)),h.push(t.on("lc-polygon-cancel",o))},e.prototype.willBecomeInactive=function(t){return e.__super__.willBecomeInactive.call(this,t),(this.points||this.maybePoint)&&this._cancel(t),this.polygonUnsubscribe()},e.prototype._getArePointsClose=function(t,e){return Math.abs(t.x-e.x)+Math.abs(t.y-e.y)<10},e.prototype._getWillClose=function(){return this.points&&this.points.length>1&&this.maybePoint?this._getArePointsClose(this.points[0],this.maybePoint):!1},e.prototype._getWillFinish=function(){return this.points&&this.points.length>1&&this.maybePoint?this._getArePointsClose(this.points[0],this.maybePoint)||this._getArePointsClose(this.points[this.points.length-1],this.maybePoint):!1; +},e.prototype._cancel=function(t){return t.trigger("lc-polygon-stopped"),this.maybePoint=null,this.points=null,t.setShapesInProgress([]),t.repaintLayer("main")},e.prototype._close=function(t){return t.trigger("lc-polygon-stopped"),t.setShapesInProgress([]),this.points.length>2&&t.saveShape(this._getShape(t,!1)),this.maybePoint=null,this.points=null},e.prototype._getShapes=function(t,e){var n;return null==e&&(e=!0),n=this._getShape(t,e),n?[n]:[]},e.prototype._getShape=function(t,e){var n;return null==e&&(e=!0),n=[],this.points&&(n=n.concat(this.points)),!e&&n.length<3?null:(e&&this.maybePoint&&n.push(this.maybePoint),n.length>1?o("Polygon",{isClosed:this._getWillClose(),strokeColor:t.getColor("primary"),fillColor:t.getColor("secondary"),strokeWidth:this.strokeWidth,points:n.map(function(t){return o("Point",t)})}):null)},e.prototype.optionsStyle="polygon-and-stroke-width",e}(r)},{"../core/shapes":13,"./base":29}],26:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Rectangle",e.prototype.iconName="rectangle",e.prototype.begin=function(t,e,n){return this.currentShape=o("Rectangle",{x:t,y:e,strokeWidth:this.strokeWidth,strokeColor:n.getColor("primary"),fillColor:n.getColor("secondary")})},e.prototype["continue"]=function(t,e,n){return this.currentShape.width=t-this.currentShape.x,this.currentShape.height=e-this.currentShape.y,n.drawShapeInProgress(this.currentShape)},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape)},e}(r)},{"../core/shapes":13,"./base":29}],27:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").Tool,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(t){this.selectCanvas=document.createElement("canvas"),this.selectCanvas.style["background-color"]="transparent",this.selectCtx=this.selectCanvas.getContext("2d")}return s(e,t),e.prototype.name="SelectShape",e.prototype.usesSimpleAPI=!1,e.prototype.didBecomeActive=function(t){var e,n,i,r;return r=[],this._selectShapeUnsubscribe=function(t){return function(){var t,e,n,i;for(i=[],e=0,n=r.length;n>e;e++)t=r[e],i.push(t());return i}}(this),e=function(e){return function(n){var i,r,s,a;return s=n.x,a=n.y,e.didDrag=!1,r=e._getPixel(s,a,t,e.selectCtx),e.selectedShape=t.shapes[r],null!=e.selectedShape?(t.trigger("shapeSelected",{selectedShape:e.selectedShape}),t.setShapesInProgress([e.selectedShape,o("SelectionBox",{shape:e.selectedShape,handleSize:0})]),t.repaintLayer("main"),i=e.selectedShape.getBoundingRect(),e.dragOffset={x:s-i.x,y:a-i.y}):void 0}}(this),n=function(e){return function(n){var i,r;return i=n.x,r=n.y,null!=e.selectedShape?(e.didDrag=!0,e.selectedShape.setUpperLeft({x:i-e.dragOffset.x,y:r-e.dragOffset.y}),t.setShapesInProgress([e.selectedShape,o("SelectionBox",{shape:e.selectedShape,handleSize:0})]),t.repaintLayer("main")):void 0}}(this),i=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.didDrag?(e.didDrag=!1,t.trigger("shapeMoved",{shape:e.selectedShape}),t.trigger("drawingChange",{}),t.repaintLayer("main"),e._drawSelectCanvas(t)):void 0}}(this),r.push(t.on("lc-pointerdown",e)),r.push(t.on("lc-pointerdrag",n)),r.push(t.on("lc-pointerup",i)),this._drawSelectCanvas(t)},e.prototype.willBecomeInactive=function(t){return this._selectShapeUnsubscribe(),t.setShapesInProgress([])},e.prototype._drawSelectCanvas=function(t){var e;return this.selectCanvas.width=t.canvas.width,this.selectCanvas.height=t.canvas.height,this.selectCtx.clearRect(0,0,this.selectCanvas.width,this.selectCanvas.height),e=t.shapes.map(function(t){return function(e,n){return o("SelectionBox",{shape:e,handleSize:0,backgroundColor:"#"+t._intToHex(n)})}}(this)),t.draw(e,this.selectCtx)},e.prototype._intToHex=function(t){return("000000"+t.toString(16)).slice(-6)},e.prototype._getPixel=function(t,e,n,i){var r,o;return r=n.drawingCoordsToClientCoords(t,e),o=i.getImageData(r.x,r.y,1,1).data,o[3]?parseInt(this._rgbToHex(o[0],o[1],o[2]),16):null},e.prototype._componentToHex=function(t){var e;return e=t.toString(16),("0"+e).slice(-2)},e.prototype._rgbToHex=function(t,e,n){return""+this._componentToHex(t)+this._componentToHex(e)+this._componentToHex(n)},e}(r)},{"../core/shapes":13,"./base":29}],28:[function(t,e,n){var i,r,o,s,a=function(t,e){function n(){this.constructor=t}for(var i in e)h.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},h={}.hasOwnProperty;r=t("./base").Tool,o=t("../core/shapes").createShape,s=function(t,e){return t.xe.x+e.width?!1:t.y>e.y+e.height?!1:!0},e.exports=i=function(t){function e(){this.text="",this.font="bold 18px sans-serif",this.currentShape=null,this.currentShapeState=null,this.initialShapeBoundingRect=null,this.dragAction=null,this.didDrag=!1}return a(e,t),e.prototype.name="Text",e.prototype.iconName="text",e.prototype.didBecomeActive=function(t){var e,n,i;return n=[],this.unsubscribe=function(t){return function(){var t,e,i,r;for(r=[],e=0,i=n.length;i>e;e++)t=n[e],r.push(t());return r}}(this),e=function(e){return function(){return e._ensureNotEditing(t),e._clearCurrentShape(t),t.repaintLayer("main")}}(this),i=function(e){return function(){return e._updateInputEl(t)}}(this),n.push(t.on("drawingChange",e)),n.push(t.on("zoom",i)),n.push(t.on("imageSizeChange",i)),n.push(t.on("snapshotLoad",function(e){return function(){return e._clearCurrentShape(t),t.repaintLayer("main")}}(this))),n.push(t.on("primaryColorChange",function(e){return function(n){return e.currentShape?(e.currentShape.color=n,e._updateInputEl(t),t.repaintLayer("main")):void 0}}(this))),n.push(t.on("setFont",function(e){return function(n){return e.currentShape?(e.font=n,e.currentShape.setFont(n),e._setShapesInProgress(t),e._updateInputEl(t),t.repaintLayer("main")):void 0}}(this)))},e.prototype.willBecomeInactive=function(t){return this.currentShape&&(this._ensureNotEditing(t),this.commit(t)),this.unsubscribe()},e.prototype.setText=function(t){return this.text=t},e.prototype._ensureNotEditing=function(t){return"editing"===this.currentShapeState?this._exitEditingState(t):void 0},e.prototype._clearCurrentShape=function(t){return this.currentShape=null,this.initialShapeBoundingRect=null,this.currentShapeState=null,t.setShapesInProgress([])},e.prototype.commit=function(t){return this.currentShape.text&&t.saveShape(this.currentShape),this._clearCurrentShape(t),t.repaintLayer("main")},e.prototype._getSelectionShape=function(t,e){return null==e&&(e=null),o("SelectionBox",{shape:this.currentShape,ctx:t,backgroundColor:e})},e.prototype._setShapesInProgress=function(t){switch(this.currentShapeState){case"selected":return t.setShapesInProgress([this._getSelectionShape(t.ctx),this.currentShape]);case"editing":return t.setShapesInProgress([this._getSelectionShape(t.ctx,"#fff")]);default:return t.setShapesInProgress([this.currentShape])}},e.prototype.begin=function(t,e,n){var i,r,a,h;return this.dragAction="none",this.didDrag=!1,"selected"===this.currentShapeState||"editing"===this.currentShapeState?(i=this.currentShape.getBoundingRect(n.ctx),h=this._getSelectionShape(n.ctx),a=h.getBoundingRect(),r={x:t,y:e},s(r,i)&&(this.dragAction="move"),s(r,h.getBottomRightHandleRect())&&(this.dragAction="resizeBottomRight"),s(r,h.getTopLeftHandleRect())&&(this.dragAction="resizeTopLeft"),s(r,h.getBottomLeftHandleRect())&&(this.dragAction="resizeBottomLeft"),s(r,h.getTopRightHandleRect())&&(this.dragAction="resizeTopRight"),"none"===this.dragAction&&"editing"===this.currentShapeState&&(this.dragAction="stop-editing",this._exitEditingState(n))):(this.color=n.getColor("primary"),this.currentShape=o("Text",{x:t,y:e,text:this.text,color:this.color,font:this.font,v:1}),this.dragAction="place",this.currentShapeState="selected"),"none"===this.dragAction?void this.commit(n):(this.initialShapeBoundingRect=this.currentShape.getBoundingRect(n.ctx),this.dragOffset={x:t-this.initialShapeBoundingRect.x,y:e-this.initialShapeBoundingRect.y},this._setShapesInProgress(n),n.repaintLayer("main"))},e.prototype["continue"]=function(t,e,n){var i,r,o;if("none"!==this.dragAction){switch(i=this.initialShapeBoundingRect,o=i.x+i.width,r=i.y+i.height,this.dragAction){case"place":this.currentShape.x=t,this.currentShape.y=e,this.didDrag=!0;break;case"move":this.currentShape.x=t-this.dragOffset.x,this.currentShape.y=e-this.dragOffset.y,this.didDrag=!0;break;case"resizeBottomRight":this.currentShape.setSize(t-(this.dragOffset.x-this.initialShapeBoundingRect.width)-i.x,e-(this.dragOffset.y-this.initialShapeBoundingRect.height)-i.y);break;case"resizeTopLeft":this.currentShape.setSize(o-t+this.dragOffset.x,r-e+this.dragOffset.y),this.currentShape.setPosition(t-this.dragOffset.x,e-this.dragOffset.y);break;case"resizeBottomLeft":this.currentShape.setSize(o-t+this.dragOffset.x,e-(this.dragOffset.y-this.initialShapeBoundingRect.height)-i.y),this.currentShape.setPosition(t-this.dragOffset.x,this.currentShape.y);break;case"resizeTopRight":this.currentShape.setSize(t-(this.dragOffset.x-this.initialShapeBoundingRect.width)-i.x,r-e+this.dragOffset.y),this.currentShape.setPosition(this.currentShape.x,e-this.dragOffset.y)}return this._setShapesInProgress(n),n.repaintLayer("main"),this._updateInputEl(n)}},e.prototype.end=function(t,e,n){return this.currentShape?(this.currentShape.setSize(this.currentShape.forcedWidth,0),"selected"===this.currentShapeState&&("place"===this.dragAction||"move"===this.dragAction&&!this.didDrag)&&this._enterEditingState(n),this._setShapesInProgress(n),n.repaintLayer("main"),this._updateInputEl(n)):void 0},e.prototype._enterEditingState=function(t){var e;if(this.currentShapeState="editing",this.inputEl)throw"State error";return this.inputEl=document.createElement("textarea"),this.inputEl.className="text-tool-input",this.inputEl.style.position="absolute",this.inputEl.style.transformOrigin="0px 0px",this.inputEl.style.backgroundColor="transparent",this.inputEl.style.border="none",this.inputEl.style.outline="none",this.inputEl.style.margin="0",this.inputEl.style.padding="4px",this.inputEl.style.zIndex="1000",this.inputEl.style.overflow="hidden",this.inputEl.style.resize="none",this.inputEl.value=this.currentShape.text,this.inputEl.addEventListener("mousedown",function(t){return t.stopPropagation()}),this.inputEl.addEventListener("touchstart",function(t){return t.stopPropagation()}),e=function(e){return function(n){return e.currentShape.setText(n.target.value),e.currentShape.enforceMaxBoundingRect(t),e._setShapesInProgress(t),t.repaintLayer("main"),e._updateInputEl(t),n.stopPropagation()}}(this),this.inputEl.addEventListener("keydown",function(e){return function(){return e._updateInputEl(t,!0)}}(this)),this.inputEl.addEventListener("keyup",e),this.inputEl.addEventListener("change",e),this._updateInputEl(t),t.containerEl.appendChild(this.inputEl),this.inputEl.focus(),this._setShapesInProgress(t)},e.prototype._exitEditingState=function(t){return this.currentShapeState="selected",t.containerEl.removeChild(this.inputEl),this.inputEl=null,this._setShapesInProgress(t),t.repaintLayer("main")},e.prototype._updateInputEl=function(t,e){var n,i;return null==e&&(e=!1),this.inputEl?(n=this.currentShape.getBoundingRect(t.ctx,!0),this.inputEl.style.font=this.currentShape.font,this.inputEl.style.color=this.currentShape.color,this.inputEl.style.left=t.position.x/t.backingScale+n.x*t.scale-4+"px",this.inputEl.style.top=t.position.y/t.backingScale+n.y*t.scale-4+"px",e&&!this.currentShape.forcedWidth?this.inputEl.style.width=n.width+10+this.currentShape.renderer.emDashWidth+"px":this.inputEl.style.width=n.width+12+"px",e?this.inputEl.style.height=n.height+10+this.currentShape.renderer.metrics.leading+"px":this.inputEl.style.height=n.height+10+"px",i="scale("+t.scale+")",this.inputEl.style.transform=i,this.inputEl.style.webkitTransform=i,this.inputEl.style.MozTransform=i,this.inputEl.style.msTransform=i,this.inputEl.style.OTransform=i):void 0},e.prototype.optionsStyle="font",e}(r)},{"../core/shapes":13,"./base":29}],29:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;o={},o.Tool=i=function(){function t(){}return t.prototype.name=null,t.prototype.iconName=null,t.prototype.usesSimpleAPI=!0,t.prototype.begin=function(t,e,n){},t.prototype["continue"]=function(t,e,n){},t.prototype.end=function(t,e,n){},t.prototype.optionsStyle=null,t.prototype.didBecomeActive=function(t){},t.prototype.willBecomeInactive=function(t){},t}(),o.ToolWithStroke=r=function(t){function e(t){this.strokeWidth=t.opts.defaultStrokeWidth}return s(e,t),e.prototype.optionsStyle="stroke-width",e.prototype.didBecomeActive=function(t){var e;return e=[],this.unsubscribe=function(t){return function(){var t,n,i,r;for(r=[],n=0,i=e.length;i>n;n++)t=e[n],r.push(t());return r}}(this),e.push(t.on("setStrokeWidth",function(e){return function(n){return e.strokeWidth=n,t.trigger("toolDidUpdateOptions")}}(this)))},e.prototype.willBecomeInactive=function(t){return this.unsubscribe()},e}(i),e.exports=o},{}]},{},[18])(18)}); \ No newline at end of file diff --git a/library/js/literallycanvas/js/literallycanvas.js b/library/js/literallycanvas/js/literallycanvas.js new file mode 100644 index 00000000000..527892f8224 --- /dev/null +++ b/library/js/literallycanvas/js/literallycanvas.js @@ -0,0 +1,6418 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.LC = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ofoo; + * } + * }); + * + * Note: This only checks shallow equality for props and state. If these contain + * complex data structures this mixin may have false-negatives for deeper + * differences. Only mixin to components which have simple props and state, or + * use `forceUpdate()` when you know deep data structures have changed. + */ +var ReactComponentWithPureRenderMixin = { + shouldComponentUpdate: function (nextProps, nextState) { + return shallowCompare(this, nextProps, nextState); + } +}; + +module.exports = ReactComponentWithPureRenderMixin; +},{"./shallowCompare":3}],3:[function(require,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * +* @providesModule shallowCompare +*/ + +'use strict'; + +var shallowEqual = require('fbjs/lib/shallowEqual'); + +/** + * Does a shallow comparison for props and state. + * See ReactComponentWithPureRenderMixin + */ +function shallowCompare(instance, nextProps, nextState) { + return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState); +} + +module.exports = shallowCompare; +},{"fbjs/lib/shallowEqual":4}],4:[function(require,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule shallowEqual + * @typechecks + * + */ + +'use strict'; + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (objA === objB) { + return true; + } + + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + var bHasOwnProperty = hasOwnProperty.bind(objB); + for (var i = 0; i < keysA.length; i++) { + if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { + return false; + } + } + + return true; +} + +module.exports = shallowEqual; +},{}],5:[function(require,module,exports){ +var INFINITE, JSONToShape, LiterallyCanvas, Pencil, actions, bindEvents, createShape, math, ref, renderShapeToContext, renderShapeToSVG, renderSnapshotToImage, renderSnapshotToSVG, shapeToJSON, util, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + slice = [].slice, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +actions = require('./actions'); + +bindEvents = require('./bindEvents'); + +math = require('./math'); + +ref = require('./shapes'), createShape = ref.createShape, shapeToJSON = ref.shapeToJSON, JSONToShape = ref.JSONToShape; + +renderShapeToContext = require('./canvasRenderer').renderShapeToContext; + +renderShapeToSVG = require('./svgRenderer').renderShapeToSVG; + +renderSnapshotToImage = require('./renderSnapshotToImage'); + +renderSnapshotToSVG = require('./renderSnapshotToSVG'); + +Pencil = require('../tools/Pencil'); + +util = require('./util'); + +INFINITE = 'infinite'; + +module.exports = LiterallyCanvas = (function() { + function LiterallyCanvas(arg1, arg2) { + this.setImageSize = bind(this.setImageSize, this); + var containerEl, opts; + opts = null; + containerEl = null; + if (arg1 instanceof HTMLElement) { + containerEl = arg1; + opts = arg2; + } else { + opts = arg1; + } + this.opts = opts || {}; + this.config = { + zoomMin: opts.zoomMin || 0.2, + zoomMax: opts.zoomMax || 4.0, + zoomStep: opts.zoomStep || 0.2 + }; + this.colors = { + primary: opts.primaryColor || '#000', + secondary: opts.secondaryColor || '#fff', + background: opts.backgroundColor || 'transparent' + }; + this.watermarkImage = opts.watermarkImage; + this.watermarkScale = opts.watermarkScale || 1; + this.backgroundCanvas = document.createElement('canvas'); + this.backgroundCtx = this.backgroundCanvas.getContext('2d'); + this.canvas = document.createElement('canvas'); + this.canvas.style['background-color'] = 'transparent'; + this.buffer = document.createElement('canvas'); + this.buffer.style['background-color'] = 'transparent'; + this.ctx = this.canvas.getContext('2d'); + this.bufferCtx = this.buffer.getContext('2d'); + this.backingScale = util.getBackingScale(this.ctx); + this.backgroundShapes = opts.backgroundShapes || []; + this._shapesInProgress = []; + this.shapes = []; + this.undoStack = []; + this.redoStack = []; + this.isDragging = false; + this.position = { + x: 0, + y: 0 + }; + this.scale = 1.0; + this.setTool(new this.opts.tools[0](this)); + this.width = opts.imageSize.width || INFINITE; + this.height = opts.imageSize.height || INFINITE; + this.setZoom(this.scale); + if (opts.snapshot) { + this.loadSnapshot(opts.snapshot); + } + this.isBound = false; + if (containerEl) { + this.bindToElement(containerEl); + } + } + + LiterallyCanvas.prototype.bindToElement = function(containerEl) { + var ref1, repaintAll; + if (this.containerEl) { + console.warn("Trying to bind Literally Canvas to a DOM element more than once is unsupported."); + return; + } + this.containerEl = containerEl; + this._unsubscribeEvents = bindEvents(this, this.containerEl, this.opts.keyboardShortcuts); + this.containerEl.style['background-color'] = this.colors.background; + this.containerEl.appendChild(this.backgroundCanvas); + this.containerEl.appendChild(this.canvas); + this.isBound = true; + repaintAll = (function(_this) { + return function() { + _this.keepPanInImageBounds(); + return _this.repaintAllLayers(); + }; + })(this); + util.matchElementSize(this.containerEl, [this.backgroundCanvas, this.canvas], this.backingScale, repaintAll); + if (this.watermarkImage) { + this.watermarkImage.onload = (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this); + } + if ((ref1 = this.tool) != null) { + ref1.didBecomeActive(this); + } + return repaintAll(); + }; + + LiterallyCanvas.prototype._teardown = function() { + this.tool.willBecomeInactive(this); + if (typeof this._unsubscribeEvents === "function") { + this._unsubscribeEvents(); + } + this.tool = null; + this.containerEl = null; + return this.isBound = false; + }; + + LiterallyCanvas.prototype.trigger = function(name, data) { + this.canvas.dispatchEvent(new CustomEvent(name, { + detail: data + })); + return null; + }; + + LiterallyCanvas.prototype.on = function(name, fn) { + var wrapper; + wrapper = function(e) { + return fn(e.detail); + }; + this.canvas.addEventListener(name, wrapper); + return (function(_this) { + return function() { + return _this.canvas.removeEventListener(name, wrapper); + }; + })(this); + }; + + LiterallyCanvas.prototype.getRenderScale = function() { + return this.scale * this.backingScale; + }; + + LiterallyCanvas.prototype.clientCoordsToDrawingCoords = function(x, y) { + return { + x: (x * this.backingScale - this.position.x) / this.getRenderScale(), + y: (y * this.backingScale - this.position.y) / this.getRenderScale() + }; + }; + + LiterallyCanvas.prototype.drawingCoordsToClientCoords = function(x, y) { + return { + x: x * this.getRenderScale() + this.position.x, + y: y * this.getRenderScale() + this.position.y + }; + }; + + LiterallyCanvas.prototype.setImageSize = function(width, height) { + this.width = width || INFINITE; + this.height = height || INFINITE; + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('imageSizeChange', { + width: this.width, + height: this.height + }); + }; + + LiterallyCanvas.prototype.setTool = function(tool) { + var ref1; + if (this.isBound) { + if ((ref1 = this.tool) != null) { + ref1.willBecomeInactive(this); + } + } + this.tool = tool; + this.trigger('toolChange', { + tool: tool + }); + if (this.isBound) { + return this.tool.didBecomeActive(this); + } + }; + + LiterallyCanvas.prototype.setShapesInProgress = function(newVal) { + return this._shapesInProgress = newVal; + }; + + LiterallyCanvas.prototype.pointerDown = function(x, y) { + var p; + p = this.clientCoordsToDrawingCoords(x, y); + if (this.tool.usesSimpleAPI) { + this.tool.begin(p.x, p.y, this); + this.isDragging = true; + return this.trigger("drawStart", { + tool: this.tool + }); + } else { + this.isDragging = true; + return this.trigger("lc-pointerdown", { + tool: this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + }; + + LiterallyCanvas.prototype.pointerMove = function(x, y) { + return util.requestAnimationFrame((function(_this) { + return function() { + var p, ref1; + p = _this.clientCoordsToDrawingCoords(x, y); + if ((ref1 = _this.tool) != null ? ref1.usesSimpleAPI : void 0) { + if (_this.isDragging) { + _this.tool["continue"](p.x, p.y, _this); + return _this.trigger("drawContinue", { + tool: _this.tool + }); + } + } else { + if (_this.isDragging) { + return _this.trigger("lc-pointerdrag", { + tool: _this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } else { + return _this.trigger("lc-pointermove", { + tool: _this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + } + }; + })(this)); + }; + + LiterallyCanvas.prototype.pointerUp = function(x, y) { + var p; + p = this.clientCoordsToDrawingCoords(x, y); + if (this.tool.usesSimpleAPI) { + if (this.isDragging) { + this.tool.end(p.x, p.y, this); + this.isDragging = false; + return this.trigger("drawEnd", { + tool: this.tool + }); + } + } else { + this.isDragging = false; + return this.trigger("lc-pointerup", { + tool: this.tool, + x: p.x, + y: p.y, + rawX: x, + rawY: y + }); + } + }; + + LiterallyCanvas.prototype.setColor = function(name, color) { + this.colors[name] = color; + if (!this.isBound) { + return; + } + switch (name) { + case 'background': + this.containerEl.style.backgroundColor = this.colors.background; + this.repaintLayer('background'); + break; + case 'primary': + this.repaintLayer('main'); + break; + case 'secondary': + this.repaintLayer('main'); + } + this.trigger(name + "ColorChange", this.colors[name]); + if (name === 'background') { + return this.trigger("drawingChange"); + } + }; + + LiterallyCanvas.prototype.getColor = function(name) { + return this.colors[name]; + }; + + LiterallyCanvas.prototype.saveShape = function(shape, triggerShapeSaveEvent, previousShapeId) { + if (triggerShapeSaveEvent == null) { + triggerShapeSaveEvent = true; + } + if (previousShapeId == null) { + previousShapeId = null; + } + if (!previousShapeId) { + previousShapeId = this.shapes.length ? this.shapes[this.shapes.length - 1].id : null; + } + this.execute(new actions.AddShapeAction(this, shape, previousShapeId)); + if (triggerShapeSaveEvent) { + this.trigger('shapeSave', { + shape: shape, + previousShapeId: previousShapeId + }); + } + return this.trigger('drawingChange'); + }; + + LiterallyCanvas.prototype.pan = function(x, y) { + return this.setPan(this.position.x - x, this.position.y - y); + }; + + LiterallyCanvas.prototype.keepPanInImageBounds = function() { + var ref1, renderScale, x, y; + renderScale = this.getRenderScale(); + ref1 = this.position, x = ref1.x, y = ref1.y; + if (this.width !== INFINITE) { + if (this.canvas.width > this.width * renderScale) { + x = (this.canvas.width - this.width * renderScale) / 2; + } else { + x = Math.max(Math.min(0, x), this.canvas.width - this.width * renderScale); + } + } + if (this.height !== INFINITE) { + if (this.canvas.height > this.height * renderScale) { + y = (this.canvas.height - this.height * renderScale) / 2; + } else { + y = Math.max(Math.min(0, y), this.canvas.height - this.height * renderScale); + } + } + return this.position = { + x: x, + y: y + }; + }; + + LiterallyCanvas.prototype.setPan = function(x, y) { + this.position = { + x: x, + y: y + }; + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('pan', { + x: this.position.x, + y: this.position.y + }); + }; + + LiterallyCanvas.prototype.zoom = function(factor) { + var newScale; + newScale = this.scale + factor; + newScale = Math.max(newScale, this.config.zoomMin); + newScale = Math.min(newScale, this.config.zoomMax); + newScale = Math.round(newScale * 100) / 100; + return this.setZoom(newScale); + }; + + LiterallyCanvas.prototype.setZoom = function(scale) { + var oldScale; + oldScale = this.scale; + this.scale = scale; + this.position.x = math.scalePositionScalar(this.position.x, this.canvas.width, oldScale, this.scale); + this.position.y = math.scalePositionScalar(this.position.y, this.canvas.height, oldScale, this.scale); + this.keepPanInImageBounds(); + this.repaintAllLayers(); + return this.trigger('zoom', { + oldScale: oldScale, + newScale: this.scale + }); + }; + + LiterallyCanvas.prototype.setWatermarkImage = function(newImage) { + this.watermarkImage = newImage; + util.addImageOnload(newImage, (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this)); + if (newImage.width) { + return this.repaintLayer('background'); + } + }; + + LiterallyCanvas.prototype.repaintAllLayers = function() { + var i, key, len, ref1; + ref1 = ['background', 'main']; + for (i = 0, len = ref1.length; i < len; i++) { + key = ref1[i]; + this.repaintLayer(key); + } + return null; + }; + + LiterallyCanvas.prototype.repaintLayer = function(repaintLayerKey, dirty) { + var retryCallback; + if (dirty == null) { + dirty = repaintLayerKey === 'main'; + } + if (!this.isBound) { + return; + } + switch (repaintLayerKey) { + case 'background': + this.backgroundCtx.clearRect(0, 0, this.backgroundCanvas.width, this.backgroundCanvas.height); + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('background'); + }; + })(this); + if (this.watermarkImage) { + this._renderWatermark(this.backgroundCtx, true, retryCallback); + } + this.draw(this.backgroundShapes, this.backgroundCtx, retryCallback); + break; + case 'main': + retryCallback = (function(_this) { + return function() { + return _this.repaintLayer('main', true); + }; + })(this); + if (dirty) { + this.buffer.width = this.canvas.width; + this.buffer.height = this.canvas.height; + this.bufferCtx.clearRect(0, 0, this.buffer.width, this.buffer.height); + this.draw(this.shapes, this.bufferCtx, retryCallback); + } + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + if (this.canvas.width > 0 && this.canvas.height > 0) { + this.ctx.fillStyle = '#ccc'; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.clipped(((function(_this) { + return function() { + _this.ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height); + return _this.ctx.drawImage(_this.buffer, 0, 0); + }; + })(this)), this.ctx); + this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + var i, len, ref1, results, shape; + ref1 = _this._shapesInProgress; + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + shape = ref1[i]; + results.push(renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + })); + } + return results; + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + } + } + return this.trigger('repaint', { + layerKey: repaintLayerKey + }); + }; + + LiterallyCanvas.prototype._renderWatermark = function(ctx, worryAboutRetina, retryCallback) { + if (worryAboutRetina == null) { + worryAboutRetina = true; + } + if (!this.watermarkImage.width) { + this.watermarkImage.onload = retryCallback; + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(this.watermarkScale, this.watermarkScale); + if (worryAboutRetina) { + ctx.scale(this.backingScale, this.backingScale); + } + ctx.drawImage(this.watermarkImage, -this.watermarkImage.width / 2, -this.watermarkImage.height / 2); + return ctx.restore(); + }; + + LiterallyCanvas.prototype.drawShapeInProgress = function(shape) { + this.repaintLayer('main', false); + return this.clipped(((function(_this) { + return function() { + return _this.transformed((function() { + return renderShapeToContext(_this.ctx, shape, { + bufferCtx: _this.bufferCtx, + shouldOnlyDrawLatest: true + }); + }), _this.ctx, _this.bufferCtx); + }; + })(this)), this.ctx, this.bufferCtx); + }; + + LiterallyCanvas.prototype.draw = function(shapes, ctx, retryCallback) { + var drawShapes; + if (!shapes.length) { + return; + } + drawShapes = (function(_this) { + return function() { + var i, len, results, shape; + results = []; + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + results.push(renderShapeToContext(ctx, shape, { + retryCallback: retryCallback + })); + } + return results; + }; + })(this); + return this.clipped(((function(_this) { + return function() { + return _this.transformed(drawShapes, ctx); + }; + })(this)), ctx); + }; + + LiterallyCanvas.prototype.clipped = function() { + var contexts, ctx, fn, height, i, j, len, len1, results, width, x, y; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + x = this.width === INFINITE ? 0 : this.position.x; + y = this.height === INFINITE ? 0 : this.position.y; + width = (function() { + switch (this.width) { + case INFINITE: + return this.canvas.width; + default: + return this.width * this.getRenderScale(); + } + }).call(this); + height = (function() { + switch (this.height) { + case INFINITE: + return this.canvas.height; + default: + return this.height * this.getRenderScale(); + } + }).call(this); + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.clip(); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.transformed = function() { + var contexts, ctx, fn, i, j, len, len1, results, scale; + fn = arguments[0], contexts = 2 <= arguments.length ? slice.call(arguments, 1) : []; + for (i = 0, len = contexts.length; i < len; i++) { + ctx = contexts[i]; + ctx.save(); + ctx.translate(Math.floor(this.position.x), Math.floor(this.position.y)); + scale = this.getRenderScale(); + ctx.scale(scale, scale); + } + fn(); + results = []; + for (j = 0, len1 = contexts.length; j < len1; j++) { + ctx = contexts[j]; + results.push(ctx.restore()); + } + return results; + }; + + LiterallyCanvas.prototype.clear = function(triggerClearEvent) { + var newShapes, oldShapes; + if (triggerClearEvent == null) { + triggerClearEvent = true; + } + oldShapes = this.shapes; + newShapes = []; + this.setShapesInProgress([]); + this.execute(new actions.ClearAction(this, oldShapes, newShapes)); + this.repaintLayer('main'); + if (triggerClearEvent) { + this.trigger('clear', null); + } + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.execute = function(action) { + this.undoStack.push(action); + action["do"](); + return this.redoStack = []; + }; + + LiterallyCanvas.prototype.undo = function() { + var action; + if (!this.undoStack.length) { + return; + } + action = this.undoStack.pop(); + action.undo(); + this.redoStack.push(action); + this.trigger('undo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.redo = function() { + var action; + if (!this.redoStack.length) { + return; + } + action = this.redoStack.pop(); + this.undoStack.push(action); + action["do"](); + this.trigger('redo', { + action: action + }); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.canUndo = function() { + return !!this.undoStack.length; + }; + + LiterallyCanvas.prototype.canRedo = function() { + return !!this.redoStack.length; + }; + + LiterallyCanvas.prototype.getPixel = function(x, y) { + var p, pixel; + p = this.drawingCoordsToClientCoords(x, y); + pixel = this.ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } + }; + + LiterallyCanvas.prototype.getContentBounds = function() { + return util.getBoundingRect((this.shapes.concat(this.backgroundShapes)).map(function(s) { + return s.getBoundingRect(); + }), this.width === INFINITE ? 0 : this.width, this.height === INFINITE ? 0 : this.height); + }; + + LiterallyCanvas.prototype.getDefaultImageRect = function(explicitSize, margin) { + var s; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + return util.getDefaultImageRect((function() { + var i, len, ref1, results; + ref1 = this.shapes.concat(this.backgroundShapes); + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + s = ref1[i]; + results.push(s.getBoundingRect(this.ctx)); + } + return results; + }).call(this), explicitSize, margin); + }; + + LiterallyCanvas.prototype.getImage = function(opts) { + if (opts == null) { + opts = {}; + } + if (opts.includeWatermark == null) { + opts.includeWatermark = true; + } + if (opts.scaleDownRetina == null) { + opts.scaleDownRetina = true; + } + if (opts.scale == null) { + opts.scale = 1; + } + if (!opts.scaleDownRetina) { + opts.scale *= this.backingScale; + } + if (opts.includeWatermark) { + opts.watermarkImage = this.watermarkImage; + opts.watermarkScale = this.watermarkScale; + if (!opts.scaleDownRetina) { + opts.watermarkScale *= this.backingScale; + } + } + return renderSnapshotToImage(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.canvasForExport = function() { + this.repaintAllLayers(); + return util.combineCanvases(this.backgroundCanvas, this.canvas); + }; + + LiterallyCanvas.prototype.canvasWithBackground = function(backgroundImageOrCanvas) { + return util.combineCanvases(backgroundImageOrCanvas, this.canvasForExport()); + }; + + LiterallyCanvas.prototype.getSnapshot = function(keys) { + var i, k, len, ref1, shape, snapshot; + if (keys == null) { + keys = null; + } + if (keys == null) { + keys = ['shapes', 'imageSize', 'colors', 'position', 'scale', 'backgroundShapes']; + } + snapshot = {}; + ref1 = ['colors', 'position', 'scale']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + if (indexOf.call(keys, k) >= 0) { + snapshot[k] = this[k]; + } + } + if (indexOf.call(keys, 'shapes') >= 0) { + snapshot.shapes = (function() { + var j, len1, ref2, results; + ref2 = this.shapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'backgroundShapes') >= 0) { + snapshot.backgroundShapes = (function() { + var j, len1, ref2, results; + ref2 = this.backgroundShapes; + results = []; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shape = ref2[j]; + results.push(shapeToJSON(shape)); + } + return results; + }).call(this); + } + if (indexOf.call(keys, 'imageSize') >= 0) { + snapshot.imageSize = { + width: this.width, + height: this.height + }; + } + return snapshot; + }; + + LiterallyCanvas.prototype.getSnapshotJSON = function() { + console.warn("lc.getSnapshotJSON() is deprecated. use JSON.stringify(lc.getSnapshot()) instead."); + return JSON.stringify(this.getSnapshot()); + }; + + LiterallyCanvas.prototype.getSVGString = function(opts) { + if (opts == null) { + opts = {}; + } + return renderSnapshotToSVG(this.getSnapshot(), opts); + }; + + LiterallyCanvas.prototype.loadSnapshot = function(snapshot) { + var i, j, k, len, len1, ref1, ref2, s, shape, shapeRepr; + if (!snapshot) { + return; + } + if (snapshot.colors) { + ref1 = ['primary', 'secondary', 'background']; + for (i = 0, len = ref1.length; i < len; i++) { + k = ref1[i]; + this.setColor(k, snapshot.colors[k]); + } + } + if (snapshot.shapes) { + this.shapes = []; + ref2 = snapshot.shapes; + for (j = 0, len1 = ref2.length; j < len1; j++) { + shapeRepr = ref2[j]; + shape = JSONToShape(shapeRepr); + if (shape) { + this.execute(new actions.AddShapeAction(this, shape)); + } + } + } + if (snapshot.backgroundShapes) { + this.backgroundShapes = (function() { + var l, len2, ref3, results; + ref3 = snapshot.backgroundShapes; + results = []; + for (l = 0, len2 = ref3.length; l < len2; l++) { + s = ref3[l]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (snapshot.imageSize) { + this.width = snapshot.imageSize.width; + this.height = snapshot.imageSize.height; + } + if (snapshot.position) { + this.position = snapshot.position; + } + if (snapshot.scale) { + this.scale = snapshot.scale; + } + this.repaintAllLayers(); + this.trigger('snapshotLoad'); + return this.trigger('drawingChange', {}); + }; + + LiterallyCanvas.prototype.loadSnapshotJSON = function(str) { + console.warn("lc.loadSnapshotJSON() is deprecated. use lc.loadSnapshot(JSON.parse(snapshot)) instead."); + return this.loadSnapshot(JSON.parse(str)); + }; + + return LiterallyCanvas; + +})(); + + +},{"../tools/Pencil":48,"./actions":7,"./bindEvents":8,"./canvasRenderer":9,"./math":14,"./renderSnapshotToImage":15,"./renderSnapshotToSVG":16,"./shapes":17,"./svgRenderer":18,"./util":19}],6:[function(require,module,exports){ +var TextRenderer, getLinesToRender, getNextLine, parseFontString; + +require('./fontmetrics.js'); + +parseFontString = function(font) { + var fontFamily, fontItems, fontSize, item, j, len, maybeSize, remainingFontString; + fontItems = font.split(' '); + fontSize = 0; + for (j = 0, len = fontItems.length; j < len; j++) { + item = fontItems[j]; + maybeSize = parseInt(item.replace("px", ""), 10); + if (!isNaN(maybeSize)) { + fontSize = maybeSize; + } + } + if (!fontSize) { + throw "Font size not found"; + } + remainingFontString = font.substring(fontItems[0].length + 1).replace('bold ', '').replace('italic ', '').replace('underline ', ''); + fontFamily = remainingFontString; + return { + fontSize: fontSize, + fontFamily: fontFamily + }; +}; + +getNextLine = function(ctx, text, forcedWidth) { + var doesSubstringFit, endIndex, isEndOfString, isNonWord, isWhitespace, lastGoodIndex, lastOkayIndex, nextWordStartIndex, textToHere, wasInWord; + if (!text.length) { + return ['', '']; + } + endIndex = 0; + lastGoodIndex = 0; + lastOkayIndex = 0; + wasInWord = false; + while (true) { + endIndex += 1; + isEndOfString = endIndex >= text.length; + isWhitespace = (!isEndOfString) && text[endIndex].match(/\s/); + isNonWord = isWhitespace || isEndOfString; + textToHere = text.substring(0, endIndex); + doesSubstringFit = forcedWidth ? ctx.measureTextWidth(textToHere).width <= forcedWidth : true; + if (doesSubstringFit) { + lastOkayIndex = endIndex; + } + if (isNonWord && wasInWord) { + wasInWord = false; + if (doesSubstringFit) { + lastGoodIndex = endIndex; + } + } + wasInWord = !isWhitespace; + if (isEndOfString || !doesSubstringFit) { + if (doesSubstringFit) { + return [text, '']; + } else if (lastGoodIndex > 0) { + nextWordStartIndex = lastGoodIndex + 1; + while (nextWordStartIndex < text.length && text[nextWordStartIndex].match('/\s/')) { + nextWordStartIndex += 1; + } + return [text.substring(0, lastGoodIndex), text.substring(nextWordStartIndex)]; + } else { + return [text.substring(0, lastOkayIndex), text.substring(lastOkayIndex)]; + } + } + } +}; + +getLinesToRender = function(ctx, text, forcedWidth) { + var j, len, lines, nextLine, ref, ref1, remainingText, textLine, textSplitOnLines; + textSplitOnLines = text.split(/\r\n|\r|\n/g); + lines = []; + for (j = 0, len = textSplitOnLines.length; j < len; j++) { + textLine = textSplitOnLines[j]; + ref = getNextLine(ctx, textLine, forcedWidth), nextLine = ref[0], remainingText = ref[1]; + if (nextLine) { + while (nextLine) { + lines.push(nextLine); + ref1 = getNextLine(ctx, remainingText, forcedWidth), nextLine = ref1[0], remainingText = ref1[1]; + } + } else { + lines.push(textLine); + } + } + return lines; +}; + +TextRenderer = (function() { + function TextRenderer(ctx, text1, font1, forcedWidth1, forcedHeight) { + var fontFamily, fontSize, ref; + this.text = text1; + this.font = font1; + this.forcedWidth = forcedWidth1; + this.forcedHeight = forcedHeight; + ref = parseFontString(this.font), fontFamily = ref.fontFamily, fontSize = ref.fontSize; + ctx.font = this.font; + ctx.textBaseline = 'baseline'; + this.emDashWidth = ctx.measureTextWidth('—', fontSize, fontFamily).width; + this.caratWidth = ctx.measureTextWidth('|', fontSize, fontFamily).width; + this.lines = getLinesToRender(ctx, this.text, this.forcedWidth); + this.metricses = this.lines.map((function(_this) { + return function(line) { + return ctx.measureText2(line || 'X', fontSize, _this.font); + }; + })(this)); + this.metrics = { + ascent: Math.max.apply(Math, this.metricses.map(function(arg) { + var ascent; + ascent = arg.ascent; + return ascent; + })), + descent: Math.max.apply(Math, this.metricses.map(function(arg) { + var descent; + descent = arg.descent; + return descent; + })), + fontsize: Math.max.apply(Math, this.metricses.map(function(arg) { + var fontsize; + fontsize = arg.fontsize; + return fontsize; + })), + leading: Math.max.apply(Math, this.metricses.map(function(arg) { + var leading; + leading = arg.leading; + return leading; + })), + width: Math.max.apply(Math, this.metricses.map(function(arg) { + var width; + width = arg.width; + return width; + })), + height: Math.max.apply(Math, this.metricses.map(function(arg) { + var height; + height = arg.height; + return height; + })), + bounds: { + minx: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.minx; + })), + miny: Math.min.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.miny; + })), + maxx: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxx; + })), + maxy: Math.max.apply(Math, this.metricses.map(function(arg) { + var bounds; + bounds = arg.bounds; + return bounds.maxy; + })) + } + }; + this.boundingBoxWidth = Math.ceil(this.metrics.width); + } + + TextRenderer.prototype.draw = function(ctx, x, y) { + var i, j, len, line, ref, results; + ctx.textBaseline = 'top'; + ctx.font = this.font; + i = 0; + ref = this.lines; + results = []; + for (j = 0, len = ref.length; j < len; j++) { + line = ref[j]; + ctx.fillText(line, x, y + i * this.metrics.leading); + results.push(i += 1); + } + return results; + }; + + TextRenderer.prototype.getWidth = function(isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (this.forcedWidth) { + return this.forcedWidth; + } else { + if (isEditing) { + return this.metrics.bounds.maxx + this.caratWidth; + } else { + return this.metrics.bounds.maxx; + } + } + }; + + TextRenderer.prototype.getHeight = function() { + return this.forcedHeight || (this.metrics.leading * this.lines.length); + }; + + return TextRenderer; + +})(); + +module.exports = TextRenderer; + + +},{"./fontmetrics.js":11}],7:[function(require,module,exports){ +var AddShapeAction, ClearAction; + +ClearAction = (function() { + function ClearAction(lc1, oldShapes, newShapes1) { + this.lc = lc1; + this.oldShapes = oldShapes; + this.newShapes = newShapes1; + } + + ClearAction.prototype["do"] = function() { + this.lc.shapes = this.newShapes; + return this.lc.repaintLayer('main'); + }; + + ClearAction.prototype.undo = function() { + this.lc.shapes = this.oldShapes; + return this.lc.repaintLayer('main'); + }; + + return ClearAction; + +})(); + +AddShapeAction = (function() { + function AddShapeAction(lc1, shape1, previousShapeId) { + this.lc = lc1; + this.shape = shape1; + this.previousShapeId = previousShapeId != null ? previousShapeId : null; + } + + AddShapeAction.prototype["do"] = function() { + var found, i, len, newShapes, ref, shape; + if (!this.lc.shapes.length || this.lc.shapes[this.lc.shapes.length - 1].id === this.previousShapeId || this.previousShapeId === null) { + this.lc.shapes.push(this.shape); + } else { + newShapes = []; + found = false; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + newShapes.push(shape); + if (shape.id === this.previousShapeId) { + newShapes.push(this.shape); + found = true; + } + } + if (!found) { + newShapes.push(this.shape); + } + this.lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + AddShapeAction.prototype.undo = function() { + var i, len, newShapes, ref, shape; + if (this.lc.shapes[this.lc.shapes.length - 1].id === this.shape.id) { + this.lc.shapes.pop(); + } else { + newShapes = []; + ref = this.lc.shapes; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + if (shape.id !== this.shape.id) { + newShapes.push(shape); + } + } + lc.shapes = newShapes; + } + return this.lc.repaintLayer('main'); + }; + + return AddShapeAction; + +})(); + +module.exports = { + ClearAction: ClearAction, + AddShapeAction: AddShapeAction +}; + + +},{}],8:[function(require,module,exports){ +var bindEvents, buttonIsDown, coordsForTouchEvent, position; + +coordsForTouchEvent = function(el, e) { + var p, tx, ty; + tx = e.changedTouches[0].clientX; + ty = e.changedTouches[0].clientY; + p = el.getBoundingClientRect(); + return [tx - p.left, ty - p.top]; +}; + +position = function(el, e) { + var p; + p = el.getBoundingClientRect(); + return { + left: e.clientX - p.left, + top: e.clientY - p.top + }; +}; + +buttonIsDown = function(e) { + if (e.buttons != null) { + return e.buttons === 1; + } else { + return e.which > 0; + } +}; + +module.exports = bindEvents = function(lc, canvas, panWithKeyboard) { + var listener, mouseMoveListener, mouseUpListener, touchEndListener, touchMoveListener, unsubs; + if (panWithKeyboard == null) { + panWithKeyboard = false; + } + unsubs = []; + mouseMoveListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + p = position(canvas, e); + return lc.pointerMove(p.left, p.top); + }; + })(this); + mouseUpListener = (function(_this) { + return function(e) { + var p; + e.preventDefault(); + canvas.onselectstart = function() { + return true; + }; + p = position(canvas, e); + lc.pointerUp(p.left, p.top); + document.removeEventListener('mousemove', mouseMoveListener); + document.removeEventListener('mouseup', mouseUpListener); + return canvas.addEventListener('mousemove', mouseMoveListener); + }; + })(this); + canvas.addEventListener('mousedown', (function(_this) { + return function(e) { + var down, p; + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + down = true; + e.preventDefault(); + canvas.onselectstart = function() { + return false; + }; + p = position(canvas, e); + lc.pointerDown(p.left, p.top); + canvas.removeEventListener('mousemove', mouseMoveListener); + document.addEventListener('mousemove', mouseMoveListener); + return document.addEventListener('mouseup', mouseUpListener); + }; + })(this)); + touchMoveListener = function(e) { + e.preventDefault(); + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + }; + touchEndListener = function(e) { + e.preventDefault(); + lc.pointerUp.apply(lc, coordsForTouchEvent(canvas, e)); + document.removeEventListener('touchmove', touchMoveListener); + document.removeEventListener('touchend', touchEndListener); + return document.removeEventListener('touchcancel', touchEndListener); + }; + canvas.addEventListener('touchstart', function(e) { + if (e.target.tagName.toLowerCase() !== 'canvas') { + return; + } + e.preventDefault(); + if (e.touches.length === 1) { + lc.pointerDown.apply(lc, coordsForTouchEvent(canvas, e)); + document.addEventListener('touchmove', touchMoveListener); + document.addEventListener('touchend', touchEndListener); + return document.addEventListener('touchcancel', touchEndListener); + } else { + return lc.pointerMove.apply(lc, coordsForTouchEvent(canvas, e)); + } + }); + if (panWithKeyboard) { + console.warn("Keyboard panning is deprecated."); + listener = function(e) { + switch (e.keyCode) { + case 37: + lc.pan(-10, 0); + break; + case 38: + lc.pan(0, -10); + break; + case 39: + lc.pan(10, 0); + break; + case 40: + lc.pan(0, 10); + } + return lc.repaintAllLayers(); + }; + document.addEventListener('keydown', listener); + unsubs.push(function() { + return document.removeEventListener(listener); + }); + } + return function() { + var f, i, len, results; + results = []; + for (i = 0, len = unsubs.length; i < len; i++) { + f = unsubs[i]; + results.push(f()); + } + return results; + }; +}; + + +},{}],9:[function(require,module,exports){ +var _drawRawLinePath, defineCanvasRenderer, drawErasedLinePath, drawErasedLinePathLatest, drawLinePath, drawLinePathLatest, lineEndCapShapes, noop, renderShapeToCanvas, renderShapeToContext, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineCanvasRenderer = function(shapeName, drawFunc, drawLatestFunc) { + return renderers[shapeName] = { + drawFunc: drawFunc, + drawLatestFunc: drawLatestFunc + }; +}; + +noop = function() {}; + +renderShapeToContext = function(ctx, shape, opts) { + var bufferCtx; + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (opts.retryCallback == null) { + opts.retryCallback = noop; + } + if (opts.shouldOnlyDrawLatest == null) { + opts.shouldOnlyDrawLatest = false; + } + if (opts.bufferCtx == null) { + opts.bufferCtx = null; + } + bufferCtx = opts.bufferCtx; + if (renderers[shape.className]) { + if (opts.shouldOnlyDrawLatest && renderers[shape.className].drawLatestFunc) { + return renderers[shape.className].drawLatestFunc(ctx, bufferCtx, shape, opts.retryCallback); + } else { + return renderers[shape.className].drawFunc(ctx, shape, opts.retryCallback); + } + } else if (opts.shouldIgnoreUnsupportedShapes) { + return console.warn("Can't render shape of type " + shape.className + " to canvas"); + } else { + throw "Can't render shape of type " + shape.className + " to canvas"; + } +}; + +renderShapeToCanvas = function(canvas, shape, opts) { + return renderShapeToContext(canvas.getContext('2d'), shape, opts); +}; + +defineCanvasRenderer('Rectangle', function(ctx, shape) { + var x, y; + x = shape.x; + y = shape.y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + ctx.fillStyle = shape.fillColor; + ctx.fillRect(x, y, shape.width, shape.height); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.strokeRect(x, y, shape.width, shape.height); +}); + +defineCanvasRenderer('Ellipse', function(ctx, shape) { + var centerX, centerY, halfHeight, halfWidth; + ctx.save(); + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + ctx.translate(centerX, centerY); + ctx.scale(1, Math.abs(shape.height / shape.width)); + ctx.beginPath(); + ctx.arc(0, 0, Math.abs(halfWidth), 0, Math.PI * 2); + ctx.closePath(); + ctx.restore(); + ctx.fillStyle = shape.fillColor; + ctx.fill(); + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.strokeColor; + return ctx.stroke(); +}); + +defineCanvasRenderer('SelectionBox', (function() { + var _drawHandle; + _drawHandle = function(ctx, arg, handleSize) { + var x, y; + x = arg.x, y = arg.y; + if (handleSize === 0) { + return; + } + ctx.fillStyle = '#fff'; + ctx.fillRect(x, y, handleSize, handleSize); + ctx.strokeStyle = '#000'; + return ctx.strokeRect(x, y, handleSize, handleSize); + }; + return function(ctx, shape) { + _drawHandle(ctx, shape.getTopLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getTopRightHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomLeftHandleRect(), shape.handleSize); + _drawHandle(ctx, shape.getBottomRightHandleRect(), shape.handleSize); + if (shape.backgroundColor) { + ctx.fillStyle = shape.backgroundColor; + ctx.fillRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + } + ctx.lineWidth = 1; + ctx.strokeStyle = '#000'; + ctx.setLineDash([2, 4]); + ctx.strokeRect(shape._br.x - shape.margin, shape._br.y - shape.margin, shape._br.width + shape.margin * 2, shape._br.height + shape.margin * 2); + return ctx.setLineDash([]); + }; +})()); + +defineCanvasRenderer('Image', function(ctx, shape, retryCallback) { + if (shape.image.width) { + if (shape.scale === 1) { + return ctx.drawImage(shape.image, shape.x, shape.y); + } else { + return ctx.drawImage(shape.image, shape.x, shape.y, shape.image.width * shape.scale, shape.image.height * shape.scale); + } + } else if (retryCallback) { + return shape.image.onload = retryCallback; + } +}); + +defineCanvasRenderer('Line', function(ctx, shape) { + var arrowWidth, x1, x2, y1, y2; + if (shape.x1 === shape.x2 && shape.y1 === shape.y2) { + return; + } + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + ctx.lineWidth = shape.strokeWidth; + ctx.strokeStyle = shape.color; + ctx.lineCap = shape.capStyle; + if (shape.dash) { + ctx.setLineDash(shape.dash); + } + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + if (shape.dash) { + ctx.setLineDash([]); + } + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + if (shape.endCapShapes[0]) { + lineEndCapShapes[shape.endCapShapes[0]].drawToCanvas(ctx, x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + return lineEndCapShapes[shape.endCapShapes[1]].drawToCanvas(ctx, x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } +}); + +_drawRawLinePath = function(ctx, points, close, lineCap) { + var i, len, point, ref; + if (close == null) { + close = false; + } + if (lineCap == null) { + lineCap = 'round'; + } + if (!points.length) { + return; + } + ctx.lineCap = lineCap; + ctx.strokeStyle = points[0].color; + ctx.lineWidth = points[0].size; + ctx.beginPath(); + if (points[0].size % 2 === 0) { + ctx.moveTo(points[0].x, points[0].y); + } else { + ctx.moveTo(points[0].x + 0.5, points[0].y + 0.5); + } + ref = points.slice(1); + for (i = 0, len = ref.length; i < len; i++) { + point = ref[i]; + if (points[0].size % 2 === 0) { + ctx.lineTo(point.x, point.y); + } else { + ctx.lineTo(point.x + 0.5, point.y + 0.5); + } + } + if (close) { + return ctx.closePath(); + } +}; + +drawLinePath = function(ctx, shape) { + _drawRawLinePath(ctx, shape.smoothedPoints); + return ctx.stroke(); +}; + +drawLinePathLatest = function(ctx, bufferCtx, shape) { + var drawEnd, drawStart, segmentStart; + if (shape.tail) { + segmentStart = shape.smoothedPoints.length - shape.segmentSize * shape.tailSize; + drawStart = segmentStart < shape.segmentSize * 2 ? 0 : segmentStart; + drawEnd = segmentStart + shape.segmentSize + 1; + _drawRawLinePath(bufferCtx, shape.smoothedPoints.slice(drawStart, drawEnd)); + return bufferCtx.stroke(); + } else { + _drawRawLinePath(bufferCtx, shape.smoothedPoints); + return bufferCtx.stroke(); + } +}; + +defineCanvasRenderer('LinePath', drawLinePath, drawLinePathLatest); + +drawErasedLinePath = function(ctx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + drawLinePath(ctx, shape); + return ctx.restore(); +}; + +drawErasedLinePathLatest = function(ctx, bufferCtx, shape) { + ctx.save(); + ctx.globalCompositeOperation = "destination-out"; + bufferCtx.save(); + bufferCtx.globalCompositeOperation = "destination-out"; + drawLinePathLatest(ctx, bufferCtx, shape); + ctx.restore(); + return bufferCtx.restore(); +}; + +defineCanvasRenderer('ErasedLinePath', drawErasedLinePath, drawErasedLinePathLatest); + +defineCanvasRenderer('Text', function(ctx, shape) { + if (!shape.renderer) { + shape._makeRenderer(ctx); + } + ctx.fillStyle = shape.color; + return shape.renderer.draw(ctx, shape.x, shape.y); +}); + +defineCanvasRenderer('Polygon', function(ctx, shape) { + ctx.fillStyle = shape.fillColor; + _drawRawLinePath(ctx, shape.points, shape.isClosed, 'butt'); + ctx.fill(); + return ctx.stroke(); +}); + +module.exports = { + defineCanvasRenderer: defineCanvasRenderer, + renderShapeToCanvas: renderShapeToCanvas, + renderShapeToContext: renderShapeToContext +}; + + +},{"./lineEndCapShapes":12}],10:[function(require,module,exports){ +'use strict'; + +module.exports = { + imageURLPrefix: 'lib/img', + primaryColor: 'hsla(0, 0%, 0%, 1)', + secondaryColor: 'hsla(0, 0%, 100%, 1)', + backgroundColor: 'transparent', + strokeWidths: [1, 2, 5, 10, 20, 30], + defaultStrokeWidth: 5, + toolbarPosition: 'top', + keyboardShortcuts: false, + imageSize: { width: 'infinite', height: 'infinite' }, + backgroundShapes: [], + watermarkImage: null, + watermarkScale: 1, + zoomMin: 0.2, + zoomMax: 4.0, + zoomStep: 0.2, + snapshot: null, + tools: [require('../tools/Pencil'), require('../tools/Eraser'), require('../tools/Line'), require('../tools/Rectangle'), require('../tools/Ellipse'), require('../tools/Text'), require('../tools/Polygon'), require('../tools/Pan'), require('../tools/Eyedropper')] +}; + +},{"../tools/Ellipse":43,"../tools/Eraser":44,"../tools/Eyedropper":45,"../tools/Line":46,"../tools/Pan":47,"../tools/Pencil":48,"../tools/Polygon":49,"../tools/Rectangle":50,"../tools/Text":52}],11:[function(require,module,exports){ +"use strict"; + +/** + This library rewrites the Canvas2D "measureText" function + so that it returns a more complete metrics object. + This library is licensed under the MIT (Expat) license, + the text for which is included below. + +** ----------------------------------------------------------------------------- + + CHANGELOG: + + 2012-01-21 - Whitespace handling added by Joe Turner + (https://github.com/oampo) + + 2015-06-08 - Various hacks added by Steve Johnson + +** ----------------------------------------------------------------------------- + + Copyright (C) 2011 by Mike "Pomax" Kamermans + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +**/ +(function () { + var NAME = "FontMetrics Library"; + var VERSION = "1-2012.0121.1300"; + + // if there is no getComputedStyle, this library won't work. + if (!document.defaultView.getComputedStyle) { + throw "ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values."; + } + + // store the old text metrics function on the Canvas2D prototype + CanvasRenderingContext2D.prototype.measureTextWidth = CanvasRenderingContext2D.prototype.measureText; + + /** + * shortcut function for getting computed CSS values + */ + var getCSSValue = function getCSSValue(element, property) { + return document.defaultView.getComputedStyle(element, null).getPropertyValue(property); + }; + + // debug function + var show = function show(canvas, ctx, xstart, w, h, metrics) { + document.body.appendChild(canvas); + ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; + + ctx.beginPath(); + ctx.moveTo(xstart, 0); + ctx.lineTo(xstart, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(xstart + metrics.bounds.maxx, 0); + ctx.lineTo(xstart + metrics.bounds.maxx, h); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 - metrics.ascent); + ctx.lineTo(w, h / 2 - metrics.ascent); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(0, h / 2 + metrics.descent); + ctx.lineTo(w, h / 2 + metrics.descent); + ctx.closePath(); + ctx.stroke(); + }; + + /** + * The new text metrics function + */ + CanvasRenderingContext2D.prototype.measureText2 = function (textstring, fontSize, fontString) { + var metrics = this.measureTextWidth(textstring), + isSpace = !/\S/.test(textstring); + metrics.fontsize = fontSize; + + // for text lead values, we meaure a multiline text container. + var leadDiv = document.createElement("div"); + leadDiv.style.position = "absolute"; + leadDiv.style.opacity = 0; + leadDiv.style.font = fontString; + leadDiv.innerHTML = textstring + "
" + textstring; + document.body.appendChild(leadDiv); + + // make some initial guess at the text leading (using the standard TeX ratio) + metrics.leading = 1.2 * fontSize; + + // then we try to get the real value from the browser + var leadDivHeight = getCSSValue(leadDiv, "height"); + leadDivHeight = leadDivHeight.replace("px", ""); + if (leadDivHeight >= fontSize * 2) { + metrics.leading = leadDivHeight / 2 | 0; + } + document.body.removeChild(leadDiv); + + // if we're not dealing with white space, we can compute metrics + if (!isSpace) { + // Have characters, so measure the text + var canvas = document.createElement("canvas"); + var padding = 100; + canvas.width = metrics.width + padding; + canvas.height = 3 * fontSize; + canvas.style.opacity = 1; + canvas.style.font = fontString; + var ctx = canvas.getContext("2d"); + ctx.font = fontString; + + var w = canvas.width, + h = canvas.height, + baseline = h / 2; + + // Set all canvas pixeldata values to 255, with all the content + // data being 0. This lets us scan for data[i] != 255. + ctx.fillStyle = "white"; + ctx.fillRect(-1, -1, w + 2, h + 2); + ctx.fillStyle = "black"; + ctx.fillText(textstring, padding / 2, baseline); + var pixelData = ctx.getImageData(0, 0, w, h).data; + + // canvas pixel data is w*4 by h*4, because R, G, B and A are separate, + // consecutive values in the array, rather than stored as 32 bit ints. + var i = 0, + w4 = w * 4, + len = pixelData.length; + + // Finding the ascent uses a normal, forward scanline + while (++i < len && pixelData[i] === 255) {} + var ascent = i / w4 | 0; + + // Finding the descent uses a reverse scanline + i = len - 1; + while (--i > 0 && pixelData[i] === 255) {} + var descent = i / w4 | 0; + + // find the min-x coordinate + for (i = 0; i < len && pixelData[i] === 255;) { + i += w4; + if (i >= len) { + i = i - len + 4; + } + } + var minx = i % w4 / 4 | 0; + + // find the max-x coordinate + var step = 1; + for (i = len - 3; i >= 0 && pixelData[i] === 255;) { + i -= w4; + if (i < 0) { + i = len - 3 - step++ * 4; + } + } + var maxx = i % w4 / 4 + 1 | 0; + + // set font metrics + metrics.ascent = baseline - ascent; + metrics.descent = descent - baseline; + metrics.bounds = { minx: minx - padding / 2, + maxx: maxx - padding / 2, + miny: 0, + maxy: descent - ascent }; + metrics.height = 1 + (descent - ascent); + } + + // if we ARE dealing with whitespace, most values will just be zero. + else { + // Only whitespace, so we can't measure the text + metrics.ascent = 0; + metrics.descent = 0; + metrics.bounds = { minx: 0, + maxx: metrics.width, // Best guess + miny: 0, + maxy: 0 }; + metrics.height = 0; + } + return metrics; + }; +})(); + +},{}],12:[function(require,module,exports){ +module.exports = { + arrow: (function() { + var getPoints; + getPoints = function(x, y, angle, width, length) { + return [ + { + x: x + Math.cos(angle + Math.PI / 2) * width / 2, + y: y + Math.sin(angle + Math.PI / 2) * width / 2 + }, { + x: x + Math.cos(angle) * length, + y: y + Math.sin(angle) * length + }, { + x: x + Math.cos(angle - Math.PI / 2) * width / 2, + y: y + Math.sin(angle - Math.PI / 2) * width / 2 + } + ]; + }; + return { + drawToCanvas: function(ctx, x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + ctx.fillStyle = color; + ctx.lineWidth = 0; + ctx.strokeStyle = 'transparent'; + ctx.beginPath(); + points = getPoints(x, y, angle, width, length); + ctx.moveTo(points[0].x, points[0].y); + ctx.lineTo(points[1].x, points[1].y); + ctx.lineTo(points[2].x, points[2].y); + return ctx.fill(); + }, + svg: function(x, y, angle, width, color, length) { + var points; + if (length == null) { + length = 0; + } + length = length || width; + points = getPoints(x, y, angle, width, length); + return ""; + } + }; + })() +}; + + +},{}],13:[function(require,module,exports){ +var _, localize, strings; + +strings = {}; + +localize = function(localStrings) { + return strings = localStrings; +}; + +_ = function(string) { + var translation; + translation = strings[string]; + return translation || string; +}; + +module.exports = { + localize: localize, + _: _ +}; + + +},{}],14:[function(require,module,exports){ +var Point, _slope, math, normals, unit, util; + +Point = require('./shapes').Point; + +util = require('./util'); + +math = {}; + +math.toPoly = function(line) { + var i, index, len, n, point, polyLeft, polyRight; + polyLeft = []; + polyRight = []; + index = 0; + for (i = 0, len = line.length; i < len; i++) { + point = line[i]; + n = normals(point, _slope(line, index)); + polyLeft = polyLeft.concat([n[0]]); + polyRight = [n[1]].concat(polyRight); + index += 1; + } + return polyLeft.concat(polyRight); +}; + +_slope = function(line, index) { + var point; + if (line.length < 3) { + point = { + x: 0, + y: 0 + }; + } + if (index === 0) { + point = _slope(line, index + 1); + } else if (index === line.length - 1) { + point = _slope(line, index - 1); + } else { + point = math.diff(line[index - 1], line[index + 1]); + } + return point; +}; + +math.diff = function(a, b) { + return { + x: b.x - a.x, + y: b.y - a.y + }; +}; + +unit = function(vector) { + var length; + length = math.len(vector); + return { + x: vector.x / length, + y: vector.y / length + }; +}; + +normals = function(p, slope) { + slope = unit(slope); + slope.x = slope.x * p.size / 2; + slope.y = slope.y * p.size / 2; + return [ + { + x: p.x - slope.y, + y: p.y + slope.x, + color: p.color + }, { + x: p.x + slope.y, + y: p.y - slope.x, + color: p.color + } + ]; +}; + +math.len = function(vector) { + return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2)); +}; + +math.scalePositionScalar = function(val, viewportSize, oldScale, newScale) { + var newSize, oldSize; + oldSize = viewportSize * oldScale; + newSize = viewportSize * newScale; + return val + (oldSize - newSize) / 2; +}; + +module.exports = math; + + +},{"./shapes":17,"./util":19}],15:[function(require,module,exports){ +var INFINITE, JSONToShape, renderWatermark, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +renderWatermark = function(ctx, image, scale) { + if (!image.width) { + return; + } + ctx.save(); + ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2); + ctx.scale(scale, scale); + ctx.drawImage(image, -image.width / 2, -image.height / 2); + return ctx.restore(); +}; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, imageSize, s, shapes, watermarkCanvas, watermarkCtx; + if (opts == null) { + opts = {}; + } + if (opts.scale == null) { + opts.scale = 1; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + watermarkCanvas = document.createElement('canvas'); + watermarkCtx = watermarkCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(watermarkCtx)); + } + return results; + })(), imageSize, opts.margin); + } + watermarkCanvas.width = opts.rect.width * opts.scale; + watermarkCanvas.height = opts.rect.height * opts.scale; + watermarkCtx.fillStyle = colors.background; + watermarkCtx.fillRect(0, 0, watermarkCanvas.width, watermarkCanvas.height); + if (!(opts.rect.width && opts.rect.height)) { + return null; + } + if (opts.watermarkImage) { + renderWatermark(watermarkCtx, opts.watermarkImage, opts.watermarkScale); + } + return util.combineCanvases(watermarkCanvas, util.renderShapes(backgroundShapes, opts.rect, opts.scale), util.renderShapes(shapes, opts.rect, opts.scale)); +}; + + +},{"./shapes":17,"./util":19}],16:[function(require,module,exports){ +var INFINITE, JSONToShape, util; + +util = require('./util'); + +JSONToShape = require('./shapes').JSONToShape; + +INFINITE = 'infinite'; + +module.exports = function(snapshot, opts) { + var allShapes, backgroundShapes, colors, ctx, dummyCanvas, imageSize, s, shapes; + if (opts == null) { + opts = {}; + } + shapes = (function() { + var i, len, ref, results; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + backgroundShapes = []; + if (snapshot.backgroundShapes) { + backgroundShapes = (function() { + var i, len, ref, results; + ref = snapshot.backgroundShapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + results.push(JSONToShape(s)); + } + return results; + })(); + } + if (opts.margin == null) { + opts.margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + imageSize = snapshot.imageSize || { + width: INFINITE, + height: INFINITE + }; + colors = snapshot.colors || { + background: 'transparent' + }; + allShapes = shapes.concat(backgroundShapes); + dummyCanvas = document.createElement('canvas'); + ctx = dummyCanvas.getContext('2d'); + if (opts.rect) { + opts.rect.x -= opts.margin.left; + opts.rect.y -= opts.margin.top; + opts.rect.width += opts.margin.left + opts.margin.right; + opts.rect.height += opts.margin.top + opts.margin.bottom; + } else { + opts.rect = util.getDefaultImageRect((function() { + var i, len, results; + results = []; + for (i = 0, len = allShapes.length; i < len; i++) { + s = allShapes[i]; + results.push(s.getBoundingRect(ctx)); + } + return results; + })(), imageSize, opts.margin); + } + return LC.renderShapesToSVG(backgroundShapes.concat(shapes), opts.rect, colors.background); +}; + + +},{"./shapes":17,"./util":19}],17:[function(require,module,exports){ +var JSONToShape, LinePath, TextRenderer, _createLinePathFromData, _doAllPointsShareStyle, _dual, _mid, _refine, bspline, createShape, defineCanvasRenderer, defineSVGRenderer, defineShape, lineEndCapShapes, linePathFuncs, ref, ref1, renderShapeToContext, renderShapeToSVG, shapeToJSON, shapes, util; + +util = require('./util'); + +TextRenderer = require('./TextRenderer'); + +lineEndCapShapes = require('./lineEndCapShapes'); + +ref = require('./canvasRenderer'), defineCanvasRenderer = ref.defineCanvasRenderer, renderShapeToContext = ref.renderShapeToContext; + +ref1 = require('./svgRenderer'), defineSVGRenderer = ref1.defineSVGRenderer, renderShapeToSVG = ref1.renderShapeToSVG; + +shapes = {}; + +defineShape = function(name, props) { + var Shape, drawFunc, drawLatestFunc, k, legacyDrawFunc, legacyDrawLatestFunc, legacySVGFunc, svgFunc; + Shape = function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + props.constructor.call(this, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + return this; + }; + Shape.prototype.className = name; + Shape.fromJSON = props.fromJSON; + if (props.draw) { + legacyDrawFunc = props.draw; + legacyDrawLatestFunc = props.draw || function(ctx, bufferCtx, retryCallback) { + return this.draw(ctx, bufferCtx, retryCallback); + }; + drawFunc = function(ctx, shape, retryCallback) { + return legacyDrawFunc.call(shape, ctx, retryCallback); + }; + drawLatestFunc = function(ctx, bufferCtx, shape, retryCallback) { + return legacyDrawLatestFunc.call(shape, ctx, bufferCtx, retryCallback); + }; + delete props.draw; + if (props.drawLatest) { + delete props.drawLatest; + } + defineCanvasRenderer(name, drawFunc, drawLatestFunc); + } + if (props.toSVG) { + legacySVGFunc = props.toSVG; + svgFunc = function(shape) { + return legacySVGFunc.call(shape); + }; + delete props.toSVG; + defineSVGRenderer(name, svgFunc); + } + Shape.prototype.draw = function(ctx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback + }); + }; + Shape.prototype.drawLatest = function(ctx, bufferCtx, retryCallback) { + return renderShapeToContext(ctx, this, { + retryCallback: retryCallback, + bufferCtx: bufferCtx, + shouldOnlyDrawLatest: true + }); + }; + Shape.prototype.toSVG = function() { + return renderShapeToSVG(this); + }; + for (k in props) { + if (k !== 'fromJSON') { + Shape.prototype[k] = props[k]; + } + } + shapes[name] = Shape; + return Shape; +}; + +createShape = function(name, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + var s; + s = new shapes[name](a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + s.id = util.getGUID(); + return s; +}; + +JSONToShape = function(arg) { + var className, data, id, shape; + className = arg.className, data = arg.data, id = arg.id; + if (className in shapes) { + shape = shapes[className].fromJSON(data); + if (shape) { + if (id) { + shape.id = id; + } + return shape; + } else { + console.log('Unreadable shape:', className, data); + return null; + } + } else { + console.log("Unknown shape:", className, data); + return null; + } +}; + +shapeToJSON = function(shape) { + return { + className: shape.className, + data: shape.toJSON(), + id: shape.id + }; +}; + +bspline = function(points, order) { + if (!order) { + return points; + } + return bspline(_dual(_dual(_refine(points))), order - 1); +}; + +_refine = function(points) { + var index, len, point, q, refined; + points = [points[0]].concat(points).concat(util.last(points)); + refined = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + refined[index * 2] = point; + if (points[index + 1]) { + refined[index * 2 + 1] = _mid(point, points[index + 1]); + } + index += 1; + } + return refined; +}; + +_dual = function(points) { + var dualed, index, len, point, q; + dualed = []; + index = 0; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (points[index + 1]) { + dualed[index] = _mid(point, points[index + 1]); + } + index += 1; + } + return dualed; +}; + +_mid = function(a, b) { + return createShape('Point', { + x: a.x + ((b.x - a.x) / 2), + y: a.y + ((b.y - a.y) / 2), + size: a.size + ((b.size - a.size) / 2), + color: a.color + }); +}; + +defineShape('Image', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.scale = args.scale || 1; + return this.image = args.image || null; + }, + getBoundingRect: function() { + return { + x: this.x, + y: this.y, + width: this.image.width * this.scale, + height: this.image.height * this.scale + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + imageSrc: this.image.src, + imageObject: this.image, + scale: this.scale + }; + }, + fromJSON: function(data) { + var img, ref2; + img = null; + if ((ref2 = data.imageObject) != null ? ref2.width : void 0) { + img = data.imageObject; + } else { + img = new Image(); + img.src = data.imageSrc; + } + return createShape('Image', { + x: data.x, + y: data.y, + image: img, + scale: data.scale + }); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Rectangle', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Rectangle', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Ellipse', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.width = args.width || 0; + this.height = args.height || 0; + this.strokeWidth = args.strokeWidth || 1; + this.strokeColor = args.strokeColor || 'black'; + return this.fillColor = args.fillColor || 'transparent'; + }, + getBoundingRect: function() { + return { + x: this.x - this.strokeWidth / 2, + y: this.y - this.strokeWidth / 2, + width: this.width + this.strokeWidth, + height: this.height + this.strokeWidth + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height, + strokeWidth: this.strokeWidth, + strokeColor: this.strokeColor, + fillColor: this.fillColor + }; + }, + fromJSON: function(data) { + return createShape('Ellipse', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Line', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x1 = args.x1 || 0; + this.y1 = args.y1 || 0; + this.x2 = args.x2 || 0; + this.y2 = args.y2 || 0; + this.strokeWidth = args.strokeWidth || 1; + this.color = args.color || 'black'; + this.capStyle = args.capStyle || 'round'; + this.endCapShapes = args.endCapShapes || [null, null]; + return this.dash = args.dash || null; + }, + getBoundingRect: function() { + return { + x: Math.min(this.x1, this.x2) - this.strokeWidth / 2, + y: Math.min(this.y1, this.y2) - this.strokeWidth / 2, + width: Math.abs(this.x2 - this.x1) + this.strokeWidth / 2, + height: Math.abs(this.y2 - this.y1) + this.strokeWidth / 2 + }; + }, + toJSON: function() { + return { + x1: this.x1, + y1: this.y1, + x2: this.x2, + y2: this.y2, + strokeWidth: this.strokeWidth, + color: this.color, + capStyle: this.capStyle, + dash: this.dash, + endCapShapes: this.endCapShapes + }; + }, + fromJSON: function(data) { + return createShape('Line', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x1 = this.x1 - moveInfo.xDiff; + this.y1 = this.y1 - moveInfo.yDiff; + this.x2 = this.x2 - moveInfo.xDiff; + return this.y2 = this.y2 - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +_doAllPointsShareStyle = function(points) { + var color, len, point, q, size; + if (!points.length) { + return false; + } + size = points[0].size; + color = points[0].color; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + if (!(point.size === size && point.color === color)) { + console.log(size, color, point.size, point.color); + } + if (!(point.size === size && point.color === color)) { + return false; + } + } + return true; +}; + +_createLinePathFromData = function(shapeName, data) { + var pointData, points, smoothedPoints, x, y; + points = null; + if (data.points) { + points = (function() { + var len, q, ref2, results; + ref2 = data.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pointData = ref2[q]; + results.push(JSONToShape(pointData)); + } + return results; + })(); + } else if (data.pointCoordinatePairs) { + points = (function() { + var len, q, ref2, ref3, results; + ref2 = data.pointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + smoothedPoints = null; + if (data.smoothedPointCoordinatePairs) { + smoothedPoints = (function() { + var len, q, ref2, ref3, results; + ref2 = data.smoothedPointCoordinatePairs; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + ref3 = ref2[q], x = ref3[0], y = ref3[1]; + results.push(JSONToShape({ + className: 'Point', + data: { + x: x, + y: y, + size: data.pointSize, + color: data.pointColor, + smooth: data.smooth + } + })); + } + return results; + })(); + } + if (!points[0]) { + return null; + } + return createShape(shapeName, { + points: points, + smoothedPoints: smoothedPoints, + order: data.order, + tailSize: data.tailSize, + smooth: data.smooth + }); +}; + +linePathFuncs = { + constructor: function(args) { + var len, point, points, q, results; + if (args == null) { + args = {}; + } + points = args.points || []; + this.order = args.order || 3; + this.tailSize = args.tailSize || 3; + this.smooth = 'smooth' in args ? args.smooth : true; + this.segmentSize = Math.pow(2, this.order); + this.sampleSize = this.tailSize + 1; + if (args.smoothedPoints) { + this.points = args.points; + return this.smoothedPoints = args.smoothedPoints; + } else { + this.points = []; + results = []; + for (q = 0, len = points.length; q < len; q++) { + point = points[q]; + results.push(this.addPoint(point)); + } + return results; + } + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return { + x: p.x - p.size / 2, + y: p.y - p.size / 2, + width: p.size, + height: p.size + }; + })); + }, + toJSON: function() { + var p, point; + if (_doAllPointsShareStyle(this.points)) { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + pointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + smoothedPointCoordinatePairs: (function() { + var len, q, ref2, results; + ref2 = this.smoothedPoints; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + results.push([point.x, point.y]); + } + return results; + }).call(this), + pointSize: this.points[0].size, + pointColor: this.points[0].color + }; + } else { + return { + order: this.order, + tailSize: this.tailSize, + smooth: this.smooth, + points: (function() { + var len, q, ref2, results; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + p = ref2[q]; + results.push(shapeToJSON(p)); + } + return results; + }).call(this) + }; + } + }, + fromJSON: function(data) { + return _createLinePathFromData('LinePath', data); + }, + addPoint: function(point) { + this.points.push(point); + if (!this.smooth) { + this.smoothedPoints = this.points; + return; + } + if (!this.smoothedPoints || this.points.length < this.sampleSize) { + return this.smoothedPoints = bspline(this.points, this.order); + } else { + this.tail = util.last(bspline(util.last(this.points, this.sampleSize), this.order), this.segmentSize * this.tailSize); + return this.smoothedPoints = this.smoothedPoints.slice(0, this.smoothedPoints.length - this.segmentSize * (this.tailSize - 1)).concat(this.tail); + } + }, + move: function(moveInfo) { + var len, pt, pts, q; + if (moveInfo == null) { + moveInfo = {}; + } + if (!this.smooth) { + pts = this.points; + } else { + pts = this.smoothedPoints; + } + for (q = 0, len = pts.length; q < len; q++) { + pt = pts[q]; + pt.move(moveInfo); + } + return this.points = this.smoothedPoints; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}; + +LinePath = defineShape('LinePath', linePathFuncs); + +defineShape('ErasedLinePath', { + constructor: linePathFuncs.constructor, + toJSON: linePathFuncs.toJSON, + addPoint: linePathFuncs.addPoint, + getBoundingRect: linePathFuncs.getBoundingRect, + fromJSON: function(data) { + return _createLinePathFromData('ErasedLinePath', data); + } +}); + +defineShape('Point', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.size = args.size || 0; + return this.color = args.color || ''; + }, + getBoundingRect: function() { + return { + x: this.x - this.size / 2, + y: this.y - this.size / 2, + width: this.size, + height: this.size + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + size: this.size, + color: this.color + }; + }, + fromJSON: function(data) { + return createShape('Point', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('Polygon', { + constructor: function(args) { + var len, point, q, ref2, results; + if (args == null) { + args = {}; + } + this.points = args.points; + this.fillColor = args.fillColor || 'white'; + this.strokeColor = args.strokeColor || 'black'; + this.strokeWidth = args.strokeWidth; + this.dash = args.dash || null; + if (args.isClosed == null) { + args.isClosed = true; + } + this.isClosed = args.isClosed; + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + point = ref2[q]; + point.color = this.strokeColor; + results.push(point.size = this.strokeWidth); + } + return results; + }, + addPoint: function(x, y) { + return this.points.push(LC.createShape('Point', { + x: x, + y: y + })); + }, + getBoundingRect: function() { + return util.getBoundingRect(this.points.map(function(p) { + return p.getBoundingRect(); + })); + }, + toJSON: function() { + return { + strokeWidth: this.strokeWidth, + fillColor: this.fillColor, + strokeColor: this.strokeColor, + dash: this.dash, + isClosed: this.isClosed, + pointCoordinatePairs: this.points.map(function(p) { + return [p.x, p.y]; + }) + }; + }, + fromJSON: function(data) { + data.points = data.pointCoordinatePairs.map(function(arg) { + var x, y; + x = arg[0], y = arg[1]; + return createShape('Point', { + x: x, + y: y, + size: data.strokeWidth, + color: data.strokeColor + }); + }); + return createShape('Polygon', data); + }, + move: function(moveInfo) { + var len, pt, q, ref2, results; + if (moveInfo == null) { + moveInfo = {}; + } + ref2 = this.points; + results = []; + for (q = 0, len = ref2.length; q < len; q++) { + pt = ref2[q]; + results.push(pt.move(moveInfo)); + } + return results; + }, + setUpperLeft: function(upperLeft) { + var br, xDiff, yDiff; + if (upperLeft == null) { + upperLeft = {}; + } + br = this.getBoundingRect(); + xDiff = br.x - upperLeft.x; + yDiff = br.y - upperLeft.y; + return this.move({ + xDiff: xDiff, + yDiff: yDiff + }); + } +}); + +defineShape('Text', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.x = args.x || 0; + this.y = args.y || 0; + this.v = args.v || 0; + this.text = args.text || ''; + this.color = args.color || 'black'; + this.font = args.font || '18px sans-serif'; + this.forcedWidth = args.forcedWidth || null; + return this.forcedHeight = args.forcedHeight || null; + }, + _makeRenderer: function(ctx) { + ctx.lineHeight = 1.2; + this.renderer = new TextRenderer(ctx, this.text, this.font, this.forcedWidth, this.forcedHeight); + if (this.v < 1) { + console.log('repairing baseline'); + this.v = 1; + this.x -= this.renderer.metrics.bounds.minx; + return this.y -= this.renderer.metrics.leading - this.renderer.metrics.descent; + } + }, + setText: function(text) { + this.text = text; + return this.renderer = null; + }, + setFont: function(font) { + this.font = font; + return this.renderer = null; + }, + setPosition: function(x, y) { + this.x = x; + return this.y = y; + }, + setSize: function(forcedWidth, forcedHeight) { + this.forcedWidth = Math.max(forcedWidth, 0); + this.forcedHeight = Math.max(forcedHeight, 0); + return this.renderer = null; + }, + enforceMaxBoundingRect: function(lc) { + var br, dx, lcBoundingRect; + br = this.getBoundingRect(lc.ctx); + lcBoundingRect = { + x: -lc.position.x / lc.scale, + y: -lc.position.y / lc.scale, + width: lc.canvas.width / lc.scale, + height: lc.canvas.height / lc.scale + }; + if (br.x + br.width > lcBoundingRect.x + lcBoundingRect.width) { + dx = br.x - lcBoundingRect.x; + this.forcedWidth = lcBoundingRect.width - dx - 10; + return this.renderer = null; + } + }, + getBoundingRect: function(ctx, isEditing) { + if (isEditing == null) { + isEditing = false; + } + if (!this.renderer) { + if (ctx) { + this._makeRenderer(ctx); + } else { + throw "Must pass ctx if text hasn't been rendered yet"; + } + } + return { + x: Math.floor(this.x), + y: Math.floor(this.y), + width: Math.ceil(this.renderer.getWidth(true)), + height: Math.ceil(this.renderer.getHeight()) + }; + }, + toJSON: function() { + return { + x: this.x, + y: this.y, + text: this.text, + color: this.color, + font: this.font, + forcedWidth: this.forcedWidth, + forcedHeight: this.forcedHeight, + v: this.v + }; + }, + fromJSON: function(data) { + return createShape('Text', data); + }, + move: function(moveInfo) { + if (moveInfo == null) { + moveInfo = {}; + } + this.x = this.x - moveInfo.xDiff; + return this.y = this.y - moveInfo.yDiff; + }, + setUpperLeft: function(upperLeft) { + if (upperLeft == null) { + upperLeft = {}; + } + this.x = upperLeft.x; + return this.y = upperLeft.y; + } +}); + +defineShape('SelectionBox', { + constructor: function(args) { + if (args == null) { + args = {}; + } + this.shape = args.shape; + if (args.handleSize != null) { + this.handleSize = args.handleSize; + } else { + this.handleSize = 10; + } + this.margin = 4; + this.backgroundColor = args.backgroundColor || null; + return this._br = this.shape.getBoundingRect(args.ctx); + }, + toJSON: function() { + return { + shape: shapeToJSON(this.shape), + backgroundColor: this.backgroundColor + }; + }, + fromJSON: function(arg) { + var backgroundColor, handleSize, margin, shape; + shape = arg.shape, handleSize = arg.handleSize, margin = arg.margin, backgroundColor = arg.backgroundColor; + return createShape('SelectionBox', { + shape: JSONToShape(shape), + backgroundColor: backgroundColor + }); + }, + getTopLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomLeftHandleRect: function() { + return { + x: this._br.x - this.handleSize - this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getTopRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y - this.handleSize - this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBottomRightHandleRect: function() { + return { + x: this._br.x + this._br.width + this.margin, + y: this._br.y + this._br.height + this.margin, + width: this.handleSize, + height: this.handleSize + }; + }, + getBoundingRect: function() { + return { + x: this._br.x - this.margin, + y: this._br.y - this.margin, + width: this._br.width + this.margin * 2, + height: this._br.height + this.margin * 2 + }; + } +}); + +module.exports = { + defineShape: defineShape, + createShape: createShape, + JSONToShape: JSONToShape, + shapeToJSON: shapeToJSON +}; + + +},{"./TextRenderer":6,"./canvasRenderer":9,"./lineEndCapShapes":12,"./svgRenderer":18,"./util":19}],18:[function(require,module,exports){ +var defineSVGRenderer, lineEndCapShapes, renderShapeToSVG, renderers; + +lineEndCapShapes = require('./lineEndCapShapes'); + +renderers = {}; + +defineSVGRenderer = function(shapeName, shapeToSVGFunc) { + return renderers[shapeName] = shapeToSVGFunc; +}; + +renderShapeToSVG = function(shape, opts) { + if (opts == null) { + opts = {}; + } + if (opts.shouldIgnoreUnsupportedShapes == null) { + opts.shouldIgnoreUnsupportedShapes = false; + } + if (renderers[shape.className]) { + return renderers[shape.className](shape); + } else if (opts.shouldIgnoreUnsupportedShapes) { + console.warn("Can't render shape of type " + shape.className + " to SVG"); + return ""; + } else { + throw "Can't render shape of type " + shape.className + " to SVG"; + } +}; + +defineSVGRenderer('Rectangle', function(shape) { + var height, width, x, x1, x2, y, y1, y2; + x1 = shape.x; + y1 = shape.y; + x2 = shape.x + shape.width; + y2 = shape.y + shape.height; + x = Math.min(x1, x2); + y = Math.min(y1, y2); + width = Math.max(x1, x2) - x; + height = Math.max(y1, y2) - y; + if (shape.strokeWidth % 2 !== 0) { + x += 0.5; + y += 0.5; + } + return ""; +}); + +defineSVGRenderer('SelectionBox', function(shape) { + return ""; +}); + +defineSVGRenderer('Ellipse', function(shape) { + var centerX, centerY, halfHeight, halfWidth; + halfWidth = Math.floor(shape.width / 2); + halfHeight = Math.floor(shape.height / 2); + centerX = shape.x + halfWidth; + centerY = shape.y + halfHeight; + return ""; +}); + +defineSVGRenderer('Image', function(shape) { + return ""; +}); + +defineSVGRenderer('Line', function(shape) { + var arrowWidth, capString, dashString, x1, x2, y1, y2; + dashString = shape.dash ? "stroke-dasharray='" + (shape.dash.join(', ')) + "'" : ''; + capString = ''; + arrowWidth = Math.max(shape.strokeWidth * 2.2, 5); + x1 = shape.x1; + x2 = shape.x2; + y1 = shape.y1; + y2 = shape.y2; + if (shape.strokeWidth % 2 !== 0) { + x1 += 0.5; + x2 += 0.5; + y1 += 0.5; + y2 += 0.5; + } + if (shape.endCapShapes[0]) { + capString += lineEndCapShapes[shape.endCapShapes[0]].svg(x1, y1, Math.atan2(y1 - y2, x1 - x2), arrowWidth, shape.color); + } + if (shape.endCapShapes[1]) { + capString += lineEndCapShapes[shape.endCapShapes[1]].svg(x2, y2, Math.atan2(y2 - y1, x2 - x1), arrowWidth, shape.color); + } + return " " + capString + " "; +}); + +defineSVGRenderer('LinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('ErasedLinePath', function(shape) { + return ""; +}); + +defineSVGRenderer('Polygon', function(shape) { + if (shape.isClosed) { + return ""; + } else { + return " "; + } +}); + +defineSVGRenderer('Text', function(shape) { + var heightString, textSplitOnLines, widthString; + widthString = shape.forcedWidth ? "width='" + shape.forcedWidth + "px'" : ""; + heightString = shape.forcedHeight ? "height='" + shape.forcedHeight + "px'" : ""; + textSplitOnLines = shape.text.split(/\r\n|\r|\n/g); + if (shape.renderer) { + textSplitOnLines = shape.renderer.lines; + } + return " " + (textSplitOnLines.map((function(_this) { + return function(line, i) { + var dy; + dy = i === 0 ? 0 : '1.2em'; + return " " + line + " "; + }; + })(this)).join('')) + " "; +}); + +module.exports = { + defineSVGRenderer: defineSVGRenderer, + renderShapeToSVG: renderShapeToSVG +}; + + +},{"./lineEndCapShapes":12}],19:[function(require,module,exports){ +var renderShapeToContext, renderShapeToSVG, slice, util, + slice1 = [].slice; + +slice = Array.prototype.slice; + +renderShapeToContext = require('./canvasRenderer').renderShapeToContext; + +renderShapeToSVG = require('./svgRenderer').renderShapeToSVG; + +util = { + addImageOnload: function(img, fn) { + var oldOnload; + oldOnload = img.onload; + img.onload = function() { + if (typeof oldOnload === "function") { + oldOnload(); + } + return fn(); + }; + return img; + }, + last: function(array, n) { + if (n == null) { + n = null; + } + if (n) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }, + classSet: function(classNameToIsPresent) { + var classNames, key; + classNames = []; + for (key in classNameToIsPresent) { + if (classNameToIsPresent[key]) { + classNames.push(key); + } + } + return classNames.join(' '); + }, + matchElementSize: function(elementToMatch, elementsToResize, scale, callback) { + var resize; + if (callback == null) { + callback = function() {}; + } + resize = (function(_this) { + return function() { + var el, i, len; + for (i = 0, len = elementsToResize.length; i < len; i++) { + el = elementsToResize[i]; + el.style.width = elementToMatch.offsetWidth + "px"; + el.style.height = elementToMatch.offsetHeight + "px"; + if (el.width != null) { + el.setAttribute('width', el.offsetWidth * scale); + el.setAttribute('height', el.offsetHeight * scale); + } + } + return callback(); + }; + })(this); + elementToMatch.addEventListener('resize', resize); + window.addEventListener('resize', resize); + window.addEventListener('orientationchange', resize); + return resize(); + }, + combineCanvases: function() { + var c, canvas, canvases, ctx, i, j, len, len1; + canvases = 1 <= arguments.length ? slice1.call(arguments, 0) : []; + c = document.createElement('canvas'); + c.width = canvases[0].width; + c.height = canvases[0].height; + for (i = 0, len = canvases.length; i < len; i++) { + canvas = canvases[i]; + c.width = Math.max(canvas.width, c.width); + c.height = Math.max(canvas.height, c.height); + } + ctx = c.getContext('2d'); + for (j = 0, len1 = canvases.length; j < len1; j++) { + canvas = canvases[j]; + ctx.drawImage(canvas, 0, 0); + } + return c; + }, + renderShapes: function(shapes, bounds, scale, canvas) { + var ctx, i, len, shape; + if (scale == null) { + scale = 1; + } + if (canvas == null) { + canvas = null; + } + canvas = canvas || document.createElement('canvas'); + canvas.width = bounds.width * scale; + canvas.height = bounds.height * scale; + ctx = canvas.getContext('2d'); + ctx.translate(-bounds.x * scale, -bounds.y * scale); + ctx.scale(scale, scale); + for (i = 0, len = shapes.length; i < len; i++) { + shape = shapes[i]; + renderShapeToContext(ctx, shape); + } + return canvas; + }, + renderShapesToSVG: function(shapes, arg, backgroundColor) { + var height, width, x, y; + x = arg.x, y = arg.y, width = arg.width, height = arg.height; + return (" " + (shapes.map(renderShapeToSVG).join('')) + " ").replace(/(\r\n|\n|\r)/gm, ""); + }, + getBoundingRect: function(rects, width, height) { + var i, len, maxX, maxY, minX, minY, rect; + if (!rects.length) { + return { + x: 0, + y: 0, + width: 0 || width, + height: 0 || height + }; + } + minX = rects[0].x; + minY = rects[0].y; + maxX = rects[0].x + rects[0].width; + maxY = rects[0].y + rects[0].height; + for (i = 0, len = rects.length; i < len; i++) { + rect = rects[i]; + minX = Math.floor(Math.min(rect.x, minX)); + minY = Math.floor(Math.min(rect.y, minY)); + maxX = Math.ceil(Math.max(maxX, rect.x + rect.width)); + maxY = Math.ceil(Math.max(maxY, rect.y + rect.height)); + } + minX = width ? 0 : minX; + minY = height ? 0 : minY; + maxX = width || maxX; + maxY = height || maxY; + return { + x: minX, + y: minY, + width: maxX - minX, + height: maxY - minY + }; + }, + getDefaultImageRect: function(shapeBoundingRects, explicitSize, margin) { + var height, rect, width; + if (explicitSize == null) { + explicitSize = { + width: 0, + height: 0 + }; + } + if (margin == null) { + margin = { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; + } + width = explicitSize.width, height = explicitSize.height; + rect = util.getBoundingRect(shapeBoundingRects, width === 'infinite' ? 0 : width, height === 'infinite' ? 0 : height); + rect.x -= margin.left; + rect.y -= margin.top; + rect.width += margin.left + margin.right; + rect.height += margin.top + margin.bottom; + return rect; + }, + getBackingScale: function(context) { + if (window.devicePixelRatio == null) { + return 1; + } + if (!(window.devicePixelRatio > 1)) { + return 1; + } + return window.devicePixelRatio; + }, + requestAnimationFrame: (window.requestAnimationFrame || window.setTimeout).bind(window), + getGUID: (function() { + var s4; + s4 = function() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); + }; + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + }; + })(), + requestAnimationFrame: function(f) { + if (window.webkitRequestAnimationFrame) { + return window.webkitRequestAnimationFrame(f); + } + if (window.requestAnimationFrame) { + return window.requestAnimationFrame(f); + } + if (window.mozRequestAnimationFrame) { + return window.mozRequestAnimationFrame(f); + } + return setTimeout(f, 0); + }, + cancelAnimationFrame: function(f) { + if (window.webkitCancelRequestAnimationFrame) { + return window.webkitCancelRequestAnimationFrame(f); + } + if (window.webkitCancelAnimationFrame) { + return window.webkitCancelAnimationFrame(f); + } + if (window.cancelAnimationFrame) { + return window.cancelAnimationFrame(f); + } + if (window.mozCancelAnimationFrame) { + return window.mozCancelAnimationFrame(f); + } + return clearTimeout(f); + } +}; + +module.exports = util; + + +},{"./canvasRenderer":9,"./svgRenderer":18}],20:[function(require,module,exports){ +'use strict'; + +(function () { + function CustomEvent(event, params) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + }; + + CustomEvent.prototype = window.CustomEvent.prototype; + + window.CustomEvent = CustomEvent; +})(); + +},{}],21:[function(require,module,exports){ +"use strict"; + +var hasWarned = false; +if (!CanvasRenderingContext2D.prototype.setLineDash) { + CanvasRenderingContext2D.prototype.setLineDash = function () { + // no-op + if (!hasWarned) { + console.warn("context2D.setLineDash is a no-op in this browser."); + hasWarned = true; + } + }; +} +module.exports = null; + +},{}],22:[function(require,module,exports){ +var LiterallyCanvasModel, LiterallyCanvasReactComponent, baseTools, canvasRenderer, conversion, defaultImageURLPrefix, defaultOptions, defaultTools, defineOptionsStyle, init, initReactDOM, initWithoutGUI, localize, registerJQueryPlugin, renderSnapshotToImage, renderSnapshotToSVG, setDefaultImageURLPrefix, shapes, svgRenderer, tools, util; + +require('./ie_customevent'); + +require('./ie_setLineDash'); + +LiterallyCanvasModel = require('./core/LiterallyCanvas'); + +defaultOptions = require('./core/defaultOptions'); + +canvasRenderer = require('./core/canvasRenderer'); + +svgRenderer = require('./core/svgRenderer'); + +shapes = require('./core/shapes'); + +util = require('./core/util'); + +renderSnapshotToImage = require('./core/renderSnapshotToImage'); + +renderSnapshotToSVG = require('./core/renderSnapshotToSVG'); + +localize = require('./core/localization').localize; + +LiterallyCanvasReactComponent = require('./reactGUI/LiterallyCanvas'); + +initReactDOM = require('./reactGUI/initDOM'); + +require('./optionsStyles/font'); + +require('./optionsStyles/stroke-width'); + +require('./optionsStyles/line-options-and-stroke-width'); + +require('./optionsStyles/polygon-and-stroke-width'); + +require('./optionsStyles/stroke-or-fill'); + +require('./optionsStyles/null'); + +defineOptionsStyle = require('./optionsStyles/optionsStyles').defineOptionsStyle; + +conversion = { + snapshotToShapes: function(snapshot) { + var i, len, ref, results, shape; + ref = snapshot.shapes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + shape = ref[i]; + results.push(shapes.JSONToShape(shape)); + } + return results; + }, + snapshotJSONToShapes: function(json) { + return conversion.snapshotToShapes(JSON.parse(json)); + } +}; + +baseTools = require('./tools/base'); + +tools = { + Pencil: require('./tools/Pencil'), + Eraser: require('./tools/Eraser'), + Line: require('./tools/Line'), + Rectangle: require('./tools/Rectangle'), + Ellipse: require('./tools/Ellipse'), + Text: require('./tools/Text'), + Polygon: require('./tools/Polygon'), + Pan: require('./tools/Pan'), + Eyedropper: require('./tools/Eyedropper'), + SelectShape: require('./tools/SelectShape'), + Tool: baseTools.Tool, + ToolWithStroke: baseTools.ToolWithStroke +}; + +defaultTools = defaultOptions.tools; + +defaultImageURLPrefix = defaultOptions.imageURLPrefix; + +setDefaultImageURLPrefix = function(newDefault) { + defaultImageURLPrefix = newDefault; + return defaultOptions.imageURLPrefix = newDefault; +}; + +init = function(el, opts) { + var child, i, len, opt, ref; + if (opts == null) { + opts = {}; + } + for (opt in defaultOptions) { + if (!(opt in opts)) { + opts[opt] = defaultOptions[opt]; + } + } + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return require('./reactGUI/initDOM')(el, opts); +}; + +initWithoutGUI = function(el, opts) { + var drawingViewElement, lc, originalClassName; + originalClassName = el.className; + if ([' ', ' '].join(el.className).indexOf(' literally ') === -1) { + el.className = el.className + ' literally'; + } + el.className = el.className + ' toolbar-hidden'; + drawingViewElement = document.createElement('div'); + drawingViewElement.className = 'lc-drawing'; + el.appendChild(drawingViewElement); + lc = new LiterallyCanvasModel(drawingViewElement, opts); + lc.teardown = function() { + var child, i, len, ref; + lc._teardown(); + ref = el.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + el.removeChild(child); + } + return el.className = originalClassName; + }; + if ('onInit' in opts) { + opts.onInit(lc); + } + return lc; +}; + +registerJQueryPlugin = function(_$) { + return _$.fn.literallycanvas = function(opts) { + if (opts == null) { + opts = {}; + } + this.each((function(_this) { + return function(ix, el) { + return el.literallycanvas = init(el, opts); + }; + })(this)); + return this; + }; +}; + +if (typeof window !== 'undefined') { + window.LC = { + init: init + }; + if (window.$) { + registerJQueryPlugin(window.$); + } +} + +module.exports = { + init: init, + registerJQueryPlugin: registerJQueryPlugin, + util: util, + tools: tools, + setDefaultImageURLPrefix: setDefaultImageURLPrefix, + defaultTools: defaultTools, + defineOptionsStyle: defineOptionsStyle, + LiterallyCanvasReactComponent: LiterallyCanvasReactComponent, + defineShape: shapes.defineShape, + createShape: shapes.createShape, + JSONToShape: shapes.JSONToShape, + shapeToJSON: shapes.shapeToJSON, + defineCanvasRenderer: canvasRenderer.defineCanvasRenderer, + renderShapeToContext: canvasRenderer.renderShapeToContext, + renderShapeToCanvas: canvasRenderer.renderShapeToCanvas, + renderShapesToCanvas: util.renderShapes, + defineSVGRenderer: svgRenderer.defineSVGRenderer, + renderShapeToSVG: svgRenderer.renderShapeToSVG, + renderShapesToSVG: util.renderShapesToSVG, + snapshotToShapes: conversion.snapshotToShapes, + snapshotJSONToShapes: conversion.snapshotJSONToShapes, + renderSnapshotToImage: renderSnapshotToImage, + renderSnapshotToSVG: renderSnapshotToSVG, + localize: localize +}; + + +},{"./core/LiterallyCanvas":5,"./core/canvasRenderer":9,"./core/defaultOptions":10,"./core/localization":13,"./core/renderSnapshotToImage":15,"./core/renderSnapshotToSVG":16,"./core/shapes":17,"./core/svgRenderer":18,"./core/util":19,"./ie_customevent":20,"./ie_setLineDash":21,"./optionsStyles/font":23,"./optionsStyles/line-options-and-stroke-width":24,"./optionsStyles/null":25,"./optionsStyles/optionsStyles":26,"./optionsStyles/polygon-and-stroke-width":27,"./optionsStyles/stroke-or-fill":28,"./optionsStyles/stroke-width":29,"./reactGUI/LiterallyCanvas":32,"./reactGUI/initDOM":42,"./tools/Ellipse":43,"./tools/Eraser":44,"./tools/Eyedropper":45,"./tools/Line":46,"./tools/Pan":47,"./tools/Pencil":48,"./tools/Polygon":49,"./tools/Rectangle":50,"./tools/SelectShape":51,"./tools/Text":52,"./tools/base":53}],23:[function(require,module,exports){ +var ALL_FONTS, FONT_NAME_TO_VALUE, MONOSPACE_FONTS, OTHER_FONTS, React, SANS_SERIF_FONTS, SERIF_FONTS, _, defineOptionsStyle, i, j, l, len, len1, len2, len3, m, name, ref, ref1, ref2, ref3, value; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +_ = require('../core/localization')._; + +SANS_SERIF_FONTS = [['Arial', 'Arial,"Helvetica Neue",Helvetica,sans-serif'], ['Arial Black', '"Arial Black","Arial Bold",Gadget,sans-serif'], ['Arial Narrow', '"Arial Narrow",Arial,sans-serif'], ['Gill Sans', '"Gill Sans","Gill Sans MT",Calibri,sans-serif'], ['Helvetica', '"Helvetica Neue",Helvetica,Arial,sans-serif'], ['Impact', 'Impact,Haettenschweiler,"Franklin Gothic Bold",Charcoal,"Helvetica Inserat","Bitstream Vera Sans Bold","Arial Black",sans-serif'], ['Tahoma', 'Tahoma,Verdana,Segoe,sans-serif'], ['Trebuchet MS', '"Trebuchet MS","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Tahoma,sans-serif'], ['Verdana', 'Verdana,Geneva,sans-serif']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +SERIF_FONTS = [['Baskerville', 'Baskerville,"Baskerville Old Face","Hoefler Text",Garamond,"Times New Roman",serif'], ['Garamond', 'Garamond,Baskerville,"Baskerville Old Face","Hoefler Text","Times New Roman",serif'], ['Georgia', 'Georgia,Times,"Times New Roman",serif'], ['Hoefler Text', '"Hoefler Text","Baskerville Old Face",Garamond,"Times New Roman",serif'], ['Lucida Bright', '"Lucida Bright",Georgia,serif'], ['Palatino', 'Palatino,"Palatino Linotype","Palatino LT STD","Book Antiqua",Georgia,serif'], ['Times New Roman', 'TimesNewRoman,"Times New Roman",Times,Baskerville,Georgia,serif']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +MONOSPACE_FONTS = [['Consolas/Monaco', 'Consolas,monaco,"Lucida Console",monospace'], ['Courier New', '"Courier New",Courier,"Lucida Sans Typewriter","Lucida Typewriter",monospace'], ['Lucida Sans Typewriter', '"Lucida Sans Typewriter","Lucida Console",monaco,"Bitstream Vera Sans Mono",monospace']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +OTHER_FONTS = [['Copperplate', 'Copperplate,"Copperplate Gothic Light",fantasy'], ['Papyrus', 'Papyrus,fantasy'], ['Script', '"Brush Script MT",cursive']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +ALL_FONTS = [[_('Sans Serif'), SANS_SERIF_FONTS], [_('Serif'), SERIF_FONTS], [_('Monospace'), MONOSPACE_FONTS], [_('Other'), OTHER_FONTS]]; + +FONT_NAME_TO_VALUE = {}; + +for (i = 0, len = SANS_SERIF_FONTS.length; i < len; i++) { + ref = SANS_SERIF_FONTS[i], name = ref.name, value = ref.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (j = 0, len1 = SERIF_FONTS.length; j < len1; j++) { + ref1 = SERIF_FONTS[j], name = ref1.name, value = ref1.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (l = 0, len2 = MONOSPACE_FONTS.length; l < len2; l++) { + ref2 = MONOSPACE_FONTS[l], name = ref2.name, value = ref2.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (m = 0, len3 = OTHER_FONTS.length; m < len3; m++) { + ref3 = OTHER_FONTS[m], name = ref3.name, value = ref3.value; + FONT_NAME_TO_VALUE[name] = value; +} + +defineOptionsStyle('font', React.createClass({ + displayName: 'FontOptions', + getInitialState: function() { + return { + isItalic: false, + isBold: false, + fontName: 'Helvetica', + fontSizeIndex: 4 + }; + }, + getFontSizes: function() { + return [9, 10, 12, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288]; + }, + updateTool: function(newState) { + var fontSize, items, k; + if (newState == null) { + newState = {}; + } + for (k in this.state) { + if (!(k in newState)) { + newState[k] = this.state[k]; + } + } + fontSize = this.getFontSizes()[newState.fontSizeIndex]; + items = []; + if (newState.isItalic) { + items.push('italic'); + } + if (newState.isBold) { + items.push('bold'); + } + items.push(fontSize + "px"); + items.push(FONT_NAME_TO_VALUE[newState.fontName]); + this.props.lc.tool.font = items.join(' '); + return this.props.lc.trigger('setFont', items.join(' ')); + }, + handleFontSize: function(event) { + var newState; + newState = { + fontSizeIndex: event.target.value + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleFontFamily: function(event) { + var newState; + newState = { + fontName: event.target.selectedOptions[0].innerHTML + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleItalic: function(event) { + var newState; + newState = { + isItalic: !this.state.isItalic + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleBold: function(event) { + var newState; + newState = { + isBold: !this.state.isBold + }; + this.setState(newState); + return this.updateTool(newState); + }, + componentDidMount: function() { + return this.updateTool(); + }, + render: function() { + var br, div, input, label, lc, optgroup, option, ref4, select, span; + lc = this.props.lc; + ref4 = React.DOM, div = ref4.div, input = ref4.input, select = ref4.select, option = ref4.option, br = ref4.br, label = ref4.label, span = ref4.span, optgroup = ref4.optgroup; + return div({ + className: 'lc-font-settings' + }, select({ + value: this.state.fontSizeIndex, + onChange: this.handleFontSize + }, this.getFontSizes().map((function(_this) { + return function(size, ix) { + return option({ + value: ix, + key: ix + }, size + "px"); + }; + })(this))), select({ + value: this.state.fontName, + onChange: this.handleFontFamily + }, ALL_FONTS.map((function(_this) { + return function(arg) { + var fonts, label; + label = arg[0], fonts = arg[1]; + return optgroup({ + key: label, + label: label + }, fonts.map(function(family, ix) { + return option({ + value: family.name, + key: ix + }, family.name); + })); + }; + })(this))), span({}, label({ + htmlFor: 'italic' + }, _("italic")), input({ + type: 'checkbox', + id: 'italic', + checked: this.state.isItalic, + onChange: this.handleItalic + })), span({}, label({ + htmlFor: 'bold' + }, _("bold")), input({ + type: 'checkbox', + id: 'bold', + checked: this.state.isBold, + onChange: this.handleBold + }))); + } +})); + +module.exports = {}; + + +},{"../core/localization":13,"../reactGUI/React-shim":35,"./optionsStyles":26}],24:[function(require,module,exports){ +var React, StrokeWidthPicker, classSet, createSetStateOnEventMixin, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = React.createFactory(require('../reactGUI/StrokeWidthPicker')); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +defineOptionsStyle('line-options-and-stroke-width', React.createClass({ + displayName: 'LineOptionsAndStrokeWidth', + getState: function() { + return { + strokeWidth: this.props.tool.strokeWidth, + isDashed: this.props.tool.isDashed, + hasEndArrow: this.props.tool.hasEndArrow + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + render: function() { + var arrowButtonClass, dashButtonClass, div, img, li, ref, style, toggleIsDashed, togglehasEndArrow, ul; + ref = React.DOM, div = ref.div, ul = ref.ul, li = ref.li, img = ref.img; + toggleIsDashed = (function(_this) { + return function() { + _this.props.tool.isDashed = !_this.props.tool.isDashed; + return _this.setState(_this.getState()); + }; + })(this); + togglehasEndArrow = (function(_this) { + return function() { + _this.props.tool.hasEndArrow = !_this.props.tool.hasEndArrow; + return _this.setState(_this.getState()); + }; + })(this); + dashButtonClass = classSet({ + 'square-toolbar-button': true, + 'selected': this.state.isDashed + }); + arrowButtonClass = classSet({ + 'square-toolbar-button': true, + 'selected': this.state.hasEndArrow + }); + style = { + float: 'left', + margin: 1 + }; + return div({}, div({ + className: dashButtonClass, + onClick: toggleIsDashed, + style: style + }, img({ + src: this.props.imageURLPrefix + "/dashed-line.png" + })), div({ + className: arrowButtonClass, + onClick: togglehasEndArrow, + style: style + }, img({ + src: this.props.imageURLPrefix + "/line-with-arrow.png" + })), StrokeWidthPicker({ + tool: this.props.tool, + lc: this.props.lc + })); + } +})); + +module.exports = {}; + + +},{"../core/util":19,"../reactGUI/React-shim":35,"../reactGUI/StrokeWidthPicker":37,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],25:[function(require,module,exports){ +var React, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +defineOptionsStyle('null', React.createClass({ + displayName: 'NoOptions', + render: function() { + return React.DOM.div(); + } +})); + +module.exports = {}; + + +},{"../reactGUI/React-shim":35,"./optionsStyles":26}],26:[function(require,module,exports){ +var React, defineOptionsStyle, optionsStyles; + +React = require('../reactGUI/React-shim'); + +optionsStyles = {}; + +defineOptionsStyle = function(name, style) { + return optionsStyles[name] = React.createFactory(style); +}; + +module.exports = { + optionsStyles: optionsStyles, + defineOptionsStyle: defineOptionsStyle +}; + + +},{"../reactGUI/React-shim":35}],27:[function(require,module,exports){ +var React, StrokeWidthPicker, createSetStateOnEventMixin, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = React.createFactory(require('../reactGUI/StrokeWidthPicker')); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +defineOptionsStyle('polygon-and-stroke-width', React.createClass({ + displayName: 'PolygonAndStrokeWidth', + getState: function() { + return { + strokeWidth: this.props.tool.strokeWidth, + inProgress: false + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + componentDidMount: function() { + var hidePolygonTools, showPolygonTools, unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + showPolygonTools = (function(_this) { + return function() { + if (!_this.state.inProgress) { + return _this.setState({ + inProgress: true + }); + } + }; + })(this); + hidePolygonTools = (function(_this) { + return function() { + return _this.setState({ + inProgress: false + }); + }; + })(this); + unsubscribeFuncs.push(this.props.lc.on('lc-polygon-started', showPolygonTools)); + return unsubscribeFuncs.push(this.props.lc.on('lc-polygon-stopped', hidePolygonTools)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + }, + render: function() { + var div, img, lc, polygonCancel, polygonFinishClosed, polygonFinishOpen, polygonToolStyle, ref; + lc = this.props.lc; + ref = React.DOM, div = ref.div, img = ref.img; + polygonFinishOpen = (function(_this) { + return function() { + return lc.trigger('lc-polygon-finishopen'); + }; + })(this); + polygonFinishClosed = (function(_this) { + return function() { + return lc.trigger('lc-polygon-finishclosed'); + }; + })(this); + polygonCancel = (function(_this) { + return function() { + return lc.trigger('lc-polygon-cancel'); + }; + })(this); + polygonToolStyle = {}; + if (!this.state.inProgress) { + polygonToolStyle = { + display: 'none' + }; + } + return div({}, div({ + className: 'polygon-toolbar horz-toolbar', + style: polygonToolStyle + }, div({ + className: 'square-toolbar-button', + onClick: polygonFinishOpen + }, img({ + src: this.props.imageURLPrefix + "/polygon-open.png" + })), div({ + className: 'square-toolbar-button', + onClick: polygonFinishClosed + }, img({ + src: this.props.imageURLPrefix + "/polygon-closed.png" + })), div({ + className: 'square-toolbar-button', + onClick: polygonCancel + }, img({ + src: this.props.imageURLPrefix + "/polygon-cancel.png" + }))), div({}, StrokeWidthPicker({ + tool: this.props.tool, + lc: this.props.lc + }))); + } +})); + +module.exports = {}; + + +},{"../reactGUI/React-shim":35,"../reactGUI/StrokeWidthPicker":37,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],28:[function(require,module,exports){ +'use strict'; + +var React = require('../reactGUI/React-shim'); + +var _require = require('./optionsStyles'); + +var defineOptionsStyle = _require.defineOptionsStyle; + +var createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +defineOptionsStyle('stroke-or-fill', React.createClass({ + displayName: 'StrokeOrFillPicker', + getState: function getState() { + return { strokeOrFill: 'stroke' }; + }, + getInitialState: function getInitialState() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + + onChange: function onChange(e) { + if (e.target.id == 'stroke-or-fill-stroke') { + this.props.lc.tool.strokeOrFill = 'stroke'; + } else { + this.props.lc.tool.strokeOrFill = 'fill'; + } + this.setState(this.getState()); + }, + + render: function render() { + var lc = this.props.lc; + + return React.createElement( + 'form', + null, + React.createElement( + 'span', + null, + 'Color to change: ' + ), + React.createElement( + 'span', + null, + React.createElement('input', { type: 'radio', name: 'stroke-or-fill', value: 'stroke', + id: 'stroke-or-fill-stroke', onChange: this.onChange, + checked: lc.tool.strokeOrFill == 'stroke' }), + React.createElement( + 'label', + { htmlFor: 'stroke-or-fill-stroke', className: 'label' }, + ' stroke' + ) + ), + React.createElement( + 'span', + null, + React.createElement('input', { type: 'radio', name: 'stroke-or-fill', value: 'fill', + id: 'stroke-or-fill-fill', onChange: this.onChange, + checked: lc.tool.strokeOrFill == 'fill' }), + React.createElement( + 'label', + { htmlFor: 'stroke-or-fill-fill', className: 'label' }, + ' fill' + ) + ) + ); + } +})); + +module.exports = {}; + +},{"../reactGUI/React-shim":35,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],29:[function(require,module,exports){ +var StrokeWidthPicker, defineOptionsStyle; + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = require('../reactGUI/StrokeWidthPicker'); + +defineOptionsStyle('stroke-width', StrokeWidthPicker); + +module.exports = {}; + + +},{"../reactGUI/StrokeWidthPicker":37,"./optionsStyles":26}],30:[function(require,module,exports){ +var ClearButton, React, _, classSet, createSetStateOnEventMixin; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +_ = require('../core/localization')._; + +classSet = require('../core/util').classSet; + +ClearButton = React.createClass({ + displayName: 'ClearButton', + getState: function() { + return { + isEnabled: this.props.lc.canUndo() + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('drawingChange')], + render: function() { + var className, div, lc, onClick; + div = React.DOM.div; + lc = this.props.lc; + className = classSet({ + 'lc-clear': true, + 'toolbar-button': true, + 'fat-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = lc.canUndo() ? ((function(_this) { + return function() { + return lc.clear(); + }; + })(this)) : function() {}; + return div({ + className: className, + onClick: onClick + }, _('Clear')); + } +}); + +module.exports = ClearButton; + + +},{"../core/localization":13,"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],31:[function(require,module,exports){ +var ColorGrid, ColorWell, PureRenderMixin, React, cancelAnimationFrame, classSet, getHSLAString, getHSLString, parseHSLAString, ref, requestAnimationFrame; + +React = require('./React-shim'); + +PureRenderMixin = require('react-addons-pure-render-mixin'); + +ref = require('../core/util'), classSet = ref.classSet, requestAnimationFrame = ref.requestAnimationFrame, cancelAnimationFrame = ref.cancelAnimationFrame; + +parseHSLAString = function(s) { + var components, firstParen, insideParens, lastParen; + if (s === 'transparent') { + return { + hue: 0, + sat: 0, + light: 0, + alpha: 0 + }; + } + if (s.substring(0, 4) !== 'hsla') { + return null; + } + firstParen = s.indexOf('('); + lastParen = s.indexOf(')'); + insideParens = s.substring(firstParen + 1, lastParen - firstParen + 4); + components = (function() { + var j, len, ref1, results; + ref1 = insideParens.split(','); + results = []; + for (j = 0, len = ref1.length; j < len; j++) { + s = ref1[j]; + results.push(s.trim()); + } + return results; + })(); + return { + hue: parseInt(components[0], 10), + sat: parseInt(components[1].substring(0, components[1].length - 1), 10), + light: parseInt(components[2].substring(0, components[2].length - 1), 10), + alpha: parseFloat(components[3]) + }; +}; + +getHSLAString = function(arg) { + var alpha, hue, light, sat; + hue = arg.hue, sat = arg.sat, light = arg.light, alpha = arg.alpha; + return "hsla(" + hue + ", " + sat + "%, " + light + "%, " + alpha + ")"; +}; + +getHSLString = function(arg) { + var hue, light, sat; + hue = arg.hue, sat = arg.sat, light = arg.light; + return "hsl(" + hue + ", " + sat + "%, " + light + "%)"; +}; + +ColorGrid = React.createFactory(React.createClass({ + displayName: 'ColorGrid', + mixins: [PureRenderMixin], + render: function() { + var div; + div = React.DOM.div; + return div({}, this.props.rows.map((function(_this) { + return function(row, ix) { + return div({ + className: 'color-row', + key: ix, + style: { + width: 20 * row.length + } + }, row.map(function(cellColor, ix2) { + var alpha, className, colorString, colorStringNoAlpha, hue, light, sat, update; + hue = cellColor.hue, sat = cellColor.sat, light = cellColor.light, alpha = cellColor.alpha; + colorString = getHSLAString(cellColor); + colorStringNoAlpha = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; + className = classSet({ + 'color-cell': true, + 'selected': _this.props.selectedColor === colorString + }); + update = function(e) { + _this.props.onChange(cellColor, colorString); + e.stopPropagation(); + return e.preventDefault(); + }; + return div({ + className: className, + onTouchStart: update, + onTouchMove: update, + onClick: update, + style: { + backgroundColor: colorStringNoAlpha + }, + key: ix2 + }); + })); + }; + })(this))); + } +})); + +ColorWell = React.createClass({ + displayName: 'ColorWell', + mixins: [PureRenderMixin], + getInitialState: function() { + var colorString, hsla; + colorString = this.props.lc.colors[this.props.colorName]; + hsla = parseHSLAString(colorString); + if (hsla == null) { + hsla = {}; + } + if (hsla.alpha == null) { + hsla.alpha = 1; + } + if (hsla.sat == null) { + hsla.sat = 100; + } + if (hsla.hue == null) { + hsla.hue = 0; + } + if (hsla.light == null) { + hsla.light = 50; + } + return { + colorString: colorString, + alpha: hsla.alpha, + sat: hsla.sat === 0 ? 100 : hsla.sat, + isPickerVisible: false, + hsla: hsla + }; + }, + componentDidMount: function() { + return this.unsubscribe = this.props.lc.on(this.props.colorName + "ColorChange", (function(_this) { + return function() { + var colorString; + colorString = _this.props.lc.colors[_this.props.colorName]; + _this.setState({ + colorString: colorString + }); + return _this.setHSLAFromColorString(colorString); + }; + })(this)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + }, + setHSLAFromColorString: function(c) { + var hsla; + hsla = parseHSLAString(c); + if (hsla) { + return this.setState({ + hsla: hsla, + alpha: hsla.alpha, + sat: hsla.sat + }); + } else { + return this.setState({ + hsla: null, + alpha: 1, + sat: 100 + }); + } + }, + closePicker: function() { + return this.setState({ + isPickerVisible: false + }); + }, + togglePicker: function() { + var isPickerVisible, shouldResetSat; + isPickerVisible = !this.state.isPickerVisible; + shouldResetSat = isPickerVisible && this.state.sat === 0; + this.setHSLAFromColorString(this.state.colorString); + return this.setState({ + isPickerVisible: isPickerVisible, + sat: shouldResetSat ? 100 : this.state.sat + }); + }, + setColor: function(c) { + this.setState({ + colorString: c + }); + this.setHSLAFromColorString(c); + return this.props.lc.setColor(this.props.colorName, c); + }, + setAlpha: function(alpha) { + var hsla; + this.setState({ + alpha: alpha + }); + if (this.state.hsla) { + hsla = this.state.hsla; + hsla.alpha = alpha; + this.setState({ + hsla: hsla + }); + return this.setColor(getHSLAString(hsla)); + } + }, + setSat: function(sat) { + var hsla; + this.setState({ + sat: sat + }); + if (isNaN(sat)) { + throw "SAT"; + } + if (this.state.hsla) { + hsla = this.state.hsla; + hsla.sat = sat; + this.setState({ + hsla: hsla + }); + return this.setColor(getHSLAString(hsla)); + } + }, + render: function() { + var br, div, label, ref1; + ref1 = React.DOM, div = ref1.div, label = ref1.label, br = ref1.br; + return div({ + className: classSet({ + 'color-well': true, + 'open': this.state.isPickerVisible + }), + onMouseLeave: this.closePicker, + style: { + float: 'left', + textAlign: 'center' + } + }, label({ + float: 'left' + }, this.props.label), br({}), div({ + className: classSet({ + 'color-well-color-container': true, + 'selected': this.state.isPickerVisible + }), + style: { + backgroundColor: 'white' + }, + onClick: this.togglePicker + }, div({ + className: 'color-well-checker color-well-checker-top-left' + }), div({ + className: 'color-well-checker color-well-checker-bottom-right', + style: { + left: '50%', + top: '50%' + } + }), div({ + className: 'color-well-color', + style: { + backgroundColor: this.state.colorString + } + }, " ")), this.renderPicker()); + }, + renderPicker: function() { + var div, hue, i, input, j, label, len, onSelectColor, ref1, ref2, renderColor, renderLabel, rows; + ref1 = React.DOM, div = ref1.div, label = ref1.label, input = ref1.input; + if (!this.state.isPickerVisible) { + return null; + } + renderLabel = (function(_this) { + return function(text) { + return div({ + className: 'color-row label', + key: text, + style: { + lineHeight: '20px', + height: 16 + } + }, text); + }; + })(this); + renderColor = (function(_this) { + return function() { + var checkerboardURL; + checkerboardURL = _this.props.lc.opts.imageURLPrefix + "/checkerboard-8x8.png"; + return div({ + className: 'color-row', + key: "color", + style: { + position: 'relative', + backgroundImage: "url(" + checkerboardURL + ")", + backgroundRepeat: 'repeat', + height: 24 + } + }, div({ + style: { + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + backgroundColor: _this.state.colorString + } + })); + }; + })(this); + rows = []; + rows.push((function() { + var j, results; + results = []; + for (i = j = 0; j <= 100; i = j += 10) { + results.push({ + hue: 0, + sat: 0, + light: i, + alpha: this.state.alpha + }); + } + return results; + }).call(this)); + ref2 = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]; + for (j = 0, len = ref2.length; j < len; j++) { + hue = ref2[j]; + rows.push((function() { + var k, results; + results = []; + for (i = k = 10; k <= 90; i = k += 8) { + results.push({ + hue: hue, + sat: this.state.sat, + light: i, + alpha: this.state.alpha + }); + } + return results; + }).call(this)); + } + onSelectColor = (function(_this) { + return function(hsla, s) { + return _this.setColor(s); + }; + })(this); + return div({ + className: 'color-picker-popup' + }, renderColor(), renderLabel("alpha"), input({ + type: 'range', + min: 0, + max: 1, + step: 0.01, + value: this.state.alpha, + onChange: (function(_this) { + return function(e) { + return _this.setAlpha(parseFloat(e.target.value)); + }; + })(this) + }), renderLabel("saturation"), input({ + type: 'range', + min: 0, + max: 100, + value: this.state.sat, + max: 100, + onChange: (function(_this) { + return function(e) { + return _this.setSat(parseInt(e.target.value, 10)); + }; + })(this) + }), ColorGrid({ + rows: rows, + selectedColor: this.state.colorString, + onChange: onSelectColor + })); + } +}); + +module.exports = ColorWell; + + +},{"../core/util":19,"./React-shim":35,"react-addons-pure-render-mixin":1}],32:[function(require,module,exports){ +'use strict'; + +var React = require('../reactGUI/React-shim'); + +var _require = require('../reactGUI/ReactDOM-shim'); + +var findDOMNode = _require.findDOMNode; + +var _require2 = require('../core/util'); + +var classSet = _require2.classSet; + +var Picker = require('./Picker'); +var Options = require('./Options'); +var createToolButton = require('./createToolButton'); +var LiterallyCanvasModel = require('../core/LiterallyCanvas'); +var defaultOptions = require('../core/defaultOptions'); + +require('../optionsStyles/font'); +require('../optionsStyles/stroke-width'); +require('../optionsStyles/line-options-and-stroke-width'); +require('../optionsStyles/polygon-and-stroke-width'); +require('../optionsStyles/null'); + +var CanvasContainer = React.createClass({ + displayName: 'CanvasContainer', + shouldComponentUpdate: function shouldComponentUpdate() { + // Avoid React trying to control this DOM + return false; + }, + render: function render() { + return React.createElement('div', { key: 'literallycanvas', className: 'lc-drawing with-gui' }); + } +}); + +var LiterallyCanvas = React.createClass({ + displayName: 'LiterallyCanvas', + + getDefaultProps: function getDefaultProps() { + return defaultOptions; + }, + bindToModel: function bindToModel() { + var canvasContainerEl = findDOMNode(this.canvas); + var opts = this.props; + this.lc.bindToElement(canvasContainerEl); + + if (typeof opts.onInit === 'function') { + opts.onInit(this.lc); + } + }, + componentWillMount: function componentWillMount() { + var _this = this; + + if (this.lc) return; + + if (this.props.lc) { + this.lc = this.props.lc; + } else { + this.lc = new LiterallyCanvasModel(this.props); + } + + this.toolButtonComponents = this.lc.opts.tools.map(function (ToolClass) { + return createToolButton(new ToolClass(_this.lc)); + }); + }, + componentDidMount: function componentDidMount() { + if (!this.lc.isBound) { + this.bindToModel(); + } + }, + componentWillUnmount: function componentWillUnmount() { + if (this.lc) { + this.lc._teardown(); + } + }, + render: function render() { + var _this2 = this; + + var lc = this.lc; + var toolButtonComponents = this.toolButtonComponents; + var props = this.props; + var _lc$opts = this.lc.opts; + var imageURLPrefix = _lc$opts.imageURLPrefix; + var toolbarPosition = _lc$opts.toolbarPosition; + + var pickerProps = { lc: lc, toolButtonComponents: toolButtonComponents, imageURLPrefix: imageURLPrefix }; + var topOrBottomClassName = classSet({ + 'toolbar-at-top': toolbarPosition === 'top', + 'toolbar-at-bottom': toolbarPosition === 'bottom', + 'toolbar-hidden': toolbarPosition === 'hidden' + }); + return React.createElement( + 'div', + { className: 'literally ' + topOrBottomClassName }, + React.createElement(CanvasContainer, { ref: function ref(item) { + return _this2.canvas = item; + } }), + React.createElement(Picker, pickerProps), + React.createElement(Options, { lc: lc, imageURLPrefix: imageURLPrefix }) + ); + } +}); + +module.exports = LiterallyCanvas; + +},{"../core/LiterallyCanvas":5,"../core/defaultOptions":10,"../core/util":19,"../optionsStyles/font":23,"../optionsStyles/line-options-and-stroke-width":24,"../optionsStyles/null":25,"../optionsStyles/polygon-and-stroke-width":27,"../optionsStyles/stroke-width":29,"../reactGUI/React-shim":35,"../reactGUI/ReactDOM-shim":36,"./Options":33,"./Picker":34,"./createToolButton":41}],33:[function(require,module,exports){ +var Options, React, createSetStateOnEventMixin, optionsStyles; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +optionsStyles = require('../optionsStyles/optionsStyles').optionsStyles; + +Options = React.createClass({ + displayName: 'Options', + getState: function() { + var ref; + return { + style: (ref = this.props.lc.tool) != null ? ref.optionsStyle : void 0, + tool: this.props.lc.tool + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + renderBody: function() { + var style; + style = "" + this.state.style; + return optionsStyles[style] && optionsStyles[style]({ + lc: this.props.lc, + tool: this.state.tool, + imageURLPrefix: this.props.imageURLPrefix + }); + }, + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-options horz-toolbar' + }, this.renderBody()); + } +}); + +module.exports = Options; + + +},{"../optionsStyles/optionsStyles":26,"./React-shim":35,"./createSetStateOnEventMixin":40}],34:[function(require,module,exports){ +var ClearButton, ColorPickers, ColorWell, Picker, React, UndoRedoButtons, ZoomButtons, _; + +React = require('./React-shim'); + +ClearButton = React.createFactory(require('./ClearButton')); + +UndoRedoButtons = React.createFactory(require('./UndoRedoButtons')); + +ZoomButtons = React.createFactory(require('./ZoomButtons')); + +_ = require('../core/localization')._; + +ColorWell = React.createFactory(require('./ColorWell')); + +ColorPickers = React.createFactory(React.createClass({ + displayName: 'ColorPickers', + render: function() { + var div, lc; + lc = this.props.lc; + div = React.DOM.div; + return div({ + className: 'lc-color-pickers' + }, ColorWell({ + lc: lc, + colorName: 'primary', + label: _('stroke') + }), ColorWell({ + lc: lc, + colorName: 'secondary', + label: _('fill') + }), ColorWell({ + lc: lc, + colorName: 'background', + label: _('bg') + })); + } +})); + +Picker = React.createClass({ + displayName: 'Picker', + getInitialState: function() { + return { + selectedToolIndex: 0 + }; + }, + renderBody: function() { + var div, imageURLPrefix, lc, ref, toolButtonComponents; + div = React.DOM.div; + ref = this.props, toolButtonComponents = ref.toolButtonComponents, lc = ref.lc, imageURLPrefix = ref.imageURLPrefix; + return div({ + className: 'lc-picker-contents' + }, toolButtonComponents.map((function(_this) { + return function(component, ix) { + return component({ + lc: lc, + imageURLPrefix: imageURLPrefix, + key: ix, + isSelected: ix === _this.state.selectedToolIndex, + onSelect: function(tool) { + lc.setTool(tool); + return _this.setState({ + selectedToolIndex: ix + }); + } + }); + }; + })(this)), toolButtonComponents.length % 2 !== 0 ? div({ + className: 'toolbar-button thin-button disabled' + }) : void 0, div({ + style: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0 + } + }, ColorPickers({ + lc: this.props.lc + }), UndoRedoButtons({ + lc: lc, + imageURLPrefix: imageURLPrefix + }), ZoomButtons({ + lc: lc, + imageURLPrefix: imageURLPrefix + }), ClearButton({ + lc: lc + }))); + }, + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-picker' + }, this.renderBody()); + } +}); + +module.exports = Picker; + + +},{"../core/localization":13,"./ClearButton":30,"./ColorWell":31,"./React-shim":35,"./UndoRedoButtons":38,"./ZoomButtons":39}],35:[function(require,module,exports){ +var React, error; + +try { + React = require('react'); +} catch (error) { + React = window.React; +} + +if (React == null) { + throw "Can't find React"; +} + +module.exports = React; + + +},{"react":"react"}],36:[function(require,module,exports){ +var ReactDOM, error, error1; + +try { + ReactDOM = require('react-dom'); +} catch (error) { + ReactDOM = window.ReactDOM; +} + +if (ReactDOM == null) { + try { + ReactDOM = require('react'); + } catch (error1) { + ReactDOM = window.React; + } +} + +if (ReactDOM == null) { + throw "Can't find ReactDOM"; +} + +module.exports = ReactDOM; + + +},{"react":"react","react-dom":"react-dom"}],37:[function(require,module,exports){ +var React, classSet, createSetStateOnEventMixin; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +module.exports = React.createClass({ + displayName: 'StrokeWidthPicker', + getState: function(tool) { + if (tool == null) { + tool = this.props.tool; + } + return { + strokeWidth: tool.strokeWidth + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolDidUpdateOptions')], + componentWillReceiveProps: function(props) { + return this.setState(this.getState(props.tool)); + }, + render: function() { + var circle, div, li, ref, strokeWidths, svg, ul; + ref = React.DOM, ul = ref.ul, li = ref.li, svg = ref.svg, circle = ref.circle, div = ref.div; + strokeWidths = this.props.lc.opts.strokeWidths; + return div({}, strokeWidths.map((function(_this) { + return function(strokeWidth, ix) { + var buttonClassName, buttonSize; + buttonClassName = classSet({ + 'square-toolbar-button': true, + 'selected': strokeWidth === _this.state.strokeWidth + }); + buttonSize = 28; + return div({ + key: strokeWidth + }, div({ + className: buttonClassName, + onClick: function() { + return _this.props.lc.trigger('setStrokeWidth', strokeWidth); + } + }, svg({ + width: buttonSize - 2, + height: buttonSize - 2, + viewPort: "0 0 " + strokeWidth + " " + strokeWidth, + version: "1.1", + xmlns: "http://www.w3.org/2000/svg" + }, circle({ + cx: Math.ceil(buttonSize / 2 - 1), + cy: Math.ceil(buttonSize / 2 - 1), + r: strokeWidth / 2 + })))); + }; + })(this))); + } +}); + + +},{"../core/util":19,"../reactGUI/createSetStateOnEventMixin":40,"./React-shim":35}],38:[function(require,module,exports){ +var React, RedoButton, UndoButton, UndoRedoButtons, classSet, createSetStateOnEventMixin, createUndoRedoButtonComponent; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +createUndoRedoButtonComponent = function(undoOrRedo) { + return React.createClass({ + displayName: undoOrRedo === 'undo' ? 'UndoButton' : 'RedoButton', + getState: function() { + return { + isEnabled: (function() { + switch (false) { + case undoOrRedo !== 'undo': + return this.props.lc.canUndo(); + case undoOrRedo !== 'redo': + return this.props.lc.canRedo(); + } + }).call(this) + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('drawingChange')], + render: function() { + var className, div, imageURLPrefix, img, lc, onClick, ref, ref1, src, style, title; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, lc = ref1.lc, imageURLPrefix = ref1.imageURLPrefix; + title = undoOrRedo === 'undo' ? 'Undo' : 'Redo'; + className = ("lc-" + undoOrRedo + " ") + classSet({ + 'toolbar-button': true, + 'thin-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = (function() { + switch (false) { + case !!this.state.isEnabled: + return function() {}; + case undoOrRedo !== 'undo': + return function() { + return lc.undo(); + }; + case undoOrRedo !== 'redo': + return function() { + return lc.redo(); + }; + } + }).call(this); + src = imageURLPrefix + "/" + undoOrRedo + ".png"; + style = { + backgroundImage: "url(" + src + ")" + }; + return div({ + className: className, + onClick: onClick, + title: title, + style: style + }); + } + }); +}; + +UndoButton = React.createFactory(createUndoRedoButtonComponent('undo')); + +RedoButton = React.createFactory(createUndoRedoButtonComponent('redo')); + +UndoRedoButtons = React.createClass({ + displayName: 'UndoRedoButtons', + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-undo-redo' + }, UndoButton(this.props), RedoButton(this.props)); + } +}); + +module.exports = UndoRedoButtons; + + +},{"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],39:[function(require,module,exports){ +var React, ZoomButtons, ZoomInButton, ZoomOutButton, classSet, createSetStateOnEventMixin, createZoomButtonComponent; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +createZoomButtonComponent = function(inOrOut) { + return React.createClass({ + displayName: inOrOut === 'in' ? 'ZoomInButton' : 'ZoomOutButton', + getState: function() { + return { + isEnabled: (function() { + switch (false) { + case inOrOut !== 'in': + return this.props.lc.scale < this.props.lc.config.zoomMax; + case inOrOut !== 'out': + return this.props.lc.scale > this.props.lc.config.zoomMin; + } + }).call(this) + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('zoom')], + render: function() { + var className, div, imageURLPrefix, img, lc, onClick, ref, ref1, src, style, title; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, lc = ref1.lc, imageURLPrefix = ref1.imageURLPrefix; + title = inOrOut === 'in' ? 'Zoom in' : 'Zoom out'; + className = ("lc-zoom-" + inOrOut + " ") + classSet({ + 'toolbar-button': true, + 'thin-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = (function() { + switch (false) { + case !!this.state.isEnabled: + return function() {}; + case inOrOut !== 'in': + return function() { + return lc.zoom(lc.config.zoomStep); + }; + case inOrOut !== 'out': + return function() { + return lc.zoom(-lc.config.zoomStep); + }; + } + }).call(this); + src = imageURLPrefix + "/zoom-" + inOrOut + ".png"; + style = { + backgroundImage: "url(" + src + ")" + }; + return div({ + className: className, + onClick: onClick, + title: title, + style: style + }); + } + }); +}; + +ZoomOutButton = React.createFactory(createZoomButtonComponent('out')); + +ZoomInButton = React.createFactory(createZoomButtonComponent('in')); + +ZoomButtons = React.createClass({ + displayName: 'ZoomButtons', + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-zoom' + }, ZoomOutButton(this.props), ZoomInButton(this.props)); + } +}); + +module.exports = ZoomButtons; + + +},{"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],40:[function(require,module,exports){ +var React, createSetStateOnEventMixin; + +React = require('./React-shim'); + +module.exports = createSetStateOnEventMixin = function(eventName) { + return { + componentDidMount: function() { + return this.unsubscribe = this.props.lc.on(eventName, (function(_this) { + return function() { + return _this.setState(_this.getState()); + }; + })(this)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + } + }; +}; + + +},{"./React-shim":35}],41:[function(require,module,exports){ +var React, classSet, createToolButton; + +React = require('./React-shim'); + +classSet = require('../core/util').classSet; + +createToolButton = function(tool) { + var displayName, imageName; + displayName = tool.name; + imageName = tool.iconName; + return React.createFactory(React.createClass({ + displayName: displayName, + getDefaultProps: function() { + return { + isSelected: false, + lc: null + }; + }, + componentWillMount: function() { + if (this.props.isSelected) { + return this.props.lc.setTool(tool); + } + }, + render: function() { + var className, div, imageURLPrefix, img, isSelected, onSelect, ref, ref1, src; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, imageURLPrefix = ref1.imageURLPrefix, isSelected = ref1.isSelected, onSelect = ref1.onSelect; + className = classSet({ + 'lc-pick-tool': true, + 'toolbar-button': true, + 'thin-button': true, + 'selected': isSelected + }); + src = imageURLPrefix + "/" + imageName + ".png"; + return div({ + className: className, + style: { + 'backgroundImage': "url(" + src + ")" + }, + onClick: (function() { + return onSelect(tool); + }), + title: displayName + }); + } + })); +}; + +module.exports = createToolButton; + + +},{"../core/util":19,"./React-shim":35}],42:[function(require,module,exports){ +'use strict'; + +var React = require('./React-shim'); +var ReactDOM = require('./ReactDOM-shim'); +var LiterallyCanvasModel = require('../core/LiterallyCanvas'); +var LiterallyCanvasReactComponent = require('./LiterallyCanvas'); + +function init(el, opts) { + var originalClassName = el.className; + var lc = new LiterallyCanvasModel(opts); + ReactDOM.render(React.createElement(LiterallyCanvasReactComponent, { lc: lc }), el); + lc.teardown = function () { + lc._teardown(); + for (var i = 0; i < el.children.length; i++) { + el.removeChild(el.children[i]); + } + el.className = originalClassName; + }; + return lc; +} + +module.exports = init; + +},{"../core/LiterallyCanvas":5,"./LiterallyCanvas":32,"./React-shim":35,"./ReactDOM-shim":36}],43:[function(require,module,exports){ +var Ellipse, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Ellipse = (function(superClass) { + extend(Ellipse, superClass); + + function Ellipse() { + return Ellipse.__super__.constructor.apply(this, arguments); + } + + Ellipse.prototype.name = 'Ellipse'; + + Ellipse.prototype.iconName = 'ellipse'; + + Ellipse.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Ellipse', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Ellipse.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Ellipse.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Ellipse; + +})(ToolWithStroke); + + +},{"../core/shapes":17,"./base":53}],44:[function(require,module,exports){ +var Eraser, Pencil, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Pencil = require('./Pencil'); + +createShape = require('../core/shapes').createShape; + +module.exports = Eraser = (function(superClass) { + extend(Eraser, superClass); + + function Eraser() { + return Eraser.__super__.constructor.apply(this, arguments); + } + + Eraser.prototype.name = 'Eraser'; + + Eraser.prototype.iconName = 'eraser'; + + Eraser.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: '#000' + }); + }; + + Eraser.prototype.makeShape = function() { + return createShape('ErasedLinePath'); + }; + + return Eraser; + +})(Pencil); + + +},{"../core/shapes":17,"./Pencil":48}],45:[function(require,module,exports){ +var Eyedropper, Tool, getPixel, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +getPixel = function(ctx, arg) { + var pixel, x, y; + x = arg.x, y = arg.y; + pixel = ctx.getImageData(x, y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } +}; + +module.exports = Eyedropper = (function(superClass) { + extend(Eyedropper, superClass); + + Eyedropper.prototype.name = 'Eyedropper'; + + Eyedropper.prototype.iconName = 'eyedropper'; + + Eyedropper.prototype.optionsStyle = 'stroke-or-fill'; + + function Eyedropper(lc) { + Eyedropper.__super__.constructor.call(this, lc); + this.strokeOrFill = 'stroke'; + } + + Eyedropper.prototype.readColor = function(x, y, lc) { + var canvas, color, newColor, offset; + offset = lc.getDefaultImageRect(); + canvas = lc.getImage(); + newColor = getPixel(canvas.getContext('2d'), { + x: x - offset.x, + y: y - offset.y + }); + color = newColor || lc.getColor('background'); + if (this.strokeOrFill === 'stroke') { + return lc.setColor('primary', newColor); + } else { + return lc.setColor('secondary', newColor); + } + }; + + Eyedropper.prototype.begin = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + Eyedropper.prototype["continue"] = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + return Eyedropper; + +})(Tool); + + +},{"./base":53}],46:[function(require,module,exports){ +var Line, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Line = (function(superClass) { + extend(Line, superClass); + + function Line() { + return Line.__super__.constructor.apply(this, arguments); + } + + Line.prototype.name = 'Line'; + + Line.prototype.iconName = 'line'; + + Line.prototype.optionsStyle = 'line-options-and-stroke-width'; + + Line.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Line', { + x1: x, + y1: y, + x2: x, + y2: y, + strokeWidth: this.strokeWidth, + dash: (function() { + switch (false) { + case !this.isDashed: + return [this.strokeWidth * 2, this.strokeWidth * 4]; + default: + return null; + } + }).call(this), + endCapShapes: this.hasEndArrow ? [null, 'arrow'] : null, + color: lc.getColor('primary') + }); + }; + + Line.prototype["continue"] = function(x, y, lc) { + this.currentShape.x2 = x; + this.currentShape.y2 = y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Line.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Line; + +})(ToolWithStroke); + + +},{"../core/shapes":17,"./base":53}],47:[function(require,module,exports){ +var Pan, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = Pan = (function(superClass) { + extend(Pan, superClass); + + function Pan() { + return Pan.__super__.constructor.apply(this, arguments); + } + + Pan.prototype.name = 'Pan'; + + Pan.prototype.iconName = 'pan'; + + Pan.prototype.usesSimpleAPI = false; + + Pan.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + unsubscribeFuncs.push(lc.on('lc-pointerdown', (function(_this) { + return function(arg) { + var rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + _this.oldPosition = lc.position; + return _this.pointerStart = { + x: rawX, + y: rawY + }; + }; + })(this))); + return unsubscribeFuncs.push(lc.on('lc-pointerdrag', (function(_this) { + return function(arg) { + var dp, rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + dp = { + x: (rawX - _this.pointerStart.x) * lc.backingScale, + y: (rawY - _this.pointerStart.y) * lc.backingScale + }; + return lc.setPan(_this.oldPosition.x + dp.x, _this.oldPosition.y + dp.y); + }; + })(this))); + }; + + Pan.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return Pan; + +})(Tool); + + +},{"../core/shapes":17,"./base":53}],48:[function(require,module,exports){ +var Pencil, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Pencil = (function(superClass) { + extend(Pencil, superClass); + + function Pencil() { + return Pencil.__super__.constructor.apply(this, arguments); + } + + Pencil.prototype.name = 'Pencil'; + + Pencil.prototype.iconName = 'pencil'; + + Pencil.prototype.eventTimeThreshold = 10; + + Pencil.prototype.begin = function(x, y, lc) { + this.color = lc.getColor('primary'); + this.currentShape = this.makeShape(); + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return this.lastEventTime = Date.now(); + }; + + Pencil.prototype["continue"] = function(x, y, lc) { + var timeDiff; + timeDiff = Date.now() - this.lastEventTime; + if (timeDiff > this.eventTimeThreshold) { + this.lastEventTime += timeDiff; + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return lc.drawShapeInProgress(this.currentShape); + } + }; + + Pencil.prototype.end = function(x, y, lc) { + lc.saveShape(this.currentShape); + return this.currentShape = void 0; + }; + + Pencil.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: this.color + }); + }; + + Pencil.prototype.makeShape = function() { + return createShape('LinePath'); + }; + + return Pencil; + +})(ToolWithStroke); + + +},{"../core/shapes":17,"./base":53}],49:[function(require,module,exports){ +var Polygon, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Polygon = (function(superClass) { + extend(Polygon, superClass); + + function Polygon() { + return Polygon.__super__.constructor.apply(this, arguments); + } + + Polygon.prototype.name = 'Polygon'; + + Polygon.prototype.iconName = 'polygon'; + + Polygon.prototype.usesSimpleAPI = false; + + Polygon.prototype.didBecomeActive = function(lc) { + var onDown, onMove, onUp, polygonCancel, polygonFinishClosed, polygonFinishOpen, polygonUnsubscribeFuncs; + Polygon.__super__.didBecomeActive.call(this, lc); + polygonUnsubscribeFuncs = []; + this.polygonUnsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = polygonUnsubscribeFuncs.length; i < len; i++) { + func = polygonUnsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + this.points = null; + this.maybePoint = null; + onUp = (function(_this) { + return function() { + if (_this._getWillFinish()) { + return _this._close(lc); + } + lc.trigger('lc-polygon-started'); + if (_this.points) { + _this.points.push(_this.maybePoint); + } else { + _this.points = [_this.maybePoint]; + } + _this.maybePoint = { + x: _this.maybePoint.x, + y: _this.maybePoint.y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + onMove = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.maybePoint) { + _this.maybePoint.x = x; + _this.maybePoint.y = y; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + } + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + _this.maybePoint = { + x: x, + y: y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + polygonFinishOpen = (function(_this) { + return function() { + _this.maybePoint = { + x: Infinity, + y: Infinity + }; + return _this._close(lc); + }; + })(this); + polygonFinishClosed = (function(_this) { + return function() { + _this.maybePoint = _this.points[0]; + return _this._close(lc); + }; + })(this); + polygonCancel = (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this); + polygonUnsubscribeFuncs.push(lc.on('drawingChange', (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this))); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointermove', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishopen', polygonFinishOpen)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishclosed', polygonFinishClosed)); + return polygonUnsubscribeFuncs.push(lc.on('lc-polygon-cancel', polygonCancel)); + }; + + Polygon.prototype.willBecomeInactive = function(lc) { + Polygon.__super__.willBecomeInactive.call(this, lc); + if (this.points || this.maybePoint) { + this._cancel(lc); + } + return this.polygonUnsubscribe(); + }; + + Polygon.prototype._getArePointsClose = function(a, b) { + return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) < 10; + }; + + Polygon.prototype._getWillClose = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint); + }; + + Polygon.prototype._getWillFinish = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint) || this._getArePointsClose(this.points[this.points.length - 1], this.maybePoint); + }; + + Polygon.prototype._cancel = function(lc) { + lc.trigger('lc-polygon-stopped'); + this.maybePoint = null; + this.points = null; + lc.setShapesInProgress([]); + return lc.repaintLayer('main'); + }; + + Polygon.prototype._close = function(lc) { + lc.trigger('lc-polygon-stopped'); + lc.setShapesInProgress([]); + if (this.points.length > 2) { + lc.saveShape(this._getShape(lc, false)); + } + this.maybePoint = null; + return this.points = null; + }; + + Polygon.prototype._getShapes = function(lc, isInProgress) { + var shape; + if (isInProgress == null) { + isInProgress = true; + } + shape = this._getShape(lc, isInProgress); + if (shape) { + return [shape]; + } else { + return []; + } + }; + + Polygon.prototype._getShape = function(lc, isInProgress) { + var points; + if (isInProgress == null) { + isInProgress = true; + } + points = []; + if (this.points) { + points = points.concat(this.points); + } + if ((!isInProgress) && points.length < 3) { + return null; + } + if (isInProgress && this.maybePoint) { + points.push(this.maybePoint); + } + if (points.length > 1) { + return createShape('Polygon', { + isClosed: this._getWillClose(), + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary'), + strokeWidth: this.strokeWidth, + points: points.map(function(xy) { + return createShape('Point', xy); + }) + }); + } else { + return null; + } + }; + + Polygon.prototype.optionsStyle = 'polygon-and-stroke-width'; + + return Polygon; + +})(ToolWithStroke); + + +},{"../core/shapes":17,"./base":53}],50:[function(require,module,exports){ +var Rectangle, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Rectangle = (function(superClass) { + extend(Rectangle, superClass); + + function Rectangle() { + return Rectangle.__super__.constructor.apply(this, arguments); + } + + Rectangle.prototype.name = 'Rectangle'; + + Rectangle.prototype.iconName = 'rectangle'; + + Rectangle.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Rectangle', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Rectangle.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Rectangle.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Rectangle; + +})(ToolWithStroke); + + +},{"../core/shapes":17,"./base":53}],51:[function(require,module,exports){ +var SelectShape, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = SelectShape = (function(superClass) { + extend(SelectShape, superClass); + + SelectShape.prototype.name = 'SelectShape'; + + SelectShape.prototype.usesSimpleAPI = false; + + function SelectShape(lc) { + this.selectCanvas = document.createElement('canvas'); + this.selectCanvas.style['background-color'] = 'transparent'; + this.selectCtx = this.selectCanvas.getContext('2d'); + } + + SelectShape.prototype.didBecomeActive = function(lc) { + var onDown, onDrag, onUp, selectShapeUnsubscribeFuncs; + selectShapeUnsubscribeFuncs = []; + this._selectShapeUnsubscribe = (function(_this) { + return function() { + var func, j, len, results; + results = []; + for (j = 0, len = selectShapeUnsubscribeFuncs.length; j < len; j++) { + func = selectShapeUnsubscribeFuncs[j]; + results.push(func()); + } + return results; + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var br, shapeIndex, x, y; + x = arg.x, y = arg.y; + _this.didDrag = false; + shapeIndex = _this._getPixel(x, y, lc, _this.selectCtx); + _this.selectedShape = lc.shapes[shapeIndex]; + if (_this.selectedShape != null) { + lc.trigger('shapeSelected', { + selectedShape: _this.selectedShape + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + lc.repaintLayer('main'); + br = _this.selectedShape.getBoundingRect(); + return _this.dragOffset = { + x: x - br.x, + y: y - br.y + }; + } + }; + })(this); + onDrag = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.selectedShape != null) { + _this.didDrag = true; + _this.selectedShape.setUpperLeft({ + x: x - _this.dragOffset.x, + y: y - _this.dragOffset.y + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + return lc.repaintLayer('main'); + } + }; + })(this); + onUp = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.didDrag) { + _this.didDrag = false; + lc.trigger('shapeMoved', { + shape: _this.selectedShape + }); + lc.trigger('drawingChange', {}); + lc.repaintLayer('main'); + return _this._drawSelectCanvas(lc); + } + }; + })(this); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onDrag)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + return this._drawSelectCanvas(lc); + }; + + SelectShape.prototype.willBecomeInactive = function(lc) { + this._selectShapeUnsubscribe(); + return lc.setShapesInProgress([]); + }; + + SelectShape.prototype._drawSelectCanvas = function(lc) { + var shapes; + this.selectCanvas.width = lc.canvas.width; + this.selectCanvas.height = lc.canvas.height; + this.selectCtx.clearRect(0, 0, this.selectCanvas.width, this.selectCanvas.height); + shapes = lc.shapes.map((function(_this) { + return function(shape, index) { + return createShape('SelectionBox', { + shape: shape, + handleSize: 0, + backgroundColor: "#" + (_this._intToHex(index)) + }); + }; + })(this)); + return lc.draw(shapes, this.selectCtx); + }; + + SelectShape.prototype._intToHex = function(i) { + return ("000000" + (i.toString(16))).slice(-6); + }; + + SelectShape.prototype._getPixel = function(x, y, lc, ctx) { + var p, pixel; + p = lc.drawingCoordsToClientCoords(x, y); + pixel = ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return parseInt(this._rgbToHex(pixel[0], pixel[1], pixel[2]), 16); + } else { + return null; + } + }; + + SelectShape.prototype._componentToHex = function(c) { + var hex; + hex = c.toString(16); + return ("0" + hex).slice(-2); + }; + + SelectShape.prototype._rgbToHex = function(r, g, b) { + return "" + (this._componentToHex(r)) + (this._componentToHex(g)) + (this._componentToHex(b)); + }; + + return SelectShape; + +})(Tool); + + +},{"../core/shapes":17,"./base":53}],52:[function(require,module,exports){ +var Text, Tool, createShape, getIsPointInBox, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +getIsPointInBox = function(point, box) { + if (point.x < box.x) { + return false; + } + if (point.y < box.y) { + return false; + } + if (point.x > box.x + box.width) { + return false; + } + if (point.y > box.y + box.height) { + return false; + } + return true; +}; + +module.exports = Text = (function(superClass) { + extend(Text, superClass); + + Text.prototype.name = 'Text'; + + Text.prototype.iconName = 'text'; + + function Text() { + this.text = ''; + this.font = 'bold 18px sans-serif'; + this.currentShape = null; + this.currentShapeState = null; + this.initialShapeBoundingRect = null; + this.dragAction = null; + this.didDrag = false; + } + + Text.prototype.didBecomeActive = function(lc) { + var switchAway, unsubscribeFuncs, updateInputEl; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + switchAway = (function(_this) { + return function() { + _this._ensureNotEditing(lc); + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this); + updateInputEl = (function(_this) { + return function() { + return _this._updateInputEl(lc); + }; + })(this); + unsubscribeFuncs.push(lc.on('drawingChange', switchAway)); + unsubscribeFuncs.push(lc.on('zoom', updateInputEl)); + unsubscribeFuncs.push(lc.on('imageSizeChange', updateInputEl)); + unsubscribeFuncs.push(lc.on('snapshotLoad', (function(_this) { + return function() { + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this))); + unsubscribeFuncs.push(lc.on('primaryColorChange', (function(_this) { + return function(newColor) { + if (!_this.currentShape) { + return; + } + _this.currentShape.color = newColor; + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + return unsubscribeFuncs.push(lc.on('setFont', (function(_this) { + return function(font) { + if (!_this.currentShape) { + return; + } + _this.font = font; + _this.currentShape.setFont(font); + _this._setShapesInProgress(lc); + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + }; + + Text.prototype.willBecomeInactive = function(lc) { + if (this.currentShape) { + this._ensureNotEditing(lc); + this.commit(lc); + } + return this.unsubscribe(); + }; + + Text.prototype.setText = function(text) { + return this.text = text; + }; + + Text.prototype._ensureNotEditing = function(lc) { + if (this.currentShapeState === 'editing') { + return this._exitEditingState(lc); + } + }; + + Text.prototype._clearCurrentShape = function(lc) { + this.currentShape = null; + this.initialShapeBoundingRect = null; + this.currentShapeState = null; + return lc.setShapesInProgress([]); + }; + + Text.prototype.commit = function(lc) { + if (this.currentShape.text) { + lc.saveShape(this.currentShape); + } + this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._getSelectionShape = function(ctx, backgroundColor) { + if (backgroundColor == null) { + backgroundColor = null; + } + return createShape('SelectionBox', { + shape: this.currentShape, + ctx: ctx, + backgroundColor: backgroundColor + }); + }; + + Text.prototype._setShapesInProgress = function(lc) { + switch (this.currentShapeState) { + case 'selected': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx), this.currentShape]); + case 'editing': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx, '#fff')]); + default: + return lc.setShapesInProgress([this.currentShape]); + } + }; + + Text.prototype.begin = function(x, y, lc) { + var br, point, selectionBox, selectionShape; + this.dragAction = 'none'; + this.didDrag = false; + if (this.currentShapeState === 'selected' || this.currentShapeState === 'editing') { + br = this.currentShape.getBoundingRect(lc.ctx); + selectionShape = this._getSelectionShape(lc.ctx); + selectionBox = selectionShape.getBoundingRect(); + point = { + x: x, + y: y + }; + if (getIsPointInBox(point, br)) { + this.dragAction = 'move'; + } + if (getIsPointInBox(point, selectionShape.getBottomRightHandleRect())) { + this.dragAction = 'resizeBottomRight'; + } + if (getIsPointInBox(point, selectionShape.getTopLeftHandleRect())) { + this.dragAction = 'resizeTopLeft'; + } + if (getIsPointInBox(point, selectionShape.getBottomLeftHandleRect())) { + this.dragAction = 'resizeBottomLeft'; + } + if (getIsPointInBox(point, selectionShape.getTopRightHandleRect())) { + this.dragAction = 'resizeTopRight'; + } + if (this.dragAction === 'none' && this.currentShapeState === 'editing') { + this.dragAction = 'stop-editing'; + this._exitEditingState(lc); + } + } else { + this.color = lc.getColor('primary'); + this.currentShape = createShape('Text', { + x: x, + y: y, + text: this.text, + color: this.color, + font: this.font, + v: 1 + }); + this.dragAction = 'place'; + this.currentShapeState = 'selected'; + } + if (this.dragAction === 'none') { + this.commit(lc); + return; + } + this.initialShapeBoundingRect = this.currentShape.getBoundingRect(lc.ctx); + this.dragOffset = { + x: x - this.initialShapeBoundingRect.x, + y: y - this.initialShapeBoundingRect.y + }; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype["continue"] = function(x, y, lc) { + var br, brBottom, brRight; + if (this.dragAction === 'none') { + return; + } + br = this.initialShapeBoundingRect; + brRight = br.x + br.width; + brBottom = br.y + br.height; + switch (this.dragAction) { + case 'place': + this.currentShape.x = x; + this.currentShape.y = y; + this.didDrag = true; + break; + case 'move': + this.currentShape.x = x - this.dragOffset.x; + this.currentShape.y = y - this.dragOffset.y; + this.didDrag = true; + break; + case 'resizeBottomRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + break; + case 'resizeTopLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(x - this.dragOffset.x, y - this.dragOffset.y); + break; + case 'resizeBottomLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + this.currentShape.setPosition(x - this.dragOffset.x, this.currentShape.y); + break; + case 'resizeTopRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(this.currentShape.x, y - this.dragOffset.y); + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype.end = function(x, y, lc) { + if (!this.currentShape) { + return; + } + this.currentShape.setSize(this.currentShape.forcedWidth, 0); + if (this.currentShapeState === 'selected') { + if (this.dragAction === 'place' || (this.dragAction === 'move' && !this.didDrag)) { + this._enterEditingState(lc); + } + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype._enterEditingState = function(lc) { + var onChange; + this.currentShapeState = 'editing'; + if (this.inputEl) { + throw "State error"; + } + this.inputEl = document.createElement('textarea'); + this.inputEl.className = 'text-tool-input'; + this.inputEl.style.position = 'absolute'; + this.inputEl.style.transformOrigin = '0px 0px'; + this.inputEl.style.backgroundColor = 'transparent'; + this.inputEl.style.border = 'none'; + this.inputEl.style.outline = 'none'; + this.inputEl.style.margin = '0'; + this.inputEl.style.padding = '4px'; + this.inputEl.style.zIndex = '1000'; + this.inputEl.style.overflow = 'hidden'; + this.inputEl.style.resize = 'none'; + this.inputEl.value = this.currentShape.text; + this.inputEl.addEventListener('mousedown', function(e) { + return e.stopPropagation(); + }); + this.inputEl.addEventListener('touchstart', function(e) { + return e.stopPropagation(); + }); + onChange = (function(_this) { + return function(e) { + _this.currentShape.setText(e.target.value); + _this.currentShape.enforceMaxBoundingRect(lc); + _this._setShapesInProgress(lc); + lc.repaintLayer('main'); + _this._updateInputEl(lc); + return e.stopPropagation(); + }; + })(this); + this.inputEl.addEventListener('keydown', (function(_this) { + return function() { + return _this._updateInputEl(lc, true); + }; + })(this)); + this.inputEl.addEventListener('keyup', onChange); + this.inputEl.addEventListener('change', onChange); + this._updateInputEl(lc); + lc.containerEl.appendChild(this.inputEl); + this.inputEl.focus(); + return this._setShapesInProgress(lc); + }; + + Text.prototype._exitEditingState = function(lc) { + this.currentShapeState = 'selected'; + lc.containerEl.removeChild(this.inputEl); + this.inputEl = null; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._updateInputEl = function(lc, withMargin) { + var br, transformString; + if (withMargin == null) { + withMargin = false; + } + if (!this.inputEl) { + return; + } + br = this.currentShape.getBoundingRect(lc.ctx, true); + this.inputEl.style.font = this.currentShape.font; + this.inputEl.style.color = this.currentShape.color; + this.inputEl.style.left = (lc.position.x / lc.backingScale + br.x * lc.scale - 4) + "px"; + this.inputEl.style.top = (lc.position.y / lc.backingScale + br.y * lc.scale - 4) + "px"; + if (withMargin && !this.currentShape.forcedWidth) { + this.inputEl.style.width = (br.width + 10 + this.currentShape.renderer.emDashWidth) + "px"; + } else { + this.inputEl.style.width = (br.width + 12) + "px"; + } + if (withMargin) { + this.inputEl.style.height = (br.height + 10 + this.currentShape.renderer.metrics.leading) + "px"; + } else { + this.inputEl.style.height = (br.height + 10) + "px"; + } + transformString = "scale(" + lc.scale + ")"; + this.inputEl.style.transform = transformString; + this.inputEl.style.webkitTransform = transformString; + this.inputEl.style.MozTransform = transformString; + this.inputEl.style.msTransform = transformString; + return this.inputEl.style.OTransform = transformString; + }; + + Text.prototype.optionsStyle = 'font'; + + return Text; + +})(Tool); + + +},{"../core/shapes":17,"./base":53}],53:[function(require,module,exports){ +var Tool, ToolWithStroke, tools, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +tools = {}; + +tools.Tool = Tool = (function() { + function Tool() {} + + Tool.prototype.name = null; + + Tool.prototype.iconName = null; + + Tool.prototype.usesSimpleAPI = true; + + Tool.prototype.begin = function(x, y, lc) {}; + + Tool.prototype["continue"] = function(x, y, lc) {}; + + Tool.prototype.end = function(x, y, lc) {}; + + Tool.prototype.optionsStyle = null; + + Tool.prototype.didBecomeActive = function(lc) {}; + + Tool.prototype.willBecomeInactive = function(lc) {}; + + return Tool; + +})(); + +tools.ToolWithStroke = ToolWithStroke = (function(superClass) { + extend(ToolWithStroke, superClass); + + function ToolWithStroke(lc) { + this.strokeWidth = lc.opts.defaultStrokeWidth; + } + + ToolWithStroke.prototype.optionsStyle = 'stroke-width'; + + ToolWithStroke.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + return unsubscribeFuncs.push(lc.on('setStrokeWidth', (function(_this) { + return function(strokeWidth) { + _this.strokeWidth = strokeWidth; + return lc.trigger('toolDidUpdateOptions'); + }; + })(this))); + }; + + ToolWithStroke.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return ToolWithStroke; + +})(Tool); + +module.exports = tools; + + +},{}]},{},[22])(22) +}); \ No newline at end of file diff --git a/library/js/literallycanvas/js/literallycanvas.min.js b/library/js/literallycanvas/js/literallycanvas.min.js new file mode 100644 index 00000000000..78c1a083905 --- /dev/null +++ b/library/js/literallycanvas/js/literallycanvas.min.js @@ -0,0 +1,4 @@ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.LC=t()}}(function(){return function t(e,n,i){function r(s,a){if(!n[s]){if(!e[s]){var h="function"==typeof require&&require;if(!a&&h)return h(s,!0);if(o)return o(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return r(n?n:t)},c,c.exports,t,e,n,i)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;se;e++)if(e in this&&this[e]===t)return e;return-1};a=t("./actions"),h=t("./bindEvents"),c=t("./math"),u=t("./shapes"),l=u.createShape,m=u.shapeToJSON,r=u.JSONToShape,p=t("./canvasRenderer").renderShapeToContext,d=t("./svgRenderer").renderShapeToSVG,f=t("./renderSnapshotToImage"),g=t("./renderSnapshotToSVG"),s=t("../tools/Pencil"),y=t("./util"),i="infinite",e.exports=o=function(){function t(t,e){this.setImageSize=S(this.setImageSize,this);var n,r;r=null,n=null,t instanceof HTMLElement?(n=t,r=e):r=t,this.opts=r||{},this.config={zoomMin:r.zoomMin||.2,zoomMax:r.zoomMax||4,zoomStep:r.zoomStep||.2},this.colors={primary:r.primaryColor||"#000",secondary:r.secondaryColor||"#fff",background:r.backgroundColor||"transparent"},this.watermarkImage=r.watermarkImage,this.watermarkScale=r.watermarkScale||1,this.backgroundCanvas=document.createElement("canvas"),this.backgroundCtx=this.backgroundCanvas.getContext("2d"),this.canvas=document.createElement("canvas"),this.canvas.style["background-color"]="transparent",this.buffer=document.createElement("canvas"),this.buffer.style["background-color"]="transparent",this.ctx=this.canvas.getContext("2d"),this.bufferCtx=this.buffer.getContext("2d"),this.backingScale=y.getBackingScale(this.ctx),this.backgroundShapes=r.backgroundShapes||[],this._shapesInProgress=[],this.shapes=[],this.undoStack=[],this.redoStack=[],this.isDragging=!1,this.position={x:0,y:0},this.scale=1,this.setTool(new this.opts.tools[0](this)),this.width=r.imageSize.width||i,this.height=r.imageSize.height||i,this.setZoom(this.scale),r.snapshot&&this.loadSnapshot(r.snapshot),this.isBound=!1,n&&this.bindToElement(n)}return t.prototype.bindToElement=function(t){var e,n;return this.containerEl?void console.warn("Trying to bind Literally Canvas to a DOM element more than once is unsupported."):(this.containerEl=t,this._unsubscribeEvents=h(this,this.containerEl,this.opts.keyboardShortcuts),this.containerEl.style["background-color"]=this.colors.background,this.containerEl.appendChild(this.backgroundCanvas),this.containerEl.appendChild(this.canvas),this.isBound=!0,n=function(t){return function(){return t.keepPanInImageBounds(),t.repaintAllLayers()}}(this),y.matchElementSize(this.containerEl,[this.backgroundCanvas,this.canvas],this.backingScale,n),this.watermarkImage&&(this.watermarkImage.onload=function(t){return function(){return t.repaintLayer("background")}}(this)),null!=(e=this.tool)&&e.didBecomeActive(this),n())},t.prototype._teardown=function(){return this.tool.willBecomeInactive(this),"function"==typeof this._unsubscribeEvents&&this._unsubscribeEvents(),this.tool=null,this.containerEl=null,this.isBound=!1},t.prototype.trigger=function(t,e){return this.canvas.dispatchEvent(new CustomEvent(t,{detail:e})),null},t.prototype.on=function(t,e){var n;return n=function(t){return e(t.detail)},this.canvas.addEventListener(t,n),function(e){return function(){return e.canvas.removeEventListener(t,n)}}(this)},t.prototype.getRenderScale=function(){return this.scale*this.backingScale},t.prototype.clientCoordsToDrawingCoords=function(t,e){return{x:(t*this.backingScale-this.position.x)/this.getRenderScale(),y:(e*this.backingScale-this.position.y)/this.getRenderScale()}},t.prototype.drawingCoordsToClientCoords=function(t,e){return{x:t*this.getRenderScale()+this.position.x,y:e*this.getRenderScale()+this.position.y}},t.prototype.setImageSize=function(t,e){return this.width=t||i,this.height=e||i,this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("imageSizeChange",{width:this.width,height:this.height})},t.prototype.setTool=function(t){var e;return this.isBound&&null!=(e=this.tool)&&e.willBecomeInactive(this),this.tool=t,this.trigger("toolChange",{tool:t}),this.isBound?this.tool.didBecomeActive(this):void 0},t.prototype.setShapesInProgress=function(t){return this._shapesInProgress=t},t.prototype.pointerDown=function(t,e){var n;return n=this.clientCoordsToDrawingCoords(t,e),this.tool.usesSimpleAPI?(this.tool.begin(n.x,n.y,this),this.isDragging=!0,this.trigger("drawStart",{tool:this.tool})):(this.isDragging=!0,this.trigger("lc-pointerdown",{tool:this.tool,x:n.x,y:n.y,rawX:t,rawY:e}))},t.prototype.pointerMove=function(t,e){return y.requestAnimationFrame(function(n){return function(){var i,r;return i=n.clientCoordsToDrawingCoords(t,e),(null!=(r=n.tool)?r.usesSimpleAPI:0)?n.isDragging?(n.tool["continue"](i.x,i.y,n),n.trigger("drawContinue",{tool:n.tool})):void 0:n.isDragging?n.trigger("lc-pointerdrag",{tool:n.tool,x:i.x,y:i.y,rawX:t,rawY:e}):n.trigger("lc-pointermove",{tool:n.tool,x:i.x,y:i.y,rawX:t,rawY:e})}}(this))},t.prototype.pointerUp=function(t,e){var n;return n=this.clientCoordsToDrawingCoords(t,e),this.tool.usesSimpleAPI?this.isDragging?(this.tool.end(n.x,n.y,this),this.isDragging=!1,this.trigger("drawEnd",{tool:this.tool})):void 0:(this.isDragging=!1,this.trigger("lc-pointerup",{tool:this.tool,x:n.x,y:n.y,rawX:t,rawY:e}))},t.prototype.setColor=function(t,e){if(this.colors[t]=e,this.isBound){switch(t){case"background":this.containerEl.style.backgroundColor=this.colors.background,this.repaintLayer("background");break;case"primary":this.repaintLayer("main");break;case"secondary":this.repaintLayer("main")}return this.trigger(t+"ColorChange",this.colors[t]),"background"===t?this.trigger("drawingChange"):void 0}},t.prototype.getColor=function(t){return this.colors[t]},t.prototype.saveShape=function(t,e,n){return null==e&&(e=!0),null==n&&(n=null),n||(n=this.shapes.length?this.shapes[this.shapes.length-1].id:null),this.execute(new a.AddShapeAction(this,t,n)),e&&this.trigger("shapeSave",{shape:t,previousShapeId:n}),this.trigger("drawingChange")},t.prototype.pan=function(t,e){return this.setPan(this.position.x-t,this.position.y-e)},t.prototype.keepPanInImageBounds=function(){var t,e,n,r;return e=this.getRenderScale(),t=this.position,n=t.x,r=t.y,this.width!==i&&(n=this.canvas.width>this.width*e?(this.canvas.width-this.width*e)/2:Math.max(Math.min(0,n),this.canvas.width-this.width*e)),this.height!==i&&(r=this.canvas.height>this.height*e?(this.canvas.height-this.height*e)/2:Math.max(Math.min(0,r),this.canvas.height-this.height*e)),this.position={x:n,y:r}},t.prototype.setPan=function(t,e){return this.position={x:t,y:e},this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("pan",{x:this.position.x,y:this.position.y})},t.prototype.zoom=function(t){var e;return e=this.scale+t,e=Math.max(e,this.config.zoomMin),e=Math.min(e,this.config.zoomMax),e=Math.round(100*e)/100,this.setZoom(e)},t.prototype.setZoom=function(t){var e;return e=this.scale,this.scale=t,this.position.x=c.scalePositionScalar(this.position.x,this.canvas.width,e,this.scale),this.position.y=c.scalePositionScalar(this.position.y,this.canvas.height,e,this.scale),this.keepPanInImageBounds(),this.repaintAllLayers(),this.trigger("zoom",{oldScale:e,newScale:this.scale})},t.prototype.setWatermarkImage=function(t){return this.watermarkImage=t,y.addImageOnload(t,function(t){return function(){return t.repaintLayer("background")}}(this)),t.width?this.repaintLayer("background"):void 0},t.prototype.repaintAllLayers=function(){var t,e,n,i;for(i=["background","main"],t=0,n=i.length;n>t;t++)e=i[t],this.repaintLayer(e);return null},t.prototype.repaintLayer=function(t,e){var n;if(null==e&&(e="main"===t),this.isBound){switch(t){case"background":this.backgroundCtx.clearRect(0,0,this.backgroundCanvas.width,this.backgroundCanvas.height),n=function(t){return function(){return t.repaintLayer("background")}}(this),this.watermarkImage&&this._renderWatermark(this.backgroundCtx,!0,n),this.draw(this.backgroundShapes,this.backgroundCtx,n);break;case"main":n=function(t){return function(){return t.repaintLayer("main",!0)}}(this),e&&(this.buffer.width=this.canvas.width,this.buffer.height=this.canvas.height,this.bufferCtx.clearRect(0,0,this.buffer.width,this.buffer.height),this.draw(this.shapes,this.bufferCtx,n)),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width>0&&this.canvas.height>0&&(this.ctx.fillStyle="#ccc",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height),this.clipped(function(t){return function(){return t.ctx.clearRect(0,0,t.canvas.width,t.canvas.height),t.ctx.drawImage(t.buffer,0,0)}}(this),this.ctx),this.clipped(function(t){return function(){return t.transformed(function(){var e,n,i,r,o;for(i=t._shapesInProgress,r=[],e=0,n=i.length;n>e;e++)o=i[e],r.push(p(t.ctx,o,{bufferCtx:t.bufferCtx,shouldOnlyDrawLatest:!0}));return r},t.ctx,t.bufferCtx)}}(this),this.ctx,this.bufferCtx))}return this.trigger("repaint",{layerKey:t})}},t.prototype._renderWatermark=function(t,e,n){return null==e&&(e=!0),this.watermarkImage.width?(t.save(),t.translate(t.canvas.width/2,t.canvas.height/2),t.scale(this.watermarkScale,this.watermarkScale),e&&t.scale(this.backingScale,this.backingScale),t.drawImage(this.watermarkImage,-this.watermarkImage.width/2,-this.watermarkImage.height/2),t.restore()):void(this.watermarkImage.onload=n)},t.prototype.drawShapeInProgress=function(t){return this.repaintLayer("main",!1),this.clipped(function(e){return function(){return e.transformed(function(){return p(e.ctx,t,{bufferCtx:e.bufferCtx,shouldOnlyDrawLatest:!0})},e.ctx,e.bufferCtx)}}(this),this.ctx,this.bufferCtx)},t.prototype.draw=function(t,e,n){var i;if(t.length)return i=function(i){return function(){var i,r,o,s;for(o=[],i=0,r=t.length;r>i;i++)s=t[i],o.push(p(e,s,{retryCallback:n}));return o}}(this),this.clipped(function(t){return function(){return t.transformed(i,e)}}(this),e)},t.prototype.clipped=function(){var t,e,n,r,o,s,a,h,l,c,u,p;for(n=arguments[0],t=2<=arguments.length?v.call(arguments,1):[],u=this.width===i?0:this.position.x,p=this.height===i?0:this.position.y,c=function(){switch(this.width){case i:return this.canvas.width;default:return this.width*this.getRenderScale()}}.call(this),r=function(){switch(this.height){case i:return this.canvas.height;default:return this.height*this.getRenderScale()}}.call(this),o=0,a=t.length;a>o;o++)e=t[o],e.save(),e.beginPath(),e.rect(u,p,c,r),e.clip();for(n(),l=[],s=0,h=t.length;h>s;s++)e=t[s],l.push(e.restore());return l},t.prototype.transformed=function(){var t,e,n,i,r,o,s,a,h;for(n=arguments[0],t=2<=arguments.length?v.call(arguments,1):[],i=0,o=t.length;o>i;i++)e=t[i],e.save(),e.translate(Math.floor(this.position.x),Math.floor(this.position.y)),h=this.getRenderScale(),e.scale(h,h);for(n(),a=[],r=0,s=t.length;s>r;r++)e=t[r],a.push(e.restore());return a},t.prototype.clear=function(t){var e,n;return null==t&&(t=!0),n=this.shapes,e=[],this.setShapesInProgress([]),this.execute(new a.ClearAction(this,n,e)),this.repaintLayer("main"),t&&this.trigger("clear",null),this.trigger("drawingChange",{})},t.prototype.execute=function(t){return this.undoStack.push(t),t["do"](),this.redoStack=[]},t.prototype.undo=function(){var t;if(this.undoStack.length)return t=this.undoStack.pop(),t.undo(),this.redoStack.push(t),this.trigger("undo",{action:t}),this.trigger("drawingChange",{})},t.prototype.redo=function(){var t;if(this.redoStack.length)return t=this.redoStack.pop(),this.undoStack.push(t),t["do"](),this.trigger("redo",{action:t}),this.trigger("drawingChange",{})},t.prototype.canUndo=function(){return!!this.undoStack.length},t.prototype.canRedo=function(){return!!this.redoStack.length},t.prototype.getPixel=function(t,e){var n,i;return n=this.drawingCoordsToClientCoords(t,e),i=this.ctx.getImageData(n.x,n.y,1,1).data,i[3]?"rgb("+i[0]+", "+i[1]+", "+i[2]+")":null},t.prototype.getContentBounds=function(){return y.getBoundingRect(this.shapes.concat(this.backgroundShapes).map(function(t){return t.getBoundingRect()}),this.width===i?0:this.width,this.height===i?0:this.height)},t.prototype.getDefaultImageRect=function(t,e){var n;return null==t&&(t={width:0,height:0}),null==e&&(e={top:0,right:0,bottom:0,left:0}),y.getDefaultImageRect(function(){var t,e,i,r;for(i=this.shapes.concat(this.backgroundShapes),r=[],t=0,e=i.length;e>t;t++)n=i[t],r.push(n.getBoundingRect(this.ctx));return r}.call(this),t,e)},t.prototype.getImage=function(t){return null==t&&(t={}),null==t.includeWatermark&&(t.includeWatermark=!0),null==t.scaleDownRetina&&(t.scaleDownRetina=!0),null==t.scale&&(t.scale=1),t.scaleDownRetina||(t.scale*=this.backingScale),t.includeWatermark&&(t.watermarkImage=this.watermarkImage,t.watermarkScale=this.watermarkScale,t.scaleDownRetina||(t.watermarkScale*=this.backingScale)),f(this.getSnapshot(),t)},t.prototype.canvasForExport=function(){return this.repaintAllLayers(),y.combineCanvases(this.backgroundCanvas,this.canvas)},t.prototype.canvasWithBackground=function(t){return y.combineCanvases(t,this.canvasForExport())},t.prototype.getSnapshot=function(t){var e,n,i,r,o,s;for(null==t&&(t=null),null==t&&(t=["shapes","imageSize","colors","position","scale","backgroundShapes"]),s={},r=["colors","position","scale"],e=0,i=r.length;i>e;e++)n=r[e],x.call(t,n)>=0&&(s[n]=this[n]);return x.call(t,"shapes")>=0&&(s.shapes=function(){var t,e,n,i;for(n=this.shapes,i=[],t=0,e=n.length;e>t;t++)o=n[t],i.push(m(o));return i}.call(this)),x.call(t,"backgroundShapes")>=0&&(s.backgroundShapes=function(){var t,e,n,i;for(n=this.backgroundShapes,i=[],t=0,e=n.length;e>t;t++)o=n[t],i.push(m(o));return i}.call(this)),x.call(t,"imageSize")>=0&&(s.imageSize={width:this.width,height:this.height}),s},t.prototype.getSnapshotJSON=function(){return console.warn("lc.getSnapshotJSON() is deprecated. use JSON.stringify(lc.getSnapshot()) instead."),JSON.stringify(this.getSnapshot())},t.prototype.getSVGString=function(t){return null==t&&(t={}),g(this.getSnapshot(),t)},t.prototype.loadSnapshot=function(t){var e,n,i,o,s,h,l,c,u,p;if(t){if(t.colors)for(h=["primary","secondary","background"],e=0,o=h.length;o>e;e++)i=h[e],this.setColor(i,t.colors[i]);if(t.shapes)for(this.shapes=[],l=t.shapes,n=0,s=l.length;s>n;n++)p=l[n],u=r(p),u&&this.execute(new a.AddShapeAction(this,u));return t.backgroundShapes&&(this.backgroundShapes=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}()),t.imageSize&&(this.width=t.imageSize.width,this.height=t.imageSize.height),t.position&&(this.position=t.position),t.scale&&(this.scale=t.scale),this.repaintAllLayers(),this.trigger("snapshotLoad"),this.trigger("drawingChange",{})}},t.prototype.loadSnapshotJSON=function(t){return console.warn("lc.loadSnapshotJSON() is deprecated. use lc.loadSnapshot(JSON.parse(snapshot)) instead."),this.loadSnapshot(JSON.parse(t))},t}()},{"../tools/Pencil":48,"./actions":7,"./bindEvents":8,"./canvasRenderer":9,"./math":14,"./renderSnapshotToImage":15,"./renderSnapshotToSVG":16,"./shapes":17,"./svgRenderer":18,"./util":19}],6:[function(t,e,n){var i,r,o,s;t("./fontmetrics.js"),s=function(t){var e,n,i,r,o,s,a,h;for(n=t.split(" "),i=0,o=0,s=n.length;s>o;o++)r=n[o],a=parseInt(r.replace("px",""),10),isNaN(a)||(i=a);if(!i)throw"Font size not found";return h=t.substring(n[0].length+1).replace("bold ","").replace("italic ","").replace("underline ",""),e=h,{fontSize:i,fontFamily:e}},o=function(t,e,n){var i,r,o,s,a,h,l,c,u,p;if(!e.length)return["",""];for(r=0,h=0,l=0,p=!1;;)if(r+=1,o=r>=e.length,a=!o&&e[r].match(/\s/),s=a||o,u=e.substring(0,r),i=n?t.measureTextWidth(u).width<=n:!0,i&&(l=r),s&&p&&(p=!1,i&&(h=r)),p=!a,o||!i){if(i)return[e,""];if(h>0){for(c=h+1;ci;i++)if(u=p[i],h=o(t,u,n),a=h[0],c=h[1],a)for(;a;)s.push(a),l=o(t,c,n),a=l[0],c=l[1];else s.push(u);return s},i=function(){function t(t,e,n,i,o){var a,h,l;this.text=e,this.font=n,this.forcedWidth=i,this.forcedHeight=o,l=s(this.font),a=l.fontFamily,h=l.fontSize,t.font=this.font,t.textBaseline="baseline",this.emDashWidth=t.measureTextWidth("—",h,a).width,this.caratWidth=t.measureTextWidth("|",h,a).width,this.lines=r(t,this.text,this.forcedWidth),this.metricses=this.lines.map(function(e){return function(n){return t.measureText2(n||"X",h,e.font)}}(this)),this.metrics={ascent:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.ascent})),descent:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.descent})),fontsize:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.fontsize})),leading:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.leading})),width:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.width})),height:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.height})),bounds:{minx:Math.min.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.minx})),miny:Math.min.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.miny})),maxx:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.maxx})),maxy:Math.max.apply(Math,this.metricses.map(function(t){var e;return e=t.bounds,e.maxy}))}},this.boundingBoxWidth=Math.ceil(this.metrics.width)}return t.prototype.draw=function(t,e,n){var i,r,o,s,a,h;for(t.textBaseline="top",t.font=this.font,i=0,a=this.lines,h=[],r=0,o=a.length;o>r;r++)s=a[r],t.fillText(s,e,n+i*this.metrics.leading),h.push(i+=1);return h},t.prototype.getWidth=function(t){return null==t&&(t=!1),this.forcedWidth?this.forcedWidth:t?this.metrics.bounds.maxx+this.caratWidth:this.metrics.bounds.maxx},t.prototype.getHeight=function(){return this.forcedHeight||this.metrics.leading*this.lines.length},t}(),e.exports=i},{"./fontmetrics.js":11}],7:[function(t,e,n){var i,r;r=function(){function t(t,e,n){this.lc=t,this.oldShapes=e,this.newShapes=n}return t.prototype["do"]=function(){return this.lc.shapes=this.newShapes,this.lc.repaintLayer("main")},t.prototype.undo=function(){return this.lc.shapes=this.oldShapes,this.lc.repaintLayer("main")},t}(),i=function(){function t(t,e,n){this.lc=t,this.shape=e,this.previousShapeId=null!=n?n:null}return t.prototype["do"]=function(){var t,e,n,i,r,o;if(this.lc.shapes.length&&this.lc.shapes[this.lc.shapes.length-1].id!==this.previousShapeId&&null!==this.previousShapeId){for(i=[],t=!1,r=this.lc.shapes,e=0,n=r.length;n>e;e++)o=r[e],i.push(o),o.id===this.previousShapeId&&(i.push(this.shape),t=!0);t||i.push(this.shape),this.lc.shapes=i}else this.lc.shapes.push(this.shape);return this.lc.repaintLayer("main")},t.prototype.undo=function(){var t,e,n,i,r;if(this.lc.shapes[this.lc.shapes.length-1].id===this.shape.id)this.lc.shapes.pop();else{for(n=[],i=this.lc.shapes,t=0,e=i.length;e>t;t++)r=i[t],r.id!==this.shape.id&&n.push(r);lc.shapes=n}return this.lc.repaintLayer("main")},t}(),e.exports={ClearAction:r,AddShapeAction:i}},{}],8:[function(t,e,n){var i,r,o,s;o=function(t,e){var n,i,r;return i=e.changedTouches[0].clientX,r=e.changedTouches[0].clientY,n=t.getBoundingClientRect(),[i-n.left,r-n.top]},s=function(t,e){var n;return n=t.getBoundingClientRect(),{left:e.clientX-n.left,top:e.clientY-n.top}},r=function(t){return null!=t.buttons?1===t.buttons:t.which>0},e.exports=i=function(t,e,n){var i,r,a,h,l,c;return null==n&&(n=!1),c=[],r=function(n){return function(n){var i;return n.preventDefault(),i=s(e,n),t.pointerMove(i.left,i.top)}}(this),a=function(n){return function(n){var i;return n.preventDefault(),e.onselectstart=function(){return!0},i=s(e,n),t.pointerUp(i.left,i.top),document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",a),e.addEventListener("mousemove",r)}}(this),e.addEventListener("mousedown",function(n){return function(n){var i,o;if("canvas"===n.target.tagName.toLowerCase())return i=!0,n.preventDefault(),e.onselectstart=function(){return!1},o=s(e,n),t.pointerDown(o.left,o.top),e.removeEventListener("mousemove",r),document.addEventListener("mousemove",r),document.addEventListener("mouseup",a)}}(this)),l=function(n){return n.preventDefault(),t.pointerMove.apply(t,o(e,n))},h=function(n){return n.preventDefault(),t.pointerUp.apply(t,o(e,n)),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",h),document.removeEventListener("touchcancel",h)},e.addEventListener("touchstart",function(n){return"canvas"===n.target.tagName.toLowerCase()?(n.preventDefault(),1===n.touches.length?(t.pointerDown.apply(t,o(e,n)),document.addEventListener("touchmove",l),document.addEventListener("touchend",h),document.addEventListener("touchcancel",h)):t.pointerMove.apply(t,o(e,n))):void 0}),n&&(console.warn("Keyboard panning is deprecated."),i=function(e){switch(e.keyCode){case 37:t.pan(-10,0);break;case 38:t.pan(0,-10);break;case 39:t.pan(10,0);break;case 40:t.pan(0,10)}return t.repaintAllLayers()},document.addEventListener("keydown",i),c.push(function(){return document.removeEventListener(i)})),function(){var t,e,n,i;for(i=[],e=0,n=c.length;n>e;e++)t=c[e],i.push(t());return i}}},{}],9:[function(t,e,n){var i,r,o,s,a,h,l,c,u,p,d;l=t("./lineEndCapShapes"),d={},r=function(t,e,n){return d[t]={drawFunc:e,drawLatestFunc:n}},c=function(){},p=function(t,e,n){var i;if(null==n&&(n={}),null==n.shouldIgnoreUnsupportedShapes&&(n.shouldIgnoreUnsupportedShapes=!1),null==n.retryCallback&&(n.retryCallback=c),null==n.shouldOnlyDrawLatest&&(n.shouldOnlyDrawLatest=!1),null==n.bufferCtx&&(n.bufferCtx=null),i=n.bufferCtx,d[e.className])return n.shouldOnlyDrawLatest&&d[e.className].drawLatestFunc?d[e.className].drawLatestFunc(t,i,e,n.retryCallback):d[e.className].drawFunc(t,e,n.retryCallback);if(n.shouldIgnoreUnsupportedShapes)return console.warn("Can't render shape of type "+e.className+" to canvas");throw"Can't render shape of type "+e.className+" to canvas"},u=function(t,e,n){return p(t.getContext("2d"),e,n)},r("Rectangle",function(t,e){var n,i;return n=e.x,i=e.y,e.strokeWidth%2!==0&&(n+=.5,i+=.5),t.fillStyle=e.fillColor,t.fillRect(n,i,e.width,e.height),t.lineWidth=e.strokeWidth,t.strokeStyle=e.strokeColor,t.strokeRect(n,i,e.width,e.height)}),r("Ellipse",function(t,e){var n,i,r,o;return t.save(),o=Math.floor(e.width/2),r=Math.floor(e.height/2),n=e.x+o,i=e.y+r,t.translate(n,i),t.scale(1,Math.abs(e.height/e.width)),t.beginPath(),t.arc(0,0,Math.abs(o),0,2*Math.PI),t.closePath(),t.restore(),t.fillStyle=e.fillColor,t.fill(),t.lineWidth=e.strokeWidth,t.strokeStyle=e.strokeColor,t.stroke()}),r("SelectionBox",function(){var t;return t=function(t,e,n){var i,r;return i=e.x,r=e.y,0!==n?(t.fillStyle="#fff",t.fillRect(i,r,n,n),t.strokeStyle="#000",t.strokeRect(i,r,n,n)):void 0},function(e,n){return t(e,n.getTopLeftHandleRect(),n.handleSize),t(e,n.getTopRightHandleRect(),n.handleSize),t(e,n.getBottomLeftHandleRect(),n.handleSize),t(e,n.getBottomRightHandleRect(),n.handleSize),n.backgroundColor&&(e.fillStyle=n.backgroundColor,e.fillRect(n._br.x-n.margin,n._br.y-n.margin,n._br.width+2*n.margin,n._br.height+2*n.margin)),e.lineWidth=1,e.strokeStyle="#000",e.setLineDash([2,4]),e.strokeRect(n._br.x-n.margin,n._br.y-n.margin,n._br.width+2*n.margin,n._br.height+2*n.margin),e.setLineDash([])}}()),r("Image",function(t,e,n){return e.image.width?1===e.scale?t.drawImage(e.image,e.x,e.y):t.drawImage(e.image,e.x,e.y,e.image.width*e.scale,e.image.height*e.scale):n?e.image.onload=n:void 0}),r("Line",function(t,e){var n,i,r,o,s;if(e.x1!==e.x2||e.y1!==e.y2)return i=e.x1,r=e.x2,o=e.y1,s=e.y2,e.strokeWidth%2!==0&&(i+=.5,r+=.5,o+=.5,s+=.5),t.lineWidth=e.strokeWidth,t.strokeStyle=e.color,t.lineCap=e.capStyle,e.dash&&t.setLineDash(e.dash),t.beginPath(),t.moveTo(i,o),t.lineTo(r,s),t.stroke(),e.dash&&t.setLineDash([]),n=Math.max(2.2*e.strokeWidth,5),e.endCapShapes[0]&&l[e.endCapShapes[0]].drawToCanvas(t,i,o,Math.atan2(o-s,i-r),n,e.color),e.endCapShapes[1]?l[e.endCapShapes[1]].drawToCanvas(t,r,s,Math.atan2(s-o,r-i),n,e.color):void 0}),i=function(t,e,n,i){var r,o,s,a;if(null==n&&(n=!1),null==i&&(i="round"),e.length){for(t.lineCap=i,t.strokeStyle=e[0].color,t.lineWidth=e[0].size,t.beginPath(),e[0].size%2===0?t.moveTo(e[0].x,e[0].y):t.moveTo(e[0].x+.5,e[0].y+.5),a=e.slice(1),r=0,o=a.length;o>r;r++)s=a[r],e[0].size%2===0?t.lineTo(s.x,s.y):t.lineTo(s.x+.5,s.y+.5);return n?t.closePath():void 0}},a=function(t,e){return i(t,e.smoothedPoints),t.stroke()},h=function(t,e,n){var r,o,s;return n.tail?(s=n.smoothedPoints.length-n.segmentSize*n.tailSize,o=s<2*n.segmentSize?0:s,r=s+n.segmentSize+1,i(e,n.smoothedPoints.slice(o,r)),e.stroke()):(i(e,n.smoothedPoints),e.stroke())},r("LinePath",a,h),o=function(t,e){return t.save(),t.globalCompositeOperation="destination-out",a(t,e),t.restore()},s=function(t,e,n){return t.save(),t.globalCompositeOperation="destination-out",e.save(),e.globalCompositeOperation="destination-out",h(t,e,n),t.restore(),e.restore()},r("ErasedLinePath",o,s),r("Text",function(t,e){return e.renderer||e._makeRenderer(t),t.fillStyle=e.color,e.renderer.draw(t,e.x,e.y)}),r("Polygon",function(t,e){return t.fillStyle=e.fillColor,i(t,e.points,e.isClosed,"butt"),t.fill(),t.stroke()}),e.exports={defineCanvasRenderer:r,renderShapeToCanvas:u,renderShapeToContext:p}},{"./lineEndCapShapes":12}],10:[function(t,e,n){"use strict";e.exports={imageURLPrefix:"lib/img",primaryColor:"hsla(0, 0%, 0%, 1)",secondaryColor:"hsla(0, 0%, 100%, 1)",backgroundColor:"transparent",strokeWidths:[1,2,5,10,20,30],defaultStrokeWidth:5,toolbarPosition:"top",keyboardShortcuts:!1,imageSize:{width:"infinite",height:"infinite"},backgroundShapes:[],watermarkImage:null,watermarkScale:1,zoomMin:.2,zoomMax:4,zoomStep:.2,snapshot:null,tools:[t("../tools/Pencil"),t("../tools/Eraser"),t("../tools/Line"),t("../tools/Rectangle"),t("../tools/Ellipse"),t("../tools/Text"),t("../tools/Polygon"),t("../tools/Pan"),t("../tools/Eyedropper")]}},{"../tools/Ellipse":43,"../tools/Eraser":44,"../tools/Eyedropper":45,"../tools/Line":46,"../tools/Pan":47,"../tools/Pencil":48,"../tools/Polygon":49,"../tools/Rectangle":50,"../tools/Text":52}],11:[function(t,e,n){"use strict";!function(){if(!document.defaultView.getComputedStyle)throw"ERROR: 'document.defaultView.getComputedStyle' not found. This library only works in browsers that can report computed CSS values.";CanvasRenderingContext2D.prototype.measureTextWidth=CanvasRenderingContext2D.prototype.measureText;var t=function(t,e){return document.defaultView.getComputedStyle(t,null).getPropertyValue(e)};CanvasRenderingContext2D.prototype.measureText2=function(e,n,i){var r=this.measureTextWidth(e),o=!/\S/.test(e);r.fontsize=n;var s=document.createElement("div");s.style.position="absolute",s.style.opacity=0,s.style.font=i,s.innerHTML=e+"
"+e,document.body.appendChild(s),r.leading=1.2*n;var a=t(s,"height");if(a=a.replace("px",""),a>=2*n&&(r.leading=a/2|0),document.body.removeChild(s),o)r.ascent=0,r.descent=0,r.bounds={minx:0,maxx:r.width,miny:0,maxy:0},r.height=0;else{var h=document.createElement("canvas"),l=100;h.width=r.width+l,h.height=3*n,h.style.opacity=1,h.style.font=i;var c=h.getContext("2d");c.font=i;var u=h.width,p=h.height,d=p/2;c.fillStyle="white",c.fillRect(-1,-1,u+2,p+2),c.fillStyle="black",c.fillText(e,l/2,d);for(var f=c.getImageData(0,0,u,p).data,g=0,m=4*u,y=f.length;++g0&&255===f[g];);var v=g/m|0;for(g=0;y>g&&255===f[g];)g+=m,g>=y&&(g=g-y+4);var x=g%m/4|0,w=1;for(g=y-3;g>=0&&255===f[g];)g-=m,0>g&&(g=y-3-4*w++);var k=g%m/4+1|0;r.ascent=d-S,r.descent=v-d,r.bounds={minx:x-l/2,maxx:k-l/2,miny:0,maxy:v-S},r.height=1+(v-S)}return r}}()},{}],12:[function(t,e,n){e.exports={arrow:function(){var t;return t=function(t,e,n,i,r){return[{x:t+Math.cos(n+Math.PI/2)*i/2,y:e+Math.sin(n+Math.PI/2)*i/2},{x:t+Math.cos(n)*r,y:e+Math.sin(n)*r},{x:t+Math.cos(n-Math.PI/2)*i/2,y:e+Math.sin(n-Math.PI/2)*i/2}]},{drawToCanvas:function(e,n,i,r,o,s,a){var h;return null==a&&(a=0),a=a||o,e.fillStyle=s,e.lineWidth=0,e.strokeStyle="transparent",e.beginPath(),h=t(n,i,r,o,a),e.moveTo(h[0].x,h[0].y),e.lineTo(h[1].x,h[1].y),e.lineTo(h[2].x,h[2].y),e.fill()},svg:function(e,n,i,r,o,s){var a;return null==s&&(s=0),s=s||r,a=t(e,n,i,r,s),""}}}()}},{}],13:[function(t,e,n){var i,r,o;o={},r=function(t){return o=t},i=function(t){var e;return e=o[t],e||t},e.exports={localize:r,_:i}},{}],14:[function(t,e,n){var i,r,o,s,a,h;i=t("./shapes").Point,h=t("./util"),o={},o.toPoly=function(t){var e,n,i,o,a,h,l;for(h=[],l=[],n=0,e=0,i=t.length;i>e;e++)a=t[e],o=s(a,r(t,n)),h=h.concat([o[0]]),l=[o[1]].concat(l),n+=1;return h.concat(l)},r=function(t,e){var n;return t.length<3&&(n={x:0,y:0}),n=0===e?r(t,e+1):e===t.length-1?r(t,e-1):o.diff(t[e-1],t[e+1])},o.diff=function(t,e){return{x:e.x-t.x,y:e.y-t.y}},a=function(t){var e;return e=o.len(t),{x:t.x/e,y:t.y/e}},s=function(t,e){return e=a(e),e.x=e.x*t.size/2,e.y=e.y*t.size/2,[{x:t.x-e.y,y:t.y+e.x,color:t.color},{x:t.x+e.y,y:t.y-e.x,color:t.color}]},o.len=function(t){return Math.sqrt(Math.pow(t.x,2)+Math.pow(t.y,2))},o.scalePositionScalar=function(t,e,n,i){var r,o;return o=e*n,r=e*i,t+(o-r)/2},e.exports=o},{"./shapes":17,"./util":19}],15:[function(t,e,n){var i,r,o,s;s=t("./util"),r=t("./shapes").JSONToShape,i="infinite",o=function(t,e,n){return e.width?(t.save(),t.translate(t.canvas.width/2,t.canvas.height/2),t.scale(n,n),t.drawImage(e,-e.width/2,-e.height/2),t.restore()):void 0},e.exports=function(t,e){var n,a,h,l,c,u,p,d;return null==e&&(e={}),null==e.scale&&(e.scale=1),u=function(){var e,n,i,o;for(i=t.shapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}(),a=[],t.backgroundShapes&&(a=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)c=i[e],o.push(r(c));return o}()),null==e.margin&&(e.margin={top:0,right:0,bottom:0,left:0}),l=t.imageSize||{width:i,height:i},h=t.colors||{background:"transparent"},n=u.concat(a),p=document.createElement("canvas"),d=p.getContext("2d"),e.rect?(e.rect.x-=e.margin.left,e.rect.y-=e.margin.top,e.rect.width+=e.margin.left+e.margin.right,e.rect.height+=e.margin.top+e.margin.bottom):e.rect=s.getDefaultImageRect(function(){var t,e,i;for(i=[],t=0,e=n.length;e>t;t++)c=n[t],i.push(c.getBoundingRect(d));return i}(),l,e.margin),p.width=e.rect.width*e.scale,p.height=e.rect.height*e.scale,d.fillStyle=h.background,d.fillRect(0,0,p.width,p.height),e.rect.width&&e.rect.height?(e.watermarkImage&&o(d,e.watermarkImage,e.watermarkScale),s.combineCanvases(p,s.renderShapes(a,e.rect,e.scale),s.renderShapes(u,e.rect,e.scale))):null}},{"./shapes":17,"./util":19}],16:[function(t,e,n){var i,r,o;o=t("./util"),r=t("./shapes").JSONToShape,i="infinite",e.exports=function(t,e){var n,s,a,h,l,c,u,p; +return null==e&&(e={}),p=function(){var e,n,i,o;for(i=t.shapes,o=[],e=0,n=i.length;n>e;e++)u=i[e],o.push(r(u));return o}(),s=[],t.backgroundShapes&&(s=function(){var e,n,i,o;for(i=t.backgroundShapes,o=[],e=0,n=i.length;n>e;e++)u=i[e],o.push(r(u));return o}()),null==e.margin&&(e.margin={top:0,right:0,bottom:0,left:0}),c=t.imageSize||{width:i,height:i},a=t.colors||{background:"transparent"},n=p.concat(s),l=document.createElement("canvas"),h=l.getContext("2d"),e.rect?(e.rect.x-=e.margin.left,e.rect.y-=e.margin.top,e.rect.width+=e.margin.left+e.margin.right,e.rect.height+=e.margin.top+e.margin.bottom):e.rect=o.getDefaultImageRect(function(){var t,e,i;for(i=[],t=0,e=n.length;e>t;t++)u=n[t],i.push(u.getBoundingRect(h));return i}(),c,e.margin),LC.renderShapesToSVG(s.concat(p),e.rect,a.background)}},{"./shapes":17,"./util":19}],17:[function(t,e,n){var i,r,o,s,a,h,l,c,u,p,d,f,g,m,y,S,v,x,w,k,b,C;C=t("./util"),o=t("./TextRenderer"),m=t("./lineEndCapShapes"),S=t("./canvasRenderer"),d=S.defineCanvasRenderer,x=S.renderShapeToContext,v=t("./svgRenderer"),f=v.defineSVGRenderer,w=v.renderShapeToSVG,b={},g=function(t,e){var n,i,r,o,s,a,h,l;n=function(t,n,i,r,o,s,a,h,l,c,u,p,d,f,g,m){return e.constructor.call(this,t,n,i,r,o,s,a,h,l,c,u,p,d,f,g,m),this},n.prototype.className=t,n.fromJSON=e.fromJSON,e.draw&&(s=e.draw,a=e.draw||function(t,e,n){return this.draw(t,e,n)},i=function(t,e,n){return s.call(e,t,n)},r=function(t,e,n,i){return a.call(n,t,e,i)},delete e.draw,e.drawLatest&&delete e.drawLatest,d(t,i,r)),e.toSVG&&(h=e.toSVG,l=function(t){return h.call(t)},delete e.toSVG,f(t,l)),n.prototype.draw=function(t,e){return x(t,this,{retryCallback:e})},n.prototype.drawLatest=function(t,e,n){return x(t,this,{retryCallback:n,bufferCtx:e,shouldOnlyDrawLatest:!0})},n.prototype.toSVG=function(){return w(this)};for(o in e)"fromJSON"!==o&&(n.prototype[o]=e[o]);return b[t]=n,n},p=function(t,e,n,i,r,o,s,a,h,l,c,u,p,d,f,g,m){var y;return y=new b[t](e,n,i,r,o,s,a,h,l,c,u,p,d,f,g,m),y.id=C.getGUID(),y},i=function(t){var e,n,i,r;return e=t.className,n=t.data,i=t.id,e in b?(r=b[e].fromJSON(n),r?(i&&(r.id=i),r):(console.log("Unreadable shape:",e,n),null)):(console.log("Unknown shape:",e,n),null)},k=function(t){return{className:t.className,data:t.toJSON(),id:t.id}},u=function(t,e){return e?u(h(h(c(t))),e-1):t},c=function(t){var e,n,i,r,o;for(t=[t[0]].concat(t).concat(C.last(t)),o=[],e=0,r=0,n=t.length;n>r;r++)i=t[r],o[2*e]=i,t[e+1]&&(o[2*e+1]=l(i,t[e+1])),e+=1;return o},h=function(t){var e,n,i,r,o;for(e=[],n=0,o=0,i=t.length;i>o;o++)r=t[o],t[n+1]&&(e[n]=l(r,t[n+1])),n+=1;return e},l=function(t,e){return p("Point",{x:t.x+(e.x-t.x)/2,y:t.y+(e.y-t.y)/2,size:t.size+(e.size-t.size)/2,color:t.color})},g("Image",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.scale=t.scale||1,this.image=t.image||null},getBoundingRect:function(){return{x:this.x,y:this.y,width:this.image.width*this.scale,height:this.image.height*this.scale}},toJSON:function(){return{x:this.x,y:this.y,imageSrc:this.image.src,imageObject:this.image,scale:this.scale}},fromJSON:function(t){var e,n;return e=null,(null!=(n=t.imageObject)?n.width:void 0)?e=t.imageObject:(e=new Image,e.src=t.imageSrc),p("Image",{x:t.x,y:t.y,image:e,scale:t.scale})},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Rectangle",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.width=t.width||0,this.height=t.height||0,this.strokeWidth=t.strokeWidth||1,this.strokeColor=t.strokeColor||"black",this.fillColor=t.fillColor||"transparent"},getBoundingRect:function(){return{x:this.x-this.strokeWidth/2,y:this.y-this.strokeWidth/2,width:this.width+this.strokeWidth,height:this.height+this.strokeWidth}},toJSON:function(){return{x:this.x,y:this.y,width:this.width,height:this.height,strokeWidth:this.strokeWidth,strokeColor:this.strokeColor,fillColor:this.fillColor}},fromJSON:function(t){return p("Rectangle",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Ellipse",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.width=t.width||0,this.height=t.height||0,this.strokeWidth=t.strokeWidth||1,this.strokeColor=t.strokeColor||"black",this.fillColor=t.fillColor||"transparent"},getBoundingRect:function(){return{x:this.x-this.strokeWidth/2,y:this.y-this.strokeWidth/2,width:this.width+this.strokeWidth,height:this.height+this.strokeWidth}},toJSON:function(){return{x:this.x,y:this.y,width:this.width,height:this.height,strokeWidth:this.strokeWidth,strokeColor:this.strokeColor,fillColor:this.fillColor}},fromJSON:function(t){return p("Ellipse",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Line",{constructor:function(t){return null==t&&(t={}),this.x1=t.x1||0,this.y1=t.y1||0,this.x2=t.x2||0,this.y2=t.y2||0,this.strokeWidth=t.strokeWidth||1,this.color=t.color||"black",this.capStyle=t.capStyle||"round",this.endCapShapes=t.endCapShapes||[null,null],this.dash=t.dash||null},getBoundingRect:function(){return{x:Math.min(this.x1,this.x2)-this.strokeWidth/2,y:Math.min(this.y1,this.y2)-this.strokeWidth/2,width:Math.abs(this.x2-this.x1)+this.strokeWidth/2,height:Math.abs(this.y2-this.y1)+this.strokeWidth/2}},toJSON:function(){return{x1:this.x1,y1:this.y1,x2:this.x2,y2:this.y2,strokeWidth:this.strokeWidth,color:this.color,capStyle:this.capStyle,dash:this.dash,endCapShapes:this.endCapShapes}},fromJSON:function(t){return p("Line",t)},move:function(t){return null==t&&(t={}),this.x1=this.x1-t.xDiff,this.y1=this.y1-t.yDiff,this.x2=this.x2-t.xDiff,this.y2=this.y2-t.yDiff},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}}),a=function(t){var e,n,i,r,o;if(!t.length)return!1;for(o=t[0].size,e=t[0].color,r=0,n=t.length;n>r;r++)if(i=t[r],(i.size!==o||i.color!==e)&&console.log(o,e,i.size,i.color),i.size!==o||i.color!==e)return!1;return!0},s=function(t,e){var n,r,o,s,a;return r=null,e.points?r=function(){var t,r,o,s;for(o=e.points,s=[],r=0,t=o.length;t>r;r++)n=o[r],s.push(i(n));return s}():e.pointCoordinatePairs&&(r=function(){var t,n,r,o,h;for(r=e.pointCoordinatePairs,h=[],n=0,t=r.length;t>n;n++)o=r[n],s=o[0],a=o[1],h.push(i({className:"Point",data:{x:s,y:a,size:e.pointSize,color:e.pointColor,smooth:e.smooth}}));return h}()),o=null,e.smoothedPointCoordinatePairs&&(o=function(){var t,n,r,o,h;for(r=e.smoothedPointCoordinatePairs,h=[],n=0,t=r.length;t>n;n++)o=r[n],s=o[0],a=o[1],h.push(i({className:"Point",data:{x:s,y:a,size:e.pointSize,color:e.pointColor,smooth:e.smooth}}));return h}()),r[0]?p(t,{points:r,smoothedPoints:o,order:e.order,tailSize:e.tailSize,smooth:e.smooth}):null},y={constructor:function(t){var e,n,i,r,o;if(null==t&&(t={}),i=t.points||[],this.order=t.order||3,this.tailSize=t.tailSize||3,this.smooth="smooth"in t?t.smooth:!0,this.segmentSize=Math.pow(2,this.order),this.sampleSize=this.tailSize+1,t.smoothedPoints)return this.points=t.points,this.smoothedPoints=t.smoothedPoints;for(this.points=[],o=[],r=0,e=i.length;e>r;r++)n=i[r],o.push(this.addPoint(n));return o},getBoundingRect:function(){return C.getBoundingRect(this.points.map(function(t){return{x:t.x-t.size/2,y:t.y-t.size/2,width:t.size,height:t.size}}))},toJSON:function(){var t,e;return a(this.points)?{order:this.order,tailSize:this.tailSize,smooth:this.smooth,pointCoordinatePairs:function(){var t,n,i,r;for(i=this.points,r=[],n=0,t=i.length;t>n;n++)e=i[n],r.push([e.x,e.y]);return r}.call(this),smoothedPointCoordinatePairs:function(){var t,n,i,r;for(i=this.smoothedPoints,r=[],n=0,t=i.length;t>n;n++)e=i[n],r.push([e.x,e.y]);return r}.call(this),pointSize:this.points[0].size,pointColor:this.points[0].color}:{order:this.order,tailSize:this.tailSize,smooth:this.smooth,points:function(){var e,n,i,r;for(i=this.points,r=[],n=0,e=i.length;e>n;n++)t=i[n],r.push(k(t));return r}.call(this)}},fromJSON:function(t){return s("LinePath",t)},addPoint:function(t){return this.points.push(t),this.smooth?!this.smoothedPoints||this.points.lengthr;r++)n=i[r],n.move(t);return this.points=this.smoothedPoints},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}},r=g("LinePath",y),g("ErasedLinePath",{constructor:y.constructor,toJSON:y.toJSON,addPoint:y.addPoint,getBoundingRect:y.getBoundingRect,fromJSON:function(t){return s("ErasedLinePath",t)}}),g("Point",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.size=t.size||0,this.color=t.color||""},getBoundingRect:function(){return{x:this.x-this.size/2,y:this.y-this.size/2,width:this.size,height:this.size}},toJSON:function(){return{x:this.x,y:this.y,size:this.size,color:this.color}},fromJSON:function(t){return p("Point",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("Polygon",{constructor:function(t){var e,n,i,r,o;for(null==t&&(t={}),this.points=t.points,this.fillColor=t.fillColor||"white",this.strokeColor=t.strokeColor||"black",this.strokeWidth=t.strokeWidth,this.dash=t.dash||null,null==t.isClosed&&(t.isClosed=!0),this.isClosed=t.isClosed,r=this.points,o=[],i=0,e=r.length;e>i;i++)n=r[i],n.color=this.strokeColor,o.push(n.size=this.strokeWidth);return o},addPoint:function(t,e){return this.points.push(LC.createShape("Point",{x:t,y:e}))},getBoundingRect:function(){return C.getBoundingRect(this.points.map(function(t){return t.getBoundingRect()}))},toJSON:function(){return{strokeWidth:this.strokeWidth,fillColor:this.fillColor,strokeColor:this.strokeColor,dash:this.dash,isClosed:this.isClosed,pointCoordinatePairs:this.points.map(function(t){return[t.x,t.y]})}},fromJSON:function(t){return t.points=t.pointCoordinatePairs.map(function(e){var n,i;return n=e[0],i=e[1],p("Point",{x:n,y:i,size:t.strokeWidth,color:t.strokeColor})}),p("Polygon",t)},move:function(t){var e,n,i,r,o;for(null==t&&(t={}),r=this.points,o=[],i=0,e=r.length;e>i;i++)n=r[i],o.push(n.move(t));return o},setUpperLeft:function(t){var e,n,i;return null==t&&(t={}),e=this.getBoundingRect(),n=e.x-t.x,i=e.y-t.y,this.move({xDiff:n,yDiff:i})}}),g("Text",{constructor:function(t){return null==t&&(t={}),this.x=t.x||0,this.y=t.y||0,this.v=t.v||0,this.text=t.text||"",this.color=t.color||"black",this.font=t.font||"18px sans-serif",this.forcedWidth=t.forcedWidth||null,this.forcedHeight=t.forcedHeight||null},_makeRenderer:function(t){return t.lineHeight=1.2,this.renderer=new o(t,this.text,this.font,this.forcedWidth,this.forcedHeight),this.v<1?(console.log("repairing baseline"),this.v=1,this.x-=this.renderer.metrics.bounds.minx,this.y-=this.renderer.metrics.leading-this.renderer.metrics.descent):void 0},setText:function(t){return this.text=t,this.renderer=null},setFont:function(t){return this.font=t,this.renderer=null},setPosition:function(t,e){return this.x=t,this.y=e},setSize:function(t,e){return this.forcedWidth=Math.max(t,0),this.forcedHeight=Math.max(e,0),this.renderer=null},enforceMaxBoundingRect:function(t){var e,n,i;return e=this.getBoundingRect(t.ctx),i={x:-t.position.x/t.scale,y:-t.position.y/t.scale,width:t.canvas.width/t.scale,height:t.canvas.height/t.scale},e.x+e.width>i.x+i.width?(n=e.x-i.x,this.forcedWidth=i.width-n-10,this.renderer=null):void 0},getBoundingRect:function(t,e){if(null==e&&(e=!1),!this.renderer){if(!t)throw"Must pass ctx if text hasn't been rendered yet";this._makeRenderer(t)}return{x:Math.floor(this.x),y:Math.floor(this.y),width:Math.ceil(this.renderer.getWidth(!0)),height:Math.ceil(this.renderer.getHeight())}},toJSON:function(){return{x:this.x,y:this.y,text:this.text,color:this.color,font:this.font,forcedWidth:this.forcedWidth,forcedHeight:this.forcedHeight,v:this.v}},fromJSON:function(t){return p("Text",t)},move:function(t){return null==t&&(t={}),this.x=this.x-t.xDiff,this.y=this.y-t.yDiff},setUpperLeft:function(t){return null==t&&(t={}),this.x=t.x,this.y=t.y}}),g("SelectionBox",{constructor:function(t){return null==t&&(t={}),this.shape=t.shape,null!=t.handleSize?this.handleSize=t.handleSize:this.handleSize=10,this.margin=4,this.backgroundColor=t.backgroundColor||null,this._br=this.shape.getBoundingRect(t.ctx)},toJSON:function(){return{shape:k(this.shape),backgroundColor:this.backgroundColor}},fromJSON:function(t){var e,n,r,o;return o=t.shape,n=t.handleSize,r=t.margin,e=t.backgroundColor,p("SelectionBox",{shape:i(o),backgroundColor:e})},getTopLeftHandleRect:function(){return{x:this._br.x-this.handleSize-this.margin,y:this._br.y-this.handleSize-this.margin,width:this.handleSize,height:this.handleSize}},getBottomLeftHandleRect:function(){return{x:this._br.x-this.handleSize-this.margin,y:this._br.y+this._br.height+this.margin,width:this.handleSize,height:this.handleSize}},getTopRightHandleRect:function(){return{x:this._br.x+this._br.width+this.margin,y:this._br.y-this.handleSize-this.margin,width:this.handleSize,height:this.handleSize}},getBottomRightHandleRect:function(){return{x:this._br.x+this._br.width+this.margin,y:this._br.y+this._br.height+this.margin,width:this.handleSize,height:this.handleSize}},getBoundingRect:function(){return{x:this._br.x-this.margin,y:this._br.y-this.margin,width:this._br.width+2*this.margin,height:this._br.height+2*this.margin}}}),e.exports={defineShape:g,createShape:p,JSONToShape:i,shapeToJSON:k}},{"./TextRenderer":6,"./canvasRenderer":9,"./lineEndCapShapes":12,"./svgRenderer":18,"./util":19}],18:[function(t,e,n){var i,r,o,s;r=t("./lineEndCapShapes"),s={},i=function(t,e){return s[t]=e},o=function(t,e){if(null==e&&(e={}),null==e.shouldIgnoreUnsupportedShapes&&(e.shouldIgnoreUnsupportedShapes=!1),s[t.className])return s[t.className](t);if(e.shouldIgnoreUnsupportedShapes)return console.warn("Can't render shape of type "+t.className+" to SVG"),"";throw"Can't render shape of type "+t.className+" to SVG"},i("Rectangle",function(t){var e,n,i,r,o,s,a,h;return r=t.x,a=t.y,o=t.x+t.width,h=t.y+t.height,i=Math.min(r,o),s=Math.min(a,h),n=Math.max(r,o)-i,e=Math.max(a,h)-s,t.strokeWidth%2!==0&&(i+=.5,s+=.5),""}),i("SelectionBox",function(t){return""}),i("Ellipse",function(t){var e,n,i,r;return r=Math.floor(t.width/2),i=Math.floor(t.height/2),e=t.x+r,n=t.y+i,""}),i("Image",function(t){return""}),i("Line",function(t){var e,n,i,o,s,a,h;return i=t.dash?"stroke-dasharray='"+t.dash.join(", ")+"'":"",n="",e=Math.max(2.2*t.strokeWidth,5),o=t.x1,s=t.x2,a=t.y1,h=t.y2,t.strokeWidth%2!==0&&(o+=.5,s+=.5,a+=.5,h+=.5),t.endCapShapes[0]&&(n+=r[t.endCapShapes[0]].svg(o,a,Math.atan2(a-h,o-s),e,t.color)),t.endCapShapes[1]&&(n+=r[t.endCapShapes[1]].svg(s,h,Math.atan2(h-a,s-o),e,t.color))," "+n+" "}),i("LinePath",function(t){return""}),i("ErasedLinePath",function(t){return""}),i("Polygon",function(t){return t.isClosed?"":" "}),i("Text",function(t){var e,n,i;return i=t.forcedWidth?"width='"+t.forcedWidth+"px'":"",e=t.forcedHeight?"height='"+t.forcedHeight+"px'":"",n=t.text.split(/\r\n|\r|\n/g),t.renderer&&(n=t.renderer.lines)," "+n.map(function(e){return function(e,n){var i;return i=0===n?0:"1.2em"," "+e+" "}}(this)).join("")+" "}),e.exports={defineSVGRenderer:i,renderShapeToSVG:o}},{"./lineEndCapShapes":12}],19:[function(t,e,n){var i,r,o,s,a=[].slice;o=Array.prototype.slice,i=t("./canvasRenderer").renderShapeToContext,r=t("./svgRenderer").renderShapeToSVG,s={addImageOnload:function(t,e){var n;return n=t.onload,t.onload=function(){return"function"==typeof n&&n(),e()},t},last:function(t,e){return null==e&&(e=null),e?o.call(t,Math.max(t.length-e,0)):t[t.length-1]},classSet:function(t){var e,n;e=[];for(n in t)t[n]&&e.push(n);return e.join(" ")},matchElementSize:function(t,e,n,i){var r;return null==i&&(i=function(){}),r=function(r){return function(){var r,o,s;for(o=0,s=e.length;s>o;o++)r=e[o],r.style.width=t.offsetWidth+"px",r.style.height=t.offsetHeight+"px",null!=r.width&&(r.setAttribute("width",r.offsetWidth*n),r.setAttribute("height",r.offsetHeight*n));return i()}}(this),t.addEventListener("resize",r),window.addEventListener("resize",r),window.addEventListener("orientationchange",r),r()},combineCanvases:function(){var t,e,n,i,r,o,s,h;for(n=1<=arguments.length?a.call(arguments,0):[],t=document.createElement("canvas"),t.width=n[0].width,t.height=n[0].height,r=0,s=n.length;s>r;r++)e=n[r],t.width=Math.max(e.width,t.width),t.height=Math.max(e.height,t.height);for(i=t.getContext("2d"),o=0,h=n.length;h>o;o++)e=n[o],i.drawImage(e,0,0);return t},renderShapes:function(t,e,n,r){var o,s,a,h;for(null==n&&(n=1),null==r&&(r=null),r=r||document.createElement("canvas"),r.width=e.width*n,r.height=e.height*n,o=r.getContext("2d"),o.translate(-e.x*n,-e.y*n),o.scale(n,n),s=0,a=t.length;a>s;s++)h=t[s],i(o,h);return r},renderShapesToSVG:function(t,e,n){var i,o,s,a;return s=e.x,a=e.y,o=e.width,i=e.height,(" "+t.map(r).join("")+" ").replace(/(\r\n|\n|\r)/gm,"")},getBoundingRect:function(t,e,n){var i,r,o,s,a,h,l;if(!t.length)return{x:0,y:0,width:e,height:n};for(a=t[0].x,h=t[0].y,o=t[0].x+t[0].width,s=t[0].y+t[0].height,i=0,r=t.length;r>i;i++)l=t[i],a=Math.floor(Math.min(l.x,a)),h=Math.floor(Math.min(l.y,h)),o=Math.ceil(Math.max(o,l.x+l.width)),s=Math.ceil(Math.max(s,l.y+l.height));return a=e?0:a,h=n?0:h,o=e||o,s=n||s,{x:a,y:h,width:o-a,height:s-h}},getDefaultImageRect:function(t,e,n){var i,r,o;return null==e&&(e={width:0,height:0}),null==n&&(n={top:0,right:0,bottom:0,left:0}),o=e.width,i=e.height,r=s.getBoundingRect(t,"infinite"===o?0:o,"infinite"===i?0:i),r.x-=n.left,r.y-=n.top,r.width+=n.left+n.right,r.height+=n.top+n.bottom,r},getBackingScale:function(t){return null==window.devicePixelRatio?1:window.devicePixelRatio>1?window.devicePixelRatio:1},requestAnimationFrame:(window.requestAnimationFrame||window.setTimeout).bind(window),getGUID:function(){var t;return t=function(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)},function(){return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()}}(),requestAnimationFrame:function(t){return window.webkitRequestAnimationFrame?window.webkitRequestAnimationFrame(t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.mozRequestAnimationFrame?window.mozRequestAnimationFrame(t):setTimeout(t,0)},cancelAnimationFrame:function(t){return window.webkitCancelRequestAnimationFrame?window.webkitCancelRequestAnimationFrame(t):window.webkitCancelAnimationFrame?window.webkitCancelAnimationFrame(t):window.cancelAnimationFrame?window.cancelAnimationFrame(t):window.mozCancelAnimationFrame?window.mozCancelAnimationFrame(t):clearTimeout(t)}},e.exports=s},{"./canvasRenderer":9,"./svgRenderer":18}],20:[function(t,e,n){"use strict";!function(){function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n}t.prototype=window.CustomEvent.prototype,window.CustomEvent=t}()},{}],21:[function(t,e,n){"use strict";var i=!1;CanvasRenderingContext2D.prototype.setLineDash||(CanvasRenderingContext2D.prototype.setLineDash=function(){i||(console.warn("context2D.setLineDash is a no-op in this browser."),i=!0)}),e.exports=null},{}],22:[function(t,e,n){var i,r,o,s,a,h,l,c,u,p,d,f,g,m,y,S,v,x,w,k,b;t("./ie_customevent"),t("./ie_setLineDash"),i=t("./core/LiterallyCanvas"),l=t("./core/defaultOptions"),s=t("./core/canvasRenderer"),w=t("./core/svgRenderer"),x=t("./core/shapes"),b=t("./core/util"),y=t("./core/renderSnapshotToImage"),S=t("./core/renderSnapshotToSVG"),g=t("./core/localization").localize,r=t("./reactGUI/LiterallyCanvas"),d=t("./reactGUI/initDOM"),t("./optionsStyles/font"),t("./optionsStyles/stroke-width"),t("./optionsStyles/line-options-and-stroke-width"),t("./optionsStyles/polygon-and-stroke-width"),t("./optionsStyles/stroke-or-fill"),t("./optionsStyles/null"),u=t("./optionsStyles/optionsStyles").defineOptionsStyle,a={snapshotToShapes:function(t){var e,n,i,r,o;for(i=t.shapes,r=[],e=0,n=i.length;n>e;e++)o=i[e],r.push(x.JSONToShape(o));return r},snapshotJSONToShapes:function(t){return a.snapshotToShapes(JSON.parse(t))}},o=t("./tools/base"),k={Pencil:t("./tools/Pencil"),Eraser:t("./tools/Eraser"),Line:t("./tools/Line"),Rectangle:t("./tools/Rectangle"),Ellipse:t("./tools/Ellipse"),Text:t("./tools/Text"),Polygon:t("./tools/Polygon"),Pan:t("./tools/Pan"),Eyedropper:t("./tools/Eyedropper"),SelectShape:t("./tools/SelectShape"),Tool:o.Tool,ToolWithStroke:o.ToolWithStroke},c=l.tools,h=l.imageURLPrefix,v=function(t){return h=t,l.imageURLPrefix=t},p=function(e,n){var i,r,o,s,a;null==n&&(n={});for(s in l)s in n||(n[s]=l[s]);for(a=e.children,r=0,o=a.length;o>r;r++)i=a[r],e.removeChild(i);return t("./reactGUI/initDOM")(e,n)},f=function(t,e){var n,r,o;return o=t.className,-1===[" "," "].join(t.className).indexOf(" literally ")&&(t.className=t.className+" literally"),t.className=t.className+" toolbar-hidden",n=document.createElement("div"),n.className="lc-drawing",t.appendChild(n),r=new i(n,e),r.teardown=function(){var e,n,i,s;for(r._teardown(),s=t.children,n=0,i=s.length;i>n;n++)e=s[n],t.removeChild(e);return t.className=o},"onInit"in e&&e.onInit(r),r},m=function(t){return t.fn.literallycanvas=function(t){return null==t&&(t={}),this.each(function(e){return function(e,n){return n.literallycanvas=p(n,t)}}(this)),this}},"undefined"!=typeof window&&(window.LC={init:p},window.$&&m(window.$)),e.exports={init:p,registerJQueryPlugin:m,util:b,tools:k,setDefaultImageURLPrefix:v,defaultTools:c,defineOptionsStyle:u,LiterallyCanvasReactComponent:r,defineShape:x.defineShape,createShape:x.createShape,JSONToShape:x.JSONToShape,shapeToJSON:x.shapeToJSON,defineCanvasRenderer:s.defineCanvasRenderer,renderShapeToContext:s.renderShapeToContext,renderShapeToCanvas:s.renderShapeToCanvas,renderShapesToCanvas:b.renderShapes,defineSVGRenderer:w.defineSVGRenderer,renderShapeToSVG:w.renderShapeToSVG,renderShapesToSVG:b.renderShapesToSVG,snapshotToShapes:a.snapshotToShapes,snapshotJSONToShapes:a.snapshotJSONToShapes,renderSnapshotToImage:y,renderSnapshotToSVG:S,localize:g}},{"./core/LiterallyCanvas":5,"./core/canvasRenderer":9,"./core/defaultOptions":10,"./core/localization":13,"./core/renderSnapshotToImage":15,"./core/renderSnapshotToSVG":16,"./core/shapes":17,"./core/svgRenderer":18,"./core/util":19,"./ie_customevent":20,"./ie_setLineDash":21,"./optionsStyles/font":23,"./optionsStyles/line-options-and-stroke-width":24,"./optionsStyles/null":25,"./optionsStyles/optionsStyles":26,"./optionsStyles/polygon-and-stroke-width":27,"./optionsStyles/stroke-or-fill":28,"./optionsStyles/stroke-width":29,"./reactGUI/LiterallyCanvas":32,"./reactGUI/initDOM":42,"./tools/Ellipse":43,"./tools/Eraser":44,"./tools/Eyedropper":45,"./tools/Line":46,"./tools/Pan":47,"./tools/Pencil":48,"./tools/Polygon":49,"./tools/Rectangle":50,"./tools/SelectShape":51,"./tools/Text":52,"./tools/base":53}],23:[function(t,e,n){var i,r,o,s,a,h,l,c,u,p,d,f,g,m,y,S,v,x,w,k,b,C,P;for(a=t("../reactGUI/React-shim"),u=t("./optionsStyles").defineOptionsStyle,c=t("../core/localization")._,h=[["Arial",'Arial,"Helvetica Neue",Helvetica,sans-serif'],["Arial Black",'"Arial Black","Arial Bold",Gadget,sans-serif'],["Arial Narrow",'"Arial Narrow",Arial,sans-serif'],["Gill Sans",'"Gill Sans","Gill Sans MT",Calibri,sans-serif'],["Helvetica",'"Helvetica Neue",Helvetica,Arial,sans-serif'],["Impact",'Impact,Haettenschweiler,"Franklin Gothic Bold",Charcoal,"Helvetica Inserat","Bitstream Vera Sans Bold","Arial Black",sans-serif'],["Tahoma","Tahoma,Verdana,Segoe,sans-serif"],["Trebuchet MS",'"Trebuchet MS","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Tahoma,sans-serif'],["Verdana","Verdana,Geneva,sans-serif"]].map(function(t){var e,n;return e=t[0],n=t[1],{name:c(e),value:n}}),l=[["Baskerville",'Baskerville,"Baskerville Old Face","Hoefler Text",Garamond,"Times New Roman",serif'],["Garamond",'Garamond,Baskerville,"Baskerville Old Face","Hoefler Text","Times New Roman",serif'],["Georgia",'Georgia,Times,"Times New Roman",serif'],["Hoefler Text",'"Hoefler Text","Baskerville Old Face",Garamond,"Times New Roman",serif'],["Lucida Bright",'"Lucida Bright",Georgia,serif'],["Palatino",'Palatino,"Palatino Linotype","Palatino LT STD","Book Antiqua",Georgia,serif'],["Times New Roman",'TimesNewRoman,"Times New Roman",Times,Baskerville,Georgia,serif']].map(function(t){var e,n;return e=t[0],n=t[1],{name:c(e),value:n}}),o=[["Consolas/Monaco",'Consolas,monaco,"Lucida Console",monospace'],["Courier New",'"Courier New",Courier,"Lucida Sans Typewriter","Lucida Typewriter",monospace'],["Lucida Sans Typewriter",'"Lucida Sans Typewriter","Lucida Console",monaco,"Bitstream Vera Sans Mono",monospace']].map(function(t){var e,n;return e=t[0],n=t[1],{name:c(e),value:n}}),s=[["Copperplate",'Copperplate,"Copperplate Gothic Light",fantasy'],["Papyrus","Papyrus,fantasy"],["Script",'"Brush Script MT",cursive']].map(function(t){var e,n;return e=t[0],n=t[1],{name:c(e),value:n}}),i=[[c("Sans Serif"),h],[c("Serif"),l],[c("Monospace"),o],[c("Other"),s]],r={},p=0,g=h.length;g>p;p++)w=h[p],x=w.name,P=w.value,r[x]=P;for(d=0,m=l.length;m>d;d++)k=l[d],x=k.name,P=k.value,r[x]=P;for(f=0,y=o.length;y>f;f++)b=o[f],x=b.name,P=b.value,r[x]=P;for(v=0,S=s.length;S>v;v++)C=s[v],x=C.name,P=C.value,r[x]=P;u("font",a.createClass({displayName:"FontOptions",getInitialState:function(){return{isItalic:!1,isBold:!1,fontName:"Helvetica",fontSizeIndex:4}},getFontSizes:function(){return[9,10,12,14,18,24,36,48,64,72,96,144,288]},updateTool:function(t){var e,n,i;null==t&&(t={});for(i in this.state)i in t||(t[i]=this.state[i]);return e=this.getFontSizes()[t.fontSizeIndex],n=[],t.isItalic&&n.push("italic"),t.isBold&&n.push("bold"),n.push(e+"px"),n.push(r[t.fontName]),this.props.lc.tool.font=n.join(" "),this.props.lc.trigger("setFont",n.join(" "))},handleFontSize:function(t){var e;return e={fontSizeIndex:t.target.value},this.setState(e),this.updateTool(e)},handleFontFamily:function(t){var e;return e={fontName:t.target.selectedOptions[0].innerHTML},this.setState(e),this.updateTool(e)},handleItalic:function(t){var e;return e={isItalic:!this.state.isItalic},this.setState(e),this.updateTool(e)},handleBold:function(t){var e;return e={isBold:!this.state.isBold},this.setState(e),this.updateTool(e)},componentDidMount:function(){return this.updateTool()},render:function(){var t,e,n,r,o,s,h,l,u,p;return o=this.props.lc,l=a.DOM,e=l.div,n=l.input,u=l.select,h=l.option,t=l.br,r=l.label,p=l.span,s=l.optgroup,e({className:"lc-font-settings"},u({value:this.state.fontSizeIndex,onChange:this.handleFontSize},this.getFontSizes().map(function(t){return function(t,e){return h({value:e,key:e},t+"px")}}(this))),u({value:this.state.fontName,onChange:this.handleFontFamily},i.map(function(t){return function(t){var e,n;return n=t[0],e=t[1],s({key:n,label:n},e.map(function(t,e){return h({value:t.name,key:e},t.name)}))}}(this))),p({},r({htmlFor:"italic"},c("italic")),n({type:"checkbox",id:"italic",checked:this.state.isItalic,onChange:this.handleItalic})),p({},r({htmlFor:"bold"},c("bold")),n({type:"checkbox",id:"bold",checked:this.state.isBold,onChange:this.handleBold})))}})),e.exports={}},{"../core/localization":13,"../reactGUI/React-shim":35,"./optionsStyles":26}],24:[function(t,e,n){var i,r,o,s,a;i=t("../reactGUI/React-shim"),a=t("./optionsStyles").defineOptionsStyle,r=i.createFactory(t("../reactGUI/StrokeWidthPicker")),s=t("../reactGUI/createSetStateOnEventMixin"),o=t("../core/util").classSet,a("line-options-and-stroke-width",i.createClass({displayName:"LineOptionsAndStrokeWidth",getState:function(){return{strokeWidth:this.props.tool.strokeWidth,isDashed:this.props.tool.isDashed,hasEndArrow:this.props.tool.hasEndArrow}},getInitialState:function(){return this.getState()},mixins:[s("toolChange")],render:function(){var t,e,n,s,a,h,l,c,u,p;return h=i.DOM,n=h.div,p=h.ul,a=h.li,s=h.img,c=function(t){return function(){return t.props.tool.isDashed=!t.props.tool.isDashed,t.setState(t.getState())}}(this),u=function(t){return function(){return t.props.tool.hasEndArrow=!t.props.tool.hasEndArrow,t.setState(t.getState())}}(this),e=o({"square-toolbar-button":!0,selected:this.state.isDashed}),t=o({"square-toolbar-button":!0,selected:this.state.hasEndArrow}),l={"float":"left",margin:1},n({},n({className:e,onClick:c,style:l},s({src:this.props.imageURLPrefix+"/dashed-line.png"})),n({className:t,onClick:u,style:l},s({src:this.props.imageURLPrefix+"/line-with-arrow.png"})),r({tool:this.props.tool,lc:this.props.lc}))}})),e.exports={}},{"../core/util":19,"../reactGUI/React-shim":35,"../reactGUI/StrokeWidthPicker":37,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],25:[function(t,e,n){var i,r;i=t("../reactGUI/React-shim"),r=t("./optionsStyles").defineOptionsStyle,r("null",i.createClass({displayName:"NoOptions",render:function(){return i.DOM.div()}})),e.exports={}},{"../reactGUI/React-shim":35,"./optionsStyles":26}],26:[function(t,e,n){var i,r,o;i=t("../reactGUI/React-shim"),o={},r=function(t,e){return o[t]=i.createFactory(e)},e.exports={optionsStyles:o,defineOptionsStyle:r}},{"../reactGUI/React-shim":35}],27:[function(t,e,n){var i,r,o,s;i=t("../reactGUI/React-shim"),s=t("./optionsStyles").defineOptionsStyle,r=i.createFactory(t("../reactGUI/StrokeWidthPicker")),o=t("../reactGUI/createSetStateOnEventMixin"),s("polygon-and-stroke-width",i.createClass({displayName:"PolygonAndStrokeWidth",getState:function(){return{strokeWidth:this.props.tool.strokeWidth,inProgress:!1}},getInitialState:function(){return this.getState()},mixins:[o("toolChange")],componentDidMount:function(){var t,e,n;return n=[],this.unsubscribe=function(t){return function(){var t,e,i,r;for(r=[],e=0,i=n.length;i>e;e++)t=n[e], +r.push(t());return r}}(this),e=function(t){return function(){return t.state.inProgress?void 0:t.setState({inProgress:!0})}}(this),t=function(t){return function(){return t.setState({inProgress:!1})}}(this),n.push(this.props.lc.on("lc-polygon-started",e)),n.push(this.props.lc.on("lc-polygon-stopped",t))},componentWillUnmount:function(){return this.unsubscribe()},render:function(){var t,e,n,o,s,a,h,l;return n=this.props.lc,l=i.DOM,t=l.div,e=l.img,a=function(t){return function(){return n.trigger("lc-polygon-finishopen")}}(this),s=function(t){return function(){return n.trigger("lc-polygon-finishclosed")}}(this),o=function(t){return function(){return n.trigger("lc-polygon-cancel")}}(this),h={},this.state.inProgress||(h={display:"none"}),t({},t({className:"polygon-toolbar horz-toolbar",style:h},t({className:"square-toolbar-button",onClick:a},e({src:this.props.imageURLPrefix+"/polygon-open.png"})),t({className:"square-toolbar-button",onClick:s},e({src:this.props.imageURLPrefix+"/polygon-closed.png"})),t({className:"square-toolbar-button",onClick:o},e({src:this.props.imageURLPrefix+"/polygon-cancel.png"}))),t({},r({tool:this.props.tool,lc:this.props.lc})))}})),e.exports={}},{"../reactGUI/React-shim":35,"../reactGUI/StrokeWidthPicker":37,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],28:[function(t,e,n){"use strict";var i=t("../reactGUI/React-shim"),r=t("./optionsStyles"),o=r.defineOptionsStyle,s=t("../reactGUI/createSetStateOnEventMixin");o("stroke-or-fill",i.createClass({displayName:"StrokeOrFillPicker",getState:function(){return{strokeOrFill:"stroke"}},getInitialState:function(){return this.getState()},mixins:[s("toolChange")],onChange:function(t){"stroke-or-fill-stroke"==t.target.id?this.props.lc.tool.strokeOrFill="stroke":this.props.lc.tool.strokeOrFill="fill",this.setState(this.getState())},render:function(){var t=this.props.lc;return i.createElement("form",null,i.createElement("span",null,"Color to change: "),i.createElement("span",null,i.createElement("input",{type:"radio",name:"stroke-or-fill",value:"stroke",id:"stroke-or-fill-stroke",onChange:this.onChange,checked:"stroke"==t.tool.strokeOrFill}),i.createElement("label",{htmlFor:"stroke-or-fill-stroke",className:"label"}," stroke")),i.createElement("span",null,i.createElement("input",{type:"radio",name:"stroke-or-fill",value:"fill",id:"stroke-or-fill-fill",onChange:this.onChange,checked:"fill"==t.tool.strokeOrFill}),i.createElement("label",{htmlFor:"stroke-or-fill-fill",className:"label"}," fill")))}})),e.exports={}},{"../reactGUI/React-shim":35,"../reactGUI/createSetStateOnEventMixin":40,"./optionsStyles":26}],29:[function(t,e,n){var i,r;r=t("./optionsStyles").defineOptionsStyle,i=t("../reactGUI/StrokeWidthPicker"),r("stroke-width",i),e.exports={}},{"../reactGUI/StrokeWidthPicker":37,"./optionsStyles":26}],30:[function(t,e,n){var i,r,o,s,a;r=t("./React-shim"),a=t("./createSetStateOnEventMixin"),o=t("../core/localization")._,s=t("../core/util").classSet,i=r.createClass({displayName:"ClearButton",getState:function(){return{isEnabled:this.props.lc.canUndo()}},getInitialState:function(){return this.getState()},mixins:[a("drawingChange")],render:function(){var t,e,n,i;return e=r.DOM.div,n=this.props.lc,t=s({"lc-clear":!0,"toolbar-button":!0,"fat-button":!0,disabled:!this.state.isEnabled}),i=n.canUndo()?function(t){return function(){return n.clear()}}(this):function(){},e({className:t,onClick:i},o("Clear"))}}),e.exports=i},{"../core/localization":13,"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],31:[function(t,e,n){var i,r,o,s,a,h,l,c,u,p,d;s=t("./React-shim"),o=t("react-addons-pure-render-mixin"),p=t("../core/util"),h=p.classSet,d=p.requestAnimationFrame,a=p.cancelAnimationFrame,u=function(t){var e,n,i,r;return"transparent"===t?{hue:0,sat:0,light:0,alpha:0}:"hsla"!==t.substring(0,4)?null:(n=t.indexOf("("),r=t.indexOf(")"),i=t.substring(n+1,r-n+4),e=function(){var e,n,r,o;for(r=i.split(","),o=[],e=0,n=r.length;n>e;e++)t=r[e],o.push(t.trim());return o}(),{hue:parseInt(e[0],10),sat:parseInt(e[1].substring(0,e[1].length-1),10),light:parseInt(e[2].substring(0,e[2].length-1),10),alpha:parseFloat(e[3])})},l=function(t){var e,n,i,r;return n=t.hue,r=t.sat,i=t.light,e=t.alpha,"hsla("+n+", "+r+"%, "+i+"%, "+e+")"},c=function(t){var e,n,i;return e=t.hue,i=t.sat,n=t.light,"hsl("+e+", "+i+"%, "+n+"%)"},i=s.createFactory(s.createClass({displayName:"ColorGrid",mixins:[o],render:function(){var t;return(t=s.DOM.div)({},this.props.rows.map(function(e){return function(n,i){return t({className:"color-row",key:i,style:{width:20*n.length}},n.map(function(n,i){var r,o,s,a,c,u,p,d;return c=n.hue,p=n.sat,u=n.light,r=n.alpha,s=l(n),a="hsl("+c+", "+p+"%, "+u+"%)",o=h({"color-cell":!0,selected:e.props.selectedColor===s}),d=function(t){return e.props.onChange(n,s),t.stopPropagation(),t.preventDefault()},t({className:o,onTouchStart:d,onTouchMove:d,onClick:d,style:{backgroundColor:a},key:i})}))}}(this)))}})),r=s.createClass({displayName:"ColorWell",mixins:[o],getInitialState:function(){var t,e;return t=this.props.lc.colors[this.props.colorName],e=u(t),null==e&&(e={}),null==e.alpha&&(e.alpha=1),null==e.sat&&(e.sat=100),null==e.hue&&(e.hue=0),null==e.light&&(e.light=50),{colorString:t,alpha:e.alpha,sat:0===e.sat?100:e.sat,isPickerVisible:!1,hsla:e}},componentDidMount:function(){return this.unsubscribe=this.props.lc.on(this.props.colorName+"ColorChange",function(t){return function(){var e;return e=t.props.lc.colors[t.props.colorName],t.setState({colorString:e}),t.setHSLAFromColorString(e)}}(this))},componentWillUnmount:function(){return this.unsubscribe()},setHSLAFromColorString:function(t){var e;return e=u(t),e?this.setState({hsla:e,alpha:e.alpha,sat:e.sat}):this.setState({hsla:null,alpha:1,sat:100})},closePicker:function(){return this.setState({isPickerVisible:!1})},togglePicker:function(){var t,e;return t=!this.state.isPickerVisible,e=t&&0===this.state.sat,this.setHSLAFromColorString(this.state.colorString),this.setState({isPickerVisible:t,sat:e?100:this.state.sat})},setColor:function(t){return this.setState({colorString:t}),this.setHSLAFromColorString(t),this.props.lc.setColor(this.props.colorName,t)},setAlpha:function(t){var e;return this.setState({alpha:t}),this.state.hsla?(e=this.state.hsla,e.alpha=t,this.setState({hsla:e}),this.setColor(l(e))):void 0},setSat:function(t){var e;if(this.setState({sat:t}),isNaN(t))throw"SAT";return this.state.hsla?(e=this.state.hsla,e.sat=t,this.setState({hsla:e}),this.setColor(l(e))):void 0},render:function(){var t,e,n,i;return i=s.DOM,e=i.div,n=i.label,t=i.br,e({className:h({"color-well":!0,open:this.state.isPickerVisible}),onMouseLeave:this.closePicker,style:{"float":"left",textAlign:"center"}},n({"float":"left"},this.props.label),t({}),e({className:h({"color-well-color-container":!0,selected:this.state.isPickerVisible}),style:{backgroundColor:"white"},onClick:this.togglePicker},e({className:"color-well-checker color-well-checker-top-left"}),e({className:"color-well-checker color-well-checker-bottom-right",style:{left:"50%",top:"50%"}}),e({className:"color-well-color",style:{backgroundColor:this.state.colorString}}," ")),this.renderPicker())},renderPicker:function(){var t,e,n,r,o,a,h,l,c,u,p,d,f;if(c=s.DOM,t=c.div,a=c.label,r=c.input,!this.state.isPickerVisible)return null;for(d=function(e){return function(e){return t({className:"color-row label",key:e,style:{lineHeight:"20px",height:16}},e)}}(this),p=function(e){return function(){var n;return n=e.props.lc.opts.imageURLPrefix+"/checkerboard-8x8.png",t({className:"color-row",key:"color",style:{position:"relative",backgroundImage:"url("+n+")",backgroundRepeat:"repeat",height:24}},t({style:{position:"absolute",top:0,right:0,bottom:0,left:0,backgroundColor:e.state.colorString}}))}}(this),f=[],f.push(function(){var t,e;for(e=[],n=t=0;100>=t;n=t+=10)e.push({hue:0,sat:0,light:n,alpha:this.state.alpha});return e}.call(this)),u=[0,30,60,90,120,150,180,210,240,270,300,330],o=0,h=u.length;h>o;o++)e=u[o],f.push(function(){var t,i;for(i=[],n=t=10;90>=t;n=t+=8)i.push({hue:e,sat:this.state.sat,light:n,alpha:this.state.alpha});return i}.call(this));return l=function(t){return function(e,n){return t.setColor(n)}}(this),t({className:"color-picker-popup"},p(),d("alpha"),r({type:"range",min:0,max:1,step:.01,value:this.state.alpha,onChange:function(t){return function(e){return t.setAlpha(parseFloat(e.target.value))}}(this)}),d("saturation"),r({type:"range",min:0,max:100,value:this.state.sat,max:100,onChange:function(t){return function(e){return t.setSat(parseInt(e.target.value,10))}}(this)}),i({rows:f,selectedColor:this.state.colorString,onChange:l}))}}),e.exports=r},{"../core/util":19,"./React-shim":35,"react-addons-pure-render-mixin":1}],32:[function(t,e,n){"use strict";var i=t("../reactGUI/React-shim"),r=t("../reactGUI/ReactDOM-shim"),o=r.findDOMNode,s=t("../core/util"),a=s.classSet,h=t("./Picker"),l=t("./Options"),c=t("./createToolButton"),u=t("../core/LiterallyCanvas"),p=t("../core/defaultOptions");t("../optionsStyles/font"),t("../optionsStyles/stroke-width"),t("../optionsStyles/line-options-and-stroke-width"),t("../optionsStyles/polygon-and-stroke-width"),t("../optionsStyles/null");var d=i.createClass({displayName:"CanvasContainer",shouldComponentUpdate:function(){return!1},render:function(){return i.createElement("div",{key:"literallycanvas",className:"lc-drawing with-gui"})}}),f=i.createClass({displayName:"LiterallyCanvas",getDefaultProps:function(){return p},bindToModel:function(){var t=o(this.canvas),e=this.props;this.lc.bindToElement(t),"function"==typeof e.onInit&&e.onInit(this.lc)},componentWillMount:function(){var t=this;this.lc||(this.props.lc?this.lc=this.props.lc:this.lc=new u(this.props),this.toolButtonComponents=this.lc.opts.tools.map(function(e){return c(new e(t.lc))}))},componentDidMount:function(){this.lc.isBound||this.bindToModel()},componentWillUnmount:function(){this.lc&&this.lc._teardown()},render:function(){var t=this,e=this.lc,n=this.toolButtonComponents,r=(this.props,this.lc.opts),o=r.imageURLPrefix,s=r.toolbarPosition,c={lc:e,toolButtonComponents:n,imageURLPrefix:o},u=a({"toolbar-at-top":"top"===s,"toolbar-at-bottom":"bottom"===s,"toolbar-hidden":"hidden"===s});return i.createElement("div",{className:"literally "+u},i.createElement(d,{ref:function(e){return t.canvas=e}}),i.createElement(h,c),i.createElement(l,{lc:e,imageURLPrefix:o}))}});e.exports=f},{"../core/LiterallyCanvas":5,"../core/defaultOptions":10,"../core/util":19,"../optionsStyles/font":23,"../optionsStyles/line-options-and-stroke-width":24,"../optionsStyles/null":25,"../optionsStyles/polygon-and-stroke-width":27,"../optionsStyles/stroke-width":29,"../reactGUI/React-shim":35,"../reactGUI/ReactDOM-shim":36,"./Options":33,"./Picker":34,"./createToolButton":41}],33:[function(t,e,n){var i,r,o,s;r=t("./React-shim"),o=t("./createSetStateOnEventMixin"),s=t("../optionsStyles/optionsStyles").optionsStyles,i=r.createClass({displayName:"Options",getState:function(){var t;return{style:null!=(t=this.props.lc.tool)?t.optionsStyle:void 0,tool:this.props.lc.tool}},getInitialState:function(){return this.getState()},mixins:[o("toolChange")],renderBody:function(){var t;return t=""+this.state.style,s[t]&&s[t]({lc:this.props.lc,tool:this.state.tool,imageURLPrefix:this.props.imageURLPrefix})},render:function(){var t;return(t=r.DOM.div)({className:"lc-options horz-toolbar"},this.renderBody())}}),e.exports=i},{"../optionsStyles/optionsStyles":26,"./React-shim":35,"./createSetStateOnEventMixin":40}],34:[function(t,e,n){var i,r,o,s,a,h,l,c;a=t("./React-shim"),i=a.createFactory(t("./ClearButton")),h=a.createFactory(t("./UndoRedoButtons")),l=a.createFactory(t("./ZoomButtons")),c=t("../core/localization")._,o=a.createFactory(t("./ColorWell")),r=a.createFactory(a.createClass({displayName:"ColorPickers",render:function(){var t,e;return e=this.props.lc,(t=a.DOM.div)({className:"lc-color-pickers"},o({lc:e,colorName:"primary",label:c("stroke")}),o({lc:e,colorName:"secondary",label:c("fill")}),o({lc:e,colorName:"background",label:c("bg")}))}})),s=a.createClass({displayName:"Picker",getInitialState:function(){return{selectedToolIndex:0}},renderBody:function(){var t,e,n,o,s;return t=a.DOM.div,o=this.props,s=o.toolButtonComponents,n=o.lc,e=o.imageURLPrefix,t({className:"lc-picker-contents"},s.map(function(t){return function(i,r){return i({lc:n,imageURLPrefix:e,key:r,isSelected:r===t.state.selectedToolIndex,onSelect:function(e){return n.setTool(e),t.setState({selectedToolIndex:r})}})}}(this)),s.length%2!==0?t({className:"toolbar-button thin-button disabled"}):void 0,t({style:{position:"absolute",bottom:0,left:0,right:0}},r({lc:this.props.lc}),h({lc:n,imageURLPrefix:e}),l({lc:n,imageURLPrefix:e}),i({lc:n})))},render:function(){var t;return(t=a.DOM.div)({className:"lc-picker"},this.renderBody())}}),e.exports=s},{"../core/localization":13,"./ClearButton":30,"./ColorWell":31,"./React-shim":35,"./UndoRedoButtons":38,"./ZoomButtons":39}],35:[function(t,e,n){var i;try{i=t("react")}catch(r){i=window.React}if(null==i)throw"Can't find React";e.exports=i},{react:"react"}],36:[function(t,e,n){var i;try{i=t("react-dom")}catch(r){i=window.ReactDOM}if(null==i)try{i=t("react")}catch(o){i=window.React}if(null==i)throw"Can't find ReactDOM";e.exports=i},{react:"react","react-dom":"react-dom"}],37:[function(t,e,n){var i,r,o;i=t("./React-shim"),o=t("../reactGUI/createSetStateOnEventMixin"),r=t("../core/util").classSet,e.exports=i.createClass({displayName:"StrokeWidthPicker",getState:function(t){return null==t&&(t=this.props.tool),{strokeWidth:t.strokeWidth}},getInitialState:function(){return this.getState()},mixins:[o("toolDidUpdateOptions")],componentWillReceiveProps:function(t){return this.setState(this.getState(t.tool))},render:function(){var t,e,n,o,s,a,h;return o=i.DOM,h=o.ul,n=o.li,a=o.svg,t=o.circle,e=o.div,s=this.props.lc.opts.strokeWidths,e({},s.map(function(n){return function(i,o){var s,h;return s=r({"square-toolbar-button":!0,selected:i===n.state.strokeWidth}),h=28,e({key:i},e({className:s,onClick:function(){return n.props.lc.trigger("setStrokeWidth",i)}},a({width:h-2,height:h-2,viewPort:"0 0 "+i+" "+i,version:"1.1",xmlns:"http://www.w3.org/2000/svg"},t({cx:Math.ceil(h/2-1),cy:Math.ceil(h/2-1),r:i/2}))))}}(this)))}})},{"../core/util":19,"../reactGUI/createSetStateOnEventMixin":40,"./React-shim":35}],38:[function(t,e,n){var i,r,o,s,a,h,l;i=t("./React-shim"),h=t("./createSetStateOnEventMixin"),a=t("../core/util").classSet,l=function(t){return i.createClass({displayName:"undo"===t?"UndoButton":"RedoButton",getState:function(){return{isEnabled:function(){switch(!1){case"undo"!==t:return this.props.lc.canUndo();case"redo"!==t:return this.props.lc.canRedo()}}.call(this)}},getInitialState:function(){return this.getState()},mixins:[h("drawingChange")],render:function(){var e,n,r,o,s,h,l,c,u,p,d;return l=i.DOM,n=l.div,o=l.img,c=this.props,s=c.lc,r=c.imageURLPrefix,d="undo"===t?"Undo":"Redo",e="lc-"+t+" "+a({"toolbar-button":!0,"thin-button":!0,disabled:!this.state.isEnabled}),h=function(){switch(!1){case!!this.state.isEnabled:return function(){};case"undo"!==t:return function(){return s.undo()};case"redo"!==t:return function(){return s.redo()}}}.call(this),u=r+"/"+t+".png",p={backgroundImage:"url("+u+")"},n({className:e,onClick:h,title:d,style:p})}})},o=i.createFactory(l("undo")),r=i.createFactory(l("redo")),s=i.createClass({displayName:"UndoRedoButtons",render:function(){var t;return(t=i.DOM.div)({className:"lc-undo-redo"},o(this.props),r(this.props))}}),e.exports=s},{"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],39:[function(t,e,n){var i,r,o,s,a,h,l;i=t("./React-shim"),h=t("./createSetStateOnEventMixin"),a=t("../core/util").classSet,l=function(t){return i.createClass({displayName:"in"===t?"ZoomInButton":"ZoomOutButton",getState:function(){return{isEnabled:function(){switch(!1){case"in"!==t:return this.props.lc.scalethis.props.lc.config.zoomMin}}.call(this)}},getInitialState:function(){return this.getState()},mixins:[h("zoom")],render:function(){var e,n,r,o,s,h,l,c,u,p,d;return l=i.DOM,n=l.div,o=l.img,c=this.props,s=c.lc,r=c.imageURLPrefix,d="in"===t?"Zoom in":"Zoom out",e="lc-zoom-"+t+" "+a({"toolbar-button":!0,"thin-button":!0,disabled:!this.state.isEnabled}),h=function(){switch(!1){case!!this.state.isEnabled:return function(){};case"in"!==t:return function(){return s.zoom(s.config.zoomStep)};case"out"!==t:return function(){return s.zoom(-s.config.zoomStep)}}}.call(this),u=r+"/zoom-"+t+".png",p={backgroundImage:"url("+u+")"},n({className:e,onClick:h,title:d,style:p})}})},s=i.createFactory(l("out")),o=i.createFactory(l("in")),r=i.createClass({displayName:"ZoomButtons",render:function(){var t;return(t=i.DOM.div)({className:"lc-zoom"},s(this.props),o(this.props))}}),e.exports=r},{"../core/util":19,"./React-shim":35,"./createSetStateOnEventMixin":40}],40:[function(t,e,n){var i,r;i=t("./React-shim"),e.exports=r=function(t){return{componentDidMount:function(){return this.unsubscribe=this.props.lc.on(t,function(t){return function(){return t.setState(t.getState())}}(this))},componentWillUnmount:function(){return this.unsubscribe()}}}},{"./React-shim":35}],41:[function(t,e,n){var i,r,o;i=t("./React-shim"),r=t("../core/util").classSet,o=function(t){var e,n;return e=t.name,n=t.iconName,i.createFactory(i.createClass({displayName:e,getDefaultProps:function(){return{isSelected:!1,lc:null}},componentWillMount:function(){return this.props.isSelected?this.props.lc.setTool(t):void 0},render:function(){var o,s,a,h,l,c,u,p,d;return u=i.DOM,s=u.div,h=u.img,p=this.props,a=p.imageURLPrefix,l=p.isSelected,c=p.onSelect,o=r({"lc-pick-tool":!0,"toolbar-button":!0,"thin-button":!0,selected:l}),d=a+"/"+n+".png",s({className:o,style:{backgroundImage:"url("+d+")"},onClick:function(){return c(t)},title:e})}}))},e.exports=o},{"../core/util":19,"./React-shim":35}],42:[function(t,e,n){"use strict";function i(t,e){var n=t.className,i=new s(e);return o.render(r.createElement(a,{lc:i}),t),i.teardown=function(){i._teardown();for(var e=0;en;n++)t=e[n],r.push(t());return r}}(this),e.push(t.on("lc-pointerdown",function(e){return function(n){var i,r;return i=n.rawX,r=n.rawY,e.oldPosition=t.position,e.pointerStart={x:i,y:r}}}(this))),e.push(t.on("lc-pointerdrag",function(e){return function(n){var i,r,o;return r=n.rawX,o=n.rawY,i={x:(r-e.pointerStart.x)*t.backingScale,y:(o-e.pointerStart.y)*t.backingScale},t.setPan(e.oldPosition.x+i.x,e.oldPosition.y+i.y)}}(this)))},e.prototype.willBecomeInactive=function(t){return this.unsubscribe()},e}(r)},{"../core/shapes":17,"./base":53}],48:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Pencil",e.prototype.iconName="pencil",e.prototype.eventTimeThreshold=10,e.prototype.begin=function(t,e,n){return this.color=n.getColor("primary"),this.currentShape=this.makeShape(),this.currentShape.addPoint(this.makePoint(t,e,n)),this.lastEventTime=Date.now()},e.prototype["continue"]=function(t,e,n){var i;return i=Date.now()-this.lastEventTime,i>this.eventTimeThreshold?(this.lastEventTime+=i,this.currentShape.addPoint(this.makePoint(t,e,n)),n.drawShapeInProgress(this.currentShape)):void 0},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape),this.currentShape=void 0},e.prototype.makePoint=function(t,e,n){return o("Point",{x:t,y:e,size:this.strokeWidth,color:this.color})},e.prototype.makeShape=function(){return o("LinePath")},e}(r)},{"../core/shapes":17,"./base":53}],49:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Polygon",e.prototype.iconName="polygon",e.prototype.usesSimpleAPI=!1,e.prototype.didBecomeActive=function(t){var n,i,r,o,s,a,h;return e.__super__.didBecomeActive.call(this,t),h=[],this.polygonUnsubscribe=function(t){return function(){var t,e,n,i;for(i=[],e=0,n=h.length;n>e;e++)t=h[e],i.push(t());return i}}(this),this.points=null,this.maybePoint=null,r=function(e){return function(){return e._getWillFinish()?e._close(t):(t.trigger("lc-polygon-started"),e.points?e.points.push(e.maybePoint):e.points=[e.maybePoint],e.maybePoint={x:e.maybePoint.x,y:e.maybePoint.y},t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main"))}}(this),i=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.maybePoint?(e.maybePoint.x=i,e.maybePoint.y=r,t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main")):void 0}}(this),n=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.maybePoint={x:i,y:r},t.setShapesInProgress(e._getShapes(t)),t.repaintLayer("main")}}(this),a=function(e){return function(){return e.maybePoint={x:1/0,y:1/0},e._close(t)}}(this),s=function(e){return function(){return e.maybePoint=e.points[0],e._close(t)}}(this),o=function(e){return function(){return e._cancel(t)}}(this),h.push(t.on("drawingChange",function(e){return function(){return e._cancel(t)}}(this))),h.push(t.on("lc-pointerdown",n)),h.push(t.on("lc-pointerdrag",i)),h.push(t.on("lc-pointermove",i)),h.push(t.on("lc-pointerup",r)),h.push(t.on("lc-polygon-finishopen",a)),h.push(t.on("lc-polygon-finishclosed",s)),h.push(t.on("lc-polygon-cancel",o))},e.prototype.willBecomeInactive=function(t){return e.__super__.willBecomeInactive.call(this,t),(this.points||this.maybePoint)&&this._cancel(t),this.polygonUnsubscribe()},e.prototype._getArePointsClose=function(t,e){return Math.abs(t.x-e.x)+Math.abs(t.y-e.y)<10},e.prototype._getWillClose=function(){return this.points&&this.points.length>1&&this.maybePoint?this._getArePointsClose(this.points[0],this.maybePoint):!1},e.prototype._getWillFinish=function(){return this.points&&this.points.length>1&&this.maybePoint?this._getArePointsClose(this.points[0],this.maybePoint)||this._getArePointsClose(this.points[this.points.length-1],this.maybePoint):!1},e.prototype._cancel=function(t){return t.trigger("lc-polygon-stopped"),this.maybePoint=null,this.points=null,t.setShapesInProgress([]),t.repaintLayer("main")},e.prototype._close=function(t){return t.trigger("lc-polygon-stopped"),t.setShapesInProgress([]),this.points.length>2&&t.saveShape(this._getShape(t,!1)),this.maybePoint=null,this.points=null},e.prototype._getShapes=function(t,e){var n;return null==e&&(e=!0),n=this._getShape(t,e),n?[n]:[]},e.prototype._getShape=function(t,e){var n;return null==e&&(e=!0),n=[],this.points&&(n=n.concat(this.points)),!e&&n.length<3?null:(e&&this.maybePoint&&n.push(this.maybePoint),n.length>1?o("Polygon",{isClosed:this._getWillClose(),strokeColor:t.getColor("primary"),fillColor:t.getColor("secondary"),strokeWidth:this.strokeWidth,points:n.map(function(t){return o("Point",t)})}):null)},e.prototype.optionsStyle="polygon-and-stroke-width",e}(r)},{"../core/shapes":17,"./base":53}],50:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").ToolWithStroke,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(){return e.__super__.constructor.apply(this,arguments)}return s(e,t),e.prototype.name="Rectangle",e.prototype.iconName="rectangle",e.prototype.begin=function(t,e,n){return this.currentShape=o("Rectangle",{x:t,y:e,strokeWidth:this.strokeWidth,strokeColor:n.getColor("primary"),fillColor:n.getColor("secondary")})},e.prototype["continue"]=function(t,e,n){return this.currentShape.width=t-this.currentShape.x,this.currentShape.height=e-this.currentShape.y,n.drawShapeInProgress(this.currentShape)},e.prototype.end=function(t,e,n){return n.saveShape(this.currentShape)},e}(r)},{"../core/shapes":17,"./base":53}],51:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;r=t("./base").Tool,o=t("../core/shapes").createShape,e.exports=i=function(t){function e(t){this.selectCanvas=document.createElement("canvas"),this.selectCanvas.style["background-color"]="transparent",this.selectCtx=this.selectCanvas.getContext("2d")}return s(e,t),e.prototype.name="SelectShape",e.prototype.usesSimpleAPI=!1,e.prototype.didBecomeActive=function(t){var e,n,i,r;return r=[],this._selectShapeUnsubscribe=function(t){return function(){var t,e,n,i;for(i=[],e=0,n=r.length;n>e;e++)t=r[e],i.push(t());return i}}(this),e=function(e){return function(n){var i,r,s,a;return s=n.x,a=n.y,e.didDrag=!1,r=e._getPixel(s,a,t,e.selectCtx),e.selectedShape=t.shapes[r],null!=e.selectedShape?(t.trigger("shapeSelected",{selectedShape:e.selectedShape}),t.setShapesInProgress([e.selectedShape,o("SelectionBox",{shape:e.selectedShape,handleSize:0})]),t.repaintLayer("main"),i=e.selectedShape.getBoundingRect(),e.dragOffset={x:s-i.x,y:a-i.y}):void 0}}(this),n=function(e){return function(n){var i,r;return i=n.x,r=n.y,null!=e.selectedShape?(e.didDrag=!0,e.selectedShape.setUpperLeft({x:i-e.dragOffset.x,y:r-e.dragOffset.y}),t.setShapesInProgress([e.selectedShape,o("SelectionBox",{shape:e.selectedShape,handleSize:0})]),t.repaintLayer("main")):void 0}}(this),i=function(e){return function(n){var i,r;return i=n.x,r=n.y,e.didDrag?(e.didDrag=!1,t.trigger("shapeMoved",{shape:e.selectedShape}),t.trigger("drawingChange",{}),t.repaintLayer("main"),e._drawSelectCanvas(t)):void 0}}(this),r.push(t.on("lc-pointerdown",e)),r.push(t.on("lc-pointerdrag",n)),r.push(t.on("lc-pointerup",i)),this._drawSelectCanvas(t)},e.prototype.willBecomeInactive=function(t){return this._selectShapeUnsubscribe(),t.setShapesInProgress([])},e.prototype._drawSelectCanvas=function(t){var e;return this.selectCanvas.width=t.canvas.width,this.selectCanvas.height=t.canvas.height,this.selectCtx.clearRect(0,0,this.selectCanvas.width,this.selectCanvas.height),e=t.shapes.map(function(t){return function(e,n){return o("SelectionBox",{shape:e,handleSize:0,backgroundColor:"#"+t._intToHex(n)})}}(this)),t.draw(e,this.selectCtx)},e.prototype._intToHex=function(t){return("000000"+t.toString(16)).slice(-6)},e.prototype._getPixel=function(t,e,n,i){var r,o;return r=n.drawingCoordsToClientCoords(t,e),o=i.getImageData(r.x,r.y,1,1).data,o[3]?parseInt(this._rgbToHex(o[0],o[1],o[2]),16):null},e.prototype._componentToHex=function(t){var e;return e=t.toString(16),("0"+e).slice(-2)},e.prototype._rgbToHex=function(t,e,n){return""+this._componentToHex(t)+this._componentToHex(e)+this._componentToHex(n)},e}(r)},{"../core/shapes":17,"./base":53}],52:[function(t,e,n){var i,r,o,s,a=function(t,e){function n(){this.constructor=t}for(var i in e)h.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},h={}.hasOwnProperty;r=t("./base").Tool,o=t("../core/shapes").createShape,s=function(t,e){return t.xe.x+e.width?!1:t.y>e.y+e.height?!1:!0},e.exports=i=function(t){function e(){this.text="",this.font="bold 18px sans-serif",this.currentShape=null, +this.currentShapeState=null,this.initialShapeBoundingRect=null,this.dragAction=null,this.didDrag=!1}return a(e,t),e.prototype.name="Text",e.prototype.iconName="text",e.prototype.didBecomeActive=function(t){var e,n,i;return n=[],this.unsubscribe=function(t){return function(){var t,e,i,r;for(r=[],e=0,i=n.length;i>e;e++)t=n[e],r.push(t());return r}}(this),e=function(e){return function(){return e._ensureNotEditing(t),e._clearCurrentShape(t),t.repaintLayer("main")}}(this),i=function(e){return function(){return e._updateInputEl(t)}}(this),n.push(t.on("drawingChange",e)),n.push(t.on("zoom",i)),n.push(t.on("imageSizeChange",i)),n.push(t.on("snapshotLoad",function(e){return function(){return e._clearCurrentShape(t),t.repaintLayer("main")}}(this))),n.push(t.on("primaryColorChange",function(e){return function(n){return e.currentShape?(e.currentShape.color=n,e._updateInputEl(t),t.repaintLayer("main")):void 0}}(this))),n.push(t.on("setFont",function(e){return function(n){return e.currentShape?(e.font=n,e.currentShape.setFont(n),e._setShapesInProgress(t),e._updateInputEl(t),t.repaintLayer("main")):void 0}}(this)))},e.prototype.willBecomeInactive=function(t){return this.currentShape&&(this._ensureNotEditing(t),this.commit(t)),this.unsubscribe()},e.prototype.setText=function(t){return this.text=t},e.prototype._ensureNotEditing=function(t){return"editing"===this.currentShapeState?this._exitEditingState(t):void 0},e.prototype._clearCurrentShape=function(t){return this.currentShape=null,this.initialShapeBoundingRect=null,this.currentShapeState=null,t.setShapesInProgress([])},e.prototype.commit=function(t){return this.currentShape.text&&t.saveShape(this.currentShape),this._clearCurrentShape(t),t.repaintLayer("main")},e.prototype._getSelectionShape=function(t,e){return null==e&&(e=null),o("SelectionBox",{shape:this.currentShape,ctx:t,backgroundColor:e})},e.prototype._setShapesInProgress=function(t){switch(this.currentShapeState){case"selected":return t.setShapesInProgress([this._getSelectionShape(t.ctx),this.currentShape]);case"editing":return t.setShapesInProgress([this._getSelectionShape(t.ctx,"#fff")]);default:return t.setShapesInProgress([this.currentShape])}},e.prototype.begin=function(t,e,n){var i,r,a,h;return this.dragAction="none",this.didDrag=!1,"selected"===this.currentShapeState||"editing"===this.currentShapeState?(i=this.currentShape.getBoundingRect(n.ctx),h=this._getSelectionShape(n.ctx),a=h.getBoundingRect(),r={x:t,y:e},s(r,i)&&(this.dragAction="move"),s(r,h.getBottomRightHandleRect())&&(this.dragAction="resizeBottomRight"),s(r,h.getTopLeftHandleRect())&&(this.dragAction="resizeTopLeft"),s(r,h.getBottomLeftHandleRect())&&(this.dragAction="resizeBottomLeft"),s(r,h.getTopRightHandleRect())&&(this.dragAction="resizeTopRight"),"none"===this.dragAction&&"editing"===this.currentShapeState&&(this.dragAction="stop-editing",this._exitEditingState(n))):(this.color=n.getColor("primary"),this.currentShape=o("Text",{x:t,y:e,text:this.text,color:this.color,font:this.font,v:1}),this.dragAction="place",this.currentShapeState="selected"),"none"===this.dragAction?void this.commit(n):(this.initialShapeBoundingRect=this.currentShape.getBoundingRect(n.ctx),this.dragOffset={x:t-this.initialShapeBoundingRect.x,y:e-this.initialShapeBoundingRect.y},this._setShapesInProgress(n),n.repaintLayer("main"))},e.prototype["continue"]=function(t,e,n){var i,r,o;if("none"!==this.dragAction){switch(i=this.initialShapeBoundingRect,o=i.x+i.width,r=i.y+i.height,this.dragAction){case"place":this.currentShape.x=t,this.currentShape.y=e,this.didDrag=!0;break;case"move":this.currentShape.x=t-this.dragOffset.x,this.currentShape.y=e-this.dragOffset.y,this.didDrag=!0;break;case"resizeBottomRight":this.currentShape.setSize(t-(this.dragOffset.x-this.initialShapeBoundingRect.width)-i.x,e-(this.dragOffset.y-this.initialShapeBoundingRect.height)-i.y);break;case"resizeTopLeft":this.currentShape.setSize(o-t+this.dragOffset.x,r-e+this.dragOffset.y),this.currentShape.setPosition(t-this.dragOffset.x,e-this.dragOffset.y);break;case"resizeBottomLeft":this.currentShape.setSize(o-t+this.dragOffset.x,e-(this.dragOffset.y-this.initialShapeBoundingRect.height)-i.y),this.currentShape.setPosition(t-this.dragOffset.x,this.currentShape.y);break;case"resizeTopRight":this.currentShape.setSize(t-(this.dragOffset.x-this.initialShapeBoundingRect.width)-i.x,r-e+this.dragOffset.y),this.currentShape.setPosition(this.currentShape.x,e-this.dragOffset.y)}return this._setShapesInProgress(n),n.repaintLayer("main"),this._updateInputEl(n)}},e.prototype.end=function(t,e,n){return this.currentShape?(this.currentShape.setSize(this.currentShape.forcedWidth,0),"selected"===this.currentShapeState&&("place"===this.dragAction||"move"===this.dragAction&&!this.didDrag)&&this._enterEditingState(n),this._setShapesInProgress(n),n.repaintLayer("main"),this._updateInputEl(n)):void 0},e.prototype._enterEditingState=function(t){var e;if(this.currentShapeState="editing",this.inputEl)throw"State error";return this.inputEl=document.createElement("textarea"),this.inputEl.className="text-tool-input",this.inputEl.style.position="absolute",this.inputEl.style.transformOrigin="0px 0px",this.inputEl.style.backgroundColor="transparent",this.inputEl.style.border="none",this.inputEl.style.outline="none",this.inputEl.style.margin="0",this.inputEl.style.padding="4px",this.inputEl.style.zIndex="1000",this.inputEl.style.overflow="hidden",this.inputEl.style.resize="none",this.inputEl.value=this.currentShape.text,this.inputEl.addEventListener("mousedown",function(t){return t.stopPropagation()}),this.inputEl.addEventListener("touchstart",function(t){return t.stopPropagation()}),e=function(e){return function(n){return e.currentShape.setText(n.target.value),e.currentShape.enforceMaxBoundingRect(t),e._setShapesInProgress(t),t.repaintLayer("main"),e._updateInputEl(t),n.stopPropagation()}}(this),this.inputEl.addEventListener("keydown",function(e){return function(){return e._updateInputEl(t,!0)}}(this)),this.inputEl.addEventListener("keyup",e),this.inputEl.addEventListener("change",e),this._updateInputEl(t),t.containerEl.appendChild(this.inputEl),this.inputEl.focus(),this._setShapesInProgress(t)},e.prototype._exitEditingState=function(t){return this.currentShapeState="selected",t.containerEl.removeChild(this.inputEl),this.inputEl=null,this._setShapesInProgress(t),t.repaintLayer("main")},e.prototype._updateInputEl=function(t,e){var n,i;return null==e&&(e=!1),this.inputEl?(n=this.currentShape.getBoundingRect(t.ctx,!0),this.inputEl.style.font=this.currentShape.font,this.inputEl.style.color=this.currentShape.color,this.inputEl.style.left=t.position.x/t.backingScale+n.x*t.scale-4+"px",this.inputEl.style.top=t.position.y/t.backingScale+n.y*t.scale-4+"px",e&&!this.currentShape.forcedWidth?this.inputEl.style.width=n.width+10+this.currentShape.renderer.emDashWidth+"px":this.inputEl.style.width=n.width+12+"px",e?this.inputEl.style.height=n.height+10+this.currentShape.renderer.metrics.leading+"px":this.inputEl.style.height=n.height+10+"px",i="scale("+t.scale+")",this.inputEl.style.transform=i,this.inputEl.style.webkitTransform=i,this.inputEl.style.MozTransform=i,this.inputEl.style.msTransform=i,this.inputEl.style.OTransform=i):void 0},e.prototype.optionsStyle="font",e}(r)},{"../core/shapes":17,"./base":53}],53:[function(t,e,n){var i,r,o,s=function(t,e){function n(){this.constructor=t}for(var i in e)a.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},a={}.hasOwnProperty;o={},o.Tool=i=function(){function t(){}return t.prototype.name=null,t.prototype.iconName=null,t.prototype.usesSimpleAPI=!0,t.prototype.begin=function(t,e,n){},t.prototype["continue"]=function(t,e,n){},t.prototype.end=function(t,e,n){},t.prototype.optionsStyle=null,t.prototype.didBecomeActive=function(t){},t.prototype.willBecomeInactive=function(t){},t}(),o.ToolWithStroke=r=function(t){function e(t){this.strokeWidth=t.opts.defaultStrokeWidth}return s(e,t),e.prototype.optionsStyle="stroke-width",e.prototype.didBecomeActive=function(t){var e;return e=[],this.unsubscribe=function(t){return function(){var t,n,i,r;for(r=[],n=0,i=e.length;i>n;n++)t=e[n],r.push(t());return r}}(this),e.push(t.on("setStrokeWidth",function(e){return function(n){return e.strokeWidth=n,t.trigger("toolDidUpdateOptions")}}(this)))},e.prototype.willBecomeInactive=function(t){return this.unsubscribe()},e}(i),e.exports=o},{}]},{},[22])(22)}); \ No newline at end of file diff --git a/library/js/literallycanvas/js/optionsStyles/font.js b/library/js/literallycanvas/js/optionsStyles/font.js new file mode 100644 index 00000000000..0a2a9f8c99e --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/font.js @@ -0,0 +1,191 @@ +var ALL_FONTS, FONT_NAME_TO_VALUE, MONOSPACE_FONTS, OTHER_FONTS, React, SANS_SERIF_FONTS, SERIF_FONTS, _, defineOptionsStyle, i, j, l, len, len1, len2, len3, m, name, ref, ref1, ref2, ref3, value; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +_ = require('../core/localization')._; + +SANS_SERIF_FONTS = [['Arial', 'Arial,"Helvetica Neue",Helvetica,sans-serif'], ['Arial Black', '"Arial Black","Arial Bold",Gadget,sans-serif'], ['Arial Narrow', '"Arial Narrow",Arial,sans-serif'], ['Gill Sans', '"Gill Sans","Gill Sans MT",Calibri,sans-serif'], ['Helvetica', '"Helvetica Neue",Helvetica,Arial,sans-serif'], ['Impact', 'Impact,Haettenschweiler,"Franklin Gothic Bold",Charcoal,"Helvetica Inserat","Bitstream Vera Sans Bold","Arial Black",sans-serif'], ['Tahoma', 'Tahoma,Verdana,Segoe,sans-serif'], ['Trebuchet MS', '"Trebuchet MS","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Tahoma,sans-serif'], ['Verdana', 'Verdana,Geneva,sans-serif']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +SERIF_FONTS = [['Baskerville', 'Baskerville,"Baskerville Old Face","Hoefler Text",Garamond,"Times New Roman",serif'], ['Garamond', 'Garamond,Baskerville,"Baskerville Old Face","Hoefler Text","Times New Roman",serif'], ['Georgia', 'Georgia,Times,"Times New Roman",serif'], ['Hoefler Text', '"Hoefler Text","Baskerville Old Face",Garamond,"Times New Roman",serif'], ['Lucida Bright', '"Lucida Bright",Georgia,serif'], ['Palatino', 'Palatino,"Palatino Linotype","Palatino LT STD","Book Antiqua",Georgia,serif'], ['Times New Roman', 'TimesNewRoman,"Times New Roman",Times,Baskerville,Georgia,serif']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +MONOSPACE_FONTS = [['Consolas/Monaco', 'Consolas,monaco,"Lucida Console",monospace'], ['Courier New', '"Courier New",Courier,"Lucida Sans Typewriter","Lucida Typewriter",monospace'], ['Lucida Sans Typewriter', '"Lucida Sans Typewriter","Lucida Console",monaco,"Bitstream Vera Sans Mono",monospace']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +OTHER_FONTS = [['Copperplate', 'Copperplate,"Copperplate Gothic Light",fantasy'], ['Papyrus', 'Papyrus,fantasy'], ['Script', '"Brush Script MT",cursive']].map(function(arg) { + var name, value; + name = arg[0], value = arg[1]; + return { + name: _(name), + value: value + }; +}); + +ALL_FONTS = [[_('Sans Serif'), SANS_SERIF_FONTS], [_('Serif'), SERIF_FONTS], [_('Monospace'), MONOSPACE_FONTS], [_('Other'), OTHER_FONTS]]; + +FONT_NAME_TO_VALUE = {}; + +for (i = 0, len = SANS_SERIF_FONTS.length; i < len; i++) { + ref = SANS_SERIF_FONTS[i], name = ref.name, value = ref.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (j = 0, len1 = SERIF_FONTS.length; j < len1; j++) { + ref1 = SERIF_FONTS[j], name = ref1.name, value = ref1.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (l = 0, len2 = MONOSPACE_FONTS.length; l < len2; l++) { + ref2 = MONOSPACE_FONTS[l], name = ref2.name, value = ref2.value; + FONT_NAME_TO_VALUE[name] = value; +} + +for (m = 0, len3 = OTHER_FONTS.length; m < len3; m++) { + ref3 = OTHER_FONTS[m], name = ref3.name, value = ref3.value; + FONT_NAME_TO_VALUE[name] = value; +} + +defineOptionsStyle('font', React.createClass({ + displayName: 'FontOptions', + getInitialState: function() { + return { + isItalic: false, + isBold: false, + fontName: 'Helvetica', + fontSizeIndex: 4 + }; + }, + getFontSizes: function() { + return [9, 10, 12, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288]; + }, + updateTool: function(newState) { + var fontSize, items, k; + if (newState == null) { + newState = {}; + } + for (k in this.state) { + if (!(k in newState)) { + newState[k] = this.state[k]; + } + } + fontSize = this.getFontSizes()[newState.fontSizeIndex]; + items = []; + if (newState.isItalic) { + items.push('italic'); + } + if (newState.isBold) { + items.push('bold'); + } + items.push(fontSize + "px"); + items.push(FONT_NAME_TO_VALUE[newState.fontName]); + this.props.lc.tool.font = items.join(' '); + return this.props.lc.trigger('setFont', items.join(' ')); + }, + handleFontSize: function(event) { + var newState; + newState = { + fontSizeIndex: event.target.value + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleFontFamily: function(event) { + var newState; + newState = { + fontName: event.target.selectedOptions[0].innerHTML + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleItalic: function(event) { + var newState; + newState = { + isItalic: !this.state.isItalic + }; + this.setState(newState); + return this.updateTool(newState); + }, + handleBold: function(event) { + var newState; + newState = { + isBold: !this.state.isBold + }; + this.setState(newState); + return this.updateTool(newState); + }, + componentDidMount: function() { + return this.updateTool(); + }, + render: function() { + var br, div, input, label, lc, optgroup, option, ref4, select, span; + lc = this.props.lc; + ref4 = React.DOM, div = ref4.div, input = ref4.input, select = ref4.select, option = ref4.option, br = ref4.br, label = ref4.label, span = ref4.span, optgroup = ref4.optgroup; + return div({ + className: 'lc-font-settings' + }, select({ + value: this.state.fontSizeIndex, + onChange: this.handleFontSize + }, this.getFontSizes().map((function(_this) { + return function(size, ix) { + return option({ + value: ix, + key: ix + }, size + "px"); + }; + })(this))), select({ + value: this.state.fontName, + onChange: this.handleFontFamily + }, ALL_FONTS.map((function(_this) { + return function(arg) { + var fonts, label; + label = arg[0], fonts = arg[1]; + return optgroup({ + key: label, + label: label + }, fonts.map(function(family, ix) { + return option({ + value: family.name, + key: ix + }, family.name); + })); + }; + })(this))), span({}, label({ + htmlFor: 'italic' + }, _("italic")), input({ + type: 'checkbox', + id: 'italic', + checked: this.state.isItalic, + onChange: this.handleItalic + })), span({}, label({ + htmlFor: 'bold' + }, _("bold")), input({ + type: 'checkbox', + id: 'bold', + checked: this.state.isBold, + onChange: this.handleBold + }))); + } +})); + +module.exports = {}; diff --git a/library/js/literallycanvas/js/optionsStyles/line-options-and-stroke-width.js b/library/js/literallycanvas/js/optionsStyles/line-options-and-stroke-width.js new file mode 100644 index 00000000000..907547bcac5 --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/line-options-and-stroke-width.js @@ -0,0 +1,72 @@ +var React, StrokeWidthPicker, classSet, createSetStateOnEventMixin, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = React.createFactory(require('../reactGUI/StrokeWidthPicker')); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +defineOptionsStyle('line-options-and-stroke-width', React.createClass({ + displayName: 'LineOptionsAndStrokeWidth', + getState: function() { + return { + strokeWidth: this.props.tool.strokeWidth, + isDashed: this.props.tool.isDashed, + hasEndArrow: this.props.tool.hasEndArrow + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + render: function() { + var arrowButtonClass, dashButtonClass, div, img, li, ref, style, toggleIsDashed, togglehasEndArrow, ul; + ref = React.DOM, div = ref.div, ul = ref.ul, li = ref.li, img = ref.img; + toggleIsDashed = (function(_this) { + return function() { + _this.props.tool.isDashed = !_this.props.tool.isDashed; + return _this.setState(_this.getState()); + }; + })(this); + togglehasEndArrow = (function(_this) { + return function() { + _this.props.tool.hasEndArrow = !_this.props.tool.hasEndArrow; + return _this.setState(_this.getState()); + }; + })(this); + dashButtonClass = classSet({ + 'square-toolbar-button': true, + 'selected': this.state.isDashed + }); + arrowButtonClass = classSet({ + 'square-toolbar-button': true, + 'selected': this.state.hasEndArrow + }); + style = { + float: 'left', + margin: 1 + }; + return div({}, div({ + className: dashButtonClass, + onClick: toggleIsDashed, + style: style + }, img({ + src: this.props.imageURLPrefix + "/dashed-line.png" + })), div({ + className: arrowButtonClass, + onClick: togglehasEndArrow, + style: style + }, img({ + src: this.props.imageURLPrefix + "/line-with-arrow.png" + })), StrokeWidthPicker({ + tool: this.props.tool, + lc: this.props.lc + })); + } +})); + +module.exports = {}; diff --git a/library/js/literallycanvas/js/optionsStyles/null.js b/library/js/literallycanvas/js/optionsStyles/null.js new file mode 100644 index 00000000000..74efbd76ac4 --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/null.js @@ -0,0 +1,14 @@ +var React, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +defineOptionsStyle('null', React.createClass({ + displayName: 'NoOptions', + render: function() { + return React.DOM.div(); + } +})); + +module.exports = {}; diff --git a/library/js/literallycanvas/js/optionsStyles/optionsStyles.js b/library/js/literallycanvas/js/optionsStyles/optionsStyles.js new file mode 100644 index 00000000000..3c22639a6ee --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/optionsStyles.js @@ -0,0 +1,14 @@ +var React, defineOptionsStyle, optionsStyles; + +React = require('../reactGUI/React-shim'); + +optionsStyles = {}; + +defineOptionsStyle = function(name, style) { + return optionsStyles[name] = React.createFactory(style); +}; + +module.exports = { + optionsStyles: optionsStyles, + defineOptionsStyle: defineOptionsStyle +}; diff --git a/library/js/literallycanvas/js/optionsStyles/polygon-and-stroke-width.js b/library/js/literallycanvas/js/optionsStyles/polygon-and-stroke-width.js new file mode 100644 index 00000000000..b54995186d5 --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/polygon-and-stroke-width.js @@ -0,0 +1,109 @@ +var React, StrokeWidthPicker, createSetStateOnEventMixin, defineOptionsStyle; + +React = require('../reactGUI/React-shim'); + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = React.createFactory(require('../reactGUI/StrokeWidthPicker')); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +defineOptionsStyle('polygon-and-stroke-width', React.createClass({ + displayName: 'PolygonAndStrokeWidth', + getState: function() { + return { + strokeWidth: this.props.tool.strokeWidth, + inProgress: false + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + componentDidMount: function() { + var hidePolygonTools, showPolygonTools, unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + showPolygonTools = (function(_this) { + return function() { + if (!_this.state.inProgress) { + return _this.setState({ + inProgress: true + }); + } + }; + })(this); + hidePolygonTools = (function(_this) { + return function() { + return _this.setState({ + inProgress: false + }); + }; + })(this); + unsubscribeFuncs.push(this.props.lc.on('lc-polygon-started', showPolygonTools)); + return unsubscribeFuncs.push(this.props.lc.on('lc-polygon-stopped', hidePolygonTools)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + }, + render: function() { + var div, img, lc, polygonCancel, polygonFinishClosed, polygonFinishOpen, polygonToolStyle, ref; + lc = this.props.lc; + ref = React.DOM, div = ref.div, img = ref.img; + polygonFinishOpen = (function(_this) { + return function() { + return lc.trigger('lc-polygon-finishopen'); + }; + })(this); + polygonFinishClosed = (function(_this) { + return function() { + return lc.trigger('lc-polygon-finishclosed'); + }; + })(this); + polygonCancel = (function(_this) { + return function() { + return lc.trigger('lc-polygon-cancel'); + }; + })(this); + polygonToolStyle = {}; + if (!this.state.inProgress) { + polygonToolStyle = { + display: 'none' + }; + } + return div({}, div({ + className: 'polygon-toolbar horz-toolbar', + style: polygonToolStyle + }, div({ + className: 'square-toolbar-button', + onClick: polygonFinishOpen + }, img({ + src: this.props.imageURLPrefix + "/polygon-open.png" + })), div({ + className: 'square-toolbar-button', + onClick: polygonFinishClosed + }, img({ + src: this.props.imageURLPrefix + "/polygon-closed.png" + })), div({ + className: 'square-toolbar-button', + onClick: polygonCancel + }, img({ + src: this.props.imageURLPrefix + "/polygon-cancel.png" + }))), div({}, StrokeWidthPicker({ + tool: this.props.tool, + lc: this.props.lc + }))); + } +})); + +module.exports = {}; diff --git a/library/js/literallycanvas/js/optionsStyles/stroke-or-fill.js b/library/js/literallycanvas/js/optionsStyles/stroke-or-fill.js new file mode 100644 index 00000000000..c6d857887b1 --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/stroke-or-fill.js @@ -0,0 +1,69 @@ +'use strict'; + +var React = require('../reactGUI/React-shim'); + +var _require = require('./optionsStyles'); + +var defineOptionsStyle = _require.defineOptionsStyle; + +var createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +defineOptionsStyle('stroke-or-fill', React.createClass({ + displayName: 'StrokeOrFillPicker', + getState: function getState() { + return { strokeOrFill: 'stroke' }; + }, + getInitialState: function getInitialState() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + + onChange: function onChange(e) { + if (e.target.id == 'stroke-or-fill-stroke') { + this.props.lc.tool.strokeOrFill = 'stroke'; + } else { + this.props.lc.tool.strokeOrFill = 'fill'; + } + this.setState(this.getState()); + }, + + render: function render() { + var lc = this.props.lc; + + return React.createElement( + 'form', + null, + React.createElement( + 'span', + null, + 'Color to change: ' + ), + React.createElement( + 'span', + null, + React.createElement('input', { type: 'radio', name: 'stroke-or-fill', value: 'stroke', + id: 'stroke-or-fill-stroke', onChange: this.onChange, + checked: lc.tool.strokeOrFill == 'stroke' }), + React.createElement( + 'label', + { htmlFor: 'stroke-or-fill-stroke', className: 'label' }, + ' stroke' + ) + ), + React.createElement( + 'span', + null, + React.createElement('input', { type: 'radio', name: 'stroke-or-fill', value: 'fill', + id: 'stroke-or-fill-fill', onChange: this.onChange, + checked: lc.tool.strokeOrFill == 'fill' }), + React.createElement( + 'label', + { htmlFor: 'stroke-or-fill-fill', className: 'label' }, + ' fill' + ) + ) + ); + } +})); + +module.exports = {}; \ No newline at end of file diff --git a/library/js/literallycanvas/js/optionsStyles/stroke-width.js b/library/js/literallycanvas/js/optionsStyles/stroke-width.js new file mode 100644 index 00000000000..be5987de71b --- /dev/null +++ b/library/js/literallycanvas/js/optionsStyles/stroke-width.js @@ -0,0 +1,9 @@ +var StrokeWidthPicker, defineOptionsStyle; + +defineOptionsStyle = require('./optionsStyles').defineOptionsStyle; + +StrokeWidthPicker = require('../reactGUI/StrokeWidthPicker'); + +defineOptionsStyle('stroke-width', StrokeWidthPicker); + +module.exports = {}; diff --git a/library/js/literallycanvas/js/reactGUI/ClearButton.js b/library/js/literallycanvas/js/reactGUI/ClearButton.js new file mode 100644 index 00000000000..421d7600da2 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/ClearButton.js @@ -0,0 +1,44 @@ +var ClearButton, React, _, classSet, createSetStateOnEventMixin; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +_ = require('../core/localization')._; + +classSet = require('../core/util').classSet; + +ClearButton = React.createClass({ + displayName: 'ClearButton', + getState: function() { + return { + isEnabled: this.props.lc.canUndo() + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('drawingChange')], + render: function() { + var className, div, lc, onClick; + div = React.DOM.div; + lc = this.props.lc; + className = classSet({ + 'lc-clear': true, + 'toolbar-button': true, + 'fat-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = lc.canUndo() ? ((function(_this) { + return function() { + return lc.clear(); + }; + })(this)) : function() {}; + return div({ + className: className, + onClick: onClick + }, _('Clear')); + } +}); + +module.exports = ClearButton; diff --git a/library/js/literallycanvas/js/reactGUI/ColorWell.js b/library/js/literallycanvas/js/reactGUI/ColorWell.js new file mode 100644 index 00000000000..0dd76a7a04d --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/ColorWell.js @@ -0,0 +1,364 @@ +var ColorGrid, ColorWell, PureRenderMixin, React, cancelAnimationFrame, classSet, getHSLAString, getHSLString, parseHSLAString, ref, requestAnimationFrame; + +React = require('./React-shim'); + +PureRenderMixin = require('react-addons-pure-render-mixin'); + +ref = require('../core/util'), classSet = ref.classSet, requestAnimationFrame = ref.requestAnimationFrame, cancelAnimationFrame = ref.cancelAnimationFrame; + +parseHSLAString = function(s) { + var components, firstParen, insideParens, lastParen; + if (s === 'transparent') { + return { + hue: 0, + sat: 0, + light: 0, + alpha: 0 + }; + } + if (s.substring(0, 4) !== 'hsla') { + return null; + } + firstParen = s.indexOf('('); + lastParen = s.indexOf(')'); + insideParens = s.substring(firstParen + 1, lastParen - firstParen + 4); + components = (function() { + var j, len, ref1, results; + ref1 = insideParens.split(','); + results = []; + for (j = 0, len = ref1.length; j < len; j++) { + s = ref1[j]; + results.push(s.trim()); + } + return results; + })(); + return { + hue: parseInt(components[0], 10), + sat: parseInt(components[1].substring(0, components[1].length - 1), 10), + light: parseInt(components[2].substring(0, components[2].length - 1), 10), + alpha: parseFloat(components[3]) + }; +}; + +getHSLAString = function(arg) { + var alpha, hue, light, sat; + hue = arg.hue, sat = arg.sat, light = arg.light, alpha = arg.alpha; + return "hsla(" + hue + ", " + sat + "%, " + light + "%, " + alpha + ")"; +}; + +getHSLString = function(arg) { + var hue, light, sat; + hue = arg.hue, sat = arg.sat, light = arg.light; + return "hsl(" + hue + ", " + sat + "%, " + light + "%)"; +}; + +ColorGrid = React.createFactory(React.createClass({ + displayName: 'ColorGrid', + mixins: [PureRenderMixin], + render: function() { + var div; + div = React.DOM.div; + return div({}, this.props.rows.map((function(_this) { + return function(row, ix) { + return div({ + className: 'color-row', + key: ix, + style: { + width: 20 * row.length + } + }, row.map(function(cellColor, ix2) { + var alpha, className, colorString, colorStringNoAlpha, hue, light, sat, update; + hue = cellColor.hue, sat = cellColor.sat, light = cellColor.light, alpha = cellColor.alpha; + colorString = getHSLAString(cellColor); + colorStringNoAlpha = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; + className = classSet({ + 'color-cell': true, + 'selected': _this.props.selectedColor === colorString + }); + update = function(e) { + _this.props.onChange(cellColor, colorString); + e.stopPropagation(); + return e.preventDefault(); + }; + return div({ + className: className, + onTouchStart: update, + onTouchMove: update, + onClick: update, + style: { + backgroundColor: colorStringNoAlpha + }, + key: ix2 + }); + })); + }; + })(this))); + } +})); + +ColorWell = React.createClass({ + displayName: 'ColorWell', + mixins: [PureRenderMixin], + getInitialState: function() { + var colorString, hsla; + colorString = this.props.lc.colors[this.props.colorName]; + hsla = parseHSLAString(colorString); + if (hsla == null) { + hsla = {}; + } + if (hsla.alpha == null) { + hsla.alpha = 1; + } + if (hsla.sat == null) { + hsla.sat = 100; + } + if (hsla.hue == null) { + hsla.hue = 0; + } + if (hsla.light == null) { + hsla.light = 50; + } + return { + colorString: colorString, + alpha: hsla.alpha, + sat: hsla.sat === 0 ? 100 : hsla.sat, + isPickerVisible: false, + hsla: hsla + }; + }, + componentDidMount: function() { + return this.unsubscribe = this.props.lc.on(this.props.colorName + "ColorChange", (function(_this) { + return function() { + var colorString; + colorString = _this.props.lc.colors[_this.props.colorName]; + _this.setState({ + colorString: colorString + }); + return _this.setHSLAFromColorString(colorString); + }; + })(this)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + }, + setHSLAFromColorString: function(c) { + var hsla; + hsla = parseHSLAString(c); + if (hsla) { + return this.setState({ + hsla: hsla, + alpha: hsla.alpha, + sat: hsla.sat + }); + } else { + return this.setState({ + hsla: null, + alpha: 1, + sat: 100 + }); + } + }, + closePicker: function() { + return this.setState({ + isPickerVisible: false + }); + }, + togglePicker: function() { + var isPickerVisible, shouldResetSat; + isPickerVisible = !this.state.isPickerVisible; + shouldResetSat = isPickerVisible && this.state.sat === 0; + this.setHSLAFromColorString(this.state.colorString); + return this.setState({ + isPickerVisible: isPickerVisible, + sat: shouldResetSat ? 100 : this.state.sat + }); + }, + setColor: function(c) { + this.setState({ + colorString: c + }); + this.setHSLAFromColorString(c); + return this.props.lc.setColor(this.props.colorName, c); + }, + setAlpha: function(alpha) { + var hsla; + this.setState({ + alpha: alpha + }); + if (this.state.hsla) { + hsla = this.state.hsla; + hsla.alpha = alpha; + this.setState({ + hsla: hsla + }); + return this.setColor(getHSLAString(hsla)); + } + }, + setSat: function(sat) { + var hsla; + this.setState({ + sat: sat + }); + if (isNaN(sat)) { + throw "SAT"; + } + if (this.state.hsla) { + hsla = this.state.hsla; + hsla.sat = sat; + this.setState({ + hsla: hsla + }); + return this.setColor(getHSLAString(hsla)); + } + }, + render: function() { + var br, div, label, ref1; + ref1 = React.DOM, div = ref1.div, label = ref1.label, br = ref1.br; + return div({ + className: classSet({ + 'color-well': true, + 'open': this.state.isPickerVisible + }), + onMouseLeave: this.closePicker, + style: { + float: 'left', + textAlign: 'center' + } + }, label({ + float: 'left' + }, this.props.label), br({}), div({ + className: classSet({ + 'color-well-color-container': true, + 'selected': this.state.isPickerVisible + }), + style: { + backgroundColor: 'white' + }, + onClick: this.togglePicker + }, div({ + className: 'color-well-checker color-well-checker-top-left' + }), div({ + className: 'color-well-checker color-well-checker-bottom-right', + style: { + left: '50%', + top: '50%' + } + }), div({ + className: 'color-well-color', + style: { + backgroundColor: this.state.colorString + } + }, " ")), this.renderPicker()); + }, + renderPicker: function() { + var div, hue, i, input, j, label, len, onSelectColor, ref1, ref2, renderColor, renderLabel, rows; + ref1 = React.DOM, div = ref1.div, label = ref1.label, input = ref1.input; + if (!this.state.isPickerVisible) { + return null; + } + renderLabel = (function(_this) { + return function(text) { + return div({ + className: 'color-row label', + key: text, + style: { + lineHeight: '20px', + height: 16 + } + }, text); + }; + })(this); + renderColor = (function(_this) { + return function() { + var checkerboardURL; + checkerboardURL = _this.props.lc.opts.imageURLPrefix + "/checkerboard-8x8.png"; + return div({ + className: 'color-row', + key: "color", + style: { + position: 'relative', + backgroundImage: "url(" + checkerboardURL + ")", + backgroundRepeat: 'repeat', + height: 24 + } + }, div({ + style: { + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + backgroundColor: _this.state.colorString + } + })); + }; + })(this); + rows = []; + rows.push((function() { + var j, results; + results = []; + for (i = j = 0; j <= 100; i = j += 10) { + results.push({ + hue: 0, + sat: 0, + light: i, + alpha: this.state.alpha + }); + } + return results; + }).call(this)); + ref2 = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]; + for (j = 0, len = ref2.length; j < len; j++) { + hue = ref2[j]; + rows.push((function() { + var k, results; + results = []; + for (i = k = 10; k <= 90; i = k += 8) { + results.push({ + hue: hue, + sat: this.state.sat, + light: i, + alpha: this.state.alpha + }); + } + return results; + }).call(this)); + } + onSelectColor = (function(_this) { + return function(hsla, s) { + return _this.setColor(s); + }; + })(this); + return div({ + className: 'color-picker-popup' + }, renderColor(), renderLabel("alpha"), input({ + type: 'range', + min: 0, + max: 1, + step: 0.01, + value: this.state.alpha, + onChange: (function(_this) { + return function(e) { + return _this.setAlpha(parseFloat(e.target.value)); + }; + })(this) + }), renderLabel("saturation"), input({ + type: 'range', + min: 0, + max: 100, + value: this.state.sat, + max: 100, + onChange: (function(_this) { + return function(e) { + return _this.setSat(parseInt(e.target.value, 10)); + }; + })(this) + }), ColorGrid({ + rows: rows, + selectedColor: this.state.colorString, + onChange: onSelectColor + })); + } +}); + +module.exports = ColorWell; diff --git a/library/js/literallycanvas/js/reactGUI/LiterallyCanvas.js b/library/js/literallycanvas/js/reactGUI/LiterallyCanvas.js new file mode 100644 index 00000000000..847bd04fa0a --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/LiterallyCanvas.js @@ -0,0 +1,104 @@ +'use strict'; + +var React = require('../reactGUI/React-shim'); + +var _require = require('../reactGUI/ReactDOM-shim'); + +var findDOMNode = _require.findDOMNode; + +var _require2 = require('../core/util'); + +var classSet = _require2.classSet; + +var Picker = require('./Picker'); +var Options = require('./Options'); +var createToolButton = require('./createToolButton'); +var LiterallyCanvasModel = require('../core/LiterallyCanvas'); +var defaultOptions = require('../core/defaultOptions'); + +require('../optionsStyles/font'); +require('../optionsStyles/stroke-width'); +require('../optionsStyles/line-options-and-stroke-width'); +require('../optionsStyles/polygon-and-stroke-width'); +require('../optionsStyles/null'); + +var CanvasContainer = React.createClass({ + displayName: 'CanvasContainer', + shouldComponentUpdate: function shouldComponentUpdate() { + // Avoid React trying to control this DOM + return false; + }, + render: function render() { + return React.createElement('div', { key: 'literallycanvas', className: 'lc-drawing with-gui' }); + } +}); + +var LiterallyCanvas = React.createClass({ + displayName: 'LiterallyCanvas', + + getDefaultProps: function getDefaultProps() { + return defaultOptions; + }, + bindToModel: function bindToModel() { + var canvasContainerEl = findDOMNode(this.canvas); + var opts = this.props; + this.lc.bindToElement(canvasContainerEl); + + if (typeof opts.onInit === 'function') { + opts.onInit(this.lc); + } + }, + componentWillMount: function componentWillMount() { + var _this = this; + + if (this.lc) return; + + if (this.props.lc) { + this.lc = this.props.lc; + } else { + this.lc = new LiterallyCanvasModel(this.props); + } + + this.toolButtonComponents = this.lc.opts.tools.map(function (ToolClass) { + return createToolButton(new ToolClass(_this.lc)); + }); + }, + componentDidMount: function componentDidMount() { + if (!this.lc.isBound) { + this.bindToModel(); + } + }, + componentWillUnmount: function componentWillUnmount() { + if (this.lc) { + this.lc._teardown(); + } + }, + render: function render() { + var _this2 = this; + + var lc = this.lc; + var toolButtonComponents = this.toolButtonComponents; + var props = this.props; + var _lc$opts = this.lc.opts; + var imageURLPrefix = _lc$opts.imageURLPrefix; + var toolbarPosition = _lc$opts.toolbarPosition; + + var pickerProps = { lc: lc, toolButtonComponents: toolButtonComponents, imageURLPrefix: imageURLPrefix }; + var topOrBottomClassName = classSet({ + 'toolbar-at-top': toolbarPosition === 'top', + 'toolbar-at-bottom': toolbarPosition === 'bottom', + 'toolbar-hidden': toolbarPosition === 'hidden' + }); + return React.createElement( + 'div', + { className: 'literally ' + topOrBottomClassName }, + React.createElement(CanvasContainer, { ref: function ref(item) { + return _this2.canvas = item; + } }), + React.createElement(Picker, pickerProps), + React.createElement(Options, { lc: lc, imageURLPrefix: imageURLPrefix }) + ); + } +}); + +module.exports = LiterallyCanvas; \ No newline at end of file diff --git a/library/js/literallycanvas/js/reactGUI/Options.js b/library/js/literallycanvas/js/reactGUI/Options.js new file mode 100644 index 00000000000..be1129c8d95 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/Options.js @@ -0,0 +1,40 @@ +var Options, React, createSetStateOnEventMixin, optionsStyles; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +optionsStyles = require('../optionsStyles/optionsStyles').optionsStyles; + +Options = React.createClass({ + displayName: 'Options', + getState: function() { + var ref; + return { + style: (ref = this.props.lc.tool) != null ? ref.optionsStyle : void 0, + tool: this.props.lc.tool + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolChange')], + renderBody: function() { + var style; + style = "" + this.state.style; + return optionsStyles[style] && optionsStyles[style]({ + lc: this.props.lc, + tool: this.state.tool, + imageURLPrefix: this.props.imageURLPrefix + }); + }, + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-options horz-toolbar' + }, this.renderBody()); + } +}); + +module.exports = Options; diff --git a/library/js/literallycanvas/js/reactGUI/Picker.js b/library/js/literallycanvas/js/reactGUI/Picker.js new file mode 100644 index 00000000000..d6765c38484 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/Picker.js @@ -0,0 +1,97 @@ +var ClearButton, ColorPickers, ColorWell, Picker, React, UndoRedoButtons, ZoomButtons, _; + +React = require('./React-shim'); + +ClearButton = React.createFactory(require('./ClearButton')); + +UndoRedoButtons = React.createFactory(require('./UndoRedoButtons')); + +ZoomButtons = React.createFactory(require('./ZoomButtons')); + +_ = require('../core/localization')._; + +ColorWell = React.createFactory(require('./ColorWell')); + +ColorPickers = React.createFactory(React.createClass({ + displayName: 'ColorPickers', + render: function() { + var div, lc; + lc = this.props.lc; + div = React.DOM.div; + return div({ + className: 'lc-color-pickers' + }, ColorWell({ + lc: lc, + colorName: 'primary', + label: _('stroke') + }), ColorWell({ + lc: lc, + colorName: 'secondary', + label: _('fill') + }), ColorWell({ + lc: lc, + colorName: 'background', + label: _('bg') + })); + } +})); + +Picker = React.createClass({ + displayName: 'Picker', + getInitialState: function() { + return { + selectedToolIndex: 0 + }; + }, + renderBody: function() { + var div, imageURLPrefix, lc, ref, toolButtonComponents; + div = React.DOM.div; + ref = this.props, toolButtonComponents = ref.toolButtonComponents, lc = ref.lc, imageURLPrefix = ref.imageURLPrefix; + return div({ + className: 'lc-picker-contents' + }, toolButtonComponents.map((function(_this) { + return function(component, ix) { + return component({ + lc: lc, + imageURLPrefix: imageURLPrefix, + key: ix, + isSelected: ix === _this.state.selectedToolIndex, + onSelect: function(tool) { + lc.setTool(tool); + return _this.setState({ + selectedToolIndex: ix + }); + } + }); + }; + })(this)), toolButtonComponents.length % 2 !== 0 ? div({ + className: 'toolbar-button thin-button disabled' + }) : void 0, div({ + style: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0 + } + }, ColorPickers({ + lc: this.props.lc + }), UndoRedoButtons({ + lc: lc, + imageURLPrefix: imageURLPrefix + }), ZoomButtons({ + lc: lc, + imageURLPrefix: imageURLPrefix + }), ClearButton({ + lc: lc + }))); + }, + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-picker' + }, this.renderBody()); + } +}); + +module.exports = Picker; diff --git a/library/js/literallycanvas/js/reactGUI/React-shim.js b/library/js/literallycanvas/js/reactGUI/React-shim.js new file mode 100644 index 00000000000..c41f8098cfc --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/React-shim.js @@ -0,0 +1,13 @@ +var React, error; + +try { + React = require('react'); +} catch (error) { + React = window.React; +} + +if (React == null) { + throw "Can't find React"; +} + +module.exports = React; diff --git a/library/js/literallycanvas/js/reactGUI/ReactDOM-shim.js b/library/js/literallycanvas/js/reactGUI/ReactDOM-shim.js new file mode 100644 index 00000000000..432ef231766 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/ReactDOM-shim.js @@ -0,0 +1,21 @@ +var ReactDOM, error, error1; + +try { + ReactDOM = require('react-dom'); +} catch (error) { + ReactDOM = window.ReactDOM; +} + +if (ReactDOM == null) { + try { + ReactDOM = require('react'); + } catch (error1) { + ReactDOM = window.React; + } +} + +if (ReactDOM == null) { + throw "Can't find ReactDOM"; +} + +module.exports = ReactDOM; diff --git a/library/js/literallycanvas/js/reactGUI/StrokeWidthPicker.js b/library/js/literallycanvas/js/reactGUI/StrokeWidthPicker.js new file mode 100644 index 00000000000..f6cbb23b6db --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/StrokeWidthPicker.js @@ -0,0 +1,59 @@ +var React, classSet, createSetStateOnEventMixin; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('../reactGUI/createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +module.exports = React.createClass({ + displayName: 'StrokeWidthPicker', + getState: function(tool) { + if (tool == null) { + tool = this.props.tool; + } + return { + strokeWidth: tool.strokeWidth + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('toolDidUpdateOptions')], + componentWillReceiveProps: function(props) { + return this.setState(this.getState(props.tool)); + }, + render: function() { + var circle, div, li, ref, strokeWidths, svg, ul; + ref = React.DOM, ul = ref.ul, li = ref.li, svg = ref.svg, circle = ref.circle, div = ref.div; + strokeWidths = this.props.lc.opts.strokeWidths; + return div({}, strokeWidths.map((function(_this) { + return function(strokeWidth, ix) { + var buttonClassName, buttonSize; + buttonClassName = classSet({ + 'square-toolbar-button': true, + 'selected': strokeWidth === _this.state.strokeWidth + }); + buttonSize = 28; + return div({ + key: strokeWidth + }, div({ + className: buttonClassName, + onClick: function() { + return _this.props.lc.trigger('setStrokeWidth', strokeWidth); + } + }, svg({ + width: buttonSize - 2, + height: buttonSize - 2, + viewPort: "0 0 " + strokeWidth + " " + strokeWidth, + version: "1.1", + xmlns: "http://www.w3.org/2000/svg" + }, circle({ + cx: Math.ceil(buttonSize / 2 - 1), + cy: Math.ceil(buttonSize / 2 - 1), + r: strokeWidth / 2 + })))); + }; + })(this))); + } +}); diff --git a/library/js/literallycanvas/js/reactGUI/UndoRedoButtons.js b/library/js/literallycanvas/js/reactGUI/UndoRedoButtons.js new file mode 100644 index 00000000000..8ab0970fe15 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/UndoRedoButtons.js @@ -0,0 +1,81 @@ +var React, RedoButton, UndoButton, UndoRedoButtons, classSet, createSetStateOnEventMixin, createUndoRedoButtonComponent; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +createUndoRedoButtonComponent = function(undoOrRedo) { + return React.createClass({ + displayName: undoOrRedo === 'undo' ? 'UndoButton' : 'RedoButton', + getState: function() { + return { + isEnabled: (function() { + switch (false) { + case undoOrRedo !== 'undo': + return this.props.lc.canUndo(); + case undoOrRedo !== 'redo': + return this.props.lc.canRedo(); + } + }).call(this) + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('drawingChange')], + render: function() { + var className, div, imageURLPrefix, img, lc, onClick, ref, ref1, src, style, title; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, lc = ref1.lc, imageURLPrefix = ref1.imageURLPrefix; + title = undoOrRedo === 'undo' ? 'Undo' : 'Redo'; + className = ("lc-" + undoOrRedo + " ") + classSet({ + 'toolbar-button': true, + 'thin-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = (function() { + switch (false) { + case !!this.state.isEnabled: + return function() {}; + case undoOrRedo !== 'undo': + return function() { + return lc.undo(); + }; + case undoOrRedo !== 'redo': + return function() { + return lc.redo(); + }; + } + }).call(this); + src = imageURLPrefix + "/" + undoOrRedo + ".png"; + style = { + backgroundImage: "url(" + src + ")" + }; + return div({ + className: className, + onClick: onClick, + title: title, + style: style + }); + } + }); +}; + +UndoButton = React.createFactory(createUndoRedoButtonComponent('undo')); + +RedoButton = React.createFactory(createUndoRedoButtonComponent('redo')); + +UndoRedoButtons = React.createClass({ + displayName: 'UndoRedoButtons', + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-undo-redo' + }, UndoButton(this.props), RedoButton(this.props)); + } +}); + +module.exports = UndoRedoButtons; diff --git a/library/js/literallycanvas/js/reactGUI/ZoomButtons.js b/library/js/literallycanvas/js/reactGUI/ZoomButtons.js new file mode 100644 index 00000000000..ca6ac663764 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/ZoomButtons.js @@ -0,0 +1,81 @@ +var React, ZoomButtons, ZoomInButton, ZoomOutButton, classSet, createSetStateOnEventMixin, createZoomButtonComponent; + +React = require('./React-shim'); + +createSetStateOnEventMixin = require('./createSetStateOnEventMixin'); + +classSet = require('../core/util').classSet; + +createZoomButtonComponent = function(inOrOut) { + return React.createClass({ + displayName: inOrOut === 'in' ? 'ZoomInButton' : 'ZoomOutButton', + getState: function() { + return { + isEnabled: (function() { + switch (false) { + case inOrOut !== 'in': + return this.props.lc.scale < this.props.lc.config.zoomMax; + case inOrOut !== 'out': + return this.props.lc.scale > this.props.lc.config.zoomMin; + } + }).call(this) + }; + }, + getInitialState: function() { + return this.getState(); + }, + mixins: [createSetStateOnEventMixin('zoom')], + render: function() { + var className, div, imageURLPrefix, img, lc, onClick, ref, ref1, src, style, title; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, lc = ref1.lc, imageURLPrefix = ref1.imageURLPrefix; + title = inOrOut === 'in' ? 'Zoom in' : 'Zoom out'; + className = ("lc-zoom-" + inOrOut + " ") + classSet({ + 'toolbar-button': true, + 'thin-button': true, + 'disabled': !this.state.isEnabled + }); + onClick = (function() { + switch (false) { + case !!this.state.isEnabled: + return function() {}; + case inOrOut !== 'in': + return function() { + return lc.zoom(lc.config.zoomStep); + }; + case inOrOut !== 'out': + return function() { + return lc.zoom(-lc.config.zoomStep); + }; + } + }).call(this); + src = imageURLPrefix + "/zoom-" + inOrOut + ".png"; + style = { + backgroundImage: "url(" + src + ")" + }; + return div({ + className: className, + onClick: onClick, + title: title, + style: style + }); + } + }); +}; + +ZoomOutButton = React.createFactory(createZoomButtonComponent('out')); + +ZoomInButton = React.createFactory(createZoomButtonComponent('in')); + +ZoomButtons = React.createClass({ + displayName: 'ZoomButtons', + render: function() { + var div; + div = React.DOM.div; + return div({ + className: 'lc-zoom' + }, ZoomOutButton(this.props), ZoomInButton(this.props)); + } +}); + +module.exports = ZoomButtons; diff --git a/library/js/literallycanvas/js/reactGUI/createSetStateOnEventMixin.js b/library/js/literallycanvas/js/reactGUI/createSetStateOnEventMixin.js new file mode 100644 index 00000000000..e4c603d80c9 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/createSetStateOnEventMixin.js @@ -0,0 +1,18 @@ +var React, createSetStateOnEventMixin; + +React = require('./React-shim'); + +module.exports = createSetStateOnEventMixin = function(eventName) { + return { + componentDidMount: function() { + return this.unsubscribe = this.props.lc.on(eventName, (function(_this) { + return function() { + return _this.setState(_this.getState()); + }; + })(this)); + }, + componentWillUnmount: function() { + return this.unsubscribe(); + } + }; +}; diff --git a/library/js/literallycanvas/js/reactGUI/createToolButton.js b/library/js/literallycanvas/js/reactGUI/createToolButton.js new file mode 100644 index 00000000000..04d34795d39 --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/createToolButton.js @@ -0,0 +1,49 @@ +var React, classSet, createToolButton; + +React = require('./React-shim'); + +classSet = require('../core/util').classSet; + +createToolButton = function(tool) { + var displayName, imageName; + displayName = tool.name; + imageName = tool.iconName; + return React.createFactory(React.createClass({ + displayName: displayName, + getDefaultProps: function() { + return { + isSelected: false, + lc: null + }; + }, + componentWillMount: function() { + if (this.props.isSelected) { + return this.props.lc.setTool(tool); + } + }, + render: function() { + var className, div, imageURLPrefix, img, isSelected, onSelect, ref, ref1, src; + ref = React.DOM, div = ref.div, img = ref.img; + ref1 = this.props, imageURLPrefix = ref1.imageURLPrefix, isSelected = ref1.isSelected, onSelect = ref1.onSelect; + className = classSet({ + 'lc-pick-tool': true, + 'toolbar-button': true, + 'thin-button': true, + 'selected': isSelected + }); + src = imageURLPrefix + "/" + imageName + ".png"; + return div({ + className: className, + style: { + 'backgroundImage': "url(" + src + ")" + }, + onClick: (function() { + return onSelect(tool); + }), + title: displayName + }); + } + })); +}; + +module.exports = createToolButton; diff --git a/library/js/literallycanvas/js/reactGUI/init.js b/library/js/literallycanvas/js/reactGUI/init.js new file mode 100644 index 00000000000..680117611db --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/init.js @@ -0,0 +1,36 @@ +// Generated by CoffeeScript 1.10.0 +var Options, Picker, React, createToolButton, init; + +React = require('./React-shim'); + +createToolButton = require('./createToolButton'); + +Options = React.createFactory(require('./Options')); + +Picker = React.createFactory(require('./Picker')); + +init = function(pickerElement, optionsElement, lc, tools, imageURLPrefix) { + var toolButtonComponents; + toolButtonComponents = tools.map(function(ToolClass) { + var toolInstance; + toolInstance = new ToolClass(lc); + return createToolButton({ + displayName: toolInstance.name, + imageName: toolInstance.iconName, + getTool: function() { + return toolInstance; + } + }); + }); + React.render(Picker({ + lc: lc, + toolButtonComponents: toolButtonComponents, + imageURLPrefix: imageURLPrefix + }), pickerElement); + return React.render(Options({ + lc: lc, + imageURLPrefix: imageURLPrefix + }), optionsElement); +}; + +module.exports = init; diff --git a/library/js/literallycanvas/js/reactGUI/initDOM.js b/library/js/literallycanvas/js/reactGUI/initDOM.js new file mode 100644 index 00000000000..abdc0b61d3c --- /dev/null +++ b/library/js/literallycanvas/js/reactGUI/initDOM.js @@ -0,0 +1,22 @@ +'use strict'; + +var React = require('./React-shim'); +var ReactDOM = require('./ReactDOM-shim'); +var LiterallyCanvasModel = require('../core/LiterallyCanvas'); +var LiterallyCanvasReactComponent = require('./LiterallyCanvas'); + +function init(el, opts) { + var originalClassName = el.className; + var lc = new LiterallyCanvasModel(opts); + ReactDOM.render(React.createElement(LiterallyCanvasReactComponent, { lc: lc }), el); + lc.teardown = function () { + lc._teardown(); + for (var i = 0; i < el.children.length; i++) { + el.removeChild(el.children[i]); + } + el.className = originalClassName; + }; + return lc; +} + +module.exports = init; \ No newline at end of file diff --git a/library/js/literallycanvas/js/tools/Ellipse.js b/library/js/literallycanvas/js/tools/Ellipse.js new file mode 100644 index 00000000000..1bdd17e2fdf --- /dev/null +++ b/library/js/literallycanvas/js/tools/Ellipse.js @@ -0,0 +1,42 @@ +var Ellipse, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Ellipse = (function(superClass) { + extend(Ellipse, superClass); + + function Ellipse() { + return Ellipse.__super__.constructor.apply(this, arguments); + } + + Ellipse.prototype.name = 'Ellipse'; + + Ellipse.prototype.iconName = 'ellipse'; + + Ellipse.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Ellipse', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Ellipse.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Ellipse.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Ellipse; + +})(ToolWithStroke); diff --git a/library/js/literallycanvas/js/tools/Eraser.js b/library/js/literallycanvas/js/tools/Eraser.js new file mode 100644 index 00000000000..071347eb561 --- /dev/null +++ b/library/js/literallycanvas/js/tools/Eraser.js @@ -0,0 +1,35 @@ +var Eraser, Pencil, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Pencil = require('./Pencil'); + +createShape = require('../core/shapes').createShape; + +module.exports = Eraser = (function(superClass) { + extend(Eraser, superClass); + + function Eraser() { + return Eraser.__super__.constructor.apply(this, arguments); + } + + Eraser.prototype.name = 'Eraser'; + + Eraser.prototype.iconName = 'eraser'; + + Eraser.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: '#000' + }); + }; + + Eraser.prototype.makeShape = function() { + return createShape('ErasedLinePath'); + }; + + return Eraser; + +})(Pencil); diff --git a/library/js/literallycanvas/js/tools/Eyedropper.js b/library/js/literallycanvas/js/tools/Eyedropper.js new file mode 100644 index 00000000000..d23a71e3aac --- /dev/null +++ b/library/js/literallycanvas/js/tools/Eyedropper.js @@ -0,0 +1,58 @@ +var Eyedropper, Tool, getPixel, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +getPixel = function(ctx, arg) { + var pixel, x, y; + x = arg.x, y = arg.y; + pixel = ctx.getImageData(x, y, 1, 1).data; + if (pixel[3]) { + return "rgb(" + pixel[0] + ", " + pixel[1] + ", " + pixel[2] + ")"; + } else { + return null; + } +}; + +module.exports = Eyedropper = (function(superClass) { + extend(Eyedropper, superClass); + + Eyedropper.prototype.name = 'Eyedropper'; + + Eyedropper.prototype.iconName = 'eyedropper'; + + Eyedropper.prototype.optionsStyle = 'stroke-or-fill'; + + function Eyedropper(lc) { + Eyedropper.__super__.constructor.call(this, lc); + this.strokeOrFill = 'stroke'; + } + + Eyedropper.prototype.readColor = function(x, y, lc) { + var canvas, color, newColor, offset; + offset = lc.getDefaultImageRect(); + canvas = lc.getImage(); + newColor = getPixel(canvas.getContext('2d'), { + x: x - offset.x, + y: y - offset.y + }); + color = newColor || lc.getColor('background'); + if (this.strokeOrFill === 'stroke') { + return lc.setColor('primary', newColor); + } else { + return lc.setColor('secondary', newColor); + } + }; + + Eyedropper.prototype.begin = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + Eyedropper.prototype["continue"] = function(x, y, lc) { + return this.readColor(x, y, lc); + }; + + return Eyedropper; + +})(Tool); diff --git a/library/js/literallycanvas/js/tools/Line.js b/library/js/literallycanvas/js/tools/Line.js new file mode 100644 index 00000000000..b1e4c72f0c9 --- /dev/null +++ b/library/js/literallycanvas/js/tools/Line.js @@ -0,0 +1,54 @@ +var Line, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Line = (function(superClass) { + extend(Line, superClass); + + function Line() { + return Line.__super__.constructor.apply(this, arguments); + } + + Line.prototype.name = 'Line'; + + Line.prototype.iconName = 'line'; + + Line.prototype.optionsStyle = 'line-options-and-stroke-width'; + + Line.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Line', { + x1: x, + y1: y, + x2: x, + y2: y, + strokeWidth: this.strokeWidth, + dash: (function() { + switch (false) { + case !this.isDashed: + return [this.strokeWidth * 2, this.strokeWidth * 4]; + default: + return null; + } + }).call(this), + endCapShapes: this.hasEndArrow ? [null, 'arrow'] : null, + color: lc.getColor('primary') + }); + }; + + Line.prototype["continue"] = function(x, y, lc) { + this.currentShape.x2 = x; + this.currentShape.y2 = y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Line.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Line; + +})(ToolWithStroke); diff --git a/library/js/literallycanvas/js/tools/Pan.js b/library/js/literallycanvas/js/tools/Pan.js new file mode 100644 index 00000000000..e61ef7e2bfa --- /dev/null +++ b/library/js/literallycanvas/js/tools/Pan.js @@ -0,0 +1,66 @@ +var Pan, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = Pan = (function(superClass) { + extend(Pan, superClass); + + function Pan() { + return Pan.__super__.constructor.apply(this, arguments); + } + + Pan.prototype.name = 'Pan'; + + Pan.prototype.iconName = 'pan'; + + Pan.prototype.usesSimpleAPI = false; + + Pan.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + unsubscribeFuncs.push(lc.on('lc-pointerdown', (function(_this) { + return function(arg) { + var rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + _this.oldPosition = lc.position; + return _this.pointerStart = { + x: rawX, + y: rawY + }; + }; + })(this))); + return unsubscribeFuncs.push(lc.on('lc-pointerdrag', (function(_this) { + return function(arg) { + var dp, rawX, rawY; + rawX = arg.rawX, rawY = arg.rawY; + dp = { + x: (rawX - _this.pointerStart.x) * lc.backingScale, + y: (rawY - _this.pointerStart.y) * lc.backingScale + }; + return lc.setPan(_this.oldPosition.x + dp.x, _this.oldPosition.y + dp.y); + }; + })(this))); + }; + + Pan.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return Pan; + +})(Tool); diff --git a/library/js/literallycanvas/js/tools/Pencil.js b/library/js/literallycanvas/js/tools/Pencil.js new file mode 100644 index 00000000000..1003128e7e7 --- /dev/null +++ b/library/js/literallycanvas/js/tools/Pencil.js @@ -0,0 +1,59 @@ +var Pencil, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Pencil = (function(superClass) { + extend(Pencil, superClass); + + function Pencil() { + return Pencil.__super__.constructor.apply(this, arguments); + } + + Pencil.prototype.name = 'Pencil'; + + Pencil.prototype.iconName = 'pencil'; + + Pencil.prototype.eventTimeThreshold = 10; + + Pencil.prototype.begin = function(x, y, lc) { + this.color = lc.getColor('primary'); + this.currentShape = this.makeShape(); + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return this.lastEventTime = Date.now(); + }; + + Pencil.prototype["continue"] = function(x, y, lc) { + var timeDiff; + timeDiff = Date.now() - this.lastEventTime; + if (timeDiff > this.eventTimeThreshold) { + this.lastEventTime += timeDiff; + this.currentShape.addPoint(this.makePoint(x, y, lc)); + return lc.drawShapeInProgress(this.currentShape); + } + }; + + Pencil.prototype.end = function(x, y, lc) { + lc.saveShape(this.currentShape); + return this.currentShape = void 0; + }; + + Pencil.prototype.makePoint = function(x, y, lc) { + return createShape('Point', { + x: x, + y: y, + size: this.strokeWidth, + color: this.color + }); + }; + + Pencil.prototype.makeShape = function() { + return createShape('LinePath'); + }; + + return Pencil; + +})(ToolWithStroke); diff --git a/library/js/literallycanvas/js/tools/Polygon.js b/library/js/literallycanvas/js/tools/Polygon.js new file mode 100644 index 00000000000..01bcf700618 --- /dev/null +++ b/library/js/literallycanvas/js/tools/Polygon.js @@ -0,0 +1,213 @@ +var Polygon, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Polygon = (function(superClass) { + extend(Polygon, superClass); + + function Polygon() { + return Polygon.__super__.constructor.apply(this, arguments); + } + + Polygon.prototype.name = 'Polygon'; + + Polygon.prototype.iconName = 'polygon'; + + Polygon.prototype.usesSimpleAPI = false; + + Polygon.prototype.didBecomeActive = function(lc) { + var onDown, onMove, onUp, polygonCancel, polygonFinishClosed, polygonFinishOpen, polygonUnsubscribeFuncs; + Polygon.__super__.didBecomeActive.call(this, lc); + polygonUnsubscribeFuncs = []; + this.polygonUnsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = polygonUnsubscribeFuncs.length; i < len; i++) { + func = polygonUnsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + this.points = null; + this.maybePoint = null; + onUp = (function(_this) { + return function() { + if (_this._getWillFinish()) { + return _this._close(lc); + } + lc.trigger('lc-polygon-started'); + if (_this.points) { + _this.points.push(_this.maybePoint); + } else { + _this.points = [_this.maybePoint]; + } + _this.maybePoint = { + x: _this.maybePoint.x, + y: _this.maybePoint.y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + onMove = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.maybePoint) { + _this.maybePoint.x = x; + _this.maybePoint.y = y; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + } + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + _this.maybePoint = { + x: x, + y: y + }; + lc.setShapesInProgress(_this._getShapes(lc)); + return lc.repaintLayer('main'); + }; + })(this); + polygonFinishOpen = (function(_this) { + return function() { + _this.maybePoint = { + x: Infinity, + y: Infinity + }; + return _this._close(lc); + }; + })(this); + polygonFinishClosed = (function(_this) { + return function() { + _this.maybePoint = _this.points[0]; + return _this._close(lc); + }; + })(this); + polygonCancel = (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this); + polygonUnsubscribeFuncs.push(lc.on('drawingChange', (function(_this) { + return function() { + return _this._cancel(lc); + }; + })(this))); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointermove', onMove)); + polygonUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishopen', polygonFinishOpen)); + polygonUnsubscribeFuncs.push(lc.on('lc-polygon-finishclosed', polygonFinishClosed)); + return polygonUnsubscribeFuncs.push(lc.on('lc-polygon-cancel', polygonCancel)); + }; + + Polygon.prototype.willBecomeInactive = function(lc) { + Polygon.__super__.willBecomeInactive.call(this, lc); + if (this.points || this.maybePoint) { + this._cancel(lc); + } + return this.polygonUnsubscribe(); + }; + + Polygon.prototype._getArePointsClose = function(a, b) { + return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) < 10; + }; + + Polygon.prototype._getWillClose = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint); + }; + + Polygon.prototype._getWillFinish = function() { + if (!(this.points && this.points.length > 1)) { + return false; + } + if (!this.maybePoint) { + return false; + } + return this._getArePointsClose(this.points[0], this.maybePoint) || this._getArePointsClose(this.points[this.points.length - 1], this.maybePoint); + }; + + Polygon.prototype._cancel = function(lc) { + lc.trigger('lc-polygon-stopped'); + this.maybePoint = null; + this.points = null; + lc.setShapesInProgress([]); + return lc.repaintLayer('main'); + }; + + Polygon.prototype._close = function(lc) { + lc.trigger('lc-polygon-stopped'); + lc.setShapesInProgress([]); + if (this.points.length > 2) { + lc.saveShape(this._getShape(lc, false)); + } + this.maybePoint = null; + return this.points = null; + }; + + Polygon.prototype._getShapes = function(lc, isInProgress) { + var shape; + if (isInProgress == null) { + isInProgress = true; + } + shape = this._getShape(lc, isInProgress); + if (shape) { + return [shape]; + } else { + return []; + } + }; + + Polygon.prototype._getShape = function(lc, isInProgress) { + var points; + if (isInProgress == null) { + isInProgress = true; + } + points = []; + if (this.points) { + points = points.concat(this.points); + } + if ((!isInProgress) && points.length < 3) { + return null; + } + if (isInProgress && this.maybePoint) { + points.push(this.maybePoint); + } + if (points.length > 1) { + return createShape('Polygon', { + isClosed: this._getWillClose(), + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary'), + strokeWidth: this.strokeWidth, + points: points.map(function(xy) { + return createShape('Point', xy); + }) + }); + } else { + return null; + } + }; + + Polygon.prototype.optionsStyle = 'polygon-and-stroke-width'; + + return Polygon; + +})(ToolWithStroke); diff --git a/library/js/literallycanvas/js/tools/Rectangle.js b/library/js/literallycanvas/js/tools/Rectangle.js new file mode 100644 index 00000000000..fcde738e5ce --- /dev/null +++ b/library/js/literallycanvas/js/tools/Rectangle.js @@ -0,0 +1,42 @@ +var Rectangle, ToolWithStroke, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +ToolWithStroke = require('./base').ToolWithStroke; + +createShape = require('../core/shapes').createShape; + +module.exports = Rectangle = (function(superClass) { + extend(Rectangle, superClass); + + function Rectangle() { + return Rectangle.__super__.constructor.apply(this, arguments); + } + + Rectangle.prototype.name = 'Rectangle'; + + Rectangle.prototype.iconName = 'rectangle'; + + Rectangle.prototype.begin = function(x, y, lc) { + return this.currentShape = createShape('Rectangle', { + x: x, + y: y, + strokeWidth: this.strokeWidth, + strokeColor: lc.getColor('primary'), + fillColor: lc.getColor('secondary') + }); + }; + + Rectangle.prototype["continue"] = function(x, y, lc) { + this.currentShape.width = x - this.currentShape.x; + this.currentShape.height = y - this.currentShape.y; + return lc.drawShapeInProgress(this.currentShape); + }; + + Rectangle.prototype.end = function(x, y, lc) { + return lc.saveShape(this.currentShape); + }; + + return Rectangle; + +})(ToolWithStroke); diff --git a/library/js/literallycanvas/js/tools/SelectShape.js b/library/js/literallycanvas/js/tools/SelectShape.js new file mode 100644 index 00000000000..af6dca6a14d --- /dev/null +++ b/library/js/literallycanvas/js/tools/SelectShape.js @@ -0,0 +1,152 @@ +var SelectShape, Tool, createShape, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +module.exports = SelectShape = (function(superClass) { + extend(SelectShape, superClass); + + SelectShape.prototype.name = 'SelectShape'; + + SelectShape.prototype.usesSimpleAPI = false; + + function SelectShape(lc) { + this.selectCanvas = document.createElement('canvas'); + this.selectCanvas.style['background-color'] = 'transparent'; + this.selectCtx = this.selectCanvas.getContext('2d'); + } + + SelectShape.prototype.didBecomeActive = function(lc) { + var onDown, onDrag, onUp, selectShapeUnsubscribeFuncs; + selectShapeUnsubscribeFuncs = []; + this._selectShapeUnsubscribe = (function(_this) { + return function() { + var func, j, len, results; + results = []; + for (j = 0, len = selectShapeUnsubscribeFuncs.length; j < len; j++) { + func = selectShapeUnsubscribeFuncs[j]; + results.push(func()); + } + return results; + }; + })(this); + onDown = (function(_this) { + return function(arg) { + var br, shapeIndex, x, y; + x = arg.x, y = arg.y; + _this.didDrag = false; + shapeIndex = _this._getPixel(x, y, lc, _this.selectCtx); + _this.selectedShape = lc.shapes[shapeIndex]; + if (_this.selectedShape != null) { + lc.trigger('shapeSelected', { + selectedShape: _this.selectedShape + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + lc.repaintLayer('main'); + br = _this.selectedShape.getBoundingRect(); + return _this.dragOffset = { + x: x - br.x, + y: y - br.y + }; + } + }; + })(this); + onDrag = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.selectedShape != null) { + _this.didDrag = true; + _this.selectedShape.setUpperLeft({ + x: x - _this.dragOffset.x, + y: y - _this.dragOffset.y + }); + lc.setShapesInProgress([ + _this.selectedShape, createShape('SelectionBox', { + shape: _this.selectedShape, + handleSize: 0 + }) + ]); + return lc.repaintLayer('main'); + } + }; + })(this); + onUp = (function(_this) { + return function(arg) { + var x, y; + x = arg.x, y = arg.y; + if (_this.didDrag) { + _this.didDrag = false; + lc.trigger('shapeMoved', { + shape: _this.selectedShape + }); + lc.trigger('drawingChange', {}); + lc.repaintLayer('main'); + return _this._drawSelectCanvas(lc); + } + }; + })(this); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdown', onDown)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerdrag', onDrag)); + selectShapeUnsubscribeFuncs.push(lc.on('lc-pointerup', onUp)); + return this._drawSelectCanvas(lc); + }; + + SelectShape.prototype.willBecomeInactive = function(lc) { + this._selectShapeUnsubscribe(); + return lc.setShapesInProgress([]); + }; + + SelectShape.prototype._drawSelectCanvas = function(lc) { + var shapes; + this.selectCanvas.width = lc.canvas.width; + this.selectCanvas.height = lc.canvas.height; + this.selectCtx.clearRect(0, 0, this.selectCanvas.width, this.selectCanvas.height); + shapes = lc.shapes.map((function(_this) { + return function(shape, index) { + return createShape('SelectionBox', { + shape: shape, + handleSize: 0, + backgroundColor: "#" + (_this._intToHex(index)) + }); + }; + })(this)); + return lc.draw(shapes, this.selectCtx); + }; + + SelectShape.prototype._intToHex = function(i) { + return ("000000" + (i.toString(16))).slice(-6); + }; + + SelectShape.prototype._getPixel = function(x, y, lc, ctx) { + var p, pixel; + p = lc.drawingCoordsToClientCoords(x, y); + pixel = ctx.getImageData(p.x, p.y, 1, 1).data; + if (pixel[3]) { + return parseInt(this._rgbToHex(pixel[0], pixel[1], pixel[2]), 16); + } else { + return null; + } + }; + + SelectShape.prototype._componentToHex = function(c) { + var hex; + hex = c.toString(16); + return ("0" + hex).slice(-2); + }; + + SelectShape.prototype._rgbToHex = function(r, g, b) { + return "" + (this._componentToHex(r)) + (this._componentToHex(g)) + (this._componentToHex(b)); + }; + + return SelectShape; + +})(Tool); diff --git a/library/js/literallycanvas/js/tools/Text.js b/library/js/literallycanvas/js/tools/Text.js new file mode 100644 index 00000000000..5178cd6c40c --- /dev/null +++ b/library/js/literallycanvas/js/tools/Text.js @@ -0,0 +1,358 @@ +var Text, Tool, createShape, getIsPointInBox, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +Tool = require('./base').Tool; + +createShape = require('../core/shapes').createShape; + +getIsPointInBox = function(point, box) { + if (point.x < box.x) { + return false; + } + if (point.y < box.y) { + return false; + } + if (point.x > box.x + box.width) { + return false; + } + if (point.y > box.y + box.height) { + return false; + } + return true; +}; + +module.exports = Text = (function(superClass) { + extend(Text, superClass); + + Text.prototype.name = 'Text'; + + Text.prototype.iconName = 'text'; + + function Text() { + this.text = ''; + this.font = 'bold 18px sans-serif'; + this.currentShape = null; + this.currentShapeState = null; + this.initialShapeBoundingRect = null; + this.dragAction = null; + this.didDrag = false; + } + + Text.prototype.didBecomeActive = function(lc) { + var switchAway, unsubscribeFuncs, updateInputEl; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + switchAway = (function(_this) { + return function() { + _this._ensureNotEditing(lc); + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this); + updateInputEl = (function(_this) { + return function() { + return _this._updateInputEl(lc); + }; + })(this); + unsubscribeFuncs.push(lc.on('drawingChange', switchAway)); + unsubscribeFuncs.push(lc.on('zoom', updateInputEl)); + unsubscribeFuncs.push(lc.on('imageSizeChange', updateInputEl)); + unsubscribeFuncs.push(lc.on('snapshotLoad', (function(_this) { + return function() { + _this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + })(this))); + unsubscribeFuncs.push(lc.on('primaryColorChange', (function(_this) { + return function(newColor) { + if (!_this.currentShape) { + return; + } + _this.currentShape.color = newColor; + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + return unsubscribeFuncs.push(lc.on('setFont', (function(_this) { + return function(font) { + if (!_this.currentShape) { + return; + } + _this.font = font; + _this.currentShape.setFont(font); + _this._setShapesInProgress(lc); + _this._updateInputEl(lc); + return lc.repaintLayer('main'); + }; + })(this))); + }; + + Text.prototype.willBecomeInactive = function(lc) { + if (this.currentShape) { + this._ensureNotEditing(lc); + this.commit(lc); + } + return this.unsubscribe(); + }; + + Text.prototype.setText = function(text) { + return this.text = text; + }; + + Text.prototype._ensureNotEditing = function(lc) { + if (this.currentShapeState === 'editing') { + return this._exitEditingState(lc); + } + }; + + Text.prototype._clearCurrentShape = function(lc) { + this.currentShape = null; + this.initialShapeBoundingRect = null; + this.currentShapeState = null; + return lc.setShapesInProgress([]); + }; + + Text.prototype.commit = function(lc) { + if (this.currentShape.text) { + lc.saveShape(this.currentShape); + } + this._clearCurrentShape(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._getSelectionShape = function(ctx, backgroundColor) { + if (backgroundColor == null) { + backgroundColor = null; + } + return createShape('SelectionBox', { + shape: this.currentShape, + ctx: ctx, + backgroundColor: backgroundColor + }); + }; + + Text.prototype._setShapesInProgress = function(lc) { + switch (this.currentShapeState) { + case 'selected': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx), this.currentShape]); + case 'editing': + return lc.setShapesInProgress([this._getSelectionShape(lc.ctx, '#fff')]); + default: + return lc.setShapesInProgress([this.currentShape]); + } + }; + + Text.prototype.begin = function(x, y, lc) { + var br, point, selectionBox, selectionShape; + this.dragAction = 'none'; + this.didDrag = false; + if (this.currentShapeState === 'selected' || this.currentShapeState === 'editing') { + br = this.currentShape.getBoundingRect(lc.ctx); + selectionShape = this._getSelectionShape(lc.ctx); + selectionBox = selectionShape.getBoundingRect(); + point = { + x: x, + y: y + }; + if (getIsPointInBox(point, br)) { + this.dragAction = 'move'; + } + if (getIsPointInBox(point, selectionShape.getBottomRightHandleRect())) { + this.dragAction = 'resizeBottomRight'; + } + if (getIsPointInBox(point, selectionShape.getTopLeftHandleRect())) { + this.dragAction = 'resizeTopLeft'; + } + if (getIsPointInBox(point, selectionShape.getBottomLeftHandleRect())) { + this.dragAction = 'resizeBottomLeft'; + } + if (getIsPointInBox(point, selectionShape.getTopRightHandleRect())) { + this.dragAction = 'resizeTopRight'; + } + if (this.dragAction === 'none' && this.currentShapeState === 'editing') { + this.dragAction = 'stop-editing'; + this._exitEditingState(lc); + } + } else { + this.color = lc.getColor('primary'); + this.currentShape = createShape('Text', { + x: x, + y: y, + text: this.text, + color: this.color, + font: this.font, + v: 1 + }); + this.dragAction = 'place'; + this.currentShapeState = 'selected'; + } + if (this.dragAction === 'none') { + this.commit(lc); + return; + } + this.initialShapeBoundingRect = this.currentShape.getBoundingRect(lc.ctx); + this.dragOffset = { + x: x - this.initialShapeBoundingRect.x, + y: y - this.initialShapeBoundingRect.y + }; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype["continue"] = function(x, y, lc) { + var br, brBottom, brRight; + if (this.dragAction === 'none') { + return; + } + br = this.initialShapeBoundingRect; + brRight = br.x + br.width; + brBottom = br.y + br.height; + switch (this.dragAction) { + case 'place': + this.currentShape.x = x; + this.currentShape.y = y; + this.didDrag = true; + break; + case 'move': + this.currentShape.x = x - this.dragOffset.x; + this.currentShape.y = y - this.dragOffset.y; + this.didDrag = true; + break; + case 'resizeBottomRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + break; + case 'resizeTopLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(x - this.dragOffset.x, y - this.dragOffset.y); + break; + case 'resizeBottomLeft': + this.currentShape.setSize(brRight - x + this.dragOffset.x, y - (this.dragOffset.y - this.initialShapeBoundingRect.height) - br.y); + this.currentShape.setPosition(x - this.dragOffset.x, this.currentShape.y); + break; + case 'resizeTopRight': + this.currentShape.setSize(x - (this.dragOffset.x - this.initialShapeBoundingRect.width) - br.x, brBottom - y + this.dragOffset.y); + this.currentShape.setPosition(this.currentShape.x, y - this.dragOffset.y); + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype.end = function(x, y, lc) { + if (!this.currentShape) { + return; + } + this.currentShape.setSize(this.currentShape.forcedWidth, 0); + if (this.currentShapeState === 'selected') { + if (this.dragAction === 'place' || (this.dragAction === 'move' && !this.didDrag)) { + this._enterEditingState(lc); + } + } + this._setShapesInProgress(lc); + lc.repaintLayer('main'); + return this._updateInputEl(lc); + }; + + Text.prototype._enterEditingState = function(lc) { + var onChange; + this.currentShapeState = 'editing'; + if (this.inputEl) { + throw "State error"; + } + this.inputEl = document.createElement('textarea'); + this.inputEl.className = 'text-tool-input'; + this.inputEl.style.position = 'absolute'; + this.inputEl.style.transformOrigin = '0px 0px'; + this.inputEl.style.backgroundColor = 'transparent'; + this.inputEl.style.border = 'none'; + this.inputEl.style.outline = 'none'; + this.inputEl.style.margin = '0'; + this.inputEl.style.padding = '4px'; + this.inputEl.style.zIndex = '1000'; + this.inputEl.style.overflow = 'hidden'; + this.inputEl.style.resize = 'none'; + this.inputEl.value = this.currentShape.text; + this.inputEl.addEventListener('mousedown', function(e) { + return e.stopPropagation(); + }); + this.inputEl.addEventListener('touchstart', function(e) { + return e.stopPropagation(); + }); + onChange = (function(_this) { + return function(e) { + _this.currentShape.setText(e.target.value); + _this.currentShape.enforceMaxBoundingRect(lc); + _this._setShapesInProgress(lc); + lc.repaintLayer('main'); + _this._updateInputEl(lc); + return e.stopPropagation(); + }; + })(this); + this.inputEl.addEventListener('keydown', (function(_this) { + return function() { + return _this._updateInputEl(lc, true); + }; + })(this)); + this.inputEl.addEventListener('keyup', onChange); + this.inputEl.addEventListener('change', onChange); + this._updateInputEl(lc); + lc.containerEl.appendChild(this.inputEl); + this.inputEl.focus(); + return this._setShapesInProgress(lc); + }; + + Text.prototype._exitEditingState = function(lc) { + this.currentShapeState = 'selected'; + lc.containerEl.removeChild(this.inputEl); + this.inputEl = null; + this._setShapesInProgress(lc); + return lc.repaintLayer('main'); + }; + + Text.prototype._updateInputEl = function(lc, withMargin) { + var br, transformString; + if (withMargin == null) { + withMargin = false; + } + if (!this.inputEl) { + return; + } + br = this.currentShape.getBoundingRect(lc.ctx, true); + this.inputEl.style.font = this.currentShape.font; + this.inputEl.style.color = this.currentShape.color; + this.inputEl.style.left = (lc.position.x / lc.backingScale + br.x * lc.scale - 4) + "px"; + this.inputEl.style.top = (lc.position.y / lc.backingScale + br.y * lc.scale - 4) + "px"; + if (withMargin && !this.currentShape.forcedWidth) { + this.inputEl.style.width = (br.width + 10 + this.currentShape.renderer.emDashWidth) + "px"; + } else { + this.inputEl.style.width = (br.width + 12) + "px"; + } + if (withMargin) { + this.inputEl.style.height = (br.height + 10 + this.currentShape.renderer.metrics.leading) + "px"; + } else { + this.inputEl.style.height = (br.height + 10) + "px"; + } + transformString = "scale(" + lc.scale + ")"; + this.inputEl.style.transform = transformString; + this.inputEl.style.webkitTransform = transformString; + this.inputEl.style.MozTransform = transformString; + this.inputEl.style.msTransform = transformString; + return this.inputEl.style.OTransform = transformString; + }; + + Text.prototype.optionsStyle = 'font'; + + return Text; + +})(Tool); diff --git a/library/js/literallycanvas/js/tools/base.js b/library/js/literallycanvas/js/tools/base.js new file mode 100644 index 00000000000..7d5ce040ecd --- /dev/null +++ b/library/js/literallycanvas/js/tools/base.js @@ -0,0 +1,71 @@ +var Tool, ToolWithStroke, tools, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +tools = {}; + +tools.Tool = Tool = (function() { + function Tool() {} + + Tool.prototype.name = null; + + Tool.prototype.iconName = null; + + Tool.prototype.usesSimpleAPI = true; + + Tool.prototype.begin = function(x, y, lc) {}; + + Tool.prototype["continue"] = function(x, y, lc) {}; + + Tool.prototype.end = function(x, y, lc) {}; + + Tool.prototype.optionsStyle = null; + + Tool.prototype.didBecomeActive = function(lc) {}; + + Tool.prototype.willBecomeInactive = function(lc) {}; + + return Tool; + +})(); + +tools.ToolWithStroke = ToolWithStroke = (function(superClass) { + extend(ToolWithStroke, superClass); + + function ToolWithStroke(lc) { + this.strokeWidth = lc.opts.defaultStrokeWidth; + } + + ToolWithStroke.prototype.optionsStyle = 'stroke-width'; + + ToolWithStroke.prototype.didBecomeActive = function(lc) { + var unsubscribeFuncs; + unsubscribeFuncs = []; + this.unsubscribe = (function(_this) { + return function() { + var func, i, len, results; + results = []; + for (i = 0, len = unsubscribeFuncs.length; i < len; i++) { + func = unsubscribeFuncs[i]; + results.push(func()); + } + return results; + }; + })(this); + return unsubscribeFuncs.push(lc.on('setStrokeWidth', (function(_this) { + return function(strokeWidth) { + _this.strokeWidth = strokeWidth; + return lc.trigger('toolDidUpdateOptions'); + }; + })(this))); + }; + + ToolWithStroke.prototype.willBecomeInactive = function(lc) { + return this.unsubscribe(); + }; + + return ToolWithStroke; + +})(Tool); + +module.exports = tools; diff --git a/library/js/react/README.md b/library/js/react/README.md new file mode 100644 index 00000000000..15bea2b9023 --- /dev/null +++ b/library/js/react/README.md @@ -0,0 +1,116 @@ +# [React](https://facebook.github.io/react/) [![Build Status](https://img.shields.io/travis/facebook/react/master.svg?style=flat)](https://travis-ci.org/facebook/react) [![Coverage Status](https://img.shields.io/coveralls/facebook/react/master.svg?style=flat)](https://coveralls.io/github/facebook/react?branch=master) [![npm version](https://img.shields.io/npm/v/react.svg?style=flat)](https://www.npmjs.com/package/react) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md#pull-requests) + +React is a JavaScript library for building user interfaces. + +* **Just the UI:** Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project. +* **Virtual DOM:** React abstracts away the DOM from you, giving a simpler programming model and better performance. React can also render on the server using Node, and it can power native apps using [React Native](https://facebook.github.io/react-native/). +* **Data flow:** React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding. + +**NEW**! Check out our newest project [React Native](https://github.com/facebook/react-native), which uses React and JavaScript to create native mobile apps. + +[Learn how to use React in your own project](https://facebook.github.io/react/docs/getting-started.html). + +## Examples + +We have several examples [on the website](https://facebook.github.io/react/). Here is the first one to get you started: + +```js +var HelloMessage = React.createClass({ + render: function() { + return
Hello {this.props.name}
; + } +}); + +ReactDOM.render( + , + document.getElementById('container') +); +``` + +This example will render "Hello John" into a container on the page. + +You'll notice that we used an HTML-like syntax; [we call it JSX](https://facebook.github.io/react/docs/jsx-in-depth.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest. + +## Installation + +The fastest way to get started is to serve JavaScript from the CDN (also available on [cdnjs](https://cdnjs.com/libraries/react) and [jsdelivr](https://www.jsdelivr.com/projects/react)): + +```html + + + + +``` + +We've also built a [starter kit](https://facebook.github.io/react/downloads/react-15.1.0.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code. + +If you'd like to use [bower](http://bower.io), it's as easy as: + +```sh +bower install --save react +``` + +And it's just as easy with [npm](http://npmjs.com): + +```sh +npm i --save react +``` + +## Contribute + +The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. If you're interested in helping with that, then keep reading. If you're not interested in helping right now that's ok too. :) Any feedback you have about using React would be greatly appreciated. + +### Building Your Copy of React + +The process to build `react.js` is built entirely on top of node.js, using many libraries you may already be familiar with. + +#### Prerequisites + +* You have `node` installed at v4.0.0+ and `npm` at v2.0.0+. +* You are familiar with `npm` and know whether or not you need to use `sudo` when installing packages globally. +* You are familiar with `git`. + +#### Build + +Once you have the repository cloned, building a copy of `react.js` is really easy. + +```sh +# grunt-cli is needed by grunt; you might have this installed already +npm install -g grunt-cli +npm install +grunt build +``` + +At this point, you should now have a `build/` directory populated with everything you need to use React. The examples should all work. + +### Grunt + +We use grunt to automate many tasks. Run `grunt -h` to see a mostly complete listing. The important ones to know: + +```sh +# Build and run tests with PhantomJS +grunt test +# Lint the code with ESLint +grunt lint +# Wipe out build directory +grunt clean +``` + +### Good First Bug +To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first bugs](https://github.com/facebook/react/labels/good%20first%20bug) that contain bugs which are fairly easy to fix. This is a great place to get started. + + +### License + +React is [BSD licensed](./LICENSE). We also provide an additional [patent grant](./PATENTS). + +React documentation is [Creative Commons licensed](./LICENSE-docs). + +Examples provided in this repository and in the documentation are [separately licensed](./LICENSE-examples). + +### More… + +There's only so much we can cram in here. To read more about the community and guidelines for submitting pull requests, please read the [Contributing document](CONTRIBUTING.md). + +## Troubleshooting +See the [Troubleshooting Guide](https://github.com/facebook/react/wiki/Troubleshooting) diff --git a/library/js/react/README.openemr.txt b/library/js/react/README.openemr.txt new file mode 100644 index 00000000000..c889c4c9c21 --- /dev/null +++ b/library/js/react/README.openemr.txt @@ -0,0 +1,5 @@ +This is the React distribution 15.1.0 obtained from http://facebook.github.io/react/ +and modified as follows: + + 1. Removed examples. + 2. Added this file. diff --git a/library/js/react/build/react-dom-server.js b/library/js/react/build/react-dom-server.js new file mode 100644 index 00000000000..586130d1cd7 --- /dev/null +++ b/library/js/react/build/react-dom-server.js @@ -0,0 +1,42 @@ +/** + * ReactDOMServer v15.1.0 + * + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ +// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js +;(function(f) { + // CommonJS + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = f(require('react')); + + // RequireJS + } else if (typeof define === "function" && define.amd) { + define(['react'], f); + + //