Browse Source

feat: init commit

wxyyxc1992 5 years ago
commit
50b1c8e62b
100 changed files with 3768 additions and 0 deletions
  1. 0
    0
      dist/cjs/index.js
  2. 39
    0
      dist/cjs/markers/arrow/ArrowMarker.js
  3. 14
    0
      dist/cjs/markers/arrow/ArrowMarkerToolbarItem.js
  4. 112
    0
      dist/cjs/markers/base/MarkerBase.js
  5. 193
    0
      dist/cjs/markers/base/RectangularMarkerBase.js
  6. 31
    0
      dist/cjs/markers/base/RectangularMarkerGrips.js
  7. 11
    0
      dist/cjs/markers/base/ResizeGrip.js
  8. 34
    0
      dist/cjs/markers/cover/CoverMarker.js
  9. 14
    0
      dist/cjs/markers/cover/CoverMarkerToolbarItem.js
  10. 34
    0
      dist/cjs/markers/highlight/HighlightMarker.js
  11. 14
    0
      dist/cjs/markers/highlight/HighlightMarkerToolbarItem.js
  12. 34
    0
      dist/cjs/markers/line/LineMarker.js
  13. 148
    0
      dist/cjs/markers/line/LineMarkerBase.js
  14. 14
    0
      dist/cjs/markers/line/LineMarkerToolbarItem.js
  15. 34
    0
      dist/cjs/markers/rect/RectMarker.js
  16. 40
    0
      dist/cjs/markers/rect/RectMarkerBase.js
  17. 14
    0
      dist/cjs/markers/rect/RectMarkerToolbarItem.js
  18. 140
    0
      dist/cjs/markers/text/TextMarker.js
  19. 14
    0
      dist/cjs/markers/text/TextMarkerToolbarItem.js
  20. 20
    0
      dist/cjs/render/Activator.js
  21. 305
    0
      dist/cjs/render/MarkerArea.js
  22. 30
    0
      dist/cjs/render/Renderer.js
  23. 22
    0
      dist/cjs/toolbar/Toolbar.js
  24. 37
    0
      dist/cjs/toolbar/ToolbarButton.js
  25. 2
    0
      dist/cjs/toolbar/ToolbarItem.js
  26. 97
    0
      dist/cjs/utils/SvgHelper/index.js
  27. 1
    0
      dist/index.js
  28. 0
    0
      dist/types/index.d.ts
  29. 6
    0
      dist/types/markers/arrow/ArrowMarker.d.ts
  30. 8
    0
      dist/types/markers/arrow/ArrowMarkerToolbarItem.d.ts
  31. 27
    0
      dist/types/markers/base/MarkerBase.d.ts
  32. 25
    0
      dist/types/markers/base/RectangularMarkerBase.d.ts
  33. 12
    0
      dist/types/markers/base/RectangularMarkerGrips.d.ts
  34. 5
    0
      dist/types/markers/base/ResizeGrip.d.ts
  35. 5
    0
      dist/types/markers/cover/CoverMarker.d.ts
  36. 8
    0
      dist/types/markers/cover/CoverMarkerToolbarItem.d.ts
  37. 5
    0
      dist/types/markers/highlight/HighlightMarker.d.ts
  38. 8
    0
      dist/types/markers/highlight/HighlightMarkerToolbarItem.d.ts
  39. 5
    0
      dist/types/markers/line/LineMarker.d.ts
  40. 30
    0
      dist/types/markers/line/LineMarkerBase.d.ts
  41. 8
    0
      dist/types/markers/line/LineMarkerToolbarItem.d.ts
  42. 5
    0
      dist/types/markers/rect/RectMarker.d.ts
  43. 7
    0
      dist/types/markers/rect/RectMarkerBase.d.ts
  44. 8
    0
      dist/types/markers/rect/RectMarkerToolbarItem.d.ts
  45. 21
    0
      dist/types/markers/text/TextMarker.d.ts
  46. 8
    0
      dist/types/markers/text/TextMarkerToolbarItem.d.ts
  47. 4
    0
      dist/types/render/Activator.d.ts
  48. 55
    0
      dist/types/render/MarkerArea.d.ts
  49. 3
    0
      dist/types/render/Renderer.d.ts
  50. 8
    0
      dist/types/toolbar/Toolbar.d.ts
  51. 7
    0
      dist/types/toolbar/ToolbarButton.d.ts
  52. 7
    0
      dist/types/toolbar/ToolbarItem.d.ts
  53. 13
    0
      dist/types/utils/SvgHelper/index.d.ts
  54. 0
    0
      example/index.less
  55. 19
    0
      example/index.ts
  56. 9
    0
      example/types.d.ts
  57. 89
    0
      package.json
  58. 5
    0
      postcss.config.js
  59. 0
    0
      public/drawboard.html
  60. BIN
      public/favicon.ico
  61. 39
    0
      public/index.html
  62. 15
    0
      public/manifest.json
  63. 0
    0
      public/mirror.html
  64. 19
    0
      scripts/webpack/webpack.config.dev.js
  65. 10
    0
      scripts/webpack/webpack.config.umd.js
  66. 5
    0
      src/assets/arrow.svg
  67. 5
    0
      src/assets/check.svg
  68. 5
    0
      src/assets/cover.svg
  69. 5
    0
      src/assets/eraser.svg
  70. 5
    0
      src/assets/highlight.svg
  71. 5
    0
      src/assets/line.svg
  72. 5
    0
      src/assets/mouse-pointer.svg
  73. 5
    0
      src/assets/rect.svg
  74. 5
    0
      src/assets/text.svg
  75. 5
    0
      src/assets/times.svg
  76. 116
    0
      src/board/Drawboard/index.less
  77. 440
    0
      src/board/Drawboard/index.ts
  78. 0
    0
      src/board/WhitePage/index.less
  79. 57
    0
      src/board/WhitePage/index.ts
  80. 0
    0
      src/board/Whiteboard/index.less
  81. 15
    0
      src/board/Whiteboard/index.ts
  82. 6
    0
      src/board/types.ts
  83. 20
    0
      src/event/Event.ts
  84. 10
    0
      src/event/EventHub.ts
  85. 1
    0
      src/index.ts
  86. 38
    0
      src/markers/ArrowMarker/index.ts
  87. 11
    0
      src/markers/BaseMarker/ResizeGrip.ts
  88. 185
    0
      src/markers/BaseMarker/index.ts
  89. 18
    0
      src/markers/CoverMarker/index.ts
  90. 18
    0
      src/markers/HighlightMarker/index.ts
  91. 18
    0
      src/markers/LineMarker/index.ts
  92. 168
    0
      src/markers/LinearMarker/index.ts
  93. 26
    0
      src/markers/RectMarker/RectBaseMarker.ts
  94. 18
    0
      src/markers/RectMarker/index.ts
  95. 35
    0
      src/markers/RectangularMarker/RectangularMarkerGrips.ts
  96. 246
    0
      src/markers/RectangularMarker/index.ts
  97. 151
    0
      src/markers/TextMarker/index.ts
  98. 27
    0
      src/markers/types.ts
  99. 143
    0
      src/renderer/SvgHelper/index.ts
  100. 0
    0
      src/renderer/Synthetizer/index.ts

+ 0
- 0
dist/cjs/index.js View File


+ 39
- 0
dist/cjs/markers/arrow/ArrowMarker.js View File

@@ -0,0 +1,39 @@
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 LineMarkerBase_1 = require("../line/LineMarkerBase");
17
+var SvgHelper_1 = require("../../utils/SvgHelper");
18
+var ArrowMarker = (function (_super) {
19
+    __extends(ArrowMarker, _super);
20
+    function ArrowMarker() {
21
+        var _this = _super !== null && _super.apply(this, arguments) || this;
22
+        _this.ARROW_SIZE = 6;
23
+        return _this;
24
+    }
25
+    ArrowMarker.prototype.setup = function () {
26
+        _super.prototype.setup.call(this);
27
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'arrow-marker']]);
28
+        var tip = SvgHelper_1.SvgHelper.createPolygon("0,0 " + this.ARROW_SIZE + "," + this.ARROW_SIZE / 2 + " 0," + this.ARROW_SIZE, [['class', 'arrow-marker-tip']]);
29
+        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));
30
+        this.markerLine.setAttribute('marker-end', 'url(#arrow-marker-head');
31
+    };
32
+    ArrowMarker.createMarker = function () {
33
+        var marker = new ArrowMarker();
34
+        marker.setup();
35
+        return marker;
36
+    };
37
+    return ArrowMarker;
38
+}(LineMarkerBase_1.LineMarkerBase));
39
+exports.ArrowMarker = ArrowMarker;

+ 14
- 0
dist/cjs/markers/arrow/ArrowMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var ArrowMarker_1 = require("./ArrowMarker");
4
+var arrow_marker_toolbar_icon_svg_1 = require("./arrow-marker-toolbar-icon.svg");
5
+var ArrowMarkerToolbarItem = (function () {
6
+    function ArrowMarkerToolbarItem() {
7
+        this.name = 'arrow-marker';
8
+        this.tooltipText = 'Arrow';
9
+        this.icon = arrow_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = ArrowMarker_1.ArrowMarker;
11
+    }
12
+    return ArrowMarkerToolbarItem;
13
+}());
14
+exports.ArrowMarkerToolbarItem = ArrowMarkerToolbarItem;

+ 112
- 0
dist/cjs/markers/base/MarkerBase.js View File

@@ -0,0 +1,112 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var SvgHelper_1 = require("../../utils/SvgHelper");
4
+var MarkerBase = (function () {
5
+    function MarkerBase() {
6
+        var _this = this;
7
+        this.defs = [];
8
+        this.width = 200;
9
+        this.height = 50;
10
+        this.isActive = true;
11
+        this.isResizing = false;
12
+        this.previousMouseX = 0;
13
+        this.previousMouseY = 0;
14
+        this.isDragging = false;
15
+        this.manipulate = function (ev) {
16
+            var scale = _this.visual.getScreenCTM().a;
17
+            var dx = (ev.screenX - _this.previousMouseX) / scale;
18
+            var dy = (ev.screenY - _this.previousMouseY) / scale;
19
+            if (_this.isDragging) {
20
+                _this.move(dx, dy);
21
+            }
22
+            if (_this.isResizing) {
23
+                _this.resize(dx, dy);
24
+            }
25
+            _this.previousMouseX = ev.screenX;
26
+            _this.previousMouseY = ev.screenY;
27
+        };
28
+        this.addToVisual = function (el) {
29
+            _this.visual.appendChild(el);
30
+        };
31
+        this.addToRenderVisual = function (el) {
32
+            _this.renderVisual.appendChild(el);
33
+        };
34
+        this.mouseDown = function (ev) {
35
+            ev.stopPropagation();
36
+            _this.select();
37
+            _this.isDragging = true;
38
+            _this.previousMouseX = ev.screenX;
39
+            _this.previousMouseY = ev.screenY;
40
+        };
41
+        this.mouseUp = function (ev) {
42
+            ev.stopPropagation();
43
+            _this.endManipulation();
44
+        };
45
+        this.mouseMove = function (ev) {
46
+            ev.stopPropagation();
47
+            _this.manipulate(ev);
48
+        };
49
+        this.move = function (dx, dy) {
50
+            var translate = _this.visual.transform.baseVal.getItem(0);
51
+            translate.setMatrix(translate.matrix.translate(dx, dy));
52
+            _this.visual.transform.baseVal.replaceItem(translate, 0);
53
+        };
54
+    }
55
+    MarkerBase.prototype.endManipulation = function () {
56
+        this.isDragging = false;
57
+        this.isResizing = false;
58
+    };
59
+    MarkerBase.prototype.select = function () {
60
+        this.isActive = true;
61
+        if (this.onSelected) {
62
+            this.onSelected(this);
63
+        }
64
+        return;
65
+    };
66
+    MarkerBase.prototype.deselect = function () {
67
+        this.isActive = false;
68
+        this.endManipulation();
69
+        return;
70
+    };
71
+    MarkerBase.prototype.setup = function () {
72
+        this.visual = SvgHelper_1.SvgHelper.createGroup();
73
+        this.visual.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
74
+        this.visual.addEventListener('mousedown', this.mouseDown);
75
+        this.visual.addEventListener('mouseup', this.mouseUp);
76
+        this.visual.addEventListener('mousemove', this.mouseMove);
77
+        this.visual.addEventListener('touchstart', this.onTouch, { passive: false });
78
+        this.visual.addEventListener('touchend', this.onTouch, { passive: false });
79
+        this.visual.addEventListener('touchmove', this.onTouch, { passive: false });
80
+        this.renderVisual = SvgHelper_1.SvgHelper.createGroup([['class', 'render-visual']]);
81
+        this.visual.appendChild(this.renderVisual);
82
+    };
83
+    MarkerBase.prototype.resize = function (x, y) {
84
+        return;
85
+    };
86
+    MarkerBase.prototype.onTouch = function (ev) {
87
+        ev.preventDefault();
88
+        var newEvt = document.createEvent('MouseEvents');
89
+        var touch = ev.changedTouches[0];
90
+        var type = null;
91
+        switch (ev.type) {
92
+            case 'touchstart':
93
+                type = 'mousedown';
94
+                break;
95
+            case 'touchmove':
96
+                type = 'mousemove';
97
+                break;
98
+            case 'touchend':
99
+                type = 'mouseup';
100
+                break;
101
+        }
102
+        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);
103
+        ev.target.dispatchEvent(newEvt);
104
+    };
105
+    MarkerBase.createMarker = function () {
106
+        var marker = new MarkerBase();
107
+        marker.setup();
108
+        return marker;
109
+    };
110
+    return MarkerBase;
111
+}());
112
+exports.MarkerBase = MarkerBase;

+ 193
- 0
dist/cjs/markers/base/RectangularMarkerBase.js View File

@@ -0,0 +1,193 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var MarkerBase_1 = require("./MarkerBase");
18
+var RectangularMarkerGrips_1 = require("./RectangularMarkerGrips");
19
+var ResizeGrip_1 = require("./ResizeGrip");
20
+var RectangularMarkerBase = (function (_super) {
21
+    __extends(RectangularMarkerBase, _super);
22
+    function RectangularMarkerBase() {
23
+        var _this = _super !== null && _super.apply(this, arguments) || this;
24
+        _this.MIN_SIZE = 5;
25
+        _this.CB_DISTANCE = 10;
26
+        _this.addControlBox = function () {
27
+            _this.controlBox = SvgHelper_1.SvgHelper.createGroup([['class', 'fc-whiteboardrect-control-box']]);
28
+            var translate = SvgHelper_1.SvgHelper.createTransform();
29
+            translate.setTranslate(-_this.CB_DISTANCE / 2, -_this.CB_DISTANCE / 2);
30
+            _this.controlBox.transform.baseVal.appendItem(translate);
31
+            _this.addToVisual(_this.controlBox);
32
+            _this.controlRect = SvgHelper_1.SvgHelper.createRect(_this.width + _this.CB_DISTANCE, _this.height + _this.CB_DISTANCE, [['class', 'fc-whiteboardrect-control-rect']]);
33
+            _this.controlBox.appendChild(_this.controlRect);
34
+            _this.controlGrips = new RectangularMarkerGrips_1.RectangularMarkerGrips();
35
+            _this.addControlGrips();
36
+        };
37
+        _this.adjustControlBox = function () {
38
+            _this.controlRect.setAttribute('width', (_this.width + _this.CB_DISTANCE).toString());
39
+            _this.controlRect.setAttribute('height', (_this.height + _this.CB_DISTANCE).toString());
40
+            _this.positionGrips();
41
+        };
42
+        _this.addControlGrips = function () {
43
+            _this.controlGrips.topLeft = _this.createGrip();
44
+            _this.controlGrips.topCenter = _this.createGrip();
45
+            _this.controlGrips.topRight = _this.createGrip();
46
+            _this.controlGrips.centerLeft = _this.createGrip();
47
+            _this.controlGrips.centerRight = _this.createGrip();
48
+            _this.controlGrips.bottomLeft = _this.createGrip();
49
+            _this.controlGrips.bottomCenter = _this.createGrip();
50
+            _this.controlGrips.bottomRight = _this.createGrip();
51
+            _this.positionGrips();
52
+        };
53
+        _this.createGrip = function () {
54
+            var grip = new ResizeGrip_1.ResizeGrip();
55
+            grip.visual.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
56
+            _this.controlBox.appendChild(grip.visual);
57
+            grip.visual.addEventListener('mousedown', _this.gripMouseDown);
58
+            grip.visual.addEventListener('mousemove', _this.gripMouseMove);
59
+            grip.visual.addEventListener('mouseup', _this.gripMouseUp);
60
+            grip.visual.addEventListener('touchstart', _this.onTouch, { passive: false });
61
+            grip.visual.addEventListener('touchend', _this.onTouch, { passive: false });
62
+            grip.visual.addEventListener('touchmove', _this.onTouch, { passive: false });
63
+            return grip;
64
+        };
65
+        _this.positionGrips = function () {
66
+            var gripSize = _this.controlGrips.topLeft.GRIP_SIZE;
67
+            var left = -gripSize / 2;
68
+            var top = left;
69
+            var cx = (_this.width + _this.CB_DISTANCE) / 2 - gripSize / 2;
70
+            var cy = (_this.height + _this.CB_DISTANCE) / 2 - gripSize / 2;
71
+            var bottom = _this.height + _this.CB_DISTANCE - gripSize / 2;
72
+            var right = _this.width + _this.CB_DISTANCE - gripSize / 2;
73
+            _this.positionGrip(_this.controlGrips.topLeft.visual, left, top);
74
+            _this.positionGrip(_this.controlGrips.topCenter.visual, cx, top);
75
+            _this.positionGrip(_this.controlGrips.topRight.visual, right, top);
76
+            _this.positionGrip(_this.controlGrips.centerLeft.visual, left, cy);
77
+            _this.positionGrip(_this.controlGrips.centerRight.visual, right, cy);
78
+            _this.positionGrip(_this.controlGrips.bottomLeft.visual, left, bottom);
79
+            _this.positionGrip(_this.controlGrips.bottomCenter.visual, cx, bottom);
80
+            _this.positionGrip(_this.controlGrips.bottomRight.visual, right, bottom);
81
+        };
82
+        _this.positionGrip = function (grip, x, y) {
83
+            var translate = grip.transform.baseVal.getItem(0);
84
+            translate.setTranslate(x, y);
85
+            grip.transform.baseVal.replaceItem(translate, 0);
86
+        };
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
+        return _this;
105
+    }
106
+    RectangularMarkerBase.prototype.endManipulation = function () {
107
+        _super.prototype.endManipulation.call(this);
108
+        this.isResizing = false;
109
+        this.activeGrip = null;
110
+    };
111
+    RectangularMarkerBase.prototype.select = function () {
112
+        _super.prototype.select.call(this);
113
+        this.controlBox.style.display = '';
114
+    };
115
+    RectangularMarkerBase.prototype.deselect = function () {
116
+        _super.prototype.deselect.call(this);
117
+        this.controlBox.style.display = 'none';
118
+    };
119
+    RectangularMarkerBase.prototype.setup = function () {
120
+        _super.prototype.setup.call(this);
121
+        this.addControlBox();
122
+    };
123
+    RectangularMarkerBase.prototype.resize = function (x, y) {
124
+        var translateX = 0;
125
+        var translateY = 0;
126
+        switch (this.activeGrip) {
127
+            case this.controlGrips.topLeft:
128
+                this.width -= x;
129
+                this.height -= y;
130
+                translateX += x;
131
+                translateY += y;
132
+                break;
133
+            case this.controlGrips.bottomLeft:
134
+                this.width -= x;
135
+                this.height += y;
136
+                translateX += x;
137
+                break;
138
+            case this.controlGrips.topRight:
139
+                this.width += x;
140
+                this.height -= y;
141
+                translateY += y;
142
+                break;
143
+            case this.controlGrips.bottomRight:
144
+                this.width += x;
145
+                this.height += y;
146
+                break;
147
+            case this.controlGrips.centerLeft:
148
+                this.width -= x;
149
+                translateX += x;
150
+                break;
151
+            case this.controlGrips.centerRight:
152
+                this.width += x;
153
+                break;
154
+            case this.controlGrips.topCenter:
155
+                this.height -= y;
156
+                translateY += y;
157
+                break;
158
+            case this.controlGrips.bottomCenter:
159
+                this.height += y;
160
+                break;
161
+        }
162
+        if (this.width < this.MIN_SIZE) {
163
+            var offset = this.MIN_SIZE - this.width;
164
+            this.width = this.MIN_SIZE;
165
+            if (translateX !== 0) {
166
+                translateX -= offset;
167
+            }
168
+        }
169
+        if (this.height < this.MIN_SIZE) {
170
+            var offset = this.MIN_SIZE - this.height;
171
+            this.height = this.MIN_SIZE;
172
+            if (translateY !== 0) {
173
+                translateY -= offset;
174
+            }
175
+        }
176
+        if (translateX !== 0 || translateY !== 0) {
177
+            var translate = this.visual.transform.baseVal.getItem(0);
178
+            translate.setMatrix(translate.matrix.translate(translateX, translateY));
179
+            this.visual.transform.baseVal.replaceItem(translate, 0);
180
+        }
181
+        this.adjustControlBox();
182
+    };
183
+    RectangularMarkerBase.prototype.onTouch = function (ev) {
184
+        _super.prototype.onTouch.call(this, ev);
185
+    };
186
+    RectangularMarkerBase.createMarker = function () {
187
+        var marker = new RectangularMarkerBase();
188
+        marker.setup();
189
+        return marker;
190
+    };
191
+    return RectangularMarkerBase;
192
+}(MarkerBase_1.MarkerBase));
193
+exports.RectangularMarkerBase = RectangularMarkerBase;

