From a4dbd32752d2ae28fe7ff58c676905a17b7f3fcd Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 24 Jun 2021 16:06:58 +0200 Subject: selection working again with hookstate :tada: --- pages/editor.tsx | 396 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 220 insertions(+), 176 deletions(-) (limited to 'pages') diff --git a/pages/editor.tsx b/pages/editor.tsx index f00c504..8fcb905 100644 --- a/pages/editor.tsx +++ b/pages/editor.tsx @@ -1,6 +1,6 @@ import { createState, Downgraded, State, useHookstate } from '@hookstate/core'; import mousetrap from 'mousetrap'; -import { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react'; +import { CSSProperties, ReactNode, Ref, useEffect, useRef, useState } from 'react'; import { animated, useSpring } from 'react-spring'; import { useDrag } from 'react-use-gesture'; @@ -114,7 +114,6 @@ function TimelineKeyframe(props: { slide: slide; }) { var workingTimeline = useHookstate(project).timeline.workingTimeline; - var updateTimeline = useHookstate(project).update.refreshLiveTimeline.value; function modifySlide(newProps: Partial) { var slide = workingTimeline.find(s => s.value.id == props.slide.id); @@ -239,166 +238,16 @@ function TimelineLabels() { return
; } -function TimelineEditor() { - var timelineZoom = useHookstate(project).timeline.zoom; +function TimelineSelection(props: { selectionAreaRef: Ref; }) { var workingTimeline = useHookstate(project).timeline.workingTimeline; var tool = useHookstate(project).timeline.tool; - var mouseX = 0; - - var timelineRef = useRef(null); - useEffect(() => { - timelineRef.current.addEventListener('wheel', (e: WheelEvent) => { - if (!e.ctrlKey && !e.altKey) return; - e.preventDefault(); - - var newZoom = Math.min(1, Math.max(0, project.timeline.zoom.value + (-e.deltaY / 1000))); - zoomAroundPoint(newZoom, mouseX); - }); - }, []); - - useEffect(() => { - var canvas = document.querySelector('.timeline .timeScale'); - window.addEventListener('mousemove', e => { - var rect = canvas.getBoundingClientRect(); - mouseX = e.clientX - rect.x; - }); - }, []); - - useEffect(() => { - player.addEventListener('TimedVideoPlayerOnFrame', (event: CustomEvent) => { - project.timeline.frame.set(event.detail); - scrubberSpring.start({ frame: event.detail }); - }); - }, []); - - useEffect(() => { - player.addEventListener('TimedVideoPlayerSlide', (event: CustomEvent) => { - document.querySelectorAll('.keyframes .frame').forEach(el => { - el.classList.remove('current'); - if (event.detail && el.id == 'slide-' + (event.detail as slide).id) { - el.classList.add('current'); - } - }); - }); - }, []); - - // timeline canvas stuff - useEffect(() => { - var canvas = document.getElementById('timeScaleCanvas') as HTMLCanvasElement; - var ctx = canvas.getContext('2d'); - - var css = (varname: string) => getComputedStyle(document.body).getPropertyValue(varname).trim(); - var baseColor = css('--c100'); - var frameColor = css('--c250'); - var markerFrame = css('--c400'); - - function draw() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - var labels: Array = []; - - var offset = document.querySelector('.timeline .timelineInner').scrollLeft; - - var frameWidth = zoomToPx(project.timeline.zoom.value); - - var d = true; - var a = 0; - var ns = [300, 150, 120, 90, 60, 30, 30, 30, 15, 15, 10, 10, 10]; - var everyN = ns[Math.floor(frameWidth)]; - for (var x = -offset; x < canvas.width + offset; x += frameWidth) { - ctx.fillStyle = baseColor; - - var rect = [Math.round(x + (frameWidth - 2) / 2), 28, 2, canvas.height]; - var drawFrame = false; - var marker = false; - if (frameWidth >= 6) { - ctx.fillStyle = d ? baseColor : frameColor; - rect = [x, 28, frameWidth, canvas.height]; - drawFrame = !d; - } - if (a % everyN == 0) { - ctx.fillStyle = markerFrame; - drawFrame = true; - marker = true; - } - - if (drawFrame) { - ctx.fillRect(Math.round(rect[0]), Math.round(rect[1]), Math.round(rect[2]), Math.round(rect[3])); - - if (marker) { - var frame = Math.round(x / frameWidth + offset / frameWidth + 1); - labels.push( - , - ); - } - } - - d = !d; - a++; - } - - project.timeline.labels.set(labels); - - requestAnimationFrame(draw); - } - draw(); - - function onresize() { - var size = document.querySelector('.timeline .timelineInner'); - canvas.width = size.clientWidth; - canvas.height = size.clientHeight; - } - onresize(); - window.addEventListener('resize', onresize); - }, []); - - // timeline scrubber - var scrubberDragRef = useRef(null); - var [scrubberPos, scrubberSpring] = useSpring( - () => ({ - frame: 0, - config: { mass: 0.5, tension: 500, friction: 20 }, - }), - ); - useDrag(({ xy: [x, _y] }) => { - var frame = Math.max(0, Math.round(getFrameAtOffset(x - 240, project.timeline.zoom.value)) - 1); - scrubberSpring.start({ frame }); - if (player.player) { - var time = player.frameToTimestamp(frame + 1); - if (isFinite(time)) player.player.currentTime = time; - } - project.timeline.frame.set(frame); - }, { domTarget: scrubberDragRef, eventOptions: { passive: false } }); - - // slide placement ghost - var [ghost, ghostApi] = useSpring(() => ({ - x: 0, - y: 0, - config: { mass: 0.5, tension: 500, friction: 20 }, - })); - useEffect(() => { - document.querySelector('.timeline').addEventListener('mousemove', (e: MouseEvent) => { - var rect = document.querySelector('.timeline').getBoundingClientRect(); - var x = e.clientX - rect.left; - var y = e.clientY - rect.top; - ghostApi.start({ x, y }); - }); - }, []); - - // selection var [selectionActive, setSelectionActive] = useState(false); var [selectionPlaced, setSelectionPlaced] = useState(false); var [selectionHidden, setSelectionHidden] = useState(true); var [selectionLeftType, setSelectionLeftType] = useState(null); var [selectionRightType, setSelectionRightType] = useState(null); + var [selectionPos, selectionPosAPI] = useSpring(() => ({ x1: 0, y1: 0, @@ -411,9 +260,10 @@ function TimelineEditor() { widthOffset: 0, config: { mass: 0.5, tension: 500, friction: 20 }, })); - var selectionAreaRef = useRef(null); + var selectionRef = useRef(null); var [selection, setSelection] = useState([]); + // drag on selection useDrag(({ movement: [x, _y], last }) => { if (!selectionPlaced) return; if (selection.length < 1) return; @@ -451,6 +301,7 @@ function TimelineEditor() { selectionPosAPI.start({ startingFrame: selectionFrame + frameOffset }); }); }, { domTarget: selectionRef, eventOptions: { passive: false } }); + useDrag(({ xy: [x, y], initial: [bx, by], first, last, movement: [ox, oy] }) => { if (tool.value != 'cursor') return; var minDistance = 5; // minimal drag distance in pixels to register selection @@ -530,12 +381,24 @@ function TimelineEditor() { startOffset, widthOffset, }); + + setTimeout(() => { + selectionPosAPI.start({ + y1: 50, + y2: 62, + startingFrame: left.frame, + frameWidth: right.frame - left.frame, + center: 0.5, + startOffset, + widthOffset, + }); + }, 100); setSelectionLeftType(left.type); setSelectionRightType(right.type); setSelectionPlaced(true); } } - }, { domTarget: selectionAreaRef, eventOptions: { passive: false } }); + }, { domTarget: props.selectionAreaRef, eventOptions: { passive: false } }); useEffect(() => { var delkeys = ['del', 'backspace']; @@ -562,6 +425,206 @@ function TimelineEditor() { }; }, [selectionPlaced, workingTimeline]); + function CustomSelection(props: { + x1: number; + x2: number; + y1: number; + y2: number; + widthOffset: number; + frameWidth: number; + className: string; + }) { + return ; + } + var AnimatedSelection = animated(props => ); + + return + + ; +} + +function TimelineEditor() { + var timelineZoom = useHookstate(project).timeline.zoom; + var workingTimeline = useHookstate(project).timeline.workingTimeline; + var tool = useHookstate(project).timeline.tool; + + var mouseX = 0; + + var timelineRef = useRef(null); + var selectionAreaRef = useRef(null); + useEffect(() => { + timelineRef.current.addEventListener('wheel', (e: WheelEvent) => { + if (!e.ctrlKey && !e.altKey) return; + e.preventDefault(); + + var newZoom = Math.min(1, Math.max(0, project.timeline.zoom.value + (-e.deltaY / 1000))); + zoomAroundPoint(newZoom, mouseX); + }); + }, []); + + useEffect(() => { + var canvas = document.querySelector('.timeline .timeScale'); + window.addEventListener('mousemove', e => { + var rect = canvas.getBoundingClientRect(); + mouseX = e.clientX - rect.x; + }); + }, []); + + useEffect(() => { + player.addEventListener('TimedVideoPlayerOnFrame', (event: CustomEvent) => { + project.timeline.frame.set(event.detail); + scrubberSpring.start({ frame: event.detail }); + }); + }, []); + + useEffect(() => { + player.addEventListener('TimedVideoPlayerSlide', (event: CustomEvent) => { + document.querySelectorAll('.keyframes .frame').forEach(el => { + el.classList.remove('current'); + if (event.detail && el.id == 'slide-' + (event.detail as slide).id) { + el.classList.add('current'); + } + }); + }); + }, []); + + // timeline canvas stuff + useEffect(() => { + var canvas = document.getElementById('timeScaleCanvas') as HTMLCanvasElement; + var ctx = canvas.getContext('2d'); + + var css = (varname: string) => getComputedStyle(document.body).getPropertyValue(varname).trim(); + var baseColor = css('--c100'); + var frameColor = css('--c250'); + var markerFrame = css('--c400'); + + function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var labels: Array = []; + + var offset = document.querySelector('.timeline .timelineInner').scrollLeft; + + var frameWidth = zoomToPx(project.timeline.zoom.value); + + var d = true; + var a = 0; + var ns = [300, 150, 120, 90, 60, 30, 30, 30, 15, 15, 10, 10, 10]; + var everyN = ns[Math.floor(frameWidth)]; + for (var x = -offset; x < canvas.width + offset; x += frameWidth) { + ctx.fillStyle = baseColor; + + var rect = [Math.round(x + (frameWidth - 2) / 2), 28, 2, canvas.height]; + var drawFrame = false; + var marker = false; + if (frameWidth >= 6) { + ctx.fillStyle = d ? baseColor : frameColor; + rect = [x, 28, frameWidth, canvas.height]; + drawFrame = !d; + } + if (a % everyN == 0) { + ctx.fillStyle = markerFrame; + drawFrame = true; + marker = true; + } + + if (drawFrame) { + ctx.fillRect(Math.round(rect[0]), Math.round(rect[1]), Math.round(rect[2]), Math.round(rect[3])); + + if (marker) { + var frame = Math.round(x / frameWidth + offset / frameWidth + 1); + labels.push( + , + ); + } + } + + d = !d; + a++; + } + + project.timeline.labels.set(labels); + + requestAnimationFrame(draw); + } + draw(); + + function onresize() { + var size = document.querySelector('.timeline .timelineInner'); + canvas.width = size.clientWidth; + canvas.height = size.clientHeight; + } + onresize(); + window.addEventListener('resize', onresize); + }, []); + + // timeline scrubber + var scrubberDragRef = useRef(null); + var [scrubberPos, scrubberSpring] = useSpring( + () => ({ + frame: 0, + config: { mass: 0.5, tension: 500, friction: 20 }, + }), + ); + useDrag(({ xy: [x, _y] }) => { + var frame = Math.max(0, Math.round(getFrameAtOffset(x - 240, project.timeline.zoom.value)) - 1); + scrubberSpring.start({ frame }); + if (player.player) { + var time = player.frameToTimestamp(frame + 1); + if (isFinite(time)) player.player.currentTime = time; + } + project.timeline.frame.set(frame); + }, { domTarget: scrubberDragRef, eventOptions: { passive: false } }); + + // slide placement ghost + var [ghost, ghostApi] = useSpring(() => ({ + x: 0, + y: 0, + config: { mass: 0.5, tension: 500, friction: 20 }, + })); + useEffect(() => { + document.querySelector('.timeline').addEventListener('mousemove', (e: MouseEvent) => { + var rect = document.querySelector('.timeline').getBoundingClientRect(); + var x = e.clientX - rect.left; + var y = e.clientY - rect.top; + ghostApi.start({ x, y }); + }); + }, []); + return
{workingTimeline.value.map(slide => )} -
} - /> +
-- cgit v1.2.3