annotate-image 2.0.0-beta.1 → 2.0.0-beta.3

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/jquery.js CHANGED
@@ -1,3 +1,30 @@
1
+ // src/positioning.ts
2
+ function clampNote(note, naturalWidth, naturalHeight) {
3
+ const width = Math.min(note.width, naturalWidth);
4
+ const height = Math.min(note.height, naturalHeight);
5
+ const left = Math.max(0, Math.min(note.left, naturalWidth - width));
6
+ const top = Math.max(0, Math.min(note.top, naturalHeight - height));
7
+ return { top, left, width, height };
8
+ }
9
+ function clampNotes(notes, naturalWidth, naturalHeight) {
10
+ for (const note of notes) {
11
+ Object.assign(note, clampNote(note, naturalWidth, naturalHeight));
12
+ }
13
+ }
14
+ function computeNoteLeft(noteWidth, areaLeftInViewport, areaWidth, viewportWidth) {
15
+ let left = (areaWidth - noteWidth) / 2;
16
+ const noteLeftInViewport = areaLeftInViewport + left;
17
+ const noteRightInViewport = noteLeftInViewport + noteWidth;
18
+ if (noteRightInViewport > viewportWidth) {
19
+ left -= noteRightInViewport - viewportWidth;
20
+ }
21
+ const adjustedNoteLeft = areaLeftInViewport + left;
22
+ if (adjustedNoteLeft < 0) {
23
+ left -= adjustedNoteLeft;
24
+ }
25
+ return left;
26
+ }
27
+
1
28
  // src/annotate-edit.ts
2
29
  var DEFAULT_NOTE_TOP = 30;
3
30
  var DEFAULT_NOTE_LEFT = 30;
@@ -27,10 +54,11 @@ var AnnotateEdit = class {
27
54
  };
28
55
  }
29
56
  this.area = image.editOverlay.querySelector(".image-annotate-edit-area");
30
- this.area.style.height = this.note.height + "px";
31
- this.area.style.width = this.note.width + "px";
32
- this.area.style.left = this.note.left + "px";
33
- this.area.style.top = this.note.top + "px";
57
+ const rendered = image.toRendered(this.note);
58
+ this.area.style.height = rendered.height + "px";
59
+ this.area.style.width = rendered.width + "px";
60
+ this.area.style.left = rendered.left + "px";
61
+ this.area.style.top = rendered.top + "px";
34
62
  this.form = document.createElement("div");
35
63
  this.form.className = "image-annotate-edit-form";
36
64
  const formEl = document.createElement("form");
