js-draw 1.7.1 → 1.8.0
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/dist/Editor.css +1 -0
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.js +4 -4
- package/dist/cjs/EventDispatcher.js +2 -1
- package/dist/cjs/Viewport.d.ts +2 -0
- package/dist/cjs/Viewport.js +2 -0
- package/dist/cjs/components/AbstractComponent.d.ts +9 -0
- package/dist/cjs/components/AbstractComponent.js +11 -0
- package/dist/cjs/components/Stroke.d.ts +3 -0
- package/dist/cjs/components/Stroke.js +55 -1
- package/dist/cjs/image/EditorImage.js +17 -1
- package/dist/cjs/rendering/RenderablePathSpec.d.ts +20 -2
- package/dist/cjs/rendering/RenderablePathSpec.js +72 -9
- package/dist/cjs/rendering/caching/CacheRecord.js +5 -3
- package/dist/cjs/rendering/renderers/AbstractRenderer.d.ts +10 -0
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +12 -3
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +2 -2
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +0 -10
- package/dist/cjs/rendering/renderers/SVGRenderer.js +0 -14
- package/dist/cjs/testing/startPinchGesture.d.ts +14 -0
- package/dist/cjs/testing/startPinchGesture.js +41 -0
- package/dist/cjs/tools/PanZoom.d.ts +4 -0
- package/dist/cjs/tools/PanZoom.js +21 -2
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.mjs +4 -4
- package/dist/mjs/EventDispatcher.mjs +2 -1
- package/dist/mjs/Viewport.d.ts +2 -0
- package/dist/mjs/Viewport.mjs +2 -0
- package/dist/mjs/components/AbstractComponent.d.ts +9 -0
- package/dist/mjs/components/AbstractComponent.mjs +11 -0
- package/dist/mjs/components/Stroke.d.ts +3 -0
- package/dist/mjs/components/Stroke.mjs +56 -2
- package/dist/mjs/image/EditorImage.mjs +17 -1
- package/dist/mjs/rendering/RenderablePathSpec.d.ts +20 -2
- package/dist/mjs/rendering/RenderablePathSpec.mjs +71 -9
- package/dist/mjs/rendering/caching/CacheRecord.mjs +5 -3
- package/dist/mjs/rendering/renderers/AbstractRenderer.d.ts +10 -0
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +12 -3
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +2 -2
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +0 -10
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +0 -14
- package/dist/mjs/testing/startPinchGesture.d.ts +14 -0
- package/dist/mjs/testing/startPinchGesture.mjs +36 -0
- package/dist/mjs/tools/PanZoom.d.ts +4 -0
- package/dist/mjs/tools/PanZoom.mjs +21 -2
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -3
- package/src/Editor.scss +2 -0
@@ -15,8 +15,11 @@ export default class AbstractRenderer {
|
|
15
15
|
this.objectLevel = 0;
|
16
16
|
this.currentPaths = null;
|
17
17
|
}
|
18
|
-
|
19
|
-
|
18
|
+
/**
|
19
|
+
* this.canvasToScreen, etc. should be used instead of the corresponding
|
20
|
+
* methods on `Viewport`, because the viewport may not accurately reflect
|
21
|
+
* what is rendered.
|
22
|
+
*/
|
20
23
|
getViewport() { return this.viewport; }
|
21
24
|
setDraftMode(_draftMode) { }
|
22
25
|
flushPath() {
|
@@ -158,12 +161,18 @@ export default class AbstractRenderer {
|
|
158
161
|
getSizeOfCanvasPixelOnScreen() {
|
159
162
|
return this.getCanvasToScreenTransform().transformVec3(Vec2.unitX).length();
|
160
163
|
}
|
164
|
+
/**
|
165
|
+
* @internal
|
166
|
+
*/
|
167
|
+
overrideVisibleRect(rect) {
|
168
|
+
this.visibleRectOverride = rect;
|
169
|
+
}
|
161
170
|
// Returns the region in canvas space that is visible within the viewport this
|
162
171
|
// canvas is rendering to.
|
163
172
|
//
|
164
173
|
// Note that in some cases this might not be the same as the `visibleRect` given
|
165
174
|
// to components in their `render` method.
|
166
175
|
getVisibleRect() {
|
167
|
-
return this.viewport.visibleRect;
|
176
|
+
return this.visibleRectOverride ?? this.viewport.visibleRect;
|
168
177
|
}
|
169
178
|
}
|
@@ -144,7 +144,7 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
144
144
|
return;
|
145
145
|
}
|
146
146
|
// If part of a huge object, it might be worth trimming the path
|
147
|
-
const visibleRect = this.
|
147
|
+
const visibleRect = this.getVisibleRect();
|
148
148
|
if (this.currentObjectBBox?.containsRect(visibleRect)) {
|
149
149
|
// Try to trim/remove parts of the path outside of the bounding box.
|
150
150
|
path = visualEquivalent(path, visibleRect);
|
@@ -184,7 +184,7 @@ export default class CanvasRenderer extends AbstractRenderer {
|
|
184
184
|
if (!this.ignoringObject && clip) {
|
185
185
|
// Don't clip if it would only remove content already trimmed by
|
186
186
|
// the edge of the screen.
|
187
|
-
const clippedIsOutsideScreen = boundingBox.containsRect(this.
|
187
|
+
const clippedIsOutsideScreen = boundingBox.containsRect(this.getVisibleRect());
|
188
188
|
if (!clippedIsOutsideScreen) {
|
189
189
|
this.clipLevels.push(this.objectLevel);
|
190
190
|
this.ctx.save();
|
@@ -59,16 +59,6 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
59
59
|
drawPoints(...points: Point2[]): void;
|
60
60
|
drawSVGElem(elem: SVGElement): void;
|
61
61
|
isTooSmallToRender(_rect: Rect2): boolean;
|
62
|
-
private visibleRectOverride;
|
63
|
-
/**
|
64
|
-
* Overrides the visible region returned by `getVisibleRect`.
|
65
|
-
*
|
66
|
-
* This is useful when the `viewport`'s transform has been modified,
|
67
|
-
* for example, to compensate for storing part of the image's
|
68
|
-
* transformation in an SVG property.
|
69
|
-
*/
|
70
|
-
private overrideVisibleRect;
|
71
|
-
getVisibleRect(): Rect2;
|
72
62
|
/**
|
73
63
|
* Creates a new SVG element and `SVGRenerer` with `width`, `height`, `viewBox`,
|
74
64
|
* and other metadata attributes set for the given `Viewport`.
|
@@ -36,7 +36,6 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
36
36
|
this.textContainer = null;
|
37
37
|
this.textContainerTransform = null;
|
38
38
|
this.textParentStyle = defaultTextStyle;
|
39
|
-
this.visibleRectOverride = null;
|
40
39
|
this.clear();
|
41
40
|
this.addStyleSheet();
|
42
41
|
}
|
@@ -339,19 +338,6 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
339
338
|
isTooSmallToRender(_rect) {
|
340
339
|
return false;
|
341
340
|
}
|
342
|
-
/**
|
343
|
-
* Overrides the visible region returned by `getVisibleRect`.
|
344
|
-
*
|
345
|
-
* This is useful when the `viewport`'s transform has been modified,
|
346
|
-
* for example, to compensate for storing part of the image's
|
347
|
-
* transformation in an SVG property.
|
348
|
-
*/
|
349
|
-
overrideVisibleRect(newRect) {
|
350
|
-
this.visibleRectOverride = newRect;
|
351
|
-
}
|
352
|
-
getVisibleRect() {
|
353
|
-
return this.visibleRectOverride ?? super.getVisibleRect();
|
354
|
-
}
|
355
341
|
/**
|
356
342
|
* Creates a new SVG element and `SVGRenerer` with `width`, `height`, `viewBox`,
|
357
343
|
* and other metadata attributes set for the given `Viewport`.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import type Editor from '../Editor';
|
2
|
+
import { Point2 } from '@js-draw/math';
|
3
|
+
/**
|
4
|
+
* Creates two pointers and sends the touch {@link InputEvtType.PointerDownEvt}s for them.
|
5
|
+
*
|
6
|
+
* Returns an object that allows continuing or ending the gesture.
|
7
|
+
*
|
8
|
+
* `initialRotation` should be in radians.
|
9
|
+
*/
|
10
|
+
declare const startPinchGesture: (editor: Editor, center: Point2, initialDistance: number, initialRotation: number) => {
|
11
|
+
update(center: Point2, distance: number, rotation: number): void;
|
12
|
+
end(): void;
|
13
|
+
};
|
14
|
+
export default startPinchGesture;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { Mat33, Vec2 } from '@js-draw/math';
|
2
|
+
import sendTouchEvent from './sendTouchEvent.mjs';
|
3
|
+
import { InputEvtType } from '../inputEvents.mjs';
|
4
|
+
/**
|
5
|
+
* Creates two pointers and sends the touch {@link InputEvtType.PointerDownEvt}s for them.
|
6
|
+
*
|
7
|
+
* Returns an object that allows continuing or ending the gesture.
|
8
|
+
*
|
9
|
+
* `initialRotation` should be in radians.
|
10
|
+
*/
|
11
|
+
const startPinchGesture = (editor, center, initialDistance, initialRotation) => {
|
12
|
+
const computeTouchPoints = (center, distance, rotation) => {
|
13
|
+
const halfDisplacement = Mat33.zRotation(rotation).transformVec2(Vec2.of(0, distance / 2));
|
14
|
+
const point1 = center.plus(halfDisplacement);
|
15
|
+
const point2 = center.minus(halfDisplacement);
|
16
|
+
return [point1, point2];
|
17
|
+
};
|
18
|
+
let [touchPoint1, touchPoint2] = computeTouchPoints(center, initialDistance, initialRotation);
|
19
|
+
let firstPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, touchPoint1);
|
20
|
+
let secondPointer = sendTouchEvent(editor, InputEvtType.PointerDownEvt, touchPoint2, [firstPointer]);
|
21
|
+
return {
|
22
|
+
update(center, distance, rotation) {
|
23
|
+
const eventType = InputEvtType.PointerMoveEvt;
|
24
|
+
const [newPoint1, newPoint2] = computeTouchPoints(center, distance, rotation);
|
25
|
+
touchPoint1 = newPoint1;
|
26
|
+
touchPoint2 = newPoint2;
|
27
|
+
firstPointer = sendTouchEvent(editor, eventType, newPoint1, [secondPointer]);
|
28
|
+
secondPointer = sendTouchEvent(editor, eventType, newPoint2, [firstPointer]);
|
29
|
+
},
|
30
|
+
end() {
|
31
|
+
sendTouchEvent(editor, InputEvtType.PointerUpEvt, touchPoint1, [secondPointer]);
|
32
|
+
sendTouchEvent(editor, InputEvtType.PointerUpEvt, touchPoint2);
|
33
|
+
},
|
34
|
+
};
|
35
|
+
};
|
36
|
+
export default startPinchGesture;
|
@@ -21,6 +21,9 @@ export default class PanZoom extends BaseTool {
|
|
21
21
|
private editor;
|
22
22
|
private mode;
|
23
23
|
private transform;
|
24
|
+
private readonly initialRotationSnapAngle;
|
25
|
+
private readonly afterRotationStartSnapAngle;
|
26
|
+
private readonly pinchZoomStartThreshold;
|
24
27
|
private startDist;
|
25
28
|
private lastDist;
|
26
29
|
private lastScreenCenter;
|
@@ -29,6 +32,7 @@ export default class PanZoom extends BaseTool {
|
|
29
32
|
private initialTouchAngle;
|
30
33
|
private initialViewportRotation;
|
31
34
|
private isScaling;
|
35
|
+
private isRotating;
|
32
36
|
private inertialScroller;
|
33
37
|
private velocity;
|
34
38
|
constructor(editor: Editor, mode: PanZoomMode, description: string);
|
@@ -65,12 +65,19 @@ export default class PanZoom extends BaseTool {
|
|
65
65
|
this.editor = editor;
|
66
66
|
this.mode = mode;
|
67
67
|
this.transform = null;
|
68
|
+
// Constants
|
69
|
+
// initialRotationSnapAngle is larger than afterRotationStartSnapAngle to
|
70
|
+
// make it more difficult to start rotating (and easier to continue rotating).
|
71
|
+
this.initialRotationSnapAngle = 0.22; // radians
|
72
|
+
this.afterRotationStartSnapAngle = 0.07; // radians
|
73
|
+
this.pinchZoomStartThreshold = 1.08; // scale factor
|
68
74
|
this.lastPointerDownTimestamp = 0;
|
69
75
|
this.initialTouchAngle = 0;
|
70
76
|
this.initialViewportRotation = 0;
|
71
77
|
// Set to `true` only when scaling has started (if two fingers are down and have moved
|
72
78
|
// far enough).
|
73
79
|
this.isScaling = false;
|
80
|
+
this.isRotating = false;
|
74
81
|
this.inertialScroller = null;
|
75
82
|
this.velocity = null;
|
76
83
|
}
|
@@ -112,6 +119,9 @@ export default class PanZoom extends BaseTool {
|
|
112
119
|
this.initialTouchAngle = angle;
|
113
120
|
this.initialViewportRotation = this.editor.viewport.getRotationAngle();
|
114
121
|
this.isScaling = false;
|
122
|
+
// We're initially rotated if `initialViewportRotation` isn't near a multiple of pi/2.
|
123
|
+
// In other words, if sin(2 initialViewportRotation) is near zero.
|
124
|
+
this.isRotating = Math.abs(Math.sin(this.initialViewportRotation * 2)) > 1e-3;
|
115
125
|
handlingGesture = true;
|
116
126
|
}
|
117
127
|
else if (pointers.length === 1 && ((this.mode & PanZoomMode.OneFingerTouchGestures && allAreTouch)
|
@@ -168,7 +178,9 @@ export default class PanZoom extends BaseTool {
|
|
168
178
|
const roundedFullRotation = Math.round(fullRotation / snapToMultipleOf) * snapToMultipleOf;
|
169
179
|
// The maximum angle for which we snap the given angle to a multiple of
|
170
180
|
// `snapToMultipleOf`.
|
171
|
-
|
181
|
+
// Use a smaller snap angle if already rotated (to avoid pinch zoom gestures from
|
182
|
+
// starting rotation).
|
183
|
+
const maxSnapAngle = this.isRotating ? this.afterRotationStartSnapAngle : this.initialRotationSnapAngle;
|
172
184
|
// Snap the rotation
|
173
185
|
if (Math.abs(fullRotation - roundedFullRotation) < maxSnapAngle) {
|
174
186
|
fullRotation = roundedFullRotation;
|
@@ -191,6 +203,11 @@ export default class PanZoom extends BaseTool {
|
|
191
203
|
else {
|
192
204
|
deltaRotation = this.toSnappedRotationDelta(angle);
|
193
205
|
}
|
206
|
+
// If any rotation, make a note of this (affects rotation snap
|
207
|
+
// angles).
|
208
|
+
if (Math.abs(deltaRotation) > 1e-8) {
|
209
|
+
this.isRotating = true;
|
210
|
+
}
|
194
211
|
this.updateVelocity(screenCenter);
|
195
212
|
let scaleFactor = 1;
|
196
213
|
if (this.isScaling) {
|
@@ -199,7 +216,9 @@ export default class PanZoom extends BaseTool {
|
|
199
216
|
else {
|
200
217
|
const initialScaleFactor = dist / this.startDist;
|
201
218
|
// Only start scaling if scaling done so far exceeds some threshold.
|
202
|
-
|
219
|
+
const upperBound = this.pinchZoomStartThreshold;
|
220
|
+
const lowerBound = 1 / this.pinchZoomStartThreshold;
|
221
|
+
if (initialScaleFactor > upperBound || initialScaleFactor < lowerBound) {
|
203
222
|
scaleFactor = initialScaleFactor;
|
204
223
|
this.isScaling = true;
|
205
224
|
}
|
package/dist/mjs/version.mjs
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "js-draw",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.8.0",
|
4
4
|
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -64,7 +64,7 @@
|
|
64
64
|
"postpack": "ts-node tools/copyREADME.ts revert"
|
65
65
|
},
|
66
66
|
"dependencies": {
|
67
|
-
"@js-draw/math": "^1.
|
67
|
+
"@js-draw/math": "^1.8.0",
|
68
68
|
"@melloware/coloris": "0.21.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "89f7991833dec5c17ce0890321286198ff7b1900"
|
90
90
|
}
|