UNPKG

lost-sia

Version:

Single Image Annotation Tool

2 lines (1 loc) 9.56 kB
import{jsxs as W,jsx as x,Fragment as Qe}from"react/jsx-runtime";import{useState as E,useRef as Z,useEffect as M}from"react";import w from"../models/AnnotationTool.js";import i from"../models/EditorModes.js";import Ze from"../utils/KeyMapper.js";import a from"../models/KeyAction.js";import me from"../Annotation/logic/Annotation.js";import qe from"../models/CanvasAction.js";import et from"../Annotation/ui/AnnotationComponent.js";import pe from"../utils/mouse.js";import N from"../models/AnnotationMode.js";import tt from"./LabelInput.js";import{FontAwesomeIcon as nt}from"@fortawesome/react-fontawesome";import{faBan as ot}from"@fortawesome/free-solid-svg-icons";import D from"../models/AnnotationStatus.js";import C from"../utils/transform.js";import rt from"../models/NotificationType.js";import st from"../utils/TimeUtils.js";import xe from"../utils/windowViewport.js";const wt=({annotations:O=[],annotationSettings:B,defaultLabelId:q,image:ee,isFullscreen:Ce=!1,isImageJunk:K=!1,isPolygonSelectionMode:F=!1,polygonOperationResult:X={annotationsToDelete:[],polygonsToCreate:[]},possibleLabels:te,preventScrolling:ne=!0,selectedAnnotation:r,selectedAnnoTool:R,toolbarHeight:U=0,uiConfig:z,onAnnoCreated:Oe,onAnnoCreationFinished:oe,onAnnoChanged:re,onAnnoEditing:Te=g=>{},onNotification:se=g=>{},onRequestNewAnnoId:k,onSelectAnnotation:A,onSetIsImageJunk:ve,onSetSelectedTool:Ae=g=>{},onShouldDeleteAnno:ie})=>{const[g,T]=E(i.VIEW),[Me,Ie]=E(),[ce,we]=E(q),[V,De]=E({x:-1,y:-1}),[ae,de]=E(0),L={x:V.x,y:V.y},[u,Y]=E({x:-1,y:-1}),[l,G]=E({x:-1,y:-1}),[h,le]=E({x:-1,y:-1}),[d,P]=E(1),[c,S]=E({x:0,y:0}),H={x:c.x+ae,y:c.y},[m,$]=E(),[j,_]=E(!1),fe=Z(null),p=Z(null),y=Z(null),v=((e,t)=>{if(e.x===0||e.y===0||t.x===0||t.y===0)return 0;const n=t.x/e.x,o=t.y/e.y;return Math.min(n,o)})(u,l),Se=()=>{if((y==null?void 0:y.current)===null)return{x:0,y:0};const e=u.x*v;if(z.imageCentered&&l.x>e){const f=(l.x-e)/2;de(f)}else de(0);const{top:t,left:n}=p.current.getBoundingClientRect(),o={x:n+window.scrollX,y:t+window.scrollY};De(o)},_e=new Ze(e=>Pe(e)),be=e=>{T(i.CREATE);const t=C.convertStageCoordinatesToPercentaged([e],v,u);R===w.BBox&&t.push(t[0]);const n=k(),o=new me(n,R,t);if(Ie(performance.now()),ce!==void 0&&(o.labelIds=[ce]),Oe(o),R===w.Point){const s={...o,coordinates:[e],annoTime:0};Q(s)}},Ne=()=>{if(r&&![w.Line,w.Polygon].includes(r.type))return;const e=O.find(n=>n.internalId===(r==null?void 0:r.internalId));if(e===void 0)return;T(i.CREATE),Ae(e.type);const t={...e,mode:N.CREATE,status:D.CREATING,internalId:k(),selectedNode:e.coordinates.length-1};Te(t)},Re=()=>{const e=r?r.internalId:0,t=O.find(n=>n.internalId>e);if(t)return A(t);if(O.length>0)return A(O[0])},ke=()=>{const e=r?r.internalId:0,t=[...O];t.sort((o,s)=>s.internalId-o.internalId);const n=t.find(o=>o.internalId<e);if(n)return A(n);if(O.length>0)return A(O[O.length-1])},Ve=()=>{if(r){const e=JSON.stringify(r);localStorage.setItem("lostAnnotationClipboard",e);const t={title:"Success",message:"Annotation copied",type:rt.SUCCESS};se(t)}},Le=()=>{const e=localStorage.getItem("lostAnnotationClipboard");if(e==null)return;const t=JSON.parse(e);t.internalId=k(),t.externalId="",oe(t,!0),A(t)},Pe=e=>{switch(e){case a.EDIT_LABEL:r&&_(!0);break;case a.DELETE_ANNO:r&&ie(r.internalId);break;case a.DELETE_ANNO_IN_CREATION:g===i.CREATE&&(ie(r.internalId),T(i.VIEW));break;case a.ENTER_ANNO_ADD_MODE:console.log("KeyAction TODO: ENTER_ANNO_ADD_MODE");break;case a.LEAVE_ANNO_ADD_MODE:console.log("KeyAction TODO: LEAVE_ANNO_ADD_MODE");break;case a.UNDO:console.log("KeyAction TODO: UNDO");break;case a.REDO:console.log("KeyAction TODO: REDO");break;case a.TRAVERSE_ANNOS:Re();break;case a.TRAVERSE_ANNOS_BACKWARDS:ke();break;case a.CAM_MOVE_LEFT:b(20*d,0);break;case a.CAM_MOVE_RIGHT:b(-20*d,0);break;case a.CAM_MOVE_UP:b(0,20*d);break;case a.CAM_MOVE_DOWN:b(0,-20*d);break;case a.CAM_MOVE_STOP:console.log("KeyAction TODO: CAM_MOVE_STOP");break;case a.COPY_ANNOTATION:Ve();break;case a.PASTE_ANNOTATION:Le();break;case a.RECREATE_ANNO:console.log("KeyAction TODO: RECREATE_ANNO"),Ne();break;case a.TOGGLE_IMAGE_JUNK:if(g===i.ADD||g===i.CREATE)return;ve(!K);break;default:console.log("Unknown KeyAction",e);break}},b=(e,t)=>{let n=c.x+e/d,o=c.y+t/d;const s=l.x*.45,f=l.x*.55,I=l.y*.45,je=l.y*.55,Je={x:0,y:0},Ee=xe.getViewportCoordinates(c,l,d,Je),he=xe.getViewportCoordinates(c,l,d,l);Ee.vX>=s?n=c.x-5:he.vX<=f?n=c.x+5:Ee.vY>=I?o=c.y-5:he.vY<=je&&(o=c.y+5),S({x:n,y:o})},J=(e=>h.x<=0||h.y<=0||u.x<=0||u.y<=0?[]:O.map(n=>({...n,coordinates:C.convertPercentagedCoordinatesToStage(n.coordinates,u,h)})))(),We=()=>{if(T(i.VIEW),le({x:-1,y:-1}),y.current!==null){const{width:e,height:t}=y.current.getBoundingClientRect();Y({x:e,y:t})}P(1),S({x:0,y:0}),$(void 0),_(!1)};M(()=>{var e;(e=fe.current)==null||e.focus()},[]),M(()=>{if((p==null?void 0:p.current)!==void 0){const{width:e,height:t}=p.current.getBoundingClientRect(),n=t-U;G({x:e,y:n});const o=new ResizeObserver(()=>{const{width:s,height:f}=p.current.getBoundingClientRect(),I=f-U;G({x:s,y:I})});return o.observe(p.current),()=>o.disconnect()}We()},[ee,Ce]),M(()=>{Se()},[y,c,l]),M(()=>{if(p.current===null)return;const{width:e,height:t}=p.current.getBoundingClientRect(),n=t-U;G({x:e,y:n})},[p]),M(()=>{if(y.current===null)return;const{width:e,height:t}=y.current.getBoundingClientRect();Y({x:e,y:t});const n=new ResizeObserver(()=>{const{width:o,height:s}=y.current.getBoundingClientRect();Y({x:o,y:s})});return n.observe(y.current),()=>n.disconnect()},[y]),M(()=>{if(v===0)return;const e={x:u.x*v,y:u.y*v};le(e)},[v,u]),M(()=>{F&&X.polygonsToCreate!==void 0&&X.polygonsToCreate.forEach(e=>{const t=k(),n=new me(t,e.type,C.convertPercentagedCoordinatesToStage(e.coordinates,u,h),N.VIEW,D.CREATED);Q(n)})},[X]);const Q=e=>{T(i.VIEW);const t={...e,mode:N.VIEW};if(e.type!==w.Point){const s=st.getRoundedDuration(Me,performance.now());t.annoTime=s}const n=C.convertStageCoordinatesToPercentaged(e.coordinates,v,u);t.coordinates=n,re(t);const o=R===w.Point||F;oe(t,o)},Be=e=>{e.preventDefault(),_e.keyDown(e.key,e.shiftKey,e.ctrlKey)},Ke=e=>{e.preventDefault()},Fe=e=>{if(e.button!==0){if(e.button===1)T(i.CAMERA_MOVE);else if(e.button===2){if(!B.canCreate||g===i.ADD||g===i.CREATE)return;const t=pe.getAntiScaledMouseStagePosition(e,L,d,c),n={x:t.x-ae,y:t.y};be(n)}}},Xe=()=>{ne&&(document.body.style.overflow="hidden")},Ue=e=>{switch(e.button){case 1:T(i.VIEW);break}},ue=(e,t)=>{g===i.CAMERA_MOVE&&b(e,t)},ze=()=>{ne&&(document.body.style.overflow="")},Ye=e=>{const o=(e.deltaY<0?1:-1)>0?d*1.25:d/1.25,s=pe.getAntiScaledMouseStagePosition(e,L,d,c),f=d/o,I={x:f*(s.x+c.x)-s.x,y:f*(s.y+c.y)-s.y};o<1?(P(1),(c.x!=0||c.y!=0)&&S({x:0,y:0})):o>200?(P(200),S(I)):(P(o),S(I))},Ge=(e,t)=>{if(t!==qe.ANNO_SELECTED){console.log("Unknown Canvas Action:",t);return}const n={...e,coordinates:C.convertStageCoordinatesToPercentaged([...e.coordinates],v,u)};A(n);const o=C.getMostLeftPoints(e.coordinates),s=C.getTopPoint(o)[0],f=C.convertStageToPage(s,L,d,c);$(f)},ge=e=>{const t=C.convertStageCoordinatesToPercentaged(e.coordinates,v,u),n={...e,coordinates:t};n.status===D.LOADED&&(n.status=D.CHANGED),re(n)},He=()=>{if(g===i.CAMERA_MOVE)return x(Qe,{});const t=[i.CREATE,i.ADD,i.MOVE].includes(g),n=J.map(o=>{const s=o.internalId===(r==null?void 0:r.internalId);return t&&!s?x("g",{},`annotationComponent_${o.internalId}`):x(et,{scaledAnnotation:o,annotationSettings:B,possibleLabels:te,svgScale:d,svgTranslation:H,pageToStageOffset:L,nodeRadius:z.nodeRadius,strokeWidth:z.strokeWidth,isSelected:s,isDisabled:F&&s,onFinishAnnoCreate:Q,onLabelIconClicked:()=>_(!0),onAction:Ge,onAnnoChanged:ge,onAnnotationModeChange:f=>{f===N.MOVE&&T(i.MOVE),g===i.MOVE&&f===N.VIEW&&T(i.VIEW)},onNotification:se},`annotationComponent_${o.internalId}`)});if(r){const o=J.find(f=>f.internalId===(r==null?void 0:r.internalId)),s=J.indexOf(o);n.push(n.splice(s,1)[0])}return x("g",{children:n})},$e=()=>x("circle",{cx:h.x/2,cy:h.y/2,r:"100%",style:{opacity:0},onContextMenu:e=>e.preventDefault(),onClick:()=>{_(!1)}}),ye={x:V.x+l.x/2,y:V.y+l.y/2};return W("div",{ref:p,style:{width:"100%",height:"100%"},children:[x("div",{style:{position:"absolute",left:(m==null?void 0:m.x)!==void 0?m.x:0,top:(m==null?void 0:m.y)!==void 0?m.y:0,display:(m==null?void 0:m.y)!==void 0?"inherit":"none",zIndex:j?7e3:-1},children:x(tt,{defaultLabelId:q,isVisible:j,selectedLabelsIds:r==null?void 0:r.labelIds,possibleLabels:te,isMultilabel:B.canHaveMultipleLabels,onLabelSelect:e=>{if(_(!1),e.length>0){const o=e.filter(s=>!r.labelIds.includes(s));o.length>0&&we(o[0])}const t=r.status===D.LOADED?D.CHANGED:r.status,n={...r,coordinates:C.convertPercentagedCoordinatesToStage(r.coordinates,u,h),labelIds:[...e],status:t};ge(n)}})}),K&&W("div",{style:{position:"absolute",left:ye.x,top:ye.y,transform:"translate(-50%, -50%)",textAlign:"center",color:"white"},children:[x(nt,{icon:ot,size:"5x",style:{marginBottom:15}}),x("h2",{children:"Marked as Junk"})]}),W("svg",{ref:fe,width:"100%",height:"100%",onKeyDown:Be,onKeyUp:Ke,onMouseMove:e=>ue(e.movementX,e.movementY),tabIndex:0,onMouseDown:e=>Fe(e),children:[W("g",{transform:`scale(${d}) translate(${H.x}, ${H.y})`,onMouseOver:Xe,onMouseLeave:ze,onMouseUp:Ue,onWheel:Ye,onMouseMove:e=>ue(e.movementX,e.movementY),onClick:()=>{A(void 0)},children:[x("image",{onContextMenu:e=>e.preventDefault(),href:ee,ref:y,width:h.x>0?h.x:void 0,height:h.y>0?h.y:void 0}),He()]}),j&&$e(),K&&x("rect",{x:"0",y:"0",width:l.x,height:l.y,style:{opacity:.8},onContextMenu:e=>e.preventDefault(),onClick:()=>{$(void 0)}})]})]})};export{wt as default};