UNPKG

lost-sia

Version:

Single Image Annotation Tool

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