annotate-image 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +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};})();