annotate-image 2.0.0-beta.1 → 2.0.0-beta.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/dist/core.js +118 -38
- package/dist/core.min.js +1 -1
- package/dist/css/annotate.min.css +1 -1
- package/dist/jquery.js +117 -38
- package/dist/jquery.min.js +1 -1
- package/dist/react.js +119 -39
- package/dist/types/annotate-image.d.ts +42 -0
- package/dist/types/annotate-view.d.ts +1 -1
- package/dist/types/react.d.ts +2 -0
- package/dist/types/types.d.ts +2 -0
- package/dist/types/vue.d.ts +11 -0
- package/dist/vue.js +121 -39
- package/package.json +1 -1
- package/readme.md +25 -0
package/dist/jquery.min.js
CHANGED
|
@@ -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";(()=>{var F=30,X=30,Y=30,_=30,D=class{constructor(t,n,i){this.busy=!1;this.image=t,this.handlers=t.handlers,n?this.note=n:this.note={id:"new",top:F,left:X,width:Y,height:_,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 d=this.image.options.labels?.placeholder??"";d&&(this.textarea.placeholder=d),l.appendChild(this.textarea),this.form.appendChild(l),this.area.appendChild(this.form),this.form.addEventListener("pointerdown",a=>a.stopPropagation());let s=this.area,c=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:c,onStop:c}),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.textarea.focus(),this.form.addEventListener("keydown",a=>{if(a.key==="Escape"){let b=this.form.querySelector(".image-annotate-edit-close");b&&b.click()}});let r=document.createElement("div");r.className="image-annotate-edit-buttons",this.form.appendChild(r),this.addSaveButton(r,i),i&&this.addDeleteButton(r,i),this.addCancelButton(r)}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,n){let i=document.createElement("button");i.className="image-annotate-edit-ok",i.textContent=this.image.options.labels?.save??"OK",i.type="button",i.addEventListener("click",()=>{if(this.busy)return;let o=this.textarea.value,l=()=>{this.image.setMode("view"),n?n.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(),this.image.flushPendingRescale()},d=O(this.area),s=M(this.area),c=this.image.toNatural({top:d.top,left:d.left,width:s.width,height:s.height});this.note.top=c.top,this.note.left=c.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(r=>{r.annotation_id!=null&&(this.note.id=r.annotation_id),l()}).catch(r=>{this.busy=!1;let a=r instanceof Error?r:new Error(String(r));this.image.reportError({type:"save",error:a,note:this.note})})):l()}),t.appendChild(i)}addDeleteButton(t,n){let i=document.createElement("button");i.className="image-annotate-edit-delete",i.textContent=this.image.options.labels?.delete??"Delete",i.type="button",i.addEventListener("click",()=>{if(this.busy)return;let o=()=>{this.image.setMode("view"),this.destroy(),n.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 d=l instanceof Error?l:new Error(String(l));this.image.reportError({type:"delete",error:d,note:this.note})})):o()}),t.appendChild(i)}addCancelButton(t){let n=document.createElement("button");n.className="image-annotate-edit-close",n.textContent=this.image.options.labels?.cancel??"Cancel",n.type="button",n.addEventListener("click",()=>{this.image.cancelEdit()}),t.appendChild(n)}};function O(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,n){this.image=t,this.note=n,this.editable=!!(n.editable&&t.options.editable),this.area=document.createElement("div"),this.area.className="image-annotate-area"+(this.editable?" image-annotate-area-editable":"");let i=document.createElement("div");this.area.appendChild(i),t.viewOverlay.insertBefore(this.area,t.viewOverlay.firstChild),this.tooltip=document.createElement("div"),this.tooltip.className="image-annotate-note",this.tooltip.textContent=n.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),n=this.area.firstElementChild;n.style.height=t.height+"px",n.style.width=t.width+"px",this.area.style.left=t.left+"px",this.area.style.top=t.top+"px"}resetPosition(t,n){this.tooltip.textContent=n,this.tooltip.style.display="none";let i=this.image.toRendered(t.note),o=this.area.firstElementChild;o.style.height=i.height+"px",o.style.width=i.width+"px",this.area.style.left=i.left+"px",this.area.style.top=i.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=n,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 I=new WeakMap,P=new WeakMap;function V(e,t){z(e);function n(i){if(i.button!==0)return;i.preventDefault(),e.setPointerCapture&&e.setPointerCapture(i.pointerId);let o=i.clientX,l=i.clientY,d=parseFloat(e.style.left)||0,s=parseFloat(e.style.top)||0,c=parseFloat(e.style.width)||e.offsetWidth,r=parseFloat(e.style.height)||e.offsetHeight,a=-1/0,b=-1/0,N=1/0,E=1/0;if(t.containment){let m=t.containment.getBoundingClientRect(),v=e.getBoundingClientRect(),g=d-(v.left-m.left),h=s-(v.top-m.top);a=g,b=h,N=m.width-c+g,E=m.height-r+h}function w(m,v,g){return Math.max(v,Math.min(g,m))}function L(m){let v=m.clientX-o,g=m.clientY-l,h=w(d+v,a,N),p=w(s+g,b,E);t.onDrag&&t.onDrag({left:h,top:p})}function x(m){e.releasePointerCapture&&e.releasePointerCapture(m.pointerId),e.removeEventListener("pointermove",L),e.removeEventListener("pointerup",x);let v=m.clientX-o,g=m.clientY-l,h=w(d+v,a,N),p=w(s+g,b,E);t.onStop&&t.onStop({left:h,top:p})}e.addEventListener("pointermove",L),e.addEventListener("pointerup",x)}e.addEventListener("pointerdown",n),I.set(e,()=>{e.removeEventListener("pointerdown",n)})}function z(e){let t=I.get(e);t&&(t(),I.delete(e))}var y=10,W=["nw","ne","sw","se"];function S(e,t,n,i,o,l,d){let s=t,c=n,r=i,a=o;return e==="nw"||e==="sw"?(s=t+l,r=i-l):r=i+l,e==="nw"||e==="ne"?(c=n+d,a=o-d):a=o+d,r<y&&((e==="nw"||e==="sw")&&(s=t+i-y),r=y),a<y&&((e==="nw"||e==="ne")&&(c=n+o-y),a=y),{left:s,top:c,width:r,height:a}}function U(e,t){k(e);let n=[];for(let i of W){let o=document.createElement("div");o.className=`image-annotate-resize-handle image-annotate-resize-handle-${i}`,e.appendChild(o),n.push(o),o.addEventListener("pointerdown",function(d){if(d.button!==0)return;d.preventDefault(),d.stopPropagation(),o.setPointerCapture&&o.setPointerCapture(d.pointerId);let s=d.clientX,c=d.clientY,r=parseFloat(e.style.left)||0,a=parseFloat(e.style.top)||0,b=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 h=t.containment.getBoundingClientRect(),p=e.getBoundingClientRect(),f=r-(p.left-h.left),u=a-(p.top-h.top);L=f,x=u,E=h.width+f,w=h.height+u}function m(h){let{left:p,top:f,width:u,height:A}=h;return p<L&&(u-=L-p,p=L),f<x&&(A-=x-f,f=x),p+u>E&&(u=E-p),f+A>w&&(A=w-f),u<y&&(u=y),A<y&&(A=y),{left:p,top:f,width:u,height:A}}function v(h){let p=h.clientX-s,f=h.clientY-c,u=m(S(i,r,a,b,N,p,f));t.onResize?.(u)}function g(h){o.releasePointerCapture&&o.releasePointerCapture(h.pointerId),o.removeEventListener("pointermove",v),o.removeEventListener("pointerup",g);let p=h.clientX-s,f=h.clientY-c,u=m(S(i,r,a,b,N,p,f));t.onStop&&t.onStop(u)}o.addEventListener("pointermove",v),o.addEventListener("pointerup",g)})}P.set(e,()=>{for(let i of n)i.remove()})}function k(e){let t=P.get(e);t&&(t(),P.delete(e))}function B(){return{makeDraggable:V,makeResizable:U,destroyDraggable:z,destroyResizable:k}}function C(e){let{view:t,editable:n,...i}=e;return i}function j(e){return{load:typeof e.load=="string"?J(e.load):e.load,save:typeof e.save=="string"?K(e.save):e.save,delete:typeof e.delete=="string"?q(e.delete):e.delete}}function J(e){return()=>fetch(e).then(t=>{if(!t.ok)throw new Error(`Load failed (HTTP ${t.status})`);return t.json()})}function K(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(n=>{if(!n.ok)throw new Error(`Save failed (HTTP ${n.status})`);return n.json()})}function q(e){return t=>fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(n=>{if(!n.ok)throw new Error(`Delete failed (HTTP ${n.status})`)})}var H=class{constructor(t,n){this._mode="view";this.activeEdit=null;this.destroyed=!1;this.pendingRescale=!1;this.originalParent=null;this.originalNextSibling=null;this.options=n,this.handlers=B(),this.img=t,this.naturalWidth=t.naturalWidth||t.width,this.naturalHeight=t.naturalHeight||t.height;let i=t.getBoundingClientRect(),o=i.width||t.width,l=i.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=n.notes.map(s=>({...s})),this.originalParent=t.parentNode,this.originalNextSibling=t.nextSibling,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 d=document.createElement("div");if(d.className="image-annotate-edit-area",this.editOverlay.appendChild(d),!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(),n.autoResize!==!1&&typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(s=>{let c=s[0];if(!c)return;let{width:r,height:a}=c.contentRect;r===0||a===0||this.rescale(r,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 n={top:t.top/this.scaleY,left:t.left/this.scaleX,width:t.width/this.scaleX,height:t.height/this.scaleY};if(!isFinite(n.top)||!isFinite(n.left)||!isFinite(n.width)||!isFinite(n.height))throw new Error("image-annotate: scale conversion produced non-finite coordinates");return n}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(){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,n){if(this.mode==="edit"){this.pendingRescale=!0;return}this.applyRescale(t,n)}applyRescale(t,n){let i=t/this.naturalWidth,o=n/this.naturalHeight;i===this.scaleX&&o===this.scaleY||(this.scaleX=i,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(n=>({...n})),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 n=t instanceof Error?t:new Error(String(t));this.reportError({type:"load",error:n})})}add(){return this.mode==="view"?(this.setMode("edit"),this.activeEdit=new D(this),!0):!1}};var R={addNote:"Add Note",save:"OK",delete:"Delete",cancel:"Cancel",placeholder:""};var Q={editable:!0,notes:[],labels:{...R}};$.fn.annotateImage=function(e){if(e==="destroy"){let l=this.data("annotateImage");return l&&(l.destroy(),this.removeData("annotateImage")),this}let t=e,n={...Q,...t,labels:{...R,...t?.labels}},i=this[0],o=new H(i,n);return this.data("annotateImage",o),this};})();
|
package/dist/react.js
CHANGED
|
@@ -36,10 +36,11 @@ var AnnotateEdit = class {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
this.area = image.editOverlay.querySelector(".image-annotate-edit-area");
|
|
39
|
-
|
|
40
|
-
this.area.style.
|
|
41
|
-
this.area.style.
|
|
42
|
-
this.area.style.
|
|
39
|
+
const rendered = image.toRendered(this.note);
|
|
40
|
+
this.area.style.height = rendered.height + "px";
|
|
41
|
+
this.area.style.width = rendered.width + "px";
|
|
42
|
+
this.area.style.left = rendered.left + "px";
|
|
43
|
+
this.area.style.top = rendered.top + "px";
|
|
43
44
|
this.form = document.createElement("div");
|
|
44
45
|
this.form.className = "image-annotate-edit-form";
|
|
45
46
|
const formEl = document.createElement("form");
|
|
@@ -126,13 +127,20 @@ var AnnotateEdit = class {
|
|
|
126
127
|
}
|
|
127
128
|
this.image.notifySave(stripInternals(this.note));
|
|
128
129
|
this.destroy();
|
|
130
|
+
this.image.flushPendingRescale();
|
|
129
131
|
};
|
|
130
132
|
const pos = readInlinePosition(this.area);
|
|
131
133
|
const size = readInlineSize(this.area);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
const natural = this.image.toNatural({
|
|
135
|
+
top: pos.top,
|
|
136
|
+
left: pos.left,
|
|
137
|
+
width: size.width,
|
|
138
|
+
height: size.height
|
|
139
|
+
});
|
|
140
|
+
this.note.top = natural.top;
|
|
141
|
+
this.note.left = natural.left;
|
|
142
|
+
this.note.width = natural.width;
|
|
143
|
+
this.note.height = natural.height;
|
|
136
144
|
this.note.text = text;
|
|
137
145
|
if (this.image.api.save) {
|
|
138
146
|
this.busy = true;
|
|
@@ -166,6 +174,7 @@ var AnnotateEdit = class {
|
|
|
166
174
|
const idx = this.image.notes.indexOf(this.note);
|
|
167
175
|
if (idx !== -1) this.image.notes.splice(idx, 1);
|
|
168
176
|
this.image.notifyDelete(stripInternals(this.note));
|
|
177
|
+
this.image.flushPendingRescale();
|
|
169
178
|
};
|
|
170
179
|
if (this.image.api.delete) {
|
|
171
180
|
this.busy = true;
|
|
@@ -241,29 +250,29 @@ var AnnotateView = class {
|
|
|
241
250
|
});
|
|
242
251
|
}
|
|
243
252
|
}
|
|
244
|
-
/** Apply the note's position and dimensions to the area element. */
|
|
253
|
+
/** Apply the note's position and dimensions to the area element, scaled to rendered size. */
|
|
245
254
|
setPosition() {
|
|
255
|
+
const rendered = this.image.toRendered(this.note);
|
|
246
256
|
const innerDiv = this.area.firstElementChild;
|
|
247
|
-
innerDiv.style.height =
|
|
248
|
-
innerDiv.style.width =
|
|
249
|
-
this.area.style.left =
|
|
250
|
-
this.area.style.top =
|
|
257
|
+
innerDiv.style.height = rendered.height + "px";
|
|
258
|
+
innerDiv.style.width = rendered.width + "px";
|
|
259
|
+
this.area.style.left = rendered.left + "px";
|
|
260
|
+
this.area.style.top = rendered.top + "px";
|
|
251
261
|
}
|
|
252
262
|
/** Update the view's position, size, and text from the edit area after a save. */
|
|
253
263
|
resetPosition(editable, text) {
|
|
254
264
|
this.tooltip.textContent = text;
|
|
255
265
|
this.tooltip.style.display = "none";
|
|
256
|
-
const
|
|
257
|
-
const areaSize = readInlineSize(editable.area);
|
|
266
|
+
const rendered = this.image.toRendered(editable.note);
|
|
258
267
|
const innerDiv = this.area.firstElementChild;
|
|
259
|
-
innerDiv.style.height =
|
|
260
|
-
innerDiv.style.width =
|
|
261
|
-
this.area.style.left =
|
|
262
|
-
this.area.style.top =
|
|
263
|
-
this.note.top =
|
|
264
|
-
this.note.left =
|
|
265
|
-
this.note.height =
|
|
266
|
-
this.note.width =
|
|
268
|
+
innerDiv.style.height = rendered.height + "px";
|
|
269
|
+
innerDiv.style.width = rendered.width + "px";
|
|
270
|
+
this.area.style.left = rendered.left + "px";
|
|
271
|
+
this.area.style.top = rendered.top + "px";
|
|
272
|
+
this.note.top = editable.note.top;
|
|
273
|
+
this.note.left = editable.note.left;
|
|
274
|
+
this.note.height = editable.note.height;
|
|
275
|
+
this.note.width = editable.note.width;
|
|
267
276
|
this.note.text = text;
|
|
268
277
|
this.note.id = editable.note.id;
|
|
269
278
|
this.editable = true;
|
|
@@ -533,15 +542,25 @@ var AnnotateImage = class {
|
|
|
533
542
|
this._mode = "view";
|
|
534
543
|
this.activeEdit = null;
|
|
535
544
|
this.destroyed = false;
|
|
545
|
+
this.pendingRescale = false;
|
|
546
|
+
this.originalParent = null;
|
|
547
|
+
this.originalNextSibling = null;
|
|
536
548
|
this.options = options;
|
|
537
549
|
this.handlers = createDefaultHandlers();
|
|
538
550
|
this.img = img;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
551
|
+
this.naturalWidth = img.naturalWidth || img.width;
|
|
552
|
+
this.naturalHeight = img.naturalHeight || img.height;
|
|
553
|
+
const rendered = img.getBoundingClientRect();
|
|
554
|
+
const renderedWidth = rendered.width || img.width;
|
|
555
|
+
const renderedHeight = rendered.height || img.height;
|
|
556
|
+
if (this.naturalWidth === 0 || this.naturalHeight === 0) {
|
|
542
557
|
throw new Error("image-annotate: image must have non-zero dimensions (is the image loaded?)");
|
|
543
558
|
}
|
|
559
|
+
this.scaleX = renderedWidth / this.naturalWidth;
|
|
560
|
+
this.scaleY = renderedHeight / this.naturalHeight;
|
|
544
561
|
this.notes = options.notes.map((n) => ({ ...n }));
|
|
562
|
+
this.originalParent = img.parentNode;
|
|
563
|
+
this.originalNextSibling = img.nextSibling;
|
|
545
564
|
this.canvas = document.createElement("div");
|
|
546
565
|
this.canvas.className = "image-annotate-canvas";
|
|
547
566
|
this.viewOverlay = document.createElement("div");
|
|
@@ -552,19 +571,13 @@ var AnnotateImage = class {
|
|
|
552
571
|
const editArea = document.createElement("div");
|
|
553
572
|
editArea.className = "image-annotate-edit-area";
|
|
554
573
|
this.editOverlay.appendChild(editArea);
|
|
555
|
-
this.canvas.appendChild(this.viewOverlay);
|
|
556
|
-
this.canvas.appendChild(this.editOverlay);
|
|
557
574
|
if (!img.parentNode) {
|
|
558
575
|
throw new Error("image-annotate: image must be in the DOM before initialization");
|
|
559
576
|
}
|
|
560
|
-
img.parentNode.insertBefore(this.canvas, img
|
|
561
|
-
this.canvas.
|
|
562
|
-
this.canvas.
|
|
563
|
-
this.canvas.
|
|
564
|
-
this.viewOverlay.style.height = height + "px";
|
|
565
|
-
this.viewOverlay.style.width = width + "px";
|
|
566
|
-
this.editOverlay.style.height = height + "px";
|
|
567
|
-
this.editOverlay.style.width = width + "px";
|
|
577
|
+
img.parentNode.insertBefore(this.canvas, img);
|
|
578
|
+
this.canvas.appendChild(img);
|
|
579
|
+
this.canvas.appendChild(this.viewOverlay);
|
|
580
|
+
this.canvas.appendChild(this.editOverlay);
|
|
568
581
|
this.api = this.options.api ? normalizeApi(this.options.api) : {};
|
|
569
582
|
if (this.api.load) {
|
|
570
583
|
this.loadFromApi();
|
|
@@ -574,7 +587,38 @@ var AnnotateImage = class {
|
|
|
574
587
|
if (this.options.editable) {
|
|
575
588
|
this.createButton();
|
|
576
589
|
}
|
|
577
|
-
|
|
590
|
+
if (options.autoResize !== false && typeof ResizeObserver !== "undefined") {
|
|
591
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
|
592
|
+
const entry = entries[0];
|
|
593
|
+
if (!entry) return;
|
|
594
|
+
const { width, height } = entry.contentRect;
|
|
595
|
+
if (width === 0 || height === 0) return;
|
|
596
|
+
this.rescale(width, height);
|
|
597
|
+
});
|
|
598
|
+
this.resizeObserver.observe(this.canvas);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
/** Convert a rect from natural image coordinates to rendered (scaled) coordinates. */
|
|
602
|
+
toRendered(rect) {
|
|
603
|
+
return {
|
|
604
|
+
top: rect.top * this.scaleY,
|
|
605
|
+
left: rect.left * this.scaleX,
|
|
606
|
+
width: rect.width * this.scaleX,
|
|
607
|
+
height: rect.height * this.scaleY
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
/** Convert a rect from rendered (scaled) coordinates to natural image coordinates. */
|
|
611
|
+
toNatural(rect) {
|
|
612
|
+
const result = {
|
|
613
|
+
top: rect.top / this.scaleY,
|
|
614
|
+
left: rect.left / this.scaleX,
|
|
615
|
+
width: rect.width / this.scaleX,
|
|
616
|
+
height: rect.height / this.scaleY
|
|
617
|
+
};
|
|
618
|
+
if (!isFinite(result.top) || !isFinite(result.left) || !isFinite(result.width) || !isFinite(result.height)) {
|
|
619
|
+
throw new Error("image-annotate: scale conversion produced non-finite coordinates");
|
|
620
|
+
}
|
|
621
|
+
return result;
|
|
578
622
|
}
|
|
579
623
|
/** Current interaction mode — 'view' for browsing, 'edit' when an annotation is being created or modified. */
|
|
580
624
|
get mode() {
|
|
@@ -646,8 +690,15 @@ var AnnotateImage = class {
|
|
|
646
690
|
if (this.button) {
|
|
647
691
|
this.button.remove();
|
|
648
692
|
}
|
|
693
|
+
if (this.resizeObserver) {
|
|
694
|
+
this.resizeObserver.disconnect();
|
|
695
|
+
this.resizeObserver = void 0;
|
|
696
|
+
}
|
|
697
|
+
if (this.originalParent && this.originalParent.isConnected) {
|
|
698
|
+
const ref = this.originalNextSibling?.parentNode === this.originalParent ? this.originalNextSibling : null;
|
|
699
|
+
this.originalParent.insertBefore(this.img, ref);
|
|
700
|
+
}
|
|
649
701
|
this.canvas.remove();
|
|
650
|
-
this.img.style.display = "";
|
|
651
702
|
}
|
|
652
703
|
/** Cancel the active edit (if any) and return to view mode. */
|
|
653
704
|
cancelEdit() {
|
|
@@ -655,6 +706,34 @@ var AnnotateImage = class {
|
|
|
655
706
|
this.activeEdit.destroy();
|
|
656
707
|
this.setMode("view");
|
|
657
708
|
}
|
|
709
|
+
this.flushPendingRescale();
|
|
710
|
+
}
|
|
711
|
+
/** Recompute scale factors, deferring if an edit is active. */
|
|
712
|
+
rescale(renderedWidth, renderedHeight) {
|
|
713
|
+
if (this.mode === "edit") {
|
|
714
|
+
this.pendingRescale = true;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
this.applyRescale(renderedWidth, renderedHeight);
|
|
718
|
+
}
|
|
719
|
+
/** Apply new scale factors and re-render all views. */
|
|
720
|
+
applyRescale(renderedWidth, renderedHeight) {
|
|
721
|
+
const newScaleX = renderedWidth / this.naturalWidth;
|
|
722
|
+
const newScaleY = renderedHeight / this.naturalHeight;
|
|
723
|
+
if (newScaleX === this.scaleX && newScaleY === this.scaleY) return;
|
|
724
|
+
this.scaleX = newScaleX;
|
|
725
|
+
this.scaleY = newScaleY;
|
|
726
|
+
this.destroyViews();
|
|
727
|
+
this.createViews();
|
|
728
|
+
}
|
|
729
|
+
/** @internal Flush any deferred rescale after an edit completes. */
|
|
730
|
+
flushPendingRescale() {
|
|
731
|
+
if (!this.pendingRescale) return;
|
|
732
|
+
this.pendingRescale = false;
|
|
733
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
734
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
735
|
+
this.applyRescale(rect.width, rect.height);
|
|
736
|
+
}
|
|
658
737
|
}
|
|
659
738
|
/** Replace all annotations with new data. Does not fire lifecycle callbacks. */
|
|
660
739
|
setNotes(notes) {
|
|
@@ -746,6 +825,7 @@ var AnnotateImage2 = forwardRef(
|
|
|
746
825
|
try {
|
|
747
826
|
const instance = new AnnotateImage(imgRef.current, {
|
|
748
827
|
editable: props.editable ?? true,
|
|
828
|
+
autoResize: props.autoResize ?? true,
|
|
749
829
|
notes: props.notes ? props.notes.slice() : [],
|
|
750
830
|
onChange: (notes) => onChangeRef.current?.(notes),
|
|
751
831
|
onSave: (note) => onSaveRef.current?.(note),
|
|
@@ -786,7 +866,7 @@ var AnnotateImage2 = forwardRef(
|
|
|
786
866
|
return instanceRef.current?.getNotes() ?? [];
|
|
787
867
|
}
|
|
788
868
|
}));
|
|
789
|
-
return /* @__PURE__ */ jsx("img", { ref: imgRef, src: props.src, width: props.width, height: props.height, alt: props.alt });
|
|
869
|
+
return /* @__PURE__ */ jsx("span", { style: { display: "contents" }, children: /* @__PURE__ */ jsx("img", { ref: imgRef, src: props.src, width: props.width, height: props.height, alt: props.alt }) });
|
|
790
870
|
}
|
|
791
871
|
);
|
|
792
872
|
export {
|
|
@@ -24,6 +24,42 @@ export declare class AnnotateImage {
|
|
|
24
24
|
handlers: InteractionHandlers;
|
|
25
25
|
activeEdit: AnnotateEdit | null;
|
|
26
26
|
private destroyed;
|
|
27
|
+
private pendingRescale;
|
|
28
|
+
private resizeObserver?;
|
|
29
|
+
private originalParent;
|
|
30
|
+
private originalNextSibling;
|
|
31
|
+
/** Natural (intrinsic) image width. */
|
|
32
|
+
readonly naturalWidth: number;
|
|
33
|
+
/** Natural (intrinsic) image height. */
|
|
34
|
+
readonly naturalHeight: number;
|
|
35
|
+
/** Current horizontal scale factor (rendered / natural). */
|
|
36
|
+
scaleX: number;
|
|
37
|
+
/** Current vertical scale factor (rendered / natural). */
|
|
38
|
+
scaleY: number;
|
|
39
|
+
/** Convert a rect from natural image coordinates to rendered (scaled) coordinates. */
|
|
40
|
+
toRendered(rect: {
|
|
41
|
+
top: number;
|
|
42
|
+
left: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
}): {
|
|
46
|
+
top: number;
|
|
47
|
+
left: number;
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
};
|
|
51
|
+
/** Convert a rect from rendered (scaled) coordinates to natural image coordinates. */
|
|
52
|
+
toNatural(rect: {
|
|
53
|
+
top: number;
|
|
54
|
+
left: number;
|
|
55
|
+
width: number;
|
|
56
|
+
height: number;
|
|
57
|
+
}): {
|
|
58
|
+
top: number;
|
|
59
|
+
left: number;
|
|
60
|
+
width: number;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
27
63
|
/**
|
|
28
64
|
* @param img - Image element to annotate. Must be in the DOM with non-zero dimensions.
|
|
29
65
|
* @param options - Plugin configuration.
|
|
@@ -53,6 +89,12 @@ export declare class AnnotateImage {
|
|
|
53
89
|
destroy(): void;
|
|
54
90
|
/** Cancel the active edit (if any) and return to view mode. */
|
|
55
91
|
cancelEdit(): void;
|
|
92
|
+
/** Recompute scale factors, deferring if an edit is active. */
|
|
93
|
+
private rescale;
|
|
94
|
+
/** Apply new scale factors and re-render all views. */
|
|
95
|
+
private applyRescale;
|
|
96
|
+
/** @internal Flush any deferred rescale after an edit completes. */
|
|
97
|
+
flushPendingRescale(): void;
|
|
56
98
|
/** Replace all annotations with new data. Does not fire lifecycle callbacks. */
|
|
57
99
|
setNotes(notes: AnnotationNote[]): void;
|
|
58
100
|
/** Toggle editing mode. Creates or removes Add Note button and rebuilds views. Does not fire lifecycle callbacks. */
|
|
@@ -25,7 +25,7 @@ export declare class AnnotateView {
|
|
|
25
25
|
* @param note - Annotation data to display.
|
|
26
26
|
*/
|
|
27
27
|
constructor(image: AnnotateImage, note: AnnotationNote);
|
|
28
|
-
/** Apply the note's position and dimensions to the area element. */
|
|
28
|
+
/** Apply the note's position and dimensions to the area element, scaled to rendered size. */
|
|
29
29
|
setPosition(): void;
|
|
30
30
|
/** Update the view's position, size, and text from the edit area after a save. */
|
|
31
31
|
resetPosition(editable: {
|
package/dist/types/react.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface AnnotateImageProps {
|
|
|
23
23
|
onLoad?: (notes: NoteData[]) => void;
|
|
24
24
|
/** Called when an operation fails. */
|
|
25
25
|
onError?: (context: AnnotateErrorContext) => void;
|
|
26
|
+
/** Enable automatic re-scaling when the container resizes. Default: true. */
|
|
27
|
+
autoResize?: boolean;
|
|
26
28
|
}
|
|
27
29
|
/** Imperative methods exposed via ref. */
|
|
28
30
|
export interface AnnotateImageRef {
|
package/dist/types/types.d.ts
CHANGED
|
@@ -84,6 +84,8 @@ export interface AnnotateImageOptions {
|
|
|
84
84
|
onLoad?: (notes: NoteData[]) => void;
|
|
85
85
|
/** UI label overrides. Missing fields use built-in defaults. */
|
|
86
86
|
labels?: Labels;
|
|
87
|
+
/** Attach a ResizeObserver to rescale annotations when the image resizes. Default: true. */
|
|
88
|
+
autoResize?: boolean;
|
|
87
89
|
}
|
|
88
90
|
export interface DragCallbacks {
|
|
89
91
|
containment?: HTMLElement;
|
package/dist/types/vue.d.ts
CHANGED
|
@@ -33,6 +33,11 @@ export declare const AnnotateImage: import("vue").DefineComponent<import("vue").
|
|
|
33
33
|
type: BooleanConstructor;
|
|
34
34
|
default: boolean;
|
|
35
35
|
};
|
|
36
|
+
/** Enable automatic re-scaling when the container resizes. Default: true. */
|
|
37
|
+
autoResize: {
|
|
38
|
+
type: BooleanConstructor;
|
|
39
|
+
default: boolean;
|
|
40
|
+
};
|
|
36
41
|
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
37
42
|
[key: string]: any;
|
|
38
43
|
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
@@ -68,6 +73,11 @@ export declare const AnnotateImage: import("vue").DefineComponent<import("vue").
|
|
|
68
73
|
type: BooleanConstructor;
|
|
69
74
|
default: boolean;
|
|
70
75
|
};
|
|
76
|
+
/** Enable automatic re-scaling when the container resizes. Default: true. */
|
|
77
|
+
autoResize: {
|
|
78
|
+
type: BooleanConstructor;
|
|
79
|
+
default: boolean;
|
|
80
|
+
};
|
|
71
81
|
}>> & Readonly<{
|
|
72
82
|
onChange?: ((_notes: NoteData[]) => any) | undefined;
|
|
73
83
|
onError?: ((_context: AnnotateErrorContext) => any) | undefined;
|
|
@@ -76,4 +86,5 @@ export declare const AnnotateImage: import("vue").DefineComponent<import("vue").
|
|
|
76
86
|
onDelete?: ((_note: NoteData) => any) | undefined;
|
|
77
87
|
}>, {
|
|
78
88
|
editable: boolean;
|
|
89
|
+
autoResize: boolean;
|
|
79
90
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|