@nasser-sw/fabric 7.0.1-beta8 → 7.0.1-beta9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug/konva-master/CHANGELOG.md +1475 -0
- package/debug/konva-master/LICENSE +22 -0
- package/debug/konva-master/README.md +209 -0
- package/debug/konva-master/gulpfile.mjs +110 -0
- package/debug/konva-master/package.json +139 -0
- package/debug/konva-master/release.sh +62 -0
- package/debug/konva-master/resources/doc-includes/ContainerParams.txt +6 -0
- package/debug/konva-master/resources/doc-includes/NodeParams.txt +20 -0
- package/debug/konva-master/resources/doc-includes/ShapeParams.txt +53 -0
- package/debug/konva-master/resources/jsdoc.conf.json +28 -0
- package/debug/konva-master/rollup.config.mjs +32 -0
- package/debug/konva-master/src/Animation.ts +237 -0
- package/debug/konva-master/src/BezierFunctions.ts +826 -0
- package/debug/konva-master/src/Canvas.ts +230 -0
- package/debug/konva-master/src/Container.ts +649 -0
- package/debug/konva-master/src/Context.ts +1017 -0
- package/debug/konva-master/src/Core.ts +5 -0
- package/debug/konva-master/src/DragAndDrop.ts +173 -0
- package/debug/konva-master/src/Factory.ts +246 -0
- package/debug/konva-master/src/FastLayer.ts +29 -0
- package/debug/konva-master/src/Global.ts +210 -0
- package/debug/konva-master/src/Group.ts +31 -0
- package/debug/konva-master/src/Layer.ts +546 -0
- package/debug/konva-master/src/Node.ts +3477 -0
- package/debug/konva-master/src/PointerEvents.ts +67 -0
- package/debug/konva-master/src/Shape.ts +2081 -0
- package/debug/konva-master/src/Stage.ts +1000 -0
- package/debug/konva-master/src/Tween.ts +811 -0
- package/debug/konva-master/src/Util.ts +1123 -0
- package/debug/konva-master/src/Validators.ts +210 -0
- package/debug/konva-master/src/_CoreInternals.ts +85 -0
- package/debug/konva-master/src/_FullInternals.ts +171 -0
- package/debug/konva-master/src/canvas-backend.ts +36 -0
- package/debug/konva-master/src/filters/Blur.ts +388 -0
- package/debug/konva-master/src/filters/Brighten.ts +48 -0
- package/debug/konva-master/src/filters/Brightness.ts +30 -0
- package/debug/konva-master/src/filters/Contrast.ts +75 -0
- package/debug/konva-master/src/filters/Emboss.ts +207 -0
- package/debug/konva-master/src/filters/Enhance.ts +154 -0
- package/debug/konva-master/src/filters/Grayscale.ts +25 -0
- package/debug/konva-master/src/filters/HSL.ts +108 -0
- package/debug/konva-master/src/filters/HSV.ts +106 -0
- package/debug/konva-master/src/filters/Invert.ts +23 -0
- package/debug/konva-master/src/filters/Kaleidoscope.ts +274 -0
- package/debug/konva-master/src/filters/Mask.ts +220 -0
- package/debug/konva-master/src/filters/Noise.ts +44 -0
- package/debug/konva-master/src/filters/Pixelate.ts +107 -0
- package/debug/konva-master/src/filters/Posterize.ts +46 -0
- package/debug/konva-master/src/filters/RGB.ts +82 -0
- package/debug/konva-master/src/filters/RGBA.ts +103 -0
- package/debug/konva-master/src/filters/Sepia.ts +27 -0
- package/debug/konva-master/src/filters/Solarize.ts +29 -0
- package/debug/konva-master/src/filters/Threshold.ts +44 -0
- package/debug/konva-master/src/index.ts +3 -0
- package/debug/konva-master/src/shapes/Arc.ts +176 -0
- package/debug/konva-master/src/shapes/Arrow.ts +231 -0
- package/debug/konva-master/src/shapes/Circle.ts +76 -0
- package/debug/konva-master/src/shapes/Ellipse.ts +121 -0
- package/debug/konva-master/src/shapes/Image.ts +319 -0
- package/debug/konva-master/src/shapes/Label.ts +386 -0
- package/debug/konva-master/src/shapes/Line.ts +364 -0
- package/debug/konva-master/src/shapes/Path.ts +1013 -0
- package/debug/konva-master/src/shapes/Rect.ts +79 -0
- package/debug/konva-master/src/shapes/RegularPolygon.ts +167 -0
- package/debug/konva-master/src/shapes/Ring.ts +94 -0
- package/debug/konva-master/src/shapes/Sprite.ts +370 -0
- package/debug/konva-master/src/shapes/Star.ts +125 -0
- package/debug/konva-master/src/shapes/Text.ts +1065 -0
- package/debug/konva-master/src/shapes/TextPath.ts +583 -0
- package/debug/konva-master/src/shapes/Transformer.ts +1889 -0
- package/debug/konva-master/src/shapes/Wedge.ts +129 -0
- package/debug/konva-master/src/skia-backend.ts +35 -0
- package/debug/konva-master/src/types.ts +84 -0
- package/debug/konva-master/tsconfig.json +31 -0
- package/debug/konva-master/tsconfig.test.json +7 -0
- package/dist/index.js +915 -23
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +915 -23
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +915 -23
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +915 -23
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/shapes/Text/Text.d.ts +19 -0
- package/dist/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist/src/shapes/Text/Text.min.mjs +1 -1
- package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.mjs +238 -4
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts +38 -1
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs +497 -15
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
- package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
- package/dist/src/text/measure.d.ts +9 -0
- package/dist/src/text/measure.d.ts.map +1 -1
- package/dist/src/text/measure.min.mjs +1 -1
- package/dist/src/text/measure.min.mjs.map +1 -1
- package/dist/src/text/measure.mjs +175 -4
- package/dist/src/text/measure.mjs.map +1 -1
- package/dist/src/text/overlayEditor.d.ts.map +1 -1
- package/dist/src/text/overlayEditor.min.mjs +1 -1
- package/dist/src/text/overlayEditor.min.mjs.map +1 -1
- package/dist/src/text/overlayEditor.mjs +7 -0
- package/dist/src/text/overlayEditor.mjs.map +1 -1
- package/dist/src/text/scriptUtils.d.ts +142 -0
- package/dist/src/text/scriptUtils.d.ts.map +1 -0
- package/dist/src/text/scriptUtils.min.mjs +2 -0
- package/dist/src/text/scriptUtils.min.mjs.map +1 -0
- package/dist/src/text/scriptUtils.mjs +212 -0
- package/dist/src/text/scriptUtils.mjs.map +1 -0
- package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts +38 -1
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/text/measure.d.ts +9 -0
- package/dist-extensions/src/text/measure.d.ts.map +1 -1
- package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
- package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
- package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
- package/fabric-test-editor.html +2401 -46
- package/fonts/STV Bold.ttf +0 -0
- package/fonts/STV Light.ttf +0 -0
- package/fonts/STV Regular.ttf +0 -0
- package/package.json +1 -1
- package/src/shapes/Text/Text.ts +238 -5
- package/src/shapes/Textbox.ts +521 -11
- package/src/text/measure.ts +200 -50
- package/src/text/overlayEditor.ts +7 -0
|
@@ -0,0 +1,1000 @@
|
|
|
1
|
+
import { Util } from './Util.ts';
|
|
2
|
+
import { Factory } from './Factory.ts';
|
|
3
|
+
import type { ContainerConfig } from './Container.ts';
|
|
4
|
+
import { Container } from './Container.ts';
|
|
5
|
+
import { Konva } from './Global.ts';
|
|
6
|
+
import { SceneCanvas, HitCanvas } from './Canvas.ts';
|
|
7
|
+
import type { GetSet, Vector2d } from './types.ts';
|
|
8
|
+
import type { Shape } from './Shape.ts';
|
|
9
|
+
import type { Layer } from './Layer.ts';
|
|
10
|
+
import { DD } from './DragAndDrop.ts';
|
|
11
|
+
import { _registerNode } from './Global.ts';
|
|
12
|
+
import * as PointerEvents from './PointerEvents.ts';
|
|
13
|
+
|
|
14
|
+
export interface StageConfig extends ContainerConfig {
|
|
15
|
+
container?: HTMLDivElement | string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// CONSTANTS
|
|
19
|
+
const STAGE = 'Stage',
|
|
20
|
+
STRING = 'string',
|
|
21
|
+
PX = 'px',
|
|
22
|
+
MOUSEOUT = 'mouseout',
|
|
23
|
+
MOUSELEAVE = 'mouseleave',
|
|
24
|
+
MOUSEOVER = 'mouseover',
|
|
25
|
+
MOUSEENTER = 'mouseenter',
|
|
26
|
+
MOUSEMOVE = 'mousemove',
|
|
27
|
+
MOUSEDOWN = 'mousedown',
|
|
28
|
+
MOUSEUP = 'mouseup',
|
|
29
|
+
POINTERMOVE = 'pointermove',
|
|
30
|
+
POINTERDOWN = 'pointerdown',
|
|
31
|
+
POINTERUP = 'pointerup',
|
|
32
|
+
POINTERCANCEL = 'pointercancel',
|
|
33
|
+
LOSTPOINTERCAPTURE = 'lostpointercapture',
|
|
34
|
+
POINTEROUT = 'pointerout',
|
|
35
|
+
POINTERLEAVE = 'pointerleave',
|
|
36
|
+
POINTEROVER = 'pointerover',
|
|
37
|
+
POINTERENTER = 'pointerenter',
|
|
38
|
+
CONTEXTMENU = 'contextmenu',
|
|
39
|
+
TOUCHSTART = 'touchstart',
|
|
40
|
+
TOUCHEND = 'touchend',
|
|
41
|
+
TOUCHMOVE = 'touchmove',
|
|
42
|
+
TOUCHCANCEL = 'touchcancel',
|
|
43
|
+
WHEEL = 'wheel',
|
|
44
|
+
MAX_LAYERS_NUMBER = 5,
|
|
45
|
+
EVENTS = [
|
|
46
|
+
[MOUSEENTER, '_pointerenter'],
|
|
47
|
+
[MOUSEDOWN, '_pointerdown'],
|
|
48
|
+
[MOUSEMOVE, '_pointermove'],
|
|
49
|
+
[MOUSEUP, '_pointerup'],
|
|
50
|
+
[MOUSELEAVE, '_pointerleave'],
|
|
51
|
+
[TOUCHSTART, '_pointerdown'],
|
|
52
|
+
[TOUCHMOVE, '_pointermove'],
|
|
53
|
+
[TOUCHEND, '_pointerup'],
|
|
54
|
+
[TOUCHCANCEL, '_pointercancel'],
|
|
55
|
+
[MOUSEOVER, '_pointerover'],
|
|
56
|
+
[WHEEL, '_wheel'],
|
|
57
|
+
[CONTEXTMENU, '_contextmenu'],
|
|
58
|
+
[POINTERDOWN, '_pointerdown'],
|
|
59
|
+
[POINTERMOVE, '_pointermove'],
|
|
60
|
+
[POINTERUP, '_pointerup'],
|
|
61
|
+
[POINTERCANCEL, '_pointercancel'],
|
|
62
|
+
[POINTERLEAVE, '_pointerleave'],
|
|
63
|
+
[LOSTPOINTERCAPTURE, '_lostpointercapture'],
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
const EVENTS_MAP = {
|
|
67
|
+
mouse: {
|
|
68
|
+
[POINTEROUT]: MOUSEOUT,
|
|
69
|
+
[POINTERLEAVE]: MOUSELEAVE,
|
|
70
|
+
[POINTEROVER]: MOUSEOVER,
|
|
71
|
+
[POINTERENTER]: MOUSEENTER,
|
|
72
|
+
[POINTERMOVE]: MOUSEMOVE,
|
|
73
|
+
[POINTERDOWN]: MOUSEDOWN,
|
|
74
|
+
[POINTERUP]: MOUSEUP,
|
|
75
|
+
[POINTERCANCEL]: 'mousecancel',
|
|
76
|
+
pointerclick: 'click',
|
|
77
|
+
pointerdblclick: 'dblclick',
|
|
78
|
+
},
|
|
79
|
+
touch: {
|
|
80
|
+
[POINTEROUT]: 'touchout',
|
|
81
|
+
[POINTERLEAVE]: 'touchleave',
|
|
82
|
+
[POINTEROVER]: 'touchover',
|
|
83
|
+
[POINTERENTER]: 'touchenter',
|
|
84
|
+
[POINTERMOVE]: TOUCHMOVE,
|
|
85
|
+
[POINTERDOWN]: TOUCHSTART,
|
|
86
|
+
[POINTERUP]: TOUCHEND,
|
|
87
|
+
[POINTERCANCEL]: TOUCHCANCEL,
|
|
88
|
+
pointerclick: 'tap',
|
|
89
|
+
pointerdblclick: 'dbltap',
|
|
90
|
+
},
|
|
91
|
+
pointer: {
|
|
92
|
+
[POINTEROUT]: POINTEROUT,
|
|
93
|
+
[POINTERLEAVE]: POINTERLEAVE,
|
|
94
|
+
[POINTEROVER]: POINTEROVER,
|
|
95
|
+
[POINTERENTER]: POINTERENTER,
|
|
96
|
+
[POINTERMOVE]: POINTERMOVE,
|
|
97
|
+
[POINTERDOWN]: POINTERDOWN,
|
|
98
|
+
[POINTERUP]: POINTERUP,
|
|
99
|
+
[POINTERCANCEL]: POINTERCANCEL,
|
|
100
|
+
pointerclick: 'pointerclick',
|
|
101
|
+
pointerdblclick: 'pointerdblclick',
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const getEventType = (type) => {
|
|
106
|
+
if (type.indexOf('pointer') >= 0) {
|
|
107
|
+
return 'pointer';
|
|
108
|
+
}
|
|
109
|
+
if (type.indexOf('touch') >= 0) {
|
|
110
|
+
return 'touch';
|
|
111
|
+
}
|
|
112
|
+
return 'mouse';
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const getEventsMap = (eventType: string) => {
|
|
116
|
+
const type = getEventType(eventType);
|
|
117
|
+
if (type === 'pointer') {
|
|
118
|
+
return Konva.pointerEventsEnabled && EVENTS_MAP.pointer;
|
|
119
|
+
}
|
|
120
|
+
if (type === 'touch') {
|
|
121
|
+
return EVENTS_MAP.touch;
|
|
122
|
+
}
|
|
123
|
+
if (type === 'mouse') {
|
|
124
|
+
return EVENTS_MAP.mouse;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
function checkNoClip(attrs: any = {}) {
|
|
129
|
+
if (attrs.clipFunc || attrs.clipWidth || attrs.clipHeight) {
|
|
130
|
+
Util.warn(
|
|
131
|
+
'Stage does not support clipping. Please use clip for Layers or Groups.'
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return attrs;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const NO_POINTERS_MESSAGE = `Pointer position is missing and not registered by the stage. Looks like it is outside of the stage container. You can set it manually from event: stage.setPointersPositions(event);`;
|
|
138
|
+
|
|
139
|
+
export const stages: Stage[] = [];
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Stage constructor. A stage is used to contain multiple layers
|
|
143
|
+
* @constructor
|
|
144
|
+
* @memberof Konva
|
|
145
|
+
* @augments Konva.Container
|
|
146
|
+
* @param {Object} config
|
|
147
|
+
* @param {String|Element} config.container Container selector or DOM element
|
|
148
|
+
* @@nodeParams
|
|
149
|
+
* @example
|
|
150
|
+
* var stage = new Konva.Stage({
|
|
151
|
+
* width: 500,
|
|
152
|
+
* height: 800,
|
|
153
|
+
* container: 'containerId' // or "#containerId" or ".containerClass"
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
export class Stage extends Container<Layer> {
|
|
158
|
+
content: HTMLDivElement;
|
|
159
|
+
pointerPos: Vector2d | null;
|
|
160
|
+
_pointerPositions: (Vector2d & { id?: number })[] = [];
|
|
161
|
+
_changedPointerPositions: (Vector2d & { id: number })[] = [];
|
|
162
|
+
|
|
163
|
+
bufferCanvas: SceneCanvas;
|
|
164
|
+
bufferHitCanvas: HitCanvas;
|
|
165
|
+
_mouseTargetShape: Shape;
|
|
166
|
+
_touchTargetShape: Shape;
|
|
167
|
+
_pointerTargetShape: Shape;
|
|
168
|
+
_mouseClickStartShape: Shape;
|
|
169
|
+
_touchClickStartShape: Shape;
|
|
170
|
+
_pointerClickStartShape: Shape;
|
|
171
|
+
_mouseClickEndShape: Shape;
|
|
172
|
+
_touchClickEndShape: Shape;
|
|
173
|
+
_pointerClickEndShape: Shape;
|
|
174
|
+
|
|
175
|
+
_mouseDblTimeout: any;
|
|
176
|
+
_touchDblTimeout: any;
|
|
177
|
+
_pointerDblTimeout: any;
|
|
178
|
+
|
|
179
|
+
constructor(config: StageConfig) {
|
|
180
|
+
super(checkNoClip(config));
|
|
181
|
+
this._buildDOM();
|
|
182
|
+
this._bindContentEvents();
|
|
183
|
+
stages.push(this);
|
|
184
|
+
this.on('widthChange.konva heightChange.konva', this._resizeDOM);
|
|
185
|
+
this.on('visibleChange.konva', this._checkVisibility);
|
|
186
|
+
this.on(
|
|
187
|
+
'clipWidthChange.konva clipHeightChange.konva clipFuncChange.konva',
|
|
188
|
+
() => {
|
|
189
|
+
checkNoClip(this.attrs);
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
this._checkVisibility();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_validateAdd(child) {
|
|
196
|
+
const isLayer = child.getType() === 'Layer';
|
|
197
|
+
const isFastLayer = child.getType() === 'FastLayer';
|
|
198
|
+
const valid = isLayer || isFastLayer;
|
|
199
|
+
if (!valid) {
|
|
200
|
+
Util.throw('You may only add layers to the stage.');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
_checkVisibility() {
|
|
205
|
+
if (!this.content) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const style = this.visible() ? '' : 'none';
|
|
209
|
+
this.content.style.display = style;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* set container dom element which contains the stage wrapper div element
|
|
213
|
+
* @method
|
|
214
|
+
* @name Konva.Stage#setContainer
|
|
215
|
+
* @param {DomElement} container can pass in a dom element or id string
|
|
216
|
+
*/
|
|
217
|
+
setContainer(container) {
|
|
218
|
+
if (typeof container === STRING) {
|
|
219
|
+
let id;
|
|
220
|
+
if (container.charAt(0) === '.') {
|
|
221
|
+
const className = container.slice(1);
|
|
222
|
+
container = document.getElementsByClassName(className)[0];
|
|
223
|
+
} else {
|
|
224
|
+
if (container.charAt(0) !== '#') {
|
|
225
|
+
id = container;
|
|
226
|
+
} else {
|
|
227
|
+
id = container.slice(1);
|
|
228
|
+
}
|
|
229
|
+
container = document.getElementById(id);
|
|
230
|
+
}
|
|
231
|
+
if (!container) {
|
|
232
|
+
throw 'Can not find container in document with id ' + id;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
this._setAttr('container', container);
|
|
236
|
+
if (this.content) {
|
|
237
|
+
if (this.content.parentElement) {
|
|
238
|
+
this.content.parentElement.removeChild(this.content);
|
|
239
|
+
}
|
|
240
|
+
container.appendChild(this.content);
|
|
241
|
+
}
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
shouldDrawHit() {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* clear all layers
|
|
250
|
+
* @method
|
|
251
|
+
* @name Konva.Stage#clear
|
|
252
|
+
*/
|
|
253
|
+
clear() {
|
|
254
|
+
const layers = this.children,
|
|
255
|
+
len = layers.length;
|
|
256
|
+
|
|
257
|
+
for (let n = 0; n < len; n++) {
|
|
258
|
+
layers[n].clear();
|
|
259
|
+
}
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
clone(obj?) {
|
|
263
|
+
if (!obj) {
|
|
264
|
+
obj = {};
|
|
265
|
+
}
|
|
266
|
+
obj.container =
|
|
267
|
+
typeof document !== 'undefined' && document.createElement('div');
|
|
268
|
+
return Container.prototype.clone.call(this, obj) as this;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
destroy() {
|
|
272
|
+
super.destroy();
|
|
273
|
+
|
|
274
|
+
const content = this.content;
|
|
275
|
+
if (content && Util._isInDocument(content)) {
|
|
276
|
+
this.container().removeChild(content);
|
|
277
|
+
}
|
|
278
|
+
const index = stages.indexOf(this);
|
|
279
|
+
if (index > -1) {
|
|
280
|
+
stages.splice(index, 1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
Util.releaseCanvas(this.bufferCanvas._canvas, this.bufferHitCanvas._canvas);
|
|
284
|
+
|
|
285
|
+
return this;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* returns ABSOLUTE pointer position which can be a touch position or mouse position
|
|
289
|
+
* pointer position doesn't include any transforms (such as scale) of the stage
|
|
290
|
+
* it is just a plain position of pointer relative to top-left corner of the canvas
|
|
291
|
+
* @method
|
|
292
|
+
* @name Konva.Stage#getPointerPosition
|
|
293
|
+
* @returns {Vector2d|null}
|
|
294
|
+
*/
|
|
295
|
+
getPointerPosition(): Vector2d | null {
|
|
296
|
+
const pos = this._pointerPositions[0] || this._changedPointerPositions[0];
|
|
297
|
+
if (!pos) {
|
|
298
|
+
Util.warn(NO_POINTERS_MESSAGE);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
x: pos.x,
|
|
303
|
+
y: pos.y,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
_getPointerById(id?: number) {
|
|
307
|
+
return this._pointerPositions.find((p) => p.id === id);
|
|
308
|
+
}
|
|
309
|
+
getPointersPositions() {
|
|
310
|
+
return this._pointerPositions;
|
|
311
|
+
}
|
|
312
|
+
getStage() {
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
getContent() {
|
|
316
|
+
return this.content;
|
|
317
|
+
}
|
|
318
|
+
_toKonvaCanvas(config) {
|
|
319
|
+
config = config || {};
|
|
320
|
+
|
|
321
|
+
config.x = config.x || 0;
|
|
322
|
+
config.y = config.y || 0;
|
|
323
|
+
config.width = config.width || this.width();
|
|
324
|
+
config.height = config.height || this.height();
|
|
325
|
+
|
|
326
|
+
const canvas = new SceneCanvas({
|
|
327
|
+
width: config.width,
|
|
328
|
+
height: config.height,
|
|
329
|
+
pixelRatio: config.pixelRatio || 1,
|
|
330
|
+
});
|
|
331
|
+
const _context = canvas.getContext()._context;
|
|
332
|
+
const layers = this.children;
|
|
333
|
+
|
|
334
|
+
if (config.x || config.y) {
|
|
335
|
+
_context.translate(-1 * config.x, -1 * config.y);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
layers.forEach(function (layer) {
|
|
339
|
+
if (!layer.isVisible()) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const layerCanvas = layer._toKonvaCanvas(config);
|
|
343
|
+
_context.drawImage(
|
|
344
|
+
layerCanvas._canvas,
|
|
345
|
+
config.x,
|
|
346
|
+
config.y,
|
|
347
|
+
layerCanvas.getWidth() / layerCanvas.getPixelRatio(),
|
|
348
|
+
layerCanvas.getHeight() / layerCanvas.getPixelRatio()
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
return canvas;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* get visible intersection shape. This is the preferred
|
|
356
|
+
* method for determining if a point intersects a shape or not
|
|
357
|
+
* nodes with listening set to false will not be detected
|
|
358
|
+
* @method
|
|
359
|
+
* @name Konva.Stage#getIntersection
|
|
360
|
+
* @param {Object} pos
|
|
361
|
+
* @param {Number} pos.x
|
|
362
|
+
* @param {Number} pos.y
|
|
363
|
+
* @returns {Konva.Node}
|
|
364
|
+
* @example
|
|
365
|
+
* var shape = stage.getIntersection({x: 50, y: 50});
|
|
366
|
+
*/
|
|
367
|
+
getIntersection(pos: Vector2d) {
|
|
368
|
+
if (!pos) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
const layers = this.children,
|
|
372
|
+
len = layers.length,
|
|
373
|
+
end = len - 1;
|
|
374
|
+
|
|
375
|
+
for (let n = end; n >= 0; n--) {
|
|
376
|
+
const shape = layers[n].getIntersection(pos);
|
|
377
|
+
if (shape) {
|
|
378
|
+
return shape;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
_resizeDOM() {
|
|
385
|
+
const width = this.width();
|
|
386
|
+
const height = this.height();
|
|
387
|
+
if (this.content) {
|
|
388
|
+
// set content dimensions
|
|
389
|
+
this.content.style.width = width + PX;
|
|
390
|
+
this.content.style.height = height + PX;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
this.bufferCanvas.setSize(width, height);
|
|
394
|
+
this.bufferHitCanvas.setSize(width, height);
|
|
395
|
+
|
|
396
|
+
// set layer dimensions
|
|
397
|
+
this.children.forEach((layer) => {
|
|
398
|
+
layer.setSize({ width, height });
|
|
399
|
+
layer.draw();
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
add(layer: Layer, ...rest) {
|
|
403
|
+
if (arguments.length > 1) {
|
|
404
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
405
|
+
this.add(arguments[i]);
|
|
406
|
+
}
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
super.add(layer);
|
|
410
|
+
|
|
411
|
+
const length = this.children.length;
|
|
412
|
+
if (length > MAX_LAYERS_NUMBER) {
|
|
413
|
+
Util.warn(
|
|
414
|
+
'The stage has ' +
|
|
415
|
+
length +
|
|
416
|
+
' layers. Recommended maximum number of layers is 3-5. Adding more layers into the stage may drop the performance. Rethink your tree structure, you can use Konva.Group.'
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
layer.setSize({ width: this.width(), height: this.height() });
|
|
420
|
+
|
|
421
|
+
// draw layer and append canvas to container
|
|
422
|
+
layer.draw();
|
|
423
|
+
|
|
424
|
+
if (Konva.isBrowser) {
|
|
425
|
+
this.content.appendChild(layer.canvas._canvas);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// chainable
|
|
429
|
+
return this;
|
|
430
|
+
}
|
|
431
|
+
getParent() {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
getLayer() {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
hasPointerCapture(pointerId: number): boolean {
|
|
439
|
+
return PointerEvents.hasPointerCapture(pointerId, this);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
setPointerCapture(pointerId: number) {
|
|
443
|
+
PointerEvents.setPointerCapture(pointerId, this);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
releaseCapture(pointerId: number) {
|
|
447
|
+
PointerEvents.releaseCapture(pointerId, this);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* returns an array of layers
|
|
452
|
+
* @method
|
|
453
|
+
* @name Konva.Stage#getLayers
|
|
454
|
+
*/
|
|
455
|
+
getLayers() {
|
|
456
|
+
return this.children;
|
|
457
|
+
}
|
|
458
|
+
_bindContentEvents() {
|
|
459
|
+
if (!Konva.isBrowser) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
EVENTS.forEach(([event, methodName]) => {
|
|
463
|
+
this.content.addEventListener(
|
|
464
|
+
event,
|
|
465
|
+
(evt) => {
|
|
466
|
+
this[methodName](evt);
|
|
467
|
+
},
|
|
468
|
+
{ passive: false }
|
|
469
|
+
);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
_pointerenter(evt: PointerEvent) {
|
|
473
|
+
this.setPointersPositions(evt);
|
|
474
|
+
const events = getEventsMap(evt.type);
|
|
475
|
+
if (events) {
|
|
476
|
+
this._fire(events.pointerenter, {
|
|
477
|
+
evt: evt,
|
|
478
|
+
target: this,
|
|
479
|
+
currentTarget: this,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
_pointerover(evt) {
|
|
484
|
+
this.setPointersPositions(evt);
|
|
485
|
+
const events = getEventsMap(evt.type);
|
|
486
|
+
if (events) {
|
|
487
|
+
this._fire(events.pointerover, {
|
|
488
|
+
evt: evt,
|
|
489
|
+
target: this,
|
|
490
|
+
currentTarget: this,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
_getTargetShape(evenType) {
|
|
495
|
+
let shape: Shape | null = this[evenType + 'targetShape'];
|
|
496
|
+
if (shape && !shape.getStage()) {
|
|
497
|
+
shape = null;
|
|
498
|
+
}
|
|
499
|
+
return shape;
|
|
500
|
+
}
|
|
501
|
+
_pointerleave(evt) {
|
|
502
|
+
const events = getEventsMap(evt.type);
|
|
503
|
+
const eventType = getEventType(evt.type);
|
|
504
|
+
|
|
505
|
+
if (!events) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
this.setPointersPositions(evt);
|
|
509
|
+
|
|
510
|
+
const targetShape = this._getTargetShape(eventType);
|
|
511
|
+
const eventsEnabled =
|
|
512
|
+
!(Konva.isDragging() || Konva.isTransforming()) || Konva.hitOnDragEnabled;
|
|
513
|
+
if (targetShape && eventsEnabled) {
|
|
514
|
+
targetShape._fireAndBubble(events.pointerout, { evt: evt });
|
|
515
|
+
targetShape._fireAndBubble(events.pointerleave, { evt: evt });
|
|
516
|
+
this._fire(events.pointerleave, {
|
|
517
|
+
evt: evt,
|
|
518
|
+
target: this,
|
|
519
|
+
currentTarget: this,
|
|
520
|
+
});
|
|
521
|
+
this[eventType + 'targetShape'] = null;
|
|
522
|
+
} else if (eventsEnabled) {
|
|
523
|
+
this._fire(events.pointerleave, {
|
|
524
|
+
evt: evt,
|
|
525
|
+
target: this,
|
|
526
|
+
currentTarget: this,
|
|
527
|
+
});
|
|
528
|
+
this._fire(events.pointerout, {
|
|
529
|
+
evt: evt,
|
|
530
|
+
target: this,
|
|
531
|
+
currentTarget: this,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
this.pointerPos = null;
|
|
535
|
+
this._pointerPositions = [];
|
|
536
|
+
}
|
|
537
|
+
_pointerdown(evt: TouchEvent | MouseEvent | PointerEvent) {
|
|
538
|
+
const events = getEventsMap(evt.type);
|
|
539
|
+
const eventType = getEventType(evt.type);
|
|
540
|
+
|
|
541
|
+
if (!events) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
this.setPointersPositions(evt);
|
|
545
|
+
|
|
546
|
+
let triggeredOnShape = false;
|
|
547
|
+
this._changedPointerPositions.forEach((pos) => {
|
|
548
|
+
const shape = this.getIntersection(pos);
|
|
549
|
+
DD.justDragged = false;
|
|
550
|
+
// probably we are staring a click
|
|
551
|
+
Konva['_' + eventType + 'ListenClick'] = true;
|
|
552
|
+
|
|
553
|
+
// no shape detected? do nothing
|
|
554
|
+
if (!shape || !shape.isListening()) {
|
|
555
|
+
this[eventType + 'ClickStartShape'] = undefined;
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (Konva.capturePointerEventsEnabled) {
|
|
560
|
+
shape.setPointerCapture(pos.id);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// save where we started the click
|
|
564
|
+
this[eventType + 'ClickStartShape'] = shape;
|
|
565
|
+
|
|
566
|
+
shape._fireAndBubble(events.pointerdown, {
|
|
567
|
+
evt: evt,
|
|
568
|
+
pointerId: pos.id,
|
|
569
|
+
});
|
|
570
|
+
triggeredOnShape = true;
|
|
571
|
+
|
|
572
|
+
// TODO: test in iframe
|
|
573
|
+
// only call preventDefault if the shape is listening for events
|
|
574
|
+
const isTouch = evt.type.indexOf('touch') >= 0;
|
|
575
|
+
if (shape.preventDefault() && evt.cancelable && isTouch) {
|
|
576
|
+
evt.preventDefault();
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
// trigger down on stage if not already
|
|
581
|
+
if (!triggeredOnShape) {
|
|
582
|
+
this._fire(events.pointerdown, {
|
|
583
|
+
evt: evt,
|
|
584
|
+
target: this,
|
|
585
|
+
currentTarget: this,
|
|
586
|
+
pointerId: this._pointerPositions[0].id,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
_pointermove(evt: TouchEvent | MouseEvent | PointerEvent) {
|
|
591
|
+
const events = getEventsMap(evt.type);
|
|
592
|
+
const eventType = getEventType(evt.type);
|
|
593
|
+
if (!events) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
// prevent default only for touch-based interactions to avoid blocking
|
|
597
|
+
// native mouse wheel scrolling during drag on desktop
|
|
598
|
+
const isTouchPointer =
|
|
599
|
+
(evt as any).type.indexOf('touch') >= 0 ||
|
|
600
|
+
(evt as any).pointerType === 'touch';
|
|
601
|
+
if (
|
|
602
|
+
Konva.isDragging() &&
|
|
603
|
+
DD.node!.preventDefault() &&
|
|
604
|
+
evt.cancelable &&
|
|
605
|
+
isTouchPointer
|
|
606
|
+
) {
|
|
607
|
+
evt.preventDefault();
|
|
608
|
+
}
|
|
609
|
+
this.setPointersPositions(evt);
|
|
610
|
+
|
|
611
|
+
const eventsEnabled =
|
|
612
|
+
!(Konva.isDragging() || Konva.isTransforming()) || Konva.hitOnDragEnabled;
|
|
613
|
+
if (!eventsEnabled) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const processedShapesIds = {};
|
|
618
|
+
let triggeredOnShape = false;
|
|
619
|
+
const targetShape = this._getTargetShape(eventType);
|
|
620
|
+
this._changedPointerPositions.forEach((pos) => {
|
|
621
|
+
const shape = (PointerEvents.getCapturedShape(pos.id) ||
|
|
622
|
+
this.getIntersection(pos)) as Shape;
|
|
623
|
+
const pointerId = pos.id;
|
|
624
|
+
const event = { evt: evt, pointerId };
|
|
625
|
+
|
|
626
|
+
const differentTarget = targetShape !== shape;
|
|
627
|
+
|
|
628
|
+
if (differentTarget && targetShape) {
|
|
629
|
+
targetShape._fireAndBubble(events.pointerout, { ...event }, shape);
|
|
630
|
+
targetShape._fireAndBubble(events.pointerleave, { ...event }, shape);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (shape) {
|
|
634
|
+
if (processedShapesIds[shape._id]) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
processedShapesIds[shape._id] = true;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (shape && shape.isListening()) {
|
|
641
|
+
triggeredOnShape = true;
|
|
642
|
+
if (differentTarget) {
|
|
643
|
+
shape._fireAndBubble(events.pointerover, { ...event }, targetShape);
|
|
644
|
+
shape._fireAndBubble(events.pointerenter, { ...event }, targetShape);
|
|
645
|
+
this[eventType + 'targetShape'] = shape;
|
|
646
|
+
}
|
|
647
|
+
shape._fireAndBubble(events.pointermove, { ...event });
|
|
648
|
+
} else {
|
|
649
|
+
if (targetShape) {
|
|
650
|
+
this._fire(events.pointerover, {
|
|
651
|
+
evt: evt,
|
|
652
|
+
target: this,
|
|
653
|
+
currentTarget: this,
|
|
654
|
+
pointerId,
|
|
655
|
+
});
|
|
656
|
+
this[eventType + 'targetShape'] = null;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
if (!triggeredOnShape) {
|
|
662
|
+
this._fire(events.pointermove, {
|
|
663
|
+
evt: evt,
|
|
664
|
+
target: this,
|
|
665
|
+
currentTarget: this,
|
|
666
|
+
pointerId: this._changedPointerPositions[0].id,
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
_pointerup(evt) {
|
|
671
|
+
const events = getEventsMap(evt.type);
|
|
672
|
+
const eventType = getEventType(evt.type);
|
|
673
|
+
|
|
674
|
+
if (!events) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
this.setPointersPositions(evt);
|
|
678
|
+
const clickStartShape = this[eventType + 'ClickStartShape'];
|
|
679
|
+
const clickEndShape = this[eventType + 'ClickEndShape'];
|
|
680
|
+
const processedShapesIds = {};
|
|
681
|
+
let skipPointerUpTrigger = false;
|
|
682
|
+
this._changedPointerPositions.forEach((pos) => {
|
|
683
|
+
const shape = (PointerEvents.getCapturedShape(pos.id) ||
|
|
684
|
+
this.getIntersection(pos)) as Shape;
|
|
685
|
+
|
|
686
|
+
if (shape) {
|
|
687
|
+
shape.releaseCapture(pos.id);
|
|
688
|
+
if (processedShapesIds[shape._id]) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
processedShapesIds[shape._id] = true;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const pointerId = pos.id;
|
|
695
|
+
const event = { evt: evt, pointerId };
|
|
696
|
+
|
|
697
|
+
let fireDblClick = false;
|
|
698
|
+
if (Konva['_' + eventType + 'InDblClickWindow']) {
|
|
699
|
+
fireDblClick = true;
|
|
700
|
+
clearTimeout(this[eventType + 'DblTimeout']);
|
|
701
|
+
} else if (!DD.justDragged) {
|
|
702
|
+
// don't set inDblClickWindow after dragging
|
|
703
|
+
Konva['_' + eventType + 'InDblClickWindow'] = true;
|
|
704
|
+
clearTimeout(this[eventType + 'DblTimeout']);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
this[eventType + 'DblTimeout'] = setTimeout(function () {
|
|
708
|
+
Konva['_' + eventType + 'InDblClickWindow'] = false;
|
|
709
|
+
}, Konva.dblClickWindow);
|
|
710
|
+
|
|
711
|
+
if (shape && shape.isListening()) {
|
|
712
|
+
skipPointerUpTrigger = true;
|
|
713
|
+
this[eventType + 'ClickEndShape'] = shape;
|
|
714
|
+
shape._fireAndBubble(events.pointerup, { ...event });
|
|
715
|
+
|
|
716
|
+
// detect if click or double click occurred
|
|
717
|
+
if (
|
|
718
|
+
Konva['_' + eventType + 'ListenClick'] &&
|
|
719
|
+
clickStartShape &&
|
|
720
|
+
clickStartShape === shape
|
|
721
|
+
) {
|
|
722
|
+
shape._fireAndBubble(events.pointerclick, { ...event });
|
|
723
|
+
|
|
724
|
+
if (fireDblClick && clickEndShape && clickEndShape === shape) {
|
|
725
|
+
shape._fireAndBubble(events.pointerdblclick, { ...event });
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
this[eventType + 'ClickEndShape'] = null;
|
|
730
|
+
|
|
731
|
+
if (!skipPointerUpTrigger) {
|
|
732
|
+
this._fire(events.pointerup, {
|
|
733
|
+
evt: evt,
|
|
734
|
+
target: this,
|
|
735
|
+
currentTarget: this,
|
|
736
|
+
pointerId: this._changedPointerPositions[0].id,
|
|
737
|
+
});
|
|
738
|
+
skipPointerUpTrigger = true;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (Konva['_' + eventType + 'ListenClick']) {
|
|
742
|
+
this._fire(events.pointerclick, {
|
|
743
|
+
evt: evt,
|
|
744
|
+
target: this,
|
|
745
|
+
currentTarget: this,
|
|
746
|
+
pointerId,
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (fireDblClick) {
|
|
751
|
+
this._fire(events.pointerdblclick, {
|
|
752
|
+
evt: evt,
|
|
753
|
+
target: this,
|
|
754
|
+
currentTarget: this,
|
|
755
|
+
pointerId,
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
if (!skipPointerUpTrigger) {
|
|
762
|
+
this._fire(events.pointerup, {
|
|
763
|
+
evt: evt,
|
|
764
|
+
target: this,
|
|
765
|
+
currentTarget: this,
|
|
766
|
+
pointerId: this._changedPointerPositions[0].id,
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
Konva['_' + eventType + 'ListenClick'] = false;
|
|
771
|
+
|
|
772
|
+
// always call preventDefault for desktop events because some browsers
|
|
773
|
+
// try to drag and drop the canvas element
|
|
774
|
+
// TODO: are we sure we need to prevent default at all?
|
|
775
|
+
// do not call this function on mobile because it prevent "click" event on all parent containers
|
|
776
|
+
// but apps may listen to it.
|
|
777
|
+
if (evt.cancelable && eventType !== 'touch' && eventType !== 'pointer') {
|
|
778
|
+
evt.preventDefault();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
_contextmenu(evt) {
|
|
782
|
+
this.setPointersPositions(evt);
|
|
783
|
+
const shape = this.getIntersection(this.getPointerPosition()!);
|
|
784
|
+
|
|
785
|
+
if (shape && shape.isListening()) {
|
|
786
|
+
shape._fireAndBubble(CONTEXTMENU, { evt: evt });
|
|
787
|
+
} else {
|
|
788
|
+
this._fire(CONTEXTMENU, {
|
|
789
|
+
evt: evt,
|
|
790
|
+
target: this,
|
|
791
|
+
currentTarget: this,
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
_wheel(evt) {
|
|
797
|
+
this.setPointersPositions(evt);
|
|
798
|
+
const shape = this.getIntersection(this.getPointerPosition()!);
|
|
799
|
+
|
|
800
|
+
if (shape && shape.isListening()) {
|
|
801
|
+
shape._fireAndBubble(WHEEL, { evt: evt });
|
|
802
|
+
} else {
|
|
803
|
+
this._fire(WHEEL, {
|
|
804
|
+
evt: evt,
|
|
805
|
+
target: this,
|
|
806
|
+
currentTarget: this,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
_pointercancel(evt: PointerEvent) {
|
|
812
|
+
this.setPointersPositions(evt);
|
|
813
|
+
const shape =
|
|
814
|
+
PointerEvents.getCapturedShape(evt.pointerId) ||
|
|
815
|
+
this.getIntersection(this.getPointerPosition()!);
|
|
816
|
+
|
|
817
|
+
if (shape) {
|
|
818
|
+
shape._fireAndBubble(POINTERUP, PointerEvents.createEvent(evt));
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
PointerEvents.releaseCapture(evt.pointerId);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
_lostpointercapture(evt: PointerEvent) {
|
|
825
|
+
PointerEvents.releaseCapture(evt.pointerId);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* manually register pointers positions (mouse/touch) in the stage.
|
|
830
|
+
* So you can use stage.getPointerPosition(). Usually you don't need to use that method
|
|
831
|
+
* because all internal events are automatically registered. It may be useful if event
|
|
832
|
+
* is triggered outside of the stage, but you still want to use Konva methods to get pointers position.
|
|
833
|
+
* @method
|
|
834
|
+
* @name Konva.Stage#setPointersPositions
|
|
835
|
+
* @param {Object} event Event object
|
|
836
|
+
* @example
|
|
837
|
+
*
|
|
838
|
+
* window.addEventListener('mousemove', (e) => {
|
|
839
|
+
* stage.setPointersPositions(e);
|
|
840
|
+
* });
|
|
841
|
+
*/
|
|
842
|
+
setPointersPositions(evt) {
|
|
843
|
+
const contentPosition = this._getContentPosition();
|
|
844
|
+
let x: number | null = null,
|
|
845
|
+
y: number | null = null;
|
|
846
|
+
evt = evt ? evt : window.event;
|
|
847
|
+
|
|
848
|
+
// touch events
|
|
849
|
+
if (evt.touches !== undefined) {
|
|
850
|
+
// touchlist has not support for map method
|
|
851
|
+
// so we have to iterate
|
|
852
|
+
this._pointerPositions = [];
|
|
853
|
+
this._changedPointerPositions = [];
|
|
854
|
+
Array.prototype.forEach.call(evt.touches, (touch: any) => {
|
|
855
|
+
this._pointerPositions.push({
|
|
856
|
+
id: touch.identifier,
|
|
857
|
+
x: (touch.clientX - contentPosition.left) / contentPosition.scaleX,
|
|
858
|
+
y: (touch.clientY - contentPosition.top) / contentPosition.scaleY,
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
Array.prototype.forEach.call(
|
|
863
|
+
evt.changedTouches || evt.touches,
|
|
864
|
+
(touch: any) => {
|
|
865
|
+
this._changedPointerPositions.push({
|
|
866
|
+
id: touch.identifier,
|
|
867
|
+
x: (touch.clientX - contentPosition.left) / contentPosition.scaleX,
|
|
868
|
+
y: (touch.clientY - contentPosition.top) / contentPosition.scaleY,
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
);
|
|
872
|
+
} else {
|
|
873
|
+
// mouse events
|
|
874
|
+
x = (evt.clientX - contentPosition.left) / contentPosition.scaleX;
|
|
875
|
+
y = (evt.clientY - contentPosition.top) / contentPosition.scaleY;
|
|
876
|
+
this.pointerPos = {
|
|
877
|
+
x: x,
|
|
878
|
+
y: y,
|
|
879
|
+
};
|
|
880
|
+
this._pointerPositions = [{ x, y, id: Util._getFirstPointerId(evt) }];
|
|
881
|
+
this._changedPointerPositions = [
|
|
882
|
+
{ x, y, id: Util._getFirstPointerId(evt) },
|
|
883
|
+
];
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
_setPointerPosition(evt) {
|
|
887
|
+
Util.warn(
|
|
888
|
+
'Method _setPointerPosition is deprecated. Use "stage.setPointersPositions(event)" instead.'
|
|
889
|
+
);
|
|
890
|
+
this.setPointersPositions(evt);
|
|
891
|
+
}
|
|
892
|
+
_getContentPosition() {
|
|
893
|
+
if (!this.content || !this.content.getBoundingClientRect) {
|
|
894
|
+
return {
|
|
895
|
+
top: 0,
|
|
896
|
+
left: 0,
|
|
897
|
+
scaleX: 1,
|
|
898
|
+
scaleY: 1,
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
const rect = this.content.getBoundingClientRect();
|
|
903
|
+
|
|
904
|
+
return {
|
|
905
|
+
top: rect.top,
|
|
906
|
+
left: rect.left,
|
|
907
|
+
// sometimes clientWidth can be equals to 0
|
|
908
|
+
// i saw it in react-konva test, looks like it is because of hidden testing element
|
|
909
|
+
scaleX: rect.width / this.content.clientWidth || 1,
|
|
910
|
+
scaleY: rect.height / this.content.clientHeight || 1,
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
_buildDOM() {
|
|
914
|
+
this.bufferCanvas = new SceneCanvas({
|
|
915
|
+
width: this.width(),
|
|
916
|
+
height: this.height(),
|
|
917
|
+
});
|
|
918
|
+
this.bufferHitCanvas = new HitCanvas({
|
|
919
|
+
pixelRatio: 1,
|
|
920
|
+
width: this.width(),
|
|
921
|
+
height: this.height(),
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
if (!Konva.isBrowser) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const container = this.container();
|
|
928
|
+
if (!container) {
|
|
929
|
+
throw 'Stage has no container. A container is required.';
|
|
930
|
+
}
|
|
931
|
+
// clear content inside container
|
|
932
|
+
container.innerHTML = '';
|
|
933
|
+
|
|
934
|
+
// content
|
|
935
|
+
this.content = document.createElement('div');
|
|
936
|
+
this.content.style.position = 'relative';
|
|
937
|
+
this.content.style.userSelect = 'none';
|
|
938
|
+
this.content.className = 'konvajs-content';
|
|
939
|
+
|
|
940
|
+
this.content.setAttribute('role', 'presentation');
|
|
941
|
+
|
|
942
|
+
container.appendChild(this.content);
|
|
943
|
+
|
|
944
|
+
this._resizeDOM();
|
|
945
|
+
}
|
|
946
|
+
// currently cache function is now working for stage, because stage has no its own canvas element
|
|
947
|
+
cache() {
|
|
948
|
+
Util.warn(
|
|
949
|
+
'Cache function is not allowed for stage. You may use cache only for layers, groups and shapes.'
|
|
950
|
+
);
|
|
951
|
+
return this;
|
|
952
|
+
}
|
|
953
|
+
clearCache() {
|
|
954
|
+
return this;
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* batch draw
|
|
958
|
+
* @method
|
|
959
|
+
* @name Konva.Stage#batchDraw
|
|
960
|
+
* @return {Konva.Stage} this
|
|
961
|
+
*/
|
|
962
|
+
batchDraw() {
|
|
963
|
+
this.getChildren().forEach(function (layer) {
|
|
964
|
+
layer.batchDraw();
|
|
965
|
+
});
|
|
966
|
+
return this;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
container: GetSet<HTMLDivElement, this>;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
Stage.prototype.nodeType = STAGE;
|
|
973
|
+
_registerNode(Stage);
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* get/set container DOM element
|
|
977
|
+
* @method
|
|
978
|
+
* @name Konva.Stage#container
|
|
979
|
+
* @returns {DomElement} container
|
|
980
|
+
* @example
|
|
981
|
+
* // get container
|
|
982
|
+
* var container = stage.container();
|
|
983
|
+
* // set container
|
|
984
|
+
* var container = document.createElement('div');
|
|
985
|
+
* body.appendChild(container);
|
|
986
|
+
* stage.container(container);
|
|
987
|
+
*/
|
|
988
|
+
Factory.addGetterSetter(Stage, 'container');
|
|
989
|
+
|
|
990
|
+
// chrome is clearing canvas in inactive browser window, causing layer content to be erased
|
|
991
|
+
// so let's redraw layers as soon as window becomes active
|
|
992
|
+
// TODO: any other way to solve this issue?
|
|
993
|
+
// TODO: should we remove it if chrome fixes the issue?
|
|
994
|
+
if (Konva.isBrowser) {
|
|
995
|
+
document.addEventListener('visibilitychange', () => {
|
|
996
|
+
stages.forEach((stage) => {
|
|
997
|
+
stage.batchDraw();
|
|
998
|
+
});
|
|
999
|
+
});
|
|
1000
|
+
}
|