@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.
- package/dist/Annotorious.d.ts +7 -2
- package/dist/Annotorious.d.ts.map +1 -1
- package/dist/AnnotoriousOpts.d.ts +4 -3
- package/dist/AnnotoriousOpts.d.ts.map +1 -1
- package/dist/annotation/SVGAnnotationLayerPointerEvent.d.ts.map +1 -1
- package/dist/annotation/Transform.d.ts.map +1 -1
- package/dist/annotation/editors/Handle.svelte.d.ts +1 -0
- package/dist/annotation/editors/editorsRegistry.d.ts +1 -1
- package/dist/annotation/editors/editorsRegistry.d.ts.map +1 -1
- package/dist/annotation/editors/index.d.ts +1 -1
- package/dist/annotation/editors/index.d.ts.map +1 -1
- package/dist/annotation/tools/drawingToolsRegistry.d.ts +4 -4
- package/dist/annotation/tools/drawingToolsRegistry.d.ts.map +1 -1
- package/dist/annotation/utils/responsive.d.ts +2 -1
- package/dist/annotation/utils/responsive.d.ts.map +1 -1
- package/dist/annotation/utils/styling.d.ts +1 -1
- package/dist/annotation/utils/styling.d.ts.map +1 -1
- package/dist/annotation/utils/touch.d.ts.map +1 -1
- package/dist/annotorious.css +1 -1
- package/dist/annotorious.es.js +2370 -1991
- package/dist/annotorious.es.js.map +1 -1
- package/dist/annotorious.js +1 -1
- package/dist/annotorious.js.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/keyboardCommands.d.ts +5 -0
- package/dist/keyboardCommands.d.ts.map +1 -0
- package/dist/model/w3c/W3CImageAnnotation.d.ts +11 -0
- package/dist/model/w3c/W3CImageAnnotation.d.ts.map +1 -0
- package/dist/model/w3c/W3CImageFormatAdapter.d.ts +3 -2
- package/dist/model/w3c/W3CImageFormatAdapter.d.ts.map +1 -1
- package/dist/model/w3c/fragment/FragmentSelector.d.ts +1 -2
- package/dist/model/w3c/fragment/FragmentSelector.d.ts.map +1 -1
- package/dist/model/w3c/index.d.ts +1 -0
- package/dist/model/w3c/index.d.ts.map +1 -1
- package/dist/model/w3c/svg/SVG.d.ts.map +1 -1
- package/dist/model/w3c/svg/SVGSelector.d.ts +1 -2
- package/dist/model/w3c/svg/SVGSelector.d.ts.map +1 -1
- package/dist/state/ImageAnnotatorState.d.ts.map +1 -1
- package/dist/state/spatialTree.d.ts +1 -1
- package/dist/state/spatialTree.d.ts.map +1 -1
- package/dist/themes/smart/setTheme.d.ts +3 -1
- package/dist/themes/smart/setTheme.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/Annotorious.css +5 -5
- package/src/Annotorious.ts +44 -29
- package/src/AnnotoriousOpts.ts +11 -6
- package/src/annotation/SVGAnnotationLayer.svelte +21 -15
- package/src/annotation/SVGAnnotationLayerPointerEvent.ts +1 -2
- package/src/annotation/Transform.ts +5 -3
- package/src/annotation/editors/Editor.svelte +10 -11
- package/src/annotation/editors/EditorMount.svelte +3 -3
- package/src/annotation/editors/Handle.svelte +66 -0
- package/src/annotation/editors/index.ts +2 -2
- package/src/annotation/editors/polygon/PolygonEditor.svelte +16 -16
- package/src/annotation/editors/rectangle/RectangleEditor.svelte +46 -43
- package/src/annotation/shapes/Ellipse.svelte +2 -2
- package/src/annotation/shapes/Polygon.svelte +2 -2
- package/src/annotation/shapes/Rectangle.svelte +3 -3
- package/src/annotation/tools/ToolMount.svelte +3 -3
- package/src/annotation/tools/drawingToolsRegistry.ts +2 -1
- package/src/annotation/tools/polygon/RubberbandPolygon.svelte +58 -32
- package/src/annotation/tools/rectangle/RubberbandRectangle.svelte +17 -16
- package/src/annotation/utils/responsive.ts +1 -1
- package/src/annotation/utils/touch.ts +4 -1
- package/src/index.ts +25 -8
- package/src/keyboardCommands.ts +50 -0
- package/src/model/w3c/W3CImageAnnotation.ts +17 -0
- package/src/model/w3c/W3CImageFormatAdapter.ts +54 -20
- package/src/model/w3c/fragment/FragmentSelector.ts +5 -6
- package/src/model/w3c/index.ts +1 -0
- package/src/model/w3c/svg/SVG.ts +1 -2
- package/src/model/w3c/svg/SVGSelector.ts +11 -13
- package/src/state/ImageAnnotatorState.ts +3 -3
- package/src/state/spatialTree.ts +3 -2
- package/src/themes/dark/index.css +2 -2
- package/src/themes/light/index.css +2 -2
- package/src/themes/smart/setTheme.ts +10 -6
- package/dist/annotation/editors/Handle.d.ts +0 -14
- package/dist/annotation/editors/Handle.d.ts.map +0 -1
- 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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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 =
|
|
24
|
-
handle ===
|
|
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(
|
|
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(
|
|
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
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
2
|
-
import
|
|
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
|
|
5
|
+
import { Editor } from '..';
|
|
5
6
|
|
|
6
7
|
/** Props */
|
|
7
8
|
export let shape: Rectangle;
|
|
8
|
-
export let computedStyle: string
|
|
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
|
-
|
|
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 ===
|
|
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
|
|
32
|
-
case
|
|
33
|
-
case
|
|
30
|
+
case 'TOP':
|
|
31
|
+
case 'TOP_LEFT':
|
|
32
|
+
case 'TOP_RIGHT': {
|
|
34
33
|
y0 += dy;
|
|
35
34
|
break;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
case
|
|
39
|
-
case
|
|
40
|
-
case
|
|
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
|
|
48
|
-
case
|
|
49
|
-
case
|
|
46
|
+
case 'LEFT':
|
|
47
|
+
case 'TOP_LEFT':
|
|
48
|
+
case 'BOTTOM_LEFT': {
|
|
50
49
|
x0 += dx;
|
|
51
50
|
break;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
case
|
|
55
|
-
case
|
|
56
|
-
case
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
120
|
+
on:pointerdown={grab('LEFT')}
|
|
122
121
|
x={geom.x} y={geom.y} height={geom.h} width={1} />
|
|
123
122
|
|
|
124
|
-
<
|
|
125
|
-
class="a9s-corner-handle
|
|
126
|
-
on:pointerdown={grab(
|
|
127
|
-
x={geom.x
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
<
|
|
135
|
-
class="a9s-corner-handle
|
|
136
|
-
on:pointerdown={grab(
|
|
137
|
-
x={geom.x + geom.w
|
|
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
|
-
<
|
|
140
|
-
class="a9s-corner-handle
|
|
141
|
-
on:pointerdown={grab(
|
|
142
|
-
x={geom.x
|
|
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
|
|
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)
|
|
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
|
|
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)
|
|
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
|
|
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)
|
|
9
|
+
export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) | undefined;
|
|
10
10
|
|
|
11
11
|
$: computedStyle = computeStyle(annotation, style);
|
|
12
12
|
|
|
13
|
-
|
|
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:
|
|
27
|
-
svg
|
|
28
|
-
cleanup.push(() => svg
|
|
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]:
|
|
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
|
|
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
|
|
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]
|
|
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 = (
|
|
31
|
-
|
|
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 = (
|
|
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 = (
|
|
55
|
-
const
|
|
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
|
-
|
|
59
|
-
if (timeDifference > 300)
|
|
60
|
-
return;
|
|
79
|
+
const timeDifference = evt.timeStamp - lastPointerDown.timeStamp;
|
|
61
80
|
|
|
62
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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 = (
|
|
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 = (
|
|
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 = (
|
|
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 =
|
|
77
|
-
anchor =
|
|
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 =
|
|
102
|
-
anchor =
|
|
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"
|