From d421bb6559874a345f8aedba2c8d7686223ee932 Mon Sep 17 00:00:00 2001
From: lgf <18827634408@163.com>
Date: Thu, 19 Aug 2021 21:07:33 +0800
Subject: [PATCH] complete
---
src/appComponent.tsx | 1 +
src/components/screenshot/index.module.scss | 36 ++
src/components/screenshot/index.tsx | 23 +
src/core/controller/index.tsx | 124 +++--
src/core/controls/index.tsx | 533 ++++++++++----------
src/core/index.tsx | 9 +-
src/core/progress/index.tsx | 2 +-
src/icons/svg/close.svg | 1 +
src/interface/index.ts | 24 +
src/utils/index.ts | 11 +
10 files changed, 451 insertions(+), 313 deletions(-)
create mode 100644 src/components/screenshot/index.module.scss
create mode 100644 src/components/screenshot/index.tsx
create mode 100644 src/icons/svg/close.svg
diff --git a/src/appComponent.tsx b/src/appComponent.tsx
index cab5007..8d37f9c 100644
--- a/src/appComponent.tsx
+++ b/src/appComponent.tsx
@@ -79,6 +79,7 @@ const AppComponent = memo(function AppComponent(props) {
width: 750,
height: 420,
theme: '#00D3FF',
+ isShowMultiple: false,
poster: 'https://cdn.gudsen.com/2021/06/28/f81356b08b4842d7a3719499f557c8e4.JPG',
}}
onProgressMouseDown={onProgressMouseDown}
diff --git a/src/components/screenshot/index.module.scss b/src/components/screenshot/index.module.scss
new file mode 100644
index 0000000..3e64bdb
--- /dev/null
+++ b/src/components/screenshot/index.module.scss
@@ -0,0 +1,36 @@
+@import 'src/assets/css/mixin.scss';
+.screenshot {
+ width: 280px;
+ @include position(absolute, auto, 0, 55px, auto);
+ background: #fff;
+ padding: 3px;
+ overflow: hidden;
+ .img {
+ height: 155px;
+ overflow: hidden;
+ position: relative;
+ canvas {
+ @include position(absolute, 50%, auto, auto, 50%);
+ transform: translate(-50%, -50%);
+ }
+ }
+ .close {
+ @include position(absolute, -24px, -24px, auto, auto);
+ @include wh(0, 0);
+ z-index: 1;
+ border: 26px solid transparent;
+ border-left-color: #fff;
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ border-radius: 100%;
+ .icon {
+ @include position(absolute, -8px, 5px, auto, auto);
+ transform: rotate(45deg);
+ cursor: pointer;
+ }
+ }
+ .save {
+ padding: 10px;
+ text-align: center;
+ }
+}
diff --git a/src/components/screenshot/index.tsx b/src/components/screenshot/index.tsx
new file mode 100644
index 0000000..a60b1b6
--- /dev/null
+++ b/src/components/screenshot/index.tsx
@@ -0,0 +1,23 @@
+import React, { memo, FC } from 'react';
+import style from './index.module.scss';
+import Broadcast from '@/components/svgIcon';
+const Index: FC<{
+ setIsscreenshot: Function;
+ screenshotLoading: boolean;
+}> = memo(function Index({ setIsscreenshot, screenshotLoading }) {
+ return (
+
+
setIsscreenshot(false)}>
+
+
+
+
+
+
+ {screenshotLoading ? '截图加载失败,在点击下' : '鼠标右键图片另存为'}
+
+
+ );
+});
+
+export default Index;
diff --git a/src/core/controller/index.tsx b/src/core/controller/index.tsx
index 3dd64eb..1562b62 100644
--- a/src/core/controller/index.tsx
+++ b/src/core/controller/index.tsx
@@ -1,17 +1,14 @@
-import React, { memo, useContext, useRef, useState, useMemo } from 'react';
+import React, { memo, useContext, useRef, useMemo, useEffect, useState } from 'react';
import Broadcast from '@/components/svgIcon';
import Progress from '../progress';
import Controls from '../controls';
import { FlowContext } from '@/core/context';
import { useVideo } from '@/core/useVideo';
-import useWindowClient from '@/utils/useWindowClient';
-import usePrevious from '@/utils/usePrevious';
import EndComponent from '@/components/end';
+import Screenshot from '@/components/screenshot';
import './index.scss';
-const Index = memo(function Index(props) {
- const { clientX } = useWindowClient();
-
+const Index = memo(function Index() {
const reviceProps = useContext(FlowContext);
const { dispatch, propsAttributes } = reviceProps;
@@ -25,57 +22,72 @@ const Index = memo(function Index(props) {
const timer = useRef(null!);
- const viewClientX = useRef(null!);
-
- const prevCalculation = useRef(null!);
-
const controllerRef = useRef(null!);
- const [pre, setPre] = useState(0);
-
- viewClientX.current = clientX;
-
/**
- * @description 返回上一次的记录值
+ * @description 检查器,检查鼠标是否移动
*/
- prevCalculation.current = usePrevious(pre) as number;
+ const userActivity = useRef(false);
+ const inactivityTimeout = useRef(null!);
/**
- * @description 显示操作控件
+ * @description 是否在控制器上
*/
- const showControl = (e: any, status: string) => {
- dispatch!({ type: 'isControl', data: status === 'enter' && !isEndEd ? true : false });
- };
- /**
- * @description 隐藏鼠标
- */
- const hiddleCursor = () => {
- if (timer.current) {
- clearInterval(timer.current);
- }
+ const isControlsContainerMove = useRef(false);
+
+ const [isScreenshot, setIsscreenshot] = useState(false);
+
+ const [screenshotLoading, setScreenshotLoading] = useState(false);
+
+ useEffect(() => {
timer.current = setInterval(() => {
- setPre(viewClientX.current);
- /**
- * @description 如果在1200ms没有任何操作的话,就隐藏控件和鼠标
- */
- if (viewClientX.current! !== prevCalculation.current) {
+ if (userActivity.current) {
+ /**
+ * @description 重置
+ */
+ userActivity.current = false;
dispatch!({ type: 'isControl', data: true });
controllerRef.current.style.cursor = 'pointer';
- } else {
- dispatch!({ type: 'isControl', data: false });
- controllerRef.current.style.cursor = 'none';
+ inactivityTimeout.current && clearTimeout(inactivityTimeout.current);
+ inactivityTimeout.current = setTimeout(
+ () => {
+ /**
+ * @note 当鼠标移动在控制器Controls上时,这个时候,鼠标不能隐藏
+ */
+ if (!userActivity.current && !isControlsContainerMove.current) {
+ dispatch!({ type: 'isControl', data: false });
+ controllerRef.current.style.cursor = 'none';
+ }
+ },
+ propsAttributes!.hideMouseTime ? propsAttributes!.hideMouseTime : 2000,
+ );
}
- }, 1200);
- };
- const clearTimer = () => {
- controllerRef.current.style.cursor = 'pointer';
- if (timer.current) {
- clearInterval(timer.current);
- }
+ }, 200);
+ return () => {
+ timer.current && clearInterval(timer.current);
+ };
+ }, []);
+
+ /**
+ * @description 显示操作控件
+ */
+ const showControl = (status: string) => {
+ dispatch!({ type: 'isControl', data: status === 'enter' && !isEndEd ? true : false });
};
const handlePlay = () => {
handleChangePlayState && handleChangePlayState();
};
+ const mouseMove: React.MouseEventHandler = (e) => {
+ userActivity.current = true;
+ /**
+ * @note 这个时候要将控制器区设置为false,此时鼠标在播放器,如果不设置为false,会造成移出不能隐藏控制器的bug
+ */
+ isControlsContainerMove.current = false;
+ };
+ const leaveMove: React.MouseEventHandler = (e) => {
+ userActivity.current = false;
+ controllerRef.current.style.cursor = 'pointer';
+ };
/**
* @description 暂停键的位置
*/
@@ -93,18 +105,25 @@ const Index = memo(function Index(props) {
};
}
}, [propsAttributes!.pausePlacement]);
+ /**
+ * @param status 鼠标状态
+ * @description 控制器容器鼠标操作
+ */
+ const controlsContainerMove = (status: string) => {
+ isControlsContainerMove.current = status === 'move' ? true : false;
+ };
return (
showControl(e, 'enter')}
- onMouseLeave={(e) => showControl(e, 'leave')}
+ onMouseEnter={(e) => [showControl('enter')]}
+ onMouseLeave={(e) => [showControl('leave'), e.stopPropagation()]}
ref={controllerRef}
>
{!isPlay && !isEndEd && (
@@ -116,15 +135,22 @@ const Index = memo(function Index(props) {
style={pausePosition}
/>
)}
-
+
[controlsContainerMove('move')]}
+ onMouseLeave={(e) => [controlsContainerMove('leave')]}
+ >
+ {isScreenshot ? (
+
+ ) : null}
-
+
{isEndEd ? (
propsAttributes!.setEndPlayContent ? (
propsAttributes!.setEndPlayContent
) : (
-
[handleChangePlayState(), hiddleCursor()]} />
+ [handleChangePlayState(), showControl('enter')]} />
)
) : null}
diff --git a/src/core/controls/index.tsx b/src/core/controls/index.tsx
index e10b605..b0ab998 100644
--- a/src/core/controls/index.tsx
+++ b/src/core/controls/index.tsx
@@ -1,9 +1,9 @@
-import React, { memo, useContext, useRef, useEffect, useMemo, useCallback } from 'react';
+import React, { memo, useContext, useRef, useEffect, useMemo, FC } from 'react';
import Broadcast from '@/components/svgIcon';
import Tooltip from '@/components/tooltip';
-import { FlowContext } from '@/core/context';
+import { contextType, FlowContext } from '@/core/context';
import { useVideo } from '@/core/useVideo';
-import { secondsToMinutesAndSecondes, createALabel } from '@/utils';
+import { secondsToMinutesAndSecondes, capture } from '@/utils';
import { useControls } from './variable';
import useWindowClient from '@/utils/useWindowClient';
import screenfull, { Screenfull } from 'screenfull';
@@ -14,286 +14,295 @@ import VolumeComponent from './volume';
import MonitorComponent from './monitor';
import './index.scss';
-const Index = memo(function Index(props) {
- /**
- * @description 音量滑动元素
- */
- const volumeSliderMirror = useRef
(null!);
+const Index: FC<{ setIsscreenshot: Function; setScreenshotLoading: Function }> = memo(
+ function Index({ setIsscreenshot, setScreenshotLoading }) {
+ /**
+ * @description 音量滑动元素
+ */
+ const volumeSliderMirror = useRef(null!);
- const clientYdistance = useRef(0);
+ const clientYdistance = useRef(0);
- const volumeInterval = useRef(null);
+ const volumeInterval = useRef(null);
- const reviceProps = useContext(FlowContext);
+ const reviceProps = useContext(FlowContext);
- const revicePropsData = useRef();
+ const { propsAttributes } = reviceProps!;
- const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture, volume } =
- useVideo(
- {
- videoElement: reviceProps.videoRef,
- },
- [reviceProps.videoRef],
- );
+ const revicePropsData = useRef();
- const { controlsState, dispatch } = useControls();
+ const { isPlay, handleChangePlayState, currentTime, duration, isPictureinpicture, volume } =
+ useVideo(
+ {
+ videoElement: reviceProps.videoRef,
+ },
+ [reviceProps.videoRef],
+ );
- const { clientY } = useWindowClient();
+ const { controlsState, dispatch } = useControls();
- clientYdistance.current = clientY;
+ const { clientY } = useWindowClient();
- revicePropsData.current = reviceProps;
+ clientYdistance.current = clientY;
- useEffect(() => {
- /**
- * @description 如果调用了setVolume函数,这边的数据就要保持和video的数据一致
- */
- dispatch({ type: 'volume', data: Math.floor(volume * 100) });
- }, [volume]);
+ revicePropsData.current = reviceProps;
- useEffect(() => {
- // 为了防止音量滑动元素计时器不暂停
- window.addEventListener('mouseup', whenMouseUpDo);
- return () => {
- window.removeEventListener('mouseup', whenMouseUpDo);
- };
- }, []);
+ useEffect(() => {
+ /**
+ * @description 如果调用了setVolume函数,这边的数据就要保持和video的数据一致
+ */
+ dispatch({ type: 'volume', data: Math.floor(volume * 100) });
+ }, [volume]);
- /**
- * @description 更新当前音量控制条
- */
- const updateCurrentVolume = (volumePercent: number) => {
- const videoRef = reviceProps.videoRef!;
- if (volumePercent >= 0 && volumePercent <= 1) {
- videoRef.volume = volumePercent;
- videoRef.muted = false;
- dispatch({ type: 'volume', data: volumePercent * 100 });
- dispatch({ type: 'isMuted', data: Math.floor(volumePercent * 100) === 0 ? true : false });
- }
- if (volumePercent < 0) {
- videoRef.volume = 0;
- videoRef.muted = true;
- dispatch({ type: 'volume', data: 0 });
- dispatch({ type: 'isMuted', data: true });
- }
- if (volumePercent > 1) {
- videoRef.volume = 1;
- dispatch({ type: 'volume', data: 100 });
- }
- };
- /**
- *
- * @param e event对象
- * @description 音量滑动元素点击
- */
- const changeCurrentVolume: React.MouseEventHandler = (e) => {
- e.stopPropagation();
- const volumeSliderMirrorElement = (
- volumeSliderMirror.current as HTMLDivElement & { element: HTMLDivElement }
- ).element;
- // 获取音量区域高度
- const volumeAreaHeight = volumeSliderMirrorElement.offsetHeight;
- // 获取当前位置在整个音量区域高度的占比
- const volumePercent =
- 1 - (e.clientY - volumeSliderMirrorElement.getBoundingClientRect().top) / volumeAreaHeight;
- // 修改当前音量大小
- updateCurrentVolume(volumePercent);
- };
+ useEffect(() => {
+ // 为了防止音量滑动元素计时器不暂停
+ window.addEventListener('mouseup', whenMouseUpDo);
+ return () => {
+ window.removeEventListener('mouseup', whenMouseUpDo);
+ };
+ }, []);
- const slideCurrentVolume: React.MouseEventHandler = (e) => {
- e.stopPropagation();
- const volumeSliderMirrorElement = (
- volumeSliderMirror.current as HTMLDivElement & { element: HTMLDivElement }
- ).element;
- // 获取音量区域高度
- const volumeAreaHeight = volumeSliderMirrorElement.offsetHeight;
- // 防止点击的时候,再次出发计时器,重而造成点击卡顿
- volumeInterval.current && clearInterval(volumeInterval.current);
- volumeInterval.current = setInterval(() => {
+ /**
+ * @description 更新当前音量控制条
+ */
+ const updateCurrentVolume = (volumePercent: number) => {
+ const videoRef = reviceProps.videoRef!;
+ if (volumePercent >= 0 && volumePercent <= 1) {
+ videoRef.volume = volumePercent;
+ videoRef.muted = false;
+ dispatch({ type: 'volume', data: volumePercent * 100 });
+ dispatch({ type: 'isMuted', data: Math.floor(volumePercent * 100) === 0 ? true : false });
+ }
+ if (volumePercent < 0) {
+ videoRef.volume = 0;
+ videoRef.muted = true;
+ dispatch({ type: 'volume', data: 0 });
+ dispatch({ type: 'isMuted', data: true });
+ }
+ if (volumePercent > 1) {
+ videoRef.volume = 1;
+ dispatch({ type: 'volume', data: 100 });
+ }
+ };
+ /**
+ *
+ * @param e event对象
+ * @description 音量滑动元素点击
+ */
+ const changeCurrentVolume: React.MouseEventHandler = (e) => {
+ e.stopPropagation();
+ const volumeSliderMirrorElement = (
+ volumeSliderMirror.current as HTMLDivElement & { element: HTMLDivElement }
+ ).element;
+ // 获取音量区域高度
+ const volumeAreaHeight = volumeSliderMirrorElement.offsetHeight;
// 获取当前位置在整个音量区域高度的占比
const volumePercent =
- 1 -
- (clientYdistance.current - volumeSliderMirrorElement.getBoundingClientRect().top) /
- volumeAreaHeight;
+ 1 - (e.clientY - volumeSliderMirrorElement.getBoundingClientRect().top) / volumeAreaHeight;
// 修改当前音量大小
updateCurrentVolume(volumePercent);
- dispatch({ type: 'isSlideVolume', data: true });
- }, 1);
- };
- // 当鼠标抬起时
- const whenMouseUpDo = () => {
- volumeInterval.current && clearInterval(volumeInterval.current);
- dispatch({ type: 'isSlideVolume', data: false });
- };
- const clearVolumeInterval: React.MouseEventHandler = (e) => {
- e.stopPropagation();
- whenMouseUpDo();
- };
- /**
- * @description 开启全屏
- */
- const requestFullScreen = () => {
- if (screenfull.isEnabled) {
- screenfull.toggle(reviceProps.videoContainerRef!);
- screenfull.on('change', () =>
- dispatch({ type: 'isScreentFull', data: (screenfull as Screenfull).isFullscreen }),
- );
- }
- };
- /**
- * @description 开启画中画
- */
- const pictureInPicture = () => {
- if (isPictureinpicture) {
- (document as any).exitPictureInPicture();
- } else {
- (reviceProps.videoRef! as any).requestPictureInPicture();
- }
- };
- /**
- * @description 设置视频倍数
- */
- const selectPlayRate = (playbackRate: number) => {
- reviceProps.videoRef!.playbackRate = playbackRate;
- dispatch({ type: 'multiple', data: playbackRate });
- };
- const multipleText = useMemo(() => {
- if (controlsState.multiple === 1.0) {
- return '倍数';
- } else {
- return multipleList.filter((item) => item.id === controlsState.multiple)[0].name;
- }
- }, [controlsState.multiple]);
- /**
- * @description 在线截图
- */
- const screenshot = () => {
- const canvas = document.createElement('canvas') as HTMLCanvasElement;
- canvas.width = reviceProps.videoRef!.offsetWidth;
- canvas.height = reviceProps.videoRef!.offsetHeight;
- const context = canvas.getContext('2d')!;
- context.drawImage(reviceProps.videoRef!, 0, 0, canvas.width, canvas.height);
- try {
- createALabel(canvas.toDataURL('image/png'));
- } catch (error) {}
- };
- /**
- * @description 设置
- */
- const switchChange = (e: string, flag: string) => {
- const { videoRef, lightOffMaskRef } = revicePropsData.current;
- if (flag === 'lights') {
- if (lightOffMaskRef) {
- lightOffMaskRef.style.display = e === 'yes' ? 'block' : 'none';
+ };
+
+ const slideCurrentVolume: React.MouseEventHandler = (e) => {
+ e.stopPropagation();
+ const volumeSliderMirrorElement = (
+ volumeSliderMirror.current as HTMLDivElement & { element: HTMLDivElement }
+ ).element;
+ // 获取音量区域高度
+ const volumeAreaHeight = volumeSliderMirrorElement.offsetHeight;
+ // 防止点击的时候,再次出发计时器,重而造成点击卡顿
+ volumeInterval.current && clearInterval(volumeInterval.current);
+ volumeInterval.current = setInterval(() => {
+ // 获取当前位置在整个音量区域高度的占比
+ const volumePercent =
+ 1 -
+ (clientYdistance.current - volumeSliderMirrorElement.getBoundingClientRect().top) /
+ volumeAreaHeight;
+ // 修改当前音量大小
+ updateCurrentVolume(volumePercent);
+ dispatch({ type: 'isSlideVolume', data: true });
+ }, 1);
+ };
+ // 当鼠标抬起时
+ const whenMouseUpDo = () => {
+ volumeInterval.current && clearInterval(volumeInterval.current);
+ dispatch({ type: 'isSlideVolume', data: false });
+ };
+ const clearVolumeInterval: React.MouseEventHandler = (e) => {
+ e.stopPropagation();
+ whenMouseUpDo();
+ };
+ /**
+ * @description 开启全屏
+ */
+ const requestFullScreen = () => {
+ if (screenfull.isEnabled) {
+ screenfull.toggle(reviceProps.videoContainerRef!);
+ screenfull.on('change', () =>
+ dispatch({ type: 'isScreentFull', data: (screenfull as Screenfull).isFullscreen }),
+ );
}
- } else {
- const loop = videoRef.loop;
- videoRef.loop = loop ? false : true;
- }
- };
- /**
- * @description 网页全屏
- */
- const clientFullScreen = () => {
- const videoContainerRef = reviceProps.videoContainerRef!;
- if (videoContainerRef.classList.contains('clientFullScreen')) {
- videoContainerRef.classList.remove('clientFullScreen');
- dispatch({ type: 'isWebPageFullScreen', data: false });
- } else {
- videoContainerRef.classList.add('clientFullScreen');
- dispatch({ type: 'isWebPageFullScreen', data: true });
- }
- };
- /**
- * @description 静音键和非静音键的切换
- */
- const toggleVolume = () => {
- reviceProps.videoRef!.volume = controlsState.isMuted ? defaultVolume / 100 : 0;
- dispatch({ type: 'isMuted', data: controlsState.isMuted ? false : true });
- reviceProps.videoRef!.muted = controlsState.isMuted ? false : true;
- };
+ };
+ /**
+ * @description 开启画中画
+ */
+ const pictureInPicture = () => {
+ if (isPictureinpicture) {
+ (document as any).exitPictureInPicture();
+ } else {
+ (reviceProps.videoRef! as any).requestPictureInPicture();
+ }
+ };
+ /**
+ * @description 设置视频倍数
+ */
+ const selectPlayRate = (playbackRate: number) => {
+ reviceProps.videoRef!.playbackRate = playbackRate;
+ dispatch({ type: 'multiple', data: playbackRate });
+ };
+ const multipleText = useMemo(() => {
+ if (controlsState.multiple === 1.0) {
+ return '倍数';
+ } else {
+ return multipleList.filter((item) => item.id === controlsState.multiple)[0].name;
+ }
+ }, [controlsState.multiple]);
+ /**
+ * @description 在线截图
+ */
+ const screenshot = async () => {
+ const output = document.querySelector('#JoL-screenshotCanvas')!;
+ const canvas = capture(reviceProps.videoRef!, 0.45);
+ setIsscreenshot(true);
+ if (output) {
+ setScreenshotLoading(false);
+ output.innerHTML = '';
+ output.appendChild(canvas);
+ } else {
+ setScreenshotLoading(true);
+ }
+ };
+ /**
+ * @description 设置
+ */
+ const switchChange = (e: string, flag: string) => {
+ const { videoRef, lightOffMaskRef } = revicePropsData.current!;
+ if (flag === 'lights') {
+ if (lightOffMaskRef) {
+ lightOffMaskRef.style.display = e === 'yes' ? 'block' : 'none';
+ }
+ } else {
+ const loop = videoRef!.loop;
+ videoRef!.loop = loop ? false : true;
+ }
+ };
+ /**
+ * @description 网页全屏
+ */
+ const clientFullScreen = () => {
+ const videoContainerRef = reviceProps.videoContainerRef!;
+ if (videoContainerRef.classList.contains('clientFullScreen')) {
+ videoContainerRef.classList.remove('clientFullScreen');
+ dispatch({ type: 'isWebPageFullScreen', data: false });
+ } else {
+ videoContainerRef.classList.add('clientFullScreen');
+ dispatch({ type: 'isWebPageFullScreen', data: true });
+ }
+ };
+ /**
+ * @description 静音键和非静音键的切换
+ */
+ const toggleVolume = () => {
+ reviceProps.videoRef!.volume = controlsState.isMuted ? defaultVolume / 100 : 0;
+ dispatch({ type: 'isMuted', data: controlsState.isMuted ? false : true });
+ reviceProps.videoRef!.muted = controlsState.isMuted ? false : true;
+ };
- return (
-
-
-
-
-
-
-
- }
+ return (
+
+
-
+ {propsAttributes!.isShowMultiple && (
+
- }
- />
-
- }
- />
-
- }
- />
+ )}
+
+
+
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
-
- );
-});
+ );
+ },
+);
export default Index;
diff --git a/src/core/index.tsx b/src/core/index.tsx
index f107d21..d0ec005 100644
--- a/src/core/index.tsx
+++ b/src/core/index.tsx
@@ -175,5 +175,12 @@ const JoLPlayer = function JoLPlayer(props: videoparameter, ref: React.Ref(JoLPlayer);
-
+JoLPlayerComponent.defaultProps = {
+ option: {
+ width: 750,
+ height: 420,
+ videoSrc: 'https://cdn.gudsen.com/2021/06/28/f81356b08b4842d7a3719499f557c8e4.JPG',
+ isShowMultiple: true,
+ },
+};
export default JoLPlayerComponent;
diff --git a/src/core/progress/index.tsx b/src/core/progress/index.tsx
index ccc7830..45eba67 100644
--- a/src/core/progress/index.tsx
+++ b/src/core/progress/index.tsx
@@ -172,7 +172,7 @@ const Index = memo(function Index(props) {
return (
diff --git a/src/icons/svg/close.svg b/src/icons/svg/close.svg
new file mode 100644
index 0000000..314e1c4
--- /dev/null
+++ b/src/icons/svg/close.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/interface/index.ts b/src/interface/index.ts
index fd22738..ede0ef8 100644
--- a/src/interface/index.ts
+++ b/src/interface/index.ts
@@ -40,6 +40,30 @@ export interface videoOption
{
* @description 暂停键的位置
*/
pausePlacement?: pausePlacement;
+ /**
+ * @description 多少毫秒,无任何操作,隐藏鼠标和控制器/ms
+ */
+ hideMouseTime?: U;
+ /**
+ * @description 是否显示播放倍数功能
+ */
+ isShowMultiple?: K;
+ /**
+ * @description 是否显示设置功能
+ */
+ isShowSet?: K;
+ /**
+ * @description 是否显示截图功能
+ */
+ isShowScreenshot?: K;
+ /**
+ * @description 是否显示画中画
+ */
+ isShowPicture?: K;
+ /**
+ * @description 是否显示网页全屏
+ */
+ isShowWebFullScreen?: K;
}
export interface videoAttributes {
/**
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 885aa95..121d29f 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -37,3 +37,14 @@ export const createALabel = (path: string, fileName: string = 'JoL-player.png')
link.remove();
window.URL.revokeObjectURL(path);
};
+
+export const capture = (video: HTMLVideoElement, scaleFactor: number = 0.25) => {
+ var w = video.videoWidth * scaleFactor;
+ var h = video.videoHeight * scaleFactor;
+ var canvas = document.createElement('canvas') as HTMLCanvasElement;
+ canvas.width = w;
+ canvas.height = h;
+ var ctx = canvas.getContext('2d');
+ ctx!.drawImage(video, 0, 0, w, h);
+ return canvas;
+};