+ 31
- 0
dist/cjs/markers/base/RectangularMarkerGrips.js View File

@@ -0,0 +1,31 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var RectangularMarkerGrips = (function () {
4
+    function RectangularMarkerGrips() {
5
+        var _this = this;
6
+        this.findGripByVisual = function (gripVisual) {
7
+            switch (gripVisual) {
8
+                case _this.topLeft.visual:
9
+                    return _this.topLeft;
10
+                case _this.topCenter.visual:
11
+                    return _this.topCenter;
12
+                case _this.topRight.visual:
13
+                    return _this.topRight;
14
+                case _this.centerLeft.visual:
15
+                    return _this.centerLeft;
16
+                case _this.centerRight.visual:
17
+                    return _this.centerRight;
18
+                case _this.bottomLeft.visual:
19
+                    return _this.bottomLeft;
20
+                case _this.bottomCenter.visual:
21
+                    return _this.bottomCenter;
22
+                case _this.bottomRight.visual:
23
+                    return _this.bottomRight;
24
+                default:
25
+                    return _this.topLeft;
26
+            }
27
+        };
28
+    }
29
+    return RectangularMarkerGrips;
30
+}());
31
+exports.RectangularMarkerGrips = RectangularMarkerGrips;

+ 11
- 0
dist/cjs/markers/base/ResizeGrip.js View File

@@ -0,0 +1,11 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var SvgHelper_1 = require("../../utils/SvgHelper");
4
+var ResizeGrip = (function () {
5
+    function ResizeGrip() {
6
+        this.GRIP_SIZE = 10;
7
+        this.visual = SvgHelper_1.SvgHelper.createCircle(this.GRIP_SIZE, [['class', 'fc-whiteboardcontrol-grip']]);
8
+    }
9
+    return ResizeGrip;
10
+}());
11
+exports.ResizeGrip = ResizeGrip;

+ 34
- 0
dist/cjs/markers/cover/CoverMarker.js View File

@@ -0,0 +1,34 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var RectMarkerBase_1 = require("../rect/RectMarkerBase");
18
+var CoverMarker = (function (_super) {
19
+    __extends(CoverMarker, _super);
20
+    function CoverMarker() {
21
+        return _super !== null && _super.apply(this, arguments) || this;
22
+    }
23
+    CoverMarker.prototype.setup = function () {
24
+        _super.prototype.setup.call(this);
25
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'cover-marker']]);
26
+    };
27
+    CoverMarker.createMarker = function () {
28
+        var marker = new CoverMarker();
29
+        marker.setup();
30
+        return marker;
31
+    };
32
+    return CoverMarker;
33
+}(RectMarkerBase_1.RectMarkerBase));
34
+exports.CoverMarker = CoverMarker;

+ 14
- 0
dist/cjs/markers/cover/CoverMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var CoverMarker_1 = require("./CoverMarker");
4
+var cover_marker_toolbar_icon_svg_1 = require("./cover-marker-toolbar-icon.svg");
5
+var CoverMarkerToolbarItem = (function () {
6
+    function CoverMarkerToolbarItem() {
7
+        this.name = 'cover-marker';
8
+        this.tooltipText = 'Cover';
9
+        this.icon = cover_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = CoverMarker_1.CoverMarker;
11
+    }
12
+    return CoverMarkerToolbarItem;
13
+}());
14
+exports.CoverMarkerToolbarItem = CoverMarkerToolbarItem;

+ 34
- 0
dist/cjs/markers/highlight/HighlightMarker.js View File

@@ -0,0 +1,34 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var RectMarkerBase_1 = require("../rect/RectMarkerBase");
18
+var HighlightMarker = (function (_super) {
19
+    __extends(HighlightMarker, _super);
20
+    function HighlightMarker() {
21
+        return _super !== null && _super.apply(this, arguments) || this;
22
+    }
23
+    HighlightMarker.prototype.setup = function () {
24
+        _super.prototype.setup.call(this);
25
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'highlight-marker']]);
26
+    };
27
+    HighlightMarker.createMarker = function () {
28
+        var marker = new HighlightMarker();
29
+        marker.setup();
30
+        return marker;
31
+    };
32
+    return HighlightMarker;
33
+}(RectMarkerBase_1.RectMarkerBase));
34
+exports.HighlightMarker = HighlightMarker;

+ 14
- 0
dist/cjs/markers/highlight/HighlightMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var HighlightMarker_1 = require("./HighlightMarker");
4
+var highlight_marker_toolbar_icon_svg_1 = require("./highlight-marker-toolbar-icon.svg");
5
+var HighlightMarkerToolbarItem = (function () {
6
+    function HighlightMarkerToolbarItem() {
7
+        this.name = 'cover-marker';
8
+        this.tooltipText = 'Cover';
9
+        this.icon = highlight_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = HighlightMarker_1.HighlightMarker;
11
+    }
12
+    return HighlightMarkerToolbarItem;
13
+}());
14
+exports.HighlightMarkerToolbarItem = HighlightMarkerToolbarItem;

+ 34
- 0
dist/cjs/markers/line/LineMarker.js View File

@@ -0,0 +1,34 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var LineMarkerBase_1 = require("./LineMarkerBase");
18
+var LineMarker = (function (_super) {
19
+    __extends(LineMarker, _super);
20
+    function LineMarker() {
21
+        return _super !== null && _super.apply(this, arguments) || this;
22
+    }
23
+    LineMarker.prototype.setup = function () {
24
+        _super.prototype.setup.call(this);
25
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'line-marker']]);
26
+    };
27
+    LineMarker.createMarker = function () {
28
+        var marker = new LineMarker();
29
+        marker.setup();
30
+        return marker;
31
+    };
32
+    return LineMarker;
33
+}(LineMarkerBase_1.LineMarkerBase));
34
+exports.LineMarker = LineMarker;

+ 148
- 0
dist/cjs/markers/line/LineMarkerBase.js View File

@@ -0,0 +1,148 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var MarkerBase_1 = require("../base/MarkerBase");
18
+var ResizeGrip_1 = require("../base/ResizeGrip");
19
+var LineMarkerBase = (function (_super) {
20
+    __extends(LineMarkerBase, _super);
21
+    function LineMarkerBase() {
22
+        var _this = _super !== null && _super.apply(this, arguments) || this;
23
+        _this.MIN_LENGTH = 20;
24
+        _this.x1 = 0;
25
+        _this.y1 = 0;
26
+        _this.x2 = _this.width;
27
+        _this.y2 = 0;
28
+        _this.getLineLength = function (x1, y1, x2, y2) {
29
+            var dx = Math.abs(x1 - x2);
30
+            var dy = Math.abs(y1 - y2);
31
+            return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
32
+        };
33
+        _this.addControlBox = function () {
34
+            _this.controlBox = SvgHelper_1.SvgHelper.createGroup([['class', 'fc-whiteboardline-control-box']]);
35
+            _this.addToVisual(_this.controlBox);
36
+            _this.addControlGrips();
37
+        };
38
+        _this.adjustControlBox = function () {
39
+            _this.positionGrips();
40
+        };
41
+        _this.addControlGrips = function () {
42
+            _this.controlGrip1 = _this.createGrip();
43
+            _this.controlGrip2 = _this.createGrip();
44
+            _this.positionGrips();
45
+        };
46
+        _this.createGrip = function () {
47
+            var grip = new ResizeGrip_1.ResizeGrip();
48
+            grip.visual.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
49
+            _this.controlBox.appendChild(grip.visual);
50
+            grip.visual.addEventListener('mousedown', _this.gripMouseDown);
51
+            grip.visual.addEventListener('mousemove', _this.gripMouseMove);
52
+            grip.visual.addEventListener('mouseup', _this.gripMouseUp);
53
+            grip.visual.addEventListener('touchstart', _this.onTouch, { passive: false });
54
+            grip.visual.addEventListener('touchend', _this.onTouch, { passive: false });
55
+            grip.visual.addEventListener('touchmove', _this.onTouch, { passive: false });
56
+            return grip;
57
+        };
58
+        _this.positionGrips = function () {
59
+            var gripSize = _this.controlGrip1.GRIP_SIZE;
60
+            var x1 = _this.x1 - gripSize / 2;
61
+            var y1 = _this.y1 - gripSize / 2;
62
+            var x2 = _this.x2 - gripSize / 2;
63
+            var y2 = _this.y2 - gripSize / 2;
64
+            _this.positionGrip(_this.controlGrip1.visual, x1, y1);
65
+            _this.positionGrip(_this.controlGrip2.visual, x2, y2);
66
+        };
67
+        _this.positionGrip = function (grip, x, y) {
68
+            var translate = grip.transform.baseVal.getItem(0);
69
+            translate.setTranslate(x, y);
70
+            grip.transform.baseVal.replaceItem(translate, 0);
71
+        };
72
+        _this.gripMouseDown = function (ev) {
73
+            _this.isResizing = true;
74
+            _this.activeGrip =
75
+                ev.target === _this.controlGrip1.visual
76
+                    ? _this.controlGrip1
77
+                    : _this.controlGrip2;
78
+            _this.previousMouseX = ev.screenX;
79
+            _this.previousMouseY = ev.screenY;
80
+            ev.stopPropagation();
81
+        };
82
+        _this.gripMouseUp = function (ev) {
83
+            _this.isResizing = false;
84
+            _this.activeGrip = null;
85
+            ev.stopPropagation();
86
+        };
87
+        _this.gripMouseMove = function (ev) {
88
+            if (_this.isResizing) {
89
+                _this.resize(ev.movementX, ev.movementY);
90
+            }
91
+        };
92
+        return _this;
93
+    }
94
+    LineMarkerBase.prototype.endManipulation = function () {
95
+        _super.prototype.endManipulation.call(this);
96
+        this.isResizing = false;
97
+        this.activeGrip = null;
98
+    };
99
+    LineMarkerBase.prototype.select = function () {
100
+        _super.prototype.select.call(this);
101
+        this.controlBox.style.display = '';
102
+    };
103
+    LineMarkerBase.prototype.deselect = function () {
104
+        _super.prototype.deselect.call(this);
105
+        this.controlBox.style.display = 'none';
106
+    };
107
+    LineMarkerBase.prototype.setup = function () {
108
+        _super.prototype.setup.call(this);
109
+        this.markerBgLine = SvgHelper_1.SvgHelper.createLine(0, 0, this.x2, 0, [
110
+            ['stroke', 'transparent'],
111
+            ['stroke-width', '30']
112
+        ]);
113
+        this.addToRenderVisual(this.markerBgLine);
114
+        this.markerLine = SvgHelper_1.SvgHelper.createLine(0, 0, this.x2, 0);
115
+        this.addToRenderVisual(this.markerLine);
116
+        this.addControlBox();
117
+    };
118
+    LineMarkerBase.prototype.resize = function (x, y) {
119
+        if (this.activeGrip) {
120
+            if (this.activeGrip === this.controlGrip1 &&
121
+                this.getLineLength(this.x1 + x, this.y1 + 1, this.x2, this.y2) >= this.MIN_LENGTH) {
122
+                this.x1 += x;
123
+                this.y1 += y;
124
+                this.markerBgLine.setAttribute('x1', this.x1.toString());
125
+                this.markerBgLine.setAttribute('y1', this.y1.toString());
126
+                this.markerLine.setAttribute('x1', this.x1.toString());
127
+                this.markerLine.setAttribute('y1', this.y1.toString());
128
+            }
129
+            else if (this.activeGrip === this.controlGrip2 &&
130
+                this.getLineLength(this.x1, this.y1, this.x2 + x, this.y2 + y) >= this.MIN_LENGTH) {
131
+                this.x2 += x;
132
+                this.y2 += y;
133
+                this.markerBgLine.setAttribute('x2', this.x2.toString());
134
+                this.markerBgLine.setAttribute('y2', this.y2.toString());
135
+                this.markerLine.setAttribute('x2', this.x2.toString());
136
+                this.markerLine.setAttribute('y2', this.y2.toString());
137
+            }
138
+        }
139
+        this.adjustControlBox();
140
+    };
141
+    LineMarkerBase.createMarker = function () {
142
+        var marker = new LineMarkerBase();
143
+        marker.setup();
144
+        return marker;
145
+    };
146
+    return LineMarkerBase;
147
+}(MarkerBase_1.MarkerBase));
148
+exports.LineMarkerBase = LineMarkerBase;

+ 14
- 0
dist/cjs/markers/line/LineMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var LineMarker_1 = require("./LineMarker");
4
+var line_marker_toolbar_icon_svg_1 = require("./line-marker-toolbar-icon.svg");
5
+var LineMarkerToolbarItem = (function () {
6
+    function LineMarkerToolbarItem() {
7
+        this.name = 'line-marker';
8
+        this.tooltipText = 'Line';
9
+        this.icon = line_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = LineMarker_1.LineMarker;
11
+    }
12
+    return LineMarkerToolbarItem;
13
+}());
14
+exports.LineMarkerToolbarItem = LineMarkerToolbarItem;

+ 34
- 0
dist/cjs/markers/rect/RectMarker.js View File

@@ -0,0 +1,34 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var RectMarkerBase_1 = require("./RectMarkerBase");
18
+var RectMarker = (function (_super) {
19
+    __extends(RectMarker, _super);
20
+    function RectMarker() {
21
+        return _super !== null && _super.apply(this, arguments) || this;
22
+    }
23
+    RectMarker.prototype.setup = function () {
24
+        _super.prototype.setup.call(this);
25
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'rect-marker']]);
26
+    };
27
+    RectMarker.createMarker = function () {
28
+        var marker = new RectMarker();
29
+        marker.setup();
30
+        return marker;
31
+    };
32
+    return RectMarker;
33
+}(RectMarkerBase_1.RectMarkerBase));
34
+exports.RectMarker = RectMarker;

+ 40
- 0
dist/cjs/markers/rect/RectMarkerBase.js View File

@@ -0,0 +1,40 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var RectangularMarkerBase_1 = require("../base/RectangularMarkerBase");
18
+var RectMarkerBase = (function (_super) {
19
+    __extends(RectMarkerBase, _super);
20
+    function RectMarkerBase() {
21
+        return _super !== null && _super.apply(this, arguments) || this;
22
+    }
23
+    RectMarkerBase.prototype.setup = function () {
24
+        _super.prototype.setup.call(this);
25
+        this.markerRect = SvgHelper_1.SvgHelper.createRect(this.width, this.height);
26
+        this.addToRenderVisual(this.markerRect);
27
+    };
28
+    RectMarkerBase.prototype.resize = function (x, y) {
29
+        _super.prototype.resize.call(this, x, y);
30
+        this.markerRect.setAttribute('width', this.width.toString());
31
+        this.markerRect.setAttribute('height', this.height.toString());
32
+    };
33
+    RectMarkerBase.createMarker = function () {
34
+        var marker = new RectMarkerBase();
35
+        marker.setup();
36
+        return marker;
37
+    };
38
+    return RectMarkerBase;
39
+}(RectangularMarkerBase_1.RectangularMarkerBase));
40
+exports.RectMarkerBase = RectMarkerBase;

+ 14
- 0
dist/cjs/markers/rect/RectMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var RectMarker_1 = require("./RectMarker");
4
+var rect_marker_toolbar_icon_svg_1 = require("./rect-marker-toolbar-icon.svg");
5
+var RectMarkerToolbarItem = (function () {
6
+    function RectMarkerToolbarItem() {
7
+        this.name = "rect-marker";
8
+        this.tooltipText = "Rectangle";
9
+        this.icon = rect_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = RectMarker_1.RectMarker;
11
+    }
12
+    return RectMarkerToolbarItem;
13
+}());
14
+exports.RectMarkerToolbarItem = RectMarkerToolbarItem;

+ 140
- 0
dist/cjs/markers/text/TextMarker.js View File

