mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 10:31:46 +00:00
housekeeping, fix scrubber width math
This commit is contained in:
1 parent
894514961c
commit
b17f868db2
8 files changed
+109
-113
No files matched your search
+16
-14
@@ -8,7 +8,7 @@ import {
|
||||
Action,
|
||||
ACTION_TYPES,
|
||||
} from '../reducer';
|
||||
import { QuickTrimData } from '../types';
|
||||
import { QuickTrimData } from '../utilities';
|
||||
import { TrimScrubber } from './TrimScrubber';
|
||||
|
||||
export const ProgressBar = memo(({
|
||||
@@ -46,9 +46,9 @@ export const ProgressBar = memo(({
|
||||
}else{
|
||||
// console.log(node);
|
||||
}
|
||||
}, []);
|
||||
}, [dispatchCompState]);
|
||||
|
||||
function handleWindowResize() {
|
||||
const handleWindowResize = useCallback(()=> {
|
||||
if (playbarRef.current !== null && readyToMount){
|
||||
dispatchCompState({
|
||||
type: ACTION_TYPES.SET_PLAYBAR_LAYOUT,
|
||||
@@ -57,13 +57,13 @@ export const ProgressBar = memo(({
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},[dispatchCompState, readyToMount]);
|
||||
useLayoutEffect(() => {
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleWindowResize);
|
||||
};
|
||||
}, []);
|
||||
}, [handleWindowResize]);
|
||||
|
||||
if(readyToMount){
|
||||
// console.log('progress bar rendering');
|
||||
@@ -72,18 +72,20 @@ export const ProgressBar = memo(({
|
||||
<div className="playbar-bg" />
|
||||
<TrimScrubber
|
||||
// key={trimReset}
|
||||
boundingWidth={playbarWidth-scrubberWidth}
|
||||
boundingWidth={playbarWidth}
|
||||
scrubberWidth={scrubberWidth}
|
||||
trimStart={trimStartSeconds}
|
||||
trimStartSeconds={trimStartSeconds}
|
||||
trimDuration={trimDuration}
|
||||
duration={videoDuration}
|
||||
videoDuration={videoDuration}
|
||||
onChange={(val: QuickTrimData)=>{
|
||||
console.log(val);
|
||||
// setTrimState((curr)=>({
|
||||
// ...curr,
|
||||
// trimStart: val.trimStartSeconds,
|
||||
// trimEnd: val.trimEndSeconds
|
||||
// }))
|
||||
|
||||
dispatchCompState({
|
||||
type: ACTION_TYPES.MOVE_TRIM,
|
||||
payload: {
|
||||
trimStartSeconds: val.trimStartSeconds,
|
||||
trimEndSeconds: val.trimEndSeconds
|
||||
}
|
||||
});
|
||||
// onSelect({
|
||||
// trimStartSeconds: val.trimStartSeconds,
|
||||
// trimEndSeconds: val.trimEndSeconds,
|
||||
|
||||
+18
-19
@@ -1,51 +1,50 @@
|
||||
import React, {
|
||||
memo,
|
||||
useMemo,
|
||||
useCallback
|
||||
} from 'react';
|
||||
import {
|
||||
faGripDots
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { QuickTrimData } from '../types';
|
||||
import { QuickTrimData } from '../utilities';
|
||||
import {withScrubbing, withScrubbingPropsI} from './withScrubbing';
|
||||
|
||||
interface TrimScrubberPropsI extends withScrubbingPropsI {
|
||||
trimStart:number;
|
||||
trimStartSeconds:number;
|
||||
trimDuration: number;
|
||||
duration: number;
|
||||
videoDuration: number;
|
||||
onChange:(val:QuickTrimData)=>void
|
||||
}
|
||||
export const TrimScrubber = memo(({
|
||||
trimStart,
|
||||
trimStartSeconds,
|
||||
trimDuration,
|
||||
duration,
|
||||
videoDuration,
|
||||
onChange,
|
||||
...rest
|
||||
}:TrimScrubberPropsI)=>{
|
||||
// console.log(`TrimsSrubber reRender!! ${Date.now()}`);
|
||||
const TrimScrubberWithScrubbing =
|
||||
useMemo(()=>withScrubbing<TrimScrubberPropsI>(() => {
|
||||
return(
|
||||
<div className="trim-scrubber">
|
||||
<FontAwesomeIcon icon={faGripDots} />
|
||||
</div>
|
||||
);
|
||||
}), []);
|
||||
|
||||
const TrimScrubberWithScrubbing = withScrubbing<TrimScrubberPropsI>(() => {
|
||||
return(
|
||||
<div className="trim-scrubber">
|
||||
<FontAwesomeIcon icon={faGripDots} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const handleOnChange = useCallback((posPercent:number)=>{
|
||||
console.log(`handle on moving trim scrubber, pos%=${posPercent}`);
|
||||
onChange({
|
||||
trimStartSeconds: duration * posPercent,
|
||||
trimEndSeconds: duration * posPercent + trimDuration,
|
||||
trimStartSeconds: videoDuration * posPercent,
|
||||
trimEndSeconds: videoDuration * posPercent + trimDuration,
|
||||
});
|
||||
}, [onChange, duration, trimDuration]);
|
||||
}, [onChange, videoDuration, trimDuration]);
|
||||
|
||||
return (
|
||||
<TrimScrubberWithScrubbing
|
||||
styleOverride={{
|
||||
top: '-1rem',
|
||||
}}
|
||||
initialLeftOffsetPercent={trimStart/trimDuration}
|
||||
initialLeftOffsetPercent={trimStartSeconds/videoDuration}
|
||||
onScrubEnds={handleOnChange}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
+53
-52
@@ -1,8 +1,9 @@
|
||||
import React,{
|
||||
// useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useLayoutEffect,
|
||||
useCallback,
|
||||
// useCallback,
|
||||
} from 'react';
|
||||
|
||||
export interface withScrubbingPropsI {
|
||||
@@ -34,14 +35,17 @@ export const withScrubbing = <P extends withScrubbingPropsI>(Component: React.Co
|
||||
onScrubChanges,
|
||||
...rest
|
||||
}: withScrubbingPropsI) => {
|
||||
console.log(`withScrubbing reRender!! ${Date.now()}`);
|
||||
// console.log(`withScrubbing reRender!! ${Date.now()}`);
|
||||
const refEl = useRef<HTMLDivElement| null>(null);
|
||||
const refListener = useRef<number>(Date.now());
|
||||
|
||||
const initialLeftOffset =
|
||||
initialLeftOffsetPercent > 0 ? boundingWidth * initialLeftOffsetPercent
|
||||
: initialLeftOffsetProps;
|
||||
// const initialLeftOffset = 0;
|
||||
const [{
|
||||
key, currLeftOffset, pointerStartPos
|
||||
// key,
|
||||
currLeftOffset, pointerStartPos,
|
||||
// prevLeftOffset,
|
||||
}, setStates] = useState<withSrcubbingStates>({
|
||||
key: Date.now(),
|
||||
@@ -50,67 +54,64 @@ export const withScrubbing = <P extends withScrubbingPropsI>(Component: React.Co
|
||||
pointerStartPos: -1 // negative denotes pointer not engaged
|
||||
});
|
||||
|
||||
const handleScrubStart = useCallback( (e: MouseEvent) => {
|
||||
if(refEl.current){
|
||||
console.log(`start: ${e.clientX}` );
|
||||
if(refEl.current.contains(e.target as Node)){
|
||||
setStates((curr)=>({
|
||||
...curr,
|
||||
pointerStartPos: e.clientX
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},[]);
|
||||
const handleScrubEnd = useCallback((e: MouseEvent)=>{
|
||||
// e.persist();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setStates((curr)=>({
|
||||
...curr,
|
||||
pointerStartPos: -1,
|
||||
prevLeftOffset: curr.currLeftOffset,
|
||||
}));
|
||||
// if (onScrubEnds) onScrubEnds(currLeftOffset/boundingWidth);
|
||||
}, []);
|
||||
const handleScrubMove = useCallback ((e: MouseEvent)=>{
|
||||
// e.persist();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setStates((curr)=>{
|
||||
if(curr.pointerStartPos >= 0 && curr.pointerStartPos!==null){
|
||||
let newLeftOffset = curr.prevLeftOffset + e.clientX - curr.pointerStartPos;
|
||||
if (newLeftOffset + scrubberWidth > boundingWidth) {
|
||||
newLeftOffset = boundingWidth - scrubberWidth;
|
||||
}else if(newLeftOffset < 0) {
|
||||
newLeftOffset = 0;
|
||||
}
|
||||
if(newLeftOffset !== curr.currLeftOffset){
|
||||
return{
|
||||
useLayoutEffect(() => {
|
||||
function handleScrubStart (e: MouseEvent) {
|
||||
if(refEl.current){
|
||||
if(refEl.current.contains(e.target as Node)){
|
||||
setStates((curr)=>({
|
||||
...curr,
|
||||
currLeftOffset: newLeftOffset
|
||||
pointerStartPos: e.clientX
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
function handleScrubEnd (e: MouseEvent){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setStates((curr)=>({
|
||||
...curr,
|
||||
pointerStartPos: -1,
|
||||
prevLeftOffset: curr.currLeftOffset,
|
||||
}));
|
||||
};
|
||||
function handleScrubMove (e: MouseEvent){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setStates((curr)=>{
|
||||
if(curr.pointerStartPos >= 0 && curr.pointerStartPos!==null){
|
||||
let newLeftOffset = curr.prevLeftOffset + e.clientX - curr.pointerStartPos;
|
||||
if (newLeftOffset + scrubberWidth > boundingWidth) {
|
||||
newLeftOffset = boundingWidth - scrubberWidth;
|
||||
}else if(newLeftOffset < 0) {
|
||||
newLeftOffset = 0;
|
||||
}
|
||||
if(newLeftOffset !== curr.currLeftOffset){
|
||||
return{
|
||||
...curr,
|
||||
currLeftOffset: newLeftOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return curr;
|
||||
});
|
||||
// if (onScrubChanges) onScrubChanges(newLeftOffset/boundingWidth);
|
||||
},[scrubberWidth, boundingWidth]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if(!(window as any)[`listener-id-${key}`]){
|
||||
(window as any)[`listender-id-${key}`] = true;
|
||||
return curr;
|
||||
});
|
||||
};
|
||||
if(!(window as any)[`listener-id-${refListener}`]){
|
||||
(window as any)[`listender-id-${refListener}`] = true;
|
||||
window.addEventListener("mousedown", handleScrubStart);
|
||||
window.addEventListener("mouseup", handleScrubEnd);
|
||||
window.addEventListener("mousemove", handleScrubMove);
|
||||
return () => {
|
||||
(window as any)[`${key}listeners`] = false;
|
||||
(window as any)[`listener-id-${refListener}`] = false;
|
||||
window.removeEventListener("mousedown", handleScrubStart);
|
||||
window.removeEventListener("mouseup", handleScrubEnd);
|
||||
window.removeEventListener("mousemove", handleScrubMove);
|
||||
};
|
||||
}
|
||||
}, [handleScrubStart, handleScrubEnd, handleScrubMove, key]);
|
||||
}, []);
|
||||
// useEffect(()=>{
|
||||
// if(onScrubEnds)onScrubEnds(prevLeftOffset/boundingWidth);
|
||||
// },[prevLeftOffset, boundingWidth, onScrubEnds]);
|
||||
return(
|
||||
<div
|
||||
className="scrubber-wrapper"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {VideoQuickTrim} from './VideoQuickTrim'
|
||||
import { QuickTrimData } from './types';
|
||||
import { QuickTrimData } from './utilities';
|
||||
|
||||
export type { QuickTrimData };
|
||||
export default VideoQuickTrim;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TRIM_OPTIONS } from "./utilities";
|
||||
import { MIN_VID_DURATION, TIME_CURSOR_WIDTH, TRIM_OPTIONS } from "./utilities";
|
||||
|
||||
export enum STATE_STATUSES {
|
||||
INIT = "init",
|
||||
@@ -62,6 +62,7 @@ export enum ACTION_TYPES {
|
||||
SET_PLAYPUASE = "set_playpause",
|
||||
SET_PLAYBAR_LAYOUT = "set_playbar_layout",
|
||||
SET_TRIM_DURATION = "set_trim_duration",
|
||||
MOVE_TRIM = "move_trim"
|
||||
}
|
||||
|
||||
export type Action =
|
||||
@@ -73,13 +74,16 @@ export type Action =
|
||||
| {type: ACTION_TYPES.SET_PLAYPUASE, payload:{ playpause: string}}
|
||||
| {type: ACTION_TYPES.SET_PLAYBAR_LAYOUT, payload:{ playbarWidth: number}}
|
||||
| {type: ACTION_TYPES.SET_TRIM_DURATION, payload:{ trimDurationString: string}}
|
||||
| {type: ACTION_TYPES.MOVE_TRIM, payload:{
|
||||
trimStartSeconds: number,
|
||||
trimEndSeconds: number,
|
||||
}}
|
||||
;
|
||||
|
||||
export function reducer(state: State, action: Action): State {
|
||||
console.log("VideoQuickTrim State Dispatch");
|
||||
console.log(action);
|
||||
const timeCursorWidth = 8;
|
||||
const minVideoDuration = 3;
|
||||
|
||||
switch(action.type){
|
||||
case ACTION_TYPES.SET_PLAYPUASE:{
|
||||
return {...state, ...action.payload};
|
||||
@@ -91,7 +95,7 @@ export function reducer(state: State, action: Action): State {
|
||||
return {...state, isMuted: !state.isMuted}
|
||||
}
|
||||
case ACTION_TYPES.ON_LOADED_METADATA:{
|
||||
if(action.payload.videoDuration >= minVideoDuration){
|
||||
if(action.payload.videoDuration >= MIN_VID_DURATION){
|
||||
return{
|
||||
...state,
|
||||
status: STATE_STATUSES.VIDEO_METADATA_LOADED,
|
||||
@@ -119,7 +123,7 @@ export function reducer(state: State, action: Action): State {
|
||||
playpause: PLAYPUASE_STATES.READY,
|
||||
playbarWidth: newWidth,
|
||||
scrubberWidth: newWidth * (state.trimDuration / state.videoDuration),
|
||||
timeCursorOffset: (newWidth-timeCursorWidth)*(prevOffset/ state.videoDuration)
|
||||
timeCursorOffset: (newWidth-TIME_CURSOR_WIDTH)*(prevOffset/ state.videoDuration)
|
||||
};
|
||||
}else{
|
||||
return{
|
||||
@@ -164,6 +168,13 @@ export function reducer(state: State, action: Action): State {
|
||||
}
|
||||
}
|
||||
}
|
||||
case ACTION_TYPES.MOVE_TRIM:{
|
||||
return{
|
||||
...state,
|
||||
trimStartSeconds: action.payload.trimStartSeconds,
|
||||
trimEndSeconds: action.payload.trimEndSeconds,
|
||||
}
|
||||
}
|
||||
case ACTION_TYPES.MOVE_TIMECURSOR:{
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
//For integration into other components
|
||||
export type QuickTrimData = {
|
||||
trimStartSeconds: number;
|
||||
trimEndSeconds: number;
|
||||
}
|
||||
|
||||
// INTERNALS
|
||||
export type TrimStates = {
|
||||
canNotTrim: boolean;
|
||||
trimReset: number;
|
||||
trimDuration: number;
|
||||
trimStart: number;
|
||||
trimEnd: number;
|
||||
maxDuration: number;
|
||||
}
|
||||
|
||||
export type PlaybarStates = {
|
||||
playbarWidth: number;
|
||||
timeCursorOffset: number;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
//For integration into other components
|
||||
export const TIME_CURSOR_WIDTH = 8;
|
||||
export const MIN_VID_DURATION = 3;
|
||||
|
||||
export type QuickTrimData = {
|
||||
trimStartSeconds: number;
|
||||
trimEndSeconds: number;
|
||||
|
||||
@@ -23,13 +23,13 @@ export default function ComponentSandbox(
|
||||
/>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
{/* <br/>
|
||||
<div className="m-4">
|
||||
<VideoQuickTrim
|
||||
onSelect={handleCallback}
|
||||
mediaToken='m_h21nykes0j3ph23y5z7w9axtjjn2rr'
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
</Panel>
|
||||
</Container>);
|
||||
}
|
||||
Reference in new issue
Block a user