@annotorious/annotorious 3.0.0-rc.2 → 3.0.0-rc.21

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.
Files changed (81) hide show
  1. package/dist/Annotorious.d.ts +7 -2
  2. package/dist/Annotorious.d.ts.map +1 -1
  3. package/dist/AnnotoriousOpts.d.ts +4 -3
  4. package/dist/AnnotoriousOpts.d.ts.map +1 -1
  5. package/dist/annotation/SVGAnnotationLayerPointerEvent.d.ts.map +1 -1
  6. package/dist/annotation/Transform.d.ts.map +1 -1
  7. package/dist/annotation/editors/Handle.svelte.d.ts +1 -0
  8. package/dist/annotation/editors/editorsRegistry.d.ts +1 -1
  9. package/dist/annotation/editors/editorsRegistry.d.ts.map +1 -1
  10. package/dist/annotation/editors/index.d.ts +1 -1
  11. package/dist/annotation/editors/index.d.ts.map +1 -1
  12. package/dist/annotation/tools/drawingToolsRegistry.d.ts +4 -4
  13. package/dist/annotation/tools/drawingToolsRegistry.d.ts.map +1 -1
  14. package/dist/annotation/utils/responsive.d.ts +2 -1
  15. package/dist/annotation/utils/responsive.d.ts.map +1 -1
  16. package/dist/annotation/utils/styling.d.ts +1 -1
  17. package/dist/annotation/utils/styling.d.ts.map +1 -1
  18. package/dist/annotation/utils/touch.d.ts.map +1 -1
  19. package/dist/annotorious.css +1 -1
  20. package/dist/annotorious.es.js +2370 -1991
  21. package/dist/annotorious.es.js.map +1 -1
  22. package/dist/annotorious.js +1 -1
  23. package/dist/annotorious.js.map +1 -1
  24. package/dist/index.d.ts +2 -4
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/keyboardCommands.d.ts +5 -0
  27. package/dist/keyboardCommands.d.ts.map +1 -0
  28. package/dist/model/w3c/W3CImageAnnotation.d.ts +11 -0
  29. package/dist/model/w3c/W3CImageAnnotation.d.ts.map +1 -0
  30. package/dist/model/w3c/W3CImageFormatAdapter.d.ts +3 -2
  31. package/dist/model/w3c/W3CImageFormatAdapter.d.ts.map +1 -1
  32. package/dist/model/w3c/fragment/FragmentSelector.d.ts +1 -2
  33. package/dist/model/w3c/fragment/FragmentSelector.d.ts.map +1 -1
  34. package/dist/model/w3c/index.d.ts +1 -0
  35. package/dist/model/w3c/index.d.ts.map +1 -1
  36. package/dist/model/w3c/svg/SVG.d.ts.map +1 -1
  37. package/dist/model/w3c/svg/SVGSelector.d.ts +1 -2
  38. package/dist/model/w3c/svg/SVGSelector.d.ts.map +1 -1
  39. package/dist/state/ImageAnnotatorState.d.ts.map +1 -1
  40. package/dist/state/spatialTree.d.ts +1 -1
  41. package/dist/state/spatialTree.d.ts.map +1 -1
  42. package/dist/themes/smart/setTheme.d.ts +3 -1
  43. package/dist/themes/smart/setTheme.d.ts.map +1 -1
  44. package/package.json +13 -13
  45. package/src/Annotorious.css +5 -5
  46. package/src/Annotorious.ts +44 -29
  47. package/src/AnnotoriousOpts.ts +11 -6
  48. package/src/annotation/SVGAnnotationLayer.svelte +21 -15
  49. package/src/annotation/SVGAnnotationLayerPointerEvent.ts +1 -2
  50. package/src/annotation/Transform.ts +5 -3
  51. package/src/annotation/editors/Editor.svelte +10 -11
  52. package/src/annotation/editors/EditorMount.svelte +3 -3
  53. package/src/annotation/editors/Handle.svelte +66 -0
  54. package/src/annotation/editors/index.ts +2 -2
  55. package/src/annotation/editors/polygon/PolygonEditor.svelte +16 -16
  56. package/src/annotation/editors/rectangle/RectangleEditor.svelte +46 -43
  57. package/src/annotation/shapes/Ellipse.svelte +2 -2
  58. package/src/annotation/shapes/Polygon.svelte +2 -2
  59. package/src/annotation/shapes/Rectangle.svelte +3 -3
  60. package/src/annotation/tools/ToolMount.svelte +3 -3
  61. package/src/annotation/tools/drawingToolsRegistry.ts +2 -1
  62. package/src/annotation/tools/polygon/RubberbandPolygon.svelte +58 -32
  63. package/src/annotation/tools/rectangle/RubberbandRectangle.svelte +17 -16
  64. package/src/annotation/utils/responsive.ts +1 -1
  65. package/src/annotation/utils/touch.ts +4 -1
  66. package/src/index.ts +25 -8
  67. package/src/keyboardCommands.ts +50 -0
  68. package/src/model/w3c/W3CImageAnnotation.ts +17 -0
  69. package/src/model/w3c/W3CImageFormatAdapter.ts +54 -20
  70. package/src/model/w3c/fragment/FragmentSelector.ts +5 -6
  71. package/src/model/w3c/index.ts +1 -0
  72. package/src/model/w3c/svg/SVG.ts +1 -2
  73. package/src/model/w3c/svg/SVGSelector.ts +11 -13
  74. package/src/state/ImageAnnotatorState.ts +3 -3
  75. package/src/state/spatialTree.ts +3 -2
  76. package/src/themes/dark/index.css +2 -2
  77. package/src/themes/light/index.css +2 -2
  78. package/src/themes/smart/setTheme.ts +10 -6
  79. package/dist/annotation/editors/Handle.d.ts +0 -14
  80. package/dist/annotation/editors/Handle.d.ts.map +0 -1
  81. package/src/annotation/editors/Handle.ts +0 -21