@@ -0,0 +1,140 @@
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 SvgHelper_1 = require("../../utils/SvgHelper");
17
+var RectangularMarkerBase_1 = require("../base/RectangularMarkerBase");
18
+var check_svg_1 = require("./check.svg");
19
+var times_svg_1 = require("./times.svg");
20
+var TextMarker = (function (_super) {
21
+    __extends(TextMarker, _super);
22
+    function TextMarker() {
23
+        var _this = _super !== null && _super.apply(this, arguments) || this;
24
+        _this.MIN_SIZE = 50;
25
+        _this.DEFAULT_TEXT = 'Double-click to edit text';
26
+        _this.text = _this.DEFAULT_TEXT;
27
+        _this.inDoubleTap = false;
28
+        _this.renderText = function () {
29
+            var LINE_SIZE = '1.2em';
30
+            while (_this.textElement.lastChild) {
31
+                _this.textElement.removeChild(_this.textElement.lastChild);
32
+            }
33
+            var lines = _this.text.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/);
34
+            for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
35
+                var line = lines_1[_i];
36
+                if (line.trim() === '') {
37
+                    line = ' ';
38
+                }
39
+                _this.textElement.appendChild(SvgHelper_1.SvgHelper.createTSpan(line, [['x', '0'], ['dy', LINE_SIZE]]));
40
+            }
41
+            setTimeout(_this.sizeText, 10);
42
+        };
43
+        _this.sizeText = function () {
44
+            var textSize = _this.textElement.getBBox();
45
+            var x = 0;
46
+            var y = 0;
47
+            var scale = 1.0;
48
+            if (textSize.width > 0 && textSize.height > 0) {
49
+                var xScale = (_this.width * 1.0) / textSize.width;
50
+                var yScale = (_this.height * 1.0) / textSize.height;
51
+                scale = Math.min(xScale, yScale);
52
+                x = (_this.width - textSize.width * scale) / 2;
53
+                y = (_this.height - textSize.height * scale) / 2;
54
+            }
55
+            _this.textElement.transform.baseVal.getItem(0).setTranslate(x, y);
56
+            _this.textElement.transform.baseVal.getItem(1).setScale(scale, scale);
57
+        };
58
+        _this.onDblClick = function (ev) {
59
+            _this.showEditor();
60
+        };
61
+        _this.onTap = function (ev) {
62
+            if (_this.inDoubleTap) {
63
+                _this.inDoubleTap = false;
64
+                _this.showEditor();
65
+            }
66
+            else {
67
+                _this.inDoubleTap = true;
68
+                setTimeout(function () {
69
+                    _this.inDoubleTap = false;
70
+                }, 300);
71
+            }
72
+        };
73
+        _this.showEditor = function () {
74
+            _this.editor = document.createElement('div');
75
+            _this.editor.className = 'fc-whiteboardtext-editor';
76
+            _this.editorTextArea = document.createElement('textarea');
77
+            if (_this.text !== _this.DEFAULT_TEXT) {
78
+                _this.editorTextArea.value = _this.text;
79
+            }
80
+            _this.editorTextArea.addEventListener('keydown', _this.onEditorKeyDown);
81
+            _this.editor.appendChild(_this.editorTextArea);
82
+            document.body.appendChild(_this.editor);
83
+            var buttons = document.createElement('div');
84
+            buttons.className = 'fc-whiteboardtext-editor-button-bar';
85
+            _this.editor.appendChild(buttons);
86
+            var okButton = document.createElement('div');
87
+            okButton.className = 'fc-whiteboardtext-editor-button';
88
+            okButton.innerHTML = check_svg_1.default;
89
+            okButton.addEventListener('click', _this.onEditorOkClick);
90
+            buttons.appendChild(okButton);
91
+            var cancelButton = document.createElement('div');
92
+            cancelButton.className = 'fc-whiteboardtext-editor-button';
93
+            cancelButton.innerHTML = times_svg_1.default;
94
+            cancelButton.addEventListener('click', _this.closeEditor);
95
+            buttons.appendChild(cancelButton);
96
+        };
97
+        _this.onEditorOkClick = function (ev) {
98
+            if (_this.editorTextArea.value.trim()) {
99
+                _this.text = _this.editorTextArea.value;
100
+            }
101
+            else {
102
+                _this.text = _this.DEFAULT_TEXT;
103
+            }
104
+            _this.renderText();
105
+            _this.closeEditor();
106
+        };
107
+        _this.closeEditor = function () {
108
+            document.body.removeChild(_this.editor);
109
+        };
110
+        _this.onEditorKeyDown = function (ev) {
111
+            if (ev.key === 'Enter' && ev.ctrlKey) {
112
+                ev.preventDefault();
113
+                _this.onEditorOkClick(null);
114
+            }
115
+        };
116
+        return _this;
117
+    }
118
+    TextMarker.prototype.setup = function () {
119
+        _super.prototype.setup.call(this);
120
+        this.textElement = SvgHelper_1.SvgHelper.createText();
121
+        this.addToRenderVisual(this.textElement);
122
+        SvgHelper_1.SvgHelper.setAttributes(this.visual, [['class', 'text-marker']]);
123
+        this.textElement.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
124
+        this.textElement.transform.baseVal.appendItem(SvgHelper_1.SvgHelper.createTransform());
125
+        this.renderText();
126
+        this.visual.addEventListener('dblclick', this.onDblClick);
127
+        this.visual.addEventListener('touchstart', this.onTap);
128
+    };
129
+    TextMarker.prototype.resize = function (x, y) {
130
+        _super.prototype.resize.call(this, x, y);
131
+        this.sizeText();
132
+    };
133
+    TextMarker.createMarker = function () {
134
+        var marker = new TextMarker();
135
+        marker.setup();
136
+        return marker;
137
+    };
138
+    return TextMarker;
139
+}(RectangularMarkerBase_1.RectangularMarkerBase));
140
+exports.TextMarker = TextMarker;

+ 14
- 0
dist/cjs/markers/text/TextMarkerToolbarItem.js View File

@@ -0,0 +1,14 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var TextMarker_1 = require("./TextMarker");
4
+var text_marker_toolbar_icon_svg_1 = require("./text-marker-toolbar-icon.svg");
5
+var TextMarkerToolbarItem = (function () {
6
+    function TextMarkerToolbarItem() {
7
+        this.name = "text-marker";
8
+        this.tooltipText = "Text";
9
+        this.icon = text_marker_toolbar_icon_svg_1.default;
10
+        this.markerType = TextMarker_1.TextMarker;
11
+    }
12
+    return TextMarkerToolbarItem;
13
+}());
14
+exports.TextMarkerToolbarItem = TextMarkerToolbarItem;

+ 20
- 0
dist/cjs/render/Activator.js View File

@@ -0,0 +1,20 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var Activator = (function () {
4
+    function Activator() {
5
+    }
6
+    Object.defineProperty(Activator, "isLicensed", {
7
+        get: function () {
8
+            if (Activator.key) {
9
+                return true;
10
+            }
11
+            else {
12
+                return false;
13
+            }
14
+        },
15
+        enumerable: true,
16
+        configurable: true
17
+    });
18
+    return Activator;
19
+}());
20
+exports.Activator = Activator;

+ 305
- 0
dist/cjs/render/MarkerArea.js View File

@@ -0,0 +1,305 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var Activator_1 = require("./Activator");
4
+var SvgHelper_1 = require("../utils/SvgHelper");
5
+var Renderer_1 = require("./Renderer");
6
+var Toolbar_1 = require("../toolbar/Toolbar");
7
+var ArrowMarkerToolbarItem_1 = require("../markers/arrow/ArrowMarkerToolbarItem");
8
+var CoverMarkerToolbarItem_1 = require("../markers/cover/CoverMarkerToolbarItem");
9
+var HighlightMarkerToolbarItem_1 = require("../markers/highlight/HighlightMarkerToolbarItem");
10
+var LineMarkerToolbarItem_1 = require("../markers/line/LineMarkerToolbarItem");
11
+var RectMarkerToolbarItem_1 = require("../markers/rect/RectMarkerToolbarItem");
12
+var TextMarkerToolbarItem_1 = require("../markers/text/TextMarkerToolbarItem");
13
+var check_svg_1 = require("./assets/core-toolbar-icons/check.svg");
14
+var eraser_svg_1 = require("./assets/core-toolbar-icons/eraser.svg");
15
+var mouse_pointer_svg_1 = require("./assets/core-toolbar-icons/mouse-pointer.svg");
16
+var times_svg_1 = require("./assets/core-toolbar-icons/times.svg");
17
+var markerjs_logo_m_svg_1 = require("./assets/fc-whiteboardlogo-m.svg");
18
+var MarkerArea = (function () {
19
+    function MarkerArea(target) {
20
+        var _this = this;
21
+        this.toolbars = [
22
+            {
23
+                icon: mouse_pointer_svg_1.default,
24
+                name: 'pointer',
25
+                tooltipText: 'Pointer'
26
+            },
27
+            {
28
+                icon: eraser_svg_1.default,
29
+                name: 'delete',
30
+                tooltipText: 'Delete'
31
+            },
32
+            {
33
+                name: 'separator',
34
+                tooltipText: ''
35
+            },
36
+            new RectMarkerToolbarItem_1.RectMarkerToolbarItem(),
37
+            new CoverMarkerToolbarItem_1.CoverMarkerToolbarItem(),
38
+            new HighlightMarkerToolbarItem_1.HighlightMarkerToolbarItem(),
39
+            new LineMarkerToolbarItem_1.LineMarkerToolbarItem(),
40
+            new ArrowMarkerToolbarItem_1.ArrowMarkerToolbarItem(),
41
+            new TextMarkerToolbarItem_1.TextMarkerToolbarItem(),
42
+            {
43
+                name: 'separator',
44
+                tooltipText: ''
45
+            },
46
+            {
47
+                icon: check_svg_1.default,
48
+                name: 'ok',
49
+                tooltipText: 'OK'
50
+            },
51
+            {
52
+                icon: times_svg_1.default,
53
+                name: 'close',
54
+                tooltipText: 'Close'
55
+            }
56
+        ];
57
+        this.scale = 1.0;
58
+        this.show = function (completeCallback, cancelCallback) {
59
+            _this.completeCallback = completeCallback;
60
+            if (cancelCallback) {
61
+                _this.cancelCallback = cancelCallback;
62
+            }
63
+            _this.open();
64
+            _this.showUI();
65
+        };
66
+        this.open = function () {
67
+            _this.setTargetRect();
68
+            _this.initMarkerCanvas();
69
+            _this.attachEvents();
70
+            _this.setStyles();
71
+            if (!Activator_1.Activator.isLicensed) {
72
+                _this.adLogo();
73
+            }
74
+            window.addEventListener('resize', _this.adjustUI);
75
+        };
76
+        this.render = function (completeCallback, cancelCallback) {
77
+            _this.completeCallback = completeCallback;
78
+            if (cancelCallback) {
79
+                _this.cancelCallback = cancelCallback;
80
+            }
81
+            _this.selectMarker(null);
82
+            _this.startRender(_this.renderFinished);
83
+        };
84
+        this.close = function () {
85
+            if (_this.toolbarUI) {
86
+                document.body.removeChild(_this.toolbarUI);
87
+            }
88
+            if (_this.markerImage) {
89
+                document.body.removeChild(_this.markerImageHolder);
90
+            }
91
+            if (_this.logoUI) {
92
+                document.body.removeChild(_this.logoUI);
93
+            }
94
+        };
95
+        this.addMarker = function (markerType) {
96
+            var marker = markerType.createMarker();
97
+            marker.onSelected = _this.selectMarker;
98
+            if (marker.defs && marker.defs.length > 0) {
99
+                for (var _i = 0, _a = marker.defs; _i < _a.length; _i++) {
100
+                    var d = _a[_i];
101
+                    if (d.id && !_this.markerImage.getElementById(d.id)) {
102
+                        _this.defs.appendChild(d);
103
+                    }
104
+                }
105
+            }
106
+            _this.markers.push(marker);
107
+            _this.selectMarker(marker);
108
+            _this.markerImage.appendChild(marker.visual);
109
+            var bbox = marker.visual.getBBox();
110
+            var x = _this.width / 2 / _this.scale - bbox.width / 2;
111
+            var y = _this.height / 2 / _this.scale - bbox.height / 2;
112
+            var translate = marker.visual.transform.baseVal.getItem(0);
113
+            translate.setMatrix(translate.matrix.translate(x, y));
114
+            marker.visual.transform.baseVal.replaceItem(translate, 0);
115
+        };
116
+        this.deleteActiveMarker = function () {
117
+            if (_this.activeMarker) {
118
+                _this.deleteMarker(_this.activeMarker);
119
+            }
120
+        };
121
+        this.setTargetRect = function () {
122
+            var targetRect = _this.target.getBoundingClientRect();
123
+            var bodyRect = document.body.parentElement.getBoundingClientRect();
124
+            _this.targetRect = {
125
+                left: targetRect.left - bodyRect.left,
126
+                top: targetRect.top - bodyRect.top
127
+            };
128
+        };
129
+        this.startRender = function (done) {
130
+            var renderer = new Renderer_1.Renderer();
131
+            renderer.rasterize(_this.target, _this.markerImage, done);
132
+        };
133
+        this.attachEvents = function () {
134
+            _this.markerImage.addEventListener('mousedown', _this.mouseDown);
135
+            _this.markerImage.addEventListener('mousemove', _this.mouseMove);
136
+            _this.markerImage.addEventListener('mouseup', _this.mouseUp);
137
+        };
138
+        this.mouseDown = function (ev) {
139
+            if (_this.activeMarker && (ev.buttons & 1) > 0) {
140
+                _this.activeMarker.deselect();
141
+                _this.activeMarker = null;
142
+            }
143
+        };
144
+        this.mouseMove = function (ev) {
145
+            if (_this.activeMarker && (ev.buttons & 1) > 0) {
146
+                _this.activeMarker.manipulate(ev);
147
+            }
148
+        };
149
+        this.mouseUp = function (ev) {
150
+            if (_this.activeMarker) {
151
+                _this.activeMarker.endManipulation();
152
+            }
153
+        };
154
+        this.initMarkerCanvas = function () {
155
+            _this.markerImageHolder = document.createElement('div');
156
+            _this.markerImageHolder.style.setProperty('touch-action', 'none');
157
+            _this.markerImageHolder.style.setProperty('-ms-touch-action', 'none');
158
+            _this.markerImage = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
159
+            _this.markerImage.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
160
+            _this.markerImage.setAttribute('width', _this.width.toString());
161
+            _this.markerImage.setAttribute('height', _this.height.toString());
162
+            _this.markerImage.setAttribute('viewBox', '0 0 ' + _this.width.toString() + ' ' + _this.height.toString());
163
+            _this.markerImageHolder.style.position = 'absolute';
164
+            _this.markerImageHolder.style.width = _this.width + "px";
165
+            _this.markerImageHolder.style.height = _this.height + "px";
166
+            _this.markerImageHolder.style.transformOrigin = 'top left';
167
+            _this.positionMarkerImage();
168
+            _this.defs = SvgHelper_1.SvgHelper.createDefs();
169
+            _this.markerImage.appendChild(_this.defs);
170
+            _this.markerImageHolder.appendChild(_this.markerImage);
171
+            document.body.appendChild(_this.markerImageHolder);
172
+        };
173
+        this.adjustUI = function (ev) {
174
+            _this.adjustSize();
175
+            _this.positionUI();
176
+        };
177
+        this.adjustSize = function () {
178
+            _this.width = _this.target.clientWidth;
179
+            _this.height = _this.target.clientHeight;
180
+            var scale = _this.target.clientWidth / _this.markerImageHolder.clientWidth;
181
+            if (scale !== 1.0) {
182
+                _this.scale *= scale;
183
+                _this.markerImageHolder.style.width = _this.width + "px";
184
+                _this.markerImageHolder.style.height = _this.height + "px";
185
+                _this.markerImageHolder.style.transform = "scale(" + _this.scale + ")";
186
+            }
187
+        };
188
+        this.positionUI = function () {
189
+            _this.setTargetRect();
190
+            _this.positionMarkerImage();
191
+            _this.positionToolbar();
192
+            if (_this.logoUI) {
193
+                _this.positionLogo();
194
+            }
195
+        };
196
+        this.positionMarkerImage = function () {
197
+            _this.markerImageHolder.style.top = _this.targetRect.top + 'px';
198
+            _this.markerImageHolder.style.left = _this.targetRect.left + 'px';
199
+        };
200
+        this.positionToolbar = function () {
201
+            _this.toolbarUI.style.left = _this.targetRect.left +
202
+                _this.target.offsetWidth -
203
+                _this.toolbarUI.clientWidth + "px";
204
+            _this.toolbarUI.style.top = _this.targetRect.top - _this.toolbarUI.clientHeight + "px";
205
+        };
206
+        this.showUI = function () {
207
+            _this.toolbar = new Toolbar_1.Toolbar(_this.toolbars, _this.toolbarClick);
208
+            _this.toolbarUI = _this.toolbar.getUI();
209
+            document.body.appendChild(_this.toolbarUI);
210
+            _this.toolbarUI.style.position = 'absolute';
211
+            _this.positionToolbar();
212
+        };
213
+        this.setStyles = function () {
214
+            var editorStyleSheet = document.createElementNS('http://www.w3.org/2000/svg', 'style');
215
+            editorStyleSheet.innerHTML = "\n            .rect-marker .render-visual {\n                stroke: #ff0000;\n                stroke-width: 3;\n                fill: transparent;\n            }\n            .cover-marker .render-visual {\n                stroke-width: 0;\n                fill: #000000;\n            }\n            .highlight-marker .render-visual {\n                stroke: transparent;\n                stroke-width: 0;\n                fill: #ffff00;\n                fill-opacity: 0.4;\n            }\n            .line-marker .render-visual {\n                stroke: #ff0000;\n                stroke-width: 3;\n                fill: transparent;\n            }\n            .arrow-marker .render-visual {\n                stroke: #ff0000;\n                stroke-width: 3;\n                fill: transparent;\n            }\n            .arrow-marker-tip {\n                stroke-width: 0;\n                fill: #ff0000;\n            }\n            .text-marker text {\n                fill: #ff0000;\n                font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\",\n                    Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\",\n                    \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n            }\n            .fc-whiteboardrect-control-box .fc-whiteboardrect-control-rect {\n                stroke: black;\n                stroke-width: 1;\n                stroke-opacity: 0.5;\n                stroke-dasharray: 3, 2;\n                fill: transparent;\n            }\n            .fc-whiteboardcontrol-grip {\n                fill: #cccccc;\n                stroke: #333333;\n                stroke-width: 2;\n            }\n        ";
216
+            _this.markerImage.appendChild(editorStyleSheet);
217
+        };
218
+        this.toolbarClick = function (ev, toolbarItem) {
219
+            if (toolbarItem.markerType) {
220
+                _this.addMarker(toolbarItem.markerType);
221
+            }
222
+            else {
223
+                switch (toolbarItem.name) {
224
+                    case 'delete': {
225
+                        _this.deleteActiveMarker();
226
+                        break;
227
+                    }
228
+                    case 'pointer': {
229
+                        if (_this.activeMarker) {
230
+                            _this.selectMarker(null);
231
+                        }
232
+                        break;
233
+                    }
234
+                    case 'close': {
235
+                        _this.cancel();
236
+                        break;
237
+                    }
238
+                    case 'ok': {
239
+                        _this.complete();
240
+                        break;
241
+                    }
242
+                }
243
+            }
244
+        };
245
+        this.selectMarker = function (marker) {
246
+            if (_this.activeMarker && _this.activeMarker !== marker) {
247
+                _this.activeMarker.deselect();
248
+            }
249
+            _this.activeMarker = marker;
250
+        };
251
+        this.deleteMarker = function (marker) {
252
+            _this.markerImage.removeChild(marker.visual);
253
+            if (_this.activeMarker === marker) {
254
+                _this.activeMarker = null;
255
+            }
256
+            _this.markers.splice(_this.markers.indexOf(marker), 1);
257
+        };
258
+        this.complete = function () {
259
+            _this.selectMarker(null);
260
+            _this.startRender(_this.renderFinishedClose);
261
+        };
262
+        this.cancel = function () {
263
+            _this.close();
264
+            if (_this.cancelCallback) {
265
+                _this.cancelCallback();
266
+            }
267
+        };
268
+        this.renderFinished = function (dataUrl) {
269
+            _this.completeCallback(dataUrl);
270
+        };
271
+        this.renderFinishedClose = function (dataUrl) {
272
+            _this.close();
273
+            _this.completeCallback(dataUrl);
274
+        };
275
+        this.positionLogo = function () {
276
+            if (_this.logoUI) {
277
+                _this.logoUI.style.left = _this.targetRect.left + 10 + "px";
278
+                _this.logoUI.style.top = _this.targetRect.top +
279
+                    _this.target.offsetHeight -
280
+                    _this.logoUI.clientHeight -
281
+                    10 + "px";
282
+            }
283
+        };
284
+        this.adLogo = function () {
285
+            _this.logoUI = document.createElement('div');
286
+            _this.logoUI.className = 'fc-whiteboardlogo';
287
+            var link = document.createElement('a');
288
+            link.href = 'https://markerjs.com/';
289
+            link.target = '_blank';
290
+            link.innerHTML = markerjs_logo_m_svg_1.default;
291
+            link.title = 'Powered by marker.js';
292
+            _this.logoUI.appendChild(link);
293
+            document.body.appendChild(_this.logoUI);
294
+            _this.logoUI.style.position = 'absolute';
295
+            _this.positionLogo();
296
+        };
297
+        this.target = target;
298
+        this.width = target.clientWidth;
299
+        this.height = target.clientHeight;
300
+        this.markers = [];
301
+        this.activeMarker = null;
302
+    }
303
+    return MarkerArea;
304
+}());
305
+exports.MarkerArea = MarkerArea;

