js-draw 0.15.1 → 0.15.2
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/CHANGELOG.md +7 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Color4.d.ts +1 -1
- package/dist/src/Color4.js +5 -1
- package/dist/src/Editor.d.ts +0 -2
- package/dist/src/Editor.js +15 -30
- package/dist/src/EditorImage.d.ts +25 -0
- package/dist/src/EditorImage.js +57 -2
- package/dist/src/EventDispatcher.d.ts +4 -3
- package/dist/src/SVGLoader.d.ts +1 -0
- package/dist/src/SVGLoader.js +15 -1
- package/dist/src/Viewport.d.ts +3 -3
- package/dist/src/Viewport.js +4 -8
- package/dist/src/components/AbstractComponent.d.ts +5 -1
- package/dist/src/components/AbstractComponent.js +10 -2
- package/dist/src/components/ImageBackground.d.ts +41 -0
- package/dist/src/components/ImageBackground.js +132 -0
- package/dist/src/components/ImageComponent.js +2 -0
- package/dist/src/components/builders/ArrowBuilder.d.ts +3 -1
- package/dist/src/components/builders/ArrowBuilder.js +43 -40
- package/dist/src/components/builders/LineBuilder.d.ts +3 -1
- package/dist/src/components/builders/LineBuilder.js +25 -28
- package/dist/src/components/builders/RectangleBuilder.js +1 -1
- package/dist/src/components/lib.d.ts +2 -1
- package/dist/src/components/lib.js +2 -1
- package/dist/src/components/localization.d.ts +2 -0
- package/dist/src/components/localization.js +2 -0
- package/dist/src/math/Mat33.js +43 -5
- package/dist/src/math/Path.d.ts +5 -0
- package/dist/src/math/Path.js +80 -28
- package/dist/src/math/Vec3.js +1 -1
- package/dist/src/rendering/Display.js +1 -1
- package/dist/src/rendering/renderers/AbstractRenderer.d.ts +13 -1
- package/dist/src/rendering/renderers/AbstractRenderer.js +18 -3
- package/dist/src/rendering/renderers/CanvasRenderer.d.ts +2 -1
- package/dist/src/rendering/renderers/CanvasRenderer.js +12 -2
- package/dist/src/rendering/renderers/SVGRenderer.d.ts +1 -1
- package/dist/src/rendering/renderers/SVGRenderer.js +8 -2
- package/dist/src/testing/sendTouchEvent.d.ts +6 -0
- package/dist/src/testing/sendTouchEvent.js +26 -0
- package/dist/src/toolbar/IconProvider.js +1 -2
- package/dist/src/toolbar/widgets/HandToolWidget.js +1 -1
- package/dist/src/tools/Eraser.js +5 -2
- package/dist/src/tools/PanZoom.js +12 -0
- package/dist/src/tools/SelectionTool/Selection.js +1 -1
- package/dist/src/tools/SelectionTool/SelectionTool.js +5 -1
- package/package.json +1 -1
- package/src/Color4.test.ts +6 -0
- package/src/Color4.ts +6 -1
- package/src/Editor.ts +15 -36
- package/src/EditorImage.ts +74 -2
- package/src/EventDispatcher.ts +4 -1
- package/src/SVGLoader.ts +12 -1
- package/src/Viewport.ts +4 -7
- package/src/components/AbstractComponent.ts +11 -1
- package/src/components/ImageBackground.ts +167 -0
- package/src/components/ImageComponent.ts +2 -0
- package/src/components/builders/ArrowBuilder.ts +44 -41
- package/src/components/builders/LineBuilder.ts +26 -28
- package/src/components/builders/RectangleBuilder.ts +1 -1
- package/src/components/lib.ts +2 -0
- package/src/components/localization.ts +4 -0
- package/src/math/Mat33.test.ts +20 -1
- package/src/math/Mat33.ts +47 -5
- package/src/math/Path.ts +87 -28
- package/src/math/Vec3.test.ts +4 -0
- package/src/math/Vec3.ts +1 -1
- package/src/rendering/Display.ts +1 -1
- package/src/rendering/renderers/AbstractRenderer.ts +20 -3
- package/src/rendering/renderers/CanvasRenderer.ts +16 -3
- package/src/rendering/renderers/DummyRenderer.test.ts +1 -2
- package/src/rendering/renderers/SVGRenderer.ts +8 -1
- package/src/testing/sendTouchEvent.ts +43 -0
- package/src/toolbar/IconProvider.ts +1 -2
- package/src/toolbar/widgets/HandToolWidget.ts +1 -1
- package/src/tools/Eraser.test.ts +24 -1
- package/src/tools/Eraser.ts +6 -2
- package/src/tools/PanZoom.test.ts +267 -23
- package/src/tools/PanZoom.ts +15 -1
- package/src/tools/SelectionTool/Selection.ts +1 -1
- package/src/tools/SelectionTool/SelectionTool.ts +6 -1
- package/src/types.ts +1 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import Color4 from '../../Color4';
|
1
2
|
import { LoadSaveDataTable } from '../../components/AbstractComponent';
|
2
3
|
import Mat33 from '../../math/Mat33';
|
3
4
|
import Path, { PathCommand, PathCommandType } from '../../math/Path';
|
@@ -122,21 +123,37 @@ export default abstract class AbstractRenderer {
|
|
122
123
|
}
|
123
124
|
}
|
124
125
|
|
125
|
-
//
|
126
|
+
// Strokes a rectangle. Boundary lines have width [lineWidth] and are filled with [lineFill].
|
126
127
|
// This is equivalent to `drawPath(Path.fromRect(...).toRenderable(...))`.
|
127
128
|
public drawRect(rect: Rect2, lineWidth: number, lineFill: RenderingStyle) {
|
128
129
|
const path = Path.fromRect(rect, lineWidth);
|
129
130
|
this.drawPath(path.toRenderable(lineFill));
|
130
131
|
}
|
131
132
|
|
132
|
-
//
|
133
|
+
// Fills a rectangle.
|
134
|
+
public fillRect(rect: Rect2, fill: Color4) {
|
135
|
+
const path = Path.fromRect(rect);
|
136
|
+
this.drawPath(path.toRenderable({ fill }));
|
137
|
+
}
|
138
|
+
|
139
|
+
// Note the start of an object with the given bounding box.
|
133
140
|
// Renderers are not required to support [clip]
|
134
141
|
public startObject(_boundingBox: Rect2, _clip?: boolean) {
|
135
142
|
this.currentPaths = [];
|
136
143
|
this.objectLevel ++;
|
137
144
|
}
|
138
145
|
|
139
|
-
|
146
|
+
/**
|
147
|
+
* Notes the end of an object.
|
148
|
+
* @param _loaderData - a map from strings to JSON-ifyable objects
|
149
|
+
* and contains properties attached to the object by whatever loader loaded the image. This
|
150
|
+
* is used to preserve attributes not supported by js-draw when loading/saving an image.
|
151
|
+
* Renderers may ignore this.
|
152
|
+
*
|
153
|
+
* @param _objectTags - a list of labels (e.g. `className`s) to be attached to the object.
|
154
|
+
* Renderers may ignore this.
|
155
|
+
*/
|
156
|
+
public endObject(_loaderData?: LoadSaveDataTable, _objectTags?: string[]) {
|
140
157
|
// Render the paths all at once
|
141
158
|
this.flushPath();
|
142
159
|
this.currentPaths = null;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import Color4 from '../../Color4';
|
2
2
|
import TextComponent from '../../components/TextComponent';
|
3
3
|
import Mat33 from '../../math/Mat33';
|
4
|
+
import Path from '../../math/Path';
|
4
5
|
import Rect2 from '../../math/Rect2';
|
5
6
|
import { Point2, Vec2 } from '../../math/Vec2';
|
6
7
|
import Vec3 from '../../math/Vec3';
|
@@ -12,6 +13,7 @@ import AbstractRenderer, { RenderableImage, RenderablePathSpec } from './Abstrac
|
|
12
13
|
export default class CanvasRenderer extends AbstractRenderer {
|
13
14
|
private ignoreObjectsAboveLevel: number|null = null;
|
14
15
|
private ignoringObject: boolean = false;
|
16
|
+
private currentObjectBBox: Rect2|null = null;
|
15
17
|
|
16
18
|
// Minimum square distance of a control point from the line between the end points
|
17
19
|
// for the curve not to be drawn as a line.
|
@@ -65,8 +67,8 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
65
67
|
this.minRenderSizeAnyDimen = 0.5;
|
66
68
|
} else {
|
67
69
|
this.minSquareCurveApproxDist = 0.5;
|
68
|
-
this.minRenderSizeBothDimens = 0.
|
69
|
-
this.minRenderSizeAnyDimen = 1e-
|
70
|
+
this.minRenderSizeBothDimens = 0.2;
|
71
|
+
this.minRenderSizeAnyDimen = 1e-6;
|
70
72
|
}
|
71
73
|
}
|
72
74
|
|
@@ -149,6 +151,15 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
149
151
|
return;
|
150
152
|
}
|
151
153
|
|
154
|
+
// If part of a huge object, it might be worth trimming the path
|
155
|
+
if (this.currentObjectBBox?.containsRect(this.getViewport().visibleRect)) {
|
156
|
+
// Try to trim/remove parts of the path outside of the bounding box.
|
157
|
+
path = Path.visualEquivalent(
|
158
|
+
path,
|
159
|
+
this.getViewport().visibleRect
|
160
|
+
);
|
161
|
+
}
|
162
|
+
|
152
163
|
super.drawPath(path);
|
153
164
|
}
|
154
165
|
|
@@ -181,13 +192,14 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
181
192
|
}
|
182
193
|
|
183
194
|
private clipLevels: number[] = [];
|
184
|
-
public startObject(boundingBox: Rect2, clip
|
195
|
+
public startObject(boundingBox: Rect2, clip?: boolean) {
|
185
196
|
if (this.isTooSmallToRender(boundingBox)) {
|
186
197
|
this.ignoreObjectsAboveLevel = this.getNestingLevel();
|
187
198
|
this.ignoringObject = true;
|
188
199
|
}
|
189
200
|
|
190
201
|
super.startObject(boundingBox);
|
202
|
+
this.currentObjectBBox = boundingBox;
|
191
203
|
|
192
204
|
if (!this.ignoringObject && clip) {
|
193
205
|
this.clipLevels.push(this.objectLevel);
|
@@ -209,6 +221,7 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
209
221
|
}
|
210
222
|
}
|
211
223
|
|
224
|
+
this.currentObjectBBox = null;
|
212
225
|
super.endObject();
|
213
226
|
|
214
227
|
// If exiting an object with a too-small-to-draw bounding box,
|
@@ -1,12 +1,11 @@
|
|
1
1
|
|
2
|
-
import EventDispatcher from '../../EventDispatcher';
|
3
2
|
import Mat33 from '../../math/Mat33';
|
4
3
|
import { Vec2 } from '../../math/Vec2';
|
5
4
|
import Viewport from '../../Viewport';
|
6
5
|
import DummyRenderer from './DummyRenderer';
|
7
6
|
|
8
7
|
const makeRenderer = (): [DummyRenderer, Viewport] => {
|
9
|
-
const viewport = new Viewport(
|
8
|
+
const viewport = new Viewport(() => {});
|
10
9
|
return [ new DummyRenderer(viewport), viewport ];
|
11
10
|
};
|
12
11
|
|
@@ -248,7 +248,7 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
248
248
|
this.objectElems = [];
|
249
249
|
}
|
250
250
|
|
251
|
-
public endObject(loaderData?: LoadSaveDataTable) {
|
251
|
+
public endObject(loaderData?: LoadSaveDataTable, elemClassNames?: string[]) {
|
252
252
|
super.endObject(loaderData);
|
253
253
|
|
254
254
|
// Don't extend paths across objects
|
@@ -273,6 +273,13 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
273
273
|
}
|
274
274
|
}
|
275
275
|
}
|
276
|
+
|
277
|
+
// Add class names to the object, if given.
|
278
|
+
if (elemClassNames) {
|
279
|
+
for (const elem of this.objectElems ?? []) {
|
280
|
+
elem.classList.add(...elemClassNames);
|
281
|
+
}
|
282
|
+
}
|
276
283
|
}
|
277
284
|
|
278
285
|
// Not implemented -- use drawPath instead.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import Editor from '../Editor';
|
2
|
+
import { Vec2 } from '../math/Vec2';
|
3
|
+
import Pointer, { PointerDevice } from '../Pointer';
|
4
|
+
import { InputEvtType } from '../types';
|
5
|
+
|
6
|
+
|
7
|
+
const sendTouchEvent = (
|
8
|
+
editor: Editor,
|
9
|
+
eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
|
10
|
+
screenPos: Vec2,
|
11
|
+
allOtherPointers?: Pointer[]
|
12
|
+
) => {
|
13
|
+
const canvasPos = editor.viewport.screenToCanvas(screenPos);
|
14
|
+
|
15
|
+
let ptrId = 0;
|
16
|
+
let maxPtrId = 0;
|
17
|
+
|
18
|
+
// Get a unique ID for the main pointer
|
19
|
+
// (try to use id=0, but don't use it if it's already in use).
|
20
|
+
for (const pointer of allOtherPointers ?? []) {
|
21
|
+
maxPtrId = Math.max(pointer.id, maxPtrId);
|
22
|
+
if (pointer.id === ptrId) {
|
23
|
+
ptrId = maxPtrId + 1;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
const mainPointer = Pointer.ofCanvasPoint(
|
28
|
+
canvasPos, eventType !== InputEvtType.PointerUpEvt, editor.viewport, ptrId, PointerDevice.Touch
|
29
|
+
);
|
30
|
+
|
31
|
+
editor.toolController.dispatchInputEvent({
|
32
|
+
kind: eventType,
|
33
|
+
allPointers: [
|
34
|
+
...(allOtherPointers ?? []),
|
35
|
+
mainPointer,
|
36
|
+
],
|
37
|
+
current: mainPointer,
|
38
|
+
});
|
39
|
+
|
40
|
+
return mainPointer;
|
41
|
+
};
|
42
|
+
|
43
|
+
export default sendTouchEvent;
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import Color4 from '../Color4';
|
2
2
|
import { ComponentBuilderFactory } from '../components/builders/types';
|
3
|
-
import EventDispatcher from '../EventDispatcher';
|
4
3
|
import { Vec2 } from '../math/Vec2';
|
5
4
|
import SVGRenderer from '../rendering/renderers/SVGRenderer';
|
6
5
|
import TextStyle from '../rendering/TextRenderingStyle';
|
@@ -542,7 +541,7 @@ export default class IconProvider {
|
|
542
541
|
time: nowTime,
|
543
542
|
};
|
544
543
|
|
545
|
-
const viewport = new Viewport(
|
544
|
+
const viewport = new Viewport(() => {});
|
546
545
|
const builder = factory(startPoint, viewport);
|
547
546
|
builder.addPoint(endPoint);
|
548
547
|
|
@@ -94,7 +94,7 @@ class ZoomWidget extends BaseWidget {
|
|
94
94
|
}
|
95
95
|
|
96
96
|
protected fillDropdown(dropdown: HTMLElement): boolean {
|
97
|
-
dropdown.
|
97
|
+
dropdown.replaceChildren(makeZoomControl(this.localizationTable, this.editor));
|
98
98
|
return true;
|
99
99
|
}
|
100
100
|
}
|
package/src/tools/Eraser.test.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
import UnknownSVGObject from '../components/UnknownSVGObject';
|
1
2
|
import Editor from '../Editor';
|
2
|
-
import { Rect2, StrokeComponent } from '../lib';
|
3
|
+
import { EditorImage, Rect2, StrokeComponent } from '../lib';
|
3
4
|
import { Vec2 } from '../math/Vec2';
|
4
5
|
import createEditor from '../testing/createEditor';
|
5
6
|
import { InputEvtType } from '../types';
|
@@ -76,4 +77,26 @@ describe('Eraser', () => {
|
|
76
77
|
|
77
78
|
expect(getAllStrokes(editor)).toHaveLength(0);
|
78
79
|
});
|
80
|
+
|
81
|
+
it('should not erase unselectable objects', () => {
|
82
|
+
const editor = createEditor();
|
83
|
+
const unerasableObj = new UnknownSVGObject(document.createElementNS('http://www.w3.org/2000/svg', 'arc'));
|
84
|
+
|
85
|
+
// Add to the image
|
86
|
+
expect(editor.image.getAllElements()).toHaveLength(0);
|
87
|
+
editor.dispatch(EditorImage.addElement(unerasableObj));
|
88
|
+
expect(editor.image.getAllElements()).toHaveLength(1);
|
89
|
+
|
90
|
+
|
91
|
+
const eraser = selectEraser(editor);
|
92
|
+
eraser.setThickness(100);
|
93
|
+
|
94
|
+
// Try to erase it.
|
95
|
+
editor.sendPenEvent(InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
96
|
+
jest.advanceTimersByTime(100);
|
97
|
+
editor.sendPenEvent(InputEvtType.PointerUpEvt, Vec2.of(3, 0));
|
98
|
+
|
99
|
+
// Should not have been erased
|
100
|
+
expect(editor.image.getAllElements()).toHaveLength(1);
|
101
|
+
});
|
79
102
|
});
|
package/src/tools/Eraser.ts
CHANGED
@@ -67,11 +67,15 @@ export default class Eraser extends BaseTool {
|
|
67
67
|
return component.intersects(line) || component.intersectsRect(eraserRect);
|
68
68
|
});
|
69
69
|
|
70
|
+
// Only erase components that could be selected (and thus interacted with)
|
71
|
+
// by the user.
|
72
|
+
const toErase = intersectingElems.filter(elem => elem.isSelectable());
|
73
|
+
|
70
74
|
// Remove any intersecting elements.
|
71
|
-
this.toRemove.push(...
|
75
|
+
this.toRemove.push(...toErase);
|
72
76
|
|
73
77
|
// Create new Erase commands for the now-to-be-erased elements and apply them.
|
74
|
-
const newPartialCommands =
|
78
|
+
const newPartialCommands = toErase.map(elem => new Erase([ elem ]));
|
75
79
|
newPartialCommands.forEach(cmd => cmd.apply(this.editor));
|
76
80
|
|
77
81
|
this.partialCommands.push(...newPartialCommands);
|
@@ -1,10 +1,11 @@
|
|
1
1
|
|
2
2
|
import Editor from '../Editor';
|
3
|
-
import { Mat33,
|
3
|
+
import { Mat33, Vec2 } from '../lib';
|
4
4
|
import createEditor from '../testing/createEditor';
|
5
|
+
import sendTouchEvent from '../testing/sendTouchEvent';
|
5
6
|
import { InputEvtType } from '../types';
|
6
7
|
import waitForTimeout from '../util/waitForTimeout';
|
7
|
-
import PanZoom from './PanZoom';
|
8
|
+
import PanZoom, { PanZoomMode } from './PanZoom';
|
8
9
|
|
9
10
|
const selectPanZom = (editor: Editor): PanZoom => {
|
10
11
|
const primaryTools = editor.toolController.getPrimaryTools();
|
@@ -13,27 +14,6 @@ const selectPanZom = (editor: Editor): PanZoom => {
|
|
13
14
|
return panZoom;
|
14
15
|
};
|
15
16
|
|
16
|
-
const sendTouchEvent = (
|
17
|
-
editor: Editor,
|
18
|
-
eventType: InputEvtType.PointerDownEvt|InputEvtType.PointerMoveEvt|InputEvtType.PointerUpEvt,
|
19
|
-
screenPos: Vec2,
|
20
|
-
) => {
|
21
|
-
const canvasPos = editor.viewport.screenToCanvas(screenPos);
|
22
|
-
|
23
|
-
const ptrId = 0;
|
24
|
-
const mainPointer = Pointer.ofCanvasPoint(
|
25
|
-
canvasPos, eventType !== InputEvtType.PointerUpEvt, editor.viewport, ptrId, PointerDevice.Touch
|
26
|
-
);
|
27
|
-
|
28
|
-
editor.toolController.dispatchInputEvent({
|
29
|
-
kind: eventType,
|
30
|
-
allPointers: [
|
31
|
-
mainPointer,
|
32
|
-
],
|
33
|
-
current: mainPointer,
|
34
|
-
});
|
35
|
-
};
|
36
|
-
|
37
17
|
describe('PanZoom', () => {
|
38
18
|
it('touch and drag should pan, then inertial scroll', async () => {
|
39
19
|
const editor = createEditor();
|
@@ -63,4 +43,268 @@ describe('PanZoom', () => {
|
|
63
43
|
const afterDelayTranslation = editor.viewport.canvasToScreen(Vec2.zero);
|
64
44
|
expect(afterDelayTranslation.minus(updatedTranslation).magnitude()).toBeGreaterThan(0);
|
65
45
|
});
|
46
|
+
|
47
|
+
it('should scale the view based on distance between two touches', () => {
|
48
|
+
const editor = createEditor();
|
49
|
+
selectPanZom(editor);
|
50
|
+
editor.viewport.resetTransform(Mat33.identity);
|
51
|
+
|
52
|
+
let firstPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(0, 0));
|
53
|
+
let secondPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, Vec2.of(100, 0), [ firstPointer ]);
|
54
|
+
|
55
|
+
let expectedScale = 1;
|
56
|
+
expect(editor.viewport.getScaleFactor()).toBe(expectedScale);
|
57
|
+
expect(editor.viewport.canvasToScreen(Vec2.zero)).objEq(Vec2.zero);
|
58
|
+
|
59
|
+
const maxIterations = 10;
|
60
|
+
for (let i = 0; i < maxIterations; i++) {
|
61
|
+
jest.advanceTimersByTime(100);
|
62
|
+
|
63
|
+
const point1 = Vec2.of(-i * 5, 0);
|
64
|
+
const point2 = Vec2.of(i * 5 + 100, 0);
|
65
|
+
|
66
|
+
const eventType = InputEvtType.PointerMoveEvt;
|
67
|
+
|
68
|
+
firstPointer = sendTouchEvent(editor, eventType, point1, [ secondPointer ]);
|
69
|
+
secondPointer = sendTouchEvent(editor, eventType, point2, [ firstPointer ]);
|
70
|
+
expectedScale = point1.minus(point2).magnitude() / 100;
|
71
|
+
Vec2.zero;
|
72
|
+
if (i === maxIterations - 1) {
|
73
|
+
jest.advanceTimersByTime(10);
|
74
|
+
|
75
|
+
sendTouchEvent(editor, InputEvtType.PointerUpEvt, point1, [ secondPointer ]);
|
76
|
+
sendTouchEvent(editor, InputEvtType.PointerUpEvt, point2);
|
77
|
+
}
|
78
|
+
|
79
|
+
jest.advanceTimersByTime(100);
|
80
|
+
|
81
|
+
expect(editor.viewport.getRotationAngle()).toBe(0);
|
82
|
+
expect(editor.viewport.getScaleFactor()).toBeCloseTo(expectedScale);
|
83
|
+
|
84
|
+
// Center of touches should remain roughly center
|
85
|
+
// (One touch is updating before the other, so there will be some leftwards drift)
|
86
|
+
const translation = editor.viewport.canvasToScreen(Vec2.zero).minus(Vec2.zero);
|
87
|
+
expect(translation.magnitude()).toBeLessThanOrEqual(i * 10);
|
88
|
+
}
|
89
|
+
});
|
90
|
+
|
91
|
+
it('should zoom in to point within current screen', () => {
|
92
|
+
// This sequence of touches and initial zoom was found to cause issues in
|
93
|
+
// 4abe27ff8e7913155828f98dee77b09c57c51d30 and before.
|
94
|
+
const initialCanvasTransform = new Mat33(832845.8900685566,0,-62599136.228663616,0,832845.8900685566,-86864630.94239436,0,0,1);
|
95
|
+
const touchData = [
|
96
|
+
{ touch1Point: {'x':776.41796875,'y':161.8515625}, touch2Point: {'x':794.09765625,'y':321.3984375}, },
|
97
|
+
{ touch1Point: {'x':776.41796875,'y':159.7578125}, touch2Point: {'x':794.09765625,'y':321.3984375}, },
|
98
|
+
{ touch1Point: {'x':776.41796875,'y':159.7578125}, touch2Point: {'x':794.09765625,'y':318.2578125}, },
|
99
|
+
{ touch1Point: {'x':777.45703125,'y':157.6640625}, touch2Point: {'x':794.09765625,'y':318.2578125}, },
|
100
|
+
{ touch1Point: {'x':777.45703125,'y':157.6640625}, touch2Point: {'x':794.09765625,'y':316.16796875}, },
|
101
|
+
{ touch1Point: {'x':777.9765625,'y':155.57421875}, touch2Point: {'x':794.09765625,'y':316.16796875}, },
|
102
|
+
{ touch1Point: {'x':777.9765625,'y':155.57421875}, touch2Point: {'x':795.13671875,'y':313.02734375}, },
|
103
|
+
{ touch1Point: {'x':778.49609375,'y':153.48046875}, touch2Point: {'x':795.13671875,'y':313.02734375}, },
|
104
|
+
{ touch1Point: {'x':778.49609375,'y':153.48046875}, touch2Point: {'x':795.65625,'y':307.796875}, },
|
105
|
+
{ touch1Point: {'x':779.015625,'y':150.34375}, touch2Point: {'x':795.65625,'y':307.796875}, },
|
106
|
+
{ touch1Point: {'x':779.015625,'y':150.34375}, touch2Point: {'x':796.69921875,'y':301.51953125}, },
|
107
|
+
{ touch1Point: {'x':779.53515625,'y':146.15625}, touch2Point: {'x':796.69921875,'y':301.51953125}, },
|
108
|
+
{ touch1Point: {'x':779.53515625,'y':146.15625}, touch2Point: {'x':797.73828125,'y':295.2421875}, },
|
109
|
+
{ touch1Point: {'x':780.05859375,'y':141.97265625}, touch2Point: {'x':797.73828125,'y':295.2421875}, },
|
110
|
+
{ touch1Point: {'x':780.05859375,'y':141.97265625}, touch2Point: {'x':799.296875,'y':288.44140625}, },
|
111
|
+
{ touch1Point: {'x':780.578125,'y':136.7421875}, touch2Point: {'x':799.296875,'y':288.44140625}, },
|
112
|
+
{ touch1Point: {'x':780.578125,'y':136.7421875}, touch2Point: {'x':800.859375,'y':280.59765625}, },
|
113
|
+
{ touch1Point: {'x':781.09765625,'y':131.51171875}, touch2Point: {'x':800.859375,'y':280.59765625}, },
|
114
|
+
{ touch1Point: {'x':781.09765625,'y':131.51171875}, touch2Point: {'x':801.8984375,'y':273.796875}, },
|
115
|
+
{ touch1Point: {'x':781.6171875,'y':126.27734375}, touch2Point: {'x':801.8984375,'y':273.796875}, },
|
116
|
+
{ touch1Point: {'x':781.6171875,'y':126.27734375}, touch2Point: {'x':802.41796875,'y':267.51953125}, },
|
117
|
+
{ touch1Point: {'x':782.13671875,'y':120}, touch2Point: {'x':802.41796875,'y':267.51953125}, },
|
118
|
+
{ touch1Point: {'x':782.13671875,'y':120}, touch2Point: {'x':802.9375,'y':261.2421875}, },
|
119
|
+
{ touch1Point: {'x':782.65625,'y':113.72265625}, touch2Point: {'x':802.9375,'y':261.2421875}, },
|
120
|
+
{ touch1Point: {'x':782.65625,'y':113.72265625}, touch2Point: {'x':803.45703125,'y':254.44140625}, },
|
121
|
+
{ touch1Point: {'x':783.17578125,'y':107.96875}, touch2Point: {'x':803.45703125,'y':254.44140625}, },
|
122
|
+
{ touch1Point: {'x':783.17578125,'y':107.96875}, touch2Point: {'x':803.9765625,'y':249.2109375}, },
|
123
|
+
{ touch1Point: {'x':783.6953125,'y':102.21484375}, touch2Point: {'x':803.9765625,'y':249.2109375}, },
|
124
|
+
{ touch1Point: {'x':783.6953125,'y':102.21484375}, touch2Point: {'x':803.9765625,'y':244.5}, },
|
125
|
+
{ touch1Point: {'x':784.21875,'y':96.984375}, touch2Point: {'x':803.9765625,'y':244.5}, },
|
126
|
+
{ touch1Point: {'x':784.21875,'y':96.984375}, touch2Point: {'x':803.9765625,'y':240.31640625}, },
|
127
|
+
{ touch1Point: {'x':784.73828125,'y':92.80078125}, touch2Point: {'x':803.9765625,'y':240.31640625}, },
|
128
|
+
{ touch1Point: {'x':784.73828125,'y':92.80078125}, touch2Point: {'x':803.9765625,'y':235.0859375}, },
|
129
|
+
{ touch1Point: {'x':785.2578125,'y':89.13671875}, touch2Point: {'x':803.9765625,'y':235.0859375}, },
|
130
|
+
{ touch1Point: {'x':785.2578125,'y':89.13671875}, touch2Point: {'x':803.9765625,'y':229.85546875}, },
|
131
|
+
{ touch1Point: {'x':785.2578125,'y':86.5234375}, touch2Point: {'x':803.9765625,'y':229.85546875}, },
|
132
|
+
{ touch1Point: {'x':785.2578125,'y':86.5234375}, touch2Point: {'x':803.9765625,'y':224.625}, },
|
133
|
+
{ touch1Point: {'x':785.2578125,'y':83.90625}, touch2Point: {'x':803.9765625,'y':224.625}, },
|
134
|
+
{ touch1Point: {'x':785.2578125,'y':83.90625}, touch2Point: {'x':803.9765625,'y':220.4375}, },
|
135
|
+
{ touch1Point: {'x':785.2578125,'y':81.29296875}, touch2Point: {'x':803.9765625,'y':220.4375}, },
|
136
|
+
{ touch1Point: {'x':785.2578125,'y':81.29296875}, touch2Point: {'x':803.9765625,'y':216.77734375}, },
|
137
|
+
{ touch1Point: {'x':785.2578125,'y':78.67578125}, touch2Point: {'x':803.9765625,'y':216.77734375}, },
|
138
|
+
{ touch1Point: {'x':785.2578125,'y':78.67578125}, touch2Point: {'x':803.9765625,'y':212.58984375}, },
|
139
|
+
{ touch1Point: {'x':785.2578125,'y':76.05859375}, touch2Point: {'x':803.9765625,'y':212.58984375}, },
|
140
|
+
{ touch1Point: {'x':785.2578125,'y':76.05859375}, touch2Point: {'x':803.9765625,'y':208.40625}, },
|
141
|
+
{ touch1Point: {'x':785.2578125,'y':76.05859375}, touch2Point: {'x':803.45703125,'y':204.74609375}, },
|
142
|
+
{ touch1Point: {'x':785.2578125,'y':72.921875}, touch2Point: {'x':803.45703125,'y':204.74609375}, },
|
143
|
+
{ touch1Point: {'x':785.2578125,'y':72.921875}, touch2Point: {'x':802.9375,'y':201.08203125}, },
|
144
|
+
{ touch1Point: {'x':785.2578125,'y':70.828125}, touch2Point: {'x':802.9375,'y':201.08203125}, },
|
145
|
+
{ touch1Point: {'x':785.2578125,'y':70.828125}, touch2Point: {'x':802.41796875,'y':198.46875}, },
|
146
|
+
{ touch1Point: {'x':785.2578125,'y':68.73828125}, touch2Point: {'x':802.41796875,'y':198.46875}, },
|
147
|
+
{ touch1Point: {'x':785.2578125,'y':68.73828125}, touch2Point: {'x':801.8984375,'y':195.8515625}, },
|
148
|
+
{ touch1Point: {'x':785.2578125,'y':66.64453125}, touch2Point: {'x':801.8984375,'y':195.8515625}, },
|
149
|
+
{ touch1Point: {'x':785.2578125,'y':66.64453125}, touch2Point: {'x':801.37890625,'y':193.23828125}, },
|
150
|
+
{ touch1Point: {'x':785.2578125,'y':64.55078125}, touch2Point: {'x':801.37890625,'y':193.23828125}, },
|
151
|
+
{ touch1Point: {'x':785.2578125,'y':61.9375}, touch2Point: {'x':801.37890625,'y':193.23828125}, },
|
152
|
+
{ touch1Point: {'x':785.2578125,'y':61.9375}, touch2Point: {'x':801.37890625,'y':190.09765625}, },
|
153
|
+
{ touch1Point: {'x':785.2578125,'y':59.84375}, touch2Point: {'x':801.37890625,'y':190.09765625}, },
|
154
|
+
{ touch1Point: {'x':785.77734375,'y':57.23046875}, touch2Point: {'x':801.37890625,'y':190.09765625}, },
|
155
|
+
{ touch1Point: {'x':785.77734375,'y':57.23046875}, touch2Point: {'x':800.859375,'y':187.484375}, },
|
156
|
+
{ touch1Point: {'x':785.77734375,'y':55.13671875}, touch2Point: {'x':800.859375,'y':187.484375}, },
|
157
|
+
{ touch1Point: {'x':785.77734375,'y':55.13671875}, touch2Point: {'x':800.859375,'y':185.390625}, },
|
158
|
+
{ touch1Point: {'x':785.77734375,'y':51.99609375}, touch2Point: {'x':800.859375,'y':185.390625}, },
|
159
|
+
{ touch1Point: {'x':785.77734375,'y':51.99609375}, touch2Point: {'x':800.859375,'y':183.296875}, },
|
160
|
+
{ touch1Point: {'x':785.77734375,'y':49.90625}, touch2Point: {'x':800.859375,'y':183.296875}, },
|
161
|
+
{ touch1Point: {'x':785.77734375,'y':49.90625}, touch2Point: {'x':800.859375,'y':181.20703125}, },
|
162
|
+
{ touch1Point: {'x':785.77734375,'y':47.8125}, touch2Point: {'x':800.859375,'y':181.20703125}, },
|
163
|
+
{ touch1Point: {'x':771.21484375,'y':187.484375}, touch2Point: {'x':753.53515625,'y':321.921875}, },
|
164
|
+
{ touch1Point: {'x':768.09765625,'y':185.390625}, touch2Point: {'x':753.53515625,'y':321.921875}, },
|
165
|
+
{ touch1Point: {'x':763.9375,'y':183.296875}, touch2Point: {'x':753.53515625,'y':321.921875}, },
|
166
|
+
{ touch1Point: {'x':760.81640625,'y':182.25}, touch2Point: {'x':753.53515625,'y':321.921875}, },
|
167
|
+
{ touch1Point: {'x':760.81640625,'y':182.25}, touch2Point: {'x':756.13671875,'y':321.921875}, },
|
168
|
+
{ touch1Point: {'x':757.6953125,'y':181.20703125}, touch2Point: {'x':756.13671875,'y':321.921875}, },
|
169
|
+
{ touch1Point: {'x':755.09375,'y':180.16015625}, touch2Point: {'x':756.13671875,'y':321.921875}, },
|
170
|
+
{ touch1Point: {'x':755.09375,'y':180.16015625}, touch2Point: {'x':758.21484375,'y':321.921875}, },
|
171
|
+
{ touch1Point: {'x':753.015625,'y':179.63671875}, touch2Point: {'x':758.21484375,'y':321.921875}, },
|
172
|
+
{ touch1Point: {'x':750.93359375,'y':179.11328125}, touch2Point: {'x':758.21484375,'y':321.921875}, },
|
173
|
+
{ touch1Point: {'x':750.93359375,'y':179.11328125}, touch2Point: {'x':760.296875,'y':321.921875}, },
|
174
|
+
{ touch1Point: {'x':748.85546875,'y':178.58984375}, touch2Point: {'x':760.296875,'y':321.921875}, },
|
175
|
+
{ touch1Point: {'x':748.85546875,'y':178.58984375}, touch2Point: {'x':763.4140625,'y':321.3984375}, },
|
176
|
+
{ touch1Point: {'x':745.734375,'y':177.54296875}, touch2Point: {'x':763.4140625,'y':321.3984375}, },
|
177
|
+
{ touch1Point: {'x':745.734375,'y':177.54296875}, touch2Point: {'x':766.53515625,'y':320.3515625}, },
|
178
|
+
{ touch1Point: {'x':742.09375,'y':176.49609375}, touch2Point: {'x':766.53515625,'y':320.3515625}, },
|
179
|
+
{ touch1Point: {'x':742.09375,'y':176.49609375}, touch2Point: {'x':768.6171875,'y':319.3046875}, },
|
180
|
+
{ touch1Point: {'x':740.015625,'y':175.97265625}, touch2Point: {'x':768.6171875,'y':319.3046875}, },
|
181
|
+
{ touch1Point: {'x':737.93359375,'y':175.44921875}, touch2Point: {'x':768.6171875,'y':319.3046875}, },
|
182
|
+
{ touch1Point: {'x':737.93359375,'y':175.44921875}, touch2Point: {'x':772.2578125,'y':317.21484375}, },
|
183
|
+
{ touch1Point: {'x':735.33203125,'y':174.9296875}, touch2Point: {'x':772.2578125,'y':317.21484375}, },
|
184
|
+
{ touch1Point: {'x':733.25390625,'y':174.40625}, touch2Point: {'x':772.2578125,'y':317.21484375}, },
|
185
|
+
{ touch1Point: {'x':733.25390625,'y':174.40625}, touch2Point: {'x':775.375,'y':315.12109375}, },
|
186
|
+
{ touch1Point: {'x':731.171875,'y':173.8828125}, touch2Point: {'x':775.375,'y':315.12109375}, },
|
187
|
+
{ touch1Point: {'x':729.09375,'y':173.8828125}, touch2Point: {'x':775.375,'y':315.12109375}, },
|
188
|
+
{ touch1Point: {'x':729.09375,'y':173.8828125}, touch2Point: {'x':778.49609375,'y':313.02734375}, },
|
189
|
+
{ touch1Point: {'x':727.01171875,'y':173.8828125}, touch2Point: {'x':778.49609375,'y':313.02734375}, },
|
190
|
+
{ touch1Point: {'x':727.01171875,'y':173.8828125}, touch2Point: {'x':782.13671875,'y':310.9375}, },
|
191
|
+
{ touch1Point: {'x':723.89453125,'y':173.8828125}, touch2Point: {'x':782.13671875,'y':310.9375}, },
|
192
|
+
{ touch1Point: {'x':723.89453125,'y':173.8828125}, touch2Point: {'x':784.21875,'y':309.890625}, },
|
193
|
+
{ touch1Point: {'x':723.89453125,'y':173.8828125}, touch2Point: {'x':786.296875,'y':308.84375}, },
|
194
|
+
{ touch1Point: {'x':721.8125,'y':173.8828125}, touch2Point: {'x':786.296875,'y':308.84375}, },
|
195
|
+
{ touch1Point: {'x':721.8125,'y':173.8828125}, touch2Point: {'x':788.37890625,'y':307.796875}, },
|
196
|
+
{ touch1Point: {'x':721.8125,'y':173.8828125}, touch2Point: {'x':790.45703125,'y':306.75}, },
|
197
|
+
{ touch1Point: {'x':719.734375,'y':173.8828125}, touch2Point: {'x':790.45703125,'y':306.75}, },
|
198
|
+
{ touch1Point: {'x':719.734375,'y':173.8828125}, touch2Point: {'x':792.5390625,'y':305.703125}, },
|
199
|
+
{ touch1Point: {'x':719.734375,'y':173.8828125}, touch2Point: {'x':795.65625,'y':303.61328125}, },
|
200
|
+
{ touch1Point: {'x':717.65234375,'y':173.8828125}, touch2Point: {'x':795.65625,'y':303.61328125}, },
|
201
|
+
{ touch1Point: {'x':717.65234375,'y':173.8828125}, touch2Point: {'x':798.77734375,'y':302.56640625}, },
|
202
|
+
{ touch1Point: {'x':717.65234375,'y':173.8828125}, touch2Point: {'x':801.8984375,'y':300.47265625}, },
|
203
|
+
{ touch1Point: {'x':715.5703125,'y':173.8828125}, touch2Point: {'x':801.8984375,'y':300.47265625}, },
|
204
|
+
{ touch1Point: {'x':715.5703125,'y':173.8828125}, touch2Point: {'x':805.01953125,'y':297.859375}, },
|
205
|
+
{ touch1Point: {'x':715.5703125,'y':173.8828125}, touch2Point: {'x':806.578125,'y':296.2890625}, },
|
206
|
+
{ touch1Point: {'x':713.4921875,'y':173.8828125}, touch2Point: {'x':806.578125,'y':296.2890625}, },
|
207
|
+
{ touch1Point: {'x':713.4921875,'y':173.8828125}, touch2Point: {'x':809.1796875,'y':294.1953125}, },
|
208
|
+
{ touch1Point: {'x':711.41015625,'y':173.359375}, touch2Point: {'x':809.1796875,'y':294.1953125}, },
|
209
|
+
{ touch1Point: {'x':711.41015625,'y':173.359375}, touch2Point: {'x':811.2578125,'y':292.10546875}, },
|
210
|
+
{ touch1Point: {'x':711.41015625,'y':173.359375}, touch2Point: {'x':813.859375,'y':290.01171875}, },
|
211
|
+
{ touch1Point: {'x':709.33203125,'y':173.359375}, touch2Point: {'x':813.859375,'y':290.01171875}, },
|
212
|
+
{ touch1Point: {'x':709.33203125,'y':173.359375}, touch2Point: {'x':817.5,'y':287.91796875}, },
|
213
|
+
{ touch1Point: {'x':707.25,'y':173.359375}, touch2Point: {'x':817.5,'y':287.91796875}, },
|
214
|
+
{ touch1Point: {'x':707.25,'y':173.359375}, touch2Point: {'x':820.62109375,'y':285.828125}, },
|
215
|
+
{ touch1Point: {'x':705.171875,'y':173.359375}, touch2Point: {'x':820.62109375,'y':285.828125}, },
|
216
|
+
{ touch1Point: {'x':705.171875,'y':173.359375}, touch2Point: {'x':823.73828125,'y':283.734375}, },
|
217
|
+
{ touch1Point: {'x':705.171875,'y':173.359375}, touch2Point: {'x':825.8203125,'y':282.6875}, },
|
218
|
+
{ touch1Point: {'x':703.08984375,'y':173.8828125}, touch2Point: {'x':825.8203125,'y':282.6875}, },
|
219
|
+
{ touch1Point: {'x':703.08984375,'y':173.8828125}, touch2Point: {'x':827.8984375,'y':281.640625}, },
|
220
|
+
{ touch1Point: {'x':703.08984375,'y':173.8828125}, touch2Point: {'x':829.98046875,'y':280.59765625}, },
|
221
|
+
{ touch1Point: {'x':700.4921875,'y':174.9296875}, touch2Point: {'x':829.98046875,'y':280.59765625}, },
|
222
|
+
{ touch1Point: {'x':700.4921875,'y':174.9296875}, touch2Point: {'x':833.1015625,'y':278.50390625}, },
|
223
|
+
{ touch1Point: {'x':697.890625,'y':175.97265625}, touch2Point: {'x':833.1015625,'y':278.50390625}, },
|
224
|
+
{ touch1Point: {'x':697.890625,'y':175.97265625}, touch2Point: {'x':836.22265625,'y':277.45703125}, },
|
225
|
+
{ touch1Point: {'x':694.76953125,'y':177.54296875}, touch2Point: {'x':836.22265625,'y':277.45703125}, },
|
226
|
+
{ touch1Point: {'x':694.76953125,'y':177.54296875}, touch2Point: {'x':838.8203125,'y':276.41015625}, },
|
227
|
+
{ touch1Point: {'x':691.6484375,'y':180.16015625}, touch2Point: {'x':838.8203125,'y':276.41015625}, },
|
228
|
+
{ touch1Point: {'x':690.08984375,'y':181.7265625}, touch2Point: {'x':838.8203125,'y':276.41015625}, },
|
229
|
+
{ touch1Point: {'x':688.53125,'y':183.296875}, touch2Point: {'x':838.8203125,'y':276.41015625}, },
|
230
|
+
{ touch1Point: {'x':688.53125,'y':183.296875}, touch2Point: {'x':840.3828125,'y':274.83984375}, },
|
231
|
+
{ touch1Point: {'x':686.96875,'y':185.390625}, touch2Point: {'x':840.3828125,'y':274.83984375}, },
|
232
|
+
{ touch1Point: {'x':685.41015625,'y':188.00390625}, touch2Point: {'x':840.3828125,'y':274.83984375}, },
|
233
|
+
{ touch1Point: {'x':683.8515625,'y':190.62109375}, touch2Point: {'x':840.3828125,'y':274.83984375}, },
|
234
|
+
{ touch1Point: {'x':683.8515625,'y':190.62109375}, touch2Point: {'x':841.94140625,'y':273.2734375}, },
|
235
|
+
{ touch1Point: {'x':682.2890625,'y':194.28125}, touch2Point: {'x':841.94140625,'y':273.2734375}, },
|
236
|
+
{ touch1Point: {'x':680.73046875,'y':197.9453125}, touch2Point: {'x':841.94140625,'y':273.2734375}, },
|
237
|
+
{ touch1Point: {'x':679.16796875,'y':201.60546875}, touch2Point: {'x':841.94140625,'y':273.2734375}, },
|
238
|
+
{ touch1Point: {'x':677.609375,'y':205.79296875}, touch2Point: {'x':841.94140625,'y':273.2734375}, },
|
239
|
+
{ touch1Point: {'x':677.609375,'y':205.79296875}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
240
|
+
{ touch1Point: {'x':676.5703125,'y':209.453125}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
241
|
+
{ touch1Point: {'x':675.52734375,'y':212.58984375}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
242
|
+
{ touch1Point: {'x':674.48828125,'y':214.68359375}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
243
|
+
{ touch1Point: {'x':673.44921875,'y':216.77734375}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
244
|
+
{ touch1Point: {'x':672.9296875,'y':218.8671875}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
245
|
+
{ touch1Point: {'x':671.890625,'y':221.484375}, touch2Point: {'x':844.0234375,'y':272.2265625}, },
|
246
|
+
{ touch1Point: {'x':671.890625,'y':221.484375}, touch2Point: {'x':844.0234375,'y':270.1328125}, },
|
247
|
+
{ touch1Point: {'x':671.890625,'y':223.578125}, touch2Point: {'x':844.0234375,'y':270.1328125}, },
|
248
|
+
{ touch1Point: {'x':671.890625,'y':223.578125}, touch2Point: {'x':844.0234375,'y':267.51953125}, },
|
249
|
+
{ touch1Point: {'x':671.890625,'y':225.66796875}, touch2Point: {'x':844.0234375,'y':267.51953125}, },
|
250
|
+
{ touch1Point: {'x':671.890625,'y':225.66796875}, touch2Point: {'x':844.0234375,'y':265.42578125}, },
|
251
|
+
{ touch1Point: {'x':671.890625,'y':225.66796875}, touch2Point: {'x':844.54296875,'y':263.33203125}, },
|
252
|
+
{ touch1Point: {'x':671.890625,'y':227.76171875}, touch2Point: {'x':844.54296875,'y':263.33203125}, },
|
253
|
+
{ touch1Point: {'x':671.890625,'y':227.76171875}, touch2Point: {'x':844.54296875,'y':261.2421875}, },
|
254
|
+
{ touch1Point: {'x':672.41015625,'y':229.85546875}, touch2Point: {'x':844.54296875,'y':261.2421875}, },
|
255
|
+
{ touch1Point: {'x':672.41015625,'y':229.85546875}, touch2Point: {'x':844.54296875,'y':259.1484375}, },
|
256
|
+
{ touch1Point: {'x':673.44921875,'y':231.9453125}, touch2Point: {'x':844.54296875,'y':259.1484375}, },
|
257
|
+
{ touch1Point: {'x':673.44921875,'y':231.9453125}, touch2Point: {'x':844.54296875,'y':256.0078125}, },
|
258
|
+
{ touch1Point: {'x':675.0078125,'y':234.5625}, touch2Point: {'x':844.54296875,'y':256.0078125}, },
|
259
|
+
{ touch1Point: {'x':675.0078125,'y':234.5625}, touch2Point: {'x':844.54296875,'y':253.91796875}, },
|
260
|
+
{ touch1Point: {'x':676.05078125,'y':236.65625}, touch2Point: {'x':844.54296875,'y':253.91796875}, },
|
261
|
+
{ touch1Point: {'x':676.05078125,'y':236.65625}, touch2Point: {'x':844.54296875,'y':250.77734375}, },
|
262
|
+
{ touch1Point: {'x':677.609375,'y':238.74609375}, touch2Point: {'x':844.54296875,'y':250.77734375}, },
|
263
|
+
{ touch1Point: {'x':677.609375,'y':238.74609375}, touch2Point: {'x':844.54296875,'y':247.640625}, },
|
264
|
+
{ touch1Point: {'x':678.6484375,'y':240.83984375}, touch2Point: {'x':844.54296875,'y':247.640625}, },
|
265
|
+
{ touch1Point: {'x':678.6484375,'y':240.83984375}, touch2Point: {'x':844.54296875,'y':244.5}, },
|
266
|
+
{ touch1Point: {'x':678.6484375,'y':240.83984375}, touch2Point: {'x':844.54296875,'y':241.36328125}, },
|
267
|
+
{ touch1Point: {'x':680.73046875,'y':242.41015625}, touch2Point: {'x':844.54296875,'y':241.36328125}, },
|
268
|
+
{ touch1Point: {'x':680.73046875,'y':242.41015625}, touch2Point: {'x':844.54296875,'y':238.74609375}, },
|
269
|
+
{ touch1Point: {'x':682.2890625,'y':243.9765625}, touch2Point: {'x':844.54296875,'y':238.74609375}, },
|
270
|
+
{ touch1Point: {'x':682.2890625,'y':243.9765625}, touch2Point: {'x':844.54296875,'y':236.65625}, },
|
271
|
+
{ touch1Point: {'x':683.8515625,'y':245.546875}, touch2Point: {'x':844.54296875,'y':236.65625}, },
|
272
|
+
{ touch1Point: {'x':683.8515625,'y':245.546875}, touch2Point: {'x':844.54296875,'y':234.5625}, },
|
273
|
+
{ touch1Point: {'x':685.9296875,'y':246.0703125}, touch2Point: {'x':844.54296875,'y':234.5625}, },
|
274
|
+
{ touch1Point: {'x':685.9296875,'y':246.0703125}, touch2Point: {'x':844.54296875,'y':232.46875}, },
|
275
|
+
].map(touchPoints => {
|
276
|
+
return [
|
277
|
+
Vec2.ofXY(touchPoints.touch1Point),
|
278
|
+
Vec2.ofXY(touchPoints.touch2Point),
|
279
|
+
];
|
280
|
+
});
|
281
|
+
|
282
|
+
|
283
|
+
const editor = createEditor();
|
284
|
+
selectPanZom(editor);
|
285
|
+
editor.viewport.resetTransform(initialCanvasTransform);
|
286
|
+
|
287
|
+
editor.toolController.getMatchingTools(PanZoom).forEach(tool => {
|
288
|
+
tool.setModeEnabled(PanZoomMode.RotationLocked, false);
|
289
|
+
});
|
290
|
+
|
291
|
+
let lastVisibleRect = editor.viewport.visibleRect;
|
292
|
+
|
293
|
+
|
294
|
+
let firstPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, touchData[0][0]);
|
295
|
+
let secondPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, touchData[0][1], [ firstPointer ]);
|
296
|
+
|
297
|
+
for (const [touch1Point, touch2Point] of touchData) {
|
298
|
+
jest.advanceTimersByTime(10);
|
299
|
+
|
300
|
+
firstPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, touch1Point, [ secondPointer ]);
|
301
|
+
secondPointer = sendTouchEvent(editor, InputEvtType.PointerMoveEvt, touch2Point, [ firstPointer ]);
|
302
|
+
|
303
|
+
const rectCenterDelta = editor.viewport.visibleRect.center.minus(lastVisibleRect.center);
|
304
|
+
|
305
|
+
expect(rectCenterDelta.magnitude()).toBeLessThan(lastVisibleRect.w);
|
306
|
+
|
307
|
+
lastVisibleRect = editor.viewport.visibleRect;
|
308
|
+
}
|
309
|
+
});
|
66
310
|
});
|
package/src/tools/PanZoom.ts
CHANGED
@@ -106,6 +106,13 @@ export default class PanZoom extends BaseTool {
|
|
106
106
|
|
107
107
|
// Returns information about the pointers in a gesture
|
108
108
|
public computePinchData(p1: Pointer, p2: Pointer): PinchData {
|
109
|
+
// Swap the pointers to ensure consistent ordering.
|
110
|
+
if (p1.id < p2.id) {
|
111
|
+
const tmp = p1;
|
112
|
+
p1 = p2;
|
113
|
+
p2 = tmp;
|
114
|
+
}
|
115
|
+
|
109
116
|
const screenBetween = p2.screenPos.minus(p1.screenPos);
|
110
117
|
const angle = screenBetween.angle();
|
111
118
|
const dist = screenBetween.magnitude();
|
@@ -211,6 +218,13 @@ export default class PanZoom extends BaseTool {
|
|
211
218
|
// Snap the rotation
|
212
219
|
if (Math.abs(fullRotation - roundedFullRotation) < maxSnapAngle) {
|
213
220
|
fullRotation = roundedFullRotation;
|
221
|
+
|
222
|
+
// Work around a rotation/matrix multiply bug.
|
223
|
+
// (See commit after 4abe27ff8e7913155828f98dee77b09c57c51d30).
|
224
|
+
// TODO: Fix the underlying issue and remove this.
|
225
|
+
if (fullRotation !== 0) {
|
226
|
+
fullRotation += 0.0001;
|
227
|
+
}
|
214
228
|
}
|
215
229
|
|
216
230
|
return fullRotation - this.editor.viewport.getRotationAngle();
|
@@ -228,12 +242,12 @@ export default class PanZoom extends BaseTool {
|
|
228
242
|
deltaRotation = this.toSnappedRotationDelta(angle);
|
229
243
|
}
|
230
244
|
|
231
|
-
|
232
245
|
this.updateVelocity(screenCenter);
|
233
246
|
|
234
247
|
const transformUpdate = Mat33.translation(delta)
|
235
248
|
.rightMul(Mat33.scaling2D(dist / this.lastDist, canvasCenter))
|
236
249
|
.rightMul(Mat33.zRotation(deltaRotation, canvasCenter));
|
250
|
+
|
237
251
|
this.lastScreenCenter = screenCenter;
|
238
252
|
this.lastDist = dist;
|
239
253
|
this.transform = Viewport.transformBy(
|
@@ -324,7 +324,7 @@ export default class Selection {
|
|
324
324
|
}
|
325
325
|
|
326
326
|
this.selectedElems = this.editor.image.getElementsIntersectingRegion(this.region).filter(elem => {
|
327
|
-
return elem.intersectsRect(this.region);
|
327
|
+
return elem.intersectsRect(this.region) && elem.isSelectable();
|
328
328
|
});
|
329
329
|
|
330
330
|
if (singleItemSelectionMode && this.selectedElems.length > 0) {
|