@@ -46,6 +74,8 @@ var AnnotateEdit = class {
46
74
  formEl.appendChild(this.textarea);
47
75
  this.form.appendChild(formEl);
48
76
  this.area.appendChild(this.form);
77
+ this.positionForm();
78
+ this.textarea.focus();
49
79
  this.form.addEventListener("pointerdown", (e) => e.stopPropagation());
50
80
  const area = this.area;
51
81
  const applyRect = (rect) => {
@@ -57,7 +87,10 @@ var AnnotateEdit = class {
57
87
  this.handlers.makeResizable(area, {
58
88
  containment: image.canvas,
59
89
  onResize: applyRect,
60
- onStop: applyRect
90
+ onStop: (rect) => {
91
+ applyRect(rect);
92
+ this.positionForm();
93
+ }
61
94
  });
62
95
  this.handlers.makeDraggable(area, {
63
96
  containment: image.canvas,
@@ -68,9 +101,9 @@ var AnnotateEdit = class {
68
101
  onStop: (pos) => {
69
102
  area.style.left = pos.left + "px";
70
103
  area.style.top = pos.top + "px";
104
+ this.positionForm();
71
105
  }
72
106
  });
73
- this.textarea.focus();
74
107
  this.form.addEventListener("keydown", (e) => {
75
108
  if (e.key === "Escape") {
76
109
  const cancelBtn = this.form.querySelector(".image-annotate-edit-close");
@@ -86,6 +119,13 @@ var AnnotateEdit = class {
86
119
  }
87
120
  this.addCancelButton(buttonRow);
88
121
  }
122
+ /** Recompute the form's horizontal position relative to the area. */
123
+ positionForm() {
124
+ const formRect = this.form.getBoundingClientRect();
125
+ const areaRect = this.area.getBoundingClientRect();
126
+ const left = computeNoteLeft(formRect.width, areaRect.left, areaRect.width, window.innerWidth);
127
+ this.form.style.left = left + "px";
128
+ }
89
129
  /** Tear down the edit form and interaction handlers. */
90
130
  destroy() {
91
131
  this.image.activeEdit = null;
@@ -117,13 +157,20 @@ var AnnotateEdit = class {
117
157
  }
118
158
  this.image.notifySave(stripInternals(this.note));
119
159
  this.destroy();
160
+ this.image.flushPendingRescale();
120
161
  };
121
162
  const pos = readInlinePosition(this.area);
122
163
  const size = readInlineSize(this.area);
123
- this.note.top = pos.top;
124
- this.note.left = pos.left;
125
- this.note.width = size.width;
126
- this.note.height = size.height;
164
+ const natural = this.image.toNatural({
165
+ top: pos.top,
166
+ left: pos.left,
167
+ width: size.width,
168
+ height: size.height
169
+ });
170
+ this.note.top = natural.top;
171
+ this.note.left = natural.left;
172
+ this.note.width = natural.width;
173
+ this.note.height = natural.height;
127
174
  this.note.text = text;
128
175
  if (this.image.api.save) {
129
176
  this.busy = true;
@@ -157,6 +204,7 @@ var AnnotateEdit = class {
157
204
  const idx = this.image.notes.indexOf(this.note);
158
205
  if (idx !== -1) this.image.notes.splice(idx, 1);
159
206
  this.image.notifyDelete(stripInternals(this.note));
207
+ this.image.flushPendingRescale();
160
208
  };
161
209
  if (this.image.api.delete) {
162
210
  this.busy = true;
@@ -232,36 +280,42 @@ var AnnotateView = class {
232
280
  });
233
281
  }
234
282
  }
235
- /** Apply the note's position and dimensions to the area element. */
283
+ /** Apply the note's position and dimensions to the area element, scaled to rendered size. */
236
284
  setPosition() {
285
+ const rendered = this.image.toRendered(this.note);
237
286
  const innerDiv = this.area.firstElementChild;
238
- innerDiv.style.height = this.note.height + "px";
239
- innerDiv.style.width = this.note.width + "px";
240
- this.area.style.left = this.note.left + "px";
241
- this.area.style.top = this.note.top + "px";
287
+ innerDiv.style.height = rendered.height + "px";
288
+ innerDiv.style.width = rendered.width + "px";
289
+ this.area.style.left = rendered.left + "px";
290
+ this.area.style.top = rendered.top + "px";
242
291
  }
243
292
  /** Update the view's position, size, and text from the edit area after a save. */
244
293
  resetPosition(editable, text) {
245
294
  this.tooltip.textContent = text;
246
295
  this.tooltip.style.display = "none";
247
- const areaPos = readInlinePosition(editable.area);
248
- const areaSize = readInlineSize(editable.area);
296
+ const rendered = this.image.toRendered(editable.note);
249
297
  const innerDiv = this.area.firstElementChild;
250
- innerDiv.style.height = areaSize.height + "px";
251
- innerDiv.style.width = areaSize.width + "px";
252
- this.area.style.left = areaPos.left + "px";
253
- this.area.style.top = areaPos.top + "px";
254
- this.note.top = areaPos.top;
255
- this.note.left = areaPos.left;
256
- this.note.height = areaSize.height;
257
- this.note.width = areaSize.width;
298
+ innerDiv.style.height = rendered.height + "px";
299
+ innerDiv.style.width = rendered.width + "px";
300
+ this.area.style.left = rendered.left + "px";
301
+ this.area.style.top = rendered.top + "px";
302
+ this.note.top = editable.note.top;
303
+ this.note.left = editable.note.left;
304
+ this.note.height = editable.note.height;
305
+ this.note.width = editable.note.width;
258
306
  this.note.text = text;
259
307
  this.note.id = editable.note.id;
260
308
  this.editable = true;
261
309
  }
262
310
  /** Show the tooltip and apply hover styling. */
263
311
  show() {
312
+ this.tooltip.style.visibility = "hidden";
264
313
  this.tooltip.style.display = "block";
314
+ const noteRect = this.tooltip.getBoundingClientRect();
315
+ const areaRect = this.area.getBoundingClientRect();
316
+ const left = computeNoteLeft(noteRect.width, areaRect.left, areaRect.width, window.innerWidth);
317
+ this.tooltip.style.left = left + "px";
318
+ this.tooltip.style.visibility = "";
265
319
  if (!this.editable) {
266
320
  this.area.classList.add("image-annotate-area-hover");
267
321
  } else {
@@ -359,17 +413,19 @@ function destroyDraggable(el) {
359
413
  var MIN_SIZE = 10;
360
414
  var CORNERS = ["nw", "ne", "sw", "se"];
361
415
  function computeResize(corner, startLeft, startTop, startWidth, startHeight, dx, dy) {
362
- let left = startLeft, top = startTop, width = startWidth, height = startHeight;
416
+ let left, top, width, height;
363
417
  if (corner === "nw" || corner === "sw") {
364
418
  left = startLeft + dx;
365
419
  width = startWidth - dx;
366
420
  } else {
421
+ left = startLeft;
367
422
  width = startWidth + dx;
368
423
  }
369
424
  if (corner === "nw" || corner === "ne") {
370
425
  top = startTop + dy;
371
426
  height = startHeight - dy;
372
427
  } else {
428
+ top = startTop;
373
429
  height = startHeight + dy;
374
430
  }
375
431
  if (width < MIN_SIZE) {
@@ -524,17 +580,30 @@ var AnnotateImage = class {
524
580
  this._mode = "view";
525
581
  this.activeEdit = null;
526
582
  this.destroyed = false;
583
+ this.pendingRescale = false;
584
+ this.originalParent = null;
585
+ this.originalNextSibling = null;
527
586
  this.options = options;
528
587
  this.handlers = createDefaultHandlers();
529
588
  this.img = img;
530
- const width = img.width;
531
- const height = img.height;
532
- if (width === 0 || height === 0) {
589
+ this.naturalWidth = img.naturalWidth || img.width;
590
+ this.naturalHeight = img.naturalHeight || img.height;
591
+ const rendered = img.getBoundingClientRect();
592
+ const renderedWidth = rendered.width || img.width;
593
+ const renderedHeight = rendered.height || img.height;
594
+ if (this.naturalWidth === 0 || this.naturalHeight === 0) {
533
595
  throw new Error("image-annotate: image must have non-zero dimensions (is the image loaded?)");
534
596
  }
597
+ this.scaleX = renderedWidth / this.naturalWidth;
598
+ this.scaleY = renderedHeight / this.naturalHeight;
535
599
  this.notes = options.notes.map((n) => ({ ...n }));
600
+ this.originalParent = img.parentNode;
601
+ this.originalNextSibling = img.nextSibling;
536
602
  this.canvas = document.createElement("div");
537
603
  this.canvas.className = "image-annotate-canvas";
604
+ if (options.theme) {
605
+ this.canvas.dataset.theme = options.theme;
606
+ }
538
607
  this.viewOverlay = document.createElement("div");
539
608
  this.viewOverlay.className = "image-annotate-view";
540
609
  this.editOverlay = document.createElement("div");
@@ -543,19 +612,13 @@ var AnnotateImage = class {
543
612
  const editArea = document.createElement("div");
544
613
  editArea.className = "image-annotate-edit-area";
545
614
  this.editOverlay.appendChild(editArea);
546
- this.canvas.appendChild(this.viewOverlay);
547
- this.canvas.appendChild(this.editOverlay);
548
615
  if (!img.parentNode) {
549
616
  throw new Error("image-annotate: image must be in the DOM before initialization");
550
617
  }
551
- img.parentNode.insertBefore(this.canvas, img.nextSibling);
552
- this.canvas.style.height = height + "px";
553
- this.canvas.style.width = width + "px";
554
- this.canvas.style.backgroundImage = 'url("' + img.src + '")';
555
- this.viewOverlay.style.height = height + "px";
556
- this.viewOverlay.style.width = width + "px";
557
- this.editOverlay.style.height = height + "px";
558
- this.editOverlay.style.width = width + "px";
618
+ img.parentNode.insertBefore(this.canvas, img);
619
+ this.canvas.appendChild(img);
620
+ this.canvas.appendChild(this.viewOverlay);
621
+ this.canvas.appendChild(this.editOverlay);
559
622
  this.api = this.options.api ? normalizeApi(this.options.api) : {};
560
623
  if (this.api.load) {
561
624
  this.loadFromApi();
@@ -565,7 +628,38 @@ var AnnotateImage = class {
565
628
  if (this.options.editable) {
566
629
  this.createButton();
567
630
  }
568
- img.style.display = "none";
631
+ if (options.autoResize !== false && typeof ResizeObserver !== "undefined") {
632
+ this.resizeObserver = new ResizeObserver((entries) => {
633
+ const entry = entries[0];
634
+ if (!entry) return;
635
+ const { width, height } = entry.contentRect;
636
+ if (width === 0 || height === 0) return;
637
+ this.rescale(width, height);
638
+ });
639
+ this.resizeObserver.observe(this.canvas);
640
+ }
641
+ }
642
+ /** Convert a rect from natural image coordinates to rendered (scaled) coordinates. */
643
+ toRendered(rect) {
644
+ return {
645
+ top: rect.top * this.scaleY,
646
+ left: rect.left * this.scaleX,
647
+ width: rect.width * this.scaleX,
648
+ height: rect.height * this.scaleY
649
+ };
650
+ }
651
+ /** Convert a rect from rendered (scaled) coordinates to natural image coordinates. */
652
+ toNatural(rect) {
653
+ const result = {
654
+ top: rect.top / this.scaleY,
655
+ left: rect.left / this.scaleX,
656
+ width: rect.width / this.scaleX,
657
+ height: rect.height / this.scaleY
658
+ };
659
+ if (!isFinite(result.top) || !isFinite(result.left) || !isFinite(result.width) || !isFinite(result.height)) {
660
+ throw new Error("image-annotate: scale conversion produced non-finite coordinates");
661
+ }
662
+ return result;
569
663
  }
570
664
  /** Current interaction mode — 'view' for browsing, 'edit' when an annotation is being created or modified. */
571
665
  get mode() {
@@ -619,6 +713,7 @@ var AnnotateImage = class {
619
713
  /** Rebuild annotation views from the current notes array. */
620
714
  load() {
621
715
  this.destroyViews();
716
+ clampNotes(this.notes, this.naturalWidth, this.naturalHeight);
622
717
  this.createViews();
623
718
  this.notifyLoad();
624
719
  }
@@ -637,8 +732,15 @@ var AnnotateImage = class {
637
732
  if (this.button) {
638
733
  this.button.remove();
639
734
  }
735
+ if (this.resizeObserver) {
736
+ this.resizeObserver.disconnect();
737
+ this.resizeObserver = void 0;
738
+ }
739
+ if (this.originalParent && this.originalParent.isConnected) {
740
+ const ref = this.originalNextSibling?.parentNode === this.originalParent ? this.originalNextSibling : null;
741
+ this.originalParent.insertBefore(this.img, ref);
742
+ }
640
743
  this.canvas.remove();
641
- this.img.style.display = "";
642
744
  }
643
745
  /** Cancel the active edit (if any) and return to view mode. */
644
746
  cancelEdit() {
@@ -646,6 +748,34 @@ var AnnotateImage = class {
646
748
  this.activeEdit.destroy();
647
749
  this.setMode("view");
648
750
  }
751
+ this.flushPendingRescale();
752
+ }
753
+ /** Recompute scale factors, deferring if an edit is active. */
754
+ rescale(renderedWidth, renderedHeight) {
755
+ if (this.mode === "edit") {
756
+ this.pendingRescale = true;
757
+ return;
758
+ }
759
+ this.applyRescale(renderedWidth, renderedHeight);
760
+ }
761
+ /** Apply new scale factors and re-render all views. */
762
+ applyRescale(renderedWidth, renderedHeight) {
763
+ const newScaleX = renderedWidth / this.naturalWidth;
764
+ const newScaleY = renderedHeight / this.naturalHeight;
765
+ if (newScaleX === this.scaleX && newScaleY === this.scaleY) return;
766
+ this.scaleX = newScaleX;
767
+ this.scaleY = newScaleY;
768
+ this.destroyViews();
769
+ this.createViews();
770
+ }
771
+ /** @internal Flush any deferred rescale after an edit completes. */
772
+ flushPendingRescale() {
773
+ if (!this.pendingRescale) return;
774
+ this.pendingRescale = false;
775
+ const rect = this.canvas.getBoundingClientRect();
776
+ if (rect.width > 0 && rect.height > 0) {
777
+ this.applyRescale(rect.width, rect.height);
778
+ }
649
779
  }
650
780
  /** Replace all annotations with new data. Does not fire lifecycle callbacks. */
651
781
  setNotes(notes) {
@@ -692,6 +822,7 @@ var AnnotateImage = class {
692
822
  this.api.load().then((notes) => {
693
823
  this.destroyViews();
694
824
  this.notes = notes;
825
+ clampNotes(this.notes, this.naturalWidth, this.naturalHeight);
695
826
  this.createViews();
696
827
  this.notifyLoad();
697
828
  }).catch((err) => {
@@ -1 +1 @@
1
- "use strict";(()=>{var _=30,F=30,V=30,X=30,D=class{constructor(t,i,n){this.busy=!1;this.image=t,this.handlers=t.handlers,i?this.note=i:this.note={id:"new",top:_,left:F,width:V,height:X,text:"",editable:!0},this.area=t.editOverlay.querySelector(".image-annotate-edit-area"),this.area.style.height=this.note.height+"px",this.area.style.width=this.note.width+"px",this.area.style.left=this.note.left+"px",this.area.style.top=this.note.top+"px",this.form=document.createElement("div"),this.form.className="image-annotate-edit-form";let o=document.createElement("form");this.textarea=document.createElement("textarea"),this.textarea.name="text",this.textarea.rows=3,this.textarea.cols=30,this.textarea.value=this.note.text;let s=this.image.options.labels?.placeholder??"";s&&(this.textarea.placeholder=s),o.appendChild(this.textarea),this.form.appendChild(o),this.area.appendChild(this.form),this.form.addEventListener("pointerdown",r=>r.stopPropagation());let a=this.area,c=r=>{a.style.left=r.left+"px",a.style.top=r.top+"px",a.style.width=r.width+"px",a.style.height=r.height+"px"};this.handlers.makeResizable(a,{containment:t.canvas,onResize:c,onStop:c}),this.handlers.makeDraggable(a,{containment:t.canvas,onDrag:r=>{a.style.left=r.left+"px",a.style.top=r.top+"px"},onStop:r=>{a.style.left=r.left+"px",a.style.top=r.top+"px"}}),this.textarea.focus(),this.form.addEventListener("keydown",r=>{if(r.key==="Escape"){let p=this.form.querySelector(".image-annotate-edit-close");p&&p.click()}});let l=document.createElement("div");l.className="image-annotate-edit-buttons",this.form.appendChild(l),this.addSaveButton(l,n),n&&this.addDeleteButton(l,n),this.addCancelButton(l)}destroy(){this.image.activeEdit=null,this.handlers.destroyResizable(this.area),this.handlers.destroyDraggable(this.area),this.area.style.height="",this.area.style.width="",this.area.style.left="",this.area.style.top="",this.form.remove()}addSaveButton(t,i){let n=document.createElement("button");n.className="image-annotate-edit-ok",n.textContent=this.image.options.labels?.save??"OK",n.type="button",n.addEventListener("click",()=>{if(this.busy)return;let o=this.textarea.value,s=()=>{this.image.setMode("view"),i?i.resetPosition(this,o):(this.note.editable=!0,new T(this.image,this.note).resetPosition(this,o),this.image.notes.push(this.note)),this.image.notifySave(C(this.note)),this.destroy()},a=H(this.area),c=M(this.area);this.note.top=a.top,this.note.left=a.left,this.note.width=c.width,this.note.height=c.height,this.note.text=o,this.image.api.save?(this.busy=!0,this.image.api.save(C(this.note)).then(l=>{l.annotation_id!=null&&(this.note.id=l.annotation_id),s()}).catch(l=>{this.busy=!1;let r=l instanceof Error?l:new Error(String(l));this.image.reportError({type:"save",error:r,note:this.note})})):s()}),t.appendChild(n)}addDeleteButton(t,i){let n=document.createElement("button");n.className="image-annotate-edit-delete",n.textContent=this.image.options.labels?.delete??"Delete",n.type="button",n.addEventListener("click",()=>{if(this.busy)return;let o=()=>{this.image.setMode("view"),this.destroy(),i.destroy();let s=this.image.notes.indexOf(this.note);s!==-1&&this.image.notes.splice(s,1),this.image.notifyDelete(C(this.note))};this.image.api.delete?(this.busy=!0,this.image.api.delete(C(this.note)).then(()=>{o()}).catch(s=>{this.busy=!1;let a=s instanceof Error?s:new Error(String(s));this.image.reportError({type:"delete",error:a,note:this.note})})):o()}),t.appendChild(n)}addCancelButton(t){let i=document.createElement("button");i.className="image-annotate-edit-close",i.textContent=this.image.options.labels?.cancel??"Cancel",i.type="button",i.addEventListener("click",()=>{this.image.cancelEdit()}),t.appendChild(i)}};function H(e){return{left:parseInt(e.style.left)||0,top:parseInt(e.style.top)||0}}function M(e){return{width:parseInt(e.style.width)||e.offsetWidth,height:parseInt(e.style.height)||e.offsetHeight}}var T=class{constructor(t,i){this.image=t,this.note=i,this.editable=!!(i.editable&&t.options.editable),this.area=document.createElement("div"),this.area.className="image-annotate-area"+(this.editable?" image-annotate-area-editable":"");let n=document.createElement("div");this.area.appendChild(n),t.viewOverlay.insertBefore(this.area,t.viewOverlay.firstChild),this.tooltip=document.createElement("div"),this.tooltip.className="image-annotate-note",this.tooltip.textContent=i.text,this.tooltip.style.display="none",this.area.appendChild(this.tooltip),this.setPosition(),this.area.addEventListener("mouseenter",()=>this.show()),this.area.addEventListener("mouseleave",()=>this.hide()),this.editable&&(this.area.setAttribute("tabindex","0"),this.area.setAttribute("role","button"),this.area.addEventListener("click",()=>this.edit()),this.area.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),this.edit())}))}setPosition(){let t=this.area.firstElementChild;t.style.height=this.note.height+"px",t.style.width=this.note.width+"px",this.area.style.left=this.note.left+"px",this.area.style.top=this.note.top+"px"}resetPosition(t,i){this.tooltip.textContent=i,this.tooltip.style.display="none";let n=H(t.area),o=M(t.area),s=this.area.firstElementChild;s.style.height=o.height+"px",s.style.width=o.width+"px",this.area.style.left=n.left+"px",this.area.style.top=n.top+"px",this.note.top=n.top,this.note.left=n.left,this.note.height=o.height,this.note.width=o.width,this.note.text=i,this.note.id=t.note.id,this.editable=!0}show(){this.tooltip.style.display="block",this.editable?this.area.classList.add("image-annotate-area-editable-hover"):this.area.classList.add("image-annotate-area-hover")}hide(){this.tooltip.style.display="none",this.area.classList.remove("image-annotate-area-hover"),this.area.classList.remove("image-annotate-area-editable-hover")}destroy(){this.area.remove(),this.tooltip.remove()}edit(){this.image.mode==="view"&&(this.image.setMode("edit"),this.image.activeEdit=new D(this.image,this.note,this))}};var P=new WeakMap,O=new WeakMap;function Y(e,t){R(e);function i(n){if(n.button!==0)return;n.preventDefault(),e.setPointerCapture&&e.setPointerCapture(n.pointerId);let o=n.clientX,s=n.clientY,a=parseFloat(e.style.left)||0,c=parseFloat(e.style.top)||0,l=parseFloat(e.style.width)||e.offsetWidth,r=parseFloat(e.style.height)||e.offsetHeight,p=-1/0,x=-1/0,A=1/0,E=1/0;if(t.containment){let m=t.containment.getBoundingClientRect(),u=e.getBoundingClientRect(),y=a-(u.left-m.left),d=c-(u.top-m.top);p=y,x=d,A=m.width-l+y,E=m.height-r+d}function b(m,u,y){return Math.max(u,Math.min(y,m))}function w(m){let u=m.clientX-o,y=m.clientY-s,d=b(a+u,p,A),h=b(c+y,x,E);t.onDrag&&t.onDrag({left:d,top:h})}function L(m){e.releasePointerCapture&&e.releasePointerCapture(m.pointerId),e.removeEventListener("pointermove",w),e.removeEventListener("pointerup",L);let u=m.clientX-o,y=m.clientY-s,d=b(a+u,p,A),h=b(c+y,x,E);t.onStop&&t.onStop({left:d,top:h})}e.addEventListener("pointermove",w),e.addEventListener("pointerup",L)}e.addEventListener("pointerdown",i),P.set(e,()=>{e.removeEventListener("pointerdown",i)})}function R(e){let t=P.get(e);t&&(t(),P.delete(e))}var g=10,U=["nw","ne","sw","se"];function k(e,t,i,n,o,s,a){let c=t,l=i,r=n,p=o;return e==="nw"||e==="sw"?(c=t+s,r=n-s):r=n+s,e==="nw"||e==="ne"?(l=i+a,p=o-a):p=o+a,r<g&&((e==="nw"||e==="sw")&&(c=t+n-g),r=g),p<g&&((e==="nw"||e==="ne")&&(l=i+o-g),p=g),{left:c,top:l,width:r,height:p}}function j(e,t){z(e);let i=[];for(let n of U){let o=document.createElement("div");o.className=`image-annotate-resize-handle image-annotate-resize-handle-${n}`,e.appendChild(o),i.push(o),o.addEventListener("pointerdown",function(a){if(a.button!==0)return;a.preventDefault(),a.stopPropagation(),o.setPointerCapture&&o.setPointerCapture(a.pointerId);let c=a.clientX,l=a.clientY,r=parseFloat(e.style.left)||0,p=parseFloat(e.style.top)||0,x=parseFloat(e.style.width)||0,A=parseFloat(e.style.height)||0,E=1/0,b=1/0,w=-1/0,L=-1/0;if(t.containment){let d=t.containment.getBoundingClientRect(),h=e.getBoundingClientRect(),f=r-(h.left-d.left),v=p-(h.top-d.top);w=f,L=v,E=d.width+f,b=d.height+v}function m(d){let{left:h,top:f,width:v,height:N}=d;return h<w&&(v-=w-h,h=w),f<L&&(N-=L-f,f=L),h+v>E&&(v=E-h),f+N>b&&(N=b-f),v<g&&(v=g),N<g&&(N=g),{left:h,top:f,width:v,height:N}}function u(d){let h=d.clientX-c,f=d.clientY-l,v=m(k(n,r,p,x,A,h,f));t.onResize?.(v)}function y(d){o.releasePointerCapture&&o.releasePointerCapture(d.pointerId),o.removeEventListener("pointermove",u),o.removeEventListener("pointerup",y);let h=d.clientX-c,f=d.clientY-l,v=m(k(n,r,p,x,A,h,f));t.onStop&&t.onStop(v)}o.addEventListener("pointermove",u),o.addEventListener("pointerup",y)})}O.set(e,()=>{for(let n of i)n.remove()})}function z(e){let t=O.get(e);t&&(t(),O.delete(e))}function B(){return{makeDraggable:Y,makeResizable:j,destroyDraggable:R,destroyResizable:z}}function C(e){let{view:t,editable:i,...n}=e;return n}function J(e){return{load:typeof e.load=="string"?K(e.load):e.load,save:typeof e.save=="string"?W(e.save):e.save,delete:typeof e.delete=="string"?q(e.delete):e.delete}}function K(e){return()=>fetch(e).then(t=>{if(!t.ok)throw new Error(`Load failed (HTTP ${t.status})`);return t.json()})}function W(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(i=>{if(!i.ok)throw new Error(`Save failed (HTTP ${i.status})`);return i.json()})}function q(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(i=>{if(!i.ok)throw new Error(`Delete failed (HTTP ${i.status})`)})}var I=class{constructor(t,i){this._mode="view";this.activeEdit=null;this.destroyed=!1;this.options=i,this.handlers=B(),this.img=t;let n=t.width,o=t.height;if(n===0||o===0)throw new Error("image-annotate: image must have non-zero dimensions (is the image loaded?)");this.notes=i.notes.map(a=>({...a})),this.canvas=document.createElement("div"),this.canvas.className="image-annotate-canvas",this.viewOverlay=document.createElement("div"),this.viewOverlay.className="image-annotate-view",this.editOverlay=document.createElement("div"),this.editOverlay.className="image-annotate-edit",this.editOverlay.style.display="none";let s=document.createElement("div");if(s.className="image-annotate-edit-area",this.editOverlay.appendChild(s),this.canvas.appendChild(this.viewOverlay),this.canvas.appendChild(this.editOverlay),!t.parentNode)throw new Error("image-annotate: image must be in the DOM before initialization");t.parentNode.insertBefore(this.canvas,t.nextSibling),this.canvas.style.height=o+"px",this.canvas.style.width=n+"px",this.canvas.style.backgroundImage='url("'+t.src+'")',this.viewOverlay.style.height=o+"px",this.viewOverlay.style.width=n+"px",this.editOverlay.style.height=o+"px",this.editOverlay.style.width=n+"px",this.api=this.options.api?J(this.options.api):{},this.api.load?this.loadFromApi():this.load(),this.options.editable&&this.createButton(),t.style.display="none"}get mode(){return this._mode}setMode(t){this._mode=t,t==="edit"?(this.canvas.classList.add("image-annotate-editing"),this.editOverlay.style.display="block"):(this.canvas.classList.remove("image-annotate-editing"),this.editOverlay.style.display="none")}getNotes(){return this.notes.map(C)}notifyChange(){this.options.onChange?.(this.getNotes())}notifySave(t){this.options.onSave?.(t),this.notifyChange()}notifyDelete(t){this.options.onDelete?.(t),this.notifyChange()}notifyLoad(){this.options.onLoad?.(this.getNotes()),this.notifyChange()}destroyViews(){this.cancelEdit();for(let t of this.notes)t.view?.destroy()}createViews(){for(let t of this.notes)t.view=new T(this,t)}load(){this.destroyViews(),this.createViews(),this.notifyLoad()}clear(){this.destroyViews(),this.notes=[],this.notifyChange()}destroy(){this.destroyed||(this.destroyed=!0,this.destroyViews(),this.notes=[],this.button&&this.button.remove(),this.canvas.remove(),this.img.style.display="")}cancelEdit(){this.activeEdit&&(this.activeEdit.destroy(),this.setMode("view"))}setNotes(t){this.destroyed||(this.destroyViews(),this.notes=t.map(i=>({...i})),this.createViews())}setEditable(t){this.destroyed||this.options.editable!==t&&(this.options.editable=t,t&&!this.button?this.createButton():!t&&this.button&&(this.button.remove(),this.button=void 0),this.destroyViews(),this.createViews())}createButton(){this.button=document.createElement("button"),this.button.className="image-annotate-add",this.button.title=this.options.labels?.addNote??"Add Note",this.button.type="button",this.button.addEventListener("click",()=>{this.add()}),this.canvas.appendChild(this.button)}reportError(t){this.options.onError?this.options.onError(t):console.error(`image-annotate: ${t.type} failed`,t.error)}loadFromApi(){this.api.load&&this.api.load().then(t=>{this.destroyViews(),this.notes=t,this.createViews(),this.notifyLoad()}).catch(t=>{let i=t instanceof Error?t:new Error(String(t));this.reportError({type:"load",error:i})})}add(){return this.mode==="view"?(this.setMode("edit"),this.activeEdit=new D(this),!0):!1}};var S={addNote:"Add Note",save:"OK",delete:"Delete",cancel:"Cancel",placeholder:""};var Q={editable:!0,notes:[],labels:{...S}};$.fn.annotateImage=function(e){if(e==="destroy"){let s=this.data("annotateImage");return s&&(s.destroy(),this.removeData("annotateImage")),this}let t=e,i={...Q,...t,labels:{...S,...t?.labels}},n=this[0],o=new I(n,i);return this.data("annotateImage",o),this};})();
1
+ "use strict";(()=>{function X(e,t,i){let n=Math.min(e.width,t),o=Math.min(e.height,i),l=Math.max(0,Math.min(e.left,t-n));return{top:Math.max(0,Math.min(e.top,i-o)),left:l,width:n,height:o}}function I(e,t,i){for(let n of e)Object.assign(n,X(n,t,i))}function T(e,t,i,n){let o=(i-e)/2,r=t+o+e;r>n&&(o-=r-n);let s=t+o;return s<0&&(o-=s),o}var Y=30,_=30,W=30,U=30,R=class{constructor(t,i,n){this.busy=!1;this.image=t,this.handlers=t.handlers,i?this.note=i:this.note={id:"new",top:Y,left:_,width:W,height:U,text:"",editable:!0},this.area=t.editOverlay.querySelector(".image-annotate-edit-area");let o=t.toRendered(this.note);this.area.style.height=o.height+"px",this.area.style.width=o.width+"px",this.area.style.left=o.left+"px",this.area.style.top=o.top+"px",this.form=document.createElement("div"),this.form.className="image-annotate-edit-form";let l=document.createElement("form");this.textarea=document.createElement("textarea"),this.textarea.name="text",this.textarea.rows=3,this.textarea.cols=30,this.textarea.value=this.note.text;let r=this.image.options.labels?.placeholder??"";r&&(this.textarea.placeholder=r),l.appendChild(this.textarea),this.form.appendChild(l),this.area.appendChild(this.form),this.positionForm(),this.textarea.focus(),this.form.addEventListener("pointerdown",a=>a.stopPropagation());let s=this.area,d=a=>{s.style.left=a.left+"px",s.style.top=a.top+"px",s.style.width=a.width+"px",s.style.height=a.height+"px"};this.handlers.makeResizable(s,{containment:t.canvas,onResize:d,onStop:a=>{d(a),this.positionForm()}}),this.handlers.makeDraggable(s,{containment:t.canvas,onDrag:a=>{s.style.left=a.left+"px",s.style.top=a.top+"px"},onStop:a=>{s.style.left=a.left+"px",s.style.top=a.top+"px",this.positionForm()}}),this.form.addEventListener("keydown",a=>{if(a.key==="Escape"){let y=this.form.querySelector(".image-annotate-edit-close");y&&y.click()}});let h=document.createElement("div");h.className="image-annotate-edit-buttons",this.form.appendChild(h),this.addSaveButton(h,n),n&&this.addDeleteButton(h,n),this.addCancelButton(h)}positionForm(){let t=this.form.getBoundingClientRect(),i=this.area.getBoundingClientRect(),n=T(t.width,i.left,i.width,window.innerWidth);this.form.style.left=n+"px"}destroy(){this.image.activeEdit=null,this.handlers.destroyResizable(this.area),this.handlers.destroyDraggable(this.area),this.area.style.height="",this.area.style.width="",this.area.style.left="",this.area.style.top="",this.form.remove()}addSaveButton(t,i){let n=document.createElement("button");n.className="image-annotate-edit-ok",n.textContent=this.image.options.labels?.save??"OK",n.type="button",n.addEventListener("click",()=>{if(this.busy)return;let o=this.textarea.value,l=()=>{this.image.setMode("view"),i?i.resetPosition(this,o):(this.note.editable=!0,new D(this.image,this.note).resetPosition(this,o),this.image.notes.push(this.note)),this.image.notifySave(C(this.note)),this.destroy(),this.image.flushPendingRescale()},r=S(this.area),s=z(this.area),d=this.image.toNatural({top:r.top,left:r.left,width:s.width,height:s.height});this.note.top=d.top,this.note.left=d.left,this.note.width=d.width,this.note.height=d.height,this.note.text=o,this.image.api.save?(this.busy=!0,this.image.api.save(C(this.note)).then(h=>{h.annotation_id!=null&&(this.note.id=h.annotation_id),l()}).catch(h=>{this.busy=!1;let a=h instanceof Error?h:new Error(String(h));this.image.reportError({type:"save",error:a,note:this.note})})):l()}),t.appendChild(n)}addDeleteButton(t,i){let n=document.createElement("button");n.className="image-annotate-edit-delete",n.textContent=this.image.options.labels?.delete??"Delete",n.type="button",n.addEventListener("click",()=>{if(this.busy)return;let o=()=>{this.image.setMode("view"),this.destroy(),i.destroy();let l=this.image.notes.indexOf(this.note);l!==-1&&this.image.notes.splice(l,1),this.image.notifyDelete(C(this.note)),this.image.flushPendingRescale()};this.image.api.delete?(this.busy=!0,this.image.api.delete(C(this.note)).then(()=>{o()}).catch(l=>{this.busy=!1;let r=l instanceof Error?l:new Error(String(l));this.image.reportError({type:"delete",error:r,note:this.note})})):o()}),t.appendChild(n)}addCancelButton(t){let i=document.createElement("button");i.className="image-annotate-edit-close",i.textContent=this.image.options.labels?.cancel??"Cancel",i.type="button",i.addEventListener("click",()=>{this.image.cancelEdit()}),t.appendChild(i)}};function S(e){return{left:parseInt(e.style.left)||0,top:parseInt(e.style.top)||0}}function z(e){return{width:parseInt(e.style.width)||e.offsetWidth,height:parseInt(e.style.height)||e.offsetHeight}}var D=class{constructor(t,i){this.image=t,this.note=i,this.editable=!!(i.editable&&t.options.editable),this.area=document.createElement("div"),this.area.className="image-annotate-area"+(this.editable?" image-annotate-area-editable":"");let n=document.createElement("div");this.area.appendChild(n),t.viewOverlay.insertBefore(this.area,t.viewOverlay.firstChild),this.tooltip=document.createElement("div"),this.tooltip.className="image-annotate-note",this.tooltip.textContent=i.text,this.tooltip.style.display="none",this.area.appendChild(this.tooltip),this.setPosition(),this.area.addEventListener("mouseenter",()=>this.show()),this.area.addEventListener("mouseleave",()=>this.hide()),this.editable&&(this.area.setAttribute("tabindex","0"),this.area.setAttribute("role","button"),this.area.addEventListener("click",()=>this.edit()),this.area.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),this.edit())}))}setPosition(){let t=this.image.toRendered(this.note),i=this.area.firstElementChild;i.style.height=t.height+"px",i.style.width=t.width+"px",this.area.style.left=t.left+"px",this.area.style.top=t.top+"px"}resetPosition(t,i){this.tooltip.textContent=i,this.tooltip.style.display="none";let n=this.image.toRendered(t.note),o=this.area.firstElementChild;o.style.height=n.height+"px",o.style.width=n.width+"px",this.area.style.left=n.left+"px",this.area.style.top=n.top+"px",this.note.top=t.note.top,this.note.left=t.note.left,this.note.height=t.note.height,this.note.width=t.note.width,this.note.text=i,this.note.id=t.note.id,this.editable=!0}show(){this.tooltip.style.visibility="hidden",this.tooltip.style.display="block";let t=this.tooltip.getBoundingClientRect(),i=this.area.getBoundingClientRect(),n=T(t.width,i.left,i.width,window.innerWidth);this.tooltip.style.left=n+"px",this.tooltip.style.visibility="",this.editable?this.area.classList.add("image-annotate-area-editable-hover"):this.area.classList.add("image-annotate-area-hover")}hide(){this.tooltip.style.display="none",this.area.classList.remove("image-annotate-area-hover"),this.area.classList.remove("image-annotate-area-editable-hover")}destroy(){this.area.remove(),this.tooltip.remove()}edit(){this.image.mode==="view"&&(this.image.setMode("edit"),this.image.activeEdit=new R(this.image,this.note,this))}};var P=new WeakMap,M=new WeakMap;function j(e,t){B(e);function i(n){if(n.button!==0)return;n.preventDefault(),e.setPointerCapture&&e.setPointerCapture(n.pointerId);let o=n.clientX,l=n.clientY,r=parseFloat(e.style.left)||0,s=parseFloat(e.style.top)||0,d=parseFloat(e.style.width)||e.offsetWidth,h=parseFloat(e.style.height)||e.offsetHeight,a=-1/0,y=-1/0,N=1/0,E=1/0;if(t.containment){let p=t.containment.getBoundingClientRect(),v=e.getBoundingClientRect(),g=r-(v.left-p.left),c=s-(v.top-p.top);a=g,y=c,N=p.width-d+g,E=p.height-h+c}function w(p,v,g){return Math.max(v,Math.min(g,p))}function L(p){let v=p.clientX-o,g=p.clientY-l,c=w(r+v,a,N),m=w(s+g,y,E);t.onDrag&&t.onDrag({left:c,top:m})}function x(p){e.releasePointerCapture&&e.releasePointerCapture(p.pointerId),e.removeEventListener("pointermove",L),e.removeEventListener("pointerup",x);let v=p.clientX-o,g=p.clientY-l,c=w(r+v,a,N),m=w(s+g,y,E);t.onStop&&t.onStop({left:c,top:m})}e.addEventListener("pointermove",L),e.addEventListener("pointerup",x)}e.addEventListener("pointerdown",i),P.set(e,()=>{e.removeEventListener("pointerdown",i)})}function B(e){let t=P.get(e);t&&(t(),P.delete(e))}var b=10,q=["nw","ne","sw","se"];function k(e,t,i,n,o,l,r){let s,d,h,a;return e==="nw"||e==="sw"?(s=t+l,h=n-l):(s=t,h=n+l),e==="nw"||e==="ne"?(d=i+r,a=o-r):(d=i,a=o+r),h<b&&((e==="nw"||e==="sw")&&(s=t+n-b),h=b),a<b&&((e==="nw"||e==="ne")&&(d=i+o-b),a=b),{left:s,top:d,width:h,height:a}}function K(e,t){F(e);let i=[];for(let n of q){let o=document.createElement("div");o.className=`image-annotate-resize-handle image-annotate-resize-handle-${n}`,e.appendChild(o),i.push(o),o.addEventListener("pointerdown",function(r){if(r.button!==0)return;r.preventDefault(),r.stopPropagation(),o.setPointerCapture&&o.setPointerCapture(r.pointerId);let s=r.clientX,d=r.clientY,h=parseFloat(e.style.left)||0,a=parseFloat(e.style.top)||0,y=parseFloat(e.style.width)||0,N=parseFloat(e.style.height)||0,E=1/0,w=1/0,L=-1/0,x=-1/0;if(t.containment){let c=t.containment.getBoundingClientRect(),m=e.getBoundingClientRect(),u=h-(m.left-c.left),f=a-(m.top-c.top);L=u,x=f,E=c.width+u,w=c.height+f}function p(c){let{left:m,top:u,width:f,height:A}=c;return m<L&&(f-=L-m,m=L),u<x&&(A-=x-u,u=x),m+f>E&&(f=E-m),u+A>w&&(A=w-u),f<b&&(f=b),A<b&&(A=b),{left:m,top:u,width:f,height:A}}function v(c){let m=c.clientX-s,u=c.clientY-d,f=p(k(n,h,a,y,N,m,u));t.onResize?.(f)}function g(c){o.releasePointerCapture&&o.releasePointerCapture(c.pointerId),o.removeEventListener("pointermove",v),o.removeEventListener("pointerup",g);let m=c.clientX-s,u=c.clientY-d,f=p(k(n,h,a,y,N,m,u));t.onStop&&t.onStop(f)}o.addEventListener("pointermove",v),o.addEventListener("pointerup",g)})}M.set(e,()=>{for(let n of i)n.remove()})}function F(e){let t=M.get(e);t&&(t(),M.delete(e))}function V(){return{makeDraggable:j,makeResizable:K,destroyDraggable:B,destroyResizable:F}}function C(e){let{view:t,editable:i,...n}=e;return n}function J(e){return{load:typeof e.load=="string"?G(e.load):e.load,save:typeof e.save=="string"?Q(e.save):e.save,delete:typeof e.delete=="string"?Z(e.delete):e.delete}}function G(e){return()=>fetch(e).then(t=>{if(!t.ok)throw new Error(`Load failed (HTTP ${t.status})`);return t.json()})}function Q(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(i=>{if(!i.ok)throw new Error(`Save failed (HTTP ${i.status})`);return i.json()})}function Z(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(i=>{if(!i.ok)throw new Error(`Delete failed (HTTP ${i.status})`)})}var H=class{constructor(t,i){this._mode="view";this.activeEdit=null;this.destroyed=!1;this.pendingRescale=!1;this.originalParent=null;this.originalNextSibling=null;this.options=i,this.handlers=V(),this.img=t,this.naturalWidth=t.naturalWidth||t.width,this.naturalHeight=t.naturalHeight||t.height;let n=t.getBoundingClientRect(),o=n.width||t.width,l=n.height||t.height;if(this.naturalWidth===0||this.naturalHeight===0)throw new Error("image-annotate: image must have non-zero dimensions (is the image loaded?)");this.scaleX=o/this.naturalWidth,this.scaleY=l/this.naturalHeight,this.notes=i.notes.map(s=>({...s})),this.originalParent=t.parentNode,this.originalNextSibling=t.nextSibling,this.canvas=document.createElement("div"),this.canvas.className="image-annotate-canvas",i.theme&&(this.canvas.dataset.theme=i.theme),this.viewOverlay=document.createElement("div"),this.viewOverlay.className="image-annotate-view",this.editOverlay=document.createElement("div"),this.editOverlay.className="image-annotate-edit",this.editOverlay.style.display="none";let r=document.createElement("div");if(r.className="image-annotate-edit-area",this.editOverlay.appendChild(r),!t.parentNode)throw new Error("image-annotate: image must be in the DOM before initialization");t.parentNode.insertBefore(this.canvas,t),this.canvas.appendChild(t),this.canvas.appendChild(this.viewOverlay),this.canvas.appendChild(this.editOverlay),this.api=this.options.api?J(this.options.api):{},this.api.load?this.loadFromApi():this.load(),this.options.editable&&this.createButton(),i.autoResize!==!1&&typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(s=>{let d=s[0];if(!d)return;let{width:h,height:a}=d.contentRect;h===0||a===0||this.rescale(h,a)}),this.resizeObserver.observe(this.canvas))}toRendered(t){return{top:t.top*this.scaleY,left:t.left*this.scaleX,width:t.width*this.scaleX,height:t.height*this.scaleY}}toNatural(t){let i={top:t.top/this.scaleY,left:t.left/this.scaleX,width:t.width/this.scaleX,height:t.height/this.scaleY};if(!isFinite(i.top)||!isFinite(i.left)||!isFinite(i.width)||!isFinite(i.height))throw new Error("image-annotate: scale conversion produced non-finite coordinates");return i}get mode(){return this._mode}setMode(t){this._mode=t,t==="edit"?(this.canvas.classList.add("image-annotate-editing"),this.editOverlay.style.display="block"):(this.canvas.classList.remove("image-annotate-editing"),this.editOverlay.style.display="none")}getNotes(){return this.notes.map(C)}notifyChange(){this.options.onChange?.(this.getNotes())}notifySave(t){this.options.onSave?.(t),this.notifyChange()}notifyDelete(t){this.options.onDelete?.(t),this.notifyChange()}notifyLoad(){this.options.onLoad?.(this.getNotes()),this.notifyChange()}destroyViews(){this.cancelEdit();for(let t of this.notes)t.view?.destroy()}createViews(){for(let t of this.notes)t.view=new D(this,t)}load(){this.destroyViews(),I(this.notes,this.naturalWidth,this.naturalHeight),this.createViews(),this.notifyLoad()}clear(){this.destroyViews(),this.notes=[],this.notifyChange()}destroy(){if(!this.destroyed){if(this.destroyed=!0,this.destroyViews(),this.notes=[],this.button&&this.button.remove(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=void 0),this.originalParent&&this.originalParent.isConnected){let t=this.originalNextSibling?.parentNode===this.originalParent?this.originalNextSibling:null;this.originalParent.insertBefore(this.img,t)}this.canvas.remove()}}cancelEdit(){this.activeEdit&&(this.activeEdit.destroy(),this.setMode("view")),this.flushPendingRescale()}rescale(t,i){if(this.mode==="edit"){this.pendingRescale=!0;return}this.applyRescale(t,i)}applyRescale(t,i){let n=t/this.naturalWidth,o=i/this.naturalHeight;n===this.scaleX&&o===this.scaleY||(this.scaleX=n,this.scaleY=o,this.destroyViews(),this.createViews())}flushPendingRescale(){if(!this.pendingRescale)return;this.pendingRescale=!1;let t=this.canvas.getBoundingClientRect();t.width>0&&t.height>0&&this.applyRescale(t.width,t.height)}setNotes(t){this.destroyed||(this.destroyViews(),this.notes=t.map(i=>({...i})),this.createViews())}setEditable(t){this.destroyed||this.options.editable!==t&&(this.options.editable=t,t&&!this.button?this.createButton():!t&&this.button&&(this.button.remove(),this.button=void 0),this.destroyViews(),this.createViews())}createButton(){this.button=document.createElement("button"),this.button.className="image-annotate-add",this.button.title=this.options.labels?.addNote??"Add Note",this.button.type="button",this.button.addEventListener("click",()=>{this.add()}),this.canvas.appendChild(this.button)}reportError(t){this.options.onError?this.options.onError(t):console.error(`image-annotate: ${t.type} failed`,t.error)}loadFromApi(){this.api.load&&this.api.load().then(t=>{this.destroyViews(),this.notes=t,I(this.notes,this.naturalWidth,this.naturalHeight),this.createViews(),this.notifyLoad()}).catch(t=>{let i=t instanceof Error?t:new Error(String(t));this.reportError({type:"load",error:i})})}add(){return this.mode==="view"?(this.setMode("edit"),this.activeEdit=new R(this),!0):!1}};var O={addNote:"Add Note",save:"OK",delete:"Delete",cancel:"Cancel",placeholder:""};var tt={editable:!0,notes:[],labels:{...O}};$.fn.annotateImage=function(e){if(e==="destroy"){let l=this.data("annotateImage");return l&&(l.destroy(),this.removeData("annotateImage")),this}let t=e,i={...tt,...t,labels:{...O,...t?.labels}},n=this[0],o=new H(n,i);return this.data("annotateImage",o),this};})();