lost-sia 3.2.0-alpha0 → 3.2.0-alpha1
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/Canvas/Canvas.js +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/src/Canvas/Canvas.tsx +31 -0
- package/src/utils/index.ts +1 -0
package/dist/Canvas/Canvas.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsxs as
|
|
1
|
+
import{jsxs as U,jsx as p,Fragment as qe}from"react/jsx-runtime";import{useState as g,useRef as q,useEffect as C}from"react";import b from"../models/AnnotationTool.js";import s from"../models/EditorModes.js";import et from"../utils/KeyMapper.js";import a from"../models/KeyAction.js";import xe from"../Annotation/logic/Annotation.js";import tt from"../models/CanvasAction.js";import nt from"../Annotation/ui/AnnotationComponent.js";import he from"../utils/mouse.js";import R from"../models/AnnotationMode.js";import ot from"./LabelInput.js";import{FontAwesomeIcon as rt}from"@fortawesome/react-fontawesome";import{faBan as st}from"@fortawesome/free-solid-svg-icons";import w from"../models/AnnotationStatus.js";import A from"../utils/transform.js";import it from"../models/NotificationType.js";import at from"../utils/TimeUtils.js";import Ce from"../utils/windowViewport.js";const Dt=({annotations:I=[],annotationSettings:D,defaultLabelId:ee,image:T,isFullscreen:Ie=!1,isImageJunk:Y=!1,isPolygonSelectionMode:z=!1,polygonOperationResult:G={annotationsToDelete:[],polygonsToCreate:[]},possibleLabels:te,preventScrolling:ne=!0,selectedAnnotation:i,selectedAnnoTool:V,toolbarHeight:H=0,uiConfig:P,onAnnoCreated:ve,onAnnoCreationFinished:oe,onAnnoChanged:re,onAnnoEditing:Te=c=>{},onNotification:se=c=>{},onRequestNewAnnoId:k,onSelectAnnotation:v,onSetIsImageJunk:Me,onSetSelectedTool:Oe=c=>{},onShouldDeleteAnno:ie,onTraverseAnnotationHistory:ae})=>{const[c,m]=g(s.VIEW),[be,we]=g(),[ce,De]=g(ee),[L,Se]=g({x:-1,y:-1}),[le,de]=g(0),W={x:L.x,y:L.y},[f,B]=g({x:-1,y:-1}),[d,$]=g({x:-1,y:-1}),[y,ue]=g({x:-1,y:-1}),[u,K]=g(1),[l,S]=g({x:0,y:0}),j={x:l.x+le,y:l.y},[J,F]=g(),[Q,_]=g(!1),fe=q(null),x=q(null),M=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)})(f,d),_e=()=>{if(M?.current===null)return{x:0,y:0};const e=f.x*h;if(P.imageCentered&&d.x>e){const E=(d.x-e)/2;de(E)}else de(0);const{top:t,left:n}=x.current.getBoundingClientRect(),o={x:n+window.scrollX,y:t+window.scrollY};Se(o)},Ne=new et(e=>Be(e)),Re=e=>{m(s.CREATE);const t=A.convertStageCoordinatesToPercentaged([e],h,f);V===b.BBox&&t.push(t[0]);const n=k(),o=new xe(n,V,t);if(we(performance.now()),ce!==void 0&&(o.labelIds=[ce]),ve(o),V===b.Point){const r={...o,coordinates:[e],annoTime:0};Z(r)}},Ve=()=>{if(i&&![b.Line,b.Polygon].includes(i.type))return;const e=I.find(n=>n.internalId===i?.internalId);if(e===void 0)return;m(s.CREATE),Oe(e.type);const t={...e,mode:R.CREATE,status:w.CREATING,internalId:k(),selectedNode:e.coordinates.length-1};Te(t)},Pe=()=>{const e=i?i.internalId:0,t=I.find(n=>n.internalId>e);if(t)return v(t);if(I.length>0)return v(I[0])},ke=()=>{const e=i?i.internalId:0,t=[...I];t.sort((o,r)=>r.internalId-o.internalId);const n=t.find(o=>o.internalId<e);if(n)return v(n);if(I.length>0)return v(I.at(-1))},Le=()=>{if(i){const e=JSON.stringify(i);localStorage.setItem("lostAnnotationClipboard",e);const t={title:"Success",message:"Annotation copied",type:it.SUCCESS};se(t)}},We=()=>{const e=localStorage.getItem("lostAnnotationClipboard");if(e==null)return;const t=JSON.parse(e);t.internalId=k(),t.externalId="",oe(t,!0),v(t)},Ee=e=>{const t=A.getMostLeftPoints(e),n=A.getTopPoint(t)[0];return A.convertStageToPage(n,W,u,l)},Be=e=>{switch(e){case a.EDIT_LABEL:if(i){const t=A.convertPercentagedCoordinatesToStage(i.coordinates,f,y);F(Ee(t)),_(!0)}break;case a.DELETE_ANNO:i&&ie(i.internalId);break;case a.DELETE_ANNO_IN_CREATION:c===s.CREATE&&(ie(i.internalId),m(s.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:ae(!0);break;case a.REDO:ae(!1);break;case a.TRAVERSE_ANNOS:Pe();break;case a.TRAVERSE_ANNOS_BACKWARDS:ke();break;case a.CAM_MOVE_LEFT:N(20*u,0);break;case a.CAM_MOVE_RIGHT:N(-20*u,0);break;case a.CAM_MOVE_UP:N(0,20*u);break;case a.CAM_MOVE_DOWN:N(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:We();break;case a.RECREATE_ANNO:console.log("KeyAction TODO: RECREATE_ANNO"),Ve();break;case a.TOGGLE_IMAGE_JUNK:if(c===s.ADD||c===s.CREATE)return;Me(!Y);break;default:console.log("Unknown KeyAction",e);break}},N=(e,t)=>{let n=l.x+e/u,o=l.y+t/u;const r=d.x*.45,E=d.x*.55,O=d.y*.45,Qe=d.y*.55,Ze={x:0,y:0},me=Ce.getViewportCoordinates(l,d,u,Ze),Ae=Ce.getViewportCoordinates(l,d,u,d);me.vX>=r?n=l.x-5:Ae.vX<=E?n=l.x+5:me.vY>=O?o=l.y-5:Ae.vY<=Qe&&(o=l.y+5),S({x:n,y:o})},X=(e=>y.x<=0||y.y<=0||f.x<=0||f.y<=0?[]:I.map(n=>({...n,coordinates:A.convertPercentagedCoordinatesToStage(n.coordinates,f,y)})))(),Ke=()=>{if(m(s.VIEW),ue({x:-1,y:-1}),M.current!==null){const{width:e,height:t}=M.current.getBoundingClientRect();B({x:e,y:t})}K(1),S({x:0,y:0}),F(void 0),_(!1)};C(()=>{fe.current?.focus()},[]),C(()=>{const e=t=>{t.button===1&&c===s.CAMERA_MOVE&&m(s.VIEW)};return window.addEventListener("mouseup",e),()=>window.removeEventListener("mouseup",e)},[c]),C(()=>{if(x?.current!==void 0){Ke();const{width:e,height:t}=x.current.getBoundingClientRect(),n=t-H;$({x:e,y:n});const o=new ResizeObserver(()=>{const{width:r,height:E}=x.current.getBoundingClientRect(),O=E-H;$({x:r,y:O})});return o.observe(x.current),()=>o.disconnect()}},[T,Ie]),C(()=>{_e()},[d,f,P]),C(()=>{if(x.current===null)return;const{width:e,height:t}=x.current.getBoundingClientRect(),n=t-H;$({x:e,y:n})},[x]),C(()=>{if(M.current===null)return;const{width:e,height:t}=M.current.getBoundingClientRect();B({x:e,y:t})},[T,d]),C(()=>{if(!T){B({x:-1,y:-1});return}let e=!1;const t=new Image;return t.onload=()=>{if(e)return;const{naturalWidth:n,naturalHeight:o}=t;n>0&&o>0&&B({x:n,y:o})},t.src=T,()=>{e=!0,t.onload=null}},[T]),C(()=>{if(h===0)return;const e={x:f.x*h,y:f.y*h};ue(e)},[h,f]),C(()=>{z&&G.polygonsToCreate!==void 0&&G.polygonsToCreate.forEach(e=>{const t=k(),n=new xe(t,e.type,A.convertPercentagedCoordinatesToStage(e.coordinates,f,y),R.VIEW,w.CREATED);e.labelIds!==void 0&&(n.labelIds=e.labelIds),Z(n)})},[G]);const Z=e=>{m(s.VIEW);const t={...e,mode:R.VIEW};if(e.type!==b.Point){const r=at.getRoundedDuration(be,performance.now());t.annoTime=r}const n=A.convertStageCoordinatesToPercentaged(e.coordinates,h,f);t.coordinates=n,re(t);const o=V===b.Point||z;oe(t,o)},Fe=e=>{Ne.keyDown(e.key,e.shiftKey,e.ctrlKey)&&e.preventDefault()},Xe=e=>{e.preventDefault()},Ue=e=>{if(e.button!==0){if(e.button===1){if(c===s.CREATE||c===s.ADD){e.preventDefault();return}m(s.CAMERA_MOVE)}else if(e.button===2){if(!D.canCreate||c===s.ADD||c===s.CREATE)return;const t=he.getAntiScaledMouseStagePosition(e,W,u,l),n={x:t.x-le,y:t.y};Re(n)}}},Ye=()=>{ne&&(document.body.style.overflow="hidden")},ze=e=>{e.button===1&&c===s.CAMERA_MOVE&&m(s.VIEW)},ge=(e,t)=>{c===s.CAMERA_MOVE&&N(e,t)},Ge=()=>{ne&&(document.body.style.overflow="")},He=e=>{const o=(e.deltaY<0?1:-1)>0?u*1.25:u/1.25,r=he.getAntiScaledMouseStagePosition(e,W,u,l),E=u/o,O={x:E*(r.x+l.x)-r.x,y:E*(r.y+l.y)-r.y};o<1?(K(1),(l.x!=0||l.y!=0)&&S({x:0,y:0})):o>200?(K(200),S(O)):(K(o),S(O))},$e=(e,t)=>{if(t!==tt.ANNO_SELECTED){console.log("Unknown Canvas Action:",t);return}const n={...e,coordinates:A.convertStageCoordinatesToPercentaged([...e.coordinates],h,f)};v(n),D.canLabel&&F(Ee(e.coordinates))},ye=e=>{const t=A.convertStageCoordinatesToPercentaged(e.coordinates,h,f),n={...e,coordinates:t};n.status===w.LOADED&&(n.status=w.CHANGED),re(n)},je=()=>{if(c===s.CAMERA_MOVE)return p(qe,{});const t=[s.CREATE,s.ADD,s.MOVE].includes(c),n=X.map(o=>{const r=o.internalId===i?.internalId;return t&&!r?p("g",{},`annotationComponent_${o.internalId}`):p(nt,{scaledAnnotation:o,annotationSettings:D,possibleLabels:te,svgScale:u,svgTranslation:j,pageToStageOffset:W,nodeRadius:P.nodeRadius,strokeWidth:P.strokeWidth,isSelected:r,isDisabled:z&&r,onFinishAnnoCreate:Z,onLabelIconClicked:()=>_(!0),onAction:$e,onAnnoChanged:ye,onAnnotationModeChange:E=>{E===R.MOVE&&m(s.MOVE),c===s.MOVE&&E===R.VIEW&&m(s.VIEW)},onNotification:se},`annotationComponent_${o.internalId}`)});if(i){const o=X.find(E=>E.internalId===i?.internalId),r=X.indexOf(o);n.push(n.splice(r,1)[0])}return p("g",{children:n})},Je=()=>p("circle",{cx:y.x/2,cy:y.y/2,r:"100%",style:{opacity:0},onContextMenu:e=>e.preventDefault(),onClick:()=>{_(!1)}}),pe={x:L.x+d.x/2,y:L.y+d.y/2};return U("div",{ref:x,style:{flex:"1 1 auto",minHeight:0,display:"flex",flexDirection:"column"},children:[D.canLabel&&p("div",{style:{position:"absolute",left:J?.x??0,top:J?.y??0,display:J?.y===void 0?"none":"inherit",zIndex:Q?7e3:-1},children:p(ot,{defaultLabelId:ee,isVisible:Q,selectedLabelsIds:i?.labelIds,possibleLabels:te,isMultilabel:D.canHaveMultipleLabels,onLabelSelect:e=>{if(setTimeout(()=>_(!1),0),e.length>0){const r=e.filter(E=>!i.labelIds.includes(E));r.length>0&&De(r[0])}const t=X.find(r=>r.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};ye(o)}})}),Y&&U("div",{style:{position:"absolute",left:pe.x,top:pe.y,transform:"translate(-50%, -50%)",textAlign:"center",color:"white"},children:[p(rt,{icon:st,size:"5x",style:{marginBottom:15}}),p("h2",{children:"Marked as Junk"})]}),U("svg",{ref:fe,style:{flex:"1 1 auto",minHeight:0},onKeyDown:Fe,onKeyUp:Xe,onMouseMove:e=>ge(e.movementX,e.movementY),tabIndex:0,onMouseDown:e=>Ue(e),children:[U("g",{transform:`scale(${u}) translate(${j.x}, ${j.y})`,onMouseOver:Ye,onMouseLeave:Ge,onMouseUp:ze,onWheel:He,onMouseMove:e=>ge(e.movementX,e.movementY),onClick:()=>{v(void 0)},children:[p("image",{onContextMenu:e=>e.preventDefault(),href:T,ref:M,width:y.x>0?y.x:void 0,height:y.y>0?y.y:void 0}),je()]}),Q&&Je(),Y&&p("rect",{x:"0",y:"0",width:d.x,height:d.y,style:{opacity:.8},onContextMenu:e=>e.preventDefault(),onClick:()=>{F(void 0)}})]})]})};export{Dt as default};
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as
|
|
1
|
+
import{default as r}from"./TimeUtils.js";import{SIA_INITIAL_UI_CONFIG as f,uiConfig as I}from"./uiConfig.js";import{getColor as i,getDefaultColor as m}from"./color.js";export{f as SIA_INITIAL_UI_CONFIG,r as TimeUtils,i as getColor,m as getDefaultColor,I as uiConfig};
|
package/package.json
CHANGED
package/src/Canvas/Canvas.tsx
CHANGED
|
@@ -572,6 +572,37 @@ const Canvas = ({
|
|
|
572
572
|
setImgSize({ x: width, y: height })
|
|
573
573
|
}, [image, canvasSize])
|
|
574
574
|
|
|
575
|
+
// Source of truth for the image's natural size.
|
|
576
|
+
// The SVG <image> element above loads asynchronously, so reading
|
|
577
|
+
// imageRef.getBoundingClientRect() (the effect above) runs before the
|
|
578
|
+
// remote image has decoded and resolves to {0, 0}. That left imgSize at
|
|
579
|
+
// 0, which trips the getFittedImageScale guard (returns 0), so stageSize
|
|
580
|
+
// never got set and the <image> rendered at its natural (huge) pixel size.
|
|
581
|
+
// Preloading via an HTMLImageElement gives us naturalWidth/Height as soon
|
|
582
|
+
// as the bytes are decoded, regardless of the SVG <image> lifecycle.
|
|
583
|
+
useEffect(() => {
|
|
584
|
+
if (!image) {
|
|
585
|
+
setImgSize({ x: -1, y: -1 })
|
|
586
|
+
return
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
let cancelled = false
|
|
590
|
+
const probe = new Image()
|
|
591
|
+
probe.onload = () => {
|
|
592
|
+
if (cancelled) return
|
|
593
|
+
const { naturalWidth, naturalHeight } = probe
|
|
594
|
+
if (naturalWidth > 0 && naturalHeight > 0) {
|
|
595
|
+
setImgSize({ x: naturalWidth, y: naturalHeight })
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
probe.src = image
|
|
599
|
+
|
|
600
|
+
return () => {
|
|
601
|
+
cancelled = true
|
|
602
|
+
probe.onload = null
|
|
603
|
+
}
|
|
604
|
+
}, [image])
|
|
605
|
+
|
|
575
606
|
useEffect(() => {
|
|
576
607
|
if (imageToStageFactor === 0) return
|
|
577
608
|
|
package/src/utils/index.ts
CHANGED