triiiceratops 0.11.0 → 0.11.2
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/README.md +17 -9
- package/dist/{ArrowCounterClockwise-CN8KGaI0.js → ArrowCounterClockwise-B_hB6fl1.js} +1 -1
- package/dist/X-Boj9jj2h.js +890 -0
- package/dist/{annotation_tool_point-BpZXtX5D.js → annotation_tool_point-rZvdAtGa.js} +1 -1
- package/dist/annotorious-openseadragon.es-tb5X-LtF.js +33045 -0
- package/dist/components/AnnotationOverlay.svelte +10 -17
- package/dist/components/DemoHeader.svelte +4 -5
- package/dist/components/MetadataDialog.svelte +4 -1
- package/dist/components/OSDViewer.svelte +8 -2
- package/dist/components/SearchPanel.svelte +8 -5
- package/dist/components/ThemeToggle.svelte +1 -1
- package/dist/components/ThumbnailGallery.svelte +4 -4
- package/dist/components/Toolbar.svelte +5 -4
- package/dist/components/TriiiceratopsViewerElement.svelte +3 -1
- package/dist/custom-element.js +1 -0
- package/dist/{image_filters_reset-CyWg622b.js → image_filters_reset-CAUhlDWt.js} +1 -1
- package/dist/plugins/annotation-editor/AnnotationEditorController.svelte +5 -3
- package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte +3 -3
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.d.ts +3 -0
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.js +19 -14
- package/dist/plugins/annotation-editor/loader.svelte.js +2 -2
- package/dist/plugins/annotation-editor.js +1228 -32159
- package/dist/plugins/image-manipulation/ImageManipulationController.svelte +1 -1
- package/dist/plugins/image-manipulation.js +3 -3
- package/dist/state/manifests.svelte.d.ts +2 -1
- package/dist/state/manifests.svelte.js +5 -9
- package/dist/state/manifests.test.js +52 -50
- package/dist/state/viewer.svelte.d.ts +2 -1
- package/dist/state/viewer.svelte.js +8 -8
- package/dist/triiiceratops-bundle.js +1167 -1179
- package/dist/triiiceratops-element.iife.js +26 -26
- package/dist/triiiceratops.css +1 -1
- package/dist/utils/annotationAdapter.js +2 -2
- package/dist/utils/annotationAdapter.test.js +0 -1
- package/package.json +12 -2
- package/dist/X-i_EmjXwW.js +0 -906
|
@@ -42,18 +42,15 @@
|
|
|
42
42
|
const shouldBeVisible =
|
|
43
43
|
viewerState.config.annotations?.visible ?? true;
|
|
44
44
|
|
|
45
|
+
viewerState.visibleAnnotationIds.clear();
|
|
45
46
|
if (shouldBeVisible) {
|
|
46
|
-
const newSet = new Set<string>();
|
|
47
47
|
annotations.forEach((a: any) => {
|
|
48
48
|
const id = getAnnotationId(a);
|
|
49
|
-
if (id)
|
|
49
|
+
if (id) viewerState.visibleAnnotationIds.add(id);
|
|
50
50
|
});
|
|
51
|
-
viewerState.visibleAnnotationIds = newSet;
|
|
52
|
-
} else {
|
|
53
|
-
viewerState.visibleAnnotationIds = new Set();
|
|
54
51
|
}
|
|
55
52
|
} else {
|
|
56
|
-
viewerState.visibleAnnotationIds
|
|
53
|
+
viewerState.visibleAnnotationIds.clear();
|
|
57
54
|
}
|
|
58
55
|
});
|
|
59
56
|
|
|
@@ -72,24 +69,19 @@
|
|
|
72
69
|
} else {
|
|
73
70
|
viewerState.visibleAnnotationIds.add(id);
|
|
74
71
|
}
|
|
75
|
-
// Reassign to trigger reactivity
|
|
76
|
-
viewerState.visibleAnnotationIds = new Set(
|
|
77
|
-
viewerState.visibleAnnotationIds,
|
|
78
|
-
);
|
|
79
72
|
}
|
|
80
73
|
|
|
81
74
|
function toggleAllAnnotations() {
|
|
82
75
|
if (isAllVisible) {
|
|
83
76
|
// Hide all
|
|
84
|
-
viewerState.visibleAnnotationIds
|
|
77
|
+
viewerState.visibleAnnotationIds.clear();
|
|
85
78
|
} else {
|
|
86
79
|
// Show all
|
|
87
|
-
|
|
80
|
+
viewerState.visibleAnnotationIds.clear();
|
|
88
81
|
annotations.forEach((a: any) => {
|
|
89
82
|
const id = getAnnotationId(a);
|
|
90
|
-
if (id)
|
|
83
|
+
if (id) viewerState.visibleAnnotationIds.add(id);
|
|
91
84
|
});
|
|
92
|
-
viewerState.visibleAnnotationIds = newSet;
|
|
93
85
|
}
|
|
94
86
|
}
|
|
95
87
|
|
|
@@ -98,7 +90,7 @@
|
|
|
98
90
|
let toolbarContainer: HTMLElement | undefined = $state();
|
|
99
91
|
|
|
100
92
|
// Calculate coordinates for connecting line
|
|
101
|
-
let
|
|
93
|
+
let _connectingLine = $derived.by(() => {
|
|
102
94
|
if (!hoveredAnnotationId) return null;
|
|
103
95
|
return null;
|
|
104
96
|
});
|
|
@@ -254,7 +246,7 @@
|
|
|
254
246
|
<div
|
|
255
247
|
class="absolute right-0 mt-2 w-96 bg-base-200/95 backdrop-blur shadow-xl rounded-box p-0 max-h-[60vh] overflow-y-auto border border-base-300 flex flex-col divide-y divide-base-300"
|
|
256
248
|
>
|
|
257
|
-
{#each renderedAnnotations as anno, i}
|
|
249
|
+
{#each renderedAnnotations as anno, i (anno.id)}
|
|
258
250
|
{@const isVisible = viewerState.visibleAnnotationIds.has(
|
|
259
251
|
anno.id,
|
|
260
252
|
)}
|
|
@@ -315,7 +307,7 @@
|
|
|
315
307
|
? ''
|
|
316
308
|
: 'opacity-50'} space-y-2"
|
|
317
309
|
>
|
|
318
|
-
{#each anno.bodies as body}
|
|
310
|
+
{#each anno.bodies as body, i (i)}
|
|
319
311
|
<div
|
|
320
312
|
class="flex flex-wrap gap-2 pointer-events-auto"
|
|
321
313
|
>
|
|
@@ -354,6 +346,7 @@
|
|
|
354
346
|
<!-- Commenting / Default -->
|
|
355
347
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
356
348
|
{#if body.isHtml}
|
|
349
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
357
350
|
{@html body.value}
|
|
358
351
|
{:else}
|
|
359
352
|
{body.value || '(No content)'}
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
} catch
|
|
82
|
+
} catch {
|
|
83
83
|
/* ignore */
|
|
84
84
|
}
|
|
85
85
|
return `Canvas ${index + 1}`;
|
|
@@ -213,7 +213,7 @@
|
|
|
213
213
|
onchange={(e) => setLocale(e.currentTarget.value as any)}
|
|
214
214
|
aria-label={m.language_select_label()}
|
|
215
215
|
>
|
|
216
|
-
{#each locales as lang}
|
|
216
|
+
{#each locales as lang (lang)}
|
|
217
217
|
<option value={lang}>{languageNames[lang] || lang}</option>
|
|
218
218
|
{/each}
|
|
219
219
|
</select>
|
|
@@ -230,7 +230,6 @@
|
|
|
230
230
|
>
|
|
231
231
|
<Gear size={20} />
|
|
232
232
|
</div>
|
|
233
|
-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
234
233
|
<ul
|
|
235
234
|
tabindex="-1"
|
|
236
235
|
class="dropdown-content z-20 menu bg-base-100 rounded-box w-80 p-2 shadow border border-base-300 max-h-[80vh] overflow-y-auto block invisible pointer-events-none group-focus-within:visible group-focus-within:pointer-events-auto"
|
|
@@ -731,7 +730,7 @@
|
|
|
731
730
|
value={isCustom ? 'custom' : manifestUrl}
|
|
732
731
|
onchange={handleSelectChange}
|
|
733
732
|
>
|
|
734
|
-
{#each SUGGESTED_MANIFESTS as manifest}
|
|
733
|
+
{#each SUGGESTED_MANIFESTS as manifest (manifest.url)}
|
|
735
734
|
<option value={manifest.url}>{manifest.label}</option>
|
|
736
735
|
{/each}
|
|
737
736
|
<option value="custom">{m.try_your_own()}</option>
|
|
@@ -770,7 +769,7 @@
|
|
|
770
769
|
{#if canvases.length === 0}
|
|
771
770
|
<option value="" disabled>{m.no_canvases_loaded()}</option>
|
|
772
771
|
{:else}
|
|
773
|
-
{#each canvases as canvas, i}
|
|
772
|
+
{#each canvases as canvas, i (canvas.id)}
|
|
774
773
|
<option value={canvas.id}>
|
|
775
774
|
{getCanvasLabel(canvas, i)}
|
|
776
775
|
</option>
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
<div class="py-4 overflow-y-auto max-h-[70vh]">
|
|
99
99
|
{#if description}
|
|
100
100
|
<div class="mb-6 prose">
|
|
101
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
101
102
|
<p>{@html description}</p>
|
|
102
103
|
</div>
|
|
103
104
|
{/if}
|
|
@@ -107,6 +108,7 @@
|
|
|
107
108
|
<dt class="font-bold text-lg opacity-70 mt-6">
|
|
108
109
|
{m.attribution()}
|
|
109
110
|
</dt>
|
|
111
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
110
112
|
<dd class="text-sm ps-2">{@html attribution}</dd>
|
|
111
113
|
{/if}
|
|
112
114
|
|
|
@@ -124,10 +126,11 @@
|
|
|
124
126
|
</dd>
|
|
125
127
|
{/if}
|
|
126
128
|
|
|
127
|
-
{#each metadata as item}
|
|
129
|
+
{#each metadata as item, i (i)}
|
|
128
130
|
<dt class="font-bold text-lg opacity-70 mt-6">
|
|
129
131
|
{item.label}
|
|
130
132
|
</dt>
|
|
133
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
131
134
|
<dd class="text-sm ps-2">{@html item.value}</dd>
|
|
132
135
|
{/each}
|
|
133
136
|
</dl>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onMount } from 'svelte';
|
|
3
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
3
4
|
import { parseAnnotations } from '../utils/annotationAdapter';
|
|
4
5
|
import { manifestsState } from '../state/manifests.svelte';
|
|
5
6
|
import type { ViewerState } from '../state/viewer.svelte';
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
|
|
33
34
|
// Get search hit IDs for styling
|
|
34
35
|
let searchHitIds = $derived.by(() => {
|
|
35
|
-
const ids = new
|
|
36
|
+
const ids = new SvelteSet<string>();
|
|
36
37
|
viewerState.currentCanvasSearchAnnotations.forEach((anno: any) => {
|
|
37
38
|
const id = anno.id || anno['@id'];
|
|
38
39
|
if (id) ids.add(id);
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
// Rendered annotations with pixel coordinates
|
|
49
50
|
let renderedAnnotations = $derived.by(() => {
|
|
50
51
|
// Depend on osdVersion to trigger updates
|
|
51
|
-
osdVersion;
|
|
52
|
+
void osdVersion;
|
|
52
53
|
|
|
53
54
|
if (!viewer || !OSD || !parsedAnnotations.length) {
|
|
54
55
|
return [];
|
|
@@ -160,9 +161,13 @@
|
|
|
160
161
|
onMount(() => {
|
|
161
162
|
if (!container) return;
|
|
162
163
|
|
|
164
|
+
let mounted = true;
|
|
165
|
+
|
|
163
166
|
(async () => {
|
|
164
167
|
// Dynamically import OpenSeadragon to avoid SSR issues
|
|
165
168
|
const osdModule = await import('openseadragon');
|
|
169
|
+
if (!mounted) return;
|
|
170
|
+
|
|
166
171
|
OSD = osdModule.default || osdModule;
|
|
167
172
|
|
|
168
173
|
// Initialize OpenSeadragon viewer
|
|
@@ -191,6 +196,7 @@
|
|
|
191
196
|
})();
|
|
192
197
|
|
|
193
198
|
return () => {
|
|
199
|
+
mounted = false;
|
|
194
200
|
viewer?.destroy();
|
|
195
201
|
viewerState.osdViewer = null;
|
|
196
202
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, untrack } from 'svelte';
|
|
3
3
|
import MagnifyingGlass from 'phosphor-svelte/lib/MagnifyingGlass';
|
|
4
|
-
import Spinner from 'phosphor-svelte/lib/Spinner';
|
|
5
4
|
import X from 'phosphor-svelte/lib/X';
|
|
6
5
|
import { VIEWER_STATE_KEY, type ViewerState } from '../state/viewer.svelte';
|
|
7
6
|
import { m } from '../state/i18n.svelte';
|
|
@@ -10,7 +9,6 @@
|
|
|
10
9
|
|
|
11
10
|
// We'll initialize from viewerState to preserve context.
|
|
12
11
|
let searchQuery = $state('');
|
|
13
|
-
let resultsContainer: HTMLElement;
|
|
14
12
|
|
|
15
13
|
let showCloseButton = $derived(
|
|
16
14
|
viewerState.config.search?.showCloseButton ?? true,
|
|
@@ -124,7 +122,7 @@
|
|
|
124
122
|
})}
|
|
125
123
|
</div>
|
|
126
124
|
|
|
127
|
-
{#each viewerState.searchResults as group}
|
|
125
|
+
{#each viewerState.searchResults as group (group.canvasIndex)}
|
|
128
126
|
<button
|
|
129
127
|
class="w-full text-left bg-base-100 shadow-sm border border-base-200 rounded-box cursor-pointer hover:shadow-md transition-all block p-0 select-none {viewerState.currentCanvasIndex ===
|
|
130
128
|
group.canvasIndex
|
|
@@ -144,21 +142,26 @@
|
|
|
144
142
|
>
|
|
145
143
|
</div>
|
|
146
144
|
<div class="p-0">
|
|
147
|
-
{#each group.hits.slice(0, 1) as result}
|
|
145
|
+
{#each group.hits.slice(0, 1) as result, i (i)}
|
|
148
146
|
<div
|
|
149
147
|
class="p-3 text-sm border-b border-base-200 last:border-none hover:bg-base-200/30 transition-colors"
|
|
150
148
|
>
|
|
151
149
|
{#if result.type === 'hit'}
|
|
152
150
|
<div class="leading-relaxed">
|
|
151
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
153
152
|
<span>{@html result.before}</span>
|
|
154
153
|
<span
|
|
155
154
|
class="bg-yellow-200 text-yellow-900 font-bold px-0.5 rounded"
|
|
156
|
-
>{@html result.match}</span
|
|
157
155
|
>
|
|
156
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
157
|
+
{@html result.match}
|
|
158
|
+
</span>
|
|
159
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
158
160
|
<span>{@html result.after}</span>
|
|
159
161
|
</div>
|
|
160
162
|
{:else}
|
|
161
163
|
<div class="leading-relaxed">
|
|
164
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
162
165
|
{@html result.match}
|
|
163
166
|
</div>
|
|
164
167
|
{/if}
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
: thumb.id || thumb['@id'];
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
} catch
|
|
87
|
-
console.warn('Error getting thumbnail'
|
|
86
|
+
} catch {
|
|
87
|
+
console.warn('Error getting thumbnail');
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// Fallback to first image if no thumbnail service
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
(pObj['@id'] as string | undefined) ||
|
|
170
170
|
JSON.stringify(pObj);
|
|
171
171
|
}
|
|
172
|
-
} catch
|
|
172
|
+
} catch {
|
|
173
173
|
// ignore
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -516,7 +516,7 @@
|
|
|
516
516
|
? ''
|
|
517
517
|
: 'grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));'}
|
|
518
518
|
>
|
|
519
|
-
{#each thumbnails as thumb}
|
|
519
|
+
{#each thumbnails as thumb (thumb.id)}
|
|
520
520
|
<button
|
|
521
521
|
class="group flex flex-col gap-1 p-1 rounded hover:bg-base-200 transition-colors text-left relative shrink-0 {isHorizontal
|
|
522
522
|
? 'w-[90px]'
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
// Derived list of sorted plugin buttons
|
|
39
39
|
let sortedPluginButtons = $derived.by(() => {
|
|
40
|
-
language.current;
|
|
40
|
+
void language.current;
|
|
41
41
|
return [...viewerState.pluginMenuButtons].sort(
|
|
42
42
|
(a, b) => (a.order ?? 100) - (b.order ?? 100),
|
|
43
43
|
);
|
|
@@ -241,9 +241,9 @@
|
|
|
241
241
|
{#each sortedPluginButtons as button (button.id)}
|
|
242
242
|
{@const Icon = button.icon}
|
|
243
243
|
{@const tooltipText =
|
|
244
|
-
// @ts-
|
|
244
|
+
// @ts-expect-error - m[button.tooltip] might be a function
|
|
245
245
|
typeof m[button.tooltip] === 'function'
|
|
246
|
-
? // @ts-
|
|
246
|
+
? // @ts-expect-error - m[button.tooltip] is a function
|
|
247
247
|
m[button.tooltip]()
|
|
248
248
|
: button.tooltip}
|
|
249
249
|
<li>
|
|
@@ -272,7 +272,8 @@
|
|
|
272
272
|
{#if showToggle}
|
|
273
273
|
<button
|
|
274
274
|
class={[
|
|
275
|
-
'pointer-events-auto btn btn-circle btn-sm
|
|
275
|
+
'pointer-events-auto btn btn-circle btn-sm shadow-md z-40 transition-opacity duration-300 absolute mt-2',
|
|
276
|
+
'bg-base-200/90 backdrop-blur border border-base-300 hover:bg-base-300 text-base-content',
|
|
276
277
|
isOpen && 'opacity-0 pointer-events-none',
|
|
277
278
|
!isOpen && 'opacity-100',
|
|
278
279
|
]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- svelte-ignore options_missing_custom_element -->
|
|
1
2
|
<svelte:options
|
|
2
3
|
customElement={{
|
|
3
4
|
tag: 'triiiceratops-viewer',
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
if (typeof config === 'string') {
|
|
116
117
|
try {
|
|
117
118
|
return JSON.parse(config);
|
|
118
|
-
} catch
|
|
119
|
+
} catch {
|
|
119
120
|
console.warn(`Invalid config JSON: "${config}". Ignoring.`);
|
|
120
121
|
return undefined;
|
|
121
122
|
}
|
|
@@ -124,6 +125,7 @@
|
|
|
124
125
|
});
|
|
125
126
|
</script>
|
|
126
127
|
|
|
128
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
127
129
|
{@html `<style>${styles}</style>`}
|
|
128
130
|
|
|
129
131
|
<div bind:this={hostElement} class="w-full h-full">
|
package/dist/custom-element.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// Plugins built as IIFE need to share the same Svelte runtime instance
|
|
5
5
|
// so that getContext/setContext work correctly across bundle boundaries
|
|
6
6
|
// @ts-expect-error - svelte/internal/client is not typed but exists at runtime
|
|
7
|
+
// eslint-disable-next-line svelte/no-svelte-internal
|
|
7
8
|
import * as svelteInternal from 'svelte/internal/client';
|
|
8
9
|
import * as svelte from 'svelte';
|
|
9
10
|
window.__TriiiceratopsSvelteRuntime = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { getContext, onMount, onDestroy } from 'svelte';
|
|
2
|
+
import { getContext, onMount, onDestroy, untrack } from 'svelte';
|
|
3
3
|
import {
|
|
4
4
|
VIEWER_STATE_KEY,
|
|
5
5
|
type ViewerState,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
// Props from the plugin system
|
|
16
16
|
let {
|
|
17
|
-
isOpen = false,
|
|
17
|
+
isOpen: _isOpen = false,
|
|
18
18
|
close,
|
|
19
19
|
config,
|
|
20
20
|
}: {
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
|
|
28
28
|
// UI state
|
|
29
29
|
let isEditing = $state(false);
|
|
30
|
-
let activeTool = $state<DrawingTool>(
|
|
30
|
+
let activeTool = $state<DrawingTool>(
|
|
31
|
+
untrack(() => config.defaultTool ?? 'rectangle'),
|
|
32
|
+
);
|
|
31
33
|
let selectedAnnotation = $state<any>(null);
|
|
32
34
|
let showDeleteConfirm = $state(false);
|
|
33
35
|
let pendingDeleteId = $state<string | null>(null);
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
{m.annotation_editor_tool_label()}
|
|
159
159
|
</p>
|
|
160
160
|
<div class="join">
|
|
161
|
-
{#each availableTools as tool}
|
|
161
|
+
{#each availableTools as tool (tool)}
|
|
162
162
|
{@const Icon = toolIcons[tool] ?? Rectangle}
|
|
163
163
|
{@const toolName =
|
|
164
164
|
{
|
|
@@ -221,14 +221,14 @@
|
|
|
221
221
|
</div>
|
|
222
222
|
|
|
223
223
|
<div class="space-y-3 max-h-[40vh] overflow-y-auto pr-1">
|
|
224
|
-
{#each editableBodies as body, i}
|
|
224
|
+
{#each editableBodies as body, i (i)}
|
|
225
225
|
<div class="card bg-base-200 p-2 space-y-2">
|
|
226
226
|
<div class="flex items-center gap-2">
|
|
227
227
|
<select
|
|
228
228
|
class="select select-xs select-bordered flex-1"
|
|
229
229
|
bind:value={body.purpose}
|
|
230
230
|
>
|
|
231
|
-
{#each W3C_PURPOSES as purpose}
|
|
231
|
+
{#each W3C_PURPOSES as purpose (purpose)}
|
|
232
232
|
<option
|
|
233
233
|
value={purpose}
|
|
234
234
|
class="capitalize">{purpose}</option
|
|
@@ -8,6 +8,9 @@ export declare class AnnotationManager {
|
|
|
8
8
|
private adapter;
|
|
9
9
|
private annotorious;
|
|
10
10
|
private osdViewer;
|
|
11
|
+
private OSD;
|
|
12
|
+
private createOSDAnnotator;
|
|
13
|
+
private W3CImageFormat;
|
|
11
14
|
private currentManifestId;
|
|
12
15
|
private currentCanvasId;
|
|
13
16
|
private isDrawingEnabled;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createOSDAnnotator, W3CImageFormat, } from '@annotorious/openseadragon';
|
|
2
|
-
import OpenSeadragon from 'openseadragon';
|
|
3
1
|
import { LocalStorageAdapter } from './adapters/LocalStorageAdapter';
|
|
4
2
|
/**
|
|
5
3
|
* Manages the Annotorious instance and annotation CRUD operations.
|
|
@@ -10,8 +8,11 @@ export class AnnotationManager {
|
|
|
10
8
|
adapter;
|
|
11
9
|
annotorious = null;
|
|
12
10
|
// Store reference to OSD viewer for mouse nav toggling
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
11
|
osdViewer = null;
|
|
12
|
+
// Dynamic dependencies
|
|
13
|
+
OSD = null;
|
|
14
|
+
createOSDAnnotator = null;
|
|
15
|
+
W3CImageFormat = null;
|
|
15
16
|
// Current canvas tracking
|
|
16
17
|
currentManifestId = null;
|
|
17
18
|
currentCanvasId = null;
|
|
@@ -27,7 +28,6 @@ export class AnnotationManager {
|
|
|
27
28
|
this.adapter = config.adapter ?? new LocalStorageAdapter();
|
|
28
29
|
this.activeTool = config.defaultTool ?? 'rectangle';
|
|
29
30
|
}
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
31
|
init(viewer, canvasId) {
|
|
32
32
|
if (!viewer) {
|
|
33
33
|
console.error('[AnnotationManager] Cannot init: Viewer is null');
|
|
@@ -63,16 +63,25 @@ export class AnnotationManager {
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
initAnnotorious(viewer, canvasId) {
|
|
66
|
+
async initAnnotorious(viewer, canvasId) {
|
|
68
67
|
if (this.annotorious)
|
|
69
68
|
return;
|
|
70
69
|
try {
|
|
70
|
+
// Load dynamic dependencies
|
|
71
|
+
if (!this.createOSDAnnotator || !this.W3CImageFormat) {
|
|
72
|
+
const mod = await import('@annotorious/openseadragon');
|
|
73
|
+
this.createOSDAnnotator = mod.createOSDAnnotator;
|
|
74
|
+
this.W3CImageFormat = mod.W3CImageFormat;
|
|
75
|
+
}
|
|
76
|
+
if (!this.OSD) {
|
|
77
|
+
const mod = await import('openseadragon');
|
|
78
|
+
this.OSD = mod.default || mod;
|
|
79
|
+
}
|
|
71
80
|
const sourceId = canvasId ?? 'unknown';
|
|
72
81
|
// Initial drawing enabled state only if tool is NOT point (Annotorious handles others)
|
|
73
82
|
const initialDrawingEnabled = this.isDrawingEnabled && this.activeTool !== 'point';
|
|
74
83
|
const config = {
|
|
75
|
-
adapter: W3CImageFormat(sourceId),
|
|
84
|
+
adapter: this.W3CImageFormat(sourceId),
|
|
76
85
|
drawingEnabled: initialDrawingEnabled,
|
|
77
86
|
autoSave: false,
|
|
78
87
|
drawingMode: 'click',
|
|
@@ -90,7 +99,7 @@ export class AnnotationManager {
|
|
|
90
99
|
return ''; // No class for normal annotations
|
|
91
100
|
},
|
|
92
101
|
};
|
|
93
|
-
const anno = createOSDAnnotator(viewer, config);
|
|
102
|
+
const anno = this.createOSDAnnotator(viewer, config);
|
|
94
103
|
this.annotorious = anno;
|
|
95
104
|
if (this.config.user) {
|
|
96
105
|
anno.setUser(this.config.user);
|
|
@@ -104,14 +113,13 @@ export class AnnotationManager {
|
|
|
104
113
|
this.setupEvents();
|
|
105
114
|
// Apply pending state
|
|
106
115
|
this.updateDrawingMode(this.isDrawingEnabled);
|
|
107
|
-
|
|
116
|
+
anno.setVisible(true); // Always start visible
|
|
108
117
|
}
|
|
109
118
|
catch (error) {
|
|
110
119
|
console.error('[AnnotationManager] Failed to create annotator:', error);
|
|
111
120
|
}
|
|
112
121
|
}
|
|
113
122
|
// ... (injectStyles remains same) ...
|
|
114
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
123
|
handlePointClick(event) {
|
|
116
124
|
if (!this.osdViewer || !this.annotorious)
|
|
117
125
|
return;
|
|
@@ -128,8 +136,7 @@ export class AnnotationManager {
|
|
|
128
136
|
// Calculate width/height based on "Screen Pixels" to ensure visibility
|
|
129
137
|
// User requested a 2x2 pixel rectangle.
|
|
130
138
|
const targetScreenPixels = 2;
|
|
131
|
-
|
|
132
|
-
const OSD = OpenSeadragon;
|
|
139
|
+
const OSD = this.OSD;
|
|
133
140
|
const p1 = this.osdViewer.viewport.pointFromPixel(new OSD.Point(0, 0));
|
|
134
141
|
const p2 = this.osdViewer.viewport.pointFromPixel(new OSD.Point(targetScreenPixels, 0));
|
|
135
142
|
const imgP1 = tiledImage.viewportToImageCoordinates(p1);
|
|
@@ -175,7 +182,6 @@ export class AnnotationManager {
|
|
|
175
182
|
this.annotorious.addAnnotation(annotation);
|
|
176
183
|
// Wait for render cycle before selecting coverage
|
|
177
184
|
setTimeout(() => {
|
|
178
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
179
185
|
this.annotorious.setSelected(id);
|
|
180
186
|
}, 50);
|
|
181
187
|
}
|
|
@@ -223,7 +229,6 @@ export class AnnotationManager {
|
|
|
223
229
|
get availableTools() {
|
|
224
230
|
return this.config.tools ?? ['rectangle', 'polygon', 'point'];
|
|
225
231
|
}
|
|
226
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
232
|
injectStyles(viewer) {
|
|
228
233
|
if (!viewer.element)
|
|
229
234
|
return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { manifestsState } from '../../state/manifests.svelte';
|
|
1
|
+
// import { manifestsState } from '../../state/manifests.svelte';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a reactive loader that syncs annotations from the adapter to the viewer state.
|
|
4
4
|
* This runs independently of the Annotation Editor UI component.
|
|
@@ -21,7 +21,7 @@ export function createLoader(adapter) {
|
|
|
21
21
|
// Load annotations for this canvas
|
|
22
22
|
adapter
|
|
23
23
|
.load(manifestId, canvasId)
|
|
24
|
-
.then((
|
|
24
|
+
.then((_annotations) => {
|
|
25
25
|
// Success handling
|
|
26
26
|
})
|
|
27
27
|
.catch((err) => {
|