diff options
author | lonkaars <loek@pipeframe.xyz> | 2021-05-24 11:26:11 +0200 |
---|---|---|
committer | lonkaars <loek@pipeframe.xyz> | 2021-05-24 11:26:11 +0200 |
commit | 5e07224b4bf5010b96f745441b6ee4c213d3fb81 (patch) | |
tree | 812132ad39d4a56ae9a1529ceb9c9ff69efe1109 /pages | |
parent | 221efd26e676ca86aa6f9058d7f7d082e1b87e94 (diff) |
dragging keyframe affects timeline :tada:
Diffstat (limited to 'pages')
-rw-r--r-- | pages/editor.tsx | 57 | ||||
-rw-r--r-- | pages/present.tsx | 6 |
2 files changed, 51 insertions, 12 deletions
diff --git a/pages/editor.tsx b/pages/editor.tsx index e001dfd..7d8834c 100644 --- a/pages/editor.tsx +++ b/pages/editor.tsx @@ -1,8 +1,8 @@ import { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react'; -import { animated, useSpring, useSprings } from 'react-spring'; +import { animated, useSpring } from 'react-spring'; import { useDrag } from 'react-use-gesture'; import create from 'zustand'; -import { delaySlide, loopSlide, slide, speedChangeSlide } from '../timeline'; +import { anySlide, loopSlide, slide } from '../timeline'; import { TimedVideoPlayer } from './present'; import AppBar from '@material-ui/core/AppBar'; @@ -15,15 +15,19 @@ import ZoomInRoundedIcon from '@material-ui/icons/ZoomInRounded'; import ZoomOutRoundedIcon from '@material-ui/icons/ZoomOutRounded'; import Icon from '@mdi/react'; -import { PressureIcon, SlideKeyframe } from '../components/icons'; -import Loop from '../components/loop'; - import FullscreenRoundedIcon from '@material-ui/icons/FullscreenRounded'; import NavigateBeforeRoundedIcon from '@material-ui/icons/NavigateBeforeRounded'; import NavigateNextRoundedIcon from '@material-ui/icons/NavigateNextRounded'; import PauseRoundedIcon from '@material-ui/icons/PauseRounded'; import SkipPreviousRoundedIcon from '@material-ui/icons/SkipPreviousRounded'; import { mdiCursorDefault } from '@mdi/js'; +import { PressureIcon, SlideKeyframe } from '../components/icons'; + +var player = new TimedVideoPlayer(); +var useWorkingTimeline = create(set => ({ + timeline: [], + setTimeline: (newTimeline: anySlide[]) => set(() => ({ timeline: newTimeline })), +})); var getTimelineZoom = create(set => ({ zoom: 0.687077725615, @@ -50,8 +54,17 @@ var useFrame = create(set => ({ })); function TimelineKeyframe(props: { - slide: slide | delaySlide | loopSlide | speedChangeSlide; + slide: slide; }) { + var workingTimeline = useWorkingTimeline((st: any) => st.timeline); + var setWorkingTimeline = useWorkingTimeline((st: any) => st.setTimeline); + + function modifySlide(newProps: Partial<anySlide>) { + var slide = workingTimeline.find((s: anySlide) => s.id == props.slide.id); + slide = Object.assign(slide, newProps); + setWorkingTimeline(workingTimeline); + } + var dragRef = useRef(null); var loopStartRef = useRef(null); var loopEndRef = useRef(null); @@ -83,8 +96,13 @@ function TimelineKeyframe(props: { endOffset = endFrame - grabFrameOffset; } api.start({ begin: frame + startOffset, frame: frame + endOffset }); + + modifySlide({ frame: frame + endOffset }); + modifySlide({ beginFrame: frame + startOffset }); } else { api.start({ frame }); + + modifySlide({ frame }); } }, { domTarget: dragRef, eventOptions: { passive: false } }); @@ -92,20 +110,35 @@ function TimelineKeyframe(props: { // loop start useDrag(({ xy: [x, _y] }) => { var frame = Math.max(0, Math.round(getFrameAtOffset(x - 240, timelineZoom)) - 1); + api.start({ begin: frame }); + + modifySlide({ beginFrame: frame }); }, { domTarget: loopStartRef, eventOptions: { passive: false } }); // loop end useDrag(({ xy: [x, _y] }) => { var frame = Math.max(0, Math.round(getFrameAtOffset(x - 240, timelineZoom)) - 1); + api.start({ frame }); + + modifySlide({ frame }); }, { domTarget: loopEndRef, eventOptions: { passive: false } }); } + var mouseUpListener = useRef(null); + + useDrag(({ last }) => { + if (!last) return; + player.timeline.slides = Array(...workingTimeline); + player.timeline.slides.sort((a: anySlide, b: anySlide) => a.frame - b.frame); + }, { domTarget: mouseUpListener, eventOptions: { passive: false } }); + return <animated.div className='frame posabs' style={{ '--frame': spring.frame } as CSSProperties} id={'slide-' + props.slide.id} + ref={mouseUpListener} > <div className='keyframeWrapper posabs abscenterh'> {props.slide.type == 'loop' @@ -128,14 +161,14 @@ function TimelineKeyframe(props: { </animated.div>; } -function TimelineEditor(props: { - player: TimedVideoPlayer; -}) { +function TimelineEditor(props: { player: TimedVideoPlayer; }) { var timelineZoom = getTimelineZoom((st: any) => st.zoom); var timelineLabels = useTimelineLabels((st: any) => st.labels); var setTimelineLabels = useTimelineLabels((st: any) => st.setLabels); + var workingTimeline = useWorkingTimeline((st: any) => st.timeline); + // var frame = useFrame((st: any) => st.currentFrame); var setFrame = useFrame((st: any) => st.setFrame); @@ -281,7 +314,7 @@ function TimelineEditor(props: { <div className='keyframes' style={{ '--total-frames': props.player?.timeline?.framecount.toString() } as CSSProperties} - children={props.player?.timeline?.slides.map(slide => <TimelineKeyframe slide={slide} />)} + children={workingTimeline.map((slide: anySlide) => <TimelineKeyframe slide={slide} />)} /> </div> </>; @@ -290,7 +323,8 @@ function TimelineEditor(props: { export default function Index() { var [dummy, setDummy] = useState(false); var rerender = () => setDummy(!dummy); - var [player, _setPlayer] = useState(new TimedVideoPlayer()); + + var setWorkingTimeline = useWorkingTimeline((st: any) => st.setTimeline); var timelineZoom = getTimelineZoom((st: any) => st.zoom); var setTimelineZoom = getTimelineZoom((st: any) => st.setZoom); @@ -375,6 +409,7 @@ export default function Index() { var reader = new FileReader(); reader.addEventListener('load', ev => { player.loadSlides(ev.target.result as string); + setWorkingTimeline(player.timeline.slides); rerender(); }); reader.readAsText(file); diff --git a/pages/present.tsx b/pages/present.tsx index f5955fc..9769577 100644 --- a/pages/present.tsx +++ b/pages/present.tsx @@ -58,6 +58,9 @@ export class TimedVideoPlayer { jumpToFrame(frame: number) { this.player.currentTime = this.frameToTimestamp(frame); this.frame = frame; + + var event = new CustomEvent('TimedVideoPlayerOnFrame', { detail: this.frame }); + this.dispatchEvent(event); } jumpToSlide(slide: slide) { @@ -128,7 +131,6 @@ export class TimedVideoPlayer { setInterval(() => { if (this.player.paused) return; - var lastFrame = this.frame; this.frame = this.timestampToFrame(this.player.currentTime); var event = new CustomEvent('TimedVideoPlayerOnFrame', { detail: this.frame }); @@ -169,6 +171,7 @@ export class TimedVideoPlayer { this.framerate = this.timeline.framerate; this.timeline.slides[-1] = { + id: '00000000-0000-0000-0000-000000000000', frame: 0, type: 'default', clickThroughBehaviour: 'ImmediatelySkip', @@ -202,6 +205,7 @@ export class TimedVideoPlayer { if (!this.registeredEventListeners) return; this.slide = Math.max(this.slide - 1, -1); + var event = new CustomEvent('TimedVideoPlayerSlide', { detail: this.slide }); this.dispatchEvent(event); |