UNPKG

lost-sia

Version:

Single Image Annotation Tool

2 lines (1 loc) 30.5 kB
import{jsx as h,jsxs as A}from"react/jsx-runtime";import E,{Component as Y}from"react";import{uniqueId as B}from"lodash-es";import J from"./Annotation/Annotation.js";import W from"./AnnoLabelInput.js";import F from"./AnnoToolBar.js";import $ from"./ImgBar.js";import Z from"./LabelInput.js";import j from"./Prompt.js";import{Button as q,Icon as D,Dimmer as O,Loader as Q,Header as tt}from"semantic-ui-react";import{DATABASE as w,NEW as g,DELETED as C,CHANGED as y}from"./types/annoStatus.js";import{IMG_JUNK_UPDATE as et,CANVAS_IMG_LOADED as st,ANNO_COMMENT_UPDATE as _,ANNO_CREATED_FINAL_NODE as it,ANNO_CREATED_NODE as U,ANNO_LABEL_UPDATE as R,ANNO_DELETED as L,ANNO_EDITED as nt,ANNO_REMOVED_SPECIFIC_NODE as at,ANNO_REMOVED_NODE as ot,ANNO_ADDED_NODE as ht,ANNO_ENTER_EDIT_MODE as lt,ANNO_ENTER_MOVE_MODE as rt,ANNO_MOVED as dt,ANNO_CREATED as V,ANNO_START_CREATING as pt,ANNO_SELECTED as gt,ANNO_MARK_EXAMPLE as P,ANNO_ENTER_CREATE_MODE as T,CANVAS_IMGBAR_CLOSE as mt,IMG_LABEL_UPDATE as N,CANVAS_LABEL_INPUT_CLOSE as ct,IMG_ANNO_TIME_UPDATE as ut,CANVAS_SVG_UPDATE as ft,CANVAS_UI_CONFIG_UPDATE as At}from"./types/canvasActions.js";import{VIEW as l,CAMERA_MOVE as v,ADD as k,DELETED as m,CREATE as c,EDIT as vt,MOVE as bt,EDIT_LABEL as St}from"./types/modes.js";import{POSITIVE_POINT as M,NEGATIVE_POINT as x,SAM_BBOX as b,BBOX as It,POINT as Et}from"./types/tools.js";import{fixBackendAnnos as H,canvasToBackendAnnos as X,canvasToBackendSingleAnno as Lt,backendAnnosToCanvas as Mt}from"./utils/annoConversion.js";import{getColor as wt,getDefaultColor as Ct}from"./utils/colorlut.js";import yt from"./utils/hist.js";import Tt,{RECREATE_ANNO as Nt,PASTE_ANNOTATION as kt,COPY_ANNOTATION as xt,CAM_MOVE_STOP as Bt,CAM_MOVE_DOWN as Dt,CAM_MOVE_UP as Ot,CAM_MOVE_RIGHT as _t,CAM_MOVE_LEFT as Ut,TRAVERSE_ANNOS as Rt,REDO as Vt,UNDO as Pt,LEAVE_ANNO_ADD_MODE as Ht,ENTER_ANNO_ADD_MODE as Xt,DELETE_ANNO_IN_CREATION as Gt,TOGGLE_ANNO_COMMENT_INPUT as Kt,DELETE_ANNO as zt,EDIT_LABEL as Yt}from"./utils/keyActions.js";import{getMousePositionAbs as Jt}from"./utils/mouse.js";import{correctAnnotation as G,getArea as Wt}from"./utils/transform.js";import{getZoomTranslation as K,getViewportCoordinates as z}from"./utils/windowViewport.js";import Ft from"./InfoBoxes/InfoBoxArea.js";/* empty css */class be extends Y{constructor(t){super(t),this.state={svg:{width:"100%",height:"100%",scale:1,translateX:0,translateY:0},image:{width:void 0,height:void 0},imageOffset:{x:0,y:0},annos:[],mode:l,selectedAnnoId:void 0,showSingleAnno:void 0,showLabelInput:!1,imageLoaded:!1,imgLoadCount:0,imgLabelIds:[],imgLabelChanged:!1,imgAnnoTime:0,imgLoadTimestamp:0,performedImageInit:!1,prevLabel:[],imageBlob:void 0,isJunk:t.isJunk,imgBarVisible:!1,annoToolBarVisible:!1,possibleLabels:void 0,annoCommentInputTrigger:0,imgActions:[],isDrawingSamBBox:!1,samBBoxStartPoint:null},this.img=E.createRef(),this.svg=E.createRef(),this.container=E.createRef(),this.hist=new yt,this.keyMapper=new Tt(e=>this.handleKeyAction(e)),this.mousePosAbs=void 0,this.clipboard=void 0,this.delayedBackendUpdates={},this.tempIdMap={}}componentDidMount(){this.updatePossibleLabels(),Number.isInteger(this.props.defaultLabel)&&this.setState({prevLabel:[this.props.defaultLabel]}),this.props.onGetFunction&&this.props.onGetFunction({deleteAllAnnos:()=>this.deleteAllAnnos(),unloadImage:()=>this.unloadImage(),resetZoom:()=>this.resetZoom(),getAnnos:(t,e)=>this.getAnnos(t,e)})}componentDidUpdate(t,e){t.annoSaveResponse!==this.props.annoSaveResponse&&this.updateAnnoBySaveResponse(this.props.annoSaveResponse),t.imageMeta!==this.props.imageMeta&&this.props.imageMeta&&this.setState({imgLabelIds:this.props.imageMeta.labelIds,imgAnnoTime:this.props.imageMeta.annoTime,imgActions:this.props.imageMeta.imgActions?this.props.imageMeta.imgActions:[],imgLoadTimestamp:performance.now()}),t.annos!==this.props.annos&&this.state.imageBlob&&this.updateCanvasView(H(this.props.annos)),t.isJunk!==this.props.isJunk&&this.state.isJunk!==this.props.isJunk&&(this.setState({isJunk:this.props.isJunk}),this.state.imageLoaded&&!this.props.isImageChanging&&this.handleAnnoSaveEvent(et,void 0,{isJunk:this.props.isJunk})),this.state.imageBlob!==this.props.imageBlob&&this.setState({imageBlob:this.props.imageBlob}),this.props.possibleLabels!==t.possibleLabels&&this.updatePossibleLabels(),this.state.performedImageInit&&(this.setState({performedImageInit:!1,annoToolBarVisible:!1}),this.props.uiConfig.imgBarVisible&&this.setState({imgBarVisible:!0}),this.hist.clearHist(),this.hist.push({...this.getAnnos(),selectedAnnoId:void 0},"init")),this.state.imageLoaded&&(this.putSelectedOnTop(e),e.imgLoadCount!==this.state.imgLoadCount&&(this.updateCanvasView(H(this.props.annos)),this.props.imageMeta&&(this.setImageLabels(this.props.imageMeta.labelIds),this.setState({performedImageInit:!0}))),t.layoutUpdate!==this.props.layoutUpdate&&(this.selectAnnotation(void 0),this.updateCanvasView(X(this.state.annos,this.state.svg,!1,this.state.imageOffset))))}onImageLoad(){this.setState({imageLoaded:!0,imgLoadCount:this.state.imgLoadCount+1,showLabelInput:!1,showSingleAnno:void 0,selectedAnnoId:void 0}),this.triggerCanvasEvent(st)}onMouseOver(){this.svg.current.focus(),this.props.preventScrolling&&(document.body.style.overflow="hidden")}onMouseLeave(){this.props.preventScrolling&&(document.body.style.overflow="")}onWheel(t){const e=t.deltaY<0,s=this.getMousePosition(t),i=1.25;let n;e?n=this.state.svg.scale*i:n=this.state.svg.scale/i;let a;return n<1?(n=1,a={x:0,y:0}):n>200?(n=200,a=K(s,this.state.svg,n)):a=K(s,this.state.svg,n),this.setState({svg:{...this.state.svg,scale:n,translateX:a.x,translateY:a.y}}),!1}onRightClick(t){t.preventDefault()}onMouseDown(t){if(t.button===0)this.selectAnnotation(void 0);else if(t.button===1)this.setMode(v);else if(t.button===2){if(this.props.selectedTool===M||this.props.selectedTool===x||this.props.selectedTool===b)return;this.createNewAnnotation(t)}}onAnnoMouseDown(t){if(t.button===1)this.setMode(v);else if(t.button===2){if(this.props.selectedTool===M||this.props.selectedTool===x||this.props.selectedTool===b)return;this.createNewAnnotation(t)}else if(t.button===0&&this.state.showLabelInput){const e=this.findAnno(this.state.selectedAnnoId);this.updateSelectedAnno(e,l),this.showSingleAnno(void 0),this.showLabelInput(!1)}}onMouseUp(t){switch(t.button){case 1:this.setMode(l);break}}updateAnnoComment(t){const e=this.findAnno(this.state.selectedAnnoId);e.comment=t,this.handleAnnoEvent(e,_)}handleKeyAction(t){const e=this.findAnno(this.state.selectedAnnoId),s=20*this.state.svg.scale;switch(console.log("handleKeyAction",t,e),t){case Yt:const i=this.findAnnoRef(this.state.selectedAnnoId);let n;i!==void 0&&(n=i.current.myAnno.current.getResult()),this.editAnnoLabel(n);break;case zt:this.deleteAnnotation(e);break;case Kt:this.state.selectedAnnoId&&this.setState({annoCommentInputTrigger:this.state.annoCommentInputTrigger+1});break;case Gt:this.deleteAnnoInCreationMode(e);break;case Xt:e&&this.updateSelectedAnno(e,k);break;case Ht:e&&this.updateSelectedAnno(e,l);break;case Pt:this.undo();break;case Vt:this.redo();break;case Rt:this.traverseAnnos();break;case Ut:this.moveCamera(s,0);break;case _t:this.moveCamera(-s,0);break;case Ot:this.moveCamera(0,s);break;case Dt:this.moveCamera(0,-s);break;case Bt:break;case xt:this.copyAnnotation();break;case kt:this.pasteAnnotation(0);break;case Nt:this.state.selectedAnnoId&&this.recreateAnnotation(this.state.selectedAnnoId);break}}onKeyDown(t){t.preventDefault(),this.keyMapper.keyDown(t.key),this.props.onKeyDown&&this.props.onKeyDown(t)}onKeyUp(t){t.preventDefault(),this.keyMapper.keyUp(t.key),this.props.onKeyUp&&this.props.onKeyUp(t)}onMouseMove(t){this.state.mode===v&&this.moveCamera(t.movementX,t.movementY)}onLabelInputDeleteClick(t){this.removeSelectedAnno()}triggerCanvasEvent(t,e){this.props.onCanvasEvent&&this.props.onCanvasEvent(t,e)}checkAndCorrectAnno(t){const e=G(t.data,this.state.svg,this.state.imageOffset);let s={...t,data:e};const i=Wt(e,this.state.svg,t.type,this.state.image);return i!==void 0&&i<this.props.canvasConfig.annos.minArea&&(this.handleNotification({title:"Annotation to small",message:"Annotation area was "+Math.round(i)+"px but needs to be bigger than "+this.props.canvasConfig.annos.minArea+" px",type:void 0}),s={...s,mode:m}),this.checkAnnoLength(t)||(s={...s,mode:m}),s}handleAnnoEvent(t,e){let s,i;switch(console.log("canvasActions: ",t,e),e){case T:break;case P:s=this.updateSelectedAnno(t,l),this.pushHist(s,t.id,e,this.state.showSingleAnno),this.handleAnnoSaveEvent(e,t);break;case gt:this.selectAnnotation(t.id);break;case pt:s=this.updateSelectedAnno(t),this.pushHist(s,t.id,e,this.state.showSingleAnno);break;case V:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),s=this.updateSelectedAnno({...t,status:w},l),this.pushHist(s,t.id,e,void 0),this.showSingleAnno(void 0),this.setState({annoToolBarVisible:!0}),this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case dt:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),s=this.updateSelectedAnno(t,l),this.showSingleAnno(void 0),this.pushHist(s,t.id,e,void 0),this.setState({annoToolBarVisible:!0}),this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case rt:t=this.startAnnotimeMeasure(t),this.updateSelectedAnno(t,bt),this.showSingleAnno(t.id),this.setState({annoToolBarVisible:!1});break;case lt:t=this.startAnnotimeMeasure(t),this.updateSelectedAnno(t,vt),this.setState({annoToolBarVisible:!1});break;case ht:i=[...this.state.imgActions,e],s=this.updateSelectedAnno(t,k),this.pushHist(s,t.id,e,this.state.showSingleAnno),this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case ot:i=[...this.state.imgActions,e],this.checkAnnoLength(t)?s=this.updateSelectedAnno(t,c):(s=this.updateSelectedAnno(t,m),this.showSingleAnno(void 0)),this.pushHist(s,t.id,e,this.state.showSingleAnno),t.status!==g&&this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case at:i=[...this.state.imgActions,e],this.checkAnnoLength(t)?s=this.updateSelectedAnno(t,k):(s=this.updateSelectedAnno(t,m),this.showSingleAnno(void 0)),this.pushHist(s,t.id,e,this.state.showSingleAnno),t.status!==g&&this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case nt:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),s=this.updateSelectedAnno(t,l),this.pushHist(s,t.id,e,this.state.showSingleAnno),this.setState({annoToolBarVisible:!0}),this.handleAnnoSaveEvent(e,t,{imgActions:i});break;case L:i=[...this.state.imgActions,e];const n=this.updateSelectedAnno(t,m,!0);s=n.newAnnos,this.selectAnnotation(void 0),this.showSingleAnno(void 0),this.pushHist(s,void 0,e,this.state.showSingleAnno),this.handleAnnoSaveEvent(e,n.newAnno,{imgActions:i});break;case _:i=[...this.state.imgActions,e];const a=this.updateSelectedAnno(t,l,!0);s=a.newAnnos,this.pushHist(s,t.id,e,this.state.showSingleAnno),this.handleNotification({title:"Saved comment",message:`Saved comment: ${t.comment}`,type:void 0}),this.handleAnnoSaveEvent(e,a.newAnno,{imgActions:i});break;case R:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),t=this.checkAndCorrectAnno(t),t.mode===m?this.updateSelectedAnno(t,m):this.updateSelectedAnno({...t,status:w},l),this.setState({annoToolBarVisible:!0}),t.mode!==m&&(this.pushHist(s,t.id,e,void 0),this.handleAnnoSaveEvent(e,t,{imgActions:i}));break;case U:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),s=this.updateSelectedAnno(t,c),this.pushHist(s,t.id,e,this.state.showSingleAnno);break;case it:i=[...this.state.imgActions,e],t=this.stopAnnotimeMeasure(t),s=this.updateSelectedAnno({...t,status:w},l),this.pushHist(s,t.id,e,void 0),this.showSingleAnno(void 0),this.setState({annoToolBarVisible:!0}),this.handleAnnoSaveEvent(e,t,{imgActions:i});break}i&&this.setState({imgActions:i}),this.props.onAnnoEvent&&this.props.onAnnoEvent(t,s,e)}handleAnnoSaveEvent(t,e,s){const i={...s,imgId:this.props.imageMeta.id,annoTime:this.props.imageMeta.annoTime+(performance.now()-this.state.imgLoadTimestamp)/1e3};let n;if(e){let o=this.addDelayedBackendUpdate(e,t);if(!o)return;o.id in this.tempIdMap&&(o={...o,id:this.tempIdMap[o.id]}),n=Lt(o,this.state.svg,!1,this.state.imageOffset)}const a={anno:n,img:i,action:t};this.props.onAnnoSaveEvent&&this.props.onAnnoSaveEvent(a)}onAnnoLabelInputUpdate(t){this.updateSelectedAnno(t)}onAnnoLabelInputClose(){this.svg.current.focus(),this.showLabelInput(!1),this.showSingleAnno(void 0);const t=this.findAnno(this.state.selectedAnnoId);this.handleAnnoEvent(t,R)}handleImgBarClose(){this.triggerCanvasEvent(mt)}gotNewLabel(t){let e=!1;return t.length===0?this.state.imgLabelIds.length!==0:(t.forEach(s=>{this.state.imgLabelIds.includes(s)||(e=!0)}),e)}handleImgLabelUpdate(t){if(this.gotNewLabel(t)){const e=[...this.state.imgActions,N];this.setState({imgLabelIds:t,imgLabelChanged:!0,imgActions:e}),this.pushHist(this.state.annos,this.state.selectedAnnoId,N,this.state.showSingleAnno,t);const s={imgLabelIds:t,imgLabelChanged:!0,imgActions:e};this.handleAnnoSaveEvent(N,void 0,s)}}handleCanvasClick(t){this.props.uiConfig.imgBarVisible&&this.setState({imgBarVisible:!0})}handleContextMenu(t){if(t.preventDefault(),this.props.selectedTool===M||this.props.selectedTool===x){const{x:e,y:s}=this.getMousePosition(t),i=this.state.svg.width-2*this.state.imageOffset.x,n=this.state.svg.height-2*this.state.imageOffset.y,a=(e-this.state.imageOffset.x)/i,o=(s-this.state.imageOffset.y)/n,p=this.props.selectedTool===M?"positive":"negative";this.props.onSamPointClick(e,s,a,o,p)}}handleMouseDown(t){if(this.props.selectedTool===b){if(t.button!==2)return;t.preventDefault();const{x:e,y:s}=this.getMousePosition(t);this.setState({isDrawingSamBBox:!0,samBBoxStartPoint:{x:e,y:s}}),this.props.onUpdateSamBBox({x:e,y:s,width:0,height:0})}}handleImgBarMouseEnter(t){this.setState({imgBarVisible:!1})}handleImgLabelInputClose(){this.triggerCanvasEvent(ct)}handleSvgMouseMove(t){if(this.mousePosAbs=Jt(t,this.state.svg),this.props.selectedTool===b){if(!this.state.isDrawingSamBBox||!this.state.samBBoxStartPoint)return;const{x:e,y:s}=this.getMousePosition(t),i=this.state.samBBoxStartPoint,n=this.state.svg.width-2*this.state.imageOffset.x,a=this.state.svg.height-2*this.state.imageOffset.y,o=Math.min(i.x,e),p=Math.min(i.y,s),r=Math.abs(e-i.x),d=Math.abs(s-i.y),u=(o-this.state.imageOffset.x)/n,f=(p-this.state.imageOffset.y)/a,S=(o+r-this.state.imageOffset.x)/n,I=(p+d-this.state.imageOffset.y)/a;this.props.onUpdateSamBBox({x:o,y:p,width:r,height:d,xMinNorm:u,yMinNorm:f,xMaxNorm:S,yMaxNorm:I})}}handleMouseUp(t){if(this.props.selectedTool===b){if(t.button!==2)return;t.preventDefault(),this.setState({isDrawingSamBBox:!1})}}handleMouseLeave(t){this.props.selectedTool===b&&this.setState({isDrawingSamBBox:!1})}handleNotification(t){this.props.onNotification&&this.props.onNotification(t)}handleHideLbl(t,e){let s=!1;const i=this.state.annos.map(n=>{const a={...n};return n.labelIds.includes(t.id)?(a.visible=!e,n.id===this.state.selectedAnnoId&&(s=!0)):n.labelIds.length===0&&t.id===-1&&(a.visible=!e,n.id===this.state.selectedAnnoId&&(s=!0)),a});this.setState({annos:i}),s&&this.selectAnnotation(void 0)}handleMarkExample(t){const e={...t};e.isExample==null?e.isExample=!0:e.isExample?e.isExample=!1:e.isExample=!0,this.handleAnnoEvent(e,P)}copyAnnotation(){this.clipboard=this.findAnno(this.state.selectedAnnoId),this.handleNotification({title:"Copyed annotation to clipboard",message:"Copyed "+this.clipboard.type,type:void 0})}pasteAnnotation(t=0){if(this.clipboard){const e=B("new"),s=this.clipboard.data.map(n=>({x:n.x+t,y:n.y+t})),i={...this.clipboard,id:e,annoTime:0,status:g,mode:l,data:G(s,this.state.svg,this.state.imageOffset)};this.handleNotification({title:"Pasted annotation to canvas",message:"Pasted and selected "+this.clipboard.type,type:void 0}),this.handleAnnoEvent(i,V)}}checkAnnoLength(t){return t.type==="polygon"&&t.data.length<3?(this.handleNotification({title:"Invalid polygon!",message:"A vaild polygon needs at least 3 points!",type:void 0}),!1):!0}startAnnotimeMeasure(t){return t.timestamp=performance.now(),t}stopAnnotimeMeasure(t){if(t.timestamp!==void 0){let e=performance.now();return t.annoTime+=(e-t.timestamp)/1e3,t.timestamp=e,t}return t}updatePossibleLabels(){if(!this.props.possibleLabels||this.props.possibleLabels.length<=0)return;let t=this.props.possibleLabels;t=t.map(e=>"color"in e?{...e}:{...e,color:wt(e.id)}),this.setState({possibleLabels:[...t]})}editAnnoLabel(t){if(this.state.selectedAnnoId){let e;t===void 0?e=this.findAnno(this.state.selectedAnnoId):e={...t},e=this.startAnnotimeMeasure(e),this.showLabelInput(),this.updateSelectedAnno(e,St)}}unloadImage(){this.state.imageLoaded&&this.setState({imageLoaded:!1}),this.handleAnnoSaveEvent(ut,void 0,void 0)}findAnno(t){return this.state.annos.find(e=>e.id===t)}findAnnoRef(t){if(this.state.selectedAnnoId!==void 0)return this.annoRefs.find(e=>e.current?e.current.isSelected():!1)}pushHist(t,e,s,i,n=this.state.imgLabelIds){this.hist.push({...this.getAnnos(t,!1),selectedAnnoId:e,showSingleAnno:i,imgLabelIds:n},s)}undo(){this.handleNotification({title:"Redo/ Undo not supported",message:"Redo and Undo functions are currently not supported",type:void 0})}redo(){this.handleNotification({title:"Redo/ Undo not supported",message:"Redo and Undo functions are currently not supported",type:void 0})}deleteAnnotation(t){if(t)if(t.mode===c){const e=this.findAnnoRef(this.state.selectedAnnoId);e!==void 0&&e.current.myAnno.current.removeLastNode()}else this.handleAnnoEvent(t,L)}deleteAnnoInCreationMode(t){t&&t.mode===c&&this.handleAnnoEvent(t,L)}deleteAllAnnos(){this.state.annos.forEach(t=>{if(typeof t.id!="string"){const e={...t,status:C};this.handleAnnoEvent(e,L)}}),this.selectAnnotation(void 0),this.showSingleAnno(void 0)}setCanvasState(t,e,s,i){this.updateCanvasView({...t}),this.setImageLabels([...e]),this.selectAnnotation(s),this.setState({showSingleAnno:i})}isLocked(t){return!!(this.props.lockedAnnos&&this.props.lockedAnnos.includes(t))}selectAnnotation(t){if(this.isLocked(t)){this.handleNotification({title:"Annotation locked",message:`Annotation with id ${t} is locked and can not be edited`,type:void 0});return}if(t){const e=this.findAnno(t);this.setState({selectedAnnoId:t}),e&&e.mode!==c&&this.setState({annoToolBarVisible:!0})}else this.setState({selectedAnnoId:void 0,annoToolBarVisible:!1}),this.state.showLabelInput&&this.onAnnoLabelInputClose()}traverseAnnos(){if(this.state.annos.length>0){const t=this.state.annos.filter(e=>e.status!==C&&!this.isLocked(e.id)&&e.visible!==!1);if(t.length>0)if(!this.state.selectedAnnoId)this.selectAnnotation(t[0].id);else{let e=t.findIndex(s=>s.id===this.state.selectedAnnoId);e+1<t.length?this.selectAnnotation(t[e+1].id):this.selectAnnotation(t[0].id)}}}getAnnos(t=void 0,e=!0){const s=t||this.state.annos,i=X(s,this.state.svg,e,this.state.imageOffset);return{imgId:this.props.imageMeta.id,imgLabelIds:this.state.imgLabelIds,imgLabelChanged:this.state.imgLabelChanged,imgActions:this.state.imgActions,annotations:i,isJunk:this.state.isJunk,annoTime:this.props.imageMeta.annoTime+(performance.now()-this.state.imgLoadTimestamp)/1e3}}resetZoom(){this.setState({svg:{...this.state.svg,translateX:0,translateY:0,scale:1}})}moveCamera(t,e){let s=this.state.svg.translateX+t/this.state.svg.scale,i=this.state.svg.translateY+e/this.state.svg.scale;const n=this.state.svg.width*.25,a=this.state.svg.width*.75,o=this.state.svg.height*.25,p=this.state.svg.height*.75,r=z({x:0,y:0},this.state.svg),d=z({x:this.state.svg.width,y:this.state.svg.height},this.state.svg);r.vX>=n?s=this.state.svg.translateX-5:d.vX<=a&&(s=this.state.svg.translateX+5),r.vY>=o?i=this.state.svg.translateY-5:d.vY<=p&&(i=this.state.svg.translateY+5),this.setState({svg:{...this.state.svg,translateX:s,translateY:i}})}setMode(t){this.state.mode!==t&&this.setState({mode:t})}getMousePosition(t){const e=this.getMousePositionAbs(t);return{x:e.x/this.state.svg.scale-this.state.svg.translateX,y:e.y/this.state.svg.scale-this.state.svg.translateY}}getMousePositionAbs(t){return{x:t.pageX-this.svg.current.getBoundingClientRect().left,y:t.pageY-this.svg.current.getBoundingClientRect().top}}showLabelInput(t=!0){this.setState({showLabelInput:t}),t&&this.showSingleAnno(this.state.selectedAnnoId)}createNewAnnotation(t){let e=!1;if(!this.keyMapper.controlDown&&!this.keyMapper.shiftDown){if(this.props.selectedTool){const s=this.props.canvasConfig.annos.maxAnnos;s?this.state.annos.length<s?e=!0:this.handleNotification({title:"Maximum number of annotations reached!",message:`Only ${s} annotations per image are allowed by config`,type:void 0}):e=!0}else this.handleNotification({title:"No tool selected!",message:"Please select an annotation tool in the toolbar.",type:void 0});if(e){const s=this.getMousePosition(t);let i={id:this.props.nextAnnoId?this.props.nextAnnoId:B("new"),type:this.props.selectedTool,data:[{x:s.x,y:s.y},{x:s.x,y:s.y}],mode:c,status:g,labelIds:this.state.prevLabel,selectedNode:1,annoTime:0};if(i=this.startAnnotimeMeasure(i),this.setState({annos:[...this.state.annos,i],selectedAnnoId:i.id,showSingleAnno:i.id,annoToolBarVisible:!1}),this.props.selectedTool!==It&&this.props.selectedTool!==Et){const n=this.mergeSelectedAnno(i);this.pushHist(n.newAnnos,i.id,U,i.id)}this.handleAnnoEvent(i,T)}}}recreateAnnotation(t){let e=this.state.annos,s,i;for(var n in e)if(e[n].id==t){s=n,i=e[n];break}if(!["line","polygon"].includes(i.type))return;this.state.annos.splice(s,1);let a={id:i.id,type:i.type,data:i.data,mode:c,status:i.status==="database"||i.status==="changed"?y:g,labelIds:i.labelIds,selectedNode:i.data.length-1,annoTime:i.annoTime};a=this.startAnnotimeMeasure(a),this.setState({annos:[...this.state.annos,a],selectedAnnoId:a.id,showSingleAnno:a.id,annoToolBarVisible:!1}),this.handleAnnoEvent(a,T)}putSelectedOnTop(t){if(this.state.selectedAnnoId&&t.selectedAnnoId!==this.state.selectedAnnoId){const e=this.state.annos.filter(i=>i.id!==this.state.selectedAnnoId),s=this.state.annos.find(i=>i.id===this.state.selectedAnnoId);e.push(s),this.setState({annos:[...e]})}}getLabel(t){return this.state.possibleLabels.find(e=>e.id===t)}getAnnoColor(){if(this.state.selectedAnnoId){const t=this.findAnno(this.state.selectedAnnoId);if(t&&t.labelIds.length>0)return this.getLabel(t.labelIds[0]).color}return Ct()}updateDelayedBackendUpdates(t,e){if(t!==e&&(this.tempIdMap[t]=e),t in this.delayedBackendUpdates)if(this.delayedBackendUpdates[t]!==null){const{anno:s,action:i}=this.delayedBackendUpdates[t],n={...s,status:s.status===g?y:s.status};delete this.delayedBackendUpdates[t],this.handleAnnoSaveEvent(i,n)}else delete this.delayedBackendUpdates[t]}addDelayedBackendUpdate(t,e){if(this.props.onAnnoSaveEvent){if(typeof t.id=="string"&&!(t.id in this.tempIdMap)){let s;return t.id in this.delayedBackendUpdates?this.delayedBackendUpdates[t.id]={anno:t,action:e}:(this.delayedBackendUpdates[t.id]=null,s=t),s}}else console.error("onAnnoSaveEvent needs to be provided in order to use SIA Canvas in a correct war!");return t}updateAnnoBySaveResponse(t){if(t&&t.tempId!==t.dbId){if(!this.findAnno(t.tempId))return;this.updateDelayedBackendUpdates(t.tempId,t.dbId)}}updateSelectedAnno(t,e=void 0,s=!1){if(!t)return;const{newAnnos:i,newAnno:n}=this.mergeSelectedAnno(t,e);return this.setState({annos:i,selectedAnnoId:t.id,prevLabel:t.labelIds}),s?{newAnnos:i,newAnno:n}:i}updateAnno(t,e=void 0,s=!1){if(!t)return;const{newAnnos:i,newAnno:n}=this.mergeSelectedAnno(t,e);return this.setState({annos:i}),s?{newAnnos:i,newAnno:n}:i}mergeSelectedAnno(t,e=void 0){let s=this.state.annos.filter(a=>a.id!==t.id);s=s.map(a=>({...a,mode:l}));let i;return e?(i={...t,mode:e},e===m?t.status!==g?i={...i,status:C}:i=null:i={...i,status:t.status!==g?y:g}):i={...t},i!==null&&s.push(i),{newAnnos:[...s],newAnno:i}}showSingleAnno(t){this.state.showSingleAnno!==t&&this.setState({showSingleAnno:t})}updateImageSize(){var t=this.props.container.current.getBoundingClientRect(),e=document.documentElement.clientHeight,s,i,n,a;const o=this.props.uiConfig.layoutOffset;o?(s=t.top+o.top,i=t.left+o.left,n=e-t.top-o.bottom-o.top,a=t.right-i-o.right):(s=t.top,i=t.left,n=e-t.top,a=t.right-i);var p=this.img.current.naturalWidth/this.img.current.naturalHeight,r="100%",d="100%";n*p>a?(r=a,d=a/p):(r=n*p,d=n);var u;const f={x:0,y:0};if(this.props.uiConfig.maxCanvas)f.x=(a-r)/2,f.y=(n-d)/2,u={...this.state.svg,width:a,height:n,left:i,top:s};else{if(this.props.uiConfig.centerCanvasInContainer){const S=a-r;S>2&&(i=i+S/2);const I=n-d;I>2&&(s=s+I/2)}u={...this.state.svg,width:r,height:d,left:i,top:s}}return this.setState({svg:u,image:{width:this.img.current.naturalWidth,height:this.img.current.naturalHeight},imageOffset:f}),this.svgUpdate(u),{imgWidth:this.props.fixedImageSize?this.props.fixedImageSize:r,imgHeight:this.props.fixedImageSize?this.props.fixedImageSize:d,imgOffset:f}}svgUpdate(t){this.triggerCanvasEvent(ft,t)}setImageLabels(t){t!==this.state.imgLabelIds&&this.setState({imgLabelIds:t})}updateCanvasView(t){if(t){const e=this.updateImageSize();this.setState({annos:[...Mt(t,{width:e.imgWidth,height:e.imgHeight},e.imgOffset)]})}}renderAnnotations(){if(this.state.mode!==v){this.annoRefs=[];const t=this.state.annos.map(e=>(this.annoRefs.push(E.createRef()),h(J,{type:e.type,data:e,svg:{...this.state.svg},imageOffset:this.state.imageOffset,ref:this.annoRefs[this.annoRefs.length-1],onMouseDown:s=>this.onAnnoMouseDown(s),onAction:(s,i)=>this.handleAnnoEvent(s,i),selectedAnno:this.state.selectedAnnoId,showSingleAnno:this.state.showSingleAnno,uiConfig:this.props.uiConfig,allowedActions:this.props.canvasConfig.annos.actions,possibleLabels:this.state.possibleLabels,image:this.state.image,canvasConfig:this.props.canvasConfig,onNotification:s=>this.handleNotification(s),defaultLabel:this.props.defaultLabel},e.id)));return h("g",{children:t})}else return null}renderImgLabelInput(){return this.props.imageMeta?h(j,{onClick:()=>this.handleImgLabelInputClose(),active:this.props.uiConfig.imgLabelInputVisible,header:h("div",{children:"Add label for the whole image"}),content:A("div",{children:[h(Z,{multilabels:this.props.canvasConfig.img.multilabels,visible:!0,onLabelUpdate:t=>this.handleImgLabelUpdate(t),possibleLabelsProp:this.state.possibleLabels,initLabelIds:this.state.imgLabelIds,relatedId:this.props.imageMeta.id,defaultLabel:this.props.defaultLabel}),A(q,{basic:!0,color:"green",inverted:!0,onClick:()=>this.handleImgLabelInputClose(),children:[h(D,{name:"check"}),"OK"]})]})}):null}renderAnnoToolBar(t){let e=this.state.annoToolBarVisible;return this.state.mode===v&&(e=!1),h(F,{visible:e,selectedAnno:t,svg:this.state.svg,onClick:()=>this.editAnnoLabel(),color:this.getAnnoColor()})}renderAnnoLabelInpput(t){let e=this.state.showLabelInput;return this.state.mode===v&&(e=!1),h(W,{svg:this.state.svg,onClose:()=>this.onAnnoLabelInputClose(),onDeleteClick:s=>this.onLabelInputDeleteClick(s),selectedAnno:t,visible:e,onLabelUpdate:s=>this.onAnnoLabelInputUpdate(s),possibleLabels:this.state.possibleLabels,allowedActions:this.props.canvasConfig.annos.actions,multilabels:this.props.canvasConfig.annos.multilabels,mousePos:this.mousePosAbs,defaultLabel:this.props.defaultLabel})}renderSamPoints(){return this.props.samPoints.map((t,e)=>h("circle",{cx:t.x,cy:t.y,r:5,fill:t.type==="positive"?"lightgreen":"lightcoral"},e))}renderSamBBox(){return this.props.samBBox&&h("rect",{x:this.props.samBBox.x,y:this.props.samBBox.y,width:this.props.samBBox.width,height:this.props.samBBox.height,fill:"rgba(0, 0, 255, 0.1)",stroke:"blue",strokeWidth:"2"})}render(){const t=this.findAnno(this.state.selectedAnnoId);return A("div",{ref:this.container,children:[A("div",{height:this.state.svg.height,style:{position:this.props.isStaticPosition?"static":"fixed",top:this.state.svg.top,left:this.state.svg.left},children:[this.renderImgLabelInput(),h($,{container:this.container,visible:this.state.imgBarVisible,possibleLabels:this.state.possibleLabels,annos:this.props.annos,annoTaskId:this.props.annoTaskId,svg:this.state.svg,imageMeta:this.props.imageMeta,onClose:()=>this.handleImgBarClose(),imgLabelIds:this.state.imgLabelIds,onMouseEnter:e=>this.handleImgBarMouseEnter(e)}),h(O,{active:!this.state.imageLoaded||this.props.blocked,children:(!this.state.imageLoaded||this.props.blocked)&&h(Q,{children:"Loading"})}),h(O,{active:this.state.isJunk,children:this.state.isJunk&&A(tt,{as:"h2",icon:!0,inverted:!0,style:{background:"rgba(0,0,0,0)"},children:[h(D,{name:"ban"}),"Marked as Junk"]})}),this.renderAnnoToolBar(t),this.renderAnnoLabelInpput(t),h(Ft,{container:this.props.container,layoutUpdate:this.props.layoutUpdate,annos:this.state.annos,selectedAnno:t,possibleLabels:this.state.possibleLabels,allowedToMarkExample:this.props.canvasConfig.allowedToMarkExample,uiConfig:this.props.uiConfig,imgLoadCount:this.state.imgLoadCount,onCommentUpdate:e=>this.updateAnnoComment(e),onUiConfigUpdate:e=>this.triggerCanvasEvent(At,e),onHideLbl:(e,s)=>this.handleHideLbl(e,s),onMarkExample:e=>this.handleMarkExample(e),commentInputTrigger:this.state.annoCommentInputTrigger,onGetAnnoExample:e=>this.props.onGetAnnoExample?this.props.onGetAnnoExample(e):{},exampleImg:this.props.exampleImg}),h("svg",{ref:this.svg,width:this.props.fixedImageSize?this.props.fixedImageSize:this.state.svg.width,height:this.props.fixedImageSize?this.props.fixedImageSize:this.state.svg.height,onKeyDown:e=>this.onKeyDown(e),onKeyUp:e=>this.onKeyUp(e),onClick:e=>this.handleCanvasClick(e),onMouseMove:e=>this.handleSvgMouseMove(e),onContextMenu:e=>this.handleContextMenu(e),onMouseDown:e=>this.handleMouseDown(e),onMouseUp:e=>this.handleMouseUp(e),onMouseLeave:e=>this.handleMouseLeave(e),tabIndex:"0",children:A("g",{transform:`scale(${this.state.svg.scale}) translate(${this.state.svg.translateX}, ${this.state.svg.translateY})`,onMouseOver:()=>{this.onMouseOver()},onMouseLeave:()=>{this.onMouseLeave()},onMouseUp:e=>{this.onMouseUp(e)},onWheel:e=>this.onWheel(e),onMouseMove:e=>{this.onMouseMove(e)},children:[h("image",{onContextMenu:e=>this.onRightClick(e),onMouseDown:e=>this.onMouseDown(e),href:this.props.imageBlob,width:this.props.fixedImageSize?this.props.fixedImageSize:this.state.svg.width,height:this.props.fixedImageSize?this.props.fixedImageSize:this.state.svg.height}),this.renderAnnotations(),this.renderSamPoints(),this.renderSamBBox()]})}),h("img",{alt:"sia",style:{display:"none"},ref:this.img,onLoad:()=>{this.onImageLoad()},src:this.state.imageBlob,width:"100%",height:"100%"})]}),h("div",{style:{minHeight:this.state.svg.height}})]})}}export{be as default};