@annotorious/annotorious 3.4.6 → 3.5.0

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 (38) hide show
  1. package/dist/annotation/shapes/Line.svelte.d.ts +1 -0
  2. package/dist/annotation/shapes/index.d.ts +1 -0
  3. package/dist/annotation/utils/index.d.ts +0 -1
  4. package/dist/annotorious.css +1 -1
  5. package/dist/annotorious.es.js +1547 -1334
  6. package/dist/annotorious.es.js.map +1 -1
  7. package/dist/annotorious.js +2 -2
  8. package/dist/annotorious.js.map +1 -1
  9. package/dist/model/core/Shape.d.ts +2 -1
  10. package/dist/model/core/index.d.ts +1 -0
  11. package/dist/model/core/line/Line.d.ts +8 -0
  12. package/dist/model/core/line/index.d.ts +2 -0
  13. package/dist/model/core/line/lineUtils.d.ts +1 -0
  14. package/dist/model/core/shapeUtils.d.ts +4 -2
  15. package/dist/state/ImageAnnotationStore.d.ts +1 -1
  16. package/dist/state/spatialTree.d.ts +1 -1
  17. package/package.json +4 -4
  18. package/src/Annotorious.css +1 -0
  19. package/src/annotation/SVGAnnotationLayer.svelte +6 -2
  20. package/src/annotation/editors/multipolygon/MultiPolygonEditor.svelte +3 -5
  21. package/src/annotation/editors/polygon/PolygonEditor.svelte +1 -1
  22. package/src/annotation/shapes/Line.svelte +33 -0
  23. package/src/annotation/shapes/index.ts +2 -1
  24. package/src/annotation/tools/polygon/RubberbandPolygon.svelte +2 -2
  25. package/src/annotation/tools/rectangle/RubberbandRectangle.svelte +1 -1
  26. package/src/annotation/utils/index.ts +0 -1
  27. package/src/model/core/Shape.ts +3 -1
  28. package/src/model/core/index.ts +1 -0
  29. package/src/model/core/line/Line.ts +15 -0
  30. package/src/model/core/line/index.ts +2 -0
  31. package/src/model/core/line/lineUtils.ts +23 -0
  32. package/src/model/core/shapeUtils.ts +11 -3
  33. package/src/model/w3c/svg/SVGSelector.ts +51 -10
  34. package/src/state/ImageAnnotationStore.ts +1 -1
  35. package/src/state/ImageAnnotatorState.ts +5 -3
  36. package/src/state/spatialTree.ts +6 -6
  37. package/dist/annotation/utils/math.d.ts +0 -1
  38. package/src/annotation/utils/math.ts +0 -6
@@ -7,7 +7,8 @@ export declare enum ShapeType {
7
7
  ELLIPSE = "ELLIPSE",
8
8
  MULTIPOLYGLON = "MULTIPOLYGON",
9
9
  POLYGON = "POLYGON",
10
- RECTANGLE = "RECTANGLE"
10
+ RECTANGLE = "RECTANGLE",
11
+ LINE = "LINE"
11
12
  }