+ 30
- 0
dist/cjs/render/Renderer.js View File

@@ -0,0 +1,30 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var Renderer = (function () {
4
+    function Renderer() {
5
+    }
6
+    Renderer.prototype.rasterize = function (target, markerImage, done) {
7
+        var canvas = document.createElement('canvas');
8
+        canvas.width = markerImage.width.baseVal.value;
9
+        canvas.height = markerImage.height.baseVal.value;
10
+        var data = markerImage.outerHTML;
11
+        var ctx = canvas.getContext('2d');
12
+        if (!ctx) {
13
+            throw new Error('Invalid ctx');
14
+        }
15
+        ctx.drawImage(target, 0, 0, canvas.width, canvas.height);
16
+        var DOMURL = window.URL;
17
+        var img = new Image(canvas.width, canvas.height);
18
+        img.setAttribute('crossOrigin', 'anonymous');
19
+        var blob = new Blob([data], { type: 'image/svg+xml' });
20
+        var url = DOMURL.createObjectURL(blob);
21
+        img.onload = function () {
22
+            ctx.drawImage(img, 0, 0);
23
+            DOMURL.revokeObjectURL(url);
24
+            done(canvas.toDataURL('image/png'));
25
+        };
26
+        img.src = url;
27
+    };
28
+    return Renderer;
29
+}());
30
+exports.Renderer = Renderer;

+ 22
- 0
dist/cjs/toolbar/Toolbar.js View File

@@ -0,0 +1,22 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var ToolbarButton_1 = require("./ToolbarButton");
4
+var Toolbar = (function () {
5
+    function Toolbar(toolbarItems, clickHandler) {
6
+        var _this = this;
7
+        this.getUI = function () {
8
+            _this.toolbarUI = document.createElement('div');
9
+            _this.toolbarUI.className = 'fc-whiteboardtoolbar';
10
+            for (var _i = 0, _a = _this.toolbarItems; _i < _a.length; _i++) {
11
+                var toolbarItem = _a[_i];
12
+                var toolbarButton = new ToolbarButton_1.ToolbarButton(toolbarItem, _this.clickHandler);
13
+                _this.toolbarUI.appendChild(toolbarButton.getElement());
14
+            }
15
+            return _this.toolbarUI;
16
+        };
17
+        this.toolbarItems = toolbarItems;
18
+        this.clickHandler = clickHandler;
19
+    }
20
+    return Toolbar;
21
+}());
22
+exports.Toolbar = Toolbar;

+ 37
- 0
dist/cjs/toolbar/ToolbarButton.js View File

@@ -0,0 +1,37 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var ToolbarButton = (function () {
4
+    function ToolbarButton(toolbarItem, clickHandler) {
5
+        var _this = this;
6
+        this.getElement = function () {
7
+            var div = document.createElement('div');
8
+            if (_this.toolbarItem.name !== 'separator') {
9
+                div.className = 'fc-whiteboardtoolbar-button';
10
+                if (_this.clickHandler) {
11
+                    div.addEventListener('click', function (ev) {
12
+                        if (_this.clickHandler) {
13
+                            _this.clickHandler(ev, _this.toolbarItem);
14
+                        }
15
+                    });
16
+                }
17
+                if (_this.toolbarItem.icon) {
18
+                    div.title = _this.toolbarItem.tooltipText;
19
+                    div.innerHTML = _this.toolbarItem.icon;
20
+                }
21
+                else {
22
+                    div.innerText = _this.toolbarItem.tooltipText;
23
+                }
24
+            }
25
+            else {
26
+                div.className = 'fc-whiteboardtoolbar-separator';
27
+            }
28
+            return div;
29
+        };
30
+        this.toolbarItem = toolbarItem;
31
+        if (clickHandler) {
32
+            this.clickHandler = clickHandler;
33
+        }
34
+    }
35
+    return ToolbarButton;
36
+}());
37
+exports.ToolbarButton = ToolbarButton;

+ 2
- 0
dist/cjs/toolbar/ToolbarItem.js View File

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

+ 97
- 0
dist/cjs/utils/SvgHelper/index.js View File

@@ -0,0 +1,97 @@
1
+"use strict";
2
+Object.defineProperty(exports, "__esModule", { value: true });
3
+var SvgHelper = (function () {
4
+    function SvgHelper() {
5
+    }
6
+    SvgHelper.createRect = function (width, height, attributes) {
7
+        var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
8
+        rect.setAttribute('width', width.toString());
9
+        rect.setAttribute('height', height.toString());
10
+        if (attributes) {
11
+            SvgHelper.setAttributes(rect, attributes);
12
+        }
13
+        return rect;
14
+    };
15
+    SvgHelper.createLine = function (x1, y1, x2, y2, attributes) {
16
+        var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
17
+        line.setAttribute('x1', x1.toString());
18
+        line.setAttribute('y1', y1.toString());
19
+        line.setAttribute('x2', x2.toString());
20
+        line.setAttribute('y2', y2.toString());
21
+        if (attributes) {
22
+            SvgHelper.setAttributes(line, attributes);
23
+        }
24
+        return line;
25
+    };
26
+    SvgHelper.createPolygon = function (points, attributes) {
27
+        var polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
28
+        polygon.setAttribute('points', points);
29
+        if (attributes) {
30
+            SvgHelper.setAttributes(polygon, attributes);
31
+        }
32
+        return polygon;
33
+    };
34
+    SvgHelper.createCircle = function (radius, attributes) {
35
+        var circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
36
+        circle.setAttribute('cx', (radius / 2).toString());
37
+        circle.setAttribute('cy', (radius / 2).toString());
38
+        circle.setAttribute('r', radius.toString());
39
+        if (attributes) {
40
+            SvgHelper.setAttributes(circle, attributes);
41
+        }
42
+        return circle;
43
+    };
44
+    SvgHelper.createGroup = function (attributes) {
45
+        var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
46
+        if (attributes) {
47
+            SvgHelper.setAttributes(g, attributes);
48
+        }
49
+        return g;
50
+    };
51
+    SvgHelper.setAttributes = function (el, attributes) {
52
+        for (var _i = 0, attributes_1 = attributes; _i < attributes_1.length; _i++) {
53
+            var _a = attributes_1[_i], attr = _a[0], value = _a[1];
54
+            el.setAttribute(attr, value);
55
+        }
56
+    };
57
+    SvgHelper.createTransform = function () {
58
+        var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
59
+        return svg.createSVGTransform();
60
+    };
61
+    SvgHelper.createDefs = function () {
62
+        var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
63
+        return defs;
64
+    };
65
+    SvgHelper.createMarker = function (id, orient, markerWidth, markerHeight, refX, refY, markerElement) {
66
+        var marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
67
+        SvgHelper.setAttributes(marker, [
68
+            ['id', id],
69
+            ['orient', orient],
70
+            ['markerWidth', markerWidth.toString()],
71
+            ['markerHeight', markerHeight.toString()],
72
+            ['refX', refX.toString()],
73
+            ['refY', refY.toString()]
74
+        ]);
75
+        marker.appendChild(markerElement);
76
+        return marker;
77
+    };
78
+    SvgHelper.createText = function (attributes) {
79
+        var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
80
+        text.setAttribute('x', '0');
81
+        text.setAttribute('y', '0');
82
+        if (attributes) {
83
+            SvgHelper.setAttributes(text, attributes);
84
+        }
85
+        return text;
86
+    };
87
+    SvgHelper.createTSpan = function (text, attributes) {
88
+        var tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
89
+        tspan.textContent = text;
90
+        if (attributes) {
91
+            SvgHelper.setAttributes(tspan, attributes);
92
+        }
93
+        return tspan;
94
+    };
95
+    return SvgHelper;
96
+}());
97
+exports.SvgHelper = SvgHelper;

+ 1
- 0
dist/index.js View File

@@ -0,0 +1 @@
1
+!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var n=t();for(var r in n)("object"==typeof exports?exports:e)[r]=n[r]}}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){}])});

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


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

@@ -0,0 +1,6 @@
1
+import { LineMarkerBase } from '../line/LineMarkerBase';
2
+export declare class ArrowMarker extends LineMarkerBase {
3
+  static createMarker: () => LineMarkerBase;
4
+  private readonly ARROW_SIZE;
5
+  protected setup(): void;
6
+}

+ 8
- 0
dist/types/markers/arrow/ArrowMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
2
+import { ArrowMarker } from './ArrowMarker';
3
+export declare class ArrowMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof ArrowMarker;
8
+}

+ 27
- 0
dist/types/markers/base/MarkerBase.d.ts View File

@@ -0,0 +1,27 @@
1
+export declare class MarkerBase {
2
+  static createMarker: () => MarkerBase;
3
+  visual: SVGGElement;
4
+  renderVisual: SVGGElement;
5
+  onSelected: (marker: MarkerBase) => void;
6
+  defs: SVGElement[];
7
+  protected width: number;
8
+  protected height: number;
9
+  protected isActive: boolean;
10
+  protected isResizing: boolean;
11
+  protected previousMouseX: number;
12
+  protected previousMouseY: number;
13
+  private isDragging;
14
+  manipulate: (ev: MouseEvent) => void;
15
+  endManipulation(): void;
16
+  select(): void;
17
+  deselect(): void;
18
+  protected setup(): void;
19
+  protected addToVisual: (el: SVGElement) => void;
20
+  protected addToRenderVisual: (el: SVGElement) => void;
21
+  protected resize(x: number, y: number): void;
22
+  protected onTouch(ev: TouchEvent): void;
23
+  private mouseDown;
24
+  private mouseUp;
25
+  private mouseMove;
26
+  private move;
27
+}

+ 25
- 0
dist/types/markers/base/RectangularMarkerBase.d.ts View File

@@ -0,0 +1,25 @@
1
+import { MarkerBase } from './MarkerBase';
2
+export declare class RectangularMarkerBase extends MarkerBase {
3
+  static createMarker: () => RectangularMarkerBase;
4
+  protected MIN_SIZE: number;
5
+  private controlBox;
6
+  private readonly CB_DISTANCE;
7
+  private controlRect;
8
+  private controlGrips;
9
+  private activeGrip;
10
+  endManipulation(): void;
11
+  select(): void;
12
+  deselect(): void;
13
+  protected setup(): void;
14
+  protected resize(x: number, y: number): void;
15
+  protected onTouch(ev: TouchEvent): void;
16
+  private addControlBox;
17
+  private adjustControlBox;
18
+  private addControlGrips;
19
+  private createGrip;
20
+  private positionGrips;
21
+  private positionGrip;
22
+  private gripMouseDown;
23
+  private gripMouseUp;
24
+  private gripMouseMove;
25
+}

+ 12
- 0
dist/types/markers/base/RectangularMarkerGrips.d.ts View File

@@ -0,0 +1,12 @@
1
+import { ResizeGrip } from './ResizeGrip';
2
+export declare class RectangularMarkerGrips {
3
+    topLeft: ResizeGrip;
4
+    topCenter: ResizeGrip;
5
+    topRight: ResizeGrip;
6
+    centerLeft: ResizeGrip;
7
+    centerRight: ResizeGrip;
8
+    bottomLeft: ResizeGrip;
9
+    bottomCenter: ResizeGrip;
10
+    bottomRight: ResizeGrip;
11
+    findGripByVisual: (gripVisual: SVGGraphicsElement) => ResizeGrip;
12
+}

+ 5
- 0
dist/types/markers/base/ResizeGrip.d.ts View File

@@ -0,0 +1,5 @@
1
+export declare class ResizeGrip {
2
+    visual: SVGGraphicsElement;
3
+    readonly GRIP_SIZE = 10;
4
+    constructor();
5
+}

+ 5
- 0
dist/types/markers/cover/CoverMarker.d.ts View File

@@ -0,0 +1,5 @@
1
+import { RectMarkerBase } from '../rect/RectMarkerBase';
2
+export declare class CoverMarker extends RectMarkerBase {
3
+  static createMarker: () => RectMarkerBase;
4
+  protected setup(): void;
5
+}

+ 8
- 0
dist/types/markers/cover/CoverMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
2
+import { CoverMarker } from './CoverMarker';
3
+export declare class CoverMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof CoverMarker;
8
+}

+ 5
- 0
dist/types/markers/highlight/HighlightMarker.d.ts View File

@@ -0,0 +1,5 @@
1
+import { RectMarkerBase } from '../rect/RectMarkerBase';
2
+export declare class HighlightMarker extends RectMarkerBase {
3
+  static createMarker: () => RectMarkerBase;
4
+  protected setup(): void;
5
+}

+ 8
- 0
dist/types/markers/highlight/HighlightMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
2
+import { HighlightMarker } from './HighlightMarker';
3
+export declare class HighlightMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof HighlightMarker;
8
+}

+ 5
- 0
dist/types/markers/line/LineMarker.d.ts View File

@@ -0,0 +1,5 @@
1
+import { LineMarkerBase } from './LineMarkerBase';
2
+export declare class LineMarker extends LineMarkerBase {
3
+  static createMarker: () => LineMarkerBase;
4
+  protected setup(): void;
5
+}

+ 30
- 0
dist/types/markers/line/LineMarkerBase.d.ts View File

@@ -0,0 +1,30 @@
1
+import { MarkerBase } from '../base/MarkerBase';
2
+export declare class LineMarkerBase extends MarkerBase {
3
+  static createMarker: () => LineMarkerBase;
4
+  protected markerLine: SVGLineElement;
5
+  private readonly MIN_LENGTH;
6
+  private markerBgLine;
7
+  private controlBox;
8
+  private controlGrip1;
9
+  private controlGrip2;
10
+  private activeGrip;
11
+  private x1;
12
+  private y1;
13
+  private x2;
14
+  private y2;
15
+  endManipulation(): void;
16
+  select(): void;
17
+  deselect(): void;
18
+  protected setup(): void;
19
+  protected resize(x: number, y: number): void;
20
+  private getLineLength;
21
+  private addControlBox;
22
+  private adjustControlBox;
23
+  private addControlGrips;
24
+  private createGrip;
25
+  private positionGrips;
26
+  private positionGrip;
27
+  private gripMouseDown;
28
+  private gripMouseUp;
29
+  private gripMouseMove;
30
+}

+ 8
- 0
dist/types/markers/line/LineMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
2
+import { LineMarker } from './LineMarker';
3
+export declare class LineMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof LineMarker;
8
+}

+ 5
- 0
dist/types/markers/rect/RectMarker.d.ts View File

@@ -0,0 +1,5 @@
1
+import { RectMarkerBase } from './RectMarkerBase';
2
+export declare class RectMarker extends RectMarkerBase {
3
+  static createMarker: () => RectMarkerBase;
4
+  protected setup(): void;
5
+}

+ 7
- 0
dist/types/markers/rect/RectMarkerBase.d.ts View File

@@ -0,0 +1,7 @@
1
+import { RectangularMarkerBase } from '../base/RectangularMarkerBase';
2
+export declare class RectMarkerBase extends RectangularMarkerBase {
3
+  static createMarker: () => RectMarkerBase;
4
+  private markerRect;
5
+  protected setup(): void;
6
+  protected resize(x: number, y: number): void;
7
+}

+ 8
- 0
dist/types/markers/rect/RectMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from "../../toolbar/ToolbarItem";
2
+import { RectMarker } from "./RectMarker";
3
+export declare class RectMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof RectMarker;
8
+}

+ 21
- 0
dist/types/markers/text/TextMarker.d.ts View File

@@ -0,0 +1,21 @@
1
+import { RectangularMarkerBase } from '../base/RectangularMarkerBase';
2
+export declare class TextMarker extends RectangularMarkerBase {
3
+  static createMarker: () => TextMarker;
4
+  protected readonly MIN_SIZE = 50;
5
+  private readonly DEFAULT_TEXT;
6
+  private text;
7
+  private textElement;
8
+  private inDoubleTap;
9
+  private editor;
10
+  private editorTextArea;
11
+  protected setup(): void;
12
+  protected resize(x: number, y: number): void;
13
+  private renderText;
14
+  private sizeText;
15
+  private onDblClick;
16
+  private onTap;
17
+  private showEditor;
18
+  private onEditorOkClick;
19
+  private closeEditor;
20
+  private onEditorKeyDown;
21
+}

+ 8
- 0
dist/types/markers/text/TextMarkerToolbarItem.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from "../../toolbar/ToolbarItem";
2
+import { TextMarker } from "./TextMarker";
3
+export declare class TextMarkerToolbarItem implements ToolbarItem {
4
+    name: string;
5
+    tooltipText: string;
6
+    icon: string;
7
+    markerType: typeof TextMarker;
8
+}

+ 4
- 0
dist/types/render/Activator.d.ts View File

@@ -0,0 +1,4 @@
1
+export declare class Activator {
2
+    static key: string;
3
+    static readonly isLicensed: boolean;
4
+}

+ 55
- 0
dist/types/render/MarkerArea.d.ts View File

@@ -0,0 +1,55 @@
1
+import { MarkerBase } from '../markers/base/MarkerBase';
2
+export declare class MarkerArea {
3
+  private target;
4
+  private markerImage;
5
+  private markerImageHolder;
6
+  private defs;
7
+  private targetRect;
8
+  private width;
9
+  private height;
10
+  private markers;
11
+  private activeMarker;
12
+  private toolbar;
13
+  private toolbarUI;
14
+  private logoUI;
15
+  private completeCallback;
16
+  private cancelCallback;
17
+  private toolbars;
18
+  private scale;
19
+  constructor(target: HTMLImageElement);
20
+  show: (
21
+    completeCallback: (dataUrl: string) => void,
22
+    cancelCallback?: (() => void) | undefined
23
+  ) => void;
24
+  open: () => void;
25
+  render: (
26
+    completeCallback: (dataUrl: string) => void,
27
+    cancelCallback?: (() => void) | undefined
28
+  ) => void;
29
+  close: () => void;
30
+  addMarker: (markerType: typeof MarkerBase) => void;
31
+  deleteActiveMarker: () => void;
32
+  private setTargetRect;
33
+  private startRender;
34
+  private attachEvents;
35
+  private mouseDown;
36
+  private mouseMove;
37
+  private mouseUp;
38
+  private initMarkerCanvas;
39
+  private adjustUI;
40
+  private adjustSize;
41
+  private positionUI;
42
+  private positionMarkerImage;
43
+  private positionToolbar;
44
+  private showUI;
45
+  private setStyles;
46
+  private toolbarClick;
47
+  private selectMarker;
48
+  private deleteMarker;
49
+  private complete;
50
+  private cancel;
51
+  private renderFinished;
52
+  private renderFinishedClose;
53
+  private positionLogo;
54
+  private adLogo;
55
+}

+ 3
- 0
dist/types/render/Renderer.d.ts View File

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

+ 8
- 0
dist/types/toolbar/Toolbar.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ToolbarItem } from './ToolbarItem';
2
+export declare class Toolbar {
3
+    private toolbarItems;
4
+    private toolbarUI;
5
+    private clickHandler;
6
+    constructor(toolbarItems: ToolbarItem[], clickHandler: (ev: MouseEvent, toolbarItem: ToolbarItem) => void);
7
+    getUI: () => HTMLElement;
8
+}

