Browse Source

chore:update

wxyyxc1992 5 years ago
parent
commit
86b62c707d
98 changed files with 21243 additions and 3736 deletions
  1. 0
    234
      dist/cjs/board/Whiteboard/index.js
  2. 6
    3
      dist/cjs/drawboard/Baseboard/index.js
  3. 168
    37
      dist/cjs/drawboard/Drawboard/index.js
  4. 0
    0
      dist/cjs/event/SyncEvent.js
  5. 0
    0
      dist/cjs/event/border-events.js
  6. 2
    0
      dist/cjs/event/marker-events.js
  7. 11
    2
      dist/cjs/index.js
  8. 3
    3
      dist/cjs/markers/ArrowMarker/index.js
  9. 93
    62
      dist/cjs/markers/BaseMarker/index.js
  10. 3
    3
      dist/cjs/markers/CoverMarker/index.js
  11. 3
    3
      dist/cjs/markers/HighlightMarker/index.js
  12. 3
    3
      dist/cjs/markers/LineMarker/index.js
  13. 46
    17
      dist/cjs/markers/LinearMarker/index.js
  14. 10
    3
      dist/cjs/markers/RectMarker/RectBaseMarker.js
  15. 3
    3
      dist/cjs/markers/RectMarker/index.js
  16. 66
    41
      dist/cjs/markers/RectangularMarker/index.js
  17. 20
    4
      dist/cjs/markers/TextMarker/index.js
  18. 41
    0
      dist/cjs/renderer/DomEventAware/index.js
  19. 1
    1
      dist/cjs/renderer/Synthetizer/index.js
  20. 58
    8
      dist/cjs/toolbar/Toolbar.js
  21. 18
    2
      dist/cjs/toolbar/ToolbarButton.js
  22. 8
    1
      dist/cjs/toolbar/ToolbarItem.js
  23. 31
    27
      dist/cjs/toolbar/toolbar-items.js
  24. 10
    0
      dist/cjs/utils/layout.js
  25. 6
    0
      dist/cjs/utils/types.js
  26. 206
    0
      dist/cjs/whiteboard/AbstractWhiteboard/index.js
  27. 20
    0
      dist/cjs/whiteboard/AbstractWhiteboard/snap.js
  28. 76
    0
      dist/cjs/whiteboard/MirrorWhiteboard/index.js
  29. 103
    0
      dist/cjs/whiteboard/ReplayWhiteboard/index.js
  30. 67
    30
      dist/cjs/whiteboard/WhitePage/index.js
  31. 159
    0
      dist/cjs/whiteboard/Whiteboard/index.js
  32. 18921
    2825
      dist/index.js
  33. 1
    1
      dist/index.js.map
  34. 0
    53
      dist/types/board/Drawboard/index.d.ts
  35. 0
    28
      dist/types/board/WhitePage/index.d.ts
  36. 0
    45
      dist/types/board/Whiteboard/index.d.ts
  37. 0
    5
      dist/types/board/types.d.ts
  38. 5
    4
      dist/types/drawboard/Baseboard/index.d.ts
  39. 64
    0
      dist/types/drawboard/Drawboard/index.d.ts
  40. 0
    11
      dist/types/event/Event.d.ts
  41. 15
    0
      dist/types/event/SyncEvent.d.ts
  42. 1
    0
      dist/types/event/border-events.d.ts
  43. 11
    0
      dist/types/event/marker-events.d.ts
  44. 8
    3
      dist/types/index.d.ts
  45. 2
    2
      dist/types/markers/ArrowMarker/index.d.ts
  46. 28
    23
      dist/types/markers/BaseMarker/index.d.ts
  47. 2
    2
      dist/types/markers/CoverMarker/index.d.ts
  48. 2
    2
      dist/types/markers/HighlightMarker/index.d.ts
  49. 2
    2
      dist/types/markers/LineMarker/index.d.ts
  50. 17
    12
      dist/types/markers/LinearMarker/index.d.ts
  51. 5
    3
      dist/types/markers/RectMarker/RectBaseMarker.d.ts
  52. 2
    2
      dist/types/markers/RectMarker/index.d.ts
  53. 11
    8
      dist/types/markers/RectangularMarker/index.d.ts
  54. 8
    5
      dist/types/markers/TextMarker/index.d.ts
  55. 6
    0
      dist/types/markers/types.d.ts
  56. 11
    0
      dist/types/renderer/DomEventAware/index.d.ts
  57. 1
    1
      dist/types/renderer/Synthetizer/index.d.ts
  58. 17
    5
      dist/types/toolbar/Toolbar.d.ts
  59. 6
    2
      dist/types/toolbar/ToolbarButton.d.ts
  60. 6
    7
      dist/types/toolbar/ToolbarItem.d.ts
  61. 4
    1
      dist/types/toolbar/toolbar-items.d.ts
  62. 5
    0
      dist/types/utils/layout.d.ts
  63. 6
    0
      dist/types/utils/types.d.ts
  64. 42
    0
      dist/types/whiteboard/AbstractWhiteboard/index.d.ts
  65. 32
    0
      dist/types/whiteboard/AbstractWhiteboard/snap.d.ts
  66. 8
    0
      dist/types/whiteboard/MirrorWhiteboard/index.d.ts
  67. 20
    0
      dist/types/whiteboard/ReplayWhiteboard/index.d.ts
  68. 30
    0
      dist/types/whiteboard/WhitePage/index.d.ts
  69. 10
    0
      dist/types/whiteboard/Whiteboard/index.d.ts
  70. 0
    0
      example/drawboard-fullscreen/index.ts
  71. 0
    0
      example/drawboard/index.ts
  72. 0
    27
      example/index.ts
  73. 0
    0
      example/mirror-whiteboard/index.ts
  74. 0
    0
      example/mirror/index.less
  75. 0
    32
      example/mirror/index.ts
  76. 0
    13
      example/whiteboard/index.ts
  77. 4
    0
      package.json
  78. 27
    0
      src/assets/finish.svg
  79. 1
    0
      src/assets/rollback-disable.svg
  80. 1
    0
      src/assets/rollback.svg
  81. 6
    3
      src/drawboard/Baseboard/index.ts
  82. 153
    29
      src/drawboard/Drawboard/index.ts
  83. 3
    1
      src/event/border-events.ts
  84. 8
    1
      src/markers/BaseMarker/index.ts
  85. 14
    4
      src/toolbar/Toolbar.ts
  86. 18
    1
      src/toolbar/ToolbarButton.ts
  87. 17
    2
      src/toolbar/ToolbarItem.ts
  88. 11
    0
      src/toolbar/index.less
  89. 24
    14
      src/toolbar/toolbar-items.ts
  90. 2
    0
      src/types.d.ts
  91. 9
    0
      src/utils/layout.ts
  92. 16
    0
      src/whiteboard/AbstractWhiteboard/index.less
  93. 115
    6
      src/whiteboard/AbstractWhiteboard/index.ts
  94. 9
    50
      src/whiteboard/MirrorWhiteboard/index.ts
  95. 1
    1
      src/whiteboard/ReplayWhiteboard/index.ts
  96. 32
    8
      src/whiteboard/WhitePage/index.ts
  97. 71
    4
      src/whiteboard/Whiteboard/index.ts
  98. 151
    1
      yarn.lock

+ 0
- 234
dist/cjs/board/Whiteboard/index.js View File

@@ -1,234 +0,0 @@
1
-"use strict";
2
-Object.defineProperty(exports, "__esModule", { value: true });
3
-var Siema = require("siema");
4
-var index_1 = require("../WhitePage/index");
5
-var uuid_1 = require("../../utils/uuid");
6
-var dom_1 = require("../../utils/dom");
7
-require("./index.less");
8
-var LeftArrowIcon = require('../../assets/bx-left-arrow.svg');
9
-var RightArrowIcon = require('../../assets/bx-right-arrow.svg');
10
-var prefix = 'fcw-board';
11
-var SerializableWhiteboard = (function () {
12
-    function SerializableWhiteboard() {
13
-    }
14
-    return SerializableWhiteboard;
15
-}());
16
-exports.SerializableWhiteboard = SerializableWhiteboard;
17
-var Whiteboard = (function () {
18
-    function Whiteboard(target, _a) {
19
-        var _b = _a === void 0 ? {} : _a, sources = _b.sources, eventHub = _b.eventHub, mode = _b.mode, visiblePageIndex = _b.visiblePageIndex;
20
-        this.id = uuid_1.uuid();
21
-        this.sources = [];
22
-        this.mode = 'master';
23
-        this.isFullscreen = false;
24
-        this.pages = [];
25
-        this.isInitialized = false;
26
-        this.isSyncing = false;
27
-        this.visiblePageIndex = 0;
28
-        if (target) {
29
-            this.target = target;
30
-        }
31
-        else {
32
-            this.target = document.createElement('div');
33
-            document.body.appendChild(this.target);
34
-        }
35
-        if (!this.target.id) {
36
-            this.target.id = this.id;
37
-        }
38
-        dom_1.addClassName(this.target, prefix);
39
-        if (sources) {
40
-            this.sources = sources;
41
-        }
42
-        this.eventHub = eventHub;
43
-        if (mode) {
44
-            this.mode = mode;
45
-        }
46
-        if (typeof visiblePageIndex !== 'undefined') {
47
-            this.visiblePageIndex = visiblePageIndex;
48
-        }
49
-        this.init();
50
-    }
51
-    Object.defineProperty(Whiteboard.prototype, "activePage", {
52
-        get: function () {
53
-            return this.pages[this.visiblePageIndex];
54
-        },
55
-        enumerable: true,
56
-        configurable: true
57
-    });
58
-    Whiteboard.prototype.open = function () {
59
-        var _this = this;
60
-        this.pages.forEach(function (page, i) {
61
-            page.open();
62
-            if (i !== _this.visiblePageIndex) {
63
-                page.hide();
64
-            }
65
-        });
66
-    };
67
-    Whiteboard.prototype.close = function () {
68
-        if (this.emitInterval) {
69
-            clearInterval(this.emitInterval);
70
-        }
71
-    };
72
-    Whiteboard.prototype.show = function () {
73
-        if (this.activePage) {
74
-            this.activePage.show();
75
-        }
76
-    };
77
-    Whiteboard.prototype.hide = function () {
78
-        if (this.activePage) {
79
-            this.activePage.hide();
80
-        }
81
-    };
82
-    Whiteboard.prototype.snap = function () {
83
-        return {
84
-            id: this.id,
85
-            sources: this.sources,
86
-            pageIds: this.pages.map(function (page) { return page.id; }),
87
-            visiblePageIndex: this.visiblePageIndex
88
-        };
89
-    };
90
-    Whiteboard.prototype.init = function () {
91
-        this.imgsContainer = dom_1.createDivWithClassName(prefix + "-imgs", this.target);
92
-        this.pagesContainer = dom_1.createDivWithClassName(prefix + "-pages", this.target);
93
-        if (this.mode === 'master') {
94
-            this.initMaster();
95
-            this.emitSnapshot();
96
-        }
97
-        if (this.mode === 'mirror') {
98
-            this.initMirror();
99
-        }
100
-    };
101
-    Whiteboard.prototype.initMaster = function () {
102
-        var _this = this;
103
-        this.sources.forEach(function (source) {
104
-            var page = new index_1.WhitePage({ imgSrc: source }, {
105
-                mode: _this.mode,
106
-                eventHub: _this.eventHub,
107
-                parentContainer: _this.pagesContainer
108
-            });
109
-            page.container.style.visibility = 'hidden';
110
-            _this.pages.push(page);
111
-        });
112
-        this.initSiema();
113
-        var controller = dom_1.createDivWithClassName(prefix + "-controller", this.target);
114
-        var prevEle = dom_1.createDivWithClassName(prefix + "-flip-arrow", controller);
115
-        prevEle.innerHTML = LeftArrowIcon;
116
-        var nextEle = dom_1.createDivWithClassName(prefix + "-flip-arrow", controller);
117
-        nextEle.innerHTML = RightArrowIcon;
118
-        nextEle.addEventListener('click', function () {
119
-            var nextPageIndex = _this.visiblePageIndex + 1 > _this.pages.length - 1 ? 0 : _this.visiblePageIndex + 1;
120
-            _this.onPageChange(nextPageIndex);
121
-        });
122
-        prevEle.addEventListener('click', function () {
123
-            var nextPageIndex = _this.visiblePageIndex - 1 < 0 ? _this.pages.length - 1 : _this.visiblePageIndex - 1;
124
-            _this.onPageChange(nextPageIndex);
125
-        });
126
-    };
127
-    Whiteboard.prototype.initMirror = function () {
128
-        var _this = this;
129
-        if (!this.eventHub) {
130
-            throw new Error('Invalid eventHub');
131
-        }
132
-        this.eventHub.on('sync', function (ev) {
133
-            if (ev.target !== 'whiteboard') {
134
-                return;
135
-            }
136
-            if (ev.event === 'snap') {
137
-                if (_this.isInitialized) {
138
-                    return;
139
-                }
140
-                _this.onSnapshot(ev.data);
141
-            }
142
-            if (ev.event === 'changeIndex' && ev.id === _this.id) {
143
-                if (_this.isInitialized) {
144
-                    _this.onPageChange(ev.data);
145
-                }
146
-            }
147
-        });
148
-    };
149
-    Whiteboard.prototype.initSiema = function () {
150
-        var _this = this;
151
-        this.sources.forEach(function (source) {
152
-            var imgEle = document.createElement('img');
153
-            dom_1.addClassName(imgEle, prefix + "-img");
154
-            imgEle.src = source;
155
-            imgEle.alt = 'Siema image';
156
-            _this.imgsContainer.appendChild(imgEle);
157
-        });
158
-        this.siema = new Siema({
159
-            selector: this.imgsContainer,
160
-            duration: 200,
161
-            easing: 'ease-out',
162
-            perPage: 1,
163
-            startIndex: 0,
164
-            draggable: false,
165
-            multipleDrag: true,
166
-            threshold: 20,
167
-            loop: false,
168
-            rtl: false
169
-        });
170
-    };
171
-    Whiteboard.prototype.onPageChange = function (nextPageIndex) {
172
-        this.siema.goTo(nextPageIndex);
173
-        this.visiblePageIndex = nextPageIndex;
174
-        this.pages.forEach(function (page, i) {
175
-            if (nextPageIndex === i) {
176
-                page.show();
177
-            }
178
-            else {
179
-                page.hide();
180
-            }
181
-        });
182
-        if (this.mode === 'master' && this.eventHub) {
183
-            this.eventHub.emit('sync', {
184
-                event: 'changeIndex',
185
-                id: this.id,
186
-                target: 'whiteboard',
187
-                data: nextPageIndex
188
-            });
189
-        }
190
-    };
191
-    Whiteboard.prototype.emitSnapshot = function () {
192
-        var _this = this;
193
-        var innerFunc = function () {
194
-            if (_this.eventHub) {
195
-                _this.eventHub.emit('sync', {
196
-                    event: 'snap',
197
-                    id: _this.id,
198
-                    target: 'whiteboard',
199
-                    data: _this.snap()
200
-                });
201
-            }
202
-        };
203
-        this.emitInterval = setInterval(function () {
204
-            innerFunc();
205
-        }, 5 * 1000);
206
-        setTimeout(innerFunc, 500);
207
-    };
208
-    Whiteboard.prototype.onSnapshot = function (snap) {
209
-        var _this = this;
210
-        var id = snap.id, sources = snap.sources, pageIds = snap.pageIds, visiblePageIndex = snap.visiblePageIndex;
211
-        if (!this.isInitialized && !this.isSyncing) {
212
-            this.id = id;
213
-            this.sources = sources;
214
-            this.isSyncing = true;
215
-            this.sources.forEach(function (source, i) {
216
-                var page = new index_1.WhitePage({ imgSrc: source }, {
217
-                    mode: _this.mode,
218
-                    eventHub: _this.eventHub,
219
-                    parentContainer: _this.pagesContainer
220
-                });
221
-                page.id = pageIds[i];
222
-                page.container.style.visibility = 'hidden';
223
-                _this.pages.push(page);
224
-                page.open();
225
-            });
226
-            this.initSiema();
227
-        }
228
-        this.isInitialized = true;
229
-        this.isSyncing = false;
230
-        this.onPageChange(visiblePageIndex);
231
-    };
232
-    return Whiteboard;
233
-}());
234
-exports.Whiteboard = Whiteboard;

dist/cjs/board/Baseboard/index.js → dist/cjs/drawboard/Baseboard/index.js View File

