js-draw 1.15.0 → 1.16.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor.css +14 -0
- package/dist/bundle.js +1 -1
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +4 -1
- package/dist/cjs/Editor.js +25 -2
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +1 -1
- package/dist/cjs/tools/PanZoom.d.ts +8 -2
- package/dist/cjs/tools/PanZoom.js +29 -10
- package/dist/cjs/tools/PasteHandler.js +4 -0
- package/dist/cjs/tools/SelectionTool/Selection.js +16 -2
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +4 -1
- package/dist/mjs/Editor.mjs +25 -2
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +1 -1
- package/dist/mjs/tools/PanZoom.d.ts +8 -2
- package/dist/mjs/tools/PanZoom.mjs +29 -10
- package/dist/mjs/tools/PasteHandler.mjs +4 -0
- package/dist/mjs/tools/SelectionTool/Selection.mjs +16 -2
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -3
- package/src/Editor.scss +10 -0
- package/src/toolbar/EdgeToolbar.scss +2 -0
- package/src/tools/SelectionTool/SelectionTool.scss +4 -0
- package/src/tools/SoundUITool.scss +4 -1
@@ -71,9 +71,11 @@ export default class PanZoom extends BaseTool {
|
|
71
71
|
this.initialRotationSnapAngle = 0.22; // radians
|
72
72
|
this.afterRotationStartSnapAngle = 0.07; // radians
|
73
73
|
this.pinchZoomStartThreshold = 1.08; // scale factor
|
74
|
+
// Last timestamp at which a pointerdown event was received
|
74
75
|
this.lastPointerDownTimestamp = 0;
|
75
76
|
this.initialTouchAngle = 0;
|
76
77
|
this.initialViewportRotation = 0;
|
78
|
+
this.initialViewportScale = 0;
|
77
79
|
// Set to `true` only when scaling has started (if two fingers are down and have moved
|
78
80
|
// far enough).
|
79
81
|
this.isScaling = false;
|
@@ -113,11 +115,12 @@ export default class PanZoom extends BaseTool {
|
|
113
115
|
const isRightClick = this.allPointersAreOfType(pointers, PointerDevice.RightButtonMouse);
|
114
116
|
if (allAreTouch && pointers.length === 2 && this.mode & PanZoomMode.TwoFingerTouchGestures) {
|
115
117
|
const { screenCenter, angle, dist } = this.computePinchData(pointers[0], pointers[1]);
|
116
|
-
this.
|
117
|
-
this.
|
118
|
+
this.lastTouchDist = dist;
|
119
|
+
this.startTouchDist = dist;
|
118
120
|
this.lastScreenCenter = screenCenter;
|
119
121
|
this.initialTouchAngle = angle;
|
120
122
|
this.initialViewportRotation = this.editor.viewport.getRotationAngle();
|
123
|
+
this.initialViewportScale = this.editor.viewport.getScaleFactor();
|
121
124
|
this.isScaling = false;
|
122
125
|
// We're initially rotated if `initialViewportRotation` isn't near a multiple of pi/2.
|
123
126
|
// In other words, if sin(2 initialViewportRotation) is near zero.
|
@@ -193,6 +196,22 @@ export default class PanZoom extends BaseTool {
|
|
193
196
|
}
|
194
197
|
return fullRotation - this.editor.viewport.getRotationAngle();
|
195
198
|
}
|
199
|
+
/**
|
200
|
+
* Given a scale update, `scaleFactor`, returns a new scale factor snapped
|
201
|
+
* to a power of two (if within some tolerance of that scale).
|
202
|
+
*/
|
203
|
+
toSnappedScaleFactor(touchDist) {
|
204
|
+
// scaleFactor is applied to the current transformation of the viewport.
|
205
|
+
const newScale = this.initialViewportScale * touchDist / this.startTouchDist;
|
206
|
+
const currentScale = this.editor.viewport.getScaleFactor();
|
207
|
+
const logNewScale = Math.log(newScale) / Math.log(10);
|
208
|
+
const roundedLogNewScale = Math.round(logNewScale);
|
209
|
+
const logTolerance = 0.04;
|
210
|
+
if (Math.abs(roundedLogNewScale - logNewScale) < logTolerance) {
|
211
|
+
return Math.pow(10, roundedLogNewScale) / currentScale;
|
212
|
+
}
|
213
|
+
return touchDist / this.lastTouchDist;
|
214
|
+
}
|
196
215
|
handleTwoFingerMove(allPointers) {
|
197
216
|
const { screenCenter, canvasCenter, angle, dist } = this.computePinchData(allPointers[0], allPointers[1]);
|
198
217
|
const delta = this.getCenterDelta(screenCenter);
|
@@ -209,25 +228,25 @@ export default class PanZoom extends BaseTool {
|
|
209
228
|
this.isRotating = true;
|
210
229
|
}
|
211
230
|
this.updateVelocity(screenCenter);
|
212
|
-
|
213
|
-
|
214
|
-
scaleFactor = dist / this.lastDist;
|
215
|
-
}
|
216
|
-
else {
|
217
|
-
const initialScaleFactor = dist / this.startDist;
|
231
|
+
if (!this.isScaling) {
|
232
|
+
const initialScaleFactor = dist / this.startTouchDist;
|
218
233
|
// Only start scaling if scaling done so far exceeds some threshold.
|
219
234
|
const upperBound = this.pinchZoomStartThreshold;
|
220
235
|
const lowerBound = 1 / this.pinchZoomStartThreshold;
|
221
236
|
if (initialScaleFactor > upperBound || initialScaleFactor < lowerBound) {
|
222
|
-
scaleFactor = initialScaleFactor;
|
223
237
|
this.isScaling = true;
|
224
238
|
}
|
225
239
|
}
|
240
|
+
let scaleFactor = 1;
|
241
|
+
if (this.isScaling) {
|
242
|
+
scaleFactor = this.toSnappedScaleFactor(dist);
|
243
|
+
// Don't set lastDist until we start scaling --
|
244
|
+
this.lastTouchDist = dist;
|
245
|
+
}
|
226
246
|
const transformUpdate = Mat33.translation(delta)
|
227
247
|
.rightMul(Mat33.scaling2D(scaleFactor, canvasCenter))
|
228
248
|
.rightMul(Mat33.zRotation(deltaRotation, canvasCenter));
|
229
249
|
this.lastScreenCenter = screenCenter;
|
230
|
-
this.lastDist = dist;
|
231
250
|
this.transform = Viewport.transformBy(this.transform.transform.rightMul(transformUpdate));
|
232
251
|
return transformUpdate;
|
233
252
|
}
|
@@ -62,6 +62,10 @@ export default class PasteHandler extends BaseTool {
|
|
62
62
|
});
|
63
63
|
const defaultTextStyle = { size: 12, fontFamily: 'sans', renderingStyle: { fill: Color4.red } };
|
64
64
|
const pastedTextStyle = textTools[0]?.getTextStyle() ?? defaultTextStyle;
|
65
|
+
// Don't paste text that would be invisible.
|
66
|
+
if (text.trim() === '') {
|
67
|
+
return;
|
68
|
+
}
|
65
69
|
const lines = text.split('\n');
|
66
70
|
await this.addComponentsFromPaste([TextComponent.fromLines(lines, Mat33.identity, pastedTextStyle)]);
|
67
71
|
}
|
@@ -80,6 +80,7 @@ class Selection {
|
|
80
80
|
for (const handle of this.handles) {
|
81
81
|
handle.addTo(this.backgroundElem);
|
82
82
|
}
|
83
|
+
this.updateUI();
|
83
84
|
}
|
84
85
|
// @internal Intended for unit tests
|
85
86
|
getBackgroundElem() {
|
@@ -285,6 +286,13 @@ class Selection {
|
|
285
286
|
else {
|
286
287
|
this.innerContainer.classList.remove(perpendicularClassName);
|
287
288
|
}
|
289
|
+
// Hide handles when empty
|
290
|
+
if (screenRegion.width === 0 && screenRegion.height === 0) {
|
291
|
+
this.innerContainer.classList.add('-empty');
|
292
|
+
}
|
293
|
+
else {
|
294
|
+
this.innerContainer.classList.remove('-empty');
|
295
|
+
}
|
288
296
|
for (const handle of this.handles) {
|
289
297
|
handle.updatePosition();
|
290
298
|
}
|
@@ -533,7 +541,11 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
533
541
|
this.transformCommands = this.selectedElemIds.map(id => {
|
534
542
|
const elem = editor.image.lookupElement(id);
|
535
543
|
if (!elem) {
|
536
|
-
|
544
|
+
// There may be valid reasons for an element lookup to fail:
|
545
|
+
// For example, if the element was deleted remotely and the remote deletion
|
546
|
+
// hasn't been undone.
|
547
|
+
console.warn(`Unable to find element with ID, ${id}.`);
|
548
|
+
return null;
|
537
549
|
}
|
538
550
|
let originalZIndex = elem.getZIndex();
|
539
551
|
let targetZIndex = elem.getZIndex() + this.deltaZIndex;
|
@@ -544,7 +556,9 @@ Selection.ApplyTransformationCommand = class extends SerializableCommand {
|
|
544
556
|
originalZIndex = elem.getZIndex() - this.deltaZIndex;
|
545
557
|
}
|
546
558
|
return elem.setZIndexAndTransformBy(this.fullTransform, targetZIndex, originalZIndex);
|
547
|
-
})
|
559
|
+
}).filter(// Remove all null commands
|
560
|
+
// Remove all null commands
|
561
|
+
command => command !== null);
|
548
562
|
}
|
549
563
|
async apply(editor) {
|
550
564
|
this.resolveToElems(editor, false);
|
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.16.1",
|
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.16.0",
|
68
68
|
"@melloware/coloris": "0.22.0"
|
69
69
|
},
|
70
70
|
"devDependencies": {
|
@@ -86,5 +86,5 @@
|
|
86
86
|
"freehand",
|
87
87
|
"svg"
|
88
88
|
],
|
89
|
-
"gitHead": "
|
89
|
+
"gitHead": "7a1d4ea8bae0a2549494fce672b9d43ce97a68a8"
|
90
90
|
}
|
package/src/Editor.scss
CHANGED
@@ -118,6 +118,10 @@
|
|
118
118
|
max-width: inherit;
|
119
119
|
min-height: 0px;
|
120
120
|
max-height: inherit;
|
121
|
+
|
122
|
+
user-select: none;
|
123
|
+
-webkit-user-select: none;
|
124
|
+
-webkit-user-drag: none;
|
121
125
|
}
|
122
126
|
|
123
127
|
.imageEditorContainer .loadingMessage {
|
@@ -137,7 +141,10 @@
|
|
137
141
|
width: 0;
|
138
142
|
height: 0;
|
139
143
|
overflow: hidden;
|
144
|
+
|
140
145
|
pointer-events: none;
|
146
|
+
user-select: none;
|
147
|
+
-webkit-user-select: none;
|
141
148
|
}
|
142
149
|
|
143
150
|
.imageEditorContainer .textRendererOutputContainer {
|
@@ -146,6 +153,9 @@
|
|
146
153
|
width: 0.001px;
|
147
154
|
height: 0.001px;
|
148
155
|
overflow: hidden;
|
156
|
+
|
157
|
+
-webkit-user-select: none;
|
158
|
+
user-select: none;
|
149
159
|
}
|
150
160
|
|
151
161
|
.imageEditorContainer .textRendererOutputContainer:focus-within {
|
@@ -335,6 +335,7 @@
|
|
335
335
|
|
336
336
|
touch-action: none;
|
337
337
|
user-select: none;
|
338
|
+
-webkit-user-select: none;
|
338
339
|
|
339
340
|
background-color: var(--background-color-2);
|
340
341
|
color: var(--foreground-color-2);
|
@@ -356,6 +357,7 @@
|
|
356
357
|
|
357
358
|
input, textarea {
|
358
359
|
user-select: auto;
|
360
|
+
-webkit-user-select: auto;
|
359
361
|
}
|
360
362
|
|
361
363
|
.toolbar-toolContainer {
|