Skip to content

Commit 08c68ea

Browse files
committed
image canvas supports video frames
1 parent 8314560 commit 08c68ea

File tree

5 files changed

+140
-26
lines changed

5 files changed

+140
-26
lines changed

src/ImageCanvas/index.js

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ import { useRafState } from "react-use"
3535
import PointDistances from "../PointDistances"
3636
import RegionTags from "../RegionTags"
3737
import RegionSelectAndTransformBoxes from "../RegionSelectAndTransformBoxes"
38+
import VideoOrImageCanvasBackground from "../VideoOrImageCanvasBackground"
39+
import useEventCallback from "use-event-callback"
3840

3941
const useStyles = makeStyles(styles)
4042

4143
type Props = {
4244
regions: Array<Region>,
43-
imageSrc: string,
45+
imageSrc?: string,
46+
videoSrc?: string,
47+
videoTime?: number,
4448
onMouseMove?: ({ x: number, y: number }) => any,
4549
onMouseDown?: ({ x: number, y: number }) => any,
4650
onMouseUp?: ({ x: number, y: number }) => any,
@@ -73,6 +77,8 @@ const getDefaultMat = () => Matrix.from(1, 0, 0, 1, -10, -10)
7377
export default ({
7478
regions,
7579
imageSrc,
80+
videoSrc,
81+
videoTime,
7682
realSize,
7783
showTags,
7884
onMouseMove = p => null,
@@ -138,10 +144,19 @@ export default ({
138144

139145
const projectRegionBox = useProjectRegionBox({ layoutParams, mat })
140146

141-
const [image, imageLoaded] = useLoadImage(imageSrc, onImageLoaded)
147+
const [imageDimensions, changeImageDimensions] = useState()
148+
const imageLoaded = Boolean(imageDimensions)
149+
const onVideoOrImageLoaded = useEventCallback(
150+
({ naturalWidth, naturalHeight }) => {
151+
changeImageDimensions({ naturalWidth, naturalHeight })
152+
}
153+
)
154+
155+
// const [image, imageLoaded] = useLoadImage(imageSrc, onImageLoaded)
142156
const excludePattern = useExcludePattern()
143157

144158
useLayoutEffect(() => {
159+
if (!imageDimensions) return
145160
const canvas = canvasEl.current
146161
const { clientWidth, clientHeight } = canvas
147162
canvas.width = clientWidth
@@ -157,13 +172,13 @@ export default ({
157172
)
158173

159174
const fitScale = Math.max(
160-
image.naturalWidth / (clientWidth - 20),
161-
image.naturalHeight / (clientHeight - 20)
175+
imageDimensions.naturalWidth / (clientWidth - 20),
176+
imageDimensions.naturalHeight / (clientHeight - 20)
162177
)
163178

164179
const [iw, ih] = [
165-
image.naturalWidth / fitScale,
166-
image.naturalHeight / fitScale
180+
imageDimensions.naturalWidth / fitScale,
181+
imageDimensions.naturalHeight / fitScale
167182
]
168183

169184
layoutParams.current = {
@@ -378,22 +393,24 @@ export default ({
378393
}}
379394
>
380395
{showCrosshairs && <Crosshairs mousePosition={mousePosition} />}
381-
<RegionSelectAndTransformBoxes
382-
regions={regions}
383-
mouseEvents={mouseEvents}
384-
projectRegionBox={projectRegionBox}
385-
dragWithPrimary={dragWithPrimary}
386-
createWithPrimary={createWithPrimary}
387-
zoomWithPrimary={zoomWithPrimary}
388-
onBeginMovePoint={onBeginMovePoint}
389-
onSelectRegion={onSelectRegion}
390-
layoutParams={layoutParams}
391-
mat={mat}
392-
onBeginBoxTransform={onBeginBoxTransform}
393-
onBeginMovePolygonPoint={onBeginMovePolygonPoint}
394-
onAddPolygonPoint={onAddPolygonPoint}
395-
/>
396-
{showTags && (
396+
{imageLoaded && (
397+
<RegionSelectAndTransformBoxes
398+
regions={regions}
399+
mouseEvents={mouseEvents}
400+
projectRegionBox={projectRegionBox}
401+
dragWithPrimary={dragWithPrimary}
402+
createWithPrimary={createWithPrimary}
403+
zoomWithPrimary={zoomWithPrimary}
404+
onBeginMovePoint={onBeginMovePoint}
405+
onSelectRegion={onSelectRegion}
406+
layoutParams={layoutParams}
407+
mat={mat}
408+
onBeginBoxTransform={onBeginBoxTransform}
409+
onBeginMovePolygonPoint={onBeginMovePolygonPoint}
410+
onAddPolygonPoint={onAddPolygonPoint}
411+
/>
412+
)}
413+
{imageLoaded && showTags && (
397414
<PreventScrollToParents>
398415
<RegionTags
399416
regions={regions}
@@ -437,7 +454,15 @@ export default ({
437454
>
438455
<>
439456
<canvas className={classes.canvas} ref={canvasEl} />
440-
<img
457+
<VideoOrImageCanvasBackground
458+
imagePosition={imagePosition}
459+
mouseEvents={mouseEvents}
460+
onLoad={onVideoOrImageLoaded}
461+
videoTime={videoTime}
462+
videoSrc={videoSrc}
463+
imageSrc={imageSrc}
464+
/>
465+
{/* <img
441466
src={imageSrc}
442467
className={classes.image}
443468
{...mouseEvents}
@@ -447,7 +472,7 @@ export default ({
447472
width: imagePosition.bottomRight.x - imagePosition.topLeft.x,
448473
height: imagePosition.bottomRight.y - imagePosition.topLeft.y
449474
}}
450-
/>
475+
/> */}
451476
</>
452477
</PreventScrollToParents>
453478
<div className={classes.zoomIndicator}>

src/ImageCanvas/styles.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { grey } from "@material-ui/core/colors"
22

33
export default {
4-
image: { zIndex: 0, position: "absolute" },
54
canvas: { width: "100%", height: "100%", position: "relative", zIndex: 1 },
65
zoomIndicator: {
76
position: "absolute",

src/RegionTags/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const RegionTags = ({
4545
if (region.locked) {
4646
return (
4747
<div
48+
key={region.id}
4849
style={{
4950
position: "absolute",
5051
...coords,
@@ -72,6 +73,7 @@ export const RegionTags = ({
7273
}
7374
return (
7475
<div
76+
key={region.id}
7577
style={{
7678
position: "absolute",
7779
...coords,

src/SettingsDialog/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { useSettings } from "../SettingsProvider"
1212
export const SettingsDialog = ({ open, onClose }) => {
1313
const settings = useSettings()
1414
return (
15-
<Dialog open={open} onClose={onClose}>
15+
<Dialog open={open || false} onClose={onClose}>
1616
<DialogTitle>Settings</DialogTitle>
1717
<DialogContent style={{ minWidth: 400 }}>
1818
<Survey
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// @flow weak
2+
3+
import React, { useRef, useEffect, useMemo } from "react"
4+
import { styled } from "@material-ui/core/styles"
5+
import useEventCallback from "use-event-callback"
6+
7+
const Video = styled("video")({
8+
zIndex: 0,
9+
position: "absolute"
10+
})
11+
12+
const StyledImage = styled("img")({
13+
zIndex: 0,
14+
position: "absolute"
15+
})
16+
17+
export default ({
18+
imagePosition,
19+
mouseEvents,
20+
videoTime = 0,
21+
videoSrc,
22+
imageSrc,
23+
onLoad
24+
}) => {
25+
const videoRef = useRef()
26+
const imageRef = useRef()
27+
28+
useEffect(() => {
29+
if (videoRef.current) {
30+
videoRef.current.currentTime = videoTime / 1000
31+
}
32+
}, [videoTime])
33+
34+
const onLoadedVideoMetadata = useEventCallback(event => {
35+
const videoElm = event.currentTarget
36+
videoElm.currentTime = videoTime / 1000
37+
if (onLoad)
38+
onLoad({
39+
naturalWidth: videoElm.videoWidth,
40+
naturalHeight: videoElm.videoHeight,
41+
videoElm: videoElm
42+
})
43+
})
44+
const onImageLoaded = useEventCallback(event => {
45+
const imageElm = event.currentTarget
46+
if (onLoad)
47+
onLoad({
48+
naturalWidth: imageElm.naturalWidth,
49+
naturalHeight: imageElm.naturalHeight,
50+
imageElm
51+
})
52+
})
53+
54+
const stylePosition = useMemo(
55+
() => ({
56+
left: imagePosition.topLeft.x,
57+
top: imagePosition.topLeft.y,
58+
width: imagePosition.bottomRight.x - imagePosition.topLeft.x,
59+
height: imagePosition.bottomRight.y - imagePosition.topLeft.y
60+
}),
61+
[
62+
imagePosition.topLeft.x,
63+
imagePosition.topLeft.y,
64+
imagePosition.bottomRight.x,
65+
imagePosition.bottomRight.y
66+
]
67+
)
68+
69+
if (!videoSrc && !imageSrc) return "No imageSrc or videoSrc provided"
70+
71+
return imageSrc ? (
72+
<StyledImage
73+
{...mouseEvents}
74+
src={imageSrc}
75+
ref={imageRef}
76+
style={stylePosition}
77+
onLoad={onImageLoaded}
78+
/>
79+
) : (
80+
<Video
81+
{...mouseEvents}
82+
ref={videoRef}
83+
style={stylePosition}
84+
onLoadedMetadata={onLoadedVideoMetadata}
85+
src={videoSrc}
86+
/>
87+
)
88+
}

0 commit comments

Comments
 (0)