js-draw 0.11.0 → 0.11.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 +8 -0
- package/dist/bundle.js +1 -1
- package/dist/src/Editor.d.ts +9 -2
- package/dist/src/Editor.js +24 -14
- package/dist/src/EditorImage.js +1 -1
- package/dist/src/tools/Eraser.d.ts +1 -1
- package/dist/src/tools/Eraser.js +18 -18
- package/dist/src/tools/SelectionTool/Selection.d.ts +2 -3
- package/dist/src/tools/SelectionTool/Selection.js +63 -26
- package/dist/src/tools/SelectionTool/SelectionTool.js +9 -0
- package/package.json +1 -1
- package/src/Editor.ts +28 -15
- package/src/EditorImage.ts +1 -1
- package/src/tools/Eraser.ts +21 -15
- package/src/tools/SelectionTool/Selection.ts +62 -22
- package/src/tools/SelectionTool/SelectionTool.ts +12 -0
@@ -19,8 +19,10 @@ import Duplicate from '../../commands/Duplicate';
|
|
19
19
|
import Command from '../../commands/Command';
|
20
20
|
import { DragTransformer, ResizeTransformer, RotateTransformer } from './TransformMode';
|
21
21
|
import { ResizeMode } from './types';
|
22
|
+
import EditorImage from '../../EditorImage';
|
22
23
|
|
23
24
|
const updateChunkSize = 100;
|
25
|
+
const maxPreviewElemCount = 500;
|
24
26
|
|
25
27
|
// @internal
|
26
28
|
export default class Selection {
|
@@ -28,9 +30,7 @@ export default class Selection {
|
|
28
30
|
private originalRegion: Rect2;
|
29
31
|
|
30
32
|
private transformers;
|
31
|
-
|
32
33
|
private transform: Mat33 = Mat33.identity;
|
33
|
-
private transformCommands: SerializableCommand[] = [];
|
34
34
|
|
35
35
|
private selectedElems: AbstractComponent[] = [];
|
36
36
|
|
@@ -147,33 +147,22 @@ export default class Selection {
|
|
147
147
|
return this.regionRotation + this.editor.viewport.getRotationAngle();
|
148
148
|
}
|
149
149
|
|
150
|
-
private computeTransformCommands(): SerializableCommand[] {
|
151
|
-
return this.selectedElems.map(elem => {
|
152
|
-
return elem.transformBy(this.transform);
|
153
|
-
});
|
154
|
-
}
|
155
|
-
|
156
150
|
// Applies, previews, but doesn't finalize the given transformation.
|
157
151
|
public setTransform(transform: Mat33, preview: boolean = true) {
|
158
152
|
this.transform = transform;
|
159
153
|
|
160
154
|
if (preview && this.hasParent) {
|
161
|
-
this.previewTransformCmds();
|
162
155
|
this.scrollTo();
|
156
|
+
this.previewTransformCmds();
|
163
157
|
}
|
164
158
|
}
|
165
159
|
|
166
160
|
// Applies the current transformation to the selection
|
167
161
|
public finalizeTransform() {
|
168
|
-
this.transformCommands.forEach(cmd => {
|
169
|
-
cmd.unapply(this.editor);
|
170
|
-
});
|
171
|
-
|
172
162
|
const fullTransform = this.transform;
|
173
163
|
const selectedElems = this.selectedElems;
|
174
164
|
|
175
165
|
// Reset for the next drag
|
176
|
-
this.transformCommands = [];
|
177
166
|
this.originalRegion = this.originalRegion.transformedBoundingBox(this.transform);
|
178
167
|
this.transform = Mat33.identity;
|
179
168
|
|
@@ -277,14 +266,23 @@ export default class Selection {
|
|
277
266
|
// Preview the effects of the current transformation on the selection
|
278
267
|
private previewTransformCmds() {
|
279
268
|
// Don't render what we're moving if it's likely to be slow.
|
280
|
-
if (this.selectedElems.length >
|
269
|
+
if (this.selectedElems.length > maxPreviewElemCount) {
|
281
270
|
this.updateUI();
|
282
271
|
return;
|
283
272
|
}
|
284
273
|
|
285
|
-
this.
|
286
|
-
|
287
|
-
|
274
|
+
const wetInkRenderer = this.editor.display.getWetInkRenderer();
|
275
|
+
wetInkRenderer.clear();
|
276
|
+
wetInkRenderer.pushTransform(this.transform);
|
277
|
+
|
278
|
+
const viewportVisibleRect = this.editor.viewport.visibleRect;
|
279
|
+
const visibleRect = viewportVisibleRect.transformedBoundingBox(this.transform.inverse());
|
280
|
+
|
281
|
+
for (const elem of this.selectedElems) {
|
282
|
+
elem.render(wetInkRenderer, visibleRect);
|
283
|
+
}
|
284
|
+
|
285
|
+
wetInkRenderer.popTransform();
|
288
286
|
|
289
287
|
this.updateUI();
|
290
288
|
}
|
@@ -394,9 +392,44 @@ export default class Selection {
|
|
394
392
|
}
|
395
393
|
}
|
396
394
|
|
395
|
+
// Add/remove the contents of this' seleciton from the editor.
|
396
|
+
// Used to prevent previewed content from looking like duplicate content
|
397
|
+
// while dragging.
|
398
|
+
//
|
399
|
+
// Does nothing if a large number of elements are selected (and so modifying
|
400
|
+
// the editor image is likely to be slow.)
|
401
|
+
//
|
402
|
+
// If removed from the image, selected elements are drawn as wet ink.
|
403
|
+
private async addRemoveSelectionFromImage(inImage: boolean) {
|
404
|
+
// Don't hide elements if doing so will be slow.
|
405
|
+
if (!inImage && this.selectedElems.length > maxPreviewElemCount) {
|
406
|
+
return;
|
407
|
+
}
|
408
|
+
|
409
|
+
for (const elem of this.selectedElems) {
|
410
|
+
const parent = this.editor.image.findParent(elem);
|
411
|
+
|
412
|
+
if (!inImage) {
|
413
|
+
parent?.remove();
|
414
|
+
}
|
415
|
+
// If we're making things visible and the selected object wasn't previously
|
416
|
+
// visible,
|
417
|
+
else if (!parent) {
|
418
|
+
EditorImage.addElement(elem).apply(this.editor);
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
422
|
+
await this.editor.queueRerender();
|
423
|
+
if (!inImage) {
|
424
|
+
this.previewTransformCmds();
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
397
428
|
private targetHandle: SelectionHandle|null = null;
|
398
429
|
private backgroundDragging: boolean = false;
|
399
430
|
public onDragStart(pointer: Pointer, target: EventTarget): boolean {
|
431
|
+
void this.addRemoveSelectionFromImage(false);
|
432
|
+
|
400
433
|
for (const handle of this.handles) {
|
401
434
|
if (handle.isTarget(target)) {
|
402
435
|
handle.handleDragStart(pointer);
|
@@ -422,8 +455,6 @@ export default class Selection {
|
|
422
455
|
if (this.targetHandle) {
|
423
456
|
this.targetHandle.handleDragUpdate(pointer);
|
424
457
|
}
|
425
|
-
|
426
|
-
this.updateUI();
|
427
458
|
}
|
428
459
|
|
429
460
|
public onDragEnd() {
|
@@ -434,6 +465,8 @@ export default class Selection {
|
|
434
465
|
this.targetHandle.handleDragEnd();
|
435
466
|
}
|
436
467
|
|
468
|
+
this.addRemoveSelectionFromImage(true);
|
469
|
+
|
437
470
|
this.backgroundDragging = false;
|
438
471
|
this.targetHandle = null;
|
439
472
|
this.updateUI();
|
@@ -443,10 +476,12 @@ export default class Selection {
|
|
443
476
|
this.backgroundDragging = false;
|
444
477
|
this.targetHandle = null;
|
445
478
|
this.setTransform(Mat33.identity);
|
479
|
+
|
480
|
+
this.addRemoveSelectionFromImage(true);
|
446
481
|
}
|
447
482
|
|
448
483
|
// Scroll the viewport to this. Does not zoom
|
449
|
-
public scrollTo() {
|
484
|
+
public async scrollTo() {
|
450
485
|
if (this.selectedElems.length === 0) {
|
451
486
|
return;
|
452
487
|
}
|
@@ -456,9 +491,14 @@ export default class Selection {
|
|
456
491
|
const closestPoint = screenRect.getClosestPointOnBoundaryTo(this.screenRegion.center);
|
457
492
|
const screenDelta = this.screenRegion.center.minus(closestPoint);
|
458
493
|
const delta = this.editor.viewport.screenToCanvasTransform.transformVec3(screenDelta);
|
459
|
-
this.editor.dispatchNoAnnounce(
|
494
|
+
await this.editor.dispatchNoAnnounce(
|
460
495
|
Viewport.transformBy(Mat33.translation(delta.times(-1))), false
|
461
496
|
);
|
497
|
+
|
498
|
+
// Re-renders clear wet ink, so we need to re-draw the preview
|
499
|
+
// after the full re-render.
|
500
|
+
await this.editor.queueRerender();
|
501
|
+
this.previewTransformCmds();
|
462
502
|
}
|
463
503
|
}
|
464
504
|
|
@@ -381,6 +381,18 @@ export default class SelectionTool extends BaseTool {
|
|
381
381
|
// Only select selectable objects.
|
382
382
|
objects = objects.filter(obj => obj.isSelectable());
|
383
383
|
|
384
|
+
// Sort by z-index
|
385
|
+
objects.sort((a, b) => a.getZIndex() - b.getZIndex());
|
386
|
+
|
387
|
+
// Remove duplicates
|
388
|
+
objects = objects.filter((current, idx) => {
|
389
|
+
if (idx > 0) {
|
390
|
+
return current !== objects[idx - 1];
|
391
|
+
}
|
392
|
+
|
393
|
+
return true;
|
394
|
+
});
|
395
|
+
|
384
396
|
let bbox: Rect2|null = null;
|
385
397
|
for (const object of objects) {
|
386
398
|
if (bbox) {
|