@@ -0,0 +1,66 @@
1
+ <script lang="ts">
2
+ import { isTouch } from '../utils';
3
+
4
+ /** props **/
5
+ export let x: number;
6
+ export let y: number;
7
+ export let scale: number;
8
+ export let radius: number = 30;
9
+
10
+ let touched = false;
11
+
12
+ const onPointerDown = (event: PointerEvent) => {
13
+ if (event.pointerType === 'touch')
14
+ touched = true;
15
+ }
16
+
17
+ const onPointerUp = () =>
18
+ touched = false;
19
+
20
+ $: handleSize = 10 / scale;
21
+ </script>
22
+
23
+ {#if isTouch}
24
+ <g class="a9s-touch-handle">
25
+ <circle
26
+ cx={x}
27
+ cy={y}
28
+ r={radius / scale}
29
+ class="a9s-touch-halo"
30
+ class:touched={touched}
31
+ on:pointerdown
32
+ on:pointerdown={onPointerDown}
33
+ on:pointerup={onPointerUp} />
34
+
35
+ <rect
36
+ class={`a9s-handle ${$$props.class || ''}`.trim()}
37
+ x={x - handleSize / 2}
38
+ y={y - handleSize / 2}
39
+ width={handleSize}
40
+ height={handleSize}
41
+ on:pointerdown
42
+ on:pointerdown={onPointerDown}
43
+ on:pointerup={onPointerUp} />
44
+ </g>
45
+ {:else}
46
+ <rect
47
+ class={`a9s-handle ${$$props.class || ''}`.trim()}
48
+ x={x - handleSize / 2}
49
+ y={y - handleSize / 2}
50
+ width={handleSize}
51
+ height={handleSize}
52
+ on:pointerdown />
53
+ {/if}
54
+
55
+ <style>
56
+ .a9s-touch-halo {
57
+ fill: transparent;
58
+ stroke-width: 0;
59
+ }
60
+
61
+ .a9s-touch-halo.touched {
62
+ fill: rgba(255, 255, 255, 0.25);
63
+ }
64
+
65
+
66
+ </style>
@@ -1,7 +1,7 @@
1
1
  export * from './polygon';
2
2
  export * from './rectangle';
3
3
  export * from './editorsRegistry';
4
- export * from './Handle';
5
4
 
6
5
  export { default as Editor } from './Editor.svelte';
7
- export { default as EditorMount } from './EditorMount.svelte';
6
+ export { default as EditorMount } from './EditorMount.svelte';
7
+ export { default as Handle } from './Handle.svelte';
@@ -1,27 +1,27 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import { boundsFromPoints } from '../../../model';
3
- import type { Polygon } from '../../../model';
3
+ import type { Polygon, PolygonGeometry, Shape } from '../../../model';
4
4
  import type { Transform } from '../../Transform';
5
5
  import { Editor, Handle } from '..';
6
6
 
7
7
  /** Props */
8
8
  export let shape: Polygon;
9
- export let computedStyle: string = undefined;
9
+ export let computedStyle: string | undefined;
10
10
  export let transform: Transform;
11
11
  export let viewportScale: number = 1;
12
12
 
13
13
  $: geom = shape.geometry;
14
14
 
15
- $: handleSize = 10 / viewportScale;
16
-
17
- const editor = (polygon: Polygon, handle: Handle, delta: [number, number]) => {
15
+ const editor = (polygon: Shape, handle: string, delta: [number, number]) => {
18
16
  let points: [number, number][];
19
17
 
20
- if (handle === Handle.SHAPE) {
21
- points = polygon.geometry.points.map(([x, y]) => [x + delta[0], y + delta[1]]);
18
+ const geom = (polygon.geometry) as PolygonGeometry;
19
+
20
+ if (handle === 'SHAPE') {
21
+ points = geom.points.map(([x, y]) => [x + delta[0], y + delta[1]]);
22
22
  } else {
23
- points = polygon.geometry.points.map(([x, y], idx) =>
24
- handle === Handle(idx) ? [x + delta[0], y + delta[1]] : [x, y]
23
+ points = geom.points.map(([x, y], idx) =>
24
+ handle === `HANDLE-${idx}` ? [x + delta[0], y + delta[1]] : [x, y]
25
25
  );
26
26
  }
27
27
 
@@ -46,19 +46,19 @@
46
46
  <polygon
47
47
  class="a9s-outer"
48
48
  style={computedStyle ? 'display:none;' : undefined}
49
- on:pointerdown={grab(Handle.SHAPE)}
49
+ on:pointerdown={grab('SHAPE')}
50
50
  points={geom.points.map(xy => xy.join(',')).join(' ')} />
51
51
 
52
52
  <polygon
53
53
  class="a9s-inner a9s-shape-handle"
54
54
  style={computedStyle}
55
- on:pointerdown={grab(Handle.SHAPE)}
55
+ on:pointerdown={grab('SHAPE')}
56
56
  points={geom.points.map(xy => xy.join(',')).join(' ')} />
57
57
 
58
58
  {#each geom.points as point, idx}
59
- <rect
60
- class="a9s-corner-handle"
61
- on:pointerdown={grab(Handle(idx))}
62
- x={point[0] - handleSize / 2} y={point[1] - handleSize / 2} height={handleSize} width={handleSize} />
59
+ <Handle
60
+ on:pointerdown={grab(`HANDLE-${idx}`)}
61
+ x={point[0]} y={point[1]}
62
+ scale={viewportScale} />
63
63
  {/each}
64
64
  </Editor>
@@ -1,19 +1,18 @@
1
- <script type="ts">
2
- import type { Rectangle } from '../../../model';
1
+ <script lang="ts">
2
+ import Handle from '../Handle.svelte';
3
+ import type { Rectangle, Shape } from '../../../model';
3
4
  import type { Transform } from '../../Transform';
4
- import { Editor, Handle } from '..';
5
+ import { Editor } from '..';
5
6
 
6
7
  /** Props */
7
8
  export let shape: Rectangle;
8
- export let computedStyle: string = undefined;
9
+ export let computedStyle: string | undefined;
9
10
  export let transform: Transform;
10
11
  export let viewportScale: number = 1;
11
12
 
12
13
  $: geom = shape.geometry;
13
14
 
14
- $: handleSize = 10 / viewportScale;
15
-
16
- const editor = (rectangle: Rectangle, handle: Handle, delta: [number, number]) => {
15
+ const editor = (rectangle: Shape, handle: string, delta: [number, number]) => {
17
16
  const initialBounds = rectangle.geometry.bounds;
18
17
 
19
18
  let [x0, y0] = [initialBounds.minX, initialBounds.minY];
@@ -21,39 +20,39 @@
21
20
 
22
21
  const [dx, dy] = delta;
23
22
 
24
- if (handle === Handle.SHAPE) {
23
+ if (handle === 'SHAPE') {
25
24
  x0 += dx;
26
25
  x1 += dx;
27
26
  y0 += dy;
28
27
  y1 += dy;
29
28
  } else {
30
29
  switch (handle) {
31
- case Handle.TOP:
32
- case Handle.TOP_LEFT:
33
- case Handle.TOP_RIGHT: {
30
+ case 'TOP':
31
+ case 'TOP_LEFT':
32
+ case 'TOP_RIGHT': {
34
33
  y0 += dy;
35
34
  break;
36
35
  }
37
36
 
38
- case Handle.BOTTOM:
39
- case Handle.BOTTOM_LEFT:
40
- case Handle.BOTTOM_RIGHT: {
37
+ case 'BOTTOM':
38
+ case 'BOTTOM_LEFT':
39
+ case 'BOTTOM_RIGHT': {
41
40
  y1 += dy;
42
41
  break;
43
42
  }
44
43
  }
45
44
 
46
45
  switch (handle) {
47
- case Handle.LEFT:
48
- case Handle.TOP_LEFT:
49
- case Handle.BOTTOM_LEFT: {
46
+ case 'LEFT':
47
+ case 'TOP_LEFT':
48
+ case 'BOTTOM_LEFT': {
50
49
  x0 += dx;
51
50
  break;
52
51
  }
53
52
 
54
- case Handle.RIGHT:
55
- case Handle.TOP_RIGHT:
56
- case Handle.BOTTOM_RIGHT: {
53
+ case 'RIGHT':
54
+ case 'TOP_RIGHT':
55
+ case 'BOTTOM_RIGHT': {
57
56
  x1 += dx;
58
57
  break;
59
58
  }
@@ -92,52 +91,56 @@
92
91
  <rect
93
92
  class="a9s-outer"
94
93
  style={computedStyle ? 'display:none;' : undefined}
95
- on:pointerdown={grab(Handle.SHAPE)}
94
+ on:pointerdown={grab('SHAPE')}
96
95
  x={geom.x} y={geom.y} width={geom.w} height={geom.h} />
97
96
 
98
97
  <rect
99
98
  class="a9s-inner a9s-shape-handle"
100
99
  style={computedStyle}
101
- on:pointerdown={grab(Handle.SHAPE)}
100
+ on:pointerdown={grab('SHAPE')}
102
101
  x={geom.x} y={geom.y} width={geom.w} height={geom.h} />
103
102
 
104
103
  <rect
105
104
  class="a9s-edge-handle a9s-edge-handle-top"
106
- on:pointerdown={grab(Handle.TOP)}
105
+ on:pointerdown={grab('TOP')}
107
106
  x={geom.x} y={geom.y} height={1} width={geom.w} />
108
107
 
109
108
  <rect
110
109
  class="a9s-edge-handle a9s-edge-handle-right"
111
- on:pointerdown={grab(Handle.RIGHT)}
110
+ on:pointerdown={grab('RIGHT')}
112
111
  x={geom.x + geom.w} y={geom.y} height={geom.h} width={1}/>
113
112
 
114
113
  <rect
115
114
  class="a9s-edge-handle a9s-edge-handle-bottom"
116
- on:pointerdown={grab(Handle.BOTTOM)}
115
+ on:pointerdown={grab('BOTTOM')}
117
116
  x={geom.x} y={geom.y + geom.h} height={1} width={geom.w} />
118
117
 
119
118
  <rect
120
119
  class="a9s-edge-handle a9s-edge-handle-left"
121
- on:pointerdown={grab(Handle.LEFT)}
120
+ on:pointerdown={grab('LEFT')}
122
121
  x={geom.x} y={geom.y} height={geom.h} width={1} />
123
122
 
124
- <rect
125
- class="a9s-corner-handle a9s-corner-handle-topleft"
126
- on:pointerdown={grab(Handle.TOP_LEFT)}
127
- x={geom.x - handleSize / 2} y={geom.y - handleSize / 2} height={handleSize} width={handleSize} />
128
-
129
- <rect
130
- class="a9s-corner-handle a9s-corner-handle-topright"
131
- on:pointerdown={grab(Handle.TOP_RIGHT)}
132
- x={geom.x + geom.w - handleSize / 2} y={geom.y - handleSize / 2} height={handleSize} width={handleSize} />
123
+ <Handle
124
+ class="a9s-corner-handle-topleft"
125
+ on:pointerdown={grab('TOP_LEFT')}
126
+ x={geom.x} y={geom.y}
127
+ scale={viewportScale} />
128
+
129
+ <Handle
130
+ class="a9s-corner-handle-topright"
131
+ on:pointerdown={grab('TOP_RIGHT')}
132
+ x={geom.x + geom.w} y={geom.y}
133
+ scale={viewportScale} />
133
134
 
134
- <rect
135
- class="a9s-corner-handle a9s-corner-handle-bottomright"
136
- on:pointerdown={grab(Handle.BOTTOM_RIGHT)}
137
- x={geom.x + geom.w - handleSize / 2} y={geom.y + geom.h - handleSize / 2} height={handleSize} width={handleSize} />
135
+ <Handle
136
+ class="a9s-corner-handle-bottomright"
137
+ on:pointerdown={grab('BOTTOM_RIGHT')}
138
+ x={geom.x + geom.w} y={geom.y + geom.h}
139
+ scale={viewportScale} />
138
140
 
139
- <rect
140
- class="a9s-corner-handle a9s-corner-handle-bottomleft"
141
- on:pointerdown={grab(Handle.BOTTOM_LEFT)}
142
- x={geom.x - handleSize / 2} y={geom.y + geom.h - handleSize / 2} height={handleSize} width={handleSize} />
141
+ <Handle
142
+ class="a9s-corner-handle-bottomleft"
143
+ on:pointerdown={grab('BOTTOM_LEFT')}
144
+ x={geom.x} y={geom.y + geom.h}
145
+ scale={viewportScale} />
143
146
  </Editor>
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import type { DrawingStyle } from '@annotorious/core';
3
3
  import type { Geometry, EllipseGeometry, ImageAnnotation } from '../../model';
4
4
  import { computeStyle } from '../utils/styling';
@@ -6,7 +6,7 @@
6
6
  /** Props */
7
7
  export let annotation: ImageAnnotation;
8
8
  export let geom: Geometry;
9
- export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) | undefined;
10
10
 
11
11
  $: computedStyle = computeStyle(annotation, style);
12
12
 
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import type { DrawingStyle } from '@annotorious/core';
3
3
  import type { Geometry, ImageAnnotation, PolygonGeometry } from '../../model';
4
4
  import { computeStyle } from '../utils/styling';
@@ -6,7 +6,7 @@
6
6
  /** Props **/
7
7
  export let annotation: ImageAnnotation;
8
8
  export let geom: Geometry;
9
- export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) | undefined;
10
10
 
11
11
  $: computedStyle = computeStyle(annotation, style);
12
12
 
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import type { DrawingStyle } from '@annotorious/core';
3
3
  import type { Geometry, ImageAnnotation, RectangleGeometry } from '../../model';
4
4
  import { computeStyle } from '../utils/styling';
@@ -6,11 +6,11 @@
6
6
  /** Props **/
7
7
  export let annotation: ImageAnnotation;
8
8
  export let geom: Geometry;
9
- export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) | undefined;
10
10
 
11
11
  $: computedStyle = computeStyle(annotation, style);
12
12
 
13
- const { x, y, w, h } = geom as RectangleGeometry;
13
+ $: ({ x, y, w, h } = geom as RectangleGeometry);
14
14
  </script>
15
15
 
16
16
  <g data-id={annotation.id}>
@@ -23,9 +23,9 @@
23
23
 
24
24
  const cleanup: Function[] = [];
25
25
 
26
- const addEventListener = (name: string, handler: (evt: PointerEvent) => void, capture?: boolean) => {
27
- svg.addEventListener(name, handler, capture);
28
- cleanup.push(() => svg.removeEventListener(name, handler, capture));
26
+ const addEventListener = (name: keyof SVGSVGElementEventMap, handler: EventListenerOrEventListenerObject, capture?: boolean) => {
27
+ svg?.addEventListener(name, handler, capture);
28
+ cleanup.push(() => svg?.removeEventListener(name, handler, capture));
29
29
  }
30
30
 
31
31
  toolComponent = new tool({
@@ -9,10 +9,11 @@ export type DrawingToolOpts = {
9
9
 
10
10
  drawingMode?: DrawingMode;
11
11
 
12
- [key: string]: string;
12
+ [key: string]: any;
13
13
 
14
14
  }
15
15
 
16
+ // @ts-ignore
16
17
  const REGISTERED = new Map<DrawingTool, { tool: typeof SvelteComponent, opts?: DrawingToolOpts }>([
17
18
  ['rectangle', { tool: RubberbandRectangle }],
18
19
  ['polygon', { tool: RubberbandPolygon }]
@@ -1,7 +1,7 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import { onMount, createEventDispatcher } from 'svelte';
3
3
  import type { DrawingMode } from '../../../AnnotoriousOpts';
4
- import { boundsFromPoints, ShapeType, type Polygon } from '../../../model';
4
+ import { boundsFromPoints, computeArea, ShapeType, type Polygon } from '../../../model';
5
5
  import { distance } from '../../utils';
6
6
  import type { Transform } from '../..';
7
7
 
@@ -13,22 +13,31 @@
13
13
  export let transform: Transform;
14
14
  export let viewportScale = 1;
15
15
 
16
- let container: SVGGElement;
17
-
18
- let lastPointerDown: number;
16
+ let lastPointerDown: { timeStamp: number, offsetX: number, offsetY: number };
19
17
 
20
18
  let points: [number, number][] = [];
21
19
 
22
- let cursor: [number, number] = null;
20
+ let cursor: [number, number] | undefined;
21
+
22
+ // Keep track of the user keeping the finger
23
+ // in place. Long pauses will be interpreted like a
24
+ // double click and close the shape.
25
+ let touchPauseTimer: number | undefined;
23
26
 
24
27
  let isClosable: boolean = false;
25
28
 
26
29
  const CLOSE_DISTANCE = 20;
27
30
 
31
+ const TOUCH_PAUSE_LIMIT = 1500;
32
+
28
33
  $: handleSize = 10 / viewportScale;
29
34
 
30
- const onPointerDown = (evt: PointerEvent) => {
31
- lastPointerDown = performance.now();
35
+ const onPointerDown = (event: Event) => {
36
+ const evt = event as PointerEvent;
37
+
38
+ // Note that the event itself is ephemeral!
39
+ const { timeStamp, offsetX, offsetY } = evt;
40
+ lastPointerDown = { timeStamp, offsetX, offsetY };
32
41
 
33
42
  if (drawingMode === 'drag') {
34
43
  if (points.length === 0) {
@@ -40,7 +49,11 @@
40
49
  }
41
50
  }
42
51
 
43
- const onPointerMove = (evt: PointerEvent) => {
52
+ const onPointerMove = (event: Event) => {
53
+ const evt = event as PointerEvent;
54
+
55
+ if (touchPauseTimer) clearTimeout(touchPauseTimer);
56
+
44
57
  if (points.length > 0) {
45
58
  cursor = transform.elementToImage(evt.offsetX, evt.offsetY);
46
59
 
@@ -48,18 +61,29 @@
48
61
  const d = distance(cursor, points[0]) * viewportScale;
49
62
  isClosable = d < CLOSE_DISTANCE;
50
63
  }
64
+
65
+ if (evt.pointerType === 'touch') {
66
+ touchPauseTimer = setTimeout(() => {
67
+ onDblClick();
68
+ }, TOUCH_PAUSE_LIMIT);
69
+ }
51
70
  }
52
71
  }
53
72
 
54
- const onPointerUp = (evt: PointerEvent) => {
55
- const timeDifference = performance.now() - lastPointerDown;
73
+ const onPointerUp = (event: Event) => {
74
+ const evt = event as PointerEvent;
75
+
76
+ if (touchPauseTimer) clearTimeout(touchPauseTimer);
56
77
 
57
78
  if (drawingMode === 'click') {
58
- // Not a single click - ignore
59
- if (timeDifference > 300)
60
- return;
79
+ const timeDifference = evt.timeStamp - lastPointerDown.timeStamp;
61
80
 
62
- evt.stopPropagation();
81
+ const d = distance(
82
+ [lastPointerDown.offsetX, lastPointerDown.offsetY],
83
+ [evt.offsetX, evt.offsetY]);
84
+
85
+ if (timeDifference > 300 || d > 15) // Not a single click - ignore
86
+ return;
63
87
 
64
88
  if (isClosable) {
65
89
  stopDrawing();
@@ -70,17 +94,17 @@
70
94
 
71
95
  cursor = point;
72
96
  } else {
73
- points.push(cursor);
97
+ points.push(cursor!);
74
98
  }
75
99
  } else {
76
100
  // Require minimum drag of 4px
77
101
  if (points.length === 1) {
78
- const dist = distance(points[0], cursor);
102
+ const dist = distance(points[0], cursor!);
79
103
 
80
104
  if (dist <= 4) {
81
105
  // Cancel
82
106
  points = [];
83
- cursor = null;
107
+ cursor = undefined;
84
108
 
85
109
  return;
86
110
  }
@@ -92,28 +116,33 @@
92
116
  if (isClosable) {
93
117
  stopDrawing();
94
118
  } else {
95
- points.push(cursor);
119
+ points.push(cursor!);
96
120
  }
97
121
  }
98
122
  }
99
123
 
100
124
  const onDblClick = () => {
101
- console.log('dblclick');
102
-
125
+ if (!cursor) return;
126
+
127
+ // Require min 3 points (incl. cursor) and minimum
128
+ // polygon area
103
129
  const p = [...points, cursor];
104
130
 
105
131
  const shape: Polygon = {
106
- type: ShapeType.POLYGON,
107
- geometry: {
108
- bounds: boundsFromPoints(p),
109
- points: p
110
- }
132
+ type: ShapeType.POLYGON,
133
+ geometry: {
134
+ bounds: boundsFromPoints(p),
135
+ points: p
111
136
  }
137
+ }
112
138
 
139
+ const area = computeArea(shape);
140
+ if (area > 4) {
113
141
  points = [];
114
- cursor = null;
142
+ cursor = undefined;
115
143
 
116
144
  dispatch('create', shape);
145
+ }
117
146
  }
118
147
 
119
148
  const stopDrawing = () => {
@@ -126,7 +155,7 @@
126
155
  }
127
156
 
128
157
  points = [];
129
- cursor = null;
158
+ cursor = undefined;
130
159
 
131
160
  dispatch('create', shape);
132
161
  }
@@ -139,10 +168,7 @@
139
168
  });
140
169
  </script>
141
170
 
142
- <g
143
- bind:this={container}
144
- class="a9s-annotation a9s-rubberband">
145
-
171
+ <g class="a9s-annotation a9s-rubberband">
146
172
  {#if cursor}
147
173
  {@const coords = (isClosable ? points : [...points, cursor]).map(xy => xy.join(',')).join(' ')}
148
174
  <polygon
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import { createEventDispatcher, onMount } from 'svelte';
3
3
  import type { DrawingMode } from '../../../AnnotoriousOpts';
4
4
  import { ShapeType, type Rectangle } from '../../../model';
@@ -10,18 +10,18 @@
10
10
  export let addEventListener: (type: string, fn: EventListener, capture?: boolean) => void;
11
11
  export let drawingMode: DrawingMode;
12
12
  export let transform: Transform;
13
-
14
- let container: SVGGElement;
15
13
 
16
14
  let lastPointerDown: number;
17
15
 
18
- let origin: [x: number, y: number];
16
+ let origin: [x: number, y: number] | undefined;
19
17
 
20
- let anchor: [number, number];
18
+ let anchor: [number, number] | undefined;
21
19
 
22
20
  let x: number, y: number, w: number, h: number;
23
21
 
24
- const onPointerDown = (evt: PointerEvent) => {
22
+ const onPointerDown = (event: Event) => {
23
+ const evt = event as PointerEvent;
24
+
25
25
  lastPointerDown = performance.now();
26
26
 
27
27
  if (drawingMode === 'drag') {
@@ -35,7 +35,9 @@
35
35
  }
36
36
  }
37
37
 
38
- const onPointerMove = (evt: PointerEvent) => {
38
+ const onPointerMove = (event: Event) => {
39
+ const evt = event as PointerEvent;
40
+
39
41
  if (origin) {
40
42
  anchor = transform.elementToImage(evt.offsetX, evt.offsetY);
41
43
 
@@ -46,7 +48,9 @@
46
48
  }
47
49
  }
48
50
 
49
- const onPointerUp = (evt: PointerEvent) => {
51
+ const onPointerUp = (event: Event) => {
52
+ const evt = event as PointerEvent;
53
+
50
54
  const timeDifference = performance.now() - lastPointerDown;
51
55
 
52
56
  if (drawingMode === 'click') {
@@ -73,8 +77,8 @@
73
77
  evt.stopPropagation();
74
78
  stopDrawing();
75
79
  } else {
76
- origin = null;
77
- anchor = null;
80
+ origin = undefined;
81
+ anchor = undefined;
78
82
  }
79
83
  }
80
84
  }
@@ -98,8 +102,8 @@
98
102
  dispatch('create', shape);
99
103
  }
100
104
 
101
- origin = null;
102
- anchor = null;
105
+ origin = undefined;
106
+ anchor = undefined;
103
107
  }
104
108
 
105
109
  onMount(() => {
@@ -109,10 +113,7 @@
109
113
  });
110
114
  </script>
111
115
 
112
- <g
113
- bind:this={container}
114
- class="a9s-annotation a9s-rubberband">
115
-
116
+ <g class="a9s-annotation a9s-rubberband">
116
117
  {#if origin}
117
118
  <rect
118
119
  class="a9s-outer"
@@ -42,7 +42,7 @@ export const enableResponsive = (image: HTMLImageElement | HTMLCanvasElement, sv
42
42
  set(scale);
43
43
  });
44
44
 
45
- resizeObserver.observe(svg.parentElement);
45
+ resizeObserver.observe(svg.parentElement!);
46
46
  }
47
47
 
48
48
  const destroy = () => {
@@ -1 +1,4 @@
1
- export const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
1
+ export const isTouch = 'ontouchstart' in window
2
+ || navigator.maxTouchPoints > 0
3
+ // @ts-ignore
4
+ || navigator.msMaxTouchPoints > 0;