Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ yarn-debug.log*
yarn-error.log*
lerna-debug.log*
packages/sensebee_frontend/
.codegraph/
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface IVideoClipToolContext {
clipStatus: EClipStatus;
selectedAttribute?: string;
contextToCancel?: (e: any) => void;
selectTimeSliceByTime?: (time: number) => void;
}

export const VideoClipToolContext = React.createContext<IVideoClipToolContext>({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const ToolTipForClip = (props: {
<div>{`${t('textTool')}:${textAttribute}`}</div>
</div>
);
return <Tooltip title={title}>{slot}</Tooltip>;
return <Tooltip title={title} placement="leftTop">{slot}</Tooltip>;
};

export default ToolTipForClip;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { timeFormat } from '@/utils/audio';
import { IVideoTimeSlice } from '@labelbee/lb-utils';
import { classnames } from '@/utils';
import { EnvironmentFilled, ScissorOutlined, CloseCircleFilled } from '@ant-design/icons';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { EClipStatus, ETimeSliceType, TIME_SLICE_TYPE } from '../../constant';
import TimeSliceRange from '../timeSliceRange';
import ToolTipForClip from '../ToolTipForClip';
Expand Down Expand Up @@ -51,11 +51,18 @@ const EmptyVideoClipAnnotatedList = () => {
* 标注列表包裹组件,无内容时渲染 EmptyVideoClipAnnotatedList
* @returns
*/
const VideoClipAnnotatedListWrapper = ({ children }: { children: any }) => {
const VideoClipAnnotatedListWrapper = ({
children,
scrollRef,
}: {
children: any;
scrollRef?: React.Ref<HTMLDivElement>;
}) => {
const isEmpty = children.length === 0;

return (
<div
ref={scrollRef}
className={classnames({
[styles.empty]: isEmpty,
[styles.timeSliceListContent]: true,
Expand All @@ -70,12 +77,14 @@ const VideoClipAnnotatedItem = ({
timeSliceProps,
index,
exportContext,
onItemClick,
}: {
timeSliceProps: IVideoTimeSlice;
index: number;
exportContext: any,
exportContext: any;
onItemClick: (timeSliceProps: IVideoTimeSlice) => void;
}) => {
const { selectedID, attributeList, onSelectedTimeSlice, removeTimeSlice } = exportContext
const { selectedID, attributeList, removeTimeSlice } = exportContext;

return (
<div
Expand All @@ -85,7 +94,7 @@ const VideoClipAnnotatedItem = ({
[styles.timeSliceItemActivated]: timeSliceProps.id === selectedID,
})}
onClick={() => {
onSelectedTimeSlice(timeSliceProps);
onItemClick(timeSliceProps);
}}
>
<ToolTipForClip
Expand Down Expand Up @@ -138,6 +147,8 @@ const VideoClipAnnotatedList = (props: { toolInstance: any }) => {
const { selectedID, result, videoPlayer, clipStatus, updateSelectedSliceTimeProperty } = toolInstance?.exportContext || {}

const [_, forceRender] = useState(0);
const listRef = useRef<HTMLDivElement>(null);
const skipScrollRef = useRef(false);
const { t } = useTranslation();

useEffect(() => {
Expand All @@ -154,19 +165,42 @@ const VideoClipAnnotatedList = (props: { toolInstance: any }) => {
const selectedTimeSlice = result?.find((i: any) => i.id === selectedID);
const resultList = result?.filter((i: any) => i.end !== null);

const handleItemClick = (timeSliceProps: IVideoTimeSlice) => {
skipScrollRef.current = true;
toolInstance.exportContext.onSelectedTimeSlice(timeSliceProps);
};

useLayoutEffect(() => {
if (!selectedID || !listRef.current) {
return;
}
if (skipScrollRef.current) {
skipScrollRef.current = false;
return;
}
const list = toolInstance?.exportContext?.result?.filter(
(i: IVideoTimeSlice) => i.end !== null,
);
const index = list?.findIndex((i: IVideoTimeSlice) => i.id === selectedID);
if (index >= 0) {
listRef.current.children[index]?.scrollIntoView({ block: 'nearest' });
}
}, [selectedID, _, toolInstance]);

if (!toolInstance?.exportContext) {
return null
}
return (
<div>
<div className={styles.timeSliceListHeader}>{t('AnnotatedList')}</div>
<VideoClipAnnotatedListWrapper>
<VideoClipAnnotatedListWrapper scrollRef={listRef}>
{resultList?.map((timeSliceProps: IVideoTimeSlice, index: number) => (
<VideoClipAnnotatedItem
timeSliceProps={timeSliceProps}
index={index}
key={timeSliceProps.id}
exportContext={toolInstance?.exportContext || {}}
onItemClick={handleItemClick}
/>
))}
</VideoClipAnnotatedListWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,45 @@ class VideoClipTool extends React.Component<IVideoClipProps, IState> {
this.setState({
currentTime: time,
});
this.selectTimeSliceByTime(time);
};

/** 根据时间查找片段 */
public findTimeSliceByTime = (time: number): IVideoTimeSlice | undefined => {
const t = decimalReserved(time, 2);
return this.state.result.find((item) => {
if (item.end === null) {
return false;
}
if (item.type === ETimeSliceType.Time) {
return decimalReserved(item.start, 2) === t;
}
return item.start <= t && t < item.end;
});
};

/** 根据时间选中片段(不 seek、不 pause) */
public selectTimeSliceByTime = (time: number) => {
if (this.isClipping) {
return;
}
const slice = this.findTimeSliceByTime(time);
if (slice) {
if (slice.id === this.state.selectedID) {
return;
}
this.setState({
selectedID: slice.id,
selectedAttribute: slice.attribute,
textValue: slice.textAttribute,
});
} else {
if (!this.state.selectedID) {
return;
}
this.setState({ selectedID: '' });
}
this.updateSidebar();
};

/**
Expand Down Expand Up @@ -810,6 +849,7 @@ class VideoClipTool extends React.Component<IVideoClipProps, IState> {
clipStatus,
selectedAttribute,
contextToCancel: this.contextToCancel,
selectTimeSliceByTime: this.selectTimeSliceByTime,
}}
>
{this.renderMediaContent()}
Expand Down
9 changes: 3 additions & 6 deletions packages/lb-components/src/components/videoPlayer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const VideoPlayerCtx = React.createContext<{
toggleClipStatus: () => {},
});

const PER_INTERVAL = 50;
const PER_INTERVAL = 300;
const PER_FORWARD = 0.1;
const PLAYBACK_RATES = [0.1, 0.2, 0.3, 0.4, 0.5, 1, 1.5, 2, 4, 6, 8, 16];

Expand Down Expand Up @@ -221,12 +221,9 @@ export class VideoPlayer extends React.Component<IVideoPlayerProps, IVideoPlayer
try {
if (this.videoElm?.buffered.length > 0) {
const buffered = this.videoElm?.buffered.end(0);

this.setState({
currentTime: decimalReserved(this.videoElm?.currentTime, 1),
buffered,
});
this.setState({ buffered });
}
this.props.updateCurrentTime?.(decimalReserved(this.videoElm?.currentTime, 1));
} catch (error) {
console.error(error);
}
Expand Down
Loading