12
13
  export interface Geometry {
13
14
  bounds: Bounds;
@@ -1,4 +1,5 @@
1
1
  export * from './ellipse';
2
+ export * from './line';
2
3
  export * from './multipolygon';
3
4
  export * from './polygon';
4
5
  export * from './rectangle';
@@ -0,0 +1,8 @@
1
+ import { Bounds, Geometry, Shape } from '../Shape';
2
+ export interface Line extends Shape {
3
+ geometry: LineGeometry;
4
+ }
5
+ export interface LineGeometry extends Geometry {
6
+ points: [[number, number], [number, number]];
7
+ bounds: Bounds;
8
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Line';
2
+ export * from './lineUtils';
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { Bounds, Shape, ShapeType } from './Shape';
2
2
  export interface ShapeUtil<T extends Shape> {
3
3
  area: (shape: T) => number;
4
- intersects: (shape: T, x: number, y: number) => boolean;
4
+ intersects: (shape: T, x: number, y: number, buffer?: number) => boolean;
5
5
  }
6
6
  /**
7
7
  * Registers a new ShapeUtil for a given shape type.
@@ -20,9 +20,10 @@ export declare const computeArea: (shape: Shape) => number;
20
20
  * @param shape the shape
21
21
  * @param x point x coord
22
22
  * @param y point y coord
23
+ * @param buffer optional buffer around the point to consider as intersection
23
24
  * @returns true if shape and point intersect
24
25
  */
25
- export declare const intersects: (shape: Shape, x: number, y: number) => boolean;
26
+ export declare const intersects: (shape: Shape, x: number, y: number, buffer?: number) => boolean;
26
27
  /**
27
28
  * Computes Bounds from a given list of points.
28
29
  * @param points the points
@@ -33,3 +34,4 @@ export declare const computePolygonArea: (points: [number, number][]) => number;
33
34
  export declare const isPointInPolygon: (points: [number, number][], x: number, y: number) => boolean;
34
35
  export declare const pointsToPath: (points: [number, number][], close?: boolean) => string;
35
36
  export declare const simplifyPoints: (points: number[][], tolerance?: number) => [number, number][];
37
+ export declare const distance: (a: [number, number], b: [number, number]) => number;
@@ -1,6 +1,6 @@
1
1
  import { Annotation, Filter, Store, SvelteAnnotatorState, SvelteStore } from '@annotorious/core';
2
2
  export type ImageAnnotationStore<I extends Annotation> = Store<I> & {
3
- getAt(x: number, y: number, filter?: Filter<I>): I | undefined;
3
+ getAt(x: number, y: number, filter?: Filter<I>, buffer?: number): I | undefined;
4
4
  getIntersecting(x: number, y: number, width: number, height: number): I[];
5
5
  };
6
6
  export type SvelteImageAnnotationStore<I extends Annotation = Annotation> = SvelteStore<I> & ImageAnnotationStore<I>;
@@ -10,7 +10,7 @@ interface IndexedTarget {
10
10
  export declare const createSpatialTree: () => {
11
11
  all: () => IndexedTarget[];
12
12
  clear: () => void;
13
- getAt: (x: number, y: number, filter?: Filter<Annotation>) => ImageAnnotationTarget[];
13
+ getAt: (x: number, y: number, filter?: Filter<Annotation>, buffer?: number) => ImageAnnotationTarget[];
14
14
  getIntersecting: (x: number, y: number, width: number, height: number) => ImageAnnotationTarget[];
15
15
  insert: (target: AnnotationTarget) => void;
16
16
  remove: (target: AnnotationTarget) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@annotorious/annotorious",
3
- "version": "3.4.6",
3
+ "version": "3.5.0",
4
4
  "description": "Add image annotation functionality to any web page with a few lines of JavaScript",
5
5
  "author": "Rainer Simon",
6
6
  "license": "BSD-3-Clause",
@@ -46,14 +46,14 @@
46
46
  "typescript": "5.8.3",
47
47
  "vite": "^5.4.19",
48
48
  "vite-plugin-dts": "^4.5.4",
49
- "vitest": "^3.1.4"
49
+ "vitest": "^3.2.4"
50
50
  },
51
51
  "dependencies": {
52
- "@annotorious/core": "3.4.6",
52
+ "@annotorious/core": "3.5.0",
53
53
  "dequal": "^2.0.3",
54
54
  "rbush": "^4.0.1",
55
55
  "simplify-js": "^1.2.4",
56
- "svg-pathdata": "^7.2.0",
56
+ "svg-pathdata": "^8.0.0",
57
57
  "uuid": "^11.1.0"
58
58
  }
59
59
  }
@@ -28,6 +28,7 @@
28
28
  }
29
29
 
30
30
  .a9s-annotationlayer ellipse,
31
+ .a9s-annotationlayer line,
31
32
  .a9s-annotationlayer path,
32
33
  .a9s-annotationlayer polygon,
33
34
  .a9s-annotationlayer rect {
@@ -5,14 +5,13 @@
5
5
  import { isImageAnnotation, ShapeType } from '../model';
6
6
  import type { ImageAnnotation, Shape} from '../model';
7
7
  import { getEditor as _getEditor, EditorMount } from './editors';
8
- import { Ellipse, Polygon, Rectangle} from './shapes';
8
+ import { Ellipse, Line, MultiPolygon, Polygon, Rectangle} from './shapes';
9
9
  import { getTool, listDrawingTools, ToolMount } from './tools';
10
10
  import { enableResponsive } from './utils';
11
11
  import { createSVGTransform } from './Transform';
12
12
  import { addEventListeners, getSVGPoint } from './SVGAnnotationLayerPointerEvent';
13
13
  import type { SvelteImageAnnotatorState } from 'src/state';
14
14
  import type { DrawingMode } from 'src/AnnotoriousOpts';
15
- import MultiPolygon from './shapes/MultiPolygon.svelte';
16
15
 
17
16
  /** Props **/
18
17
  export let drawingEnabled: boolean;
@@ -181,6 +180,11 @@
181
180
  annotation={annotation}
182
181
  geom={selector.geometry}
183
182
  style={style} />
183
+ {:else if (selector?.type === ShapeType.LINE)}
184
+ <Line
185
+ annotation={annotation}
186
+ geom={selector.geometry}
187
+ style={style} />
184
188
  {/if}
185
189
  {/key}
186
190
  {/if}
@@ -264,13 +264,11 @@
264
264
 
265
265
  if (hasSelected) {
266
266
  const updatedRings = polygon.rings.map((ring, ringIdx) => {
267
- const hasSelected = selectedCorners.some(s => s.polygon === polygonIdx && s.ring === ringIdx);
267
+ const selectedCornersInRing = selectedCorners.filter(s => s.polygon === polygonIdx && s.ring === ringIdx);
268
268
 
269
269
  // Rings needs 3 points min
270
- if (hasSelected && ring.points.length > 3) {
271
- const points = ring.points.filter((_, i) =>
272
- !selectedCorners.some(s => s.polygon === polygonIdx && s.ring === ringIdx && s.point === i));
273
-
270
+ if (selectedCornersInRing.length && ring.points.length - selectedCornersInRing.length >= 3) {
271
+ const points = ring.points.filter((_, i) => !selectedCornersInRing.some(s => s.point === i));
274
272
  return { points };
275
273
  } else {
276
274
  // No points selected on this ring
@@ -211,7 +211,7 @@
211
211
 
212
212
  const onDeleteSelected = () => {
213
213
  // Polygon needs 3 points min
214
- if (geom.points.length < 4) return;
214
+ if (geom.points.length - selectedCorners.length < 3) return;
215
215
 
216
216
  const points = geom.points.filter((_, i) => !selectedCorners.includes(i)) as [number, number][];
217
217
  const bounds = boundsFromPoints(points);
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import type { DrawingStyleExpression } from '@annotorious/core';
3
+ import type { Geometry, LineGeometry, 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: DrawingStyleExpression<ImageAnnotation> | undefined;
10
+
11
+ $: computedStyle = computeStyle(annotation, style);
12
+
13
+ const { points } = geom as LineGeometry;
14
+ const [[x1, y1], [x2, y2]] = points;
15
+ </script>
16
+
17
+ <g class="a9s-annotation" data-id={annotation.id}>
18
+ <line
19
+ class="a9s-outer"
20
+ style={computedStyle ? 'display:none;' : undefined}
21
+ x1={x1}
22
+ y1={y1}
23
+ x2={x2}
24
+ y2={y2} />
25
+
26
+ <line
27
+ class="a9s-inner"
28
+ style={computedStyle}
29
+ x1={x1}
30
+ y1={y1}
31
+ x2={x2}
32
+ y2={y2} />
33
+ </g>
@@ -1,4 +1,5 @@
1
1
  export { default as Ellipse } from './Ellipse.svelte';
2
2
  export { default as MultiPolygon } from './MultiPolygon.svelte';
3
3
  export { default as Polygon } from './Polygon.svelte';
4
- export { default as Rectangle } from './Rectangle.svelte';
4
+ export { default as Rectangle } from './Rectangle.svelte';
5
+ export { default as Line } from './Line.svelte';
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { onMount, createEventDispatcher } from 'svelte';
3
3
  import type { DrawingMode } from '../../../AnnotoriousOpts';
4
- import { boundsFromPoints, computeArea, ShapeType, type Polygon } from '../../../model';
5
- import { distance, getMaskDimensions } from '../../utils';
4
+ import { boundsFromPoints, computeArea, distance, ShapeType, type Polygon } from '../../../model';
5
+ import { getMaskDimensions } from '../../utils';
6
6
  import type { Transform } from '../..';
7
7
 
8
8
  const dispatch = createEventDispatcher<{ create: Polygon }>();
@@ -2,7 +2,7 @@
2
2
  import { createEventDispatcher, onMount } from 'svelte';
3
3
  import type { DrawingMode } from '../../../AnnotoriousOpts';
4
4
  import { ShapeType, type Rectangle } from '../../../model';
5
- import { getMaskDimensions, type Transform } from '../..';
5
+ import type { Transform } from '../..';
6
6
 
7
7
  const dispatch = createEventDispatcher<{ create: Rectangle }>();
8
8
 
@@ -1,4 +1,3 @@
1
- export * from './math';
2
1
  export * from './responsive';
3
2
  export * from './styling';
4
3
  export * from './svg';
@@ -16,7 +16,9 @@ export enum ShapeType {
16
16
 
17
17
  POLYGON = 'POLYGON',
18
18
 
19
- RECTANGLE = 'RECTANGLE'
19
+ RECTANGLE = 'RECTANGLE',
20
+
21
+ LINE = 'LINE'
20
22
 
21
23
  }
22
24
 
@@ -1,4 +1,5 @@
1
1
  export * from './ellipse';
2
+ export * from './line';
2
3
  export * from './multipolygon';
3
4
  export * from './polygon';
4
5
  export * from './rectangle';
@@ -0,0 +1,15 @@
1
+ import type { Bounds, Geometry, Shape } from '../Shape';
2
+
3
+ export interface Line extends Shape {
4
+
5
+ geometry: LineGeometry;
6
+
7
+ }
8
+
9
+ export interface LineGeometry extends Geometry {
10
+
11
+ points: [[number, number], [number, number]]
12
+
13
+ bounds: Bounds;
14
+
15
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Line';
2
+ export * from './lineUtils';
@@ -0,0 +1,23 @@
1
+ import { ShapeType } from '../Shape';
2
+ import { distance, registerShapeUtil, type ShapeUtil } from '../shapeUtils';
3
+ import type { Line } from './Line';
4
+
5
+ const LineUtil: ShapeUtil<Line> = {
6
+
7
+ area: (_: Line): number => 0,
8
+
9
+ intersects: (l: Line, x: number, y: number, buffer: number = 2): boolean => {
10
+ // See https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
11
+ const [[x1, y1], [x2, y2]] = l.geometry.points;
12
+
13
+ // Twice the area of the triangle formed by connecting the three points
14
+ const area = Math.abs(((y2 - y1) * x) - ((x2 - x1) * y) + (x2 * y1) - (y2 * x1));
15
+
16
+ const length = distance([x1, y1], [x2, y2]);
17
+
18
+ return area / length <= buffer;
19
+ }
20
+
21
+ };
22
+
23
+ registerShapeUtil(ShapeType.LINE, LineUtil);
@@ -5,7 +5,7 @@ export interface ShapeUtil<T extends Shape> {
5
5
 
6
6
  area: (shape: T) => number;
7
7
 
8
- intersects: (shape: T, x: number, y: number) => boolean;
8
+ intersects: (shape: T, x: number, y: number, buffer?: number) => boolean;
9
9
 
10
10
  }
11
11
 
@@ -31,10 +31,11 @@ export const computeArea = (shape: Shape) => Utils[shape.type].area(shape);
31
31
  * @param shape the shape
32
32
  * @param x point x coord
33
33
  * @param y point y coord
34
+ * @param buffer optional buffer around the point to consider as intersection
34
35
  * @returns true if shape and point intersect
35
36
  */
36
- export const intersects = (shape: Shape, x: number, y: number): boolean =>
37
- Utils[shape.type].intersects(shape, x, y);
37
+ export const intersects = (shape: Shape, x: number, y: number, buffer?: number): boolean =>
38
+ Utils[shape.type].intersects(shape, x, y, buffer);
38
39
 
39
40
  /**
40
41
  * Computes Bounds from a given list of points.
@@ -108,4 +109,11 @@ export const pointsToPath = (points: [number, number][], close: boolean = true):
108
109
  export const simplifyPoints = (points: number[][], tolerance = 1): [number, number][] => {
109
110
  const mapped = points.map(([x, y]) => ({ x, y }));
110
111
  return simplify(mapped, tolerance, true).map(pt => [pt.x, pt.y]);
112
+ }
113
+
114
+ export const distance = (a: [number, number], b: [number, number]): number => {
115
+ const dx = Math.abs(b[0] - a[0]);
116
+ const dy = Math.abs(b[1] - a[1]);
117
+
118
+ return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
111
119
  }
@@ -4,6 +4,8 @@ import { svgPathToMultiPolygonElement } from './pathParser';
4
4
  import type {
5
5
  Ellipse,
6
6
  EllipseGeometry,
7
+ Line,
8
+ LineGeometry,
7
9
  MultiPolygon,
8
10
  MultiPolygonGeometry,
9
11
  Polygon,
@@ -59,6 +61,30 @@ const parseSVGEllipse = (value: string): Ellipse => {
59
61
  };
60
62
  }
61
63
 
64
+ const parseSVGLine = (value: string): Line => {
65
+ const doc = parseSVGXML(value);
66
+
67
+ const x1 = parseFloat(doc.getAttribute("x1")!);
68
+ const x2 = parseFloat(doc.getAttribute("x2")!);
69
+ const y1 = parseFloat(doc.getAttribute("y1")!);
70
+ const y2 = parseFloat(doc.getAttribute("y2")!);
71
+
72
+ const bounds = {
73
+ minX: Math.min(x1, x2),
74
+ minY: Math.min(y1, y2),
75
+ maxX: Math.max(x1, x2),
76
+ maxY: Math.max(y1, y2),
77
+ };
78
+
79
+ return {
80
+ type: ShapeType.LINE,
81
+ geometry: {
82
+ points: [[x1, y1], [x2, y2]],
83
+ bounds,
84
+ },
85
+ };
86
+ }
87
+
62
88
  const parseSVGPath = (value: string): Polygon | MultiPolygon => {
63
89
  const doc = parseSVGXML(value);
64
90
 
@@ -99,6 +125,8 @@ export const parseSVGSelector = <T extends Shape>(valueOrSelector: SVGSelector |
99
125
  return parseSVGPath(value) as unknown as T;
100
126
  else if (value.includes('<ellipse '))
101
127
  return parseSVGEllipse(value) as unknown as T;
128
+ else if (value.includes("<line "))
129
+ return parseSVGLine(value) as unknown as T;
102
130
  else
103
131
  throw 'Unsupported SVG shape: ' + value;
104
132
  }
@@ -113,16 +141,29 @@ const serializeMultiPolygon = (geom: MultiPolygonGeometry) => {
113
141
  export const serializeSVGSelector = (shape: Shape): SVGSelector => {
114
142
  let value: string | undefined;
115
143
 
116
- if (shape.type === ShapeType.POLYGON) {
117
- const geom = shape.geometry as PolygonGeometry;
118
- const { points } = geom;
119
- value = `<svg><polygon points="${points.map((xy) => xy.join(',')).join(' ')}" /></svg>`;
120
- } else if (shape.type === ShapeType.ELLIPSE) {
121
- const geom = shape.geometry as EllipseGeometry;
122
- value = `<svg><ellipse cx="${geom.cx}" cy="${geom.cy}" rx="${geom.rx}" ry="${geom.ry}" /></svg>`;
123
- } else if (shape.type === ShapeType.MULTIPOLYGLON) {
124
- const geom = shape.geometry as MultiPolygonGeometry;
125
- value = `<svg>${serializeMultiPolygon(geom)}</svg>`;
144
+ switch (shape.type) {
145
+ case ShapeType.POLYGON: {
146
+ const geom = shape.geometry as PolygonGeometry;
147
+ const { points } = geom;
148
+ value = `<svg><polygon points="${points.map((xy) => xy.join(',')).join(' ')}" /></svg>`;
149
+ break;
150
+ }
151
+ case ShapeType.ELLIPSE: {
152
+ const geom = shape.geometry as EllipseGeometry;
153
+ value = `<svg><ellipse cx="${geom.cx}" cy="${geom.cy}" rx="${geom.rx}" ry="${geom.ry}" /></svg>`;
154
+ break;
155
+ }
156
+ case ShapeType.MULTIPOLYGLON: {
157
+ const geom = shape.geometry as MultiPolygonGeometry;
158
+ value = `<svg>${serializeMultiPolygon(geom)}</svg>`;
159
+ break;
160
+ }
161
+ case ShapeType.LINE: {
162
+ const geom = shape.geometry as LineGeometry;
163
+ const [[x1, y1], [x2, y2]] = geom.points;
164
+ value = `<svg><line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" /></svg>`;
165
+ break;
166
+ }
126
167
  }
127
168
 
128
169
  if (value) {
@@ -2,7 +2,7 @@ import type { Annotation, Filter, Store, SvelteAnnotatorState, SvelteStore } fro
2
2
 
3
3
  export type ImageAnnotationStore<I extends Annotation> = Store<I> & {
4
4
 
5
- getAt(x: number, y: number, filter?: Filter<I>): I | undefined;
5
+ getAt(x: number, y: number, filter?: Filter<I>, buffer?: number): I | undefined;
6
6
 
7
7
  getIntersecting(x: number, y: number, width: number, height: number): I[];
8
8
 
@@ -54,8 +54,8 @@ export const createImageAnnotatorState = <I extends Annotation, E extends unknow
54
54
  tree.update(oldValue.target, newValue.target));
55
55
  });
56
56
 
57
- const getAt = (x: number, y: number, filter?: Filter<I>): I | undefined => {
58
- const targets = tree.getAt(x, y, filter as Filter<Annotation>);
57
+ const getAt = (x: number, y: number, filter?: Filter<I>, buffer?: number): I | undefined => {
58
+ const targets = tree.getAt(x, y, filter as Filter<Annotation>, buffer);
59
59
 
60
60
  if (filter) {
61
61
  // Resolve annotations first, so we can filter
@@ -71,7 +71,9 @@ export const createImageAnnotatorState = <I extends Annotation, E extends unknow
71
71
  }
72
72
 
73
73
  const getIntersecting = (x: number, y: number, width: number, height: number) =>
74
- tree.getIntersecting(x, y, width, height).map(target => store.getAnnotation(target.annotation) as I);
74
+ tree.getIntersecting(x, y, width, height)
75
+ .map(target => store.getAnnotation(target.annotation) as I)
76
+ .filter(Boolean); // Race conditions may have deleted annotations concurrently
75
77
 
76
78
  return {
77
79
  store: {
@@ -75,18 +75,18 @@ export const createSpatialTree = () => {
75
75
  };
76
76
 
77
77
 
78
- const getAt = (x: number, y: number, filter?: Filter<Annotation>): ImageAnnotationTarget[] => {
78
+ const getAt = (x: number, y: number, filter?: Filter<Annotation>, buffer: number = 0): ImageAnnotationTarget[] => {
79
79
  const idxHits = tree.search({
80
- minX: x,
81
- minY: y,
82
- maxX: x,
83
- maxY: y
80
+ minX: x - buffer,
81
+ minY: y - buffer,
82
+ maxX: x + buffer,
83
+ maxY: y + buffer
84
84
  }).map(item => item.target);
85
85
 
86
86
  // Exact hit test on shape (not needed for rectangles!)
87
87
  const exactHits = idxHits.filter(target => {
88
88
  return (target.selector.type === ShapeType.RECTANGLE) ||
89
- intersects(target.selector, x, y);
89
+ intersects(target.selector, x, y, buffer);
90
90
  });
91
91
 
92
92
  // Get smallest shape
@@ -1 +0,0 @@
1
- export declare const distance: (a: [number, number], b: [number, number]) => number;
@@ -1,6 +0,0 @@
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
- }