@annotorious/annotorious 3.0.0-rc.1

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 (183) hide show
  1. package/README.md +6 -0
  2. package/dist/Annotorious.d.ts +15 -0
  3. package/dist/Annotorious.d.ts.map +1 -0
  4. package/dist/AnnotoriousOpts.d.ts +14 -0
  5. package/dist/AnnotoriousOpts.d.ts.map +1 -0
  6. package/dist/annotation/SVGAnnotationLayer.svelte.d.ts +1 -0
  7. package/dist/annotation/SVGAnnotationLayerPointerEvent.d.ts +11 -0
  8. package/dist/annotation/SVGAnnotationLayerPointerEvent.d.ts.map +1 -0
  9. package/dist/annotation/Transform.d.ts +6 -0
  10. package/dist/annotation/Transform.d.ts.map +1 -0
  11. package/dist/annotation/editors/Editor.svelte.d.ts +1 -0
  12. package/dist/annotation/editors/EditorMount.svelte.d.ts +1 -0
  13. package/dist/annotation/editors/Handle.d.ts +14 -0
  14. package/dist/annotation/editors/Handle.d.ts.map +1 -0
  15. package/dist/annotation/editors/editorsRegistry.d.ts +5 -0
  16. package/dist/annotation/editors/editorsRegistry.d.ts.map +1 -0
  17. package/dist/annotation/editors/index.d.ts +7 -0
  18. package/dist/annotation/editors/index.d.ts.map +1 -0
  19. package/dist/annotation/editors/polygon/PolygonEditor.svelte.d.ts +1 -0
  20. package/dist/annotation/editors/polygon/index.d.ts +2 -0
  21. package/dist/annotation/editors/polygon/index.d.ts.map +1 -0
  22. package/dist/annotation/editors/rectangle/RectangleEditor.svelte.d.ts +1 -0
  23. package/dist/annotation/editors/rectangle/index.d.ts +2 -0
  24. package/dist/annotation/editors/rectangle/index.d.ts.map +1 -0
  25. package/dist/annotation/index.d.ts +7 -0
  26. package/dist/annotation/index.d.ts.map +1 -0
  27. package/dist/annotation/shapes/Ellipse.svelte.d.ts +1 -0
  28. package/dist/annotation/shapes/Polygon.svelte.d.ts +1 -0
  29. package/dist/annotation/shapes/Rectangle.svelte.d.ts +1 -0
  30. package/dist/annotation/shapes/index.d.ts +4 -0
  31. package/dist/annotation/shapes/index.d.ts.map +1 -0
  32. package/dist/annotation/tools/DrawingToolConfig.d.ts +8 -0
  33. package/dist/annotation/tools/DrawingToolConfig.d.ts.map +1 -0
  34. package/dist/annotation/tools/ToolMount.svelte.d.ts +1 -0
  35. package/dist/annotation/tools/drawingToolsRegistry.d.ts +17 -0
  36. package/dist/annotation/tools/drawingToolsRegistry.d.ts.map +1 -0
  37. package/dist/annotation/tools/index.d.ts +5 -0
  38. package/dist/annotation/tools/index.d.ts.map +1 -0
  39. package/dist/annotation/tools/polygon/RubberbandPolygon.svelte.d.ts +1 -0
  40. package/dist/annotation/tools/polygon/index.d.ts +2 -0
  41. package/dist/annotation/tools/polygon/index.d.ts.map +1 -0
  42. package/dist/annotation/tools/rectangle/RubberbandRectangle.svelte.d.ts +1 -0
  43. package/dist/annotation/tools/rectangle/index.d.ts +2 -0
  44. package/dist/annotation/tools/rectangle/index.d.ts.map +1 -0
  45. package/dist/annotation/utils/index.d.ts +4 -0
  46. package/dist/annotation/utils/index.d.ts.map +1 -0
  47. package/dist/annotation/utils/math.d.ts +2 -0
  48. package/dist/annotation/utils/math.d.ts.map +1 -0
  49. package/dist/annotation/utils/responsive.d.ts +5 -0
  50. package/dist/annotation/utils/responsive.d.ts.map +1 -0
  51. package/dist/annotation/utils/styling.d.ts +4 -0
  52. package/dist/annotation/utils/styling.d.ts.map +1 -0
  53. package/dist/annotation/utils/touch.d.ts +2 -0
  54. package/dist/annotation/utils/touch.d.ts.map +1 -0
  55. package/dist/annotorious.css +1 -0
  56. package/dist/annotorious.es.js +3890 -0
  57. package/dist/annotorious.es.js.map +1 -0
  58. package/dist/annotorious.js +2 -0
  59. package/dist/annotorious.js.map +1 -0
  60. package/dist/index.d.ts +12 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/model/core/ImageAnnotation.d.ts +9 -0
  63. package/dist/model/core/ImageAnnotation.d.ts.map +1 -0
  64. package/dist/model/core/Shape.d.ts +20 -0
  65. package/dist/model/core/Shape.d.ts.map +1 -0
  66. package/dist/model/core/ellipse/Ellipse.d.ts +12 -0
  67. package/dist/model/core/ellipse/Ellipse.d.ts.map +1 -0
  68. package/dist/model/core/ellipse/ellipseUtils.d.ts +2 -0
  69. package/dist/model/core/ellipse/ellipseUtils.d.ts.map +1 -0
  70. package/dist/model/core/ellipse/index.d.ts +3 -0
  71. package/dist/model/core/ellipse/index.d.ts.map +1 -0
  72. package/dist/model/core/index.d.ts +7 -0
  73. package/dist/model/core/index.d.ts.map +1 -0
  74. package/dist/model/core/polygon/Polygon.d.ts +9 -0
  75. package/dist/model/core/polygon/Polygon.d.ts.map +1 -0
  76. package/dist/model/core/polygon/index.d.ts +3 -0
  77. package/dist/model/core/polygon/index.d.ts.map +1 -0
  78. package/dist/model/core/polygon/polygonUtils.d.ts +2 -0
  79. package/dist/model/core/polygon/polygonUtils.d.ts.map +1 -0
  80. package/dist/model/core/rectangle/Rectangle.d.ts +12 -0
  81. package/dist/model/core/rectangle/Rectangle.d.ts.map +1 -0
  82. package/dist/model/core/rectangle/index.d.ts +3 -0
  83. package/dist/model/core/rectangle/index.d.ts.map +1 -0
  84. package/dist/model/core/rectangle/rectangleUtils.d.ts +4 -0
  85. package/dist/model/core/rectangle/rectangleUtils.d.ts.map +1 -0
  86. package/dist/model/core/shapeUtils.d.ts +35 -0
  87. package/dist/model/core/shapeUtils.d.ts.map +1 -0
  88. package/dist/model/index.d.ts +3 -0
  89. package/dist/model/index.d.ts.map +1 -0
  90. package/dist/model/w3c/W3CImageFormatAdapter.d.ts +7 -0
  91. package/dist/model/w3c/W3CImageFormatAdapter.d.ts.map +1 -0
  92. package/dist/model/w3c/fragment/FragmentSelector.d.ts +10 -0
  93. package/dist/model/w3c/fragment/FragmentSelector.d.ts.map +1 -0
  94. package/dist/model/w3c/fragment/index.d.ts +2 -0
  95. package/dist/model/w3c/fragment/index.d.ts.map +1 -0
  96. package/dist/model/w3c/index.d.ts +4 -0
  97. package/dist/model/w3c/index.d.ts.map +1 -0
  98. package/dist/model/w3c/svg/SVG.d.ts +5 -0
  99. package/dist/model/w3c/svg/SVG.d.ts.map +1 -0
  100. package/dist/model/w3c/svg/SVGSelector.d.ts +9 -0
  101. package/dist/model/w3c/svg/SVGSelector.d.ts.map +1 -0
  102. package/dist/model/w3c/svg/index.d.ts +2 -0
  103. package/dist/model/w3c/svg/index.d.ts.map +1 -0
  104. package/dist/state/ImageAnnotationStore.d.ts +11 -0
  105. package/dist/state/ImageAnnotationStore.d.ts.map +1 -0
  106. package/dist/state/ImageAnnotatorState.d.ts +12 -0
  107. package/dist/state/ImageAnnotatorState.d.ts.map +1 -0
  108. package/dist/state/index.d.ts +3 -0
  109. package/dist/state/index.d.ts.map +1 -0
  110. package/dist/state/spatialTree.d.ts +21 -0
  111. package/dist/state/spatialTree.d.ts.map +1 -0
  112. package/dist/themes/index.d.ts +2 -0
  113. package/dist/themes/index.d.ts.map +1 -0
  114. package/dist/themes/smart/index.d.ts +2 -0
  115. package/dist/themes/smart/index.d.ts.map +1 -0
  116. package/dist/themes/smart/setTheme.d.ts +3 -0
  117. package/dist/themes/smart/setTheme.d.ts.map +1 -0
  118. package/package.json +55 -0
  119. package/src/Annotorious.css +74 -0
  120. package/src/Annotorious.ts +158 -0
  121. package/src/AnnotoriousOpts.ts +40 -0
  122. package/src/annotation/SVGAnnotationLayer.svelte +169 -0
  123. package/src/annotation/SVGAnnotationLayerPointerEvent.ts +55 -0
  124. package/src/annotation/Transform.ts +24 -0
  125. package/src/annotation/editors/Editor.svelte +61 -0
  126. package/src/annotation/editors/EditorMount.svelte +44 -0
  127. package/src/annotation/editors/Handle.ts +21 -0
  128. package/src/annotation/editors/editorsRegistry.ts +14 -0
  129. package/src/annotation/editors/index.ts +7 -0
  130. package/src/annotation/editors/polygon/PolygonEditor.svelte +64 -0
  131. package/src/annotation/editors/polygon/index.ts +1 -0
  132. package/src/annotation/editors/rectangle/RectangleEditor.svelte +143 -0
  133. package/src/annotation/editors/rectangle/index.ts +1 -0
  134. package/src/annotation/index.ts +7 -0
  135. package/src/annotation/shapes/Ellipse.svelte +32 -0
  136. package/src/annotation/shapes/Polygon.svelte +26 -0
  137. package/src/annotation/shapes/Rectangle.svelte +32 -0
  138. package/src/annotation/shapes/index.ts +3 -0
  139. package/src/annotation/tools/DrawingToolConfig.ts +9 -0
  140. package/src/annotation/tools/ToolMount.svelte +49 -0
  141. package/src/annotation/tools/drawingToolsRegistry.ts +26 -0
  142. package/src/annotation/tools/index.ts +4 -0
  143. package/src/annotation/tools/polygon/RubberbandPolygon.svelte +165 -0
  144. package/src/annotation/tools/polygon/index.ts +1 -0
  145. package/src/annotation/tools/rectangle/RubberbandRectangle.svelte +131 -0
  146. package/src/annotation/tools/rectangle/index.ts +1 -0
  147. package/src/annotation/utils/index.ts +3 -0
  148. package/src/annotation/utils/math.ts +6 -0
  149. package/src/annotation/utils/responsive.ts +56 -0
  150. package/src/annotation/utils/styling.ts +19 -0
  151. package/src/annotation/utils/touch.ts +1 -0
  152. package/src/index.ts +20 -0
  153. package/src/model/core/ImageAnnotation.ts +14 -0
  154. package/src/model/core/Shape.ts +37 -0
  155. package/src/model/core/ellipse/Ellipse.ts +21 -0
  156. package/src/model/core/ellipse/ellipseUtils.ts +28 -0
  157. package/src/model/core/ellipse/index.ts +2 -0
  158. package/src/model/core/index.ts +6 -0
  159. package/src/model/core/polygon/Polygon.ts +15 -0
  160. package/src/model/core/polygon/index.ts +2 -0
  161. package/src/model/core/polygon/polygonUtils.ts +43 -0
  162. package/src/model/core/rectangle/Rectangle.ts +21 -0
  163. package/src/model/core/rectangle/index.ts +2 -0
  164. package/src/model/core/rectangle/rectangleUtils.ts +17 -0
  165. package/src/model/core/shapeUtils.ts +57 -0
  166. package/src/model/index.ts +2 -0
  167. package/src/model/w3c/W3CImageFormatAdapter.ts +83 -0
  168. package/src/model/w3c/fragment/FragmentSelector.ts +59 -0
  169. package/src/model/w3c/fragment/index.ts +1 -0
  170. package/src/model/w3c/index.ts +3 -0
  171. package/src/model/w3c/svg/SVG.ts +36 -0
  172. package/src/model/w3c/svg/SVGSelector.ts +99 -0
  173. package/src/model/w3c/svg/index.ts +1 -0
  174. package/src/state/ImageAnnotationStore.ts +18 -0
  175. package/src/state/ImageAnnotatorState.ts +88 -0
  176. package/src/state/index.ts +2 -0
  177. package/src/state/spatialTree.ts +108 -0
  178. package/src/themes/dark/index.css +24 -0
  179. package/src/themes/index.ts +1 -0
  180. package/src/themes/light/index.css +30 -0
  181. package/src/themes/smart/index.ts +1 -0
  182. package/src/themes/smart/setTheme.ts +46 -0
  183. package/src/vite-env.d.ts +2 -0
