@operato/image-marker 8.0.0-alpha.23 → 8.0.0-alpha.25

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.
@@ -1,42 +1,41 @@
1
1
  import { __decorate } from "tslib";
2
2
  import './ox-image-marker-mode';
3
3
  import { html, css, svg, nothing } from 'lit';
4
- import { state, customElement } from 'lit/decorators.js';
4
+ import { query, state, customElement } from 'lit/decorators.js';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
  import { keyed } from 'lit/directives/keyed.js';
7
7
  import { BaseImageMarker } from './base-image-marker';
8
8
  let OxImageMarker = class OxImageMarker extends BaseImageMarker {
9
9
  constructor() {
10
10
  super(...arguments);
11
- this.currentMode = 'select';
11
+ this.currentMode = 'edit';
12
12
  this.selectedShape = null;
13
13
  this.drawing = false;
14
14
  this.startX = 0;
15
15
  this.startY = 0;
16
16
  this.offsetX = 0;
17
17
  this.offsetY = 0;
18
+ this.shapeMoveThreshold = 10;
19
+ this.shapeMoveInitiated = false;
18
20
  this.onSvgTouchStart = (event) => {
19
21
  event.preventDefault();
20
22
  if (this.isDoubleTouch(event)) {
21
23
  this.resetZoom();
22
24
  }
23
25
  if (event.touches.length === 1) {
24
- this.selectedShape = null;
25
- this.shapes = this.shapes.map(s => {
26
- return { ...s, selected: false };
27
- });
28
- if (this.currentMode === 'move') {
29
- this.startPanning(event);
30
- }
31
- else if (this.currentMode === 'draw') {
26
+ this.setSelectedShape(null);
27
+ if (this.currentMode === 'shape') {
32
28
  this.startDrawing(event);
33
29
  }
30
+ else {
31
+ this.startPanning(event);
32
+ }
34
33
  }
35
34
  else if (event.touches.length === 2) {
36
35
  this.startPinchZooming(event);
37
36
  }
38
37
  };
39
- this.onDrawingMouseMove = (event) => {
38
+ this.onMouseMoveForDrawing = (event) => {
40
39
  if (!this.drawing) {
41
40
  return;
42
41
  }
@@ -100,8 +99,8 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
100
99
  default:
101
100
  return;
102
101
  }
103
- this.selectedShape = newShape;
104
102
  this.shapes = [...this.shapes, newShape];
103
+ this.setSelectedShape(newShape);
105
104
  }
106
105
  if (this.selectedShape) {
107
106
  switch (this.selectedShape.type) {
@@ -132,85 +131,90 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
132
131
  this.requestUpdate();
133
132
  }
134
133
  };
135
- this.onDrawingMouseUp = (event) => {
134
+ this.onMouseUpForDrawing = (event) => {
136
135
  event.preventDefault();
137
136
  this.drawing = false;
138
137
  const svg = this.svg;
139
138
  if ('touches' in event) {
140
- svg.removeEventListener('touchmove', this.onDrawingMouseMove);
141
- svg.removeEventListener('touchend', this.onDrawingMouseUp);
139
+ svg.removeEventListener('touchmove', this.onMouseMoveForDrawing);
140
+ svg.removeEventListener('touchend', this.onMouseUpForDrawing);
142
141
  }
143
142
  else {
144
- svg.removeEventListener('mousemove', this.onDrawingMouseMove);
145
- svg.removeEventListener('mouseup', this.onDrawingMouseUp);
146
- }
147
- if (this.selectedShape) {
148
- this.selectedShape.selected = true;
143
+ svg.removeEventListener('mousemove', this.onMouseMoveForDrawing);
144
+ svg.removeEventListener('mouseup', this.onMouseUpForDrawing);
149
145
  }
146
+ this.imageMarkerMode.setMode('edit');
150
147
  this.requestUpdate();
151
148
  };
152
- this.onShapeMouseMove = (event) => {
149
+ this.onMouseMoveOnShape = (event) => {
153
150
  if (!this.selectedShape) {
154
151
  return;
155
152
  }
153
+ if ('touches' in event && event.touches.length > 1) {
154
+ return;
155
+ }
156
156
  event.preventDefault();
157
157
  const { x, y } = this.getSvgPoint(event);
158
+ const dx = x - this.offsetX;
159
+ const dy = y - this.offsetY;
160
+ if (!this.shapeMoveInitiated) {
161
+ const distance = Math.sqrt(dx * dx + dy * dy);
162
+ if (distance < this.shapeMoveThreshold) {
163
+ return;
164
+ }
165
+ this.shapeMoveInitiated = true;
166
+ }
167
+ this.offsetX = x;
168
+ this.offsetY = y;
158
169
  switch (this.selectedShape.type) {
159
170
  case 'text':
160
171
  case 'rectangle':
161
- this.selectedShape.x = x - this.offsetX;
162
- this.selectedShape.y = y - this.offsetY;
172
+ this.selectedShape.x += dx;
173
+ this.selectedShape.y += dy;
163
174
  break;
164
175
  case 'circle':
165
- this.selectedShape.cx = x - this.offsetX;
166
- this.selectedShape.cy = y - this.offsetY;
176
+ this.selectedShape.cx += dx;
177
+ this.selectedShape.cy += dy;
167
178
  break;
168
179
  case 'triangle':
169
180
  const points = this.selectedShape.points.split(' ').map(p => p.split(',').map(Number));
170
- const [ox, oy] = points[0];
171
- this.selectedShape.points = points
172
- .map(([px, py]) => [px - ox + x - this.offsetX, py - oy + y - this.offsetY].join(','))
173
- .join(' ');
181
+ this.selectedShape.points = points.map(([px, py]) => [px + dx, py + dy].join(',')).join(' ');
174
182
  break;
175
183
  case 'line':
176
184
  case 'arrow':
177
- const dxLine = x - this.offsetX;
178
- const dyLine = y - this.offsetY;
179
- const deltaX = dxLine - this.selectedShape.x1;
180
- const deltaY = dyLine - this.selectedShape.y1;
181
- this.selectedShape.x1 = dxLine;
182
- this.selectedShape.y1 = dyLine;
183
- this.selectedShape.x2 = this.selectedShape.x2 + deltaX;
184
- this.selectedShape.y2 = this.selectedShape.y2 + deltaY;
185
+ this.selectedShape.x1 += dx;
186
+ this.selectedShape.x2 += dx;
187
+ this.selectedShape.y1 += dy;
188
+ this.selectedShape.y2 += dy;
185
189
  break;
186
190
  }
187
191
  this.requestUpdate();
188
192
  };
189
- this.onShapeMouseUp = (event) => {
193
+ this.onMouseUpOnShape = (event) => {
194
+ if (!this.selectedShape) {
195
+ return;
196
+ }
197
+ if ('touches' in event && event.touches.length > 1) {
198
+ return;
199
+ }
190
200
  event.preventDefault();
191
201
  const svg = this.svg;
192
202
  if ('touches' in event) {
193
- svg.removeEventListener('touchmove', this.onShapeMouseMove);
194
- svg.removeEventListener('touchend', this.onShapeMouseUp);
203
+ svg.removeEventListener('touchmove', this.onMouseMoveOnShape);
204
+ svg.removeEventListener('touchend', this.onMouseUpOnShape);
195
205
  }
196
206
  else {
197
- svg.removeEventListener('mousemove', this.onShapeMouseMove);
198
- svg.removeEventListener('mouseup', this.onShapeMouseUp);
207
+ svg.removeEventListener('mousemove', this.onMouseMoveOnShape);
208
+ svg.removeEventListener('mouseup', this.onMouseUpOnShape);
199
209
  }
200
210
  };
201
- this.onHandleMouseMove = (event) => {
211
+ this.onResizeHandleMouseMove = (event) => {
202
212
  if (!this.selectedShape) {
203
213
  return;
204
214
  }
205
215
  event.preventDefault();
206
216
  const { x, y } = this.getSvgPoint(event);
207
217
  switch (this.selectedShape.type) {
208
- // case 'text':
209
- // this.selectedShape.width = Math.abs(x - this.selectedShape.x!)
210
- // this.selectedShape.height = Math.abs(y - this.selectedShape.y!)
211
- // if (x < this.selectedShape.x!) this.selectedShape.x = x
212
- // if (y < this.selectedShape.y!) this.selectedShape.y = y
213
- // break
214
218
  case 'rectangle':
215
219
  const startX = this.selectedShape.x;
216
220
  const startY = this.selectedShape.y;
@@ -278,18 +282,17 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
278
282
  }
279
283
  this.requestUpdate();
280
284
  };
281
- this.onHandleMouseUp = (event) => {
285
+ this.onResizeHandleMouseUp = (event) => {
282
286
  event.preventDefault();
283
287
  const svg = this.svg;
284
288
  if ('touches' in event) {
285
- svg.removeEventListener('touchmove', this.onHandleMouseMove);
286
- svg.removeEventListener('touchend', this.onHandleMouseUp);
289
+ svg.removeEventListener('touchmove', this.onResizeHandleMouseMove);
290
+ svg.removeEventListener('touchend', this.onResizeHandleMouseUp);
287
291
  }
288
292
  else {
289
- svg.removeEventListener('mousemove', this.onHandleMouseMove);
290
- svg.removeEventListener('mouseup', this.onHandleMouseUp);
293
+ svg.removeEventListener('mousemove', this.onResizeHandleMouseMove);
294
+ svg.removeEventListener('mouseup', this.onResizeHandleMouseUp);
291
295
  }
292
- this.selectedShape = null;
293
296
  };
294
297
  this.onFocus = () => {
295
298
  this.addEventListener('keydown', this.handleKeyDown);
@@ -320,11 +323,11 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
320
323
  }
321
324
 
322
325
  svg {
323
- cursor: crosshair;
326
+ cursor: default;
324
327
  }
325
328
 
326
- svg.dragging {
327
- cursor: move;
329
+ svg[drawing] {
330
+ cursor: crosshair;
328
331
  }
329
332
 
330
333
  .resize-handle {
@@ -352,6 +355,7 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
352
355
  @wheel=${this.onSvgWheel}
353
356
  @dblclick=${this.onSvgDoubleClick}
354
357
  viewBox=${this.viewBox}
358
+ ?drawing=${this.currentMode == 'shape'}
355
359
  >
356
360
  <image href=${this.imageUrl} @load=${this.onImageLoad}></image>
357
361
  ${this.shapes.map(shape => keyed(shape.id, this.renderShape(shape)))}
@@ -379,16 +383,13 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
379
383
  }
380
384
  onSvgMouseDown(event) {
381
385
  event.preventDefault();
382
- this.selectedShape = null;
383
- this.shapes = this.shapes.map(s => {
384
- return { ...s, selected: false };
385
- });
386
- if (this.currentMode === 'move') {
387
- this.startPanning(event);
388
- }
389
- else if (this.currentMode === 'draw') {
386
+ this.setSelectedShape(null);
387
+ if (this.currentMode === 'shape') {
390
388
  this.startDrawing(event);
391
389
  }
390
+ else {
391
+ this.startPanning(event);
392
+ }
392
393
  }
393
394
  startDrawing(event) {
394
395
  const { x, y } = this.getSvgPoint(event);
@@ -408,18 +409,32 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
408
409
  this.drawing = true;
409
410
  }
410
411
  if ('touches' in event) {
411
- this.svg.addEventListener('touchmove', this.onDrawingMouseMove);
412
- this.svg.addEventListener('touchend', this.onDrawingMouseUp);
412
+ this.svg.addEventListener('touchmove', this.onMouseMoveForDrawing);
413
+ this.svg.addEventListener('touchend', this.onMouseUpForDrawing);
413
414
  }
414
415
  else {
415
- this.svg.addEventListener('mousemove', this.onDrawingMouseMove);
416
- this.svg.addEventListener('mouseup', this.onDrawingMouseUp);
416
+ this.svg.addEventListener('mousemove', this.onMouseMoveForDrawing);
417
+ this.svg.addEventListener('mouseup', this.onMouseUpForDrawing);
417
418
  }
418
419
  }
419
420
  setMode(mode, shapeType) {
421
+ if (mode == 'view') {
422
+ this.setSelectedShape(null);
423
+ }
420
424
  this.currentMode = mode;
421
425
  this.currentShapeType = shapeType;
422
426
  }
427
+ setSelectedShape(shape) {
428
+ this.selectedShape = shape;
429
+ if (!shape) {
430
+ this.shapes = this.shapes.map(s => {
431
+ return { ...s, selected: false };
432
+ });
433
+ }
434
+ else {
435
+ this.selectedShape.selected = true;
436
+ }
437
+ }
423
438
  getSvgPoint(event) {
424
439
  const { x, y } = this.getPointFromEvent(event);
425
440
  const svg = this.svg;
@@ -444,8 +459,8 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
444
459
  y="${shape.y}"
445
460
  fill="${commonAttrs.stroke}"
446
461
  style="cursor: ${commonAttrs.cursor}; font-size: 16px;"
447
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
448
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
462
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
463
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
449
464
  @dblclick="${(e) => this.onTextDoubleClick(e, shape)}"
450
465
  >${shape.text}</text>
451
466
  `;
@@ -460,8 +475,8 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
460
475
  stroke-width="${commonAttrs['stroke-width']}"
461
476
  fill="${commonAttrs.fill}"
462
477
  style="cursor: ${commonAttrs.cursor}"
463
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
464
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
478
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
479
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
465
480
  ></rect>
466
481
  ${shape.selected ? this.renderResizeHandles(shape) : ''}
467
482
  `;
@@ -475,8 +490,8 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
475
490
  stroke-width="${commonAttrs['stroke-width']}"
476
491
  fill="${commonAttrs.fill}"
477
492
  style="cursor: ${commonAttrs.cursor}"
478
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
479
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
493
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
494
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
480
495
  ></circle>
481
496
  ${shape.selected ? this.renderResizeHandles(shape) : ''}
482
497
  `;
@@ -488,8 +503,8 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
488
503
  stroke-width="${commonAttrs['stroke-width']}"
489
504
  fill="${commonAttrs.fill}"
490
505
  style="cursor: ${commonAttrs.cursor}"
491
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
492
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
506
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
507
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
493
508
  ></polygon>
494
509
  ${shape.selected ? this.renderResizeHandles(shape) : ''}
495
510
  `;
@@ -503,8 +518,20 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
503
518
  stroke="${commonAttrs.stroke}"
504
519
  stroke-width="${commonAttrs['stroke-width']}"
505
520
  style="cursor: ${commonAttrs.cursor}"
506
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
507
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
521
+ ></line>
522
+ <line
523
+ x1="${shape.x1}"
524
+ y1="${shape.y1}"
525
+ x2="${shape.x2 ?? shape.x1}"
526
+ y2="${shape.y2 ?? shape.y1}"
527
+ stroke="${commonAttrs.stroke}"
528
+ stroke-width="25"
529
+ stroke-opacity="0"
530
+ pointer-events="stroke"
531
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
532
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
533
+ @mouseenter="${() => (this.svg.style.cursor = 'pointer')}"
534
+ @mouseleave="${() => (this.svg.style.cursor = 'default')}"
508
535
  ></line>
509
536
  ${shape.selected ? this.renderResizeHandles(shape) : ''}
510
537
  `;
@@ -524,8 +551,20 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
524
551
  stroke-width="${commonAttrs['stroke-width']}"
525
552
  marker-end="url(#arrowhead-${shape.id})"
526
553
  style="cursor: ${commonAttrs.cursor}"
527
- @mousedown="${(e) => this.onShapeMouseDown(e, shape)}"
528
- @touchstart="${(e) => this.onShapeMouseDown(e, shape)}"
554
+ ></line>
555
+ <line
556
+ x1="${shape.x1}"
557
+ y1="${shape.y1}"
558
+ x2="${shape.x2 ?? shape.x1}"
559
+ y2="${shape.y2 ?? shape.y1}"
560
+ stroke="${commonAttrs.stroke}"
561
+ stroke-width="25"
562
+ stroke-opacity="0"
563
+ pointer-events="stroke"
564
+ @mousedown="${(e) => this.onMouseDownOnShape(e, shape)}"
565
+ @touchstart="${(e) => this.onMouseDownOnShape(e, shape)}"
566
+ @mouseenter="${() => (this.svg.style.cursor = 'pointer')}"
567
+ @mouseleave="${() => (this.svg.style.cursor = 'default')}"
529
568
  ></line>
530
569
  ${shape.selected ? this.renderResizeHandles(shape) : ''}
531
570
  `;
@@ -533,42 +572,32 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
533
572
  return nothing;
534
573
  }
535
574
  }
536
- onShapeMouseDown(event, shape) {
575
+ onMouseDownOnShape(event, shape) {
576
+ if (this.currentMode !== 'edit') {
577
+ return;
578
+ }
579
+ if ('touches' in event && event.touches.length > 1) {
580
+ return;
581
+ }
537
582
  event.stopPropagation();
538
583
  event.preventDefault();
539
584
  this.shapes = this.shapes.map(s => ({
540
585
  ...s,
541
586
  selected: s.id === shape.id
542
587
  }));
543
- this.selectedShape = this.shapes.find(s => s.id == shape.id);
588
+ this.shapeMoveInitiated = false;
589
+ this.setSelectedShape(this.shapes.find(s => s.id == shape.id));
544
590
  const { x, y } = this.getSvgPoint(event);
545
- switch (shape.type) {
546
- case 'text':
547
- case 'rectangle':
548
- case 'circle':
549
- this.offsetX = x - (shape.x || shape.cx || 0);
550
- this.offsetY = y - (shape.y || shape.cy || 0);
551
- break;
552
- case 'triangle':
553
- const points = this.selectedShape.points.split(' ').map(p => p.split(',').map(Number));
554
- const [px, py] = points[0] || [0, 0];
555
- this.offsetX = x - px;
556
- this.offsetY = y - py;
557
- break;
558
- case 'line':
559
- case 'arrow':
560
- this.offsetX = x - shape.x1;
561
- this.offsetY = y - shape.y1;
562
- break;
563
- }
591
+ this.offsetX = x;
592
+ this.offsetY = y;
564
593
  const svg = this.svg;
565
594
  if ('touches' in event) {
566
- svg.addEventListener('touchmove', this.onShapeMouseMove);
567
- svg.addEventListener('touchend', this.onShapeMouseUp);
595
+ svg.addEventListener('touchmove', this.onMouseMoveOnShape);
596
+ svg.addEventListener('touchend', this.onMouseUpOnShape);
568
597
  }
569
598
  else {
570
- svg.addEventListener('mousemove', this.onShapeMouseMove);
571
- svg.addEventListener('mouseup', this.onShapeMouseUp);
599
+ svg.addEventListener('mousemove', this.onMouseMoveOnShape);
600
+ svg.addEventListener('mouseup', this.onMouseUpOnShape);
572
601
  }
573
602
  }
574
603
  renderResizeHandles(shape) {
@@ -618,27 +647,27 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
618
647
  stroke="black"
619
648
  class="resize-handle"
620
649
  style="cursor: ${handle.cursor};"
621
- @mousedown="${(e) => this.onHandleMouseDown(e, shape, handle)}"
622
- @touchstart="${(e) => this.onHandleMouseDown(e, shape, handle)}"
650
+ @mousedown="${(e) => this.onResizeHandleMouseDown(e, shape, handle)}"
651
+ @touchstart="${(e) => this.onResizeHandleMouseDown(e, shape, handle)}"
623
652
  ></rect>
624
653
  </g>
625
654
  `)}
626
655
  `;
627
656
  }
628
- onHandleMouseDown(event, shape, handle) {
657
+ onResizeHandleMouseDown(event, shape, handle) {
629
658
  event.stopPropagation();
630
659
  event.preventDefault();
631
- this.selectedShape = shape;
660
+ this.setSelectedShape(shape);
632
661
  this.offsetX = handle.x;
633
662
  this.offsetY = handle.y;
634
663
  const svg = this.svg;
635
664
  if ('touches' in event) {
636
- svg.addEventListener('touchmove', this.onHandleMouseMove);
637
- svg.addEventListener('touchend', this.onHandleMouseUp);
665
+ svg.addEventListener('touchmove', this.onResizeHandleMouseMove);
666
+ svg.addEventListener('touchend', this.onResizeHandleMouseUp);
638
667
  }
639
668
  else {
640
- svg.addEventListener('mousemove', this.onHandleMouseMove);
641
- svg.addEventListener('mouseup', this.onHandleMouseUp);
669
+ svg.addEventListener('mousemove', this.onResizeHandleMouseMove);
670
+ svg.addEventListener('mouseup', this.onResizeHandleMouseUp);
642
671
  }
643
672
  }
644
673
  onTextDoubleClick(event, shape) {
@@ -750,7 +779,7 @@ let OxImageMarker = class OxImageMarker extends BaseImageMarker {
750
779
  deleteSelectedShape() {
751
780
  if (this.selectedShape) {
752
781
  this.shapes = this.shapes.filter(s => s.id !== this.selectedShape.id);
753
- this.selectedShape = null;
782
+ this.setSelectedShape(null);
754
783
  this.requestUpdate();
755
784
  }
756
785
  }
@@ -764,6 +793,9 @@ __decorate([
764
793
  __decorate([
765
794
  state()
766
795
  ], OxImageMarker.prototype, "selectedShape", void 0);
796
+ __decorate([
797
+ query('ox-image-marker-mode')
798
+ ], OxImageMarker.prototype, "imageMarkerMode", void 0);
767
799
  OxImageMarker = __decorate([
768
800
  customElement('ox-image-marker')
769
801
  ], OxImageMarker);