+ 7
- 0
dist/types/toolbar/ToolbarButton.d.ts View File

@@ -0,0 +1,7 @@
1
+import { ToolbarItem } from './ToolbarItem';
2
+export declare class ToolbarButton {
3
+    private toolbarItem;
4
+    private clickHandler;
5
+    constructor(toolbarItem: ToolbarItem, clickHandler?: (ev: MouseEvent, toolbarItem: ToolbarItem) => void);
6
+    getElement: () => HTMLElement;
7
+}

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

@@ -0,0 +1,7 @@
1
+import { MarkerBase } from '../markers/base/MarkerBase';
2
+export interface ToolbarItem {
3
+  name: string;
4
+  tooltipText: string;
5
+  icon?: string;
6
+  markerType?: typeof MarkerBase;
7
+}

+ 13
- 0
dist/types/utils/SvgHelper/index.d.ts View File

@@ -0,0 +1,13 @@
1
+export declare class SvgHelper {
2
+    static createRect: (width: string | number, height: string | number, attributes?: [string, string][] | undefined) => SVGRectElement;
3
+    static createLine: (x1: string | number, y1: string | number, x2: string | number, y2: string | number, attributes?: [string, string][] | undefined) => SVGLineElement;
4
+    static createPolygon: (points: string, attributes?: [string, string][] | undefined) => SVGPolygonElement;
5
+    static createCircle: (radius: number, attributes?: [string, string][] | undefined) => SVGCircleElement;
6
+    static createGroup: (attributes?: [string, string][] | undefined) => SVGGElement;
7
+    static setAttributes: (el: SVGElement, attributes: [string, string][]) => void;
8
+    static createTransform: () => SVGTransform;
9
+    static createDefs: () => SVGDefsElement;
10
+    static createMarker: (id: string, orient: string, markerWidth: string | number, markerHeight: string | number, refX: string | number, refY: string | number, markerElement: SVGGraphicsElement) => SVGMarkerElement;
11
+    static createText: (attributes?: [string, string][] | undefined) => SVGTextElement;
12
+    static createTSpan: (text: string, attributes?: [string, string][] | undefined) => SVGTSpanElement;
13
+}

+ 0
- 0
example/index.less View File


+ 19
- 0
example/index.ts View File

@@ -0,0 +1,19 @@
1
+import { eventHub } from './../src/event/EventHub';
2
+import { WhitePage } from './../src/board/WhitePage/index';
3
+
4
+const page1 = new WhitePage(document.getElementById('image1') as HTMLImageElement, { eventHub });
5
+
6
+page1.drawboard.show((dataUrl: string) => {
7
+  const res = document.getElementById('resultImage') as HTMLImageElement;
8
+  res.src = dataUrl;
9
+});
10
+
11
+const page2 = new WhitePage(document.getElementById('image2') as HTMLImageElement, {
12
+  mode: 'mirror',
13
+  eventHub
14
+});
15
+
16
+page2.drawboard.show((dataUrl: string) => {
17
+  const res = document.getElementById('resultImage') as HTMLImageElement;
18
+  res.src = dataUrl;
19
+});

+ 9
- 0
example/types.d.ts View File

@@ -0,0 +1,9 @@
1
+declare module '*.less' {
2
+  const styles: Record<string, string>;
3
+  export = styles;
4
+}
5
+
6
+declare module '*.css' {
7
+  const content: any;
8
+  export default content;
9
+}

+ 89
- 0
package.json View File

@@ -0,0 +1,89 @@
1
+{
2
+  "keywords": [
3
+    "webpack",
4
+    "react"
5
+  ],
6
+  "name": "whiteboard",
7
+  "version": "0.0.1",
8
+  "private": true,
9
+  "main": "dist/index.js",
10
+  "types": "dist/types/index.d.ts",
11
+  "prettier": {
12
+    "printWidth": 100,
13
+    "singleQuote": true
14
+  },
15
+  "lint-staged": {
16
+    "*.{ts,tsx,scss,less,md}": [
17
+      "prettier --write",
18
+      "git add"
19
+    ]
20
+  },
21
+  "scripts": {
22
+    "clean": "rimraf dist",
23
+    "build": "npm run clean && npm run build:cjs && npm run copy && npm run build:umd",
24
+    "build:cjs": "tsc --project ./tsconfig.cjs.json",
25
+    "build:umd": "NODE_ENV=production webpack --config ./scripts/webpack/webpack.config.umd.js",
26
+    "copy": "copyfiles -u 1 './src/**/*.(less|svg)' dist/cjs/",
27
+    "dev": "webpack-dev-server --config ./scripts/webpack/webpack.config.dev.js --hot",
28
+    "start": "npm run dev"
29
+  },
30
+  "dependencies": {
31
+    "eventemitter3": "^3.1.0",
32
+    "prop-types": "^15.6.2",
33
+    "react": "^16.8.0",
34
+    "react-dom": "^16.8.0",
35
+    "uuid": "^3.3.2"
36
+  },
37
+  "devDependencies": {
38
+    "@types/classnames": "^2.2.7",
39
+    "@types/eventemitter3": "^2.0.2",
40
+    "@types/jest": "23.3.12",
41
+    "@types/react-dom": "^16.0.11",
42
+    "@types/react-router-dom": "^4.3.1",
43
+    "@types/uuid": "^3.4.4",
44
+    "autoprefixer": "9.4.4",
45
+    "awesome-typescript-loader": "^5.2.1",
46
+    "classnames": "^2.2.6",
47
+    "copy-webpack-plugin": "^4.6.0",
48
+    "copyfiles": "^2.1.0",
49
+    "css-loader": "2.1.0",
50
+    "enzyme": "^3.8.0",
51
+    "file-loader": "3.0.1",
52
+    "fork-ts-checker-webpack-plugin": "^0.5.2",
53
+    "html-webpack-plugin": "^3.2.0",
54
+    "html-webpack-template": "^6.2.0",
55
+    "jest": "23.6.0",
56
+    "jest-cli": "23.6.0",
57
+    "json-server": "0.14.2",
58
+    "lerna": "^3.8.5",
59
+    "less": "^3.9.0",
60
+    "less-loader": "^4.1.0",
61
+    "mini-css-extract-plugin": "^0.5.0",
62
+    "optimize-css-assets-webpack-plugin": "5.0.1",
63
+    "parallelshell": "^3.0.2",
64
+    "postcss-loader": "3.0.0",
65
+    "react-hot-loader": "^4.6.3",
66
+    "react-router-dom": "^4.3.1",
67
+    "resolve-url-loader": "3.0.0",
68
+    "rimraf": "^2.6.3",
69
+    "style-loader": "0.23.1",
70
+    "svg-inline-loader": "^0.8.0",
71
+    "ts-jest": "^23.10.5",
72
+    "ts-loader": "5.3.3",
73
+    "tslint": "^5.12.0",
74
+    "tslint-config-prettier": "^1.17.0",
75
+    "tslint-react": "^3.6.0",
76
+    "typescript": "3.2.2",
77
+    "uglifyjs-webpack-plugin": "2.1.1",
78
+    "url-loader": "^1.1.2",
79
+    "wasm-loader": "^1.3.0",
80
+    "webpack": "^4.28.3",
81
+    "webpack-cli": "3.2.1",
82
+    "webpack-dashboard": "2.0.0",
83
+    "webpack-dev-server": "^3.1.14",
84
+    "webpack-merge": "^4.2.1"
85
+  },
86
+  "files": [
87
+    "dist/"
88
+  ]
89
+}

+ 5
- 0
postcss.config.js View File

@@ -0,0 +1,5 @@
1
+const autoprefixer = require('autoprefixer');
2
+
3
+module.exports = {
4
+  plugins: [autoprefixer({ browsers: ['last 4 versions'], flexbox: 'no-2009' })]
5
+};

+ 0
- 0
public/drawboard.html View File


BIN
public/favicon.ico View File


+ 39
- 0
public/index.html View File

@@ -0,0 +1,39 @@
1
+<html lang="en">
2
+  <head>
3
+    <meta charset="UTF-8" />
4
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
+    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
6
+    <title>fc-whiteboard</title>
7
+    <style>
8
+      .image {
9
+        width: 500px;
10
+        height: 500px;
11
+        top: 100px;
12
+        position: absolute;
13
+      }
14
+    </style>
15
+  </head>
16
+  <body>
17
+    <body>
18
+      <noscript>You need to enable JavaScript to run this app.</noscript>
19
+      <div id="root">
20
+        <img
21
+          id="image1"
22
+          class="image"
23
+          style="left:100px"
24
+          src="https://i.postimg.cc/SNDkCfXD/image.png"
25
+        />
26
+        <img
27
+          id="image2"
28
+          class="image"
29
+          style="left:800px"
30
+          src="https://i.postimg.cc/SNDkCfXD/image.png"
31
+        />
32
+      </div>
33
+      <script>
34
+        window.__DEV_APP__ = {};
35
+      </script>
36
+      <script src="./index.js"></script>
37
+    </body>
38
+  </body>
39
+</html>

+ 15
- 0
public/manifest.json View File

@@ -0,0 +1,15 @@
1
+{
2
+  "short_name": "RTW",
3
+  "name": "Micro Frontend Boilerplate",
4
+  "icons": [
5
+    {
6
+      "src": "favicon.ico",
7
+      "sizes": "64x64 32x32 24x24 16x16",
8
+      "type": "image/x-icon"
9
+    }
10
+  ],
11
+  "start_url": "./index.html",
12
+  "display": "standalone",
13
+  "theme_color": "#000000",
14
+  "background_color": "#ffffff"
15
+}

+ 0
- 0
public/mirror.html View File


+ 19
- 0
scripts/webpack/webpack.config.dev.js View File

@@ -0,0 +1,19 @@
1
+const path = require('path');
2
+const merge = require('webpack-merge');
3
+
4
+const devConfig = require('../../../../scripts/webpack/webpack.config.dev');
5
+
6
+module.exports = merge(devConfig, {
7
+  entry: {
8
+    index: path.resolve(__dirname, '../../example')
9
+  },
10
+  devServer: {
11
+    contentBase: path.resolve(__dirname, '../../public')
12
+  },
13
+  resolve: {
14
+    alias: {
15
+      react: path.resolve('./node_modules/react'),
16
+      'react-dom': path.resolve('./node_modules/react-dom')
17
+    }
18
+  }
19
+});

+ 10
- 0
scripts/webpack/webpack.config.umd.js View File

@@ -0,0 +1,10 @@
1
+const merge = require('webpack-merge');
2
+const path = require('path');
3
+
4
+const umdConfig = require('../../../../scripts/webpack/webpack.config.umd');
5
+
6
+module.exports = merge(umdConfig, {
7
+  entry: {
8
+    index: path.resolve(__dirname, '../../src/index.ts')
9
+  }
10
+});

+ 5
- 0
src/assets/arrow.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/check.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/cover.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/eraser.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M497.941 273.941c18.745-18.745 18.745-49.137 0-67.882l-160-160c-18.745-18.745-49.136-18.746-67.883 0l-256 256c-18.745 18.745-18.745 49.137 0 67.882l96 96A48.004 48.004 0 0 0 144 480h356c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H355.883l142.058-142.059zm-302.627-62.627l137.373 137.373L265.373 416H150.628l-80-80 124.686-124.686z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/highlight.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 544 512"><path d="M0 479.98L99.92 512l35.45-35.45-67.04-67.04L0 479.98zm124.61-240.01a36.592 36.592 0 0 0-10.79 38.1l13.05 42.83-50.93 50.94 96.23 96.23 50.86-50.86 42.74 13.08c13.73 4.2 28.65-.01 38.15-10.78l35.55-41.64-173.34-173.34-41.52 35.44zm403.31-160.7l-63.2-63.2c-20.49-20.49-53.38-21.52-75.12-2.35L190.55 183.68l169.77 169.78L530.27 154.4c19.18-21.74 18.15-54.63-2.35-75.13z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/line.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M594.53 508.63L6.18 53.9c-6.97-5.42-8.23-15.47-2.81-22.45L23.01 6.18C28.43-.8 38.49-2.06 45.47 3.37L633.82 458.1c6.97 5.42 8.23 15.47 2.81 22.45l-19.64 25.27c-5.42 6.98-15.48 8.23-22.46 2.81z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/mouse-pointer.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M302.189 329.126H196.105l55.831 135.993c3.889 9.428-.555 19.999-9.444 23.999l-49.165 21.427c-9.165 4-19.443-.571-23.332-9.714l-53.053-129.136-86.664 89.138C18.729 472.71 0 463.554 0 447.977V18.299C0 1.899 19.921-6.096 30.277 5.443l284.412 292.542c11.472 11.179 3.007 31.141-12.5 31.141z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/rect.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h340c3.3 0 6 2.7 6 6v340c0 3.3-2.7 6-6 6z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/text.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M152 416h-24.013l26.586-80.782H292.8L319.386 416H296c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h136c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-26.739L275.495 42.746A16 16 0 0 0 260.382 32h-72.766a16 16 0 0 0-15.113 10.746L42.739 416H16c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h136c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16zm64.353-271.778c4.348-15.216 6.61-28.156 7.586-34.644.839 6.521 2.939 19.476 7.727 34.706l41.335 124.006h-98.619l41.971-124.068z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 5
- 0
src/assets/times.svg View File

@@ -0,0 +1,5 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"/></svg>
2
+<!--
3
+Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com
4
+License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
5
+-->

+ 116
- 0
src/board/Drawboard/index.less View File

