-
Notifications
You must be signed in to change notification settings - Fork 552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add python panel timeline support #4834
Changes from 10 commits
dacca18
fe7030b
bb166bb
cadb2fb
3d1a25f
784c02b
ec67893
1d7f0c3
33dccf0
da6d1da
4d9f178
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,123 @@ | ||||||||||||||||||||||||||||
import React, { | ||||||||||||||||||||||||||||
forwardRef, | ||||||||||||||||||||||||||||
useCallback, | ||||||||||||||||||||||||||||
useEffect, | ||||||||||||||||||||||||||||
useMemo, | ||||||||||||||||||||||||||||
useRef, | ||||||||||||||||||||||||||||
useState, | ||||||||||||||||||||||||||||
} from "react"; | ||||||||||||||||||||||||||||
import { ObjectSchemaType, ViewPropsType } from "../utils/types"; | ||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||
DEFAULT_FRAME_NUMBER, | ||||||||||||||||||||||||||||
GLOBAL_TIMELINE_ID, | ||||||||||||||||||||||||||||
} from "@fiftyone/playback/src/lib/constants"; | ||||||||||||||||||||||||||||
import { BufferManager, BufferRange } from "@fiftyone/utilities"; | ||||||||||||||||||||||||||||
import { usePanelEvent } from "@fiftyone/operators"; | ||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||
usePanelId, | ||||||||||||||||||||||||||||
usePanelState, | ||||||||||||||||||||||||||||
useSetPanelStateById, | ||||||||||||||||||||||||||||
} from "@fiftyone/spaces"; | ||||||||||||||||||||||||||||
import { useTimeline } from "@fiftyone/playback/src/lib/use-timeline"; | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^ |
||||||||||||||||||||||||||||
import _ from "lodash"; | ||||||||||||||||||||||||||||
import { useDefaultTimelineName } from "@fiftyone/playback/src/lib/use-default-timeline-name"; | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^ |
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
export default function FrameLoaderView(props: ViewPropsType) { | ||||||||||||||||||||||||||||
const { schema, path, data } = props; | ||||||||||||||||||||||||||||
const { view = {} } = schema; | ||||||||||||||||||||||||||||
const { on_load_range, timeline_id, target } = view; | ||||||||||||||||||||||||||||
const { properties } = schema as ObjectSchemaType; | ||||||||||||||||||||||||||||
const panelId = usePanelId(); | ||||||||||||||||||||||||||||
const [myLocalFrameNumber, setMyLocalFrameNumber] = | ||||||||||||||||||||||||||||
React.useState(DEFAULT_FRAME_NUMBER); | ||||||||||||||||||||||||||||
const triggerEvent = usePanelEvent(); | ||||||||||||||||||||||||||||
const setPanelState = useSetPanelStateById(true); | ||||||||||||||||||||||||||||
const localIdRef = React.useRef<string>(); | ||||||||||||||||||||||||||||
const bufm = useRef(new BufferManager()); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||
localIdRef.current = Math.random().toString(36).substring(7); | ||||||||||||||||||||||||||||
// console.log("localIdRef", localIdRef.current); | ||||||||||||||||||||||||||||
if (data?.frames) | ||||||||||||||||||||||||||||
// console.log("dispatching frames-loaded", localIdRef.current); | ||||||||||||||||||||||||||||
dispatchEvent( | ||||||||||||||||||||||||||||
new CustomEvent(`frames-loaded`, { | ||||||||||||||||||||||||||||
detail: { localId: localIdRef.current }, | ||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
}, [data?.signature]); // remove this JSON.strignify | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const loadRange = React.useCallback( | ||||||||||||||||||||||||||||
async (range: BufferRange) => { | ||||||||||||||||||||||||||||
if (on_load_range) { | ||||||||||||||||||||||||||||
// if (!bufm.current.containsRange(range)) { | ||||||||||||||||||||||||||||
// // only trigger event if the range is not already in the buffer | ||||||||||||||||||||||||||||
// await triggerEvent(panelId, { | ||||||||||||||||||||||||||||
// params: { range }, | ||||||||||||||||||||||||||||
// operator: on_load_range, | ||||||||||||||||||||||||||||
// }); | ||||||||||||||||||||||||||||
// } | ||||||||||||||||||||||||||||
const unp = bufm.current.getUnprocessedBufferRange(range); | ||||||||||||||||||||||||||||
const isProcessed = unp === null; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
if (!isProcessed) { | ||||||||||||||||||||||||||||
await triggerEvent(panelId, { | ||||||||||||||||||||||||||||
params: { range: unp }, | ||||||||||||||||||||||||||||
operator: on_load_range, | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
console.log("loading range", range); | ||||||||||||||||||||||||||||
return new Promise<void>((resolve) => { | ||||||||||||||||||||||||||||
window.addEventListener(`frames-loaded`, (e) => { | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool! |
||||||||||||||||||||||||||||
// console.log("frames loaded", e, {'current': localIdRef.current, 'detail': e.detail.localId}); | ||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||
e instanceof CustomEvent && | ||||||||||||||||||||||||||||
e.detail.localId === localIdRef.current | ||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||
// console.log("resolving"); | ||||||||||||||||||||||||||||
bufm.current.addNewRange(range); | ||||||||||||||||||||||||||||
resolve(); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
[triggerEvent, on_load_range, localIdRef.current] | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid including mutable Including |
||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const [currentFrame, setCurrentFrame] = useState(DEFAULT_FRAME_NUMBER); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const myRenderFrame = React.useCallback( | ||||||||||||||||||||||||||||
(frameNumber: number) => { | ||||||||||||||||||||||||||||
setMyLocalFrameNumber(frameNumber); | ||||||||||||||||||||||||||||
// console.log("rendering frame", frameNumber, props); | ||||||||||||||||||||||||||||
setPanelState(panelId, (current) => { | ||||||||||||||||||||||||||||
const currentData = current.data ? _.cloneDeep(current.data) : {}; // Clone the object | ||||||||||||||||||||||||||||
const currentFrameData = _.get(currentData, path, { frames: [] }) | ||||||||||||||||||||||||||||
.frames[frameNumber]; | ||||||||||||||||||||||||||||
let updatedData = { ...currentData }; | ||||||||||||||||||||||||||||
_.set(updatedData, target, currentFrameData); // Use lodash set to update safely | ||||||||||||||||||||||||||||
return { ...current, data: updatedData }; | ||||||||||||||||||||||||||||
Comment on lines
+67
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optimize deep cloning and updating of In your Apply this diff to optimize state updates: setPanelState(panelId, (current) => {
- const currentData = current.data ? _.cloneDeep(current.data) : {}; // Clone the object
- const currentFrameData = _.get(currentData, path, { frames: [] }).frames[frameNumber];
- let updatedData = { ...currentData };
- _.set(updatedData, target, currentFrameData); // Use lodash set to update safely
- return { ...current, data: updatedData };
+ return {
+ ...current,
+ data: {
+ ...current.data,
+ [target]: _.get(current.data, [path, 'frames', frameNumber], {}),
+ },
+ };
}); Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
setCurrentFrame(frameNumber); | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
[data, setPanelState, panelId, target] | ||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const { isTimelineInitialized, subscribe } = useTimeline(); | ||||||||||||||||||||||||||||
const [subscribed, setSubscribed] = useState(false); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
React.useEffect(() => { | ||||||||||||||||||||||||||||
if (subscribed) return; | ||||||||||||||||||||||||||||
if (isTimelineInitialized) { | ||||||||||||||||||||||||||||
subscribe({ | ||||||||||||||||||||||||||||
id: timeline_id || GLOBAL_TIMELINE_ID, | ||||||||||||||||||||||||||||
loadRange, | ||||||||||||||||||||||||||||
renderFrame: myRenderFrame, | ||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||
setSubscribed(true); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
}, [isTimelineInitialized, loadRange, myRenderFrame, subscribe]); | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
return null; | ||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be worth re-exporting at top-level of that package