@@ -0,0 +1,143 @@
1
+ <script type="ts">
2
+ import type { Rectangle } from '../../../model';
3
+ import type { Transform } from '../../Transform';
4
+ import { Editor, Handle } from '..';
5
+
6
+ /** Props */
7
+ export let shape: Rectangle;
8
+ export let computedStyle: string = undefined;
9
+ export let transform: Transform;
10
+ export let viewportScale: number = 1;
11
+
12
+ $: geom = shape.geometry;
13
+
14
+ $: handleSize = 10 / viewportScale;
15
+
16
+ const editor = (rectangle: Rectangle, handle: Handle, delta: [number, number]) => {
17
+ const initialBounds = rectangle.geometry.bounds;
18
+
19
+ let [x0, y0] = [initialBounds.minX, initialBounds.minY];
20
+ let [x1, y1] = [initialBounds.maxX, initialBounds.maxY];
21
+
22
+ const [dx, dy] = delta;
23
+
24
+ if (handle === Handle.SHAPE) {
25
+ x0 += dx;
26
+ x1 += dx;
27
+ y0 += dy;
28
+ y1 += dy;
29
+ } else {
30
+ switch (handle) {
31
+ case Handle.TOP:
32
+ case Handle.TOP_LEFT:
33
+ case Handle.TOP_RIGHT: {
34
+ y0 += dy;
35
+ break;
36
+ }
37
+
38
+ case Handle.BOTTOM:
39
+ case Handle.BOTTOM_LEFT:
40
+ case Handle.BOTTOM_RIGHT: {
41
+ y1 += dy;
42
+ break;
43
+ }
44
+ }
45
+
46
+ switch (handle) {
47
+ case Handle.LEFT:
48
+ case Handle.TOP_LEFT:
49
+ case Handle.BOTTOM_LEFT: {
50
+ x0 += dx;
51
+ break;
52
+ }
53
+
54
+ case Handle.RIGHT:
55
+ case Handle.TOP_RIGHT:
56
+ case Handle.BOTTOM_RIGHT: {
57
+ x1 += dx;
58
+ break;
59
+ }
60
+ }
61
+ }
62
+
63
+ const x = Math.min(x0, x1);
64
+ const y = Math.min(y0, y1);
65
+ const w = Math.abs(x1 - x0);
66
+ const h = Math.abs(y1 - y0);
67
+
68
+ return {
69
+ ...rectangle,
70
+ geometry: {
71
+ x, y, w, h,
72
+ bounds: {
73
+ minX: x,
74
+ minY: y,
75
+ maxX: x + w,
76
+ maxY: y + h
77
+ }
78
+ }
79
+ };
80
+ }
81
+ </script>
82
+
83
+ <Editor
84
+ shape={shape}
85
+ transform={transform}
86
+ editor={editor}
87
+ on:grab
88
+ on:change
89
+ on:release
90
+ let:grab={grab}>
91
+
92
+ <rect
93
+ class="a9s-outer"
94
+ style={computedStyle ? 'display:none;' : undefined}
95
+ on:pointerdown={grab(Handle.SHAPE)}
96
+ x={geom.x} y={geom.y} width={geom.w} height={geom.h} />
97
+
98
+ <rect
99
+ class="a9s-inner a9s-shape-handle"
100
+ style={computedStyle}
101
+ on:pointerdown={grab(Handle.SHAPE)}
102
+ x={geom.x} y={geom.y} width={geom.w} height={geom.h} />
103
+
104
+ <rect
105
+ class="a9s-edge-handle a9s-edge-handle-top"
106
+ on:pointerdown={grab(Handle.TOP)}
107
+ x={geom.x} y={geom.y} height={1} width={geom.w} />
108
+
109
+ <rect
110
+ class="a9s-edge-handle a9s-edge-handle-right"
111
+ on:pointerdown={grab(Handle.RIGHT)}
112
+ x={geom.x + geom.w} y={geom.y} height={geom.h} width={1}/>
113
+
114
+ <rect
115
+ class="a9s-edge-handle a9s-edge-handle-bottom"
116
+ on:pointerdown={grab(Handle.BOTTOM)}
117
+ x={geom.x} y={geom.y + geom.h} height={1} width={geom.w} />
118
+
119
+ <rect
120
+ class="a9s-edge-handle a9s-edge-handle-left"
121
+ on:pointerdown={grab(Handle.LEFT)}
122
+ x={geom.x} y={geom.y} height={geom.h} width={1} />
123
+
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} />
133
+
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} />
138
+
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} />
143
+ </Editor>
@@ -0,0 +1 @@
1
+ export { default as RectangleEditor } from './RectangleEditor.svelte';
@@ -0,0 +1,7 @@
1
+ export * from './editors';
2
+ export * from './tools';
3
+ export * from './utils';
4
+
5
+ export { default as SVGAnnotationLayer } from './SVGAnnotationLayer.svelte';
6
+ export * from './SVGAnnotationLayerPointerEvent';
7
+ export * from './Transform';
@@ -0,0 +1,32 @@
1
+ <script type="ts">
2
+ import type { DrawingStyle } from '@annotorious/core';
3
+ import type { Geometry, EllipseGeometry, ImageAnnotation } from '../../model';
4
+ import { computeStyle } from '../utils/styling';
5
+
6
+ /** Props */
7
+ export let annotation: ImageAnnotation;
8
+ export let geom: Geometry;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
10
+
11
+ $: computedStyle = computeStyle(annotation, style);
12
+
13
+ const { cx, cy, rx, ry } = geom as EllipseGeometry;
14
+ </script>
15
+
16
+ <g data-id={annotation.id}>
17
+ <ellipse
18
+ class="a9s-outer"
19
+ style={computedStyle ? 'display:none;' : undefined}
20
+ cx={cx}
21
+ cy={cy}
22
+ rx={rx}
23
+ ry={ry} />
24
+
25
+ <ellipse
26
+ class="a9s-inner"
27
+ style={computedStyle}
28
+ cx={cx}
29
+ cy={cy}
30
+ rx={rx}
31
+ ry={ry} />
32
+ </g>
@@ -0,0 +1,26 @@
1
+ <script type="ts">
2
+ import type { DrawingStyle } from '@annotorious/core';
3
+ import type { Geometry, ImageAnnotation, PolygonGeometry } from '../../model';
4
+ import { computeStyle } from '../utils/styling';
5
+
6
+ /** Props **/
7
+ export let annotation: ImageAnnotation;
8
+ export let geom: Geometry;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
10
+
11
+ $: computedStyle = computeStyle(annotation, style);
12
+
13
+ const { points } = geom as PolygonGeometry;
14
+ </script>
15
+
16
+ <g data-id={annotation.id}>
17
+ <polygon
18
+ class="a9s-outer"
19
+ style={computedStyle ? 'display:none;' : undefined}
20
+ points={points.map(xy => xy.join(',')).join(' ')} />
21
+
22
+ <polygon
23
+ class="a9s-inner"
24
+ style={computedStyle}
25
+ points={points.map(xy => xy.join(',')).join(' ')} />
26
+ </g>
@@ -0,0 +1,32 @@
1
+ <script type="ts">
2
+ import type { DrawingStyle } from '@annotorious/core';
3
+ import type { Geometry, ImageAnnotation, RectangleGeometry } from '../../model';
4
+ import { computeStyle } from '../utils/styling';
5
+
6
+ /** Props **/
7
+ export let annotation: ImageAnnotation;
8
+ export let geom: Geometry;
9
+ export let style: DrawingStyle | ((annotation: ImageAnnotation) => DrawingStyle) = undefined;
10
+
11
+ $: computedStyle = computeStyle(annotation, style);
12
+
13
+ const { x, y, w, h } = geom as RectangleGeometry;
14
+ </script>
15
+
16
+ <g data-id={annotation.id}>
17
+ <rect
18
+ class="a9s-outer"
19
+ style={computedStyle ? 'display:none;' : undefined}
20
+ x={x}
21
+ y={y}
22
+ width={w}
23
+ height={h} />
24
+
25
+ <rect
26
+ class="a9s-inner"
27
+ style={computedStyle}
28
+ x={x}
29
+ y={y}
30
+ width={w}
31
+ height={h} />
32
+ </g>
@@ -0,0 +1,3 @@
1
+ export { default as Ellipse } from './Ellipse.svelte';
2
+ export { default as Polygon } from './Polygon.svelte';
3
+ export { default as Rectangle } from './Rectangle.svelte';
@@ -0,0 +1,9 @@
1
+ import type { SvelteComponent } from 'svelte';
2
+
3
+ export interface ToolConfig {
4
+
5
+ component: typeof SvelteComponent;
6
+
7
+ opts?: { [key: string]: any }
8
+
9
+ }
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import { createEventDispatcher, onMount, type SvelteComponent } from 'svelte';
3
+ import type { Transform } from '../Transform';
4
+ import type { Shape } from 'src/model';
5
+ import type { DrawingMode } from 'src/AnnotoriousOpts';
6
+
7
+ const dispatch = createEventDispatcher<{ create: Shape }>();
8
+
9
+ /** Props **/
10
+ export let drawingMode: DrawingMode;
11
+ export let target: SVGGElement;
12
+ export let tool: typeof SvelteComponent;
13
+ export let transform: Transform;
14
+ export let viewportScale: number;
15
+
16
+ let toolComponent: SvelteComponent;
17
+
18
+ $: if (toolComponent) toolComponent.$set({ transform });
19
+ $: if (toolComponent) toolComponent.$set({ viewportScale });
20
+
21
+ onMount(() => {
22
+ const svg = target.closest('svg');
23
+
24
+ const cleanup: Function[] = [];
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));
29
+ }
30
+
31
+ toolComponent = new tool({
32
+ target,
33
+ props: {
34
+ addEventListener,
35
+ drawingMode,
36
+ transform,
37
+ viewportScale
38
+ }
39
+ });
40
+
41
+ toolComponent.$on('create',
42
+ event => dispatch('create', event.detail));
43
+
44
+ return () => {
45
+ cleanup.forEach(fn => fn());
46
+ toolComponent.$destroy();
47
+ }
48
+ });
49
+ </script>
@@ -0,0 +1,26 @@
1
+ import type { SvelteComponent } from 'svelte';
2
+ import { RubberbandRectangle } from './rectangle';
3
+ import { RubberbandPolygon } from './polygon';
4
+ import type { DrawingMode } from '../../AnnotoriousOpts';
5
+
6
+ export type DrawingTool = 'rectangle' | 'polygon' | string;
7
+
8
+ export type DrawingToolOpts = {
9
+
10
+ drawingMode?: DrawingMode;
11
+
12
+ [key: string]: string;
13
+
14
+ }
15
+
16
+ const REGISTERED = new Map<DrawingTool, { tool: typeof SvelteComponent, opts?: DrawingToolOpts }>([
17
+ ['rectangle', { tool: RubberbandRectangle }],
18
+ ['polygon', { tool: RubberbandPolygon }]
19
+ ]);
20
+
21
+ export const listDrawingTools = () => [...REGISTERED.keys()];
22
+
23
+ export const getTool = (name: string) => REGISTERED.get(name);
24
+
25
+ export const registerTool = (name: string, tool: typeof SvelteComponent, opts?: DrawingToolOpts) =>
26
+ REGISTERED.set(name, { tool, opts });
@@ -0,0 +1,4 @@
1
+ export { default as ToolMount } from './ToolMount.svelte';
2
+ export * from './rectangle';
3
+ export * from './DrawingToolConfig';
4
+ export * from './drawingToolsRegistry';
@@ -0,0 +1,165 @@
1
+ <script type="ts">
2
+ import { onMount, createEventDispatcher } from 'svelte';
3
+ import type { DrawingMode } from '../../../AnnotoriousOpts';
4
+ import { boundsFromPoints, ShapeType, type Polygon } from '../../../model';
5
+ import { distance } from '../../utils';
6
+ import type { Transform } from '../..';
7
+
8
+ const dispatch = createEventDispatcher<{ create: Polygon }>();
9
+
10
+ /** Props **/
11
+ export let addEventListener: (type: string, fn: EventListener, capture?: boolean) => void;
12
+ export let drawingMode: DrawingMode;
13
+ export let transform: Transform;
14
+ export let viewportScale = 1;
15
+
16
+ let container: SVGGElement;
17
+
18
+ let lastPointerDown: number;
19
+
20
+ let points: [number, number][] = [];
21
+
22
+ let cursor: [number, number] = null;
23
+
24
+ let isClosable: boolean = false;
25
+
26
+ const CLOSE_DISTANCE = 20;
27
+
28
+ $: handleSize = 10 / viewportScale;
29
+
30
+ const onPointerDown = (evt: PointerEvent) => {
31
+ lastPointerDown = performance.now();
32
+
33
+ if (drawingMode === 'drag') {
34
+ if (points.length === 0) {
35
+ const point = transform.elementToImage(evt.offsetX, evt.offsetY);
36
+ points.push(point);
37
+
38
+ cursor = point;
39
+ }
40
+ }
41
+ }
42
+
43
+ const onPointerMove = (evt: PointerEvent) => {
44
+ if (points.length > 0) {
45
+ cursor = transform.elementToImage(evt.offsetX, evt.offsetY);
46
+
47
+ if (points.length > 2) {
48
+ const d = distance(cursor, points[0]) * viewportScale;
49
+ isClosable = d < CLOSE_DISTANCE;
50
+ }
51
+ }
52
+ }
53
+
54
+ const onPointerUp = (evt: PointerEvent) => {
55
+ const timeDifference = performance.now() - lastPointerDown;
56
+
57
+ if (drawingMode === 'click') {
58
+ // Not a single click - ignore
59
+ if (timeDifference > 300)
60
+ return;
61
+
62
+ evt.stopPropagation();
63
+
64
+ if (isClosable) {
65
+ stopDrawing();
66
+ } else if (points.length === 0) {
67
+ // Start drawing
68
+ const point = transform.elementToImage(evt.offsetX, evt.offsetY);
69
+ points.push(point);
70
+
71
+ cursor = point;
72
+ } else {
73
+ points.push(cursor);
74
+ }
75
+ } else {
76
+ // Require minimum drag of 4px
77
+ if (points.length === 1) {
78
+ const dist = distance(points[0], cursor);
79
+
80
+ if (dist <= 4) {
81
+ // Cancel
82
+ points = [];
83
+ cursor = null;
84
+
85
+ return;
86
+ }
87
+ }
88
+
89
+ // Stop click event from propagating if we're drawing
90
+ evt.stopImmediatePropagation();
91
+
92
+ if (isClosable) {
93
+ stopDrawing();
94
+ } else {
95
+ points.push(cursor);
96
+ }
97
+ }
98
+ }
99
+
100
+ const onDblClick = () => {
101
+ console.log('dblclick');
102
+
103
+ const p = [...points, cursor];
104
+
105
+ const shape: Polygon = {
106
+ type: ShapeType.POLYGON,
107
+ geometry: {
108
+ bounds: boundsFromPoints(p),
109
+ points: p
110
+ }
111
+ }
112
+
113
+ points = [];
114
+ cursor = null;
115
+
116
+ dispatch('create', shape);
117
+ }
118
+
119
+ const stopDrawing = () => {
120
+ const shape: Polygon = {
121
+ type: ShapeType.POLYGON,
122
+ geometry: {
123
+ bounds: boundsFromPoints(points),
124
+ points: [...points]
125
+ }
126
+ }
127
+
128
+ points = [];
129
+ cursor = null;
130
+
131
+ dispatch('create', shape);
132
+ }
133
+
134
+ onMount(() => {
135
+ addEventListener('pointerdown', onPointerDown, true);
136
+ addEventListener('pointermove', onPointerMove);
137
+ addEventListener('pointerup', onPointerUp, true);
138
+ addEventListener('dblclick', onDblClick, true);
139
+ });
140
+ </script>
141
+
142
+ <g
143
+ bind:this={container}
144
+ class="a9s-annotation a9s-rubberband">
145
+
146
+ {#if cursor}
147
+ {@const coords = (isClosable ? points : [...points, cursor]).map(xy => xy.join(',')).join(' ')}
148
+ <polygon
149
+ class="a9s-outer"
150
+ points={coords} />
151
+
152
+ <polygon
153
+ class="a9s-inner"
154
+ points={coords} />
155
+
156
+ {#if isClosable}
157
+ <rect
158
+ class="a9s-corner-handle"
159
+ x={points[0][0] - handleSize / 2}
160
+ y={points[0][1] - handleSize / 2}
161
+ height={handleSize}
162
+ width={handleSize} />
163
+ {/if}
164
+ {/if}
165
+ </g>
@@ -0,0 +1 @@
1
+ export { default as RubberbandPolygon } from './RubberbandPolygon.svelte';
@@ -0,0 +1,131 @@
1
+ <script type="ts">
2
+ import { createEventDispatcher, onMount } from 'svelte';
3
+ import type { DrawingMode } from '../../../AnnotoriousOpts';
4
+ import { ShapeType, type Rectangle } from '../../../model';
5
+ import type { Transform } from '../..';
6
+
7
+ const dispatch = createEventDispatcher<{ create: Rectangle }>();
8
+
9
+ /** Props **/
10
+ export let addEventListener: (type: string, fn: EventListener, capture?: boolean) => void;
11
+ export let drawingMode: DrawingMode;
12
+ export let transform: Transform;
13
+
14
+ let container: SVGGElement;
15
+
16
+ let lastPointerDown: number;
17
+
18
+ let origin: [x: number, y: number];
19
+
20
+ let anchor: [number, number];
21
+
22
+ let x: number, y: number, w: number, h: number;
23
+
24
+ const onPointerDown = (evt: PointerEvent) => {
25
+ lastPointerDown = performance.now();
26
+
27
+ if (drawingMode === 'drag') {
28
+ origin = transform.elementToImage(evt.offsetX, evt.offsetY);
29
+ anchor = origin;
30
+
31
+ x = origin[0];
32
+ y = origin[1];
33
+ w = 1;
34
+ h = 1;
35
+ }
36
+ }
37
+
38
+ const onPointerMove = (evt: PointerEvent) => {
39
+ if (origin) {
40
+ anchor = transform.elementToImage(evt.offsetX, evt.offsetY);
41
+
42
+ x = Math.min(anchor[0], origin[0]);
43
+ y = Math.min(anchor[1], origin[1]);
44
+ w = Math.abs(anchor[0] - origin[0]);
45
+ h = Math.abs(anchor[1] - origin[1]);
46
+ }
47
+ }
48
+
49
+ const onPointerUp = (evt: PointerEvent) => {
50
+ const timeDifference = performance.now() - lastPointerDown;
51
+
52
+ if (drawingMode === 'click') {
53
+ // Not a single click - ignore
54
+ if (timeDifference > 300)
55
+ return;
56
+
57
+ evt.stopPropagation();
58
+
59
+ if (origin) {
60
+ stopDrawing();
61
+ } else {
62
+ // Start drawing
63
+ origin = transform.elementToImage(evt.offsetX, evt.offsetY);
64
+ anchor = origin;
65
+
66
+ x = origin[0];
67
+ y = origin[1];
68
+ w = 1;
69
+ h = 1;
70
+ }
71
+ } else if (origin) {
72
+ if (timeDifference > 300 || w * h > 100) {
73
+ evt.stopPropagation();
74
+ stopDrawing();
75
+ } else {
76
+ origin = null;
77
+ anchor = null;
78
+ }
79
+ }
80
+ }
81
+
82
+ const stopDrawing = () => {
83
+ // Require 4x4 pixels minimum
84
+ if (w * h > 15) {
85
+ const shape: Rectangle = {
86
+ type: ShapeType.RECTANGLE,
87
+ geometry: {
88
+ bounds: {
89
+ minX: x,
90
+ minY: y,
91
+ maxX: x + w,
92
+ maxY: y + h
93
+ },
94
+ x, y, w, h
95
+ }
96
+ }
97
+
98
+ dispatch('create', shape);
99
+ }
100
+
101
+ origin = null;
102
+ anchor = null;
103
+ }
104
+
105
+ onMount(() => {
106
+ addEventListener('pointerdown', onPointerDown);
107
+ addEventListener('pointermove', onPointerMove);
108
+ addEventListener('pointerup', onPointerUp, true);
109
+ });
110
+ </script>
111
+
112
+ <g
113
+ bind:this={container}
114
+ class="a9s-annotation a9s-rubberband">
115
+
116
+ {#if origin}
117
+ <rect
118
+ class="a9s-outer"
119
+ x={x}
120
+ y={y}
121
+ width={w}
122
+ height={h} />
123
+
124
+ <rect
125
+ class="a9s-inner"
126
+ x={x}
127
+ y={y}
128
+ width={w}
129
+ height={h} />
130
+ {/if}
131
+ </g>
@@ -0,0 +1 @@
1
+ export { default as RubberbandRectangle } from './RubberbandRectangle.svelte';
@@ -0,0 +1,3 @@
1
+ export * from './math';
2
+ export * from './responsive';
3
+ export * from './touch';
@@ -0,0 +1,6 @@
1
+ export const distance = (a: [number, number], b: [number, number]): number => {
2
+ const dx = Math.abs(b[0] - a[0]);
3
+ const dy = Math.abs(b[1] - a[1]);
4
+
5
+ return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
6
+ }