@@ -0,0 +1,116 @@
1
+.fc-whiteboard-logo {
2
+  display: inline-block;
3
+  margin: 0px;
4
+  padding: 0px;
5
+
6
+  fill: #333333;
7
+}
8
+
9
+.fc-whiteboard-logo a {
10
+  display: grid;
11
+  align-items: center;
12
+  justify-items: center;
13
+  padding: 3px;
14
+  width: 20px;
15
+  height: 20px;
16
+}
17
+
18
+.fc-whiteboard-logo a:hover {
19
+  fill: #ff8080;
20
+}
21
+
22
+.fc-whiteboard-toolbar {
23
+  background-color: #cccccc;
24
+  padding: 0px 5px;
25
+  margin: 0px;
26
+  border-top-left-radius: 10px;
27
+  border-top-right-radius: 10px;
28
+
29
+  display: grid;
30
+  grid-template-columns: repeat(20, auto);
31
+}
32
+
33
+.fc-whiteboard-toolbar-button,
34
+.fc-whiteboard-toolbar-logo a {
35
+  display: inline-block;
36
+  margin: 2px;
37
+  padding: 3px;
38
+  cursor: pointer;
39
+  width: 20px;
40
+  height: 20px;
41
+  border-radius: 2px;
42
+  border-bottom: transparent solid 1px;
43
+  border-right: transparent solid 1px;
44
+
45
+  fill: #333333;
46
+
47
+  display: grid;
48
+  align-items: center;
49
+  justify-items: center;
50
+}
51
+
52
+.fc-whiteboard-toolbar-separator {
53
+  margin: 5px 5px;
54
+  border: 1px solid #dddddd;
55
+}
56
+
57
+.fc-whiteboard-toolbar-button:hover,
58
+.fc-whiteboard-toolbar-logo a:hover {
59
+  background-color: #eeeeee;
60
+  background: radial-gradient(#eeeeee, #cccccc);
61
+
62
+  fill: #ff8080;
63
+}
64
+
65
+.fc-whiteboard-toolbar-button svg {
66
+  height: 16px;
67
+}
68
+
69
+.fc-whiteboard-text-editor {
70
+  position: fixed;
71
+  z-index: 20000;
72
+  left: 0px;
73
+  top: 0px;
74
+  width: 100vw;
75
+  height: 100vh;
76
+  background-color: rgba(0, 0, 0, 0.9);
77
+
78
+  display: flex;
79
+  flex-direction: column;
80
+  align-items: center;
81
+  justify-content: center;
82
+}
83
+
84
+.fc-whiteboard-text-editor textarea {
85
+  width: 50%;
86
+  min-width: 50px;
87
+  max-width: 500px;
88
+  height: 50%;
89
+  min-height: 50px;
90
+  max-height: 500px;
91
+}
92
+
93
+.fc-whiteboard-text-editor .fc-whiteboard-text-editor-button-bar {
94
+  display: flex;
95
+  flex-direction: row;
96
+  justify-content: flex-end;
97
+  width: 50%;
98
+  min-width: 50px;
99
+  max-width: 500px;
100
+  padding-top: 10px;
101
+}
102
+.fc-whiteboard-text-editor .fc-whiteboard-text-editor-button {
103
+  display: grid;
104
+  align-items: center;
105
+  padding: 0px;
106
+  margin-left: 15px;
107
+  width: 20px;
108
+  height: 20px;
109
+
110
+  cursor: pointer;
111
+
112
+  fill: #888888;
113
+}
114
+.fc-whiteboard-text-editor .fc-whiteboard-text-editor-button:hover {
115
+  fill: #ff8080;
116
+}

+ 440
- 0
src/board/Drawboard/index.ts View File

@@ -0,0 +1,440 @@
1
+import { BaseMarker } from './../../markers/BaseMarker/index';
2
+import { lineMarkerToolbarItem } from './../../toolbar/toolbar-items';
3
+import { WhitePage } from './../WhitePage/index';
4
+import { onChangeFunc } from './../../event/Event';
5
+import { uuid } from './../../utils/uuid';
6
+import { SvgHelper } from '../../renderer/SvgHelper';
7
+import { Synthetizer } from '../../renderer/Synthetizer';
8
+import { Toolbar } from '../../toolbar/Toolbar';
9
+import { ToolbarItem } from '../../toolbar/ToolbarItem';
10
+
11
+import './index.less';
12
+import {
13
+  arrowMarkerToolbarItem,
14
+  highlightMarkerToolbarItem,
15
+  textMarkerToolbarItem,
16
+  coverMarkerToolbarItem,
17
+  rectMarkerToolbarItem
18
+} from '../../toolbar/toolbar-items';
19
+
20
+const OkIcon = require('../../assets/check.svg');
21
+const DeleteIcon = require('../../assets/eraser.svg');
22
+const PointerIcon = require('../../assets/mouse-pointer.svg');
23
+const CloseIcon = require('../../assets/times.svg');
24
+
25
+export class Drawboard {
26
+  id: string = uuid();
27
+
28
+  /** 句柄 */
29
+  page: WhitePage;
30
+
31
+  private target: HTMLImageElement;
32
+  private markerImage: SVGSVGElement;
33
+  private markerImageHolder: HTMLDivElement;
34
+  private defs: SVGDefsElement;
35
+
36
+  private targetRect: ClientRect;
37
+  private width: number;
38
+  private height: number;
39
+
40
+  private markers: BaseMarker[];
41
+  get markerMap(): { [key: string]: BaseMarker } {
42
+    const map = {};
43
+    this.markers.forEach(marker => {
44
+      map[marker.id] = marker;
45
+    });
46
+    return map;
47
+  }
48
+  private activeMarker: BaseMarker | null;
49
+
50
+  private toolbar: Toolbar;
51
+  private toolbarUI: HTMLElement;
52
+
53
+  private completeCallback: (dataUrl: string) => void;
54
+  private cancelCallback: () => void;
55
+  private onChange: onChangeFunc = () => {};
56
+
57
+  private toolbars: ToolbarItem[] = [
58
+    {
59
+      icon: PointerIcon,
60
+      name: 'pointer',
61
+      tooltipText: 'Pointer'
62
+    },
63
+    {
64
+      icon: DeleteIcon,
65
+      name: 'delete',
66
+      tooltipText: 'Delete'
67
+    },
68
+    {
69
+      name: 'separator',
70
+      tooltipText: ''
71
+    },
72
+    rectMarkerToolbarItem,
73
+    coverMarkerToolbarItem,
74
+    highlightMarkerToolbarItem,
75
+    lineMarkerToolbarItem,
76
+    arrowMarkerToolbarItem,
77
+    textMarkerToolbarItem,
78
+    {
79
+      name: 'separator',
80
+      tooltipText: ''
81
+    },
82
+    {
83
+      icon: OkIcon,
84
+      name: 'ok',
85
+      tooltipText: 'OK'
86
+    },
87
+    {
88
+      icon: CloseIcon,
89
+      name: 'close',
90
+      tooltipText: 'Close'
91
+    }
92
+  ];
93
+
94
+  private scale = 1.0;
95
+
96
+  constructor(
97
+    page: WhitePage,
98
+    target: HTMLImageElement,
99
+    { onChange }: { onChange?: onChangeFunc } = {}
100
+  ) {
101
+    this.page = page;
102
+    this.target = target;
103
+    this.width = target.clientWidth;
104
+    this.height = target.clientHeight;
105
+
106
+    this.markers = [];
107
+    this.activeMarker = null;
108
+
109
+    if (onChange) {
110
+      this.onChange = onChange;
111
+    }
112
+  }
113
+
114
+  public show = (completeCallback: (dataUrl: string) => void, cancelCallback?: () => void) => {
115
+    this.completeCallback = completeCallback;
116
+
117
+    if (cancelCallback) {
118
+      this.cancelCallback = cancelCallback;
119
+    }
120
+
121
+    this.open();
122
+
123
+    if (this.page.mode !== 'mirror') {
124
+      this.showUI();
125
+    }
126
+  };
127
+
128
+  public open = () => {
129
+    this.setTargetRect();
130
+
131
+    this.initMarkerCanvas();
132
+    this.attachEvents();
133
+    this.setStyles();
134
+
135
+    window.addEventListener('resize', this.adjustUI);
136
+  };
137
+
138
+  public render = (completeCallback: (dataUrl: string) => void, cancelCallback?: () => void) => {
139
+    this.completeCallback = completeCallback;
140
+
141
+    if (cancelCallback) {
142
+      this.cancelCallback = cancelCallback;
143
+    }
144
+
145
+    this.selectMarker(null);
146
+    this.startRender(this.renderFinished);
147
+  };
148
+
149
+  public close = () => {
150
+    if (this.toolbarUI) {
151
+      document.body.removeChild(this.toolbarUI);
152
+    }
153
+    if (this.markerImage) {
154
+      document.body.removeChild(this.markerImageHolder);
155
+    }
156
+  };
157
+
158
+  public addMarker = (markerType: typeof BaseMarker, { id }: { id?: string } = {}) => {
159
+    const marker = markerType.createMarker();
160
+
161
+    if (id) {
162
+      marker.id = id;
163
+    }
164
+
165
+    marker.onSelected = this.selectMarker;
166
+    marker.onChange = this.onChange;
167
+
168
+    if (marker.defs && marker.defs.length > 0) {
169
+      for (const d of marker.defs) {
170
+        if (d.id && !this.markerImage.getElementById(d.id)) {
171
+          this.defs.appendChild(d);
172
+        }
173
+      }
174
+    }
175
+
176
+    // 触发事件流
177
+    this.onChange({
178
+      target: 'drawboard',
179
+      id: this.id,
180
+      event: 'add',
181
+      data: { type: marker.type, id: marker.id }
182
+    });
183
+
184
+    this.markers.push(marker);
185
+
186
+    this.selectMarker(marker);
187
+
188
+    this.markerImage.appendChild(marker.visual);
189
+
190
+    const bbox = marker.visual.getBBox();
191
+    const x = this.width / 2 / this.scale - bbox.width / 2;
192
+    const y = this.height / 2 / this.scale - bbox.height / 2;
193
+
194
+    const translate = marker.visual.transform.baseVal.getItem(0);
195
+    translate.setMatrix(translate.matrix.translate(x, y));
196
+    marker.visual.transform.baseVal.replaceItem(translate, 0);
197
+  };
198
+
199
+  public deleteActiveMarker = () => {
200
+    if (this.activeMarker) {
201
+      this.deleteMarker(this.activeMarker);
202
+    }
203
+  };
204
+
205
+  private setTargetRect = () => {
206
+    const targetRect = this.target.getBoundingClientRect() as DOMRect;
207
+    const bodyRect = document.body.parentElement!.getBoundingClientRect();
208
+    this.targetRect = {
209
+      left: targetRect.left - bodyRect.left,
210
+      top: targetRect.top - bodyRect.top
211
+    } as ClientRect;
212
+  };
213
+
214
+  private startRender = (done: (dataUrl: string) => void) => {
215
+    const renderer = new Synthetizer();
216
+    renderer.rasterize(this.target, this.markerImage, done);
217
+  };
218
+
219
+  private attachEvents = () => {
220
+    this.markerImage.addEventListener('mousedown', this.mouseDown);
221
+    this.markerImage.addEventListener('mousemove', this.mouseMove);
222
+    this.markerImage.addEventListener('mouseup', this.mouseUp);
223
+  };
224
+
225
+  private mouseDown = (ev: MouseEvent) => {
226
+    /* tslint:disable:no-bitwise */
227
+    if (this.activeMarker && (ev.buttons & 1) > 0) {
228
+      this.activeMarker.deselect();
229
+      this.activeMarker = null;
230
+    }
231
+  };
232
+
233
+  private mouseMove = (ev: MouseEvent) => {
234
+    /* tslint:disable:no-bitwise */
235
+    if (this.activeMarker && (ev.buttons & 1) > 0) {
236
+      this.activeMarker.manipulate(ev);
237
+    }
238
+  };
239
+
240
+  private mouseUp = (ev: MouseEvent) => {
241
+    if (this.activeMarker) {
242
+      this.activeMarker.endManipulation();
243
+    }
244
+  };
245
+
246
+  private initMarkerCanvas = () => {
247
+    this.markerImageHolder = document.createElement('div');
248
+    // fix for Edge's touch behavior
249
+    this.markerImageHolder.style.setProperty('touch-action', 'none');
250
+    this.markerImageHolder.style.setProperty('-ms-touch-action', 'none');
251
+
252
+    this.markerImage = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
253
+    this.markerImage.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
254
+    this.markerImage.setAttribute('width', this.width.toString());
255
+    this.markerImage.setAttribute('height', this.height.toString());
256
+    this.markerImage.setAttribute(
257
+      'viewBox',
258
+      '0 0 ' + this.width.toString() + ' ' + this.height.toString()
259
+    );
260
+
261
+    this.markerImageHolder.style.position = 'absolute';
262
+    this.markerImageHolder.style.width = `${this.width}px`;
263
+    this.markerImageHolder.style.height = `${this.height}px`;
264
+    this.markerImageHolder.style.transformOrigin = 'top left';
265
+    this.positionMarkerImage();
266
+
267
+    this.defs = SvgHelper.createDefs();
268
+    this.markerImage.appendChild(this.defs);
269
+
270
+    this.markerImageHolder.appendChild(this.markerImage);
271
+
272
+    document.body.appendChild(this.markerImageHolder);
273
+  };
274
+
275
+  private adjustUI = (ev: UIEvent) => {
276
+    this.adjustSize();
277
+    this.positionUI();
278
+  };
279
+
280
+  private adjustSize = () => {
281
+    this.width = this.target.clientWidth;
282
+    this.height = this.target.clientHeight;
283
+
284
+    const scale = this.target.clientWidth / this.markerImageHolder.clientWidth;
285
+    if (scale !== 1.0) {
286
+      this.scale *= scale;
287
+      this.markerImageHolder.style.width = `${this.width}px`;
288
+      this.markerImageHolder.style.height = `${this.height}px`;
289
+
290
+      this.markerImageHolder.style.transform = `scale(${this.scale})`;
291
+    }
292
+  };
293
+
294
+  private positionUI = () => {
295
+    this.setTargetRect();
296
+    this.positionMarkerImage();
297
+    this.positionToolbar();
298
+  };
299
+
300
+  private positionMarkerImage = () => {
301
+    this.markerImageHolder.style.top = this.targetRect.top + 'px';
302
+    this.markerImageHolder.style.left = this.targetRect.left + 'px';
303
+  };
304
+
305
+  private positionToolbar = () => {
306
+    this.toolbarUI.style.left = `${this.targetRect.left +
307
+      this.target.offsetWidth -
308
+      this.toolbarUI.clientWidth}px`;
309
+    this.toolbarUI.style.top = `${this.targetRect.top - this.toolbarUI.clientHeight}px`;
310
+  };
311
+
312
+  private showUI = () => {
313
+    this.toolbar = new Toolbar(this.toolbars, this.toolbarClick);
314
+    this.toolbarUI = this.toolbar.getUI();
315
+    document.body.appendChild(this.toolbarUI);
316
+    this.toolbarUI.style.position = 'absolute';
317
+    this.positionToolbar();
318
+  };
319
+
320
+  private setStyles = () => {
321
+    const editorStyleSheet = document.createElementNS('http://www.w3.org/2000/svg', 'style');
322
+    editorStyleSheet.innerHTML = `
323
+            .rect-marker .render-visual {
324
+                stroke: #ff0000;
325
+                stroke-width: 3;
326
+                fill: transparent;
327
+            }
328
+            .cover-marker .render-visual {
329
+                stroke-width: 0;
330
+                fill: #000000;
331
+            }
332
+            .highlight-marker .render-visual {
333
+                stroke: transparent;
334
+                stroke-width: 0;
335
+                fill: #ffff00;
336
+                fill-opacity: 0.4;
337
+            }
338
+            .line-marker .render-visual {
339
+                stroke: #ff0000;
340
+                stroke-width: 3;
341
+                fill: transparent;
342
+            }
343
+            .arrow-marker .render-visual {
344
+                stroke: #ff0000;
345
+                stroke-width: 3;
346
+                fill: transparent;
347
+            }
348
+            .arrow-marker-tip {
349
+                stroke-width: 0;
350
+                fill: #ff0000;
351
+            }
352
+            .text-marker text {
353
+                fill: #ff0000;
354
+                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
355
+                    Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
356
+                    "Segoe UI Emoji", "Segoe UI Symbol";
357
+            }
358
+            .fc-whiteboard-rect-control-box .fc-whiteboard-rect-control-rect {
359
+                stroke: black;
360
+                stroke-width: 1;
361
+                stroke-opacity: 0.5;
362
+                stroke-dasharray: 3, 2;
363
+                fill: transparent;
364
+            }
365
+            .fc-whiteboard-control-grip {
366
+                fill: #cccccc;
367
+                stroke: #333333;
368
+                stroke-width: 2;
369
+            }
370
+        `;
371
+
372
+    this.markerImage.appendChild(editorStyleSheet);
373
+  };
374
+
375
+  private toolbarClick = (ev: MouseEvent, toolbarItem: ToolbarItem) => {
376
+    if (toolbarItem.markerType) {
377
+      this.addMarker(toolbarItem.markerType);
378
+    } else {
379
+      // command button
380
+      switch (toolbarItem.name) {
381
+        case 'delete': {
382
+          this.deleteActiveMarker();
383
+          break;
384
+        }
385
+        case 'pointer': {
386
+          if (this.activeMarker) {
387
+            this.selectMarker(null);
388
+          }
389
+          break;
390
+        }
391
+        case 'close': {
392
+          this.cancel();
393
+          break;
394
+        }
395
+        case 'ok': {
396
+          this.complete();
397
+          break;
398
+        }
399
+        default:
400
+          break;
401
+      }
402
+    }
403
+  };
404
+
405
+  private selectMarker = (marker: BaseMarker | null) => {
406
+    if (this.activeMarker && this.activeMarker !== marker) {
407
+      this.activeMarker.deselect();
408
+    }
409
+    this.activeMarker = marker;
410
+  };
411
+
412
+  private deleteMarker = (marker: BaseMarker) => {
413
+    this.markerImage.removeChild(marker.visual);
414
+    if (this.activeMarker === marker) {
415
+      this.activeMarker = null;
416
+    }
417
+    this.markers.splice(this.markers.indexOf(marker), 1);
418
+  };
419
+
420
+  private complete = () => {
421
+    this.selectMarker(null);
422
+    this.startRender(this.renderFinishedClose);
423
+  };
424
+
425
+  private cancel = () => {
426
+    this.close();
427
+    if (this.cancelCallback) {
428
+      this.cancelCallback();
429
+    }
430
+  };
431
+
432
+  private renderFinished = (dataUrl: string) => {
433
+    this.completeCallback(dataUrl);
434
+  };
435
+
436
+  private renderFinishedClose = (dataUrl: string) => {
437
+    this.close();
438
+    this.completeCallback(dataUrl);
439
+  };
440
+}

+ 0
- 0
src/board/WhitePage/index.less View File


+ 57
- 0
src/board/WhitePage/index.ts View File

@@ -0,0 +1,57 @@
1
+import { MarkerType } from './../../markers/types';
2
+import { ChangeEvent } from './../../event/Event';
3
+import { EventHub } from '../../event/EventHub';
4
+import { WhiteboardMode } from './../types';
5
+import { Drawboard } from './../Drawboard/index';
6
+import { uuid } from './../../utils/uuid';
7
+import { getMarkerByType } from '../../markers/types';
8
+
9
+/** 白板中的每一页 */
10
+export class WhitePage {
11
+  id: string = uuid();
12
+
13
+  drawboard: Drawboard;
14
+  mode: WhiteboardMode = 'master';
15
+
16
+  constructor(
17
+    target: HTMLImageElement,
18
+    { mode, eventHub }: { mode?: WhiteboardMode; eventHub?: EventHub } = {}
19
+  ) {
20
+    if (mode) {
21
+      this.mode = mode;
22
+    }
23
+
24
+    if (this.mode === 'master') {
25
+      if (eventHub) {
26
+        this.drawboard = new Drawboard(this, target, {
27
+          onChange: ev => eventHub.emit('change', ev)
28
+        });
29
+      } else {
30
+        this.drawboard = new Drawboard(this, target);
31
+      }
32
+    }
33
+
34
+    if (this.mode === 'mirror') {
35
+      if (!eventHub) {
36
+        throw new Error('Invalid eventHub');
37
+      }
38
+
39
+      this.drawboard = new Drawboard(this, target);
40
+
41
+      eventHub.on('change', (ev: ChangeEvent) => {
42
+        if (ev.event === 'add') {
43
+          const data: { id: string; type: MarkerType } = ev.data as {
44
+            id: string;
45
+            type: MarkerType;
46
+          };
47
+          this.drawboard.addMarker(getMarkerByType(data.type), { id: data.id });
48
+        }
49
+
50
+        if (ev.event === 'move' || ev.event === 'resize') {
51
+          const marker = this.drawboard.markerMap[ev.id];
52
+          marker.reactToManipulation(ev.event, ev.data as any);
53
+        }
54
+      });
55
+    }
56
+  }
57
+}

+ 0
- 0
src/board/Whiteboard/index.less View File


+ 15
- 0
src/board/Whiteboard/index.ts View File

@@ -0,0 +1,15 @@
1
+import { WhiteboardMode, WhitePageSource } from '../types';
2
+
3
+export class Whiteboard {
4
+  mode: WhiteboardMode = 'master';
5
+  sources: WhitePageSource[] = [];
6
+
7
+  /** @region UI Options */
8
+  // 是否为全屏模式
9
+  isFullscreen: boolean = false;
10
+
11
+  constructor() {}
12
+
13
+  /** 初始化操作 */
14
+  init() {}
15
+}

+ 6
- 0
src/board/types.ts View File

@@ -0,0 +1,6 @@
1
+// 是主动绘制模式,还是镜像模式
2
+export type WhiteboardMode = 'master' | 'mirror';
3
+
4
+export type RenderCallback = (container: HTMLElement) => void;
5
+
6
+export type WhitePageSource = string | RenderCallback;

+ 20
- 0
src/event/Event.ts View File

@@ -0,0 +1,20 @@
1
+export type TargetType = 'page' | 'drawboard' | 'marker';
2
+export type EventType = 'add' | 'resize' | 'move' | 'remove';
3
+export type PositionType =
4
+  | 'topLeft'
5
+  | 'bottomLeft'
6
+  | 'topRight'
7
+  | 'bottomRight'
8
+  | 'centerLeft'
9
+  | 'centerRight'
10
+  | 'topCenter'
11
+  | 'bottomCenter';
12
+
13
+export interface ChangeEvent {
14
+  target: TargetType;
15
+  id: string;
16
+  event: EventType;
17
+  data?: object | string;
18
+}
19
+
20
+export type onChangeFunc = (ev: ChangeEvent) => void;

+ 10
- 0
src/event/EventHub.ts View File

@@ -0,0 +1,10 @@
1
+import { ChangeEvent } from './Event';
2
+import * as EventEmitter from 'eventemitter3';
3
+
4
+export class EventHub extends EventEmitter<'change'> {}
5
+
6
+export const eventHub = new EventHub();
7
+
8
+eventHub.on('change', (changeEv: ChangeEvent) => {
9
+  console.log(changeEv);
10
+});

+ 1
- 0
src/index.ts View File

@@ -0,0 +1 @@
1
+export { Drawboard } from './board/Drawboard';

+ 38
- 0
src/markers/ArrowMarker/index.ts View File

@@ -0,0 +1,38 @@
1
+import { MarkerType } from './../types';
2
+import { LinearMarker } from '../LinearMarker';
3
+import { SvgHelper } from 'fc-whiteboard/src/renderer/SvgHelper';
4
+
5
+export class ArrowMarker extends LinearMarker {
6
+  type: MarkerType = 'arrow';
7
+
8
+  public static createMarker = (): LinearMarker => {
9
+    const marker = new ArrowMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  private readonly ARROW_SIZE = 6;
15
+
16
+  protected setup() {
17
+    super.setup();
18
+    SvgHelper.setAttributes(this.visual, [['class', 'arrow-marker']]);
19
+
20
+    const tip = SvgHelper.createPolygon(
21
+      `0,0 ${this.ARROW_SIZE},${this.ARROW_SIZE / 2} 0,${this.ARROW_SIZE}`,
22
+      [['class', 'arrow-marker-tip']]
23
+    );
24
+    this.defs.push(
25
+      SvgHelper.createMarker(
26
+        'arrow-marker-head',
27
+        'auto',
28
+        this.ARROW_SIZE,
29
+        this.ARROW_SIZE,
30
+        this.ARROW_SIZE - 1,
31
+        this.ARROW_SIZE / 2,
32
+        tip
33
+      )
34
+    );
35
+
36
+    this.markerLine.setAttribute('marker-end', 'url(#arrow-marker-head');
37
+  }
38
+}

+ 11
- 0
src/markers/BaseMarker/ResizeGrip.ts View File

@@ -0,0 +1,11 @@
1
+import { SvgHelper } from '../../renderer/SvgHelper';
2
+
3
+export class ResizeGrip {
4
+  public visual: SVGGraphicsElement;
5
+
6
+  public readonly GRIP_SIZE = 10;
7
+
8
+  constructor() {
9
+    this.visual = SvgHelper.createCircle(this.GRIP_SIZE, [['class', 'fc-whiteboard-control-grip']]);
10
+  }
11
+}

+ 185
- 0
src/markers/BaseMarker/index.ts View File

@@ -0,0 +1,185 @@
1
+import { PositionType } from 'fc-whiteboard/src/event/Event';
2
+import { onChangeFunc, EventType } from '../../event/Event';
3
+import { MarkerType } from '../types';
4
+import * as uuid from 'uuid/v1';
5
+import { SvgHelper } from '../../renderer/SvgHelper';
6
+
7
+export class BaseMarker {
8
+  id: string = uuid();
9
+  type: MarkerType = 'base';
10
+  onChange: onChangeFunc = () => {};
11
+
12
+  public static createMarker = (): BaseMarker => {
13
+    const marker = new BaseMarker();
14
+    marker.setup();
15
+    return marker;
16
+  };
17
+
18
+  public visual: SVGGElement;
19
+  public renderVisual: SVGGElement;
20
+
21
+  public onSelected: (marker: BaseMarker) => void;
22
+
23
+  public defs: SVGElement[] = [];
24
+
25
+  protected width: number = 200;
26
+  protected height: number = 50;
27
+
28
+  protected isActive: boolean = true;
29
+  protected isResizing: boolean = false;
30
+
31
+  protected previousMouseX: number = 0;
32
+  protected previousMouseY: number = 0;
33
+
34
+  private isDragging: boolean = false;
35
+
36
+  public reactToManipulation(
37
+    type: EventType,
38
+    { dx, dy, pos }: { dx: number; dy: number; pos: PositionType }
39
+  ) {
40
+    if (type === 'move') {
41
+      this.move(dx, dy);
42
+    }
43
+
44
+    if (type === 'resize') {
45
+      this.resizeByEvent(dx, dy, pos);
46
+    }
47
+  }
48
+
49
+  public manipulate = (ev: MouseEvent) => {
50
+    const scale = this.visual.getScreenCTM()!.a;
51
+    const dx = (ev.screenX - this.previousMouseX) / scale;
52
+    const dy = (ev.screenY - this.previousMouseY) / scale;
53
+
54
+    if (this.isDragging) {
55
+      this.onChange({ target: 'marker', id: this.id, event: 'move', data: { dx, dy } });
56
+      this.move(dx, dy);
57
+    }
58
+
59
+    if (this.isResizing) {
60
+      this.resize(dx, dy, (pos: PositionType) => {
61
+        this.onChange({ target: 'marker', id: this.id, event: 'resize', data: { dx, dy, pos } });
62
+      });
63
+    }
64
+
65
+    this.previousMouseX = ev.screenX;
66
+    this.previousMouseY = ev.screenY;
67
+  };
68
+
69
+  public endManipulation() {
70
+    this.isDragging = false;
71
+    this.isResizing = false;
72
+  }
73
+
74
+  public select() {
75
+    this.isActive = true;
76
+    if (this.onSelected) {
77
+      this.onSelected(this);
78
+    }
79
+    return;
80
+  }
81
+
82
+  public deselect() {
83
+    this.isActive = false;
84
+    this.endManipulation();
85
+    return;
86
+  }
87
+
88
+  protected setup() {
89
+    this.visual = SvgHelper.createGroup();
90
+    // translate
91
+    this.visual.transform.baseVal.appendItem(SvgHelper.createTransform());
92
+
93
+    this.visual.addEventListener('mousedown', this.mouseDown);
94
+    this.visual.addEventListener('mouseup', this.mouseUp);
95
+    this.visual.addEventListener('mousemove', this.mouseMove);
96
+
97
+    this.visual.addEventListener('touchstart', this.onTouch, { passive: false });
98
+    this.visual.addEventListener('touchend', this.onTouch, { passive: false });
99
+    this.visual.addEventListener('touchmove', this.onTouch, { passive: false });
100
+
101
+    this.renderVisual = SvgHelper.createGroup([['class', 'render-visual']]);
102
+    this.visual.appendChild(this.renderVisual);
103
+  }
104
+
105
+  protected addToVisual = (el: SVGElement) => {
106
+    this.visual.appendChild(el);
107
+  };
108
+
109
+  protected addToRenderVisual = (el: SVGElement) => {
110
+    this.renderVisual.appendChild(el);
111
+  };
112
+
113
+  protected resize(x: number, y: number, cb?: Function) {
114
+    return;
115
+  }
116
+  protected resizeByEvent(x: number, y: number, pos?: PositionType) {
117
+    return;
118
+  }
119
+
120
+  /** 截获 Touch 事件,并且转发为 Mouse 事件 */
121
+  protected onTouch(ev: TouchEvent) {
122
+    ev.preventDefault();
123
+    const newEvt = document.createEvent('MouseEvents');
124
+    const touch = ev.changedTouches[0];
125
+    let type = null;
126
+
127
+    switch (ev.type) {
128
+      case 'touchstart':
129
+        type = 'mousedown';
130
+        break;
131
+      case 'touchmove':
132
+        type = 'mousemove';
133
+        break;
134
+      case 'touchend':
135
+        type = 'mouseup';
136
+        break;
137
+      default:
138
+        break;
139
+    }
140
+
141
+    newEvt.initMouseEvent(
142
+      type!,
143
+      true,
144
+      true,
145
+      window,
146
+      0,
147
+      touch.screenX,
148
+      touch.screenY,
149
+      touch.clientX,
150
+      touch.clientY,
151
+      ev.ctrlKey,
152
+      ev.altKey,
153
+      ev.shiftKey,
154
+      ev.metaKey,
155
+      0,
156
+      null
157
+    );
158
+
159
+    ev.target!.dispatchEvent(newEvt);
160
+  }
161
+
162
+  private mouseDown = (ev: MouseEvent) => {
163
+    ev.stopPropagation();
164
+    this.select();
165
+    this.isDragging = true;
166
+    this.previousMouseX = ev.screenX;
167
+    this.previousMouseY = ev.screenY;
168
+  };
169
+
170
+  private mouseUp = (ev: MouseEvent) => {
171
+    ev.stopPropagation();
172
+    this.endManipulation();
173
+  };
174
+
175
+  private mouseMove = (ev: MouseEvent) => {
176
+    ev.stopPropagation();
177
+    this.manipulate(ev);
178
+  };
179
+
180
+  private move = (dx: number, dy: number) => {
181
+    const translate = this.visual.transform.baseVal.getItem(0);
182
+    translate.setMatrix(translate.matrix.translate(dx, dy));
183
+    this.visual.transform.baseVal.replaceItem(translate, 0);
184
+  };
185
+}

+ 18
- 0
src/markers/CoverMarker/index.ts View File

@@ -0,0 +1,18 @@
1
+import { MarkerType } from './../types';
2
+import { SvgHelper } from '../../renderer/SvgHelper';
3
+import { RectBaseMarker } from '../RectMarker/RectBaseMarker';
4
+
5
+export class CoverMarker extends RectBaseMarker {
6
+  type: MarkerType = 'cover';
7
+
8
+  public static createMarker = (): RectBaseMarker => {
9
+    const marker = new CoverMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  protected setup() {
15
+    super.setup();
16
+    SvgHelper.setAttributes(this.visual, [['class', 'cover-marker']]);
17
+  }
18
+}

+ 18
- 0
src/markers/HighlightMarker/index.ts View File

@@ -0,0 +1,18 @@
1
+import { MarkerType } from './../types';
2
+import { SvgHelper } from '../../renderer/SvgHelper';
3
+import { RectBaseMarker } from '../RectMarker/RectBaseMarker';
4
+
5
+export class HighlightMarker extends RectBaseMarker {
6
+  type: MarkerType = 'highlight';
7
+
8
+  public static createMarker = (): RectBaseMarker => {
9
+    const marker = new HighlightMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  protected setup() {
15
+    super.setup();
16
+    SvgHelper.setAttributes(this.visual, [['class', 'highlight-marker']]);
17
+  }
18
+}

+ 18
- 0
src/markers/LineMarker/index.ts View File

@@ -0,0 +1,18 @@
1
+import { MarkerType } from './../types';
2
+import { LinearMarker } from '../LinearMarker';
3
+import { SvgHelper } from './../../renderer/SvgHelper/index';
4
+
5
+export class LineMarker extends LinearMarker {
6
+  type: MarkerType = 'line';
7
+
8
+  public static createMarker = (): LinearMarker => {
9
+    const marker = new LineMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  protected setup() {
15
+    super.setup();
16
+    SvgHelper.setAttributes(this.visual, [['class', 'line-marker']]);
17
+  }
18
+}

+ 168
- 0
src/markers/LinearMarker/index.ts View File

@@ -0,0 +1,168 @@
1
+import { BaseMarker } from '../BaseMarker';
2
+import { ResizeGrip } from '../BaseMarker/ResizeGrip';
3
+import { SvgHelper } from '../../renderer/SvgHelper';
4
+
5
+export class LinearMarker extends BaseMarker {
6
+  public static createMarker = (): LinearMarker => {
7
+    const marker = new LinearMarker();
8
+    marker.setup();
9
+    return marker;
10
+  };
11
+
12
+  protected markerLine: SVGLineElement;
13
+
14
+  private readonly MIN_LENGTH = 20;
15
+
16
+  private markerBgLine: SVGLineElement; // touch target
17
+
18
+  private controlBox: SVGGElement;
19
+
20
+  private controlGrip1: ResizeGrip;
21
+  private controlGrip2: ResizeGrip;
22
+  private activeGrip: ResizeGrip | null;
23
+
24
+  private x1: number = 0;
25
+  private y1: number = 0;
26
+  private x2: number = this.width;
27
+  private y2: number = 0;
28
+
29
+  public endManipulation() {
30
+    super.endManipulation();
31
+    this.isResizing = false;
32
+    this.activeGrip = null;
33
+  }
34
+
35
+  public select() {
36
+    super.select();
37
+    this.controlBox.style.display = '';
38
+  }
39
+
40
+  public deselect() {
41
+    super.deselect();
42
+    this.controlBox.style.display = 'none';
43
+  }
44
+
45
+  protected setup() {
46
+    super.setup();
47
+
48
+    this.markerBgLine = SvgHelper.createLine(0, 0, this.x2, 0, [
49
+      ['stroke', 'transparent'],
50
+      ['stroke-width', '30']
51
+    ]);
52
+    this.addToRenderVisual(this.markerBgLine);
53
+    this.markerLine = SvgHelper.createLine(0, 0, this.x2, 0);
54
+    this.addToRenderVisual(this.markerLine);
55
+
56
+    this.addControlBox();
57
+  }
58
+
59
+  protected resize(x: number, y: number) {
60
+    if (this.activeGrip) {
61
+      if (
62
+        this.activeGrip === this.controlGrip1 &&
63
+        this.getLineLength(this.x1 + x, this.y1 + 1, this.x2, this.y2) >= this.MIN_LENGTH
64
+      ) {
65
+        this.x1 += x;
66
+        this.y1 += y;
67
+        this.markerBgLine.setAttribute('x1', this.x1.toString());
68
+        this.markerBgLine.setAttribute('y1', this.y1.toString());
69
+        this.markerLine.setAttribute('x1', this.x1.toString());
70
+        this.markerLine.setAttribute('y1', this.y1.toString());
71
+      } else if (
72
+        this.activeGrip === this.controlGrip2 &&
73
+        this.getLineLength(this.x1, this.y1, this.x2 + x, this.y2 + y) >= this.MIN_LENGTH
74
+      ) {
75
+        this.x2 += x;
76
+        this.y2 += y;
77
+        this.markerBgLine.setAttribute('x2', this.x2.toString());
78
+        this.markerBgLine.setAttribute('y2', this.y2.toString());
79
+        this.markerLine.setAttribute('x2', this.x2.toString());
80
+        this.markerLine.setAttribute('y2', this.y2.toString());
81
+      }
82
+    }
83
+
84
+    this.adjustControlBox();
85
+  }
86
+
87
+  private getLineLength = (x1: number, y1: number, x2: number, y2: number): number => {
88
+    const dx = Math.abs(x1 - x2);
89
+    const dy = Math.abs(y1 - y2);
90
+
91
+    return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
92
+  };
93
+
94
+  private addControlBox = () => {
95
+    this.controlBox = SvgHelper.createGroup([['class', 'fc-whiteboard-line-control-box']]);
96
+    this.addToVisual(this.controlBox);
97
+
98
+    this.addControlGrips();
99
+  };
100
+
101
+  private adjustControlBox = () => {
102
+    this.positionGrips();
103
+  };
104
+
105
+  private addControlGrips = () => {
106
+    this.controlGrip1 = this.createGrip();
107
+    this.controlGrip2 = this.createGrip();
108
+
109
+    this.positionGrips();
110
+  };
111
+
112
+  private createGrip = (): ResizeGrip => {
113
+    const grip = new ResizeGrip();
114
+    grip.visual.transform.baseVal.appendItem(SvgHelper.createTransform());
115
+    this.controlBox.appendChild(grip.visual);
116
+
117
+    grip.visual.addEventListener('mousedown', this.gripMouseDown);
118
+    grip.visual.addEventListener('mousemove', this.gripMouseMove);
119
+    grip.visual.addEventListener('mouseup', this.gripMouseUp);
120
+
121
+    grip.visual.addEventListener('touchstart', this.onTouch, { passive: false });
122
+    grip.visual.addEventListener('touchend', this.onTouch, { passive: false });
123
+    grip.visual.addEventListener('touchmove', this.onTouch, { passive: false });
124
+
125
+    return grip;
126
+  };
127
+
128
+  private positionGrips = () => {
129
+    const gripSize = this.controlGrip1.GRIP_SIZE;
130
+
131
+    const x1 = this.x1 - gripSize / 2;
132
+    const y1 = this.y1 - gripSize / 2;
133
+    const x2 = this.x2 - gripSize / 2;
134
+    const y2 = this.y2 - gripSize / 2;
135
+
136
+    this.positionGrip(this.controlGrip1.visual, x1, y1);
137
+    this.positionGrip(this.controlGrip2.visual, x2, y2);
138
+  };
139
+
140
+  private positionGrip = (grip: SVGGraphicsElement, x: number, y: number) => {
141
+    const translate = grip.transform.baseVal.getItem(0);
142
+    translate.setTranslate(x, y);
143
+    grip.transform.baseVal.replaceItem(translate, 0);
144
+  };
145
+
146
+  private gripMouseDown = (ev: MouseEvent) => {
147
+    this.isResizing = true;
148
+    this.activeGrip =
149
+      (ev.target as SVGGraphicsElement) === this.controlGrip1.visual
150
+        ? this.controlGrip1
151
+        : this.controlGrip2;
152
+    this.previousMouseX = ev.screenX;
153
+    this.previousMouseY = ev.screenY;
154
+    ev.stopPropagation();
155
+  };
156
+
157
+  private gripMouseUp = (ev: MouseEvent) => {
158
+    this.isResizing = false;
159
+    this.activeGrip = null;
160
+    ev.stopPropagation();
161
+  };
162
+
163
+  private gripMouseMove = (ev: MouseEvent) => {
164
+    if (this.isResizing) {
165
+      this.resize(ev.movementX, ev.movementY);
166
+    }
167
+  };
168
+}

+ 26
- 0
src/markers/RectMarker/RectBaseMarker.ts View File

@@ -0,0 +1,26 @@
1
+import { PositionType } from '../../event/Event';
2
+import { SvgHelper } from '../../renderer/SvgHelper';
3
+import { RectangularMarker } from '../RectangularMarker';
4
+
5
+export class RectBaseMarker extends RectangularMarker {
6
+  public static createMarker = (): RectBaseMarker => {
7
+    const marker = new RectBaseMarker();
8
+    marker.setup();
9
+    return marker;
10
+  };
11
+
12
+  private markerRect: SVGRectElement;
13
+
14
+  protected setup() {
15
+    super.setup();
16
+
17
+    this.markerRect = SvgHelper.createRect(this.width, this.height);
18
+    this.addToRenderVisual(this.markerRect);
19
+  }
20
+
21
+  protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void) {
22
+    super.resize(x, y, onPosition);
23
+    this.markerRect.setAttribute('width', this.width.toString());
24
+    this.markerRect.setAttribute('height', this.height.toString());
25
+  }
26
+}

+ 18
- 0
src/markers/RectMarker/index.ts View File

@@ -0,0 +1,18 @@
1
+import { MarkerType } from './../types';
2
+import { RectBaseMarker } from './RectBaseMarker';
3
+import { SvgHelper } from 'fc-whiteboard/src/renderer/SvgHelper';
4
+
5
+export class RectMarker extends RectBaseMarker {
6
+  type: MarkerType = 'rect';
7
+
8
+  public static createMarker = (): RectBaseMarker => {
9
+    const marker = new RectMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  protected setup() {
15
+    super.setup();
16
+    SvgHelper.setAttributes(this.visual, [['class', 'rect-marker']]);
17
+  }
18
+}

+ 35
- 0
src/markers/RectangularMarker/RectangularMarkerGrips.ts View File

@@ -0,0 +1,35 @@
1
+import { ResizeGrip } from '../BaseMarker/ResizeGrip';
2
+
3
+export class RectangularMarkerGrips {
4
+  public topLeft: ResizeGrip;
5
+  public topCenter: ResizeGrip;
6
+  public topRight: ResizeGrip;
7
+  public centerLeft: ResizeGrip;
8
+  public centerRight: ResizeGrip;
9
+  public bottomLeft: ResizeGrip;
10
+  public bottomCenter: ResizeGrip;
11
+  public bottomRight: ResizeGrip;
12
+
13
+  public findGripByVisual = (gripVisual: SVGGraphicsElement) => {
14
+    switch (gripVisual) {
15
+      case this.topLeft.visual:
16
+        return this.topLeft;
17
+      case this.topCenter.visual:
18
+        return this.topCenter;
19
+      case this.topRight.visual:
20
+        return this.topRight;
21
+      case this.centerLeft.visual:
22
+        return this.centerLeft;
23
+      case this.centerRight.visual:
24
+        return this.centerRight;
25
+      case this.bottomLeft.visual:
26
+        return this.bottomLeft;
27
+      case this.bottomCenter.visual:
28
+        return this.bottomCenter;
29
+      case this.bottomRight.visual:
30
+        return this.bottomRight;
31
+      default:
32
+        return this.topLeft;
33
+    }
34
+  };
35
+}

+ 246
- 0
src/markers/RectangularMarker/index.ts View File

@@ -0,0 +1,246 @@
1
+import { SvgHelper } from '../../renderer/SvgHelper';
2
+import { BaseMarker } from '../BaseMarker';
3
+import { RectangularMarkerGrips } from './RectangularMarkerGrips';
4
+import { ResizeGrip } from '../BaseMarker/ResizeGrip';
5
+import { PositionType } from 'fc-whiteboard/src/event/Event';
6
+
7
+export class RectangularMarker extends BaseMarker {
8
+  public static createMarker = (): RectangularMarker => {
9
+    const marker = new RectangularMarker();
10
+    marker.setup();
11
+    return marker;
12
+  };
13
+
14
+  protected MIN_SIZE = 5;
15
+
16
+  private controlBox: SVGGElement;
17
+  private readonly CB_DISTANCE: number = 10;
18
+  private controlRect: SVGRectElement;
19
+
20
+  private controlGrips: RectangularMarkerGrips;
21
+  private activeGrip: ResizeGrip | null;
22
+
23
+  public endManipulation() {
24
+    super.endManipulation();
25
+    this.isResizing = false;
26
+    this.activeGrip = null;
27
+  }
28
+
29
+  public select() {
30
+    super.select();
31
+    this.controlBox.style.display = '';
32
+  }
33
+
34
+  public deselect() {
35
+    super.deselect();
36
+    this.controlBox.style.display = 'none';
37
+  }
38
+
39
+  protected setup() {
40
+    super.setup();
41
+
42
+    this.addControlBox();
43
+  }
44
+
45
+  protected resizeByEvent(x: number, y: number, pos: PositionType) {
46
+    this.activeGrip = this.controlGrips[pos];
47
+    this.resize(x, y);
48
+  }
49
+
50
+  protected resize(x: number, y: number, onPosition?: (pos: PositionType) => void) {
51
+    let translateX = 0;
52
+    let translateY = 0;
53
+
54
+    switch (this.activeGrip) {
55
+      case this.controlGrips.topLeft:
56
+        this.width -= x;
57
+        this.height -= y;
58
+        translateX += x;
59
+        translateY += y;
60
+        if (onPosition) {
61
+          onPosition('topLeft');
62
+        }
63
+        break;
64
+      case this.controlGrips.bottomLeft:
65
+        this.width -= x;
66
+        this.height += y;
67
+        translateX += x;
68
+        if (onPosition) {
69
+          onPosition('bottomLeft');
70
+        }
71
+        break;
72
+      case this.controlGrips.topRight:
73
+        this.width += x;
74
+        this.height -= y;
75
+        translateY += y;
76
+        if (onPosition) {
77
+          onPosition('topRight');
78
+        }
79
+        break;
80
+      case this.controlGrips.bottomRight:
81
+        this.width += x;
82
+        this.height += y;
83
+        if (onPosition) {
84
+          onPosition('bottomRight');
85
+        }
86
+        break;
87
+      case this.controlGrips.centerLeft:
88
+        this.width -= x;
89
+        translateX += x;
90
+        if (onPosition) {
91
+          onPosition('centerLeft');
92
+        }
93
+        break;
94
+      case this.controlGrips.centerRight:
95
+        this.width += x;
96
+        if (onPosition) {
97
+          onPosition('centerRight');
98
+        }
99
+        break;
100
+      case this.controlGrips.topCenter:
101
+        this.height -= y;
102
+        translateY += y;
103
+        if (onPosition) {
104
+          onPosition('topCenter');
105
+        }
106
+        break;
107
+      case this.controlGrips.bottomCenter:
108
+        this.height += y;
109
+        if (onPosition) {
110
+          onPosition('bottomCenter');
111
+        }
112
+        break;
113
+      default:
114
+        break;
115
+    }
116
+
117
+    if (this.width < this.MIN_SIZE) {
118
+      const offset = this.MIN_SIZE - this.width;
119
+      this.width = this.MIN_SIZE;
120
+      if (translateX !== 0) {
121
+        translateX -= offset;
122
+      }
123
+    }
124
+    if (this.height < this.MIN_SIZE) {
125
+      const offset = this.MIN_SIZE - this.height;
126
+      this.height = this.MIN_SIZE;
127
+      if (translateY !== 0) {
128
+        translateY -= offset;
129
+      }
130
+    }
131
+
132
+    if (translateX !== 0 || translateY !== 0) {
133
+      const translate = this.visual.transform.baseVal.getItem(0);
134
+      translate.setMatrix(translate.matrix.translate(translateX, translateY));
135
+      this.visual.transform.baseVal.replaceItem(translate, 0);
136
+    }
137
+
138
+    this.adjustControlBox();
139
+  }
140
+
141
+  protected onTouch(ev: TouchEvent) {
142
+    super.onTouch(ev);
143
+  }
144
+
145
+  private addControlBox = () => {
146
+    this.controlBox = SvgHelper.createGroup([['class', 'fc-whiteboard-rect-control-box']]);
147
+    const translate = SvgHelper.createTransform();
148
+    translate.setTranslate(-this.CB_DISTANCE / 2, -this.CB_DISTANCE / 2);
149
+    this.controlBox.transform.baseVal.appendItem(translate);
150
+
151
+    this.addToVisual(this.controlBox);
152
+
153
+    this.controlRect = SvgHelper.createRect(
154
+      this.width + this.CB_DISTANCE,
155
+      this.height + this.CB_DISTANCE,
156
+      [['class', 'fc-whiteboard-rect-control-rect']]
157
+    );
158
+
159
+    this.controlBox.appendChild(this.controlRect);
160
+
161
+    this.controlGrips = new RectangularMarkerGrips();
162
+    this.addControlGrips();
163
+  };
164
+
165
+  private adjustControlBox = () => {
166
+    this.controlRect.setAttribute('width', (this.width + this.CB_DISTANCE).toString());
167
+    this.controlRect.setAttribute('height', (this.height + this.CB_DISTANCE).toString());
168
+
169
+    this.positionGrips();
170
+  };
171
+
172
+  private addControlGrips = () => {
173
+    this.controlGrips.topLeft = this.createGrip();
174
+    this.controlGrips.topCenter = this.createGrip();
175
+    this.controlGrips.topRight = this.createGrip();
176
+    this.controlGrips.centerLeft = this.createGrip();
177
+    this.controlGrips.centerRight = this.createGrip();
178
+    this.controlGrips.bottomLeft = this.createGrip();
179
+    this.controlGrips.bottomCenter = this.createGrip();
180
+    this.controlGrips.bottomRight = this.createGrip();
181
+
182
+    this.positionGrips();
183
+  };
184
+
185
+  private createGrip = (): ResizeGrip => {
186
+    const grip = new ResizeGrip();
187
+    grip.visual.transform.baseVal.appendItem(SvgHelper.createTransform());
188
+    this.controlBox.appendChild(grip.visual);
189
+
190
+    grip.visual.addEventListener('mousedown', this.gripMouseDown);
191
+    grip.visual.addEventListener('mousemove', this.gripMouseMove);
192
+    grip.visual.addEventListener('mouseup', this.gripMouseUp);
193
+
194
+    grip.visual.addEventListener('touchstart', this.onTouch, { passive: false });
195
+    grip.visual.addEventListener('touchend', this.onTouch, { passive: false });
196
+    grip.visual.addEventListener('touchmove', this.onTouch, { passive: false });
197
+
198
+    return grip;
199
+  };
200
+
201
+  private positionGrips = () => {
202
+    const gripSize = this.controlGrips.topLeft.GRIP_SIZE;
203
+
204
+    const left = -gripSize / 2;
205
+    const top = left;
206
+    const cx = (this.width + this.CB_DISTANCE) / 2 - gripSize / 2;
207
+    const cy = (this.height + this.CB_DISTANCE) / 2 - gripSize / 2;
208
+    const bottom = this.height + this.CB_DISTANCE - gripSize / 2;
209
+    const right = this.width + this.CB_DISTANCE - gripSize / 2;
210
+
211
+    this.positionGrip(this.controlGrips.topLeft.visual, left, top);
212
+    this.positionGrip(this.controlGrips.topCenter.visual, cx, top);
213
+    this.positionGrip(this.controlGrips.topRight.visual, right, top);
214
+    this.positionGrip(this.controlGrips.centerLeft.visual, left, cy);
215
+    this.positionGrip(this.controlGrips.centerRight.visual, right, cy);
216
+    this.positionGrip(this.controlGrips.bottomLeft.visual, left, bottom);
217
+    this.positionGrip(this.controlGrips.bottomCenter.visual, cx, bottom);
218
+    this.positionGrip(this.controlGrips.bottomRight.visual, right, bottom);
219
+  };
220
+
221
+  private positionGrip = (grip: SVGGraphicsElement, x: number, y: number) => {
222
+    const translate = grip.transform.baseVal.getItem(0);
223
+    translate.setTranslate(x, y);
224
+    grip.transform.baseVal.replaceItem(translate, 0);
225
+  };
226
+
227
+  private gripMouseDown = (ev: MouseEvent) => {
228
+    this.isResizing = true;
229
+    this.activeGrip = this.controlGrips.findGripByVisual(ev.target as SVGGraphicsElement) || null;
230
+    this.previousMouseX = ev.screenX;
231
+    this.previousMouseY = ev.screenY;
232
+    ev.stopPropagation();
233
+  };
234
+
235
+  private gripMouseUp = (ev: MouseEvent) => {
236
+    this.isResizing = false;
237
+    this.activeGrip = null;
238
+    ev.stopPropagation();
239
+  };
240
+
241
+  private gripMouseMove = (ev: MouseEvent) => {
242
+    if (this.isResizing) {
243
+      this.manipulate(ev);
244
+    }
245
+  };
246
+}

+ 151
- 0
src/markers/TextMarker/index.ts View File

@@ -0,0 +1,151 @@
1
+import { MarkerType } from '../types';
2
+import { RectangularMarker } from '../RectangularMarker';
3
+import { SvgHelper } from '../../renderer/SvgHelper';
4
+
5
+const OkIcon = require('../../assets/check.svg');
6
+const CancelIcon = require('../../assets/times.svg');
7
+
8
+export class TextMarker extends RectangularMarker {
9
+  type: MarkerType = 'text';
10
+
11
+  public static createMarker = (): TextMarker => {
12
+    const marker = new TextMarker();
13
+    marker.setup();
14
+    return marker;
15
+  };
16
+
17
+  protected readonly MIN_SIZE = 50;
18
+
19
+  private readonly DEFAULT_TEXT = 'Double-click to edit text';
20
+  private text: string = this.DEFAULT_TEXT;
21
+  private textElement: SVGTextElement;
22
+
23
+  private inDoubleTap = false;
24
+
25
+  private editor: HTMLDivElement;
26
+
27
+  private editorTextArea: HTMLTextAreaElement;
28
+
29
+  protected setup() {
30
+    super.setup();
31
+    this.textElement = SvgHelper.createText();
32
+    this.addToRenderVisual(this.textElement);
33
+    SvgHelper.setAttributes(this.visual, [['class', 'text-marker']]);
34
+
35
+    this.textElement.transform.baseVal.appendItem(SvgHelper.createTransform()); // translate transorm
36
+    this.textElement.transform.baseVal.appendItem(SvgHelper.createTransform()); // scale transorm
37
+
38
+    this.renderText();
39
+
40
+    this.visual.addEventListener('dblclick', this.onDblClick);
41
+    this.visual.addEventListener('touchstart', this.onTap);
42
+  }
43
+
44
+  protected resize(x: number, y: number) {
45
+    super.resize(x, y);
46
+    this.sizeText();
47
+  }
48
+
49
+  private renderText = () => {
50
+    const LINE_SIZE = '1.2em';
51
+
52
+    while (this.textElement.lastChild) {
53
+      this.textElement.removeChild(this.textElement.lastChild);
54
+    }
55
+
56
+    const lines = this.text.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/);
57
+    for (let line of lines) {
58
+      if (line.trim() === '') {
59
+        line = ' '; // workaround for swallowed empty lines
60
+      }
61
+      this.textElement.appendChild(SvgHelper.createTSpan(line, [['x', '0'], ['dy', LINE_SIZE]]));
62
+    }
63
+
64
+    setTimeout(this.sizeText, 10);
65
+  };
66
+
67
+  private sizeText = () => {
68
+    const textSize = this.textElement.getBBox();
69
+    let x = 0;
70
+    let y = 0;
71
+    let scale = 1.0;
72
+    if (textSize.width > 0 && textSize.height > 0) {
73
+      const xScale = (this.width * 1.0) / textSize.width;
74
+      const yScale = (this.height * 1.0) / textSize.height;
75
+      scale = Math.min(xScale, yScale);
76
+
77
+      x = (this.width - textSize.width * scale) / 2;
78
+      y = (this.height - textSize.height * scale) / 2;
79
+    }
80
+
81
+    this.textElement.transform.baseVal.getItem(0).setTranslate(x, y);
82
+    this.textElement.transform.baseVal.getItem(1).setScale(scale, scale);
83
+  };
84
+
85
+  private onDblClick = (ev: MouseEvent) => {
86
+    this.showEditor();
87
+  };
88
+
89
+  private onTap = (ev: TouchEvent) => {
90
+    if (this.inDoubleTap) {
91
+      this.inDoubleTap = false;
92
+      this.showEditor();
93
+    } else {
94
+      this.inDoubleTap = true;
95
+      setTimeout(() => {
96
+        this.inDoubleTap = false;
97
+      }, 300);
98
+    }
99
+  };
100
+
101
+  private showEditor = () => {
102
+    this.editor = document.createElement('div');
103
+    this.editor.className = 'fc-whiteboard-text-editor';
104
+
105
+    this.editorTextArea = document.createElement('textarea');
106
+    if (this.text !== this.DEFAULT_TEXT) {
107
+      this.editorTextArea.value = this.text;
108
+    }
109
+    this.editorTextArea.addEventListener('keydown', this.onEditorKeyDown);
110
+    this.editor.appendChild(this.editorTextArea);
111
+
112
+    document.body.appendChild(this.editor);
113
+
114
+    const buttons = document.createElement('div');
115
+    buttons.className = 'fc-whiteboard-text-editor-button-bar';
116
+    this.editor.appendChild(buttons);
117
+
118
+    const okButton = document.createElement('div');
119
+    okButton.className = 'fc-whiteboard-text-editor-button';
120
+    okButton.innerHTML = OkIcon;
121
+    okButton.addEventListener('click', this.onEditorOkClick);
122
+    buttons.appendChild(okButton);
123
+
124
+    const cancelButton = document.createElement('div');
125
+    cancelButton.className = 'fc-whiteboard-text-editor-button';
126
+    cancelButton.innerHTML = CancelIcon;
127
+    cancelButton.addEventListener('click', this.closeEditor);
128
+    buttons.appendChild(cancelButton);
129
+  };
130
+
131
+  private onEditorOkClick = (ev: MouseEvent | null) => {
132
+    if (this.editorTextArea.value.trim()) {
133
+      this.text = this.editorTextArea.value;
134
+    } else {
135
+      this.text = this.DEFAULT_TEXT;
136
+    }
137
+    this.renderText();
138
+    this.closeEditor();
139
+  };
140
+
141
+  private closeEditor = () => {
142
+    document.body.removeChild(this.editor);
143
+  };
144
+
145
+  private onEditorKeyDown = (ev: KeyboardEvent) => {
146
+    if (ev.key === 'Enter' && ev.ctrlKey) {
147
+      ev.preventDefault();
148
+      this.onEditorOkClick(null);
149
+    }
150
+  };
151
+}

+ 27
- 0
src/markers/types.ts View File

@@ -0,0 +1,27 @@
1
+import { TextMarker } from './TextMarker/index';
2
+import { ArrowMarker } from './ArrowMarker/index';
3
+import { BaseMarker } from './BaseMarker/index';
4
+import { CoverMarker } from './CoverMarker';
5
+import { LineMarker } from './LineMarker';
6
+import { RectMarker } from './RectMarker';
7
+
8
+export type MarkerType = 'base' | 'arrow' | 'cover' | 'line' | 'rect' | 'text' | 'highlight';
9
+
10
+export function getMarkerByType(type: MarkerType): typeof BaseMarker {
11
+  switch (type) {
12
+    case 'base':
13
+      return BaseMarker;
14
+    case 'arrow':
15
+      return ArrowMarker;
16
+    case 'cover':
17
+      return CoverMarker;
18
+    case 'line':
19
+      return LineMarker;
20
+    case 'rect':
21
+      return RectMarker;
22
+    case 'text':
23
+      return TextMarker;
24
+    default:
25
+      return BaseMarker;
26
+  }
27
+}

+ 143
- 0
src/renderer/SvgHelper/index.ts View File

@@ -0,0 +1,143 @@
1
+export class SvgHelper {
2
+  public static createRect = (
3
+    width: number | string,
4
+    height: number | string,
5
+    attributes?: Array<[string, string]>
6
+  ): SVGRectElement => {
7
+    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
8
+
9
+    rect.setAttribute('width', width.toString());
10
+    rect.setAttribute('height', height.toString());
11
+    if (attributes) {
12
+      SvgHelper.setAttributes(rect, attributes);
13
+    }
14
+
15
+    return rect;
16
+  };
17
+
18
+  public static createLine = (
19
+    x1: number | string,
20
+    y1: number | string,
21
+    x2: number | string,
22
+    y2: number | string,
23
+    attributes?: Array<[string, string]>
24
+  ): SVGLineElement => {
25
+    const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
26
+
27
+    line.setAttribute('x1', x1.toString());
28
+    line.setAttribute('y1', y1.toString());
29
+    line.setAttribute('x2', x2.toString());
30
+    line.setAttribute('y2', y2.toString());
31
+    if (attributes) {
32
+      SvgHelper.setAttributes(line, attributes);
33
+    }
34
+
35
+    return line;
36
+  };
37
+
38
+  public static createPolygon = (
39
+    points: string,
40
+    attributes?: Array<[string, string]>
41
+  ): SVGPolygonElement => {
42
+    const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
43
+
44
+    polygon.setAttribute('points', points);
45
+    if (attributes) {
46
+      SvgHelper.setAttributes(polygon, attributes);
47
+    }
48
+
49
+    return polygon;
50
+  };
51
+
52
+  public static createCircle = (
53
+    radius: number,
54
+    attributes?: Array<[string, string]>
55
+  ): SVGCircleElement => {
56
+    const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
57
+
58
+    circle.setAttribute('cx', (radius / 2).toString());
59
+    circle.setAttribute('cy', (radius / 2).toString());
60
+    circle.setAttribute('r', radius.toString());
61
+    if (attributes) {
62
+      SvgHelper.setAttributes(circle, attributes);
63
+    }
64
+
65
+    return circle;
66
+  };
67
+
68
+  public static createGroup = (attributes?: Array<[string, string]>): SVGGElement => {
69
+    const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
70
+    if (attributes) {
71
+      SvgHelper.setAttributes(g, attributes);
72
+    }
73
+    return g;
74
+  };
75
+
76
+  public static setAttributes = (el: SVGElement, attributes: Array<[string, string]>) => {
77
+    for (const [attr, value] of attributes) {
78
+      el.setAttribute(attr, value);
79
+    }
80
+  };
81
+
82
+  public static createTransform = (): SVGTransform => {
83
+    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
84
+
85
+    return svg.createSVGTransform();
86
+  };
87
+
88
+  public static createDefs = (): SVGDefsElement => {
89
+    const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
90
+
91
+    return defs;
92
+  };
93
+
94
+  public static createMarker = (
95
+    id: string,
96
+    orient: string,
97
+    markerWidth: number | string,
98
+    markerHeight: number | string,
99
+    refX: number | string,
100
+    refY: number | string,
101
+    markerElement: SVGGraphicsElement
102
+  ): SVGMarkerElement => {
103
+    const marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
104
+    SvgHelper.setAttributes(marker, [
105
+      ['id', id],
106
+      ['orient', orient],
107
+      ['markerWidth', markerWidth.toString()],
108
+      ['markerHeight', markerHeight.toString()],
109
+      ['refX', refX.toString()],
110
+      ['refY', refY.toString()]
111
+    ]);
112
+
113
+    marker.appendChild(markerElement);
114
+
115
+    return marker;
116
+  };
117
+
118
+  public static createText = (attributes?: Array<[string, string]>): SVGTextElement => {
119
+    const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
120
+    text.setAttribute('x', '0');
121
+    text.setAttribute('y', '0');
122
+
123
+    if (attributes) {
124
+      SvgHelper.setAttributes(text, attributes);
125
+    }
126
+
127
+    return text;
128
+  };
129
+
130
+  public static createTSpan = (
131
+    text: string,
132
+    attributes?: Array<[string, string]>
133
+  ): SVGTSpanElement => {
134
+    const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
135
+    tspan.textContent = text;
136
+
137
+    if (attributes) {
138
+      SvgHelper.setAttributes(tspan, attributes);
139
+    }
140
+
141
+    return tspan;
142
+  };
143
+}

+ 0
- 0
src/renderer/Synthetizer/index.ts View File


Some files were not shown because too many files changed in this diff