@@ -6,18 +6,21 @@ var Baseboard = (function () {
6 6
     function Baseboard(source) {
7 7
         var _this = this;
8 8
         this.id = uuid_1.uuid();
9
-        this.initBoard = function () {
9
+        this.isFullscreen = false;
10
+        this.initBoard = function (mountContainer) {
10 11
             _this.boardHolder = document.createElement('div');
11 12
             _this.boardHolder.id = "fcw-board-holder-" + _this.id;
13
+            _this.boardHolder.className = "fcw-board-holder";
14
+            _this.boardHolder.style.zIndex = '999';
12 15
             _this.boardHolder.style.setProperty('touch-action', 'none');
13 16
             _this.boardHolder.style.setProperty('-ms-touch-action', 'none');
14
-            document.body.appendChild(_this.boardHolder);
17
+            mountContainer.appendChild(_this.boardHolder);
15 18
             _this.boardCanvas = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
16 19
             _this.boardCanvas.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
17 20
             _this.boardCanvas.setAttribute('width', _this.width.toString());
18 21
             _this.boardCanvas.setAttribute('height', _this.height.toString());
19 22
             _this.boardCanvas.setAttribute('viewBox', '0 0 ' + _this.width.toString() + ' ' + _this.height.toString());
20
-            _this.boardHolder.style.position = 'absolute';
23
+            _this.boardHolder.style.position = 'fixed';
21 24
             _this.boardHolder.style.width = _this.width + "px";
22 25
             _this.boardHolder.style.height = _this.height + "px";
23 26
             _this.boardHolder.style.transformOrigin = 'top left';

dist/cjs/board/Drawboard/index.js → dist/cjs/drawboard/Drawboard/index.js View File

@@ -13,17 +13,29 @@ var __extends = (this && this.__extends) || (function () {
13 13
     };
14 14
 })();
15 15
 Object.defineProperty(exports, "__esModule", { value: true });
16
+var fc_hotkeys_1 = require("fc-hotkeys");
17
+var debounce = require("lodash.debounce");
16 18
 var index_1 = require("./../Baseboard/index");
17 19
 var toolbar_items_1 = require("./../../toolbar/toolbar-items");
18 20
 var Synthetizer_1 = require("../../renderer/Synthetizer");
19 21
 var Toolbar_1 = require("../../toolbar/Toolbar");
20 22
 require("./index.less");
23
+var layout_1 = require("../../utils/layout");
24
+var index_2 = require("../../markers/RectMarker/index");
25
+var index_3 = require("../../markers/HighlightMarker/index");
26
+var index_4 = require("../../markers/CoverMarker/index");
27
+var index_5 = require("../../markers/LineMarker/index");
28
+var index_6 = require("../../markers/ArrowMarker/index");
29
+var index_7 = require("../../markers/TextMarker/index");
21 30
 var Drawboard = (function (_super) {
22 31
     __extends(Drawboard, _super);
23 32
     function Drawboard(source, _a) {
24
-        var _b = _a === void 0 ? {} : _a, page = _b.page, onChange = _b.onChange;
33
+        var _b = _a === void 0 ? {} : _a, _c = _b.allowKeyboard, allowKeyboard = _c === void 0 ? true : _c, extraToolbarItems = _b.extraToolbarItems, mountContainer = _b.mountContainer, page = _b.page, zIndex = _b.zIndex, onChange = _b.onChange;
25 34
         var _this = _super.call(this, source) || this;
35
+        _this.mountContainer = document.body;
26 36
         _this.scale = 1.0;
37
+        _this.zIndex = 999;
38
+        _this.allowKeyboard = true;
27 39
         _this.onComplete = function () { };
28 40
         _this.onChange = function () { };
29 41
         _this.open = function (onComplete, onCancel) {
@@ -34,11 +46,11 @@ var Drawboard = (function (_super) {
34 46
                 _this.onCancel = onCancel;
35 47
             }
36 48
             _this.setTargetRect();
37
-            _this.initBoard();
49
+            _this.initBoard(_this.mountContainer);
38 50
             _this.attachEvents();
39 51
             _this.setStyles();
40 52
             window.addEventListener('resize', _this.adjustUI);
41
-            if (_this.page.mode === 'master') {
53
+            if ((_this.page && _this.page.mode === 'master') || !_this.page) {
42 54
                 _this.showUI();
43 55
             }
44 56
         };
@@ -57,17 +69,20 @@ var Drawboard = (function (_super) {
57 69
                 _this.target.style.display = 'block';
58 70
             }
59 71
             _this.boardHolder.style.visibility = 'visible';
60
-            _this.boardHolder.style.zIndex = '9999';
72
+            _this.boardHolder.style.zIndex = "" + _this.zIndex;
61 73
             if (_this.toolbar) {
62 74
                 _this.toolbar.show();
63 75
             }
64 76
         };
65
-        _this.close = function () {
77
+        _this.destroy = function () {
66 78
             if (_this.toolbarUI) {
67
-                document.body.removeChild(_this.toolbarUI);
79
+                _this.mountContainer.removeChild(_this.toolbarUI);
68 80
             }
69 81
             if (_this.boardCanvas) {
70
-                document.body.removeChild(_this.boardHolder);
82
+                _this.mountContainer.removeChild(_this.boardHolder);
83
+            }
84
+            if (_this.listener) {
85
+                _this.listener.reset();
71 86
             }
72 87
         };
73 88
         _this.render = function (onComplete, onCancel) {
@@ -79,48 +94,64 @@ var Drawboard = (function (_super) {
79 94
             _this.startRender(_this.renderFinished);
80 95
         };
81 96
         _this.addMarker = function (markerType, _a) {
82
-            var id = (_a === void 0 ? {} : _a).id;
97
+            var _b = _a === void 0 ? {} : _a, id = _b.id, originX = _b.originX, originY = _b.originY;
83 98
             var marker = markerType.createMarker(_this.page);
84 99
             if (id) {
85 100
                 marker.id = id;
86 101
             }
102
+            marker.drawboard = _this;
87 103
             marker.onSelected = _this.selectMarker;
88 104
             marker.onChange = _this.onChange;
89 105
             if (marker.defs && marker.defs.length > 0) {
90
-                for (var _i = 0, _b = marker.defs; _i < _b.length; _i++) {
91
-                    var d = _b[_i];
106
+                for (var _i = 0, _c = marker.defs; _i < _c.length; _i++) {
107
+                    var d = _c[_i];
92 108
                     if (d.id && !_this.boardCanvas.getElementById(d.id)) {
93 109
                         _this.defs.appendChild(d);
94 110
                     }
95 111
                 }
96 112
             }
113
+            _this.markers.push(marker);
114
+            _this.selectMarker(marker);
115
+            _this.boardCanvas.appendChild(marker.visual);
116
+            var x;
117
+            var y;
118
+            if (originX && originY) {
119
+                x = originX;
120
+                y = originY;
121
+            }
122
+            else {
123
+                var bbox = marker.visual.getBBox();
124
+                x = _this.width / 2 / _this.scale - bbox.width / 2;
125
+                y = _this.height / 2 / _this.scale - bbox.height / 2;
126
+            }
97 127
             _this.onChange({
98 128
                 target: 'marker',
99 129
                 parentId: _this.page ? _this.page.id : _this.id,
100
-                event: 'add',
101
-                data: { type: marker.type, id: marker.id }
130
+                event: 'addMarker',
131
+                marker: { type: marker.type, id: marker.id, dx: x, dy: y }
102 132
             });
103
-            _this.markers.push(marker);
104
-            _this.selectMarker(marker);
105
-            _this.boardCanvas.appendChild(marker.visual);
106
-            var bbox = marker.visual.getBBox();
107
-            var x = _this.width / 2 / _this.scale - bbox.width / 2;
108
-            var y = _this.height / 2 / _this.scale - bbox.height / 2;
109
-            var translate = marker.visual.transform.baseVal.getItem(0);
110
-            translate.setMatrix(translate.matrix.translate(x, y));
111
-            marker.visual.transform.baseVal.replaceItem(translate, 0);
133
+            marker.moveTo(x, y);
134
+            return marker;
112 135
         };
113 136
         _this.deleteActiveMarker = function () {
114
-            if (_this.activeMarker) {
137
+            _this.deleteMarkerWithEvent(_this.activeMarker);
138
+        };
139
+        _this.clearMarkers = function () {
140
+            _this.markers.slice().forEach(function (marker) {
141
+                _this.deleteMarkerWithEvent(marker);
142
+            });
143
+        };
144
+        _this.deleteMarkerWithEvent = function (marker) {
145
+            if (marker) {
115 146
                 if (_this.onChange) {
116 147
                     _this.onChange({
117
-                        event: 'remove',
118
-                        id: _this.activeMarker.id,
148
+                        event: 'removeMarker',
149
+                        id: marker.id,
119 150
                         target: 'marker',
120
-                        data: { id: _this.activeMarker.id }
151
+                        marker: { id: marker.id }
121 152
                     });
122 153
                 }
123
-                _this.deleteMarker(_this.activeMarker);
154
+                _this.deleteMarker(marker);
124 155
             }
125 156
         };
126 157
         _this.setTargetRect = function () {
@@ -156,6 +187,56 @@ var Drawboard = (function (_super) {
156 187
                 _this.activeMarker.endManipulation();
157 188
             }
158 189
         };
190
+        _this.onKeyboard = function (e, _a) {
191
+            var hotkey = _a.hotkey;
192
+            switch (hotkey) {
193
+                case 'Shift+R':
194
+                    _this.addMarker(index_2.RectMarker);
195
+                    return;
196
+                case 'Shift+H':
197
+                    _this.addMarker(index_3.HighlightMarker);
198
+                    return;
199
+                case 'Shift+C':
200
+                    _this.addMarker(index_4.CoverMarker);
201
+                    return;
202
+                case 'Shift+L':
203
+                    _this.addMarker(index_5.LineMarker);
204
+                    return;
205
+                case 'Shift+A':
206
+                    _this.addMarker(index_6.ArrowMarker);
207
+                    return;
208
+                case 'Shift+T':
209
+                    _this.addMarker(index_7.TextMarker);
210
+                    return;
211
+                case 'ESC':
212
+                    _this.page.whiteboard.rollbackSnap();
213
+                    return;
214
+                default:
215
+                    break;
216
+            }
217
+            if (!_this.activeMarker) {
218
+                return;
219
+            }
220
+            switch (hotkey) {
221
+                case 'UP':
222
+                    _this.activeMarker.move(0, -10);
223
+                    return;
224
+                case 'LEFT':
225
+                    _this.activeMarker.move(-10, 0);
226
+                    return;
227
+                case 'RIGHT':
228
+                    _this.activeMarker.move(10, 0);
229
+                    return;
230
+                case 'DOWN':
231
+                    _this.activeMarker.move(0, 10);
232
+                    return;
233
+                case 'BACKSPACE':
234
+                    _this.deleteActiveMarker();
235
+                    return;
236
+                default:
237
+                    return;
238
+            }
239
+        };
159 240
         _this.adjustUI = function (ev) {
160 241
             _this.adjustSize();
161 242
             _this.positionUI();
@@ -177,17 +258,49 @@ var Drawboard = (function (_super) {
177 258
             _this.positionToolbar();
178 259
         };
179 260
         _this.positionToolbar = function () {
180
-            _this.toolbarUI.style.left = _this.targetRect.left +
181
-                _this.target.offsetWidth -
182
-                _this.toolbarUI.clientWidth + "px";
183
-            _this.toolbarUI.style.top = _this.targetRect.top - _this.toolbarUI.clientHeight + "px";
261
+            if (_this.toolbarUI && _this.targetRect) {
262
+                _this.toolbarUI.style.left = _this.targetRect.left +
263
+                    _this.target.offsetWidth -
264
+                    _this.toolbarUI.clientWidth + "px";
265
+                _this.toolbarUI.style.top = _this.targetRect.top - _this.toolbarUI.clientHeight + "px";
266
+            }
184 267
         };
185 268
         _this.showUI = function () {
186
-            _this.toolbar = new Toolbar_1.Toolbar(_this.toolbars, _this.toolbarClick);
187
-            _this.toolbarUI = _this.toolbar.getUI();
188
-            document.body.appendChild(_this.toolbarUI);
269
+            _this.toolbar = new Toolbar_1.Toolbar(_this.toolbarItems, _this.toolbarClick);
270
+            _this.toolbar.zIndex = _this.zIndex + 1;
271
+            _this.toolbarUI = _this.toolbar.getUI(_this);
272
+            _this.boardHolder.appendChild(_this.toolbarUI);
189 273
             _this.toolbarUI.style.position = 'absolute';
190 274
             _this.positionToolbar();
275
+            _this.toolbar.show();
276
+            _this.toolbar.toolbarButtons.forEach(function (button) {
277
+                if (button.toolbarItem.draggable) {
278
+                    button.container.draggable = true;
279
+                    button.container.ondragstart = function (ev) {
280
+                        if (ev) {
281
+                            ev.dataTransfer.setData('id', button.id);
282
+                        }
283
+                    };
284
+                }
285
+            });
286
+            _this.boardCanvas.ondragover = function (ev) {
287
+                ev.preventDefault();
288
+            };
289
+            _this.boardCanvas.ondrop = function (ev) {
290
+                var markerX = ev.x;
291
+                var markerY = ev.y;
292
+                var rect = _this.boardHolder.getBoundingClientRect();
293
+                if (layout_1.rectContains(rect, { x: markerX, y: markerY })) {
294
+                    var buttonId = ev.dataTransfer.getData('id');
295
+                    var button = _this.toolbar.toolbarButtonMap[buttonId];
296
+                    if (button.toolbarItem && button.toolbarItem.markerType) {
297
+                        _this.addMarker(button.toolbarItem.markerType, {
298
+                            originX: markerX - rect.left,
299
+                            originY: markerY - rect.top
300
+                        });
301
+                    }
302
+                }
303
+            };
191 304
         };
192 305
         _this.setStyles = function () {
193 306
             var editorStyleSheet = document.createElementNS('http://www.w3.org/2000/svg', 'style');
@@ -195,7 +308,10 @@ var Drawboard = (function (_super) {
195 308
             _this.boardCanvas.appendChild(editorStyleSheet);
196 309
         };
197 310
         _this.toolbarClick = function (ev, toolbarItem) {
198
-            if (toolbarItem.markerType) {
311
+            if (toolbarItem.onClick) {
312
+                toolbarItem.onClick();
313
+            }
314
+            else if (toolbarItem.markerType) {
199 315
                 _this.addMarker(toolbarItem.markerType);
200 316
             }
201 317
             else {
@@ -241,7 +357,7 @@ var Drawboard = (function (_super) {
241 357
             _this.startRender(_this.renderFinishedClose);
242 358
         };
243 359
         _this.cancel = function () {
244
-            _this.close();
360
+            _this.destroy();
245 361
             if (_this.onCancel) {
246 362
                 _this.onCancel();
247 363
             }
@@ -250,18 +366,33 @@ var Drawboard = (function (_super) {
250 366
             _this.onComplete(dataUrl);
251 367
         };
252 368
         _this.renderFinishedClose = function (dataUrl) {
253
-            _this.close();
369
+            _this.destroy();
254 370
             _this.onComplete(dataUrl);
255 371
         };
256 372
         if (page) {
257 373
             _this.page = page;
258 374
         }
375
+        if (zIndex) {
376
+            _this.zIndex = zIndex;
377
+        }
378
+        _this.allowKeyboard = allowKeyboard;
259 379
         _this.markers = [];
260 380
         _this.activeMarker = null;
261
-        _this.toolbars = toolbar_items_1.getToolbars(page);
381
+        var toolbarItems = toolbar_items_1.getToolbars(page);
382
+        if (extraToolbarItems) {
383
+            toolbarItems.push.apply(toolbarItems, extraToolbarItems);
384
+        }
385
+        _this.toolbarItems = toolbarItems;
262 386
         if (onChange) {
263 387
             _this.onChange = onChange;
264 388
         }
389
+        if (allowKeyboard && _this.page && _this.page.mode === 'master') {
390
+            _this.listener = new fc_hotkeys_1.HotkeysListener();
391
+            _this.listener.on(fc_hotkeys_1.KEY_ALL, debounce(_this.onKeyboard, 150));
392
+        }
393
+        if (mountContainer) {
394
+            _this.mountContainer = mountContainer;
395
+        }
265 396
         return _this;
266 397
     }
267 398
     Object.defineProperty(Drawboard.prototype, "markerMap", {

dist/cjs/board/types.js → dist/cjs/event/SyncEvent.js View File


dist/cjs/event/Event.js → dist/cjs/event/border-events.js View File


+ 2
- 0
dist/cjs/event/marker-events.js View File

@@ -0,0 +1,2 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });

+ 11
- 2
dist/cjs/index.js View File

@@ -1,6 +1,15 @@
1 1
 "use strict";
2 2
 Object.defineProperty(exports, "__esModule", { value: true });
3
-var Drawboard_1 = require("./board/Drawboard");
3
+var Drawboard_1 = require("./drawboard/Drawboard");
4 4
 exports.Drawboard = Drawboard_1.Drawboard;
5
-var Whiteboard_1 = require("./board/Whiteboard");
5
+var toolbar_items_1 = require("./toolbar/toolbar-items");
6
+exports.separatorToolbarItem = toolbar_items_1.separatorToolbarItem;
7
+exports.closeToolbarItem = toolbar_items_1.closeToolbarItem;
8
+var EventHub_1 = require("./event/EventHub");
9
+exports.EventHub = EventHub_1.EventHub;
10
+var Whiteboard_1 = require("./whiteboard/Whiteboard");
6 11
 exports.Whiteboard = Whiteboard_1.Whiteboard;
12
+var MirrorWhiteboard_1 = require("./whiteboard/MirrorWhiteboard");
13
+exports.MirrorWhiteboard = MirrorWhiteboard_1.MirrorWhiteboard;
14
+var ReplayWhiteboard_1 = require("./whiteboard/ReplayWhiteboard");
15
+exports.ReplayWhiteboard = ReplayWhiteboard_1.ReplayWhiteboard;

+ 3
- 3
dist/cjs/markers/ArrowMarker/index.js View File

@@ -23,8 +23,8 @@ var ArrowMarker = (function (_super) {
23 23
         _this.ARROW_SIZE = 6;
24 24
         return _this;
25 25
     }
26
-    ArrowMarker.prototype.setup = function () {
27
-        _super.prototype.setup.call(this);
26
+    ArrowMarker.prototype.init = function () {
27
+        _super.prototype.init.call(this);
28 28
         SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'arrow-marker']]);
29 29
         var tip = SvgHelper_1.SvgHelper.createPolygon("0,0 " + this.ARROW_SIZE + "," + this.ARROW_SIZE / 2 + " 0," + this.ARROW_SIZE, [['class', 'arrow-marker-tip']]);
30 30
         this.defs.push(SvgHelper_1.SvgHelper.createMarker('arrow-marker-head', 'auto', this.ARROW_SIZE, this.ARROW_SIZE, this.ARROW_SIZE - 1, this.ARROW_SIZE / 2, tip));
@@ -33,7 +33,7 @@ var ArrowMarker = (function (_super) {
33 33
     ArrowMarker.createMarker = function (page) {
34 34
         var marker = new ArrowMarker();
35 35
         marker.page = page;
36
-        marker.setup();
36
+        marker.init();
37 37
         return marker;
38 38
     };
39 39
     return ArrowMarker;

+ 93
- 62
dist/cjs/markers/BaseMarker/index.js View File

@@ -1,44 +1,77 @@
1 1
 "use strict";
2
+var __extends = (this && this.__extends) || (function () {
3
+    var extendStatics = function (d, b) {
4
+        extendStatics = Object.setPrototypeOf ||
5
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+        return extendStatics(d, b);
8
+    };
9
+    return function (d, b) {
10
+        extendStatics(d, b);
11
+        function __() { this.constructor = d; }
12
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+    };
14
+})();
2 15
 Object.defineProperty(exports, "__esModule", { value: true });
3 16
 var uuid = require("uuid/v1");
4 17
 var SvgHelper_1 = require("../../renderer/SvgHelper");
5
-var BaseMarker = (function () {
18
+var index_1 = require("../../renderer/DomEventAware/index");
19
+var types_1 = require("../../utils/types");
20
+var BaseMarker = (function (_super) {
21
+    __extends(BaseMarker, _super);
6 22
     function BaseMarker() {
7
-        var _this = this;
8
-        this.id = uuid();
9
-        this.type = 'base';
10
-        this.onChange = function () { };
11
-        this.defs = [];
12
-        this.width = 200;
13
-        this.height = 50;
14
-        this.isActive = true;
15
-        this.isDragging = false;
16
-        this.isResizing = false;
17
-        this.previousMouseX = 0;
18
-        this.previousMouseY = 0;
19
-        this.manipulate = function (ev) {
23
+        var _this = _super !== null && _super.apply(this, arguments) || this;
24
+        _this.id = uuid();
25
+        _this.type = 'base';
26
+        _this.onChange = function () { };
27
+        _this.defs = [];
28
+        _this.width = 200;
29
+        _this.height = 50;
30
+        _this.isActive = true;
31
+        _this.isDragging = false;
32
+        _this.isResizing = false;
33
+        _this.manipulate = function (ev) {
20 34
             var scale = _this.visual.getScreenCTM().a;
21 35
             var dx = (ev.screenX - _this.previousMouseX) / scale;
22 36
             var dy = (ev.screenY - _this.previousMouseY) / scale;
23 37
             if (_this.isDragging) {
24
-                _this.onChange({ target: 'marker', id: _this.id, event: 'move', data: { dx: dx, dy: dy } });
25 38
                 _this.move(dx, dy);
26 39
             }
27 40
             if (_this.isResizing) {
28 41
                 _this.resize(dx, dy, function (pos) {
29
-                    _this.onChange({ target: 'marker', id: _this.id, event: 'resize', data: { dx: dx, dy: dy, pos: pos } });
42
+                    _this.onChange({
43
+                        target: 'marker',
44
+                        id: _this.id,
45
+                        event: 'resizeMarker',
46
+                        marker: { dx: dx, dy: dy, pos: pos }
47
+                    });
30 48
                 });
31 49
             }
32 50
             _this.previousMouseX = ev.screenX;
33 51
             _this.previousMouseY = ev.screenY;
34 52
         };
35
-        this.addToVisual = function (el) {
53
+        _this.move = function (dx, dy) {
54
+            var translate = _this.visual.transform.baseVal.getItem(0);
55
+            translate.setMatrix(translate.matrix.translate(dx, dy));
56
+            _this.visual.transform.baseVal.replaceItem(translate, 0);
57
+            _this.x += dx;
58
+            _this.y += dy;
59
+            _this.onChange({ target: 'marker', id: _this.id, event: 'moveMarker', marker: { dx: dx, dy: dy } });
60
+        };
61
+        _this.moveTo = function (x, y) {
62
+            var translate = _this.visual.transform.baseVal.getItem(0);
63
+            translate.setMatrix(translate.matrix.translate(x - _this.x, y - _this.y));
64
+            _this.visual.transform.baseVal.replaceItem(translate, 0);
65
+            _this.x = x;
66
+            _this.y = y;
67
+        };
68
+        _this.addToVisual = function (el) {
36 69
             _this.visual.appendChild(el);
37 70
         };
38
-        this.addToRenderVisual = function (el) {
71
+        _this.addToRenderVisual = function (el) {
39 72
             _this.renderVisual.appendChild(el);
40 73
         };
41
-        this.mouseDown = function (ev) {
74
+        _this.onMouseDown = function (ev) {
42 75
             ev.stopPropagation();
43 76
             if (_this.page && _this.page.mode === 'mirror') {
44 77
                 return;
@@ -48,26 +81,28 @@ var BaseMarker = (function () {
48 81
             _this.previousMouseX = ev.screenX;
49 82
             _this.previousMouseY = ev.screenY;
50 83
         };
51
-        this.mouseUp = function (ev) {
84
+        _this.onMouseUp = function (ev) {
52 85
             ev.stopPropagation();
53 86
             _this.endManipulation();
54 87
         };
55
-        this.mouseMove = function (ev) {
88
+        _this.onMouseMove = function (ev) {
56 89
             ev.stopPropagation();
57 90
             _this.manipulate(ev);
58 91
         };
59
-        this.move = function (dx, dy) {
60
-            var translate = _this.visual.transform.baseVal.getItem(0);
61
-            translate.setMatrix(translate.matrix.translate(dx, dy));
62
-            _this.visual.transform.baseVal.replaceItem(translate, 0);
63
-        };
92
+        return _this;
64 93
     }
65 94
     BaseMarker.prototype.reactToManipulation = function (type, _a) {
66
-        var dx = _a.dx, dy = _a.dy, pos = _a.pos;
67
-        if (type === 'move') {
95
+        var _b = _a === void 0 ? {} : _a, dx = _b.dx, dy = _b.dy, pos = _b.pos;
96
+        if (type === 'moveMarker') {
97
+            if (types_1.isNil(dx) || types_1.isNil(dy)) {
98
+                return;
99
+            }
68 100
             this.move(dx, dy);
69 101
         }
70
-        if (type === 'resize') {
102
+        if (type === 'resizeMarker') {
103
+            if (types_1.isNil(dx) || types_1.isNil(dy)) {
104
+                return;
105
+            }
71 106
             this.resizeByEvent(dx, dy, pos);
72 107
         }
73 108
     };
@@ -87,17 +122,27 @@ var BaseMarker = (function () {
87 122
         this.endManipulation();
88 123
         return;
89 124
     };
90
-    BaseMarker.prototype.setup = function () {
91
-        this.visual = SvgHelper_1.SvgHelper.createGroup();
92
-        this.visual.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
93
-        this.visual.addEventListener('mousedown', this.mouseDown);
94
-        this.visual.addEventListener('mouseup', this.mouseUp);
95
-        this.visual.addEventListener('mousemove', this.mouseMove);
96
-        this.visual.addEventListener('touchstart', this.onTouch, { passive: false });
97
-        this.visual.addEventListener('touchend', this.onTouch, { passive: false });
98
-        this.visual.addEventListener('touchmove', this.onTouch, { passive: false });
99
-        this.renderVisual = SvgHelper_1.SvgHelper.createGroup([['class', 'render-visual']]);
100
-        this.visual.appendChild(this.renderVisual);
125
+    BaseMarker.prototype.captureSnap = function () {
126
+        return {
127
+            id: this.id,
128
+            type: this.type,
129
+            isActive: this.isActive,
130
+            x: this.x,
131
+            y: this.y
132
+        };
133
+    };
134
+    BaseMarker.prototype.applySnap = function (snap) {
135
+        this.id = snap.id;
136
+        this.type = snap.type;
137
+        if (snap.x && snap.y) {
138
+            this.moveTo(snap.x, snap.y);
139
+        }
140
+        if (this.isActive) {
141
+            this.select();
142
+        }
143
+    };
144
+    BaseMarker.prototype.destroy = function () {
145
+        this.visual.style.display = 'none';
101 146
     };
102 147
     BaseMarker.prototype.resize = function (x, y, cb) {
103 148
         return;
@@ -105,33 +150,19 @@ var BaseMarker = (function () {
105 150
     BaseMarker.prototype.resizeByEvent = function (x, y, pos) {
106 151
         return;
107 152
     };
108
-    BaseMarker.prototype.onTouch = function (ev) {
109
-        ev.preventDefault();
110
-        var newEvt = document.createEvent('MouseEvents');
111
-        var touch = ev.changedTouches[0];
112
-        var type = null;
113
-        switch (ev.type) {
114
-            case 'touchstart':
115
-                type = 'mousedown';
116
-                break;
117
-            case 'touchmove':
118
-                type = 'mousemove';
119
-                break;
120
-            case 'touchend':
121
-                type = 'mouseup';
122
-                break;
123
-            default:
124
-                break;
125
-        }
126
-        newEvt.initMouseEvent(type, true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey, 0, null);
127
-        ev.target.dispatchEvent(newEvt);
153
+    BaseMarker.prototype.init = function () {
154
+        this.visual = SvgHelper_1.SvgHelper.createGroup();
155
+        this.visual.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
156
+        _super.prototype.init.call(this, this.visual);
157
+        this.renderVisual = SvgHelper_1.SvgHelper.createGroup([['class', 'render-visual']]);
158
+        this.visual.appendChild(this.renderVisual);
128 159
     };
129 160
     BaseMarker.createMarker = function (page) {
130 161
         var marker = new BaseMarker();
131 162
         marker.page = page;
132
-        marker.setup();
163
+        marker.init();
133 164
         return marker;
134 165
     };
135 166
     return BaseMarker;
136
-}());
167
+}(index_1.DomEventAware));
137 168
 exports.BaseMarker = BaseMarker;

+ 3
- 3
dist/cjs/markers/CoverMarker/index.js View File

@@ -22,14 +22,14 @@ var CoverMarker = (function (_super) {
22 22
         _this.type = 'cover';
23 23
         return _this;
24 24
     }
25
-    CoverMarker.prototype.setup = function () {
26
-        _super.prototype.setup.call(this);
25
+    CoverMarker.prototype.init = function () {
26
+        _super.prototype.init.call(this);
27 27
         SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'cover-marker']]);
28 28
     };
29 29
     CoverMarker.createMarker = function (page) {
30 30
         var marker = new CoverMarker();
31 31
         marker.page = page;
32
-        marker.setup();
32
+        marker.init();
33 33
         return marker;
34 34
     };
35 35
     return CoverMarker;

+ 3
- 3
dist/cjs/markers/HighlightMarker/index.js View File

@@ -22,14 +22,14 @@ var HighlightMarker = (function (_super) {
22 22
         _this.type = 'highlight';
23 23
         return _this;
24 24
     }
25
-    HighlightMarker.prototype.setup = function () {
26
-        _super.prototype.setup.call(this);
25
+    HighlightMarker.prototype.init = function () {
26
+        _super.prototype.init.call(this);
27 27
         SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'highlight-marker']]);
28 28
     };
29 29
     HighlightMarker.createMarker = function (page) {
30 30
         var marker = new HighlightMarker();
31 31
         marker.page = page;
32
-        marker.setup();
32
+        marker.init();
33 33
         return marker;
34 34
     };
35 35
     return HighlightMarker;

+ 3
- 3
dist/cjs/markers/LineMarker/index.js View File

@@ -22,14 +22,14 @@ var LineMarker = (function (_super) {
22 22
         _this.type = 'line';
23 23
         return _this;
24 24
     }
25
-    LineMarker.prototype.setup = function () {
26
-        _super.prototype.setup.call(this);
25
+    LineMarker.prototype.init = function () {
26
+        _super.prototype.init.call(this);
27 27
         index_1.SvgHelper.setAttributes(this.visual, [['class', 'line-marker']]);
28 28
     };
29 29
     LineMarker.createMarker = function (page) {
30 30
         var marker = new LineMarker();
31 31
         marker.page = page;
32
-        marker.setup();
32
+        marker.init();
33 33
         return marker;
34 34
     };
35 35
     return LineMarker;

+ 46
- 17
dist/cjs/markers/LinearMarker/index.js View File

@@ -55,22 +55,11 @@ var LinearMarker = (function (_super) {
55 55
             grip.visual.addEventListener('touchstart', _this.onTouch, { passive: false });
56 56
             grip.visual.addEventListener('touchend', _this.onTouch, { passive: false });
57 57
             grip.visual.addEventListener('touchmove', _this.onTouch, { passive: false });
58
+            if (_this.page && _this.page.mode === 'mirror') {
59
+                grip.visual.style.visibility = 'hidden';
60
+            }
58 61
             return grip;
59 62
         };
60
-        _this.positionGrips = function () {
61
-            var gripSize = _this.controlGrips.left.GRIP_SIZE;
62
-            var x1 = _this.x1 - gripSize / 2;
63
-            var y1 = _this.y1 - gripSize / 2;
64
-            var x2 = _this.x2 - gripSize / 2;
65
-            var y2 = _this.y2 - gripSize / 2;
66
-            _this.positionGrip(_this.controlGrips.left.visual, x1, y1);
67
-            _this.positionGrip(_this.controlGrips.right.visual, x2, y2);
68
-        };
69
-        _this.positionGrip = function (grip, x, y) {
70
-            var translate = grip.transform.baseVal.getItem(0);
71
-            translate.setTranslate(x, y);
72
-            grip.transform.baseVal.replaceItem(translate, 0);
73
-        };
74 63
         _this.gripMouseDown = function (ev) {
75 64
             _this.isResizing = true;
76 65
             _this.activeGrip =
@@ -91,8 +80,48 @@ var LinearMarker = (function (_super) {
91 80
                 _this.resize(ev.movementX, ev.movementY);
92 81
             }
93 82
         };
83
+        _this.positionLine = function (bound) {
84
+            _this.x1 = bound.x1;
85
+            _this.y1 = bound.y1;
86
+            _this.x2 = bound.x2;
87
+            _this.y2 = bound.y2;
88
+            _this.markerBgLine.setAttribute('x1', _this.x1.toString());
89
+            _this.markerBgLine.setAttribute('y1', _this.y1.toString());
90
+            _this.markerLine.setAttribute('x2', _this.x2.toString());
91
+            _this.markerLine.setAttribute('y2', _this.y2.toString());
92
+        };
93
+        _this.positionGrips = function () {
94
+            var gripSize = _this.controlGrips.left.GRIP_SIZE;
95
+            var x1 = _this.x1 - gripSize / 2;
96
+            var y1 = _this.y1 - gripSize / 2;
97
+            var x2 = _this.x2 - gripSize / 2;
98
+            var y2 = _this.y2 - gripSize / 2;
99
+            _this.positionGrip(_this.controlGrips.left.visual, x1, y1);
100
+            _this.positionGrip(_this.controlGrips.right.visual, x2, y2);
101
+        };
102
+        _this.positionGrip = function (grip, x, y) {
103
+            var translate = grip.transform.baseVal.getItem(0);
104
+            translate.setTranslate(x, y);
105
+            grip.transform.baseVal.replaceItem(translate, 0);
106
+        };
94 107
         return _this;
95 108
     }
109
+    LinearMarker.prototype.captureSnap = function () {
110
+        var baseSnap = _super.prototype.captureSnap.call(this);
111
+        baseSnap.linearSnap = {
112
+            x1: this.x1,
113
+            y1: this.y1,
114
+            x2: this.x2,
115
+            y2: this.y2
116
+        };
117
+        return baseSnap;
118
+    };
119
+    LinearMarker.prototype.applySnap = function (snap) {
120
+        _super.prototype.applySnap.call(this, snap);
121
+        if (snap.linearSnap) {
122
+            this.positionLine(snap.linearSnap);
123
+        }
124
+    };
96 125
     LinearMarker.prototype.endManipulation = function () {
97 126
         _super.prototype.endManipulation.call(this);
98 127
         this.isResizing = false;
@@ -106,8 +135,8 @@ var LinearMarker = (function (_super) {
106 135
         _super.prototype.deselect.call(this);
107 136
         this.controlBox.style.display = 'none';
108 137
     };
109
-    LinearMarker.prototype.setup = function () {
110
-        _super.prototype.setup.call(this);
138
+    LinearMarker.prototype.init = function () {
139
+        _super.prototype.init.call(this);
111 140
         this.markerBgLine = SvgHelper_1.SvgHelper.createLine(0, 0, this.x2, 0, [
112 141
             ['stroke', 'transparent'],
113 142
             ['stroke-width', '30']
@@ -161,7 +190,7 @@ var LinearMarker = (function (_super) {
161 190
     LinearMarker.createMarker = function (page) {
162 191
         var marker = new LinearMarker();
163 192
         marker.page = page;
164
-        marker.setup();
193
+        marker.init();
165 194
         return marker;
166 195
     };
167 196
     return LinearMarker;

+ 10
- 3
dist/cjs/markers/RectMarker/RectBaseMarker.js View File

@@ -20,8 +20,15 @@ var RectBaseMarker = (function (_super) {
20 20
     function RectBaseMarker() {
21 21
         return _super !== null && _super.apply(this, arguments) || this;
22 22
     }
23
-    RectBaseMarker.prototype.setup = function () {
24
-        _super.prototype.setup.call(this);
23
+    RectBaseMarker.prototype.applySnap = function (snap) {
24
+        _super.prototype.applySnap.call(this, snap);
25
+        if (snap.rectSnap) {
26
+            this.markerRect.setAttribute('width', this.width.toString());
27
+            this.markerRect.setAttribute('height', this.height.toString());
28
+        }
29
+    };
30
+    RectBaseMarker.prototype.init = function () {
31
+        _super.prototype.init.call(this);
25 32
         this.markerRect = SvgHelper_1.SvgHelper.createRect(this.width, this.height);
26 33
         this.addToRenderVisual(this.markerRect);
27 34
     };
@@ -33,7 +40,7 @@ var RectBaseMarker = (function (_super) {
33 40
     RectBaseMarker.createMarker = function (page) {
34 41
         var marker = new RectBaseMarker();
35 42
         marker.page = page;
36
-        marker.setup();
43
+        marker.init();
37 44
         return marker;
38 45
     };
39 46
     return RectBaseMarker;

+ 3
- 3
dist/cjs/markers/RectMarker/index.js View File

@@ -22,14 +22,14 @@ var RectMarker = (function (_super) {
22 22
         _this.type = 'rect';
23 23
         return _this;
24 24
     }
25
-    RectMarker.prototype.setup = function () {
26
-        _super.prototype.setup.call(this);
25
+    RectMarker.prototype.init = function () {
26
+        _super.prototype.init.call(this);
27 27
         SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'rect-marker']]);
28 28
     };
29 29
     RectMarker.createMarker = function (page) {
30 30
         var marker = new RectMarker();
31 31
         marker.page = page;
32
-        marker.setup();
32
+        marker.init();
33 33
         return marker;
34 34
     };
35 35
     return RectMarker;

+ 66
- 41
dist/cjs/markers/RectangularMarker/index.js View File

@@ -62,6 +62,23 @@ var RectangularMarker = (function (_super) {
62 62
             grip.visual.addEventListener('touchmove', _this.onTouch, { passive: false });
63 63
             return grip;
64 64
         };
65
+        _this.gripMouseDown = function (ev) {
66
+            _this.isResizing = true;
67
+            _this.activeGrip = _this.controlGrips.findGripByVisual(ev.target) || null;
68
+            _this.previousMouseX = ev.screenX;
69
+            _this.previousMouseY = ev.screenY;
70
+            ev.stopPropagation();
71
+        };
72
+        _this.gripMouseUp = function (ev) {
73
+            _this.isResizing = false;
74
+            _this.activeGrip = null;
75
+            ev.stopPropagation();
76
+        };
77
+        _this.gripMouseMove = function (ev) {
78
+            if (_this.isResizing) {
79
+                _this.manipulate(ev);
80
+            }
81
+        };
65 82
         _this.positionGrips = function () {
66 83
             var gripSize = _this.controlGrips.topLeft.GRIP_SIZE;
67 84
             var left = -gripSize / 2;
@@ -84,25 +101,27 @@ var RectangularMarker = (function (_super) {
84 101
             translate.setTranslate(x, y);
85 102
             grip.transform.baseVal.replaceItem(translate, 0);
86 103
         };
87
-        _this.gripMouseDown = function (ev) {
88
-            _this.isResizing = true;
89
-            _this.activeGrip = _this.controlGrips.findGripByVisual(ev.target) || null;
90
-            _this.previousMouseX = ev.screenX;
91
-            _this.previousMouseY = ev.screenY;
92
-            ev.stopPropagation();
93
-        };
94
-        _this.gripMouseUp = function (ev) {
95
-            _this.isResizing = false;
96
-            _this.activeGrip = null;
97
-            ev.stopPropagation();
98
-        };
99
-        _this.gripMouseMove = function (ev) {
100
-            if (_this.isResizing) {
101
-                _this.manipulate(ev);
102
-            }
103
-        };
104 104
         return _this;
105 105
     }
106
+    RectangularMarker.prototype.captureSnap = function () {
107
+        var snap = _super.prototype.captureSnap.call(this);
108
+        snap.rectSnap = {
109
+            width: this.width,
110
+            height: this.height
111
+        };
112
+        return snap;
113
+    };
114
+    RectangularMarker.prototype.applySnap = function (snap) {
115
+        _super.prototype.applySnap.call(this, snap);
116
+        if (snap.rectSnap) {
117
+            var _a = snap.rectSnap, width = _a.width, height = _a.height;
118
+            if (width && height) {
119
+                this.width = width;
120
+                this.height = height;
121
+                this.adjustControlBox();
122
+            }
123
+        }
124
+    };
106 125
     RectangularMarker.prototype.endManipulation = function () {
107 126
         _super.prototype.endManipulation.call(this);
108 127
         this.isResizing = false;
@@ -116,75 +135,81 @@ var RectangularMarker = (function (_super) {
116 135
         _super.prototype.deselect.call(this);
117 136
         this.controlBox.style.display = 'none';
118 137
     };
119
-    RectangularMarker.prototype.setup = function () {
120
-        _super.prototype.setup.call(this);
138
+    RectangularMarker.prototype.init = function () {
139
+        _super.prototype.init.call(this);
121 140
         this.addControlBox();
122 141
         if (this.page && this.page.mode === 'mirror') {
123 142
             this.controlBox.style.display = 'none';
124 143
         }
125 144
     };
126
-    RectangularMarker.prototype.resizeByEvent = function (x, y, pos) {
145
+    RectangularMarker.prototype.resizeByEvent = function (dx, dy, pos) {
127 146
         this.activeGrip = this.controlGrips[pos];
128
-        this.resize(x, y);
147
+        this.resize(dx, dy);
129 148
     };
130
-    RectangularMarker.prototype.resize = function (x, y, onPosition) {
149
+    RectangularMarker.prototype.resize = function (dx, dy, onPosition) {
131 150
         var translateX = 0;
132 151
         var translateY = 0;
133 152
         switch (this.activeGrip) {
134 153
             case this.controlGrips.topLeft:
135
-                this.width -= x;
136
-                this.height -= y;
137
-                translateX += x;
138
-                translateY += y;
154
+                this.width -= dx;
155
+                this.height -= dy;
156
+                translateX += dx;
157
+                translateY += dy;
158
+                this.x += dx;
159
+                this.y += dy;
139 160
                 if (onPosition) {
140 161
                     onPosition('topLeft');
141 162
                 }
142 163
                 break;
143 164
             case this.controlGrips.bottomLeft:
144
-                this.width -= x;
145
-                this.height += y;
146
-                translateX += x;
165
+                this.width -= dx;
166
+                this.height += dy;
167
+                translateX += dx;
168
+                this.x += dx;
147 169
                 if (onPosition) {
148 170
                     onPosition('bottomLeft');
149 171
                 }
150 172
                 break;
151 173
             case this.controlGrips.topRight:
152
-                this.width += x;
153
-                this.height -= y;
154
-                translateY += y;
174
+                this.width += dx;
175
+                this.height -= dy;
176
+                translateY += dy;
177
+                this.y += dy;
155 178
                 if (onPosition) {
156 179
                     onPosition('topRight');
157 180
                 }
158 181
                 break;
159 182
             case this.controlGrips.bottomRight:
160
-                this.width += x;
161
-                this.height += y;
183
+                this.width += dx;
184
+                this.height += dy;
162 185
                 if (onPosition) {
163 186
                     onPosition('bottomRight');
164 187
                 }
165 188
                 break;
166 189
             case this.controlGrips.centerLeft:
167
-                this.width -= x;
168
-                translateX += x;
190
+                this.width -= dx;
191
+                translateX += dx;
192
+                this.x += dx;
169 193
                 if (onPosition) {
170 194
                     onPosition('centerLeft');
171 195
                 }
172 196
                 break;
173 197
             case this.controlGrips.centerRight:
174
-                this.width += x;
198
+                this.width += dx;
175 199
                 if (onPosition) {
176 200
                     onPosition('centerRight');
177 201
                 }
178 202
                 break;
179 203
             case this.controlGrips.topCenter:
180
-                this.height -= y;
181
-                translateY += y;
204
+                this.height -= dy;
205
+                translateY += dy;
206
+                this.y += dy;
182 207
                 if (onPosition) {
183 208
                     onPosition('topCenter');
184 209
                 }
185 210
                 break;
186 211
             case this.controlGrips.bottomCenter:
187
-                this.height += y;
212
+                this.height += dy;
188 213
                 if (onPosition) {
189 214
                     onPosition('bottomCenter');
190 215
                 }
@@ -219,7 +244,7 @@ var RectangularMarker = (function (_super) {
219 244
     RectangularMarker.createMarker = function (page) {
220 245
         var marker = new RectangularMarker();
221 246
         marker.page = page;
222
-        marker.setup();
247
+        marker.init();
223 248
         return marker;
224 249
     };
225 250
     return RectangularMarker;

+ 20
- 4
dist/cjs/markers/TextMarker/index.js View File

@@ -102,7 +102,12 @@ var TextMarker = (function (_super) {
102 102
             else {
103 103
                 _this.text = _this.DEFAULT_TEXT;
104 104
             }
105
-            _this.onChange({ target: 'marker', id: _this.id, event: 'changeText', data: _this.text });
105
+            _this.onChange({
106
+                target: 'marker',
107
+                id: _this.id,
108
+                event: 'inputMarker',
109
+                marker: { text: _this.text }
110
+            });
106 111
             _this.renderText();
107 112
             _this.closeEditor();
108 113
         };
@@ -121,8 +126,19 @@ var TextMarker = (function (_super) {
121 126
         this.text = text;
122 127
         this.renderText();
123 128
     };
124
-    TextMarker.prototype.setup = function () {
125
-        _super.prototype.setup.call(this);
129
+    TextMarker.prototype.captureSnap = function () {
130
+        var baseSnap = _super.prototype.captureSnap.call(this);
131
+        baseSnap.textSnap = { text: this.text };
132
+        return baseSnap;
133
+    };
134
+    TextMarker.prototype.applySnap = function (snap) {
135
+        _super.prototype.applySnap.call(this, snap);
136
+        if (snap.textSnap && snap.textSnap.text !== this.text) {
137
+            this.setText(snap.textSnap.text);
138
+        }
139
+    };
140
+    TextMarker.prototype.init = function () {
141
+        _super.prototype.init.call(this);
126 142
         this.textElement = SvgHelper_1.SvgHelper.createText();
127 143
         this.addToRenderVisual(this.textElement);
128 144
         SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'text-marker']]);
@@ -139,7 +155,7 @@ var TextMarker = (function (_super) {
139 155
     TextMarker.createMarker = function (page) {
140 156
         var marker = new TextMarker();
141 157
         marker.page = page;
142
-        marker.setup();
158
+        marker.init();
143 159
         return marker;
144 160
     };
145 161
     return TextMarker;

+ 41
- 0
dist/cjs/renderer/DomEventAware/index.js View File

@@ -0,0 +1,41 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var DomEventAware = (function () {
4
+    function DomEventAware() {
5
+        this.x = 0;
6
+        this.y = 0;
7
+        this.previousMouseX = 0;
8
+        this.previousMouseY = 0;
9
+    }
10
+    DomEventAware.prototype.init = function (ele) {
11
+        ele.addEventListener('mousedown', this.onMouseDown);
12
+        ele.addEventListener('mouseup', this.onMouseUp);
13
+        ele.addEventListener('mousemove', this.onMouseMove);
14
+        ele.addEventListener('touchstart', this.onTouch, { passive: false });
15
+        ele.addEventListener('touchend', this.onTouch, { passive: false });
16
+        ele.addEventListener('touchmove', this.onTouch, { passive: false });
17
+    };
18
+    DomEventAware.prototype.onTouch = function (ev) {
19
+        ev.preventDefault();
20
+        var newEvt = document.createEvent('MouseEvents');
21
+        var touch = ev.changedTouches[0];
22
+        var type = null;
23
+        switch (ev.type) {
24
+            case 'touchstart':
25
+                type = 'mousedown';
26
+                break;
27
+            case 'touchmove':
28
+                type = 'mousemove';
29
+                break;
30
+            case 'touchend':
31
+                type = 'mouseup';
32
+                break;
33
+            default:
34
+                break;
35
+        }
36
+        newEvt.initMouseEvent(type, true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey, 0, null);
37
+        ev.target.dispatchEvent(newEvt);
38
+    };
39
+    return DomEventAware;
40
+}());
41
+exports.DomEventAware = DomEventAware;

+ 1
- 1
dist/cjs/renderer/Synthetizer/index.js View File

@@ -6,7 +6,7 @@ var Synthetizer = (function () {
6 6
     }
7 7
     Synthetizer.prototype.rasterize = function (target, markerImage, done) {
8 8
         if (!validator_1.isHTMLImageElement(target)) {
9
-            throw new Error('Error: only support export HTMLImageElement');
9
+            throw new Error('Error: only support export to HTMLImageElement');
10 10
         }
11 11
         var canvas = document.createElement('canvas');
12 12
         canvas.width = markerImage.width.baseVal.value;

+ 58
- 8
dist/cjs/toolbar/Toolbar.js View File

@@ -1,33 +1,83 @@
1 1
 "use strict";
2
+var __extends = (this && this.__extends) || (function () {
3
+    var extendStatics = function (d, b) {
4
+        extendStatics = Object.setPrototypeOf ||
5
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+        return extendStatics(d, b);
8
+    };
9
+    return function (d, b) {
10
+        extendStatics(d, b);
11
+        function __() { this.constructor = d; }
12
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+    };
14
+})();
2 15
 Object.defineProperty(exports, "__esModule", { value: true });
16
+var interactjs_1 = require("interactjs");
3 17
 var ToolbarButton_1 = require("./ToolbarButton");
4 18
 var uuid_1 = require("../utils/uuid");
5
-var Toolbar = (function () {
19
+require("./index.less");
20
+var index_1 = require("../renderer/DomEventAware/index");
21
+var toolbar_items_1 = require("./toolbar-items");
22
+var Toolbar = (function (_super) {
23
+    __extends(Toolbar, _super);
6 24
     function Toolbar(toolbarItems, clickHandler) {
7
-        var _this = this;
8
-        this.id = uuid_1.uuid();
9
-        this.getUI = function () {
25
+        var _this = _super.call(this) || this;
26
+        _this.id = uuid_1.uuid();
27
+        _this.zIndex = 999;
28
+        _this.toolbarButtons = [];
29
+        _this.getUI = function (drawboard) {
10 30
             _this.toolbarUI = document.createElement('div');
11 31
             _this.toolbarUI.id = "fcw-toolbar-" + _this.id;
12 32
             _this.toolbarUI.className = 'fc-whiteboard-toolbar';
13 33
             for (var _i = 0, _a = _this.toolbarItems; _i < _a.length; _i++) {
14 34
                 var toolbarItem = _a[_i];
15 35
                 var toolbarButton = new ToolbarButton_1.ToolbarButton(toolbarItem, _this.clickHandler);
36
+                toolbarButton.drawboard = drawboard;
16 37
                 _this.toolbarUI.appendChild(toolbarButton.getElement());
38
+                _this.toolbarButtons.push(toolbarButton);
17 39
             }
40
+            _super.prototype.init.call(_this, _this.toolbarUI);
41
+            interactjs_1.default('#drag-handler').draggable({
42
+                onmove: _this.onDragMove
43
+            });
18 44
             return _this.toolbarUI;
19 45
         };
20
-        this.toolbarItems = toolbarItems;
21
-        this.clickHandler = clickHandler;
46
+        _this.onMouseDown = function (downEv) { };
47
+        _this.onMouseUp = function (ev) { };
48
+        _this.onMouseMove = function (ev) { };
49
+        _this.onDragMove = function (event) {
50
+            var target = _this.toolbarUI;
51
+            var x = ((parseFloat(target.getAttribute('data-x')) || 0) + event.dx);
52
+            var y = ((parseFloat(target.getAttribute('data-y')) || 0) + event.dy);
53
+            target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
54
+            target.style.zIndex = "" + _this.zIndex;
55
+            target.setAttribute('data-x', x);
56
+            target.setAttribute('data-y', y);
57
+        };
58
+        _this.toolbarItems = [toolbar_items_1.dragToolbarItem].concat(toolbarItems);
59
+        _this.clickHandler = clickHandler;
60
+        return _this;
22 61
     }
62
+    Object.defineProperty(Toolbar.prototype, "toolbarButtonMap", {
63
+        get: function () {
64
+            var buttonMap = {};
65
+            this.toolbarButtons.forEach(function (b) {
66
+                buttonMap[b.id] = b;
67
+            });
68
+            return buttonMap;
69
+        },
70
+        enumerable: true,
71
+        configurable: true
72
+    });
23 73
     Toolbar.prototype.hide = function () {
24 74
         this.toolbarUI.style.visibility = 'hidden';
25 75
         this.toolbarUI.style.zIndex = '-1';
26 76
     };
27 77
     Toolbar.prototype.show = function () {
28 78
         this.toolbarUI.style.visibility = 'visible';
29
-        this.toolbarUI.style.zIndex = '999';
79
+        this.toolbarUI.style.zIndex = "" + this.zIndex;
30 80
     };
31 81
     return Toolbar;
32
-}());
82
+}(index_1.DomEventAware));
33 83
 exports.Toolbar = Toolbar;

+ 18
- 2
dist/cjs/toolbar/ToolbarButton.js View File

@@ -1,9 +1,16 @@
1 1
 "use strict";
2 2
 Object.defineProperty(exports, "__esModule", { value: true });
3
+var tippy_js_1 = require("tippy.js");
4
+var uuid_1 = require("../utils/uuid");
3 5
 var ToolbarButton = (function () {
4 6
     function ToolbarButton(toolbarItem, clickHandler) {
5 7
         var _this = this;
8
+        this.id = uuid_1.uuid();
6 9
         this.getElement = function () {
10
+            if (_this.toolbarItem.onRender) {
11
+                _this.container = _this.toolbarItem.onRender().cloneNode(true);
12
+                return _this.container;
13
+            }
7 14
             var div = document.createElement('div');
8 15
             if (_this.toolbarItem.name !== 'separator') {
9 16
                 div.className = 'fc-whiteboard-toolbar-button';
@@ -15,16 +22,25 @@ var ToolbarButton = (function () {
15 22
                     });
16 23
                 }
17 24
                 if (_this.toolbarItem.icon) {
18
-                    div.title = _this.toolbarItem.tooltipText;
25
+                    div.title = _this.toolbarItem.tooltipText || '';
19 26
                     div.innerHTML = _this.toolbarItem.icon;
20 27
                 }
21 28
                 else {
22
-                    div.innerText = _this.toolbarItem.tooltipText;
29
+                    div.innerText = _this.toolbarItem.tooltipText || '';
30
+                }
31
+                if (_this.toolbarItem.tooltipText) {
32
+                    tippy_js_1.default(div, {
33
+                        content: _this.toolbarItem.shortcut
34
+                            ? _this.toolbarItem.tooltipText + " " + _this.toolbarItem.shortcut
35
+                            : _this.toolbarItem.tooltipText
36
+                    });
23 37
                 }
24 38
             }
25 39
             else {
26 40
                 div.className = 'fc-whiteboard-toolbar-separator';
27 41
             }
42
+            div.id = "fc-whiteboard-toolbar-" + _this.toolbarItem.name;
43
+            _this.container = div;
28 44
             return div;
29 45
         };
30 46
         this.toolbarItem = toolbarItem;

+ 8
- 1
dist/cjs/toolbar/ToolbarItem.js View File

@@ -2,11 +2,18 @@
2 2
 Object.defineProperty(exports, "__esModule", { value: true });
3 3
 var ToolbarItem = (function () {
4 4
     function ToolbarItem(_a) {
5
-        var name = _a.name, tooltipText = _a.tooltipText, icon = _a.icon, markerType = _a.markerType;
5
+        var name = _a.name, tooltipText = _a.tooltipText, shortcut = _a.shortcut, icon = _a.icon, draggable = _a.draggable, markerType = _a.markerType, onRender = _a.onRender, onClick = _a.onClick;
6
+        if (!name) {
7
+            throw new Error('Invalid params');
8
+        }
6 9
         this.name = name;
7 10
         this.tooltipText = tooltipText;
11
+        this.shortcut = shortcut;
8 12
         this.icon = icon;
9 13
         this.markerType = markerType;
14
+        this.draggable = draggable;
15
+        this.onClick = onClick;
16
+        this.onRender = onRender;
10 17
     }
11 18
     return ToolbarItem;
12 19
 }());

+ 31
- 27
dist/cjs/toolbar/toolbar-items.js View File

@@ -9,70 +9,79 @@ var ToolbarItem_1 = require("./ToolbarItem");
9 9
 var LineMarker_1 = require("../markers/LineMarker");
10 10
 var OkIcon = require('../assets/check.svg');
11 11
 var DeleteIcon = require('../assets/eraser.svg');
12
-var PointerIcon = require('../assets/mouse-pointer.svg');
13 12
 var CloseIcon = require('../assets/times.svg');
13
+exports.dragToolbarItem = new ToolbarItem_1.ToolbarItem({
14
+    name: 'drag',
15
+    tooltipText: 'Drag',
16
+    icon: require('../assets/drag.svg')
17
+});
14 18
 exports.highlightMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
15 19
     name: 'cover-marker',
16
-    tooltipText: 'Cover',
20
+    tooltipText: 'Hightlight',
21
+    shortcut: 'Shift+H',
17 22
     icon: require('../assets/highlight.svg'),
18
-    markerType: index_5.HighlightMarker
23
+    markerType: index_5.HighlightMarker,
24
+    draggable: true
19 25
 });
20 26
 exports.arrowMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
21 27
     name: 'arrow-marker',
22 28
     tooltipText: 'Arrow',
29
+    shortcut: 'Shift+A',
23 30
     icon: require('../assets/arrow.svg'),
24
-    markerType: index_4.ArrowMarker
31
+    markerType: index_4.ArrowMarker,
32
+    draggable: true
25 33
 });
26 34
 exports.textMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
27 35
     name: 'text-marker',
28 36
     tooltipText: 'Text',
37
+    shortcut: 'Shift+T',
29 38
     icon: require('../assets/text.svg'),
30
-    markerType: index_3.TextMarker
39
+    markerType: index_3.TextMarker,
40
+    draggable: true
31 41
 });
32 42
 exports.coverMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
33 43
     name: 'cover-marker',
34 44
     tooltipText: 'Cover',
45
+    shortcut: 'Shift+C',
35 46
     icon: require('../assets/cover.svg'),
36
-    markerType: index_2.CoverMarker
47
+    markerType: index_2.CoverMarker,
48
+    draggable: true
37 49
 });
38 50
 exports.rectMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
39 51
     name: 'rect-marker',
40 52
     tooltipText: 'Rectangle',
53
+    shortcut: 'Shift+R',
41 54
     icon: require('../assets/rect.svg'),
42
-    markerType: index_1.RectMarker
55
+    markerType: index_1.RectMarker,
56
+    draggable: true
43 57
 });
44 58
 exports.lineMarkerToolbarItem = new ToolbarItem_1.ToolbarItem({
45 59
     name: 'line-marker',
46 60
     tooltipText: 'Line',
61
+    shortcut: 'Shift+L',
47 62
     icon: require('../assets/line.svg'),
48
-    markerType: LineMarker_1.LineMarker
63
+    markerType: LineMarker_1.LineMarker,
64
+    draggable: true
49 65
 });
66
+exports.closeToolbarItem = new ToolbarItem_1.ToolbarItem({
67
+    icon: CloseIcon,
68
+    name: 'close',
69
+    tooltipText: 'Close'
70
+});
71
+exports.separatorToolbarItem = new ToolbarItem_1.ToolbarItem({ name: 'separator', tooltipText: '' });
50 72
 function getToolbars(page) {
51 73
     var toolbars = [
52
-        {
53
-            icon: PointerIcon,
54
-            name: 'pointer',
55
-            tooltipText: 'Pointer'
56
-        },
57 74
         {
58 75
             icon: DeleteIcon,
59 76
             name: 'delete',
60 77
             tooltipText: 'Delete'
61 78
         },
62
-        {
63
-            name: 'separator',
64
-            tooltipText: ''
65
-        },
66 79
         exports.rectMarkerToolbarItem,
67 80
         exports.coverMarkerToolbarItem,
68 81
         exports.highlightMarkerToolbarItem,
69 82
         exports.lineMarkerToolbarItem,
70 83
         exports.arrowMarkerToolbarItem,
71
-        exports.textMarkerToolbarItem,
72
-        {
73
-            name: 'separator',
74
-            tooltipText: ''
75
-        }
84
+        exports.textMarkerToolbarItem
76 85
     ];
77 86
     if (!page) {
78 87
         toolbars.push.apply(toolbars, [
@@ -83,11 +92,6 @@ function getToolbars(page) {
83 92
             }
84 93
         ]);
85 94
     }
86
-    toolbars.push({
87
-        icon: CloseIcon,
88
-        name: 'close',
89
-        tooltipText: 'Close'
90
-    });
91 95
     return toolbars;
92 96
 }
93 97
 exports.getToolbars = getToolbars;

+ 10
- 0
dist/cjs/utils/layout.js View File

@@ -0,0 +1,10 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+function rectContains(rect, _a) {
4
+    var x = _a.x, y = _a.y;
5
+    if (x < rect.left || x > rect.left + rect.width || y < rect.top || y > rect.top + rect.height) {
6
+        return false;
7
+    }
8
+    return true;
9
+}
10
+exports.rectContains = rectContains;

+ 6
- 0
dist/cjs/utils/types.js View File

@@ -0,0 +1,6 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+function isNil(mayBeNil) {
4
+    return mayBeNil === null || mayBeNil === undefined;
5
+}
6
+exports.isNil = isNil;

+ 206
- 0
dist/cjs/whiteboard/AbstractWhiteboard/index.js View File

@@ -0,0 +1,206 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var index_1 = require("../WhitePage/index");
4
+var uuid_1 = require("../../utils/uuid");
5
+var dom_1 = require("../../utils/dom");
6
+require("./index.less");
7
+var Siema = require("siema");
8
+var prefix = 'fcw-board';
9
+var AbstractWhiteboard = (function () {
10
+    function AbstractWhiteboard(target, _a) {
11
+        var _b = _a === void 0 ? {} : _a, sources = _b.sources, eventHub = _b.eventHub, visiblePageIndex = _b.visiblePageIndex, allowRollback = _b.allowRollback, onlyEmitSnap = _b.onlyEmitSnap;
12
+        this.id = uuid_1.uuid();
13
+        this.sources = [];
14
+        this.imgEles = [];
15
+        this.allowRollback = false;
16
+        this.onlyEmitSnap = false;
17
+        this.snapInterval = 15 * 1000;
18
+        this.mode = 'master';
19
+        this.isFullscreen = false;
20
+        this.pages = [];
21
+        this.snapHistory = [];
22
+        this.isInitialized = false;
23
+        this.isSyncing = false;
24
+        this.visiblePageIndex = 0;
25
+        if (target) {
26
+            this.target = target;
27
+        }
28
+        else {
29
+            this.target = document.createElement('div');
30
+            document.body.appendChild(this.target);
31
+        }
32
+        if (!this.target.id) {
33
+            this.target.id = this.id;
34
+        }
35
+        dom_1.addClassName(this.target, prefix);
36
+        if (sources) {
37
+            this.sources = sources;
38
+        }
39
+        this.eventHub = eventHub;
40
+        if (typeof visiblePageIndex !== 'undefined') {
41
+            this.visiblePageIndex = visiblePageIndex;
42
+        }
43
+        this.onlyEmitSnap = !!onlyEmitSnap;
44
+        if (typeof allowRollback !== 'undefined') {
45
+            this.allowRollback = !!allowRollback;
46
+        }
47
+        this.init();
48
+    }
49
+    Object.defineProperty(AbstractWhiteboard.prototype, "activePage", {
50
+        get: function () {
51
+            return this.pages[this.visiblePageIndex];
52
+        },
53
+        enumerable: true,
54
+        configurable: true
55
+    });
56
+    Object.defineProperty(AbstractWhiteboard.prototype, "pageMap", {
57
+        get: function () {
58
+            var map = {};
59
+            this.pages.forEach(function (p) { return (map[p.id] = p); });
60
+            return map;
61
+        },
62
+        enumerable: true,
63
+        configurable: true
64
+    });
65
+    AbstractWhiteboard.prototype.open = function () {
66
+        var _this = this;
67
+        this.pages.forEach(function (page, i) {
68
+            page.open();
69
+            if (i !== _this.visiblePageIndex) {
70
+                page.hide();
71
+            }
72
+        });
73
+    };
74
+    AbstractWhiteboard.prototype.close = function () {
75
+        if (this.emitInterval) {
76
+            clearInterval(this.emitInterval);
77
+        }
78
+    };
79
+    AbstractWhiteboard.prototype.show = function () {
80
+        if (this.activePage) {
81
+            this.activePage.show();
82
+        }
83
+    };
84
+    AbstractWhiteboard.prototype.hide = function () {
85
+        if (this.activePage) {
86
+            this.activePage.hide();
87
+        }
88
+    };
89
+    AbstractWhiteboard.prototype.emit = function (borderEvent) {
90
+        if (this.mode !== 'master' || !this.eventHub) {
91
+            return;
92
+        }
93
+        if (this.onlyEmitSnap) {
94
+            if (borderEvent.event !== 'borderSnap') {
95
+                return;
96
+            }
97
+        }
98
+        if (this.allowRollback &&
99
+            (borderEvent.event === 'addMarker' || borderEvent.event === 'removeMarker')) {
100
+            if (this.snapHistory.length > 20) {
101
+                this.snapHistory.shift();
102
+            }
103
+            this.snapHistory.push(this.captureSnap(false));
104
+        }
105
+        borderEvent.timestamp = Math.floor(Date.now() / 1000);
106
+        this.eventHub.emit('sync', borderEvent);
107
+    };
108
+    AbstractWhiteboard.prototype.captureSnap = function (shadow) {
109
+        if (shadow === void 0) { shadow = true; }
110
+        if (shadow) {
111
+            return {
112
+                id: this.id,
113
+                sources: this.sources,
114
+                pageIds: this.pages.map(function (page) { return page.id; }),
115
+                visiblePageIndex: this.visiblePageIndex
116
+            };
117
+        }
118
+        return {
119
+            id: this.id,
120
+            sources: this.sources,
121
+            pageIds: this.pages.map(function (page) { return page.id; }),
122
+            visiblePageIndex: this.visiblePageIndex,
123
+            pages: this.pages.map(function (p) { return p.captureSnap(); })
124
+        };
125
+    };
126
+    AbstractWhiteboard.prototype.rollbackSnap = function () {
127
+        if (this.snapHistory.length === 0) {
128
+            return;
129
+        }
130
+        this.snapHistory.pop();
131
+        var snap = this.snapHistory[this.snapHistory.length - 1];
132
+        if (snap) {
133
+            this.applySnap(snap);
134
+        }
135
+    };
136
+    AbstractWhiteboard.prototype.destroy = function () {
137
+        if (this.emitInterval) {
138
+            clearInterval(this.emitInterval);
139
+        }
140
+        if (this.eventHub) {
141
+            this.eventHub.removeAllListeners();
142
+        }
143
+        if (this.siema) {
144
+            this.siema.destroy();
145
+        }
146
+        this.imgsContainer.remove();
147
+        this.pagesContainer.remove();
148
+        this.pages.forEach(function (page) {
149
+            page.destroy();
150
+        });
151
+    };
152
+    AbstractWhiteboard.prototype.initSiema = function () {
153
+        var _this = this;
154
+        this.sources.forEach(function (source) {
155
+            var imgEle = document.createElement('div');
156
+            dom_1.addClassName(imgEle, prefix + "-img-wrapper");
157
+            imgEle.style.backgroundImage = "url(" + source + ")";
158
+            _this.imgEles.push(imgEle);
159
+            _this.imgsContainer.appendChild(imgEle);
160
+        });
161
+        this.siema = new Siema({
162
+            selector: this.imgsContainer,
163
+            duration: 200,
164
+            easing: 'ease-out',
165
+            perPage: 1,
166
+            startIndex: 0,
167
+            draggable: false,
168
+            multipleDrag: true,
169
+            threshold: 20,
170
+            loop: false,
171
+            rtl: false
172
+        });
173
+    };
174
+    AbstractWhiteboard.prototype.applySnap = function (snap) {
175
+        var _this = this;
176
+        var id = snap.id, sources = snap.sources, pageIds = snap.pageIds;
177
+        if (!this.isInitialized && !this.isSyncing) {
178
+            this.id = id;
179
+            this.sources = sources;
180
+            this.isSyncing = true;
181
+            this.sources.forEach(function (source, i) {
182
+                var page = new index_1.WhitePage({ imgSrc: source }, {
183
+                    mode: _this.mode,
184
+                    whiteboard: _this,
185
+                    parentContainer: _this.pagesContainer
186
+                });
187
+                page.id = pageIds[i];
188
+                page.container.style.visibility = 'hidden';
189
+                _this.pages.push(page);
190
+                page.open();
191
+            });
192
+            this.initSiema();
193
+            this.isInitialized = true;
194
+            this.isSyncing = false;
195
+        }
196
+        this.onPageChange(snap.visiblePageIndex);
197
+        (snap.pages || []).forEach(function (pageSnap) {
198
+            var page = _this.pageMap[pageSnap.id];
199
+            if (page) {
200
+                page.applySnap(pageSnap);
201
+            }
202
+        });
203
+    };
204
+    return AbstractWhiteboard;
205
+}());
206
+exports.AbstractWhiteboard = AbstractWhiteboard;

+ 20
- 0
dist/cjs/whiteboard/AbstractWhiteboard/snap.js View File

@@ -0,0 +1,20 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var WhiteboardSnap = (function () {
4
+    function WhiteboardSnap() {
5
+    }
6
+    return WhiteboardSnap;
7
+}());
8
+exports.WhiteboardSnap = WhiteboardSnap;
9
+var WhitepageSnap = (function () {
10
+    function WhitepageSnap() {
11
+    }
12
+    return WhitepageSnap;
13
+}());
14
+exports.WhitepageSnap = WhitepageSnap;
15
+var MarkerSnap = (function () {
16
+    function MarkerSnap() {
17
+    }
18
+    return MarkerSnap;
19
+}());
20
+exports.MarkerSnap = MarkerSnap;

+ 76
- 0
dist/cjs/whiteboard/MirrorWhiteboard/index.js View File

@@ -0,0 +1,76 @@
1
+"use strict";
2
+var __extends = (this && this.__extends) || (function () {
3
+    var extendStatics = function (d, b) {
4
+        extendStatics = Object.setPrototypeOf ||
5
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+        return extendStatics(d, b);
8
+    };
9
+    return function (d, b) {
10
+        extendStatics(d, b);
11
+        function __() { this.constructor = d; }
12
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+    };
14
+})();
15
+Object.defineProperty(exports, "__esModule", { value: true });
16
+var dom_1 = require("../../utils/dom");
17
+var index_1 = require("../AbstractWhiteboard/index");
18
+var prefix = 'fcw-board';
19
+var MirrorWhiteboard = (function (_super) {
20
+    __extends(MirrorWhiteboard, _super);
21
+    function MirrorWhiteboard() {
22
+        var _this = _super !== null && _super.apply(this, arguments) || this;
23
+        _this.mode = 'mirror';
24
+        return _this;
25
+    }
26
+    MirrorWhiteboard.prototype.init = function () {
27
+        var _this = this;
28
+        this.imgsContainer = dom_1.createDivWithClassName(prefix + "-imgs", this.target);
29
+        this.pagesContainer = dom_1.createDivWithClassName(prefix + "-pages", this.target);
30
+        if (!this.eventHub) {
31
+            throw new Error('Invalid eventHub');
32
+        }
33
+        this.eventHub.on('sync', function (ev) {
34
+            if (ev.target !== 'whiteboard' || !ev.border) {
35
+                return;
36
+            }
37
+            if (ev.event === 'borderSnap') {
38
+                _this.applySnap(ev.border);
39
+            }
40
+            if (ev.event === 'borderChangePage' && ev.id === _this.id) {
41
+                if (_this.isInitialized) {
42
+                    _this.onPageChange(ev.border.visiblePageIndex);
43
+                }
44
+            }
45
+            if (ev.event === 'finish' && ev.id === _this.id) {
46
+                _this.destroy();
47
+            }
48
+        });
49
+    };
50
+    MirrorWhiteboard.prototype.destroy = function () {
51
+        _super.prototype.destroy.call(this);
52
+    };
53
+    MirrorWhiteboard.prototype.onPageChange = function (nextPageIndex) {
54
+        if (this.visiblePageIndex === nextPageIndex) {
55
+            return;
56
+        }
57
+        this.siema.goTo(nextPageIndex);
58
+        this.visiblePageIndex = nextPageIndex;
59
+        this.pages.forEach(function (page, i) {
60
+            if (nextPageIndex === i) {
61
+                page.show();
62
+            }
63
+            else {
64
+                page.hide();
65
+            }
66
+        });
67
+        this.emit({
68
+            event: 'borderChangePage',
69
+            id: this.id,
70
+            target: 'whiteboard',
71
+            border: this.captureSnap()
72
+        });
73
+    };
74
+    return MirrorWhiteboard;
75
+}(index_1.AbstractWhiteboard));
76
+exports.MirrorWhiteboard = MirrorWhiteboard;

+ 103
- 0
dist/cjs/whiteboard/ReplayWhiteboard/index.js View File

@@ -0,0 +1,103 @@
1
+"use strict";
2
+var __extends = (this && this.__extends) || (function () {
3
+    var extendStatics = function (d, b) {
4
+        extendStatics = Object.setPrototypeOf ||
5
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+        return extendStatics(d, b);
8
+    };
9
+    return function (d, b) {
10
+        extendStatics(d, b);
11
+        function __() { this.constructor = d; }
12
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+    };
14
+})();
15
+Object.defineProperty(exports, "__esModule", { value: true });
16
+var MirrorWhiteboard_1 = require("../MirrorWhiteboard");
17
+var EventHub_1 = require("../../event/EventHub");
18
+var windowSize = 60 * 1000;
19
+var duration = 0.05;
20
+var ReplayWhiteboard = (function (_super) {
21
+    __extends(ReplayWhiteboard, _super);
22
+    function ReplayWhiteboard() {
23
+        var _this = _super !== null && _super.apply(this, arguments) || this;
24
+        _this.leftEvents = [];
25
+        _this.currentRelativeTime = 0;
26
+        _this.loadedRelativeTime = -1;
27
+        _this.loadingLock = false;
28
+        _this.seekingLock = false;
29
+        _this.seek = function () {
30
+            if (_this.seekingLock) {
31
+                return;
32
+            }
33
+            _this.seekingLock = true;
34
+            if (_this.loadedRelativeTime < _this.currentRelativeTime) {
35
+                _this.loadEvents();
36
+            }
37
+            var waitingEvents = [];
38
+            var leftEvents = [];
39
+            _this.leftEvents.forEach(function (e, i) {
40
+                if (e.timestamp && e.timestamp < _this.currentRelativeTime + _this.recordStartTime) {
41
+                    waitingEvents.push(e);
42
+                }
43
+                else {
44
+                    leftEvents.push(e);
45
+                }
46
+            });
47
+            _this.leftEvents = leftEvents;
48
+            waitingEvents.forEach(function (e) {
49
+                _this.perform(e);
50
+            });
51
+            _this.currentRelativeTime += duration;
52
+            _this.seekingLock = false;
53
+        };
54
+        _this.perform = function (e) {
55
+            _this.eventHub.emit('sync', e);
56
+        };
57
+        return _this;
58
+    }
59
+    ReplayWhiteboard.prototype.setContext = function (recordStartTime, onLoad) {
60
+        var _this = this;
61
+        this.recordStartTime = recordStartTime;
62
+        this.onLoad = onLoad;
63
+        if (this.interval) {
64
+            clearInterval(this.interval);
65
+        }
66
+        this.interval = setInterval(function () {
67
+            _this.seek();
68
+        }, duration * 1000);
69
+    };
70
+    ReplayWhiteboard.prototype.setCurrentRelativeTime = function (time) {
71
+        this.currentRelativeTime = time;
72
+        this.loadedRelativeTime = this.currentRelativeTime - 1;
73
+    };
74
+    ReplayWhiteboard.prototype.close = function () {
75
+        _super.prototype.close.call(this);
76
+        if (this.interval) {
77
+            clearInterval(this.interval);
78
+        }
79
+    };
80
+    ReplayWhiteboard.prototype.init = function () {
81
+        this.eventHub = new EventHub_1.EventHub();
82
+        _super.prototype.init.call(this);
83
+    };
84
+    ReplayWhiteboard.prototype.loadEvents = function () {
85
+        var _this = this;
86
+        if (this.onLoad && !this.loadingLock) {
87
+            this.loadingLock = true;
88
+            var startTime = this.recordStartTime + this.currentRelativeTime;
89
+            var endTime = startTime + windowSize;
90
+            this.onLoad(startTime, endTime)
91
+                .then(function (events) {
92
+                var _a;
93
+                _this.loadedRelativeTime = _this.currentRelativeTime;
94
+                (_a = _this.leftEvents).push.apply(_a, (events || []));
95
+            })
96
+                .finally(function () {
97
+                _this.loadingLock = false;
98
+            });
99
+        }
100
+    };
101
+    return ReplayWhiteboard;
102
+}(MirrorWhiteboard_1.MirrorWhiteboard));
103
+exports.ReplayWhiteboard = ReplayWhiteboard;

dist/cjs/board/WhitePage/index.js → dist/cjs/whiteboard/WhitePage/index.js View File

@@ -1,24 +1,24 @@
1 1
 "use strict";
2 2
 Object.defineProperty(exports, "__esModule", { value: true });
3
-var index_1 = require("./../Drawboard/index");
4
-var uuid_1 = require("./../../utils/uuid");
3
+var index_1 = require("./../../drawboard/Drawboard/index");
4
+var uuid_1 = require("../../utils/uuid");
5 5
 var types_1 = require("../../markers/types");
6
-require("./index.less");
7 6
 var dom_1 = require("../../utils/dom");
7
+require("./index.less");
8 8
 var prefix = 'fcw-page';
9 9
 var WhitePage = (function () {
10 10
     function WhitePage(source, _a) {
11
-        var _b = _a === void 0 ? {} : _a, mode = _b.mode, eventHub = _b.eventHub, parentContainer = _b.parentContainer;
11
+        var _b = _a === void 0 ? {} : _a, mode = _b.mode, whiteboard = _b.whiteboard, parentContainer = _b.parentContainer, extraToolbarItems = _b.extraToolbarItems;
12 12
         this.id = uuid_1.uuid();
13 13
         this.mode = 'master';
14 14
         if (mode) {
15 15
             this.mode = mode;
16 16
         }
17
-        this.eventHub = eventHub;
18 17
         this.parentContainer = parentContainer;
18
+        this.whiteboard = whiteboard;
19 19
         this.initSource(source);
20 20
         if (this.mode === 'master') {
21
-            this.initMaster();
21
+            this.initMaster(extraToolbarItems);
22 22
         }
23 23
         if (this.mode === 'mirror') {
24 24
             this.initMirror();
@@ -33,8 +33,37 @@ var WhitePage = (function () {
33 33
     WhitePage.prototype.show = function () {
34 34
         this.drawboard.show();
35 35
     };
36
-    WhitePage.prototype.close = function () {
37
-        this.drawboard.close();
36
+    WhitePage.prototype.destroy = function () {
37
+        this.drawboard.destroy();
38
+    };
39
+    WhitePage.prototype.captureSnap = function () {
40
+        var markerSnaps = this.drawboard.markers.map(function (m) { return m.captureSnap(); });
41
+        return {
42
+            id: this.id,
43
+            markers: markerSnaps
44
+        };
45
+    };
46
+    WhitePage.prototype.applySnap = function (snap) {
47
+        var _this = this;
48
+        var markerIdsSet = new Set();
49
+        snap.markers.forEach(function (markerSnap) {
50
+            var marker = _this.drawboard.markerMap[markerSnap.id];
51
+            markerIdsSet.add(markerSnap.id);
52
+            if (marker) {
53
+                marker.applySnap(markerSnap);
54
+            }
55
+            else {
56
+                var newMarker = _this.drawboard.addMarker(types_1.getMarkerByType(markerSnap.type), {
57
+                    id: markerSnap.id
58
+                });
59
+                newMarker.applySnap(markerSnap);
60
+            }
61
+        });
62
+        this.drawboard.markers.forEach(function (marker) {
63
+            if (!markerIdsSet.has(marker.id)) {
64
+                _this.drawboard.deleteMarkerWithEvent(marker);
65
+            }
66
+        });
38 67
     };
39 68
     WhitePage.prototype.initSource = function (source) {
40 69
         if (typeof source.imgSrc === 'string' && !this.parentContainer) {
@@ -53,25 +82,27 @@ var WhitePage = (function () {
53 82
             this.container.appendChild(this.target);
54 83
         }
55 84
     };
56
-    WhitePage.prototype.initMaster = function () {
85
+    WhitePage.prototype.initMaster = function (extraToolbarItems) {
57 86
         var _this = this;
58
-        if (this.eventHub) {
87
+        if (this.whiteboard) {
59 88
             this.drawboard = new index_1.Drawboard({ imgEle: this.target }, {
89
+                extraToolbarItems: extraToolbarItems,
90
+                mountContainer: this.whiteboard.target,
60 91
                 page: this,
61
-                onChange: function (ev) { return _this.eventHub.emit('sync', ev); }
92
+                onChange: function (ev) { return _this.whiteboard.emit(ev); }
62 93
             });
63 94
         }
64 95
         else {
65
-            this.drawboard = new index_1.Drawboard({ imgEle: this.target }, { page: this });
96
+            this.drawboard = new index_1.Drawboard({ imgEle: this.target }, { page: this, mountContainer: this.whiteboard.target });
66 97
         }
67 98
     };
68 99
     WhitePage.prototype.initMirror = function () {
69 100
         var _this = this;
70
-        if (!this.eventHub) {
71
-            throw new Error('Invalid eventHub');
101
+        if (!this.whiteboard) {
102
+            throw new Error('Invalid whiteboard');
72 103
         }
73
-        this.drawboard = new index_1.Drawboard({ imgEle: this.target }, { page: this });
74
-        this.eventHub.on('sync', function (ev) {
104
+        this.drawboard = new index_1.Drawboard({ imgEle: this.target }, { page: this, mountContainer: this.whiteboard.target });
105
+        this.whiteboard.eventHub.on('sync', function (ev) {
75 106
             try {
76 107
                 if (ev.target === 'page' && ev.id === _this.id) {
77 108
                     _this.onPageSync();
@@ -87,33 +118,39 @@ var WhitePage = (function () {
87 118
     };
88 119
     WhitePage.prototype.onPageSync = function () { };
89 120
     WhitePage.prototype.onMarkerSync = function (ev) {
90
-        if (ev.event === 'add' && ev.parentId === this.id) {
91
-            var data = ev.data;
92
-            var marker = this.drawboard.markerMap[data.id];
121
+        if (!ev.marker) {
122
+            return;
123
+        }
124
+        var id = ev.id;
125
+        if (ev.event === 'addMarker' && ev.parentId === this.id) {
126
+            var marker = this.drawboard.markerMap[id];
93 127
             if (!marker) {
94
-                this.drawboard.addMarker(types_1.getMarkerByType(data.type), { id: data.id });
128
+                this.drawboard.addMarker(types_1.getMarkerByType(ev.marker.type), {
129
+                    id: ev.marker.id,
130
+                    originX: ev.marker.dx,
131
+                    originY: ev.marker.dy
132
+                });
95 133
             }
96 134
         }
97
-        if (!ev.id) {
135
+        if (!id) {
98 136
             return;
99 137
         }
100
-        if (ev.event === 'remove') {
101
-            var data = ev.data;
102
-            var marker = this.drawboard.markerMap[data.id];
138
+        if (ev.event === 'removeMarker') {
139
+            var marker = this.drawboard.markerMap[id];
103 140
             if (marker) {
104 141
                 this.drawboard.deleteMarker(marker);
105 142
             }
106 143
         }
107
-        if (ev.event === 'move' || ev.event === 'resize') {
108
-            var marker = this.drawboard.markerMap[ev.id];
144
+        if (ev.event === 'moveMarker' || ev.event === 'resizeMarker') {
145
+            var marker = this.drawboard.markerMap[id];
109 146
             if (marker) {
110
-                marker.reactToManipulation(ev.event, ev.data);
147
+                marker.reactToManipulation(ev.event, ev.marker);
111 148
             }
112 149
         }
113
-        if (ev.event === 'changeText') {
114
-            var marker = this.drawboard.markerMap[ev.id];
150
+        if (ev.event === 'inputMarker') {
151
+            var marker = this.drawboard.markerMap[id];
115 152
             if (marker) {
116
-                marker.setText(ev.data);
153
+                marker.setText(ev.marker.text);
117 154
             }
118 155
         }
119 156
     };

+ 159
- 0
dist/cjs/whiteboard/Whiteboard/index.js View File

@@ -0,0 +1,159 @@
1
+"use strict";
2
+var __extends = (this && this.__extends) || (function () {
3
+    var extendStatics = function (d, b) {
4
+        extendStatics = Object.setPrototypeOf ||
5
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
+        return extendStatics(d, b);
8
+    };
9
+    return function (d, b) {
10
+        extendStatics(d, b);
11
+        function __() { this.constructor = d; }
12
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
+    };
14
+})();
15
+Object.defineProperty(exports, "__esModule", { value: true });
16
+var index_1 = require("../WhitePage/index");
17
+var dom_1 = require("../../utils/dom");
18
+var index_2 = require("../AbstractWhiteboard/index");
19
+var toolbar_items_1 = require("../../toolbar/toolbar-items");
20
+var LeftArrowIcon = require('../../assets/bx-left-arrow.svg');
21
+var RightArrowIcon = require('../../assets/bx-right-arrow.svg');
22
+var FinishIcon = require('../../assets/finish.svg');
23
+var RollbackIcon = require('../../assets/rollback.svg');
24
+var prefix = 'fcw-board';
25
+var Whiteboard = (function (_super) {
26
+    __extends(Whiteboard, _super);
27
+    function Whiteboard() {
28
+        var _this = _super !== null && _super.apply(this, arguments) || this;
29
+        _this.mode = 'master';
30
+        return _this;
31
+    }
32
+    Whiteboard.prototype.destroy = function () {
33
+        _super.prototype.destroy.call(this);
34
+    };
35
+    Whiteboard.prototype.init = function () {
36
+        this.imgsContainer = dom_1.createDivWithClassName(prefix + "-imgs", this.target);
37
+        this.pagesContainer = dom_1.createDivWithClassName(prefix + "-pages", this.target);
38
+        this.initMaster();
39
+        this.snapHistory.push(this.captureSnap(false));
40
+        this.emitSnapshot();
41
+    };
42
+    Whiteboard.prototype.initMaster = function () {
43
+        var _this = this;
44
+        this.isInitialized = true;
45
+        var prevToolbarItem = {
46
+            icon: LeftArrowIcon,
47
+            name: 'prev-flip-arrow',
48
+            tooltipText: 'Prev',
49
+            onClick: function () {
50
+                var nextPageIndex = _this.visiblePageIndex - 1 < 0 ? _this.pages.length - 1 : _this.visiblePageIndex - 1;
51
+                document.querySelectorAll('.fc-whiteboard-indicator-current').forEach(function (e) {
52
+                    e.innerHTML = "" + (nextPageIndex + 1);
53
+                });
54
+                _this.onPageChange(nextPageIndex);
55
+            }
56
+        };
57
+        var indicatorContainer = document.createElement('div');
58
+        indicatorContainer.className = 'fc-whiteboard-indicator-container';
59
+        var indicatorCurrent = document.createElement('span');
60
+        indicatorCurrent.className = 'fc-whiteboard-indicator-current';
61
+        indicatorCurrent.innerHTML = "" + (this.visiblePageIndex + 1);
62
+        indicatorContainer.appendChild(indicatorCurrent);
63
+        indicatorContainer.appendChild(document.createTextNode("/" + this.sources.length));
64
+        var indicatorItem = {
65
+            name: 'indicator',
66
+            onRender: function () { return indicatorContainer; }
67
+        };
68
+        var nextToolbarItem = {
69
+            icon: RightArrowIcon,
70
+            name: 'next-flip-arrow',
71
+            tooltipText: 'Next',
72
+            onClick: function () {
73
+                var nextPageIndex = _this.visiblePageIndex + 1 > _this.pages.length - 1 ? 0 : _this.visiblePageIndex + 1;
74
+                document.querySelectorAll('.fc-whiteboard-indicator-current').forEach(function (e) {
75
+                    e.innerHTML = "" + (nextPageIndex + 1);
76
+                });
77
+                _this.onPageChange(nextPageIndex);
78
+            }
79
+        };
80
+        var finishItem = {
81
+            icon: FinishIcon,
82
+            name: 'finish',
83
+            tooltipText: 'Finish',
84
+            onClick: function () {
85
+                _this.emit({
86
+                    event: 'finish',
87
+                    id: _this.id,
88
+                    target: 'whiteboard'
89
+                });
90
+            }
91
+        };
92
+        var rollbackItem = {
93
+            icon: RollbackIcon,
94
+            name: 'rollback',
95
+            tooltipText: 'Rollback',
96
+            shortcut: 'ESC',
97
+            onClick: function () {
98
+                _this.rollbackSnap();
99
+            }
100
+        };
101
+        this.sources.forEach(function (source) {
102
+            var page = new index_1.WhitePage({ imgSrc: source }, {
103
+                mode: _this.mode,
104
+                whiteboard: _this,
105
+                parentContainer: _this.pagesContainer,
106
+                extraToolbarItems: [
107
+                    toolbar_items_1.separatorToolbarItem,
108
+                    prevToolbarItem,
109
+                    indicatorItem,
110
+                    nextToolbarItem,
111
+                    toolbar_items_1.separatorToolbarItem,
112
+                    finishItem,
113
+                    rollbackItem
114
+                ]
115
+            });
116
+            page.container.style.visibility = 'hidden';
117
+            _this.pages.push(page);
118
+        });
119
+        this.initSiema();
120
+    };
121
+    Whiteboard.prototype.onPageChange = function (nextPageIndex) {
122
+        if (this.visiblePageIndex === nextPageIndex) {
123
+            return;
124
+        }
125
+        this.siema.goTo(nextPageIndex);
126
+        this.visiblePageIndex = nextPageIndex;
127
+        this.pages.forEach(function (page, i) {
128
+            if (nextPageIndex === i) {
129
+                page.show();
130
+            }
131
+            else {
132
+                page.hide();
133
+            }
134
+        });
135
+        this.emit({
136
+            event: 'borderChangePage',
137
+            id: this.id,
138
+            target: 'whiteboard',
139
+            border: this.captureSnap()
140
+        });
141
+    };
142
+    Whiteboard.prototype.emitSnapshot = function () {
143
+        var _this = this;
144
+        var innerFunc = function () {
145
+            _this.emit({
146
+                event: 'borderSnap',
147
+                id: _this.id,
148
+                target: 'whiteboard',
149
+                border: _this.captureSnap(false)
150
+            });
151
+        };
152
+        this.emitInterval = setInterval(function () {
153
+            innerFunc();
154
+        }, this.snapInterval);
155
+        setTimeout(innerFunc, 500);
156
+    };
157
+    return Whiteboard;
158
+}(index_2.AbstractWhiteboard));
159
+exports.Whiteboard = Whiteboard;

+ 18921
- 2825
dist/index.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/index.js.map
File diff suppressed because it is too large
View File


+ 0
- 53
dist/types/board/Drawboard/index.d.ts View File

@@ -1,53 +0,0 @@
1
-import { WhitePageSource } from './../types';
2
-import { Baseboard } from './../Baseboard/index';
3
-import { BaseMarker } from './../../markers/BaseMarker/index';
4
-import { WhitePage } from './../WhitePage/index';
5
-import { onSyncFunc } from './../../event/Event';
6
-import './index.less';
7
-export declare class Drawboard extends Baseboard {
8
-    private scale;
9
-    page: WhitePage;
10
-    private markers;
11
-    readonly markerMap: {
12
-        [key: string]: BaseMarker;
13
-    };
14
-    private activeMarker;
15
-    private toolbar;
16
-    private toolbars;
17
-    private toolbarUI;
18
-    private onComplete;
19
-    private onChange;
20
-    private onCancel;
21
-    constructor(source: WhitePageSource, { page, onChange }?: {
22
-        page?: WhitePage;
23
-        onChange?: onSyncFunc;
24
-    });
25
-    open: (onComplete?: ((dataUrl: string) => void) | undefined, onCancel?: (() => void) | undefined) => void;
26
-    hide: () => void;
27
-    show: () => void;
28
-    close: () => void;
29
-    render: (onComplete: (dataUrl: string) => void, onCancel?: (() => void) | undefined) => void;
30
-    addMarker: (markerType: typeof BaseMarker, { id }?: {
31
-        id?: string | undefined;
32
-    }) => void;
33
-    deleteActiveMarker: () => void;
34
-    private setTargetRect;
35
-    private startRender;
36
-    private attachEvents;
37
-    private mouseDown;
38
-    private mouseMove;
39
-    private mouseUp;
40
-    private adjustUI;
41
-    private adjustSize;
42
-    private positionUI;
43
-    private positionToolbar;
44
-    private showUI;
45
-    private setStyles;
46
-    private toolbarClick;
47
-    private selectMarker;
48
-    deleteMarker: (marker: BaseMarker) => void;
49
-    private complete;
50
-    private cancel;
51
-    private renderFinished;
52
-    private renderFinishedClose;
53
-}

+ 0
- 28
dist/types/board/WhitePage/index.d.ts View File

@@ -1,28 +0,0 @@
1
-import { EventHub } from '../../event/EventHub';
2
-import { WhiteboardMode, WhitePageSource } from './../types';
3
-import { Drawboard } from './../Drawboard/index';
4
-import './index.less';
5
-export declare class WhitePage {
6
-    id: string;
7
-    source: WhitePageSource;
8
-    target: HTMLImageElement;
9
-    container: HTMLDivElement;
10
-    parentContainer?: HTMLDivElement;
11
-    mode: WhiteboardMode;
12
-    drawboard: Drawboard;
13
-    eventHub?: EventHub;
14
-    constructor(source: WhitePageSource, { mode, eventHub, parentContainer }?: {
15
-        mode?: WhiteboardMode;
16
-        eventHub?: EventHub;
17
-        parentContainer?: HTMLDivElement;
18
-    });
19
-    open(): void;
20
-    hide(): void;
21
-    show(): void;
22
-    close(): void;
23
-    private initSource;
24
-    protected initMaster(): void;
25
-    protected initMirror(): void;
26
-    private onPageSync;
27
-    private onMarkerSync;
28
-}

+ 0
- 45
dist/types/board/Whiteboard/index.d.ts View File

@@ -1,45 +0,0 @@
1
-import { WhiteboardMode } from '../types';
2
-import { WhitePage } from '../WhitePage/index';
3
-import { EventHub } from '../../event/EventHub';
4
-import './index.less';
5
-export declare class SerializableWhiteboard {
6
-    id: string;
7
-    sources: string[];
8
-    pageIds: string[];
9
-    visiblePageIndex: number;
10
-}
11
-export declare class Whiteboard {
12
-    id: string;
13
-    sources: string[];
14
-    target: HTMLDivElement;
15
-    imgsContainer: HTMLDivElement;
16
-    pagesContainer: HTMLDivElement;
17
-    eventHub?: EventHub;
18
-    mode: WhiteboardMode;
19
-    isFullscreen: boolean;
20
-    pages: WhitePage[];
21
-    readonly activePage: WhitePage;
22
-    siema: any;
23
-    isInitialized: boolean;
24
-    isSyncing: boolean;
25
-    visiblePageIndex: number;
26
-    emitInterval: any;
27
-    constructor(target: HTMLDivElement, { sources, eventHub, mode, visiblePageIndex }?: {
28
-        sources?: string[];
29
-        eventHub?: EventHub;
30
-        mode?: WhiteboardMode;
31
-        visiblePageIndex?: number;
32
-    });
33
-    open(): void;
34
-    close(): void;
35
-    show(): void;
36
-    hide(): void;
37
-    snap(): SerializableWhiteboard;
38
-    private init;
39
-    private initMaster;
40
-    private initMirror;
41
-    private initSiema;
42
-    private onPageChange;
43
-    private emitSnapshot;
44
-    private onSnapshot;
45
-}

+ 0
- 5
dist/types/board/types.d.ts View File

@@ -1,5 +0,0 @@
1
-export declare type WhiteboardMode = 'master' | 'mirror';
2
-export declare type WhitePageSource = {
3
-    imgEle?: HTMLImageElement;
4
-    imgSrc?: string;
5
-};

dist/types/board/Baseboard/index.d.ts → dist/types/drawboard/Baseboard/index.d.ts View File

@@ -1,7 +1,8 @@
1
-import { WhitePageSource } from './../types';
1
+import { Source } from './../../utils/types';
2 2
 export declare class Baseboard {
3 3
     id: string;
4
-    source: WhitePageSource;
4
+    isFullscreen: boolean;
5
+    source: Source;
5 6
     target: HTMLImageElement;
6 7
     targetRect: ClientRect;
7 8
     boardCanvas: SVGSVGElement;
@@ -9,7 +10,7 @@ export declare class Baseboard {
9 10
     defs: SVGDefsElement;
10 11
     width: number;
11 12
     height: number;
12
-    constructor(source: WhitePageSource);
13
-    protected initBoard: () => void;
13
+    constructor(source: Source);
14
+    protected initBoard: (mountContainer: HTMLElement) => void;
14 15
     protected positionBoard: () => void;
15 16
 }

+ 64
- 0
dist/types/drawboard/Drawboard/index.d.ts View File

@@ -0,0 +1,64 @@
1
+import { HotkeysListener } from 'fc-hotkeys';
2
+import { Source } from './../../utils/types';
3
+import { Baseboard } from './../Baseboard/index';
4
+import { BaseMarker } from './../../markers/BaseMarker/index';
5
+import { WhitePage } from '../../whiteboard/WhitePage';
6
+import { onSyncFunc } from '../../event/SyncEvent';
7
+import { Toolbar } from '../../toolbar/Toolbar';
8
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
9
+import './index.less';
10
+export declare class Drawboard extends Baseboard {
11
+    mountContainer: HTMLElement;
12
+    scale: number;
13
+    zIndex: number;
14
+    allowKeyboard?: boolean | undefined;
15
+    page: WhitePage;
16
+    listener: HotkeysListener;
17
+    markers: BaseMarker[];
18
+    readonly markerMap: {
19
+        [key: string]: BaseMarker;
20
+    };
21
+    activeMarker: BaseMarker | null;
22
+    toolbarItems: ToolbarItem[];
23
+    toolbar: Toolbar;
24
+    toolbarUI: HTMLElement;
25
+    onComplete: (dataUrl: string) => void;
26
+    onChange: onSyncFunc;
27
+    onCancel: () => void;
28
+    constructor(source: Source, { allowKeyboard, extraToolbarItems, mountContainer, page, zIndex, onChange }?: Partial<Drawboard> & {
29
+        extraToolbarItems?: ToolbarItem[];
30
+    });
31
+    open: (onComplete?: ((dataUrl: string) => void) | undefined, onCancel?: (() => void) | undefined) => void;
32
+    hide: () => void;
33
+    show: () => void;
34
+    destroy: () => void;
35
+    render: (onComplete: (dataUrl: string) => void, onCancel?: (() => void) | undefined) => void;
36
+    addMarker: (markerType: typeof BaseMarker, { id, originX, originY }?: {
37
+        id?: string | undefined;
38
+        originX?: number | undefined;
39
+        originY?: number | undefined;
40
+    }) => BaseMarker;
41
+    deleteActiveMarker: () => void;
42
+    clearMarkers: () => void;
43
+    deleteMarkerWithEvent: (marker: BaseMarker | null) => void;
44
+    private setTargetRect;
45
+    private startRender;
46
+    private attachEvents;
47
+    private mouseDown;
48
+    private mouseMove;
49
+    private mouseUp;
50
+    private onKeyboard;
51
+    private adjustUI;
52
+    private adjustSize;
53
+    private positionUI;
54
+    private positionToolbar;
55
+    private showUI;
56
+    private setStyles;
57
+    private toolbarClick;
58
+    private selectMarker;
59
+    deleteMarker: (marker: BaseMarker) => void;
60
+    private complete;
61
+    private cancel;
62
+    private renderFinished;
63
+    private renderFinishedClose;
64
+}

+ 0
- 11
dist/types/event/Event.d.ts View File

@@ -1,11 +0,0 @@
1
-export declare type TargetType = 'whiteboard' | 'page' | 'marker';
2
-export declare type EventType = 'snap' | 'add' | 'resize' | 'move' | 'remove' | 'changeIndex' | 'changeText';
3
-export declare type PositionType = 'left' | 'right' | 'topLeft' | 'bottomLeft' | 'topRight' | 'bottomRight' | 'centerLeft' | 'centerRight' | 'topCenter' | 'bottomCenter';
4
-export interface SyncEvent {
5
-    target: TargetType;
6
-    id?: string;
7
-    parentId?: string;
8
-    event: EventType;
9
-    data?: object | string | number;
10
-}
11
-export declare type onSyncFunc = (ev: SyncEvent) => void;

+ 15
- 0
dist/types/event/SyncEvent.d.ts View File

@@ -0,0 +1,15 @@
1
+import { BorderEventType } from './border-events';
2
+import { MarkerEventType, MarkerData } from './marker-events';
3
+import { WhiteboardSnap } from '../whiteboard/AbstractWhiteboard/snap';
4
+export declare type TargetType = 'whiteboard' | 'page' | 'marker';
5
+export declare type EventType = MarkerEventType | BorderEventType;
6
+export declare type onSyncFunc = (ev: SyncEvent) => void;
7
+export interface SyncEvent {
8
+    target: TargetType;
9
+    id?: string;
10
+    parentId?: string;
11
+    event: EventType;
12
+    marker?: MarkerData;
13
+    border?: WhiteboardSnap;
14
+    timestamp?: number;
15
+}

+ 1
- 0
dist/types/event/border-events.d.ts View File

@@ -0,0 +1 @@
1
+export declare type BorderEventType = 'borderSnap' | 'borderChangePage' | 'finish';

+ 11
- 0
dist/types/event/marker-events.d.ts View File

@@ -0,0 +1,11 @@
1
+import { MarkerType } from './../markers/types';
2
+import { PositionType } from '../utils/layout';
3
+export declare type MarkerEventType = 'addMarker' | 'resizeMarker' | 'moveMarker' | 'removeMarker' | 'inputMarker';
4
+export interface MarkerData {
5
+    id?: string;
6
+    type?: MarkerType;
7
+    text?: string;
8
+    dx?: number;
9
+    dy?: number;
10
+    pos?: PositionType;
11
+}

+ 8
- 3
dist/types/index.d.ts View File

@@ -1,3 +1,8 @@
1
-export { Drawboard } from './board/Drawboard';
2
-export { Whiteboard } from './board/Whiteboard';
3
-export { WhiteboardMode } from './board/types';
1
+export { Drawboard } from './drawboard/Drawboard';
2
+export { separatorToolbarItem, closeToolbarItem } from './toolbar/toolbar-items';
3
+export { Mode } from './utils/types';
4
+export { SyncEvent } from './event/SyncEvent';
5
+export { EventHub } from './event/EventHub';
6
+export { Whiteboard } from './whiteboard/Whiteboard';
7
+export { MirrorWhiteboard } from './whiteboard/MirrorWhiteboard';
8
+export { ReplayWhiteboard } from './whiteboard/ReplayWhiteboard';

+ 2
- 2
dist/types/markers/ArrowMarker/index.d.ts View File

@@ -1,9 +1,9 @@
1 1
 import { MarkerType } from './../types';
2 2
 import { LinearMarker } from '../LinearMarker';
3
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4 4
 export declare class ArrowMarker extends LinearMarker {
5 5
     type: MarkerType;
6 6
     static createMarker: (page?: WhitePage | undefined) => LinearMarker;
7 7
     private readonly ARROW_SIZE;
8
-    protected setup(): void;
8
+    protected init(): void;
9 9
 }

+ 28
- 23
dist/types/markers/BaseMarker/index.d.ts View File

@@ -1,41 +1,46 @@
1
-import { WhitePage } from './../../board/WhitePage/index';
2
-import { PositionType } from '../../event/Event';
3
-import { onSyncFunc, EventType } from '../../event/Event';
1
+import { WhitePage } from '../../whiteboard/WhitePage/index';
2
+import { PositionType } from '../../utils/layout';
3
+import { onSyncFunc, EventType } from '../../event/SyncEvent';
4 4
 import { MarkerType } from '../types';
5
-export declare class BaseMarker {
5
+import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap';
6
+import { Drawboard } from '../../drawboard/Drawboard/index';
7
+import { DomEventAware } from '../../renderer/DomEventAware/index';
8
+export declare class BaseMarker extends DomEventAware {
6 9
     id: string;
7 10
     type: MarkerType;
8 11
     page?: WhitePage;
12
+    drawboard?: Drawboard;
9 13
     onChange: onSyncFunc;
10 14
     static createMarker: (page?: WhitePage | undefined) => BaseMarker;
11 15
     visual: SVGGElement;
12 16
     renderVisual: SVGGElement;
13 17
     onSelected: (marker: BaseMarker) => void;
14 18
     defs: SVGElement[];
15
-    protected width: number;
16
-    protected height: number;
17
-    protected isActive: boolean;
18
-    protected isDragging: boolean;
19
-    protected isResizing: boolean;
20
-    protected previousMouseX: number;
21
-    protected previousMouseY: number;
22
-    reactToManipulation(type: EventType, { dx, dy, pos }: {
23
-        dx: number;
24
-        dy: number;
25
-        pos: PositionType;
19
+    width: number;
20
+    height: number;
21
+    isActive: boolean;
22
+    isDragging: boolean;
23
+    isResizing: boolean;
24
+    reactToManipulation(type: EventType, { dx, dy, pos }?: {
25
+        dx?: number;
26
+        dy?: number;
27
+        pos?: PositionType;
26 28
     }): void;
27 29
     manipulate: (ev: MouseEvent) => void;
28 30
     endManipulation(): void;
29 31
     select(): void;
30 32
     deselect(): void;
31
-    protected setup(): void;
32
-    protected addToVisual: (el: SVGElement) => void;
33
-    protected addToRenderVisual: (el: SVGElement) => void;
33
+    captureSnap(): MarkerSnap;
34
+    applySnap(snap: MarkerSnap): void;
35
+    destroy(): void;
34 36
     protected resize(x: number, y: number, cb?: Function): void;
35 37
     protected resizeByEvent(x: number, y: number, pos?: PositionType): void;
36
-    protected onTouch(ev: TouchEvent): void;
37
-    private mouseDown;
38
-    private mouseUp;
39
-    private mouseMove;
40
-    private move;
38
+    move: (dx: number, dy: number) => void;
39
+    moveTo: (x: number, y: number) => void;
40
+    protected init(): void;
41
+    protected addToVisual: (el: SVGElement) => void;
42
+    protected addToRenderVisual: (el: SVGElement) => void;
43
+    protected onMouseDown: (ev: MouseEvent) => void;
44
+    protected onMouseUp: (ev: MouseEvent) => void;
45
+    protected onMouseMove: (ev: MouseEvent) => void;
41 46
 }

+ 2
- 2
dist/types/markers/CoverMarker/index.d.ts View File

@@ -1,8 +1,8 @@
1 1
 import { MarkerType } from './../types';
2 2
 import { RectBaseMarker } from '../RectMarker/RectBaseMarker';
3
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4 4
 export declare class CoverMarker extends RectBaseMarker {
5 5
     type: MarkerType;
6 6
     static createMarker: (page?: WhitePage | undefined) => RectBaseMarker;
7
-    protected setup(): void;
7
+    protected init(): void;
8 8
 }

+ 2
- 2
dist/types/markers/HighlightMarker/index.d.ts View File

@@ -1,8 +1,8 @@
1 1
 import { MarkerType } from './../types';
2 2
 import { RectBaseMarker } from '../RectMarker/RectBaseMarker';
3
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4 4
 export declare class HighlightMarker extends RectBaseMarker {
5 5
     type: MarkerType;
6 6
     static createMarker: (page?: WhitePage | undefined) => RectBaseMarker;
7
-    protected setup(): void;
7
+    protected init(): void;
8 8
 }

+ 2
- 2
dist/types/markers/LineMarker/index.d.ts View File

@@ -1,8 +1,8 @@
1 1
 import { MarkerType } from './../types';
2 2
 import { LinearMarker } from '../LinearMarker';
3
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4 4
 export declare class LineMarker extends LinearMarker {
5 5
     type: MarkerType;
6 6
     static createMarker: (page?: WhitePage | undefined) => LinearMarker;
7
-    protected setup(): void;
7
+    protected init(): void;
8 8
 }

+ 17
- 12
dist/types/markers/LinearMarker/index.d.ts View File

@@ -1,32 +1,37 @@
1
-import { WhitePage } from './../../board/WhitePage/index';
1
+import { WhitePage } from '../../whiteboard/WhitePage/index';
2 2
 import { BaseMarker } from '../BaseMarker';
3
-import { PositionType } from '../../event/Event';
4
-export declare class LinearMarker extends BaseMarker {
3
+import { PositionType } from '../../utils/layout';
4
+import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap';
5
+import { LinearBound } from '../types';
6
+export declare class LinearMarker extends BaseMarker implements LinearBound {
5 7
     static createMarker: (page?: WhitePage | undefined) => LinearMarker;
6
-    protected markerLine: SVGLineElement;
7 8
     private readonly MIN_LENGTH;
9
+    x1: number;
10
+    y1: number;
11
+    x2: number;
12
+    y2: number;
13
+    protected markerLine: SVGLineElement;
8 14
     private markerBgLine;
9 15
     private controlBox;
10 16
     private controlGrips;
11 17
     private activeGrip;
12
-    private x1;
13
-    private y1;
14
-    private x2;
15
-    private y2;
18
+    getLineLength: (x1: number, y1: number, x2: number, y2: number) => number;
19
+    captureSnap(): MarkerSnap;
20
+    applySnap(snap: MarkerSnap): void;
16 21
     endManipulation(): void;
17 22
     select(): void;
18 23
     deselect(): void;
19
-    protected setup(): void;
24
+    protected init(): void;
20 25
     protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void): void;
21 26
     protected resizeByEvent(x: number, y: number, pos?: PositionType): void;
22
-    private getLineLength;
23 27
     private addControlBox;
24 28
     private adjustControlBox;
25 29
     private addControlGrips;
26 30
     private createGrip;
27
-    private positionGrips;
28
-    private positionGrip;
29 31
     private gripMouseDown;
30 32
     private gripMouseUp;
31 33
     private gripMouseMove;
34
+    private positionLine;
35
+    private positionGrips;
36
+    private positionGrip;
32 37
 }

+ 5
- 3
dist/types/markers/RectMarker/RectBaseMarker.d.ts View File

@@ -1,9 +1,11 @@
1
-import { PositionType } from '../../event/Event';
1
+import { PositionType } from '../../utils/layout';
2 2
 import { RectangularMarker } from '../RectangularMarker';
3
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4
+import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap';
4 5
 export declare class RectBaseMarker extends RectangularMarker {
5 6
     static createMarker: (page?: WhitePage | undefined) => RectBaseMarker;
6 7
     private markerRect;
7
-    protected setup(): void;
8
+    applySnap(snap: MarkerSnap): void;
9
+    protected init(): void;
8 10
     protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void): void;
9 11
 }

+ 2
- 2
dist/types/markers/RectMarker/index.d.ts View File

@@ -1,8 +1,8 @@
1
-import { WhitePage } from './../../board/WhitePage/index';
1
+import { WhitePage } from '../../whiteboard/WhitePage/index';
2 2
 import { MarkerType } from './../types';
3 3
 import { RectBaseMarker } from './RectBaseMarker';
4 4
 export declare class RectMarker extends RectBaseMarker {
5 5
     type: MarkerType;
6 6
     static createMarker: (page?: WhitePage | undefined) => RectBaseMarker;
7
-    protected setup(): void;
7
+    protected init(): void;
8 8
 }

+ 11
- 8
dist/types/markers/RectangularMarker/index.d.ts View File

@@ -1,6 +1,7 @@
1 1
 import { BaseMarker } from '../BaseMarker';
2
-import { PositionType } from '../../event/Event';
3
-import { WhitePage } from '../../board/WhitePage';
2
+import { WhitePage } from '../../whiteboard/WhitePage';
3
+import { PositionType } from '../../utils/layout';
4
+import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap';
4 5
 export declare class RectangularMarker extends BaseMarker {
5 6
     static createMarker: (page?: WhitePage | undefined) => RectangularMarker;
6 7
     protected MIN_SIZE: number;
@@ -9,20 +10,22 @@ export declare class RectangularMarker extends BaseMarker {
9 10
     private controlRect;
10 11
     private controlGrips;
11 12
     private activeGrip;
13
+    captureSnap(): MarkerSnap;
14
+    applySnap(snap: MarkerSnap): void;
12 15
     endManipulation(): void;
13 16
     select(): void;
14 17
     deselect(): void;
15
-    protected setup(): void;
16
-    protected resizeByEvent(x: number, y: number, pos: PositionType): void;
17
-    protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void): void;
18
-    protected onTouch(ev: TouchEvent): void;
18
+    protected init(): void;
19
+    protected resizeByEvent(dx: number, dy: number, pos: PositionType): void;
20
+    protected resize(dx: number, dy: number, onPosition?: (pos: PositionType) => void): void;
19 21
     private addControlBox;
20 22
     private adjustControlBox;
21 23
     private addControlGrips;
22 24
     private createGrip;
23
-    private positionGrips;
24
-    private positionGrip;
25
+    protected onTouch(ev: TouchEvent): void;
25 26
     private gripMouseDown;
26 27
     private gripMouseUp;
27 28
     private gripMouseMove;
29
+    private positionGrips;
30
+    private positionGrip;
28 31
 }

+ 8
- 5
dist/types/markers/TextMarker/index.d.ts View File

@@ -1,19 +1,22 @@
1 1
 import { MarkerType } from '../types';
2 2
 import { RectangularMarker } from '../RectangularMarker';
3
-import { PositionType } from '../../event/Event';
4
-import { WhitePage } from '../../board/WhitePage';
3
+import { WhitePage } from '../../whiteboard/WhitePage';
4
+import { PositionType } from '../../utils/layout';
5
+import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap';
5 6
 export declare class TextMarker extends RectangularMarker {
6 7
     type: MarkerType;
7 8
     static createMarker: (page?: WhitePage | undefined) => TextMarker;
8
-    setText(text: string): void;
9 9
     protected readonly MIN_SIZE = 50;
10 10
     private readonly DEFAULT_TEXT;
11 11
     private text;
12
-    private textElement;
13 12
     private inDoubleTap;
13
+    private textElement;
14 14
     private editor;
15 15
     private editorTextArea;
16
-    protected setup(): void;
16
+    setText(text: string): void;
17
+    captureSnap(): MarkerSnap;
18
+    applySnap(snap: MarkerSnap): void;
19
+    protected init(): void;
17 20
     protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void): void;
18 21
     private renderText;
19 22
     private sizeText;

+ 6
- 0
dist/types/markers/types.d.ts View File

@@ -1,3 +1,9 @@
1 1
 import { BaseMarker } from './BaseMarker/index';
2 2
 export declare type MarkerType = 'base' | 'arrow' | 'cover' | 'line' | 'rect' | 'text' | 'highlight';
3
+export interface LinearBound {
4
+    x1: number;
5
+    y1: number;
6
+    x2: number;
7
+    y2: number;
8
+}
3 9
 export declare function getMarkerByType(type: MarkerType): typeof BaseMarker;

+ 11
- 0
dist/types/renderer/DomEventAware/index.d.ts View File

@@ -0,0 +1,11 @@
1
+export declare abstract class DomEventAware {
2
+    x: number;
3
+    y: number;
4
+    previousMouseX: number;
5
+    previousMouseY: number;
6
+    protected init(ele: Element): void;
7
+    protected onTouch(ev: TouchEvent): void;
8
+    protected abstract onMouseDown(ev: MouseEvent): void;
9
+    protected abstract onMouseUp(ev: MouseEvent): void;
10
+    protected abstract onMouseMove(ev: MouseEvent): void;
11
+}

+ 1
- 1
dist/types/renderer/Synthetizer/index.d.ts View File

@@ -1,3 +1,3 @@
1 1
 export declare class Synthetizer {
2
-    rasterize(target: HTMLImageElement | HTMLDivElement, markerImage: SVGSVGElement, done: (dataUrl: string) => void): void;
2
+    rasterize(target: HTMLImageElement, markerImage: SVGSVGElement, done: (dataUrl: string) => void): void;
3 3
 }

+ 17
- 5
dist/types/toolbar/Toolbar.d.ts View File

@@ -1,11 +1,23 @@
1
+import { ToolbarButton } from './ToolbarButton';
1 2
 import { ToolbarItem } from './ToolbarItem';
2
-export declare class Toolbar {
3
+import './index.less';
4
+import { DomEventAware } from '../renderer/DomEventAware/index';
5
+import { Drawboard } from '../drawboard/Drawboard/index';
6
+export declare type MouseHandler = (ev: MouseEvent) => void;
7
+export declare class Toolbar extends DomEventAware {
3 8
     id: string;
4
-    private toolbarItems;
5
-    private toolbarUI;
6
-    private clickHandler;
9
+    zIndex: number;
10
+    toolbarItems: ToolbarItem[];
11
+    toolbarUI: HTMLElement;
12
+    toolbarButtons: ToolbarButton[];
13
+    readonly toolbarButtonMap: Record<string, ToolbarButton>;
14
+    clickHandler: (ev: MouseEvent, toolbarItem: ToolbarItem) => void;
7 15
     constructor(toolbarItems: ToolbarItem[], clickHandler: (ev: MouseEvent, toolbarItem: ToolbarItem) => void);
8
-    getUI: () => HTMLElement;
16
+    getUI: (drawboard: Drawboard) => HTMLElement;
9 17
     hide(): void;
10 18
     show(): void;
19
+    protected onMouseDown: (downEv: MouseEvent) => void;
20
+    protected onMouseUp: (ev: MouseEvent) => void;
21
+    protected onMouseMove: (ev: MouseEvent) => void;
22
+    protected onDragMove: (event: any) => void;
11 23
 }

+ 6
- 2
dist/types/toolbar/ToolbarButton.d.ts View File

@@ -1,7 +1,11 @@
1 1
 import { ToolbarItem } from './ToolbarItem';
2
+import { Drawboard } from '../drawboard/Drawboard';
2 3
 export declare class ToolbarButton {
3
-    private toolbarItem;
4
-    private clickHandler;
4
+    id: string;
5
+    drawboard: Drawboard;
6
+    toolbarItem: ToolbarItem;
7
+    container: HTMLDivElement;
8
+    clickHandler: (ev: MouseEvent, toolbarItem: ToolbarItem) => void;
5 9
     constructor(toolbarItem: ToolbarItem, clickHandler?: (ev: MouseEvent, toolbarItem: ToolbarItem) => void);
6 10
     getElement: () => HTMLElement;
7 11
 }

+ 6
- 7
dist/types/toolbar/ToolbarItem.d.ts View File

@@ -1,13 +1,12 @@
1 1
 import { BaseMarker } from './../markers/BaseMarker/index';
2 2
 export declare class ToolbarItem {
3 3
     name: string;
4
-    tooltipText: string;
4
+    tooltipText?: string;
5
+    shortcut?: string;
5 6
     icon?: string;
6 7
     markerType?: typeof BaseMarker;
7
-    constructor({ name, tooltipText, icon, markerType }: {
8
-        name: string;
9
-        tooltipText: string;
10
-        icon?: string;
11
-        markerType?: typeof BaseMarker;
12
-    });
8
+    onRender?: () => HTMLDivElement;
9
+    onClick?: () => void;
10
+    draggable?: boolean;
11
+    constructor({ name, tooltipText, shortcut, icon, draggable, markerType, onRender, onClick }: Partial<ToolbarItem>);
13 12
 }

+ 4
- 1
dist/types/toolbar/toolbar-items.d.ts View File

@@ -1,11 +1,14 @@
1
-import { WhitePage } from './../board/WhitePage/index';
1
+import { WhitePage } from '../whiteboard/WhitePage/index';
2 2
 import { ToolbarItem } from './ToolbarItem';
3
+export declare const dragToolbarItem: ToolbarItem;
3 4
 export declare const highlightMarkerToolbarItem: ToolbarItem;
4 5
 export declare const arrowMarkerToolbarItem: ToolbarItem;
5 6
 export declare const textMarkerToolbarItem: ToolbarItem;
6 7
 export declare const coverMarkerToolbarItem: ToolbarItem;
7 8
 export declare const rectMarkerToolbarItem: ToolbarItem;
8 9
 export declare const lineMarkerToolbarItem: ToolbarItem;
10
+export declare const closeToolbarItem: ToolbarItem;
11
+export declare const separatorToolbarItem: ToolbarItem;
9 12
 export declare function getToolbars(page?: WhitePage): (ToolbarItem | {
10 13
     icon: any;
11 14
     name: string;

+ 5
- 0
dist/types/utils/layout.d.ts View File

@@ -0,0 +1,5 @@
1
+export declare type PositionType = 'left' | 'right' | 'topLeft' | 'bottomLeft' | 'topRight' | 'bottomRight' | 'centerLeft' | 'centerRight' | 'topCenter' | 'bottomCenter';
2
+export declare function rectContains(rect: ClientRect, { x, y }: {
3
+    x: number;
4
+    y: number;
5
+}): boolean;

+ 6
- 0
dist/types/utils/types.d.ts View File

@@ -0,0 +1,6 @@
1
+export declare type Mode = 'master' | 'mirror' | 'replay';
2
+export declare type Source = {
3
+    imgEle?: HTMLImageElement;
4
+    imgSrc?: string;
5
+};
6
+export declare function isNil(mayBeNil: any): boolean;

+ 42
- 0
dist/types/whiteboard/AbstractWhiteboard/index.d.ts View File

@@ -0,0 +1,42 @@
1
+import { Mode } from './../../utils/types';
2
+import { SyncEvent } from '../../event/SyncEvent';
3
+import { WhitePage } from '../WhitePage/index';
4
+import { EventHub } from '../../event/EventHub';
5
+import './index.less';
6
+import { WhiteboardSnap } from '../AbstractWhiteboard/snap';
7
+export declare abstract class AbstractWhiteboard {
8
+    id: string;
9
+    sources: string[];
10
+    target: HTMLDivElement;
11
+    imgEles: HTMLDivElement[];
12
+    imgsContainer: HTMLDivElement;
13
+    pagesContainer: HTMLDivElement;
14
+    allowRollback: boolean;
15
+    onlyEmitSnap: boolean;
16
+    snapInterval: number;
17
+    eventHub?: EventHub;
18
+    mode: Mode;
19
+    isFullscreen: boolean;
20
+    pages: WhitePage[];
21
+    readonly activePage: WhitePage;
22
+    readonly pageMap: Record<string, WhitePage>;
23
+    siema: any;
24
+    snapHistory: WhiteboardSnap[];
25
+    isInitialized: boolean;
26
+    isSyncing: boolean;
27
+    visiblePageIndex: number;
28
+    emitInterval: any;
29
+    constructor(target: HTMLDivElement, { sources, eventHub, visiblePageIndex, allowRollback, onlyEmitSnap }?: Partial<AbstractWhiteboard>);
30
+    open(): void;
31
+    close(): void;
32
+    show(): void;
33
+    hide(): void;
34
+    emit(borderEvent: SyncEvent): void;
35
+    captureSnap(shadow?: boolean): WhiteboardSnap;
36
+    rollbackSnap(): void;
37
+    destroy(): void;
38
+    protected abstract init(): void;
39
+    protected initSiema(): void;
40
+    protected abstract onPageChange(nextPageIndex: number): void;
41
+    protected applySnap(snap: WhiteboardSnap): void;
42
+}

+ 32
- 0
dist/types/whiteboard/AbstractWhiteboard/snap.d.ts View File

@@ -0,0 +1,32 @@
1
+import { MarkerType } from '../../markers/types';
2
+export declare class WhiteboardSnap {
3
+    id: string;
4
+    sources: string[];
5
+    pageIds: string[];
6
+    visiblePageIndex: number;
7
+    pages?: WhitepageSnap[];
8
+}
9
+export declare class WhitepageSnap {
10
+    id: string;
11
+    markers: MarkerSnap[];
12
+}
13
+export declare class MarkerSnap {
14
+    id: string;
15
+    type: MarkerType;
16
+    isActive: boolean;
17
+    x: number;
18
+    y: number;
19
+    linearSnap?: {
20
+        x1: number;
21
+        y1: number;
22
+        x2: number;
23
+        y2: number;
24
+    };
25
+    rectSnap?: {
26
+        width: number;
27
+        height: number;
28
+    };
29
+    textSnap?: {
30
+        text: string;
31
+    };
32
+}

+ 8
- 0
dist/types/whiteboard/MirrorWhiteboard/index.d.ts View File

@@ -0,0 +1,8 @@
1
+import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
2
+import { Mode } from '../../utils/types';
3
+export declare class MirrorWhiteboard extends AbstractWhiteboard {
4
+    mode: Mode;
5
+    protected init(): void;
6
+    destroy(): void;
7
+    onPageChange(nextPageIndex: number): void;
8
+}

+ 20
- 0
dist/types/whiteboard/ReplayWhiteboard/index.d.ts View File

@@ -0,0 +1,20 @@
1
+import { MirrorWhiteboard } from '../MirrorWhiteboard';
2
+import { SyncEvent } from '../../event/SyncEvent';
3
+export declare type onLoadFunc = (startTime: number, endTime: number) => Promise<SyncEvent[]>;
4
+export declare class ReplayWhiteboard extends MirrorWhiteboard {
5
+    leftEvents: SyncEvent[];
6
+    recordStartTime: number;
7
+    currentRelativeTime: number;
8
+    loadedRelativeTime: number;
9
+    interval: any;
10
+    loadingLock: boolean;
11
+    seekingLock: boolean;
12
+    onLoad: onLoadFunc;
13
+    setContext(recordStartTime: number, onLoad: onLoadFunc): void;
14
+    setCurrentRelativeTime(time: number): void;
15
+    close(): void;
16
+    protected init(): void;
17
+    private loadEvents;
18
+    private seek;
19
+    private perform;
20
+}

+ 30
- 0
dist/types/whiteboard/WhitePage/index.d.ts View File

@@ -0,0 +1,30 @@
1
+import { Source, Mode } from './../../utils/types';
2
+import { Drawboard } from './../../drawboard/Drawboard/index';
3
+import { WhitepageSnap } from '../AbstractWhiteboard/snap';
4
+import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
5
+import './index.less';
6
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
7
+export declare class WhitePage {
8
+    id: string;
9
+    source: Source;
10
+    target: HTMLImageElement;
11
+    container: HTMLDivElement;
12
+    parentContainer?: HTMLDivElement;
13
+    mode: Mode;
14
+    drawboard: Drawboard;
15
+    whiteboard?: AbstractWhiteboard;
16
+    constructor(source: Source, { mode, whiteboard, parentContainer, extraToolbarItems }?: Partial<WhitePage> & {
17
+        extraToolbarItems?: ToolbarItem[];
18
+    });
19
+    open(): void;
20
+    hide(): void;
21
+    show(): void;
22
+    destroy(): void;
23
+    captureSnap(): WhitepageSnap;
24
+    applySnap(snap: WhitepageSnap): void;
25
+    private initSource;
26
+    protected initMaster(extraToolbarItems?: ToolbarItem[]): void;
27
+    protected initMirror(): void;
28
+    private onPageSync;
29
+    private onMarkerSync;
30
+}

+ 10
- 0
dist/types/whiteboard/Whiteboard/index.d.ts View File

@@ -0,0 +1,10 @@
1
+import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
2
+import { Mode } from '../../utils/types';
3
+export declare class Whiteboard extends AbstractWhiteboard {
4
+    mode: Mode;
5
+    destroy(): void;
6
+    protected init(): void;
7
+    private initMaster;
8
+    onPageChange(nextPageIndex: number): void;
9
+    private emitSnapshot;
10
+}

+ 0
- 0
example/drawboard-fullscreen/index.ts View File


+ 0
- 0
example/drawboard/index.ts View File


+ 0
- 27
example/index.ts View File

@@ -1,27 +0,0 @@
1
-import { EventHub } from './../src/event/EventHub';
2
-import { Whiteboard } from './../src/board/Whiteboard/index';
3
-
4
-const eventHub = new EventHub();
5
-
6
-eventHub.on('sync', (changeEv: SyncEvent) => {});
7
-
8
-const images = [
9
-  'https://upload-images.jianshu.io/upload_images/1647496-6bede989c09af527.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
10
-  'http://upload-images.jianshu.io/upload_images/1647496-d281090a702045e5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
11
-  'http://upload-images.jianshu.io/upload_images/1647496-611a416be07d7ca3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
12
-];
13
-
14
-const whiteboard = new Whiteboard(document.getElementById('root') as HTMLDivElement, {
15
-  sources: images,
16
-  eventHub
17
-});
18
-
19
-whiteboard.open();
20
-
21
-const mirrorWhiteboard = new Whiteboard(document.getElementById('root-mirror') as HTMLDivElement, {
22
-  sources: images,
23
-  eventHub,
24
-  mode: 'mirror'
25
-});
26
-
27
-mirrorWhiteboard.open();

+ 0
- 0
example/mirror-whiteboard/index.ts View File


+ 0
- 0
example/mirror/index.less View File


+ 0
- 32
example/mirror/index.ts View File

@@ -1,32 +0,0 @@
1
-import { EventHub } from './../../src/event/EventHub';
2
-import { WhitePage } from '../../src/board/WhitePage/index';
3
-import { SyncEvent } from '../../src/event/Event';
4
-
5
-const eventHub = new EventHub();
6
-
7
-eventHub.on('sync', (changeEv: SyncEvent) => {
8
-  console.log(changeEv);
9
-});
10
-
11
-const page1 = new WhitePage(
12
-  { imgEle: document.getElementById('image1') as HTMLImageElement },
13
-  { eventHub }
14
-);
15
-
16
-page1.drawboard.open((dataUrl: string) => {
17
-  const res = document.getElementById('resultImage') as HTMLImageElement;
18
-  res.src = dataUrl;
19
-});
20
-
21
-const page2 = new WhitePage(
22
-  { imgEle: document.getElementById('image2') as HTMLImageElement },
23
-  {
24
-    mode: 'mirror',
25
-    eventHub
26
-  }
27
-);
28
-
29
-page2.drawboard.open((dataUrl: string) => {
30
-  const res = document.getElementById('resultImage') as HTMLImageElement;
31
-  res.src = dataUrl;
32
-});

+ 0
- 13
example/whiteboard/index.ts View File

@@ -1,13 +0,0 @@
1
-import { Whiteboard } from '../../src/board/Whiteboard/index';
2
-
3
-const images = [
4
-  'https://upload-images.jianshu.io/upload_images/1647496-6bede989c09af527.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
5
-  'http://upload-images.jianshu.io/upload_images/1647496-d281090a702045e5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
6
-  'http://upload-images.jianshu.io/upload_images/1647496-611a416be07d7ca3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
7
-];
8
-
9
-const whiteboard = new Whiteboard(document.getElementById('root') as HTMLDivElement, {
10
-  sources: images
11
-});
12
-
13
-whiteboard.open();

+ 4
- 0
package.json View File

@@ -29,10 +29,14 @@
29 29
   },
30 30
   "dependencies": {
31 31
     "eventemitter3": "^3.1.0",
32
+    "fc-hotkeys": "^0.0.1-alpha.1",
33
+    "interactjs": "^1.4.9",
34
+    "lodash.debounce": "^4.0.8",
32 35
     "prop-types": "^15.6.2",
33 36
     "react": "^16.8.0",
34 37
     "react-dom": "^16.8.0",
35 38
     "siema": "^1.5.1",
39
+    "tippy.js": "^4.3.4",
36 40
     "uuid": "^3.3.2"
37 41
   },
38 42
   "devDependencies": {

+ 27
- 0
src/assets/finish.svg View File

@@ -0,0 +1,27 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<svg width="20px" height="20px" style="height:20px;" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+    <!-- Generator: Sketch 52.3 (67297) - http://www.bohemiancoding.com/sketch -->
4
+    <title>teacher_ppt_bar_btn_finish</title>
5
+    <desc>Created with Sketch.</desc>
6
+    <g id="Demo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="0.776211504">
7
+        <g id="教师端_白板" transform="translate(-957.000000, -578.000000)" fill="#FF3366">
8
+            <g id="分组-6" transform="translate(484.000000, 569.000000)">
9
+                <g id="Group-29">
10
+                    <g id="teacher_ppt_bar_bj">
11
+                        <g id="分组-10" transform="translate(382.000000, 9.000000)">
12
+                            <g id="分组-5">
13
+                                <g id="teacher_ppt_bar_btn_finish" transform="translate(91.000000, 0.000000)">
14
+                                    <g id="icon/ppt/结束">
15
+                                        <g id="结束" transform="translate(3.000000, 3.000000)">
16
+                                            <path d="M6.13493151,13 C5.30684932,13 4.50547945,12.839726 3.77534247,12.5191781 C3.03630137,12.1986301 2.38630137,11.7534247 1.83424658,11.210274 C1.28219178,10.6671233 0.845890411,10.0082192 0.525342466,9.27808219 C0.204794521,8.5390411 0.0445205479,7.73767123 0.0445205479,6.90068493 C0.0445205479,6.41986301 0.0979452055,5.94794521 0.21369863,5.48493151 C0.329452055,5.02191781 0.489726027,4.57671233 0.694520548,4.15821918 C0.899315068,3.73972603 1.16643836,3.34794521 1.46917808,2.99178082 C1.78082192,2.62671233 2.12808219,2.29726027 2.5109589,2.00342466 C2.64452055,1.90547945 2.77808219,1.8609589 2.92945205,1.8609589 C2.96506849,1.8609589 3.00068493,1.8609589 3.04520548,1.86986301 C3.24109589,1.89657534 3.39246575,1.99452055 3.51712329,2.15479452 C3.64178082,2.31506849 3.67739726,2.48424658 3.65068493,2.68013699 C3.6239726,2.8760274 3.5260274,3.03630137 3.36575342,3.15205479 C2.76027397,3.58835616 2.27945205,4.14041096 1.95890411,4.79041096 C1.63835616,5.44041096 1.46917808,6.14383562 1.46917808,6.89178082 C1.46917808,7.53287671 1.59383562,8.13835616 1.83424658,8.70821918 C2.07465753,9.27808219 2.4130137,9.77671233 2.83150685,10.1952055 C3.25,10.6136986 3.74863014,10.9520548 4.31849315,11.2013699 C4.88835616,11.4506849 5.49383562,11.5753425 6.13493151,11.5753425 C6.7760274,11.5753425 7.39041096,11.4506849 7.95136986,11.2013699 C8.51232877,10.9520548 9.01986301,10.6136986 9.43835616,10.1952055 C9.85684932,9.77671233 10.1952055,9.27808219 10.4445205,8.70821918 C10.6938356,8.13835616 10.8184932,7.53287671 10.8184932,6.89178082 C10.8184932,6.13493151 10.640411,5.41369863 10.2931507,4.7369863 C9.94589041,4.06027397 9.44726027,3.49931507 8.81506849,3.0630137 C8.64589041,2.94726027 8.54794521,2.79589041 8.52123288,2.6 C8.48561644,2.40410959 8.53013699,2.2260274 8.6369863,2.05684932 C8.74383562,1.90547945 8.89520548,1.80753425 9.09109589,1.77191781 C9.13561644,1.7630137 9.18013699,1.7630137 9.22465753,1.7630137 C9.36712329,1.7630137 9.50068493,1.80753425 9.63424658,1.89657534 C10.0349315,2.18150685 10.4089041,2.51986301 10.7205479,2.88493151 C11.0410959,3.25 11.3171233,3.65068493 11.539726,4.07808219 C11.7623288,4.50547945 11.940411,4.95958904 12.0561644,5.43150685 C12.1719178,5.90342466 12.2342466,6.39315068 12.2342466,6.88287671 C12.2342466,7.71986301 12.0739726,8.52123288 11.7534247,9.26027397 C11.4328767,9.99931507 10.9876712,10.6493151 10.4445205,11.2013699 C9.90136986,11.7445205 9.24246575,12.189726 8.50342466,12.510274 C7.78219178,12.839726 6.98082192,13 6.13493151,13 Z M6.13493151,6.75821918 C5.9390411,6.75821918 5.77876712,6.6869863 5.63630137,6.55342466 C5.50273973,6.4109589 5.43150685,6.25068493 5.43150685,6.05479452 L5.43150685,0.721232877 C5.43150685,0.525342466 5.50273973,0.356164384 5.63630137,0.21369863 C5.77876712,0.0712328767 5.9390411,0 6.13493151,0 C6.33972603,0 6.50890411,0.0712328767 6.64246575,0.21369863 C6.78493151,0.356164384 6.84726027,0.525342466 6.84726027,0.721232877 L6.84726027,6.05479452 C6.84726027,6.25068493 6.7760274,6.4109589 6.64246575,6.55342466 C6.50890411,6.6869863 6.33972603,6.75821918 6.13493151,6.75821918 Z" id="Shape" fill-rule="nonzero"></path>
17
+                                        </g>
18
+                                    </g>
19
+                                </g>
20
+                            </g>
21
+                        </g>
22
+                    </g>
23
+                </g>
24
+            </g>
25
+        </g>
26
+    </g>
27
+</svg>

+ 1
- 0
src/assets/rollback-disable.svg View File

@@ -0,0 +1 @@
1
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1560078592996" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2653" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M811.488 424.512Q722.976 336 597.984 336h-336l114.016-114.016q12-12 12-28.512t-12-28-28.512-11.488-28.512 12l-183.008 183.008q-12 12-12 28.512t12 28.512l178.016 178.016q12 12 28.512 12t28-11.488 11.488-28-11.008-28.512l-112.992-112h340q92 0 156.992 64.992t64.992 156.992v192q0 16.992 12 28.512t28.512 11.488 28-11.488 11.488-28.512v-192q0-124.992-88.512-213.504z" p-id="2654" fill="#cdcdcd"></path></svg>

+ 1
- 0
src/assets/rollback.svg View File

@@ -0,0 +1 @@
1
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1560078592996" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2653" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M811.488 424.512Q722.976 336 597.984 336h-336l114.016-114.016q12-12 12-28.512t-12-28-28.512-11.488-28.512 12l-183.008 183.008q-12 12-12 28.512t12 28.512l178.016 178.016q12 12 28.512 12t28-11.488 11.488-28-11.008-28.512l-112.992-112h340q92 0 156.992 64.992t64.992 156.992v192q0 16.992 12 28.512t28.512 11.488 28-11.488 11.488-28.512v-192q0-124.992-88.512-213.504z" p-id="2654" fill="#2c2c2c"></path></svg>

+ 6
- 3
src/drawboard/Baseboard/index.ts View File

@@ -37,14 +37,17 @@ export class Baseboard {
37 37
     // 如果仅传入图片地址或者 Blob,则必须为全屏模式
38 38
   }
39 39
 
40
-  protected initBoard = () => {
40
+  protected initBoard = (mountContainer: HTMLElement) => {
41 41
     // init holder
42 42
     this.boardHolder = document.createElement('div');
43 43
     this.boardHolder.id = `fcw-board-holder-${this.id}`;
44
+    this.boardHolder.className = `fcw-board-holder`;
45
+    this.boardHolder.style.zIndex = '999';
44 46
     // fix for Edge's touch behavior
45 47
     this.boardHolder.style.setProperty('touch-action', 'none');
46 48
     this.boardHolder.style.setProperty('-ms-touch-action', 'none');
47
-    document.body.appendChild(this.boardHolder);
49
+
50
+    mountContainer.appendChild(this.boardHolder);
48 51
 
49 52
     // init canvas
50 53
     this.boardCanvas = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
@@ -56,7 +59,7 @@ export class Baseboard {
56 59
       '0 0 ' + this.width.toString() + ' ' + this.height.toString()
57 60
     );
58 61
 
59
-    this.boardHolder.style.position = 'absolute';
62
+    this.boardHolder.style.position = 'fixed';
60 63
     this.boardHolder.style.width = `${this.width}px`;
61 64
     this.boardHolder.style.height = `${this.height}px`;
62 65
     this.boardHolder.style.transformOrigin = 'top left';

+ 153
- 29
src/drawboard/Drawboard/index.ts View File

@@ -1,3 +1,6 @@
1
+import { HotkeysListener, KEY_ALL } from 'fc-hotkeys';
2
+import * as debounce from 'lodash.debounce';
3
+
1 4
 import { Source } from './../../utils/types';
2 5
 import { Baseboard } from './../Baseboard/index';
3 6
 import { BaseMarker } from './../../markers/BaseMarker/index';
@@ -10,14 +13,24 @@ import { Toolbar } from '../../toolbar/Toolbar';
10 13
 import { ToolbarItem } from '../../toolbar/ToolbarItem';
11 14
 
12 15
 import './index.less';
16
+import { rectContains } from '../../utils/layout';
17
+import { RectMarker } from '../../markers/RectMarker/index';
18
+import { HighlightMarker } from '../../markers/HighlightMarker/index';
19
+import { CoverMarker } from '../../markers/CoverMarker/index';
20
+import { LineMarker } from '../../markers/LineMarker/index';
21
+import { ArrowMarker } from '../../markers/ArrowMarker/index';
22
+import { TextMarker } from '../../markers/TextMarker/index';
13 23
 
14 24
 export class Drawboard extends Baseboard {
15 25
   /** Options */
26
+  mountContainer = document.body;
16 27
   scale = 1.0;
17 28
   zIndex: number = 999;
29
+  allowKeyboard? = true;
18 30
 
19 31
   /** 句柄 */
20 32
   page: WhitePage;
33
+  listener: HotkeysListener;
21 34
 
22 35
   markers: BaseMarker[];
23 36
   get markerMap(): { [key: string]: BaseMarker } {
@@ -42,9 +55,11 @@ export class Drawboard extends Baseboard {
42 55
   constructor(
43 56
     source: Source,
44 57
     {
58
+      allowKeyboard = true,
59
+      extraToolbarItems,
60
+      mountContainer,
45 61
       page,
46 62
       zIndex,
47
-      extraToolbarItems,
48 63
       onChange
49 64
     }: Partial<Drawboard> & { extraToolbarItems?: ToolbarItem[] } = {}
50 65
   ) {
@@ -58,6 +73,8 @@ export class Drawboard extends Baseboard {
58 73
       this.zIndex = zIndex;
59 74
     }
60 75
 
76
+    this.allowKeyboard = allowKeyboard;
77
+
61 78
     this.markers = [];
62 79
     this.activeMarker = null;
63 80
 
@@ -72,6 +89,15 @@ export class Drawboard extends Baseboard {
72 89
     if (onChange) {
73 90
       this.onChange = onChange;
74 91
     }
92
+
93
+    if (allowKeyboard && this.page && this.page.mode === 'master') {
94
+      this.listener = new HotkeysListener();
95
+      this.listener.on(KEY_ALL, debounce(this.onKeyboard, 150));
96
+    }
97
+
98
+    if (mountContainer) {
99
+      this.mountContainer = mountContainer;
100
+    }
75 101
   }
76 102
 
77 103
   /** @region LifeCycle open - hide - show - ... - close */
@@ -87,7 +113,7 @@ export class Drawboard extends Baseboard {
87 113
 
88 114
     this.setTargetRect();
89 115
 
90
-    this.initBoard();
116
+    this.initBoard(this.mountContainer);
91 117
     this.attachEvents();
92 118
     this.setStyles();
93 119
 
@@ -124,12 +150,17 @@ export class Drawboard extends Baseboard {
124 150
     }
125 151
   };
126 152
 
127
-  public close = () => {
153
+  public destroy = () => {
128 154
     if (this.toolbarUI) {
129
-      document.body.removeChild(this.toolbarUI);
155
+      this.mountContainer.removeChild(this.toolbarUI);
130 156
     }
157
+
131 158
     if (this.boardCanvas) {
132
-      document.body.removeChild(this.boardHolder);
159
+      this.mountContainer.removeChild(this.boardHolder);
160
+    }
161
+
162
+    if (this.listener) {
163
+      this.listener.reset();
133 164
     }
134 165
   };
135 166
 
@@ -145,7 +176,10 @@ export class Drawboard extends Baseboard {
145 176
   };
146 177
 
147 178
   /** 添加某个 Marker */
148
-  public addMarker = (markerType: typeof BaseMarker, { id }: { id?: string } = {}) => {
179
+  public addMarker = (
180
+    markerType: typeof BaseMarker,
181
+    { id, originX, originY }: { id?: string; originX?: number; originY?: number } = {}
182
+  ) => {
149 183
     // 假如 Drawboard 存在 Page 引用,则传导给 Marker
150 184
     const marker = markerType.createMarker(this.page);
151 185
 
@@ -165,46 +199,65 @@ export class Drawboard extends Baseboard {
165 199
       }
166 200
     }
167 201
 
202
+    this.markers.push(marker);
203
+    this.selectMarker(marker);
204
+    this.boardCanvas.appendChild(marker.visual);
205
+
206
+    let x;
207
+    let y;
208
+
209
+    if (originX && originY) {
210
+      x = originX;
211
+      y = originY;
212
+    } else {
213
+      // 默认居中
214
+      const bbox = marker.visual.getBBox();
215
+      x = this.width / 2 / this.scale - bbox.width / 2;
216
+      y = this.height / 2 / this.scale - bbox.height / 2;
217
+    }
218
+
168 219
     // 触发事件流
169 220
     this.onChange({
170 221
       target: 'marker',
171 222
       parentId: this.page ? this.page.id : this.id,
172 223
       event: 'addMarker',
173
-      marker: { type: marker.type, id: marker.id }
224
+      marker: { type: marker.type, id: marker.id, dx: x, dy: y }
174 225
     });
175 226
 
176
-    this.markers.push(marker);
177
-    this.selectMarker(marker);
178
-    this.boardCanvas.appendChild(marker.visual);
179
-
180
-    // 默认居中
181
-    const bbox = marker.visual.getBBox();
182
-    const x = this.width / 2 / this.scale - bbox.width / 2;
183
-    const y = this.height / 2 / this.scale - bbox.height / 2;
184
-
185 227
     marker.moveTo(x, y);
186 228
 
187 229
     return marker;
188 230
   };
189 231
 
190 232
   public deleteActiveMarker = () => {
191
-    if (this.activeMarker) {
233
+    this.deleteMarkerWithEvent(this.activeMarker);
234
+  };
235
+
236
+  public clearMarkers = () => {
237
+    [...this.markers].forEach(marker => {
238
+      this.deleteMarkerWithEvent(marker);
239
+    });
240
+  };
241
+
242
+  public deleteMarkerWithEvent = (marker: BaseMarker | null) => {
243
+    if (marker) {
192 244
       // 触发事件
193 245
       if (this.onChange) {
194 246
         this.onChange({
195 247
           event: 'removeMarker',
196
-          id: this.activeMarker.id,
248
+          id: marker.id,
197 249
           target: 'marker',
198
-          marker: { id: this.activeMarker.id }
250
+          marker: { id: marker.id }
199 251
         });
200 252
       }
201
-      this.deleteMarker(this.activeMarker);
253
+      this.deleteMarker(marker);
202 254
     }
203 255
   };
204 256
 
205 257
   private setTargetRect = () => {
206 258
     const targetRect = this.target.getBoundingClientRect() as DOMRect;
207 259
     const bodyRect = document.body.parentElement!.getBoundingClientRect();
260
+
208 261
     this.targetRect = {
209 262
       left: targetRect.left - bodyRect.left,
210 263
       top: targetRect.top - bodyRect.top
@@ -243,6 +296,57 @@ export class Drawboard extends Baseboard {
243 296
     }
244 297
   };
245 298
 
299
+  private onKeyboard = (e: any, { hotkey }: { hotkey: string }) => {
300
+    switch (hotkey) {
301
+      case 'Shift+R':
302
+        this.addMarker(RectMarker);
303
+        return;
304
+      case 'Shift+H':
305
+        this.addMarker(HighlightMarker);
306
+        return;
307
+      case 'Shift+C':
308
+        this.addMarker(CoverMarker);
309
+        return;
310
+      case 'Shift+L':
311
+        this.addMarker(LineMarker);
312
+        return;
313
+      case 'Shift+A':
314
+        this.addMarker(ArrowMarker);
315
+        return;
316
+      case 'Shift+T':
317
+        this.addMarker(TextMarker);
318
+        return;
319
+      case 'ESC':
320
+        this.page.whiteboard!.rollbackSnap();
321
+        return;
322
+      default:
323
+        break;
324
+    }
325
+    if (!this.activeMarker) {
326
+      return;
327
+    }
328
+
329
+    switch (hotkey) {
330
+      case 'UP':
331
+        this.activeMarker.move(0, -10);
332
+        return;
333
+      case 'LEFT':
334
+        this.activeMarker.move(-10, 0);
335
+        return;
336
+      case 'RIGHT':
337
+        this.activeMarker.move(10, 0);
338
+        return;
339
+      case 'DOWN':
340
+        this.activeMarker.move(0, 10);
341
+        return;
342
+      case 'BACKSPACE':
343
+        this.deleteActiveMarker();
344
+        return;
345
+      default:
346
+        return;
347
+    }
348
+  };
349
+
246 350
   private adjustUI = (ev: UIEvent) => {
247 351
     this.adjustSize();
248 352
     this.positionUI();
@@ -269,22 +373,25 @@ export class Drawboard extends Baseboard {
269 373
   };
270 374
 
271 375
   private positionToolbar = () => {
272
-    this.toolbarUI.style.left = `${this.targetRect.left +
273
-      this.target.offsetWidth -
274
-      this.toolbarUI.clientWidth}px`;
275
-    this.toolbarUI.style.top = `${this.targetRect.top - this.toolbarUI.clientHeight}px`;
376
+    if (this.toolbarUI && this.targetRect) {
377
+      this.toolbarUI.style.left = `${this.targetRect.left +
378
+        this.target.offsetWidth -
379
+        this.toolbarUI.clientWidth}px`;
380
+      this.toolbarUI.style.top = `${this.targetRect.top - this.toolbarUI.clientHeight}px`;
381
+    }
276 382
   };
277 383
 
278 384
   private showUI = () => {
279 385
     this.toolbar = new Toolbar(this.toolbarItems, this.toolbarClick);
280
-    this.toolbar.zIndex = this.zIndex;
386
+    this.toolbar.zIndex = this.zIndex + 1;
281 387
 
282 388
     this.toolbarUI = this.toolbar.getUI(this);
283 389
 
284
-    document.body.appendChild(this.toolbarUI);
390
+    this.boardHolder.appendChild(this.toolbarUI);
285 391
     this.toolbarUI.style.position = 'absolute';
286 392
 
287 393
     this.positionToolbar();
394
+    this.toolbar.show();
288 395
 
289 396
     // 处理元素的拖拽事件
290 397
     this.toolbar.toolbarButtons.forEach(button => {
@@ -301,8 +408,25 @@ export class Drawboard extends Baseboard {
301 408
     this.boardCanvas.ondragover = ev => {
302 409
       ev.preventDefault();
303 410
     };
411
+
304 412
     this.boardCanvas.ondrop = ev => {
305
-      console.log(ev);
413
+      const markerX = ev.x;
414
+      const markerY = ev.y;
415
+
416
+      const rect = this.boardHolder.getBoundingClientRect();
417
+
418
+      if (rectContains(rect, { x: markerX, y: markerY })) {
419
+        const buttonId = ev.dataTransfer!.getData('id');
420
+
421
+        const button = this.toolbar.toolbarButtonMap[buttonId];
422
+
423
+        if (button.toolbarItem && button.toolbarItem.markerType) {
424
+          this.addMarker(button.toolbarItem.markerType, {
425
+            originX: markerX - rect.left,
426
+            originY: markerY - rect.top
427
+          });
428
+        }
429
+      }
306 430
     };
307 431
   };
308 432
 
@@ -415,7 +539,7 @@ export class Drawboard extends Baseboard {
415 539
   };
416 540
 
417 541
   private cancel = () => {
418
-    this.close();
542
+    this.destroy();
419 543
     if (this.onCancel) {
420 544
       this.onCancel();
421 545
     }
@@ -426,7 +550,7 @@ export class Drawboard extends Baseboard {
426 550
   };
427 551
 
428 552
   private renderFinishedClose = (dataUrl: string) => {
429
-    this.close();
553
+    this.destroy();
430 554
     this.onComplete(dataUrl);
431 555
   };
432 556
 }

+ 3
- 1
src/event/border-events.ts View File

@@ -2,4 +2,6 @@ export type BorderEventType =
2 2
   // 完全的状态同步,FCW 支持两种状态的同步交换:Snapshot(Snap) 与 KeyActions(KA) 方式
3 3
   | 'borderSnap'
4 4
   // 下标改变
5
-  | 'borderChangePage';
5
+  | 'borderChangePage'
6
+  // 结束
7
+  | 'finish';

+ 8
- 1
src/markers/BaseMarker/index.ts View File

@@ -69,7 +69,6 @@ export class BaseMarker extends DomEventAware {
69 69
 
70 70
     // 如果在拖拽
71 71
     if (this.isDragging) {
72
-      this.onChange({ target: 'marker', id: this.id, event: 'moveMarker', marker: { dx, dy } });
73 72
       this.move(dx, dy);
74 73
     }
75 74
 
@@ -135,6 +134,11 @@ export class BaseMarker extends DomEventAware {
135 134
     }
136 135
   }
137 136
 
137
+  /** 移除该 Marker */
138
+  public destroy() {
139
+    this.visual.style.display = 'none';
140
+  }
141
+
138 142
   protected resize(x: number, y: number, cb?: Function) {
139 143
     return;
140 144
   }
@@ -149,8 +153,11 @@ export class BaseMarker extends DomEventAware {
149 153
 
150 154
     this.x += dx;
151 155
     this.y += dy;
156
+
157
+    this.onChange({ target: 'marker', id: this.id, event: 'moveMarker', marker: { dx, dy } });
152 158
   };
153 159
 
160
+  /** Move to relative position */
154 161
   public moveTo = (x: number, y: number) => {
155 162
     const translate = this.visual.transform.baseVal.getItem(0);
156 163
     translate.setMatrix(translate.matrix.translate(x - this.x, y - this.y));

+ 14
- 4
src/toolbar/Toolbar.ts View File

@@ -19,6 +19,16 @@ export class Toolbar extends DomEventAware {
19 19
   toolbarUI: HTMLElement;
20 20
   toolbarButtons: ToolbarButton[] = [];
21 21
 
22
+  get toolbarButtonMap(): Record<string, ToolbarButton> {
23
+    const buttonMap = {};
24
+
25
+    this.toolbarButtons.forEach(b => {
26
+      buttonMap[b.id] = b;
27
+    });
28
+
29
+    return buttonMap;
30
+  }
31
+
22 32
   clickHandler: (ev: MouseEvent, toolbarItem: ToolbarItem) => void;
23 33
 
24 34
   constructor(
@@ -41,7 +51,6 @@ export class Toolbar extends DomEventAware {
41 51
       const toolbarButton = new ToolbarButton(toolbarItem, this.clickHandler);
42 52
       toolbarButton.drawboard = drawboard;
43 53
       this.toolbarUI.appendChild(toolbarButton.getElement());
44
-
45 54
       this.toolbarButtons.push(toolbarButton);
46 55
     }
47 56
 
@@ -71,14 +80,15 @@ export class Toolbar extends DomEventAware {
71 80
   protected onMouseMove = (ev: MouseEvent) => {};
72 81
 
73 82
   protected onDragMove = (event: any) => {
74
-    var target = this.toolbarUI;
83
+    let target = this.toolbarUI;
75 84
 
76 85
     // keep the dragged position in the data-x/data-y attributes
77
-    var x = ((parseFloat(target.getAttribute('data-x') as string) || 0) + event.dx) as any;
78
-    var y = ((parseFloat(target.getAttribute('data-y') as string) || 0) + event.dy) as any;
86
+    let x = ((parseFloat(target.getAttribute('data-x') as string) || 0) + event.dx) as any;
87
+    let y = ((parseFloat(target.getAttribute('data-y') as string) || 0) + event.dy) as any;
79 88
 
80 89
     // translate the element
81 90
     target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)';
91
+    target.style.zIndex = `${this.zIndex}`;
82 92
 
83 93
     // update the posiion attributes
84 94
     target.setAttribute('data-x', x);

+ 18
- 1
src/toolbar/ToolbarButton.ts View File

@@ -1,5 +1,7 @@
1
-import { uuid } from './../utils/uuid';
1
+import tippy from 'tippy.js';
2
+
2 3
 import { ToolbarItem } from './ToolbarItem';
4
+import { uuid } from '../utils/uuid';
3 5
 import { Drawboard } from '../drawboard/Drawboard';
4 6
 
5 7
 /** 工作栏按钮 */
@@ -23,6 +25,11 @@ export class ToolbarButton {
23 25
   }
24 26
 
25 27
   public getElement = (): HTMLElement => {
28
+    if (this.toolbarItem.onRender) {
29
+      this.container = this.toolbarItem.onRender().cloneNode(true) as HTMLDivElement;
30
+      return this.container;
31
+    }
32
+
26 33
     const div = document.createElement('div');
27 34
 
28 35
     if (this.toolbarItem.name !== 'separator') {
@@ -42,10 +49,20 @@ export class ToolbarButton {
42 49
       } else {
43 50
         div.innerText = this.toolbarItem.tooltipText || '';
44 51
       }
52
+
53
+      if (this.toolbarItem.tooltipText) {
54
+        tippy(div, {
55
+          content: this.toolbarItem.shortcut
56
+            ? `${this.toolbarItem.tooltipText} ${this.toolbarItem.shortcut}`
57
+            : this.toolbarItem.tooltipText
58
+        });
59
+      }
45 60
     } else {
46 61
       div.className = 'fc-whiteboard-toolbar-separator';
47 62
     }
48 63
 
64
+    div.id = `fc-whiteboard-toolbar-${this.toolbarItem.name}`;
65
+
49 66
     this.container = div;
50 67
 
51 68
     return div;

+ 17
- 2
src/toolbar/ToolbarItem.ts View File

@@ -4,21 +4,36 @@ import { BaseMarker } from './../markers/BaseMarker/index';
4 4
 export class ToolbarItem {
5 5
   name: string;
6 6
   tooltipText?: string;
7
+  shortcut?: string;
7 8
   icon?: string;
8 9
   markerType?: typeof BaseMarker;
10
+  onRender?: () => HTMLDivElement;
9 11
   onClick?: () => void;
12
+
10 13
   draggable?: boolean;
11 14
 
12
-  constructor({ name, tooltipText, icon, markerType, onClick, draggable }: Partial<ToolbarItem>) {
15
+  constructor({
16
+    name,
17
+    tooltipText,
18
+    shortcut,
19
+    icon,
20
+    draggable,
21
+    markerType,
22
+    onRender,
23
+    onClick
24
+  }: Partial<ToolbarItem>) {
13 25
     if (!name) {
14 26
       throw new Error('Invalid params');
15 27
     }
16 28
 
17 29
     this.name = name;
18 30
     this.tooltipText = tooltipText;
31
+    this.shortcut = shortcut;
19 32
     this.icon = icon;
20 33
     this.markerType = markerType;
21
-    this.onClick = onClick;
22 34
     this.draggable = draggable;
35
+
36
+    this.onClick = onClick;
37
+    this.onRender = onRender;
23 38
   }
24 39
 }

+ 11
- 0
src/toolbar/index.less View File

@@ -5,6 +5,7 @@
5 5
   border-radius: 13px;
6 6
   opacity: 0.9;
7 7
   border: 1px solid rgba(230, 236, 247, 1);
8
+  padding: 0 8px;
8 9
 
9 10
   display: flex;
10 11
   align-items: center;
@@ -47,3 +48,13 @@
47 48
 .fc-whiteboard-toolbar-button svg {
48 49
   height: 16px;
49 50
 }
51
+
52
+.fc-whiteboard-indicator-container {
53
+  font-size: 13px;
54
+  line-height: 27px;
55
+  height: 27px;
56
+  width: 40px;
57
+  display: flex;
58
+  justify-content: center;
59
+  letter-spacing: 2;
60
+}

+ 24
- 14
src/toolbar/toolbar-items.ts View File

@@ -9,7 +9,6 @@ import { LineMarker } from '../markers/LineMarker';
9 9
 
10 10
 const OkIcon = require('../assets/check.svg');
11 11
 const DeleteIcon = require('../assets/eraser.svg');
12
-const PointerIcon = require('../assets/mouse-pointer.svg');
13 12
 const CloseIcon = require('../assets/times.svg');
14 13
 
15 14
 export const dragToolbarItem = new ToolbarItem({
@@ -20,44 +19,56 @@ export const dragToolbarItem = new ToolbarItem({
20 19
 
21 20
 export const highlightMarkerToolbarItem = new ToolbarItem({
22 21
   name: 'cover-marker',
23
-  tooltipText: 'Cover',
22
+  tooltipText: 'Hightlight',
23
+  shortcut: 'Shift+H',
24 24
   icon: require('../assets/highlight.svg'),
25
-  markerType: HighlightMarker
25
+  markerType: HighlightMarker,
26
+  draggable: true
26 27
 });
27 28
 
28 29
 export const arrowMarkerToolbarItem = new ToolbarItem({
29 30
   name: 'arrow-marker',
30 31
   tooltipText: 'Arrow',
32
+  shortcut: 'Shift+A',
31 33
   icon: require('../assets/arrow.svg'),
32
-  markerType: ArrowMarker
34
+  markerType: ArrowMarker,
35
+  draggable: true
33 36
 });
34 37
 
35 38
 export const textMarkerToolbarItem = new ToolbarItem({
36 39
   name: 'text-marker',
37 40
   tooltipText: 'Text',
41
+  shortcut: 'Shift+T',
38 42
   icon: require('../assets/text.svg'),
39
-  markerType: TextMarker
43
+  markerType: TextMarker,
44
+  draggable: true
40 45
 });
41 46
 
42 47
 export const coverMarkerToolbarItem = new ToolbarItem({
43 48
   name: 'cover-marker',
44 49
   tooltipText: 'Cover',
50
+  shortcut: 'Shift+C',
45 51
   icon: require('../assets/cover.svg'),
46
-  markerType: CoverMarker
52
+  markerType: CoverMarker,
53
+  draggable: true
47 54
 });
48 55
 
49 56
 export const rectMarkerToolbarItem = new ToolbarItem({
50 57
   name: 'rect-marker',
51 58
   tooltipText: 'Rectangle',
59
+  shortcut: 'Shift+R',
52 60
   icon: require('../assets/rect.svg'),
53
-  markerType: RectMarker
61
+  markerType: RectMarker,
62
+  draggable: true
54 63
 });
55 64
 
56 65
 export const lineMarkerToolbarItem = new ToolbarItem({
57 66
   name: 'line-marker',
58 67
   tooltipText: 'Line',
68
+  shortcut: 'Shift+L',
59 69
   icon: require('../assets/line.svg'),
60
-  markerType: LineMarker
70
+  markerType: LineMarker,
71
+  draggable: true
61 72
 });
62 73
 
63 74
 export const closeToolbarItem = new ToolbarItem({
@@ -70,12 +81,11 @@ export const separatorToolbarItem = new ToolbarItem({ name: 'separator', tooltip
70 81
 
71 82
 export function getToolbars(page?: WhitePage) {
72 83
   const toolbars = [
73
-    {
74
-      icon: PointerIcon,
75
-      name: 'pointer',
76
-      tooltipText: 'Pointer',
77
-      draggable: true
78
-    },
84
+    // {
85
+    //   icon: PointerIcon,
86
+    //   name: 'pointer',
87
+    //   tooltipText: 'Pointer'
88
+    // },
79 89
     {
80 90
       icon: DeleteIcon,
81 91
       name: 'delete',

+ 2
- 0
src/types.d.ts View File

@@ -13,3 +13,5 @@ declare module '*.svg' {
13 13
 }
14 14
 
15 15
 declare module 'siema';
16
+
17
+declare module 'lodash.debounce';

+ 9
- 0
src/utils/layout.ts View File

@@ -9,3 +9,12 @@ export type PositionType =
9 9
   | 'centerRight'
10 10
   | 'topCenter'
11 11
   | 'bottomCenter';
12
+
13
+/** 判断是否在某个包含的区域呢 */
14
+export function rectContains(rect: ClientRect, { x, y }: { x: number; y: number }) {
15
+  if (x < rect.left || x > rect.left + rect.width || y < rect.top || y > rect.top + rect.height) {
16
+    return false;
17
+  }
18
+
19
+  return true;
20
+}

+ 16
- 0
src/whiteboard/AbstractWhiteboard/index.less View File

@@ -12,11 +12,27 @@
12 12
     height: 100%;
13 13
   }
14 14
 
15
+  &-imgs {
16
+    > div,
17
+    > div > div {
18
+      height: 100%;
19
+    }
20
+  }
21
+
15 22
   &-img {
16 23
     width: 100%;
17 24
     height: 100%;
18 25
   }
19 26
 
27
+  &-img-wrapper {
28
+    background-image: url(https://i.postimg.cc/RZwf0MRw/image.png);
29
+    background-size: contain;
30
+    background-position: center;
31
+    height: 100%;
32
+    width: 100%;
33
+    background-repeat: no-repeat;
34
+  }
35
+
20 36
   &-flip-arrow {
21 37
     height: 20px;
22 38
     width: 20px;

+ 115
- 6
src/whiteboard/AbstractWhiteboard/index.ts View File

@@ -19,12 +19,13 @@ export abstract class AbstractWhiteboard {
19 19
   /** 元素 */
20 20
   // 如果传入的是图片地址,则需要挂载到该 Target 元素下
21 21
   target: HTMLDivElement;
22
-  imgEles: HTMLImageElement[] = [];
22
+  imgEles: HTMLDivElement[] = [];
23 23
   imgsContainer: HTMLDivElement;
24 24
   pagesContainer: HTMLDivElement;
25 25
 
26 26
   /** Options */
27 27
   // 是否仅同步快照数据,用于弱网状态下
28
+  allowRollback: boolean = false;
28 29
   onlyEmitSnap: boolean = false;
29 30
   snapInterval: number = 15 * 1000;
30 31
 
@@ -48,6 +49,8 @@ export abstract class AbstractWhiteboard {
48 49
     return map;
49 50
   }
50 51
   siema: any;
52
+  // 历史快照记录
53
+  snapHistory: WhiteboardSnap[] = [];
51 54
 
52 55
   /** State | 内部状态 */
53 56
   // 是否被初始化过,如果尚未被初始化,则等待来自于 Master 的同步消息
@@ -58,7 +61,13 @@ export abstract class AbstractWhiteboard {
58 61
 
59 62
   constructor(
60 63
     target: HTMLDivElement,
61
-    { sources, eventHub, visiblePageIndex, onlyEmitSnap }: Partial<AbstractWhiteboard> = {}
64
+    {
65
+      sources,
66
+      eventHub,
67
+      visiblePageIndex,
68
+      allowRollback,
69
+      onlyEmitSnap
70
+    }: Partial<AbstractWhiteboard> = {}
62 71
   ) {
63 72
     if (target) {
64 73
       this.target = target;
@@ -86,6 +95,10 @@ export abstract class AbstractWhiteboard {
86 95
 
87 96
     this.onlyEmitSnap = !!onlyEmitSnap;
88 97
 
98
+    if (typeof allowRollback !== 'undefined') {
99
+      this.allowRollback = !!allowRollback;
100
+    }
101
+
89 102
     this.init();
90 103
   }
91 104
 
@@ -134,6 +147,18 @@ export abstract class AbstractWhiteboard {
134 147
       }
135 148
     }
136 149
 
150
+    // 判断是否进行了元素的增加或者删除,如果开启了则添加历史记录
151
+    if (
152
+      this.allowRollback &&
153
+      (borderEvent.event === 'addMarker' || borderEvent.event === 'removeMarker')
154
+    ) {
155
+      if (this.snapHistory.length > 20) {
156
+        this.snapHistory.shift();
157
+      }
158
+
159
+      this.snapHistory.push(this.captureSnap(false));
160
+    }
161
+
137 162
     borderEvent.timestamp = Math.floor(Date.now() / 1000);
138 163
     this.eventHub.emit('sync', borderEvent);
139 164
   }
@@ -158,6 +183,42 @@ export abstract class AbstractWhiteboard {
158 183
     };
159 184
   }
160 185
 
186
+  /** 回退到上一个 Snap */
187
+  public rollbackSnap() {
188
+    if (this.snapHistory.length === 0) {
189
+      return;
190
+    }
191
+
192
+    this.snapHistory.pop();
193
+    const snap = this.snapHistory[this.snapHistory.length - 1];
194
+
195
+    if (snap) {
196
+      this.applySnap(snap);
197
+    }
198
+  }
199
+
200
+  /** 销毁操作操作 */
201
+  public destroy(): void {
202
+    if (this.emitInterval) {
203
+      clearInterval(this.emitInterval);
204
+    }
205
+
206
+    if (this.eventHub) {
207
+      this.eventHub.removeAllListeners();
208
+    }
209
+
210
+    if (this.siema) {
211
+      this.siema.destroy();
212
+    }
213
+
214
+    this.imgsContainer.remove();
215
+    this.pagesContainer.remove();
216
+
217
+    this.pages.forEach(page => {
218
+      page.destroy();
219
+    });
220
+  }
221
+
161 222
   /** 初始化操作 */
162 223
   protected abstract init(): void;
163 224
 
@@ -165,10 +226,9 @@ export abstract class AbstractWhiteboard {
165 226
   protected initSiema() {
166 227
     // 初始化所有的占位图片,用于给 Siema 播放使用
167 228
     this.sources.forEach(source => {
168
-      const imgEle = document.createElement('img');
169
-      addClassName(imgEle, `${prefix}-img`);
170
-      imgEle.src = source;
171
-      imgEle.alt = 'Siema image';
229
+      const imgEle = document.createElement('div');
230
+      addClassName(imgEle, `${prefix}-img-wrapper`);
231
+      imgEle.style.backgroundImage = `url(${source})`;
172 232
 
173 233
       this.imgEles.push(imgEle);
174 234
       this.imgsContainer.appendChild(imgEle);
@@ -188,4 +248,53 @@ export abstract class AbstractWhiteboard {
188 248
       rtl: false
189 249
     });
190 250
   }
251
+
252
+  protected abstract onPageChange(nextPageIndex: number): void;
253
+
254
+  /** 响应获取到的快照事件 */
255
+  protected applySnap(snap: WhiteboardSnap) {
256
+    const { id, sources, pageIds } = snap;
257
+
258
+    if (!this.isInitialized && !this.isSyncing) {
259
+      this.id = id;
260
+      this.sources = sources;
261
+      this.isSyncing = true;
262
+
263
+      // 初始化所有的 WhitePages
264
+      this.sources.forEach((source, i) => {
265
+        const page = new WhitePage(
266
+          { imgSrc: source },
267
+          {
268
+            mode: this.mode,
269
+            whiteboard: this,
270
+            parentContainer: this.pagesContainer
271
+          }
272
+        );
273
+        page.id = pageIds[i];
274
+
275
+        // 这里隐藏 Dashboard 的图片源,Siema 切换的是占位图片
276
+        page.container.style.visibility = 'hidden';
277
+
278
+        this.pages.push(page);
279
+
280
+        page.open();
281
+      });
282
+
283
+      this.initSiema();
284
+      this.isInitialized = true;
285
+      this.isSyncing = false;
286
+    }
287
+
288
+    // 如果已经初始化完毕,则进行状态同步
289
+    this.onPageChange(snap.visiblePageIndex);
290
+
291
+    // 同步 Pages
292
+    (snap.pages || []).forEach(pageSnap => {
293
+      const page = this.pageMap[pageSnap.id];
294
+
295
+      if (page) {
296
+        page.applySnap(pageSnap);
297
+      }
298
+    });
299
+  }
191 300
 }

+ 9
- 50
src/whiteboard/MirrorWhiteboard/index.ts View File

@@ -1,7 +1,5 @@
1 1
 import { SyncEvent } from '../../event/SyncEvent';
2
-import { WhitePage } from '../WhitePage/index';
3 2
 import { createDivWithClassName } from '../../utils/dom';
4
-import { WhiteboardSnap } from '../AbstractWhiteboard/snap';
5 3
 import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
6 4
 import { Mode } from '../../utils/types';
7 5
 
@@ -35,11 +33,19 @@ export class MirrorWhiteboard extends AbstractWhiteboard {
35 33
           this.onPageChange(ev.border.visiblePageIndex);
36 34
         }
37 35
       }
36
+
37
+      if (ev.event === 'finish' && ev.id === this.id) {
38
+        this.destroy();
39
+      }
38 40
     });
39 41
   }
40 42
 
43
+  public destroy() {
44
+    super.destroy();
45
+  }
46
+
41 47
   /** 响应页面切换的事件 */
42
-  private onPageChange(nextPageIndex: number) {
48
+  onPageChange(nextPageIndex: number) {
43 49
     if (this.visiblePageIndex === nextPageIndex) {
44 50
       return;
45 51
     }
@@ -63,51 +69,4 @@ export class MirrorWhiteboard extends AbstractWhiteboard {
63 69
       border: this.captureSnap()
64 70
     });
65 71
   }
66
-
67
-  /** 响应获取到的快照事件 */
68
-  private applySnap(snap: WhiteboardSnap) {
69
-    const { id, sources, pageIds } = snap;
70
-
71
-    if (!this.isInitialized && !this.isSyncing) {
72
-      this.id = id;
73
-      this.sources = sources;
74
-      this.isSyncing = true;
75
-
76
-      // 初始化所有的 WhitePages
77
-      this.sources.forEach((source, i) => {
78
-        const page = new WhitePage(
79
-          { imgSrc: source },
80
-          {
81
-            mode: this.mode,
82
-            whiteboard: this,
83
-            parentContainer: this.pagesContainer
84
-          }
85
-        );
86
-        page.id = pageIds[i];
87
-
88
-        // 这里隐藏 Dashboard 的图片源,Siema 切换的是占位图片
89
-        page.container.style.visibility = 'hidden';
90
-
91
-        this.pages.push(page);
92
-
93
-        page.open();
94
-      });
95
-
96
-      this.initSiema();
97
-      this.isInitialized = true;
98
-      this.isSyncing = false;
99
-    }
100
-
101
-    // 如果已经初始化完毕,则进行状态同步
102
-    this.onPageChange(snap.visiblePageIndex);
103
-
104
-    // 同步 Pages
105
-    (snap.pages || []).forEach(pageSnap => {
106
-      const page = this.pageMap[pageSnap.id];
107
-
108
-      if (page) {
109
-        page.applySnap(pageSnap);
110
-      }
111
-    });
112
-  }
113 72
 }

+ 1
- 1
src/whiteboard/ReplayWhiteboard/index.ts View File

@@ -1,6 +1,6 @@
1 1
 import { MirrorWhiteboard } from '../MirrorWhiteboard';
2 2
 import { SyncEvent } from '../../event/SyncEvent';
3
-import { EventHub } from 'fc-whiteboard/src/event/EventHub';
3
+import { EventHub } from '../../event/EventHub';
4 4
 
5 5
 // 窗口大小为一分钟
6 6
 const windowSize = 60 * 1000;

+ 32
- 8
src/whiteboard/WhitePage/index.ts View File

@@ -9,7 +9,7 @@ import { WhitepageSnap } from '../AbstractWhiteboard/snap';
9 9
 import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
10 10
 
11 11
 import './index.less';
12
-import { ToolbarItem } from 'fc-whiteboard/src/toolbar/ToolbarItem';
12
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
13 13
 
14 14
 const prefix = 'fcw-page';
15 15
 
@@ -58,7 +58,7 @@ export class WhitePage {
58 58
     }
59 59
   }
60 60
 
61
-  /** LifeCycle open - close */
61
+  /** LifeCycle open - destroy */
62 62
   public open() {
63 63
     this.drawboard.open();
64 64
   }
@@ -71,8 +71,8 @@ export class WhitePage {
71 71
     this.drawboard.show();
72 72
   }
73 73
 
74
-  public close() {
75
-    this.drawboard.close();
74
+  public destroy() {
75
+    this.drawboard.destroy();
76 76
   }
77 77
 
78 78
   /** 生成快照 */
@@ -87,10 +87,15 @@ export class WhitePage {
87 87
 
88 88
   /** 应用快照 */
89 89
   public applySnap(snap: WhitepageSnap) {
90
+    const markerIdsSet = new Set();
91
+
90 92
     snap.markers.forEach(markerSnap => {
91 93
       // 判断是否存在,存在则同步,否则创建
92 94
       const marker = this.drawboard.markerMap[markerSnap.id];
93 95
 
96
+      markerIdsSet.add(markerSnap.id);
97
+
98
+      // 如果存在则直接应用,否则创建新的 Marker
94 99
       if (marker) {
95 100
         marker.applySnap(markerSnap);
96 101
       } else {
@@ -100,6 +105,14 @@ export class WhitePage {
100 105
         newMarker.applySnap(markerSnap);
101 106
       }
102 107
     });
108
+
109
+    // 移除当前不存在的 Marker
110
+    this.drawboard.markers.forEach(marker => {
111
+      if (!markerIdsSet.has(marker.id)) {
112
+        // 如果不存在该 Marker,则删除
113
+        this.drawboard.deleteMarkerWithEvent(marker);
114
+      }
115
+    });
103 116
   }
104 117
 
105 118
   /** 初始化源 */
@@ -136,13 +149,17 @@ export class WhitePage {
136 149
       this.drawboard = new Drawboard(
137 150
         { imgEle: this.target },
138 151
         {
139
-          page: this,
140 152
           extraToolbarItems,
153
+          mountContainer: this.whiteboard!.target,
154
+          page: this,
141 155
           onChange: ev => this.whiteboard!.emit(ev)
142 156
         }
143 157
       );
144 158
     } else {
145
-      this.drawboard = new Drawboard({ imgEle: this.target }, { page: this });
159
+      this.drawboard = new Drawboard(
160
+        { imgEle: this.target },
161
+        { page: this, mountContainer: this.whiteboard!.target }
162
+      );
146 163
     }
147 164
   }
148 165
 
@@ -152,7 +169,10 @@ export class WhitePage {
152 169
       throw new Error('Invalid whiteboard');
153 170
     }
154 171
 
155
-    this.drawboard = new Drawboard({ imgEle: this.target }, { page: this });
172
+    this.drawboard = new Drawboard(
173
+      { imgEle: this.target },
174
+      { page: this, mountContainer: this.whiteboard!.target }
175
+    );
156 176
 
157 177
     this.whiteboard!.eventHub!.on('sync', (ev: SyncEvent) => {
158 178
       try {
@@ -185,7 +205,11 @@ export class WhitePage {
185 205
     if (ev.event === 'addMarker' && ev.parentId === this.id) {
186 206
       const marker = this.drawboard.markerMap[id!];
187 207
       if (!marker) {
188
-        this.drawboard.addMarker(getMarkerByType(ev.marker.type!), { id: ev.marker.id });
208
+        this.drawboard.addMarker(getMarkerByType(ev.marker.type!), {
209
+          id: ev.marker.id,
210
+          originX: ev.marker.dx,
211
+          originY: ev.marker.dy
212
+        });
189 213
       }
190 214
     }
191 215
 

+ 71
- 4
src/whiteboard/Whiteboard/index.ts View File

@@ -1,3 +1,4 @@
1
+import { ToolbarItem } from './../../toolbar/ToolbarItem';
1 2
 import { WhitePage } from '../WhitePage/index';
2 3
 import { createDivWithClassName } from '../../utils/dom';
3 4
 import { AbstractWhiteboard } from '../AbstractWhiteboard/index';
@@ -6,12 +7,19 @@ import { separatorToolbarItem } from '../../toolbar/toolbar-items';
6 7
 
7 8
 const LeftArrowIcon = require('../../assets/bx-left-arrow.svg');
8 9
 const RightArrowIcon = require('../../assets/bx-right-arrow.svg');
10
+const FinishIcon = require('../../assets/finish.svg');
11
+const RollbackIcon = require('../../assets/rollback.svg');
9 12
 
10 13
 const prefix = 'fcw-board';
11 14
 
12 15
 export class Whiteboard extends AbstractWhiteboard {
13 16
   mode: Mode = 'master';
14 17
 
18
+  /** 销毁操作 */
19
+  public destroy() {
20
+    super.destroy();
21
+  }
22
+
15 23
   /** 初始化操作 */
16 24
   protected init() {
17 25
     // 为 target 添加子 imgs 容器
@@ -21,11 +29,16 @@ export class Whiteboard extends AbstractWhiteboard {
21 29
 
22 30
     this.initMaster();
23 31
 
32
+    // 添加初始化的 Snapshot
33
+    this.snapHistory.push(this.captureSnap(false));
34
+
24 35
     this.emitSnapshot();
25 36
   }
26 37
 
27 38
   /** 以主模式启动 */
28 39
   private initMaster() {
40
+    this.isInitialized = true;
41
+
29 42
     // 初始化控制节点
30 43
     const prevToolbarItem = {
31 44
       icon: LeftArrowIcon,
@@ -33,23 +46,69 @@ export class Whiteboard extends AbstractWhiteboard {
33 46
       tooltipText: 'Prev',
34 47
       onClick: () => {
35 48
         const nextPageIndex =
36
-          this.visiblePageIndex + 1 > this.pages.length - 1 ? 0 : this.visiblePageIndex + 1;
49
+          this.visiblePageIndex - 1 < 0 ? this.pages.length - 1 : this.visiblePageIndex - 1;
50
+
51
+        document.querySelectorAll('.fc-whiteboard-indicator-current').forEach(e => {
52
+          e.innerHTML = `${nextPageIndex + 1}`;
53
+        });
54
+
37 55
         this.onPageChange(nextPageIndex);
38 56
       }
39 57
     };
40 58
 
59
+    const indicatorContainer = document.createElement('div');
60
+    indicatorContainer.className = 'fc-whiteboard-indicator-container';
61
+    const indicatorCurrent = document.createElement('span');
62
+    indicatorCurrent.className = 'fc-whiteboard-indicator-current';
63
+    indicatorCurrent.innerHTML = `${this.visiblePageIndex + 1}`;
64
+
65
+    indicatorContainer.appendChild(indicatorCurrent);
66
+    indicatorContainer.appendChild(document.createTextNode(`/${this.sources.length}`));
67
+
68
+    const indicatorItem: ToolbarItem = {
69
+      name: 'indicator',
70
+      onRender: () => indicatorContainer
71
+    };
72
+
41 73
     const nextToolbarItem = {
42 74
       icon: RightArrowIcon,
43 75
       name: 'next-flip-arrow',
44 76
       tooltipText: 'Next',
45 77
       onClick: () => {
46 78
         const nextPageIndex =
47
-          this.visiblePageIndex - 1 < 0 ? this.pages.length - 1 : this.visiblePageIndex - 1;
79
+          this.visiblePageIndex + 1 > this.pages.length - 1 ? 0 : this.visiblePageIndex + 1;
80
+
81
+        document.querySelectorAll('.fc-whiteboard-indicator-current').forEach(e => {
82
+          e.innerHTML = `${nextPageIndex + 1}`;
83
+        });
48 84
 
49 85
         this.onPageChange(nextPageIndex);
50 86
       }
51 87
     };
52 88
 
89
+    const finishItem: ToolbarItem = {
90
+      icon: FinishIcon,
91
+      name: 'finish',
92
+      tooltipText: 'Finish',
93
+      onClick: () => {
94
+        this.emit({
95
+          event: 'finish',
96
+          id: this.id,
97
+          target: 'whiteboard'
98
+        });
99
+      }
100
+    };
101
+
102
+    const rollbackItem: ToolbarItem = {
103
+      icon: RollbackIcon,
104
+      name: 'rollback',
105
+      tooltipText: 'Rollback',
106
+      shortcut: 'ESC',
107
+      onClick: () => {
108
+        this.rollbackSnap();
109
+      }
110
+    };
111
+
53 112
     // 初始化所有的 WhitePages
54 113
     this.sources.forEach(source => {
55 114
       const page = new WhitePage(
@@ -58,7 +117,15 @@ export class Whiteboard extends AbstractWhiteboard {
58 117
           mode: this.mode,
59 118
           whiteboard: this,
60 119
           parentContainer: this.pagesContainer,
61
-          extraToolbarItems: [separatorToolbarItem, prevToolbarItem, nextToolbarItem]
120
+          extraToolbarItems: [
121
+            separatorToolbarItem,
122
+            prevToolbarItem,
123
+            indicatorItem,
124
+            nextToolbarItem,
125
+            separatorToolbarItem,
126
+            finishItem,
127
+            rollbackItem
128
+          ]
62 129
         }
63 130
       );
64 131
 
@@ -72,7 +139,7 @@ export class Whiteboard extends AbstractWhiteboard {
72 139
   }
73 140
 
74 141
   /** 响应页面切换的事件 */
75
-  private onPageChange(nextPageIndex: number) {
142
+  onPageChange(nextPageIndex: number) {
76 143
     if (this.visiblePageIndex === nextPageIndex) {
77 144
       return;
78 145
     }

+ 151
- 1
yarn.lock View File

@@ -119,6 +119,80 @@
119 119
     lodash "^4.17.11"
120 120
     to-fast-properties "^2.0.0"
121 121
 
122
+"@interactjs/actions@1.4.9":
123
+  version "1.4.9"
124
+  resolved "https://registry.npm.taobao.org/@interactjs/actions/download/@interactjs/actions-1.4.9.tgz#be7c71b17e0aa5510a6110a45e33c42382597130"
125
+  integrity sha1-vnxxsX4KpVEKYRCkXjPEI4JZcTA=
126
+
127
+"@interactjs/auto-scroll@1.4.9":
128
+  version "1.4.9"
129
+  resolved "https://registry.npm.taobao.org/@interactjs/auto-scroll/download/@interactjs/auto-scroll-1.4.9.tgz#4bafff16d0dfefe699c7547f7a751a8716412e2a"
130
+  integrity sha1-S6//FtDf7+aZx1R/enUahxZBLio=
131
+
132
+"@interactjs/auto-start@1.4.9":
133
+  version "1.4.9"
134
+  resolved "https://registry.npm.taobao.org/@interactjs/auto-start/download/@interactjs/auto-start-1.4.9.tgz#acf6178419275ff46f026e2daf01b499d2fde546"
135
+  integrity sha1-rPYXhBknX/RvAm4trwG0mdL95UY=
136
+
137
+"@interactjs/core@1.4.9":
138
+  version "1.4.9"
139
+  resolved "https://registry.npm.taobao.org/@interactjs/core/download/@interactjs/core-1.4.9.tgz#85993b67a9839676719f3e80719f0254b417439a"
140
+  integrity sha1-hZk7Z6mDlnZxnz6AcZ8CVLQXQ5o=
141
+
142
+"@interactjs/dev-tools@1.4.9":
143
+  version "1.4.9"
144
+  resolved "https://registry.npm.taobao.org/@interactjs/dev-tools/download/@interactjs/dev-tools-1.4.9.tgz#ffd555f956814a93aa12535a38186216aaa55878"
145
+  integrity sha1-/9VV+VaBSpOqElNaOBhiFqqlWHg=
146
+  dependencies:
147
+    "@interactjs/utils" "1.4.9"
148
+
149
+"@interactjs/inertia@1.4.9":
150
+  version "1.4.9"
151
+  resolved "https://registry.npm.taobao.org/@interactjs/inertia/download/@interactjs/inertia-1.4.9.tgz#9268750f1e04ae0f0e9d111bf3e12c2a05992c26"
152
+  integrity sha1-kmh1Dx4Erg8OnREb8+EsKgWZLCY=
153
+
154
+"@interactjs/interact@1.4.9":
155
+  version "1.4.9"
156
+  resolved "https://registry.npm.taobao.org/@interactjs/interact/download/@interactjs/interact-1.4.9.tgz#f0d7fb9555bb552bff421436e651cc2127f88572"
157
+  integrity sha1-8Nf7lVW7VSv/QhQ25lHMISf4hXI=
158
+
159
+"@interactjs/modifiers@1.4.9":
160
+  version "1.4.9"
161
+  resolved "https://registry.npm.taobao.org/@interactjs/modifiers/download/@interactjs/modifiers-1.4.9.tgz#9d96f7c72c4b3dab7f99fcfc9b0c50c97a7d80c9"
162
+  integrity sha1-nZb3xyxLPat/mfz8mwxQyXp9gMk=
163
+
164
+"@interactjs/pointer-events@1.4.9":
165
+  version "1.4.9"
166
+  resolved "https://registry.npm.taobao.org/@interactjs/pointer-events/download/@interactjs/pointer-events-1.4.9.tgz#1939f0076dcf10f9ca2f6dc1895a0d0bad515887"
167
+  integrity sha1-GTnwB23PEPnKL23BiVoNC61RWIc=
168
+
169
+"@interactjs/reflow@1.4.9":
170
+  version "1.4.9"
171
+  resolved "https://registry.npm.taobao.org/@interactjs/reflow/download/@interactjs/reflow-1.4.9.tgz#c4191ccf104049c46e9405593a4d23e0ac3b3db1"
172
+  integrity sha1-xBkczxBAScRulAVZOk0j4Kw7PbE=
173
+
174
+"@interactjs/types@1.4.9":
175
+  version "1.4.9"
176
+  resolved "https://registry.npm.taobao.org/@interactjs/types/download/@interactjs/types-1.4.9.tgz#13e25b1ad942071b42af95985f71407d932f8591"
177
+  integrity sha1-E+JbGtlCBxtCr5WYX3FAfZMvhZE=
178
+  dependencies:
179
+    "@interactjs/actions" "1.4.9"
180
+    "@interactjs/auto-scroll" "1.4.9"
181
+    "@interactjs/auto-start" "1.4.9"
182
+    "@interactjs/core" "1.4.9"
183
+    "@interactjs/dev-tools" "1.4.9"
184
+    "@interactjs/inertia" "1.4.9"
185
+    "@interactjs/interact" "1.4.9"
186
+    "@interactjs/modifiers" "1.4.9"
187
+    "@interactjs/pointer-events" "1.4.9"
188
+    "@interactjs/reflow" "1.4.9"
189
+    "@interactjs/utils" "1.4.9"
190
+
191
+"@interactjs/utils@1.4.9":
192
+  version "1.4.9"
193
+  resolved "https://registry.npm.taobao.org/@interactjs/utils/download/@interactjs/utils-1.4.9.tgz#be06d81eae37ceded95205500fbd3f7dd2fdadc5"
194
+  integrity sha1-vgbYHq43zt7ZUgVQD70/fdL9rcU=
195
+
122 196
 "@lerna/add@3.13.1":
123 197
   version "3.13.1"
124 198
   resolved "http://registry.npm.taobao.org/@lerna/add/download/@lerna/add-3.13.1.tgz#2cd7838857edb3b43ed73e3c21f69a20beb9b702"
@@ -3667,6 +3741,11 @@ eventemitter3@*, eventemitter3@^3.0.0, eventemitter3@^3.1.0:
3667 3741
   resolved "http://registry.npm.taobao.org/eventemitter3/download/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
3668 3742
   integrity sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=
3669 3743
 
3744
+eventemitter3@^3.1.2:
3745
+  version "3.1.2"
3746
+  resolved "https://registry.npm.taobao.org/eventemitter3/download/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
3747
+  integrity sha1-LT1I+cNGaY/Og6hdfWZOmFNd9uc=
3748
+
3670 3749
 events@^3.0.0:
3671 3750
   version "3.0.0"
3672 3751
   resolved "http://registry.npm.taobao.org/events/download/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
@@ -3936,6 +4015,20 @@ fb-watchman@^2.0.0:
3936 4015
   dependencies:
3937 4016
     bser "^2.0.0"
3938 4017
 
4018
+fc-hotkeys@^0.0.1-alpha.1:
4019
+  version "0.0.1-alpha.1"
4020
+  resolved "https://registry.npm.taobao.org/fc-hotkeys/download/fc-hotkeys-0.0.1-alpha.1.tgz#531cf2ffd73cf52ace324e76be2bd5ad4e2e9759"
4021
+  integrity sha1-Uxzy/9c89SrOMk52vivVrU4ul1k=
4022
+  dependencies:
4023
+    eventemitter3 "^3.1.2"
4024
+    interactjs "^1.4.0"
4025
+    mousetrap "^1.6.3"
4026
+    prop-types "^15.7.2"
4027
+    react "^16.8.6"
4028
+    react-dom "^16.8.6"
4029
+    siema "^1.5.1"
4030
+    uuid "^3.3.2"
4031
+
3939 4032
 figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
3940 4033
   version "3.5.1"
3941 4034
   resolved "http://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@@ -5017,6 +5110,13 @@ inspectpack@^3.0.1:
5017 5110
     pify "^3.0.0"
5018 5111
     yargs "^11.0.0"
5019 5112
 
5113
+interactjs@^1.4.0, interactjs@^1.4.9:
5114
+  version "1.4.9"
5115
+  resolved "https://registry.npm.taobao.org/interactjs/download/interactjs-1.4.9.tgz#7fb30c7c1c5befb767e700ebef12acaf22f8e563"
5116
+  integrity sha1-f7MMfBxb77dn5wDr7xKsryL45WM=
5117
+  dependencies:
5118
+    "@interactjs/types" "1.4.9"
5119
+
5020 5120
 internal-ip@^4.2.0:
5021 5121
   version "4.2.0"
5022 5122
   resolved "http://registry.npm.taobao.org/internal-ip/download/internal-ip-4.2.0.tgz#46e81b638d84c338e5c67e42b1a17db67d0814fa"
@@ -6327,6 +6427,11 @@ lodash.clonedeep@^4.5.0:
6327 6427
   resolved "http://registry.npm.taobao.org/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
6328 6428
   integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
6329 6429
 
6430
+lodash.debounce@^4.0.8:
6431
+  version "4.0.8"
6432
+  resolved "https://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash.debounce%2Fdownload%2Flodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
6433
+  integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
6434
+
6330 6435
 lodash.defaults@^3.1.2:
6331 6436
   version "3.1.2"
6332 6437
   resolved "http://registry.npm.taobao.org/lodash.defaults/download/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c"
@@ -6925,6 +7030,11 @@ most@^1.7.3:
6925 7030
     "@most/prelude" "^1.4.0"
6926 7031
     symbol-observable "^1.0.2"
6927 7032
 
7033
+mousetrap@^1.6.3:
7034
+  version "1.6.3"
7035
+  resolved "https://registry.npm.taobao.org/mousetrap/download/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a"
7036
+  integrity sha1-gP7klmX9R4vM8HLJ1GvfG/7TVYo=
7037
+
6928 7038
 move-concurrently@^1.0.1:
6929 7039
   version "1.0.1"
6930 7040
   resolved "http://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -7943,6 +8053,11 @@ pn@^1.1.0:
7943 8053
   resolved "http://registry.npm.taobao.org/pn/download/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
7944 8054
   integrity sha1-4vTO8OIZ9GPBeas3Rj5OHs3Muvs=
7945 8055
 
8056
+popper.js@^1.14.7:
8057
+  version "1.15.0"
8058
+  resolved "https://registry.npm.taobao.org/popper.js/download/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
8059
+  integrity sha1-VWC5m7rXZH6fqkdca4BWYh9aT/I=
8060
+
7946 8061
 portfinder@^1.0.9:
7947 8062
   version "1.0.20"
7948 8063
   resolved "http://registry.npm.taobao.org/portfinder/download/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a"
@@ -8382,7 +8497,7 @@ promzard@^0.3.0:
8382 8497
   dependencies:
8383 8498
     read "1"
8384 8499
 
8385
-prop-types@^15.6.1, prop-types@^15.6.2:
8500
+prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
8386 8501
   version "15.7.2"
8387 8502
   resolved "http://registry.npm.taobao.org/prop-types/download/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
8388 8503
   integrity sha1-UsQedbjIfnK52TYOAga5ncv/psU=
@@ -8592,6 +8707,16 @@ react-dom@^16.8.0:
8592 8707
     prop-types "^15.6.2"
8593 8708
     scheduler "^0.13.4"
8594 8709
 
8710
+react-dom@^16.8.6:
8711
+  version "16.8.6"
8712
+  resolved "https://registry.npm.taobao.org/react-dom/download/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
8713
+  integrity sha1-cdYwP2MeiwCX9WFl72CPBR/24Q8=
8714
+  dependencies:
8715
+    loose-envify "^1.1.0"
8716
+    object-assign "^4.1.1"
8717
+    prop-types "^15.6.2"
8718
+    scheduler "^0.13.6"
8719
+
8595 8720
 react-hot-loader@^4.6.3:
8596 8721
   version "4.8.0"
8597 8722
   resolved "http://registry.npm.taobao.org/react-hot-loader/download/react-hot-loader-4.8.0.tgz#0b7c7dd9407415e23eb8246fdd28b0b839f54cb6"
@@ -8652,6 +8777,16 @@ react@^16.8.0:
8652 8777
     prop-types "^15.6.2"
8653 8778
     scheduler "^0.13.4"
8654 8779
 
8780
+react@^16.8.6:
8781
+  version "16.8.6"
8782
+  resolved "https://registry.npm.taobao.org/react/download/react-16.8.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact%2Fdownload%2Freact-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
8783
+  integrity sha1-rWw6lhT9Ok6e9REX9U2IjaAfK74=
8784
+  dependencies:
8785
+    loose-envify "^1.1.0"
8786
+    object-assign "^4.1.1"
8787
+    prop-types "^15.6.2"
8788
+    scheduler "^0.13.6"
8789
+
8655 8790
 read-cmd-shim@^1.0.1:
8656 8791
   version "1.0.1"
8657 8792
   resolved "http://registry.npm.taobao.org/read-cmd-shim/download/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b"
@@ -9137,6 +9272,14 @@ scheduler@^0.13.4:
9137 9272
     loose-envify "^1.1.0"
9138 9273
     object-assign "^4.1.1"
9139 9274
 
9275
+scheduler@^0.13.6:
9276
+  version "0.13.6"
9277
+  resolved "https://registry.npm.taobao.org/scheduler/download/scheduler-0.13.6.tgz?cache=0&sync_timestamp=1559596534856&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fscheduler%2Fdownload%2Fscheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
9278
+  integrity sha1-RmpOwzJGezGpG5v3TlNHBy5M2Ik=
9279
+  dependencies:
9280
+    loose-envify "^1.1.0"
9281
+    object-assign "^4.1.1"
9282
+
9140 9283
 schema-utils@^1.0.0:
9141 9284
   version "1.0.0"
9142 9285
   resolved "http://registry.npm.taobao.org/schema-utils/download/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@@ -10014,6 +10157,13 @@ timsort@^0.3.0:
10014 10157
   resolved "http://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
10015 10158
   integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
10016 10159
 
10160
+tippy.js@^4.3.4:
10161
+  version "4.3.4"
10162
+  resolved "https://registry.npm.taobao.org/tippy.js/download/tippy.js-4.3.4.tgz#9a91fd5ce8c401f181b7adaa6b2c27f3d105f3ba"
10163
+  integrity sha1-mpH9XOjEAfGBt62qaywn89EF87o=
10164
+  dependencies:
10165
+    popper.js "^1.14.7"
10166
+
10017 10167
 tmp@^0.0.33:
10018 10168
   version "0.0.33"
10019 10169
   resolved "http://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"