fix(meta\biz): 视频添加od, 查看大图点击失效修复
This commit is contained in:
parent
1f3286e67d
commit
c9abef2676
@ -1,5 +1,11 @@
|
||||
# @zhst/biz
|
||||
|
||||
## 0.16.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz: fix: 在业务层控制窗口切换状态
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/biz",
|
||||
"version": "0.16.0",
|
||||
"version": "0.16.1",
|
||||
"description": "业务库",
|
||||
"keywords": [
|
||||
"business",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import VideoPlayerCard from '../../../VideoPlayerCard';
|
||||
import { VideoPlayerCardProps } from '../../../VideoPlayerCard';
|
||||
import { Segmented } from 'antd';
|
||||
@ -53,13 +53,13 @@ export const WindowToggle: React.FC<WindowToggleProps> = (props) => {
|
||||
<div className='body'>
|
||||
{
|
||||
dataSource?.map((item, index) => {
|
||||
|
||||
|
||||
if (size === "large" && index > 0) return
|
||||
return (
|
||||
<VideoPlayerCard
|
||||
key={item.windowKey}
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
size={size}
|
||||
size={size}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
{...item}
|
||||
|
@ -1,5 +1,12 @@
|
||||
# @zhst/utils
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.11.0
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/func",
|
||||
"version": "0.10.1",
|
||||
"version": "0.10.2",
|
||||
"description": "函数合集",
|
||||
"keywords": [
|
||||
"hooks"
|
||||
|
@ -1,5 +1,11 @@
|
||||
# @zhst/hooks
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.10.2
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/hooks",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.2",
|
||||
"description": "hooks合集",
|
||||
"keywords": [
|
||||
"hooks"
|
||||
|
@ -1,5 +1,12 @@
|
||||
# @zhst/material
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.16.1
|
||||
|
||||
## 0.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/material",
|
||||
"version": "0.10.3",
|
||||
"version": "0.10.4",
|
||||
"description": "物料库",
|
||||
"keywords": [
|
||||
"business",
|
||||
|
@ -1,5 +1,18 @@
|
||||
# @zhst/utils
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 视频添加 OD 框,查看大图首次点击修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.15.0
|
||||
- @zhst/func@0.10.2
|
||||
- @zhst/hooks@0.9.2
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -30,31 +30,32 @@ export default {
|
||||
_this$eventHandleList = this.eventHandleList,
|
||||
eventHandleList = _this$eventHandleList === void 0 ? [] : _this$eventHandleList,
|
||||
options = this.options;
|
||||
//图片事件
|
||||
// 鼠标滚轮事件
|
||||
var scaleAble = get(options, 'scaleAble', true);
|
||||
if (scaleAble) {
|
||||
var handleWhele = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWhele);
|
||||
var handleWheel = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWheel);
|
||||
}
|
||||
|
||||
// 鼠标 - 拖拽事件
|
||||
var dragAble = get(options, 'dragAble', true);
|
||||
if (dragAble) {
|
||||
var handleDragStart = addEventListenerWrapper(canvas, EVENT_POINTER_DOWN, this.onDragStart.bind(this));
|
||||
eventHandleList.push(addEventListenerWrapper);
|
||||
eventHandleList.push(handleDragStart);
|
||||
var handleDragMove = addEventListenerWrapper(element.ownerDocument, EVENT_POINTER_MOVE, this.onDragMove.bind(this));
|
||||
eventHandleList.push(handleDragMove);
|
||||
EVENT_POINTER_UP.trim().split(REGEXP_SPACES).forEach(function (eventName) {
|
||||
var handleDragEnd = addEventListenerWrapper(element.ownerDocument, eventName, _this.onDragEnd.bind(_this));
|
||||
EVENT_POINTER_UP.trim().split(REGEXP_SPACES).forEach(function (_eventName) {
|
||||
var handleDragEnd = addEventListenerWrapper(element.ownerDocument, _eventName, _this.onDragEnd.bind(_this));
|
||||
eventHandleList.push(handleDragEnd);
|
||||
});
|
||||
}
|
||||
|
||||
//rect事件
|
||||
var handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
// const handleLeveal = addEventListenerWrapper(canvas, EVENT_LEAVEL, this.onLeavel.bind(this));
|
||||
// eventHandleList.push(handleLeveal);
|
||||
// const handleEnter = addEventListenerWrapper(canvas, EVENT_ENTER, this.onEnter.bind(this));
|
||||
// eventHandleList.push(handleEnter);
|
||||
// 鼠标 - 点击事件
|
||||
var selectAble = get(options, 'selectAble', true);
|
||||
if (selectAble) {
|
||||
var handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
}
|
||||
},
|
||||
unbind: function unbind() {
|
||||
var eventHandleList = this.eventHandleList;
|
||||
@ -67,7 +68,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 图片事件 */onWheel: function onWheel(event, cropBox) {
|
||||
/* 鼠标滚轮事件 */onWheel: function onWheel(event, cropBox) {
|
||||
var _this2 = this;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
@ -97,6 +98,7 @@ export default {
|
||||
})
|
||||
}, cropBox);
|
||||
},
|
||||
// 鼠标拖拽 - 开始拖拽
|
||||
onDragStart: function onDragStart(event) {
|
||||
event.stopPropagation();
|
||||
// This line is required for preventing page zooming in iOS browsers
|
||||
@ -119,6 +121,7 @@ export default {
|
||||
this.action = ACTION_DRAG;
|
||||
addClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
// 鼠标拖拽 - 拖拽中
|
||||
onDragMove: function onDragMove(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
@ -147,6 +150,7 @@ export default {
|
||||
this.pointer.startX = this.pointer.endX;
|
||||
this.pointer.startY = this.pointer.endY;
|
||||
},
|
||||
// 鼠标拖拽 - 停止拖拽
|
||||
onDragEnd: function onDragEnd(event) {
|
||||
event.stopPropagation();
|
||||
var action = this.action;
|
||||
@ -158,14 +162,7 @@ export default {
|
||||
this.point = null;
|
||||
removeClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
/* rect事件 */
|
||||
// onLeavel(event) {
|
||||
// const pointerCenter = this.windowToCanvasAxis(event);
|
||||
// this.highlightShape(pointerCenter);
|
||||
// },
|
||||
// onEnter(event) {
|
||||
// this.highlightShape(null);
|
||||
// },
|
||||
// 鼠标点击
|
||||
onClick: function onClick(event) {
|
||||
event.stopPropagation();
|
||||
var pointerCenter = this.windowToCanvasAxis(event);
|
||||
|
@ -13,7 +13,12 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
||||
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||
//@ts-nocheck
|
||||
import * as turf from '@turf/turf';
|
||||
import { AXIS_TYPE_ORIGIN, AXIS_TYPE_CANVAS, AXIS_TYPE_IMAGE } from "./constants";
|
||||
export function rectToPolygon(axisRect) {
|
||||
var polygon = turf.polygon([[[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)]]]);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
//设置数据的精度
|
||||
//accuracy 表示精度 以原点为中心向左为正,向右为负,
|
||||
@ -42,7 +47,7 @@ export default {
|
||||
targetTransform: {
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
scale: 0,
|
||||
scale: 1,
|
||||
rotate: 0
|
||||
// rotate: 90,
|
||||
},
|
||||
@ -73,7 +78,8 @@ export default {
|
||||
var targetTransform = this.targetTransform;
|
||||
var translateX = targetTransform.translateX,
|
||||
translateY = targetTransform.translateY,
|
||||
scale = targetTransform.scale;
|
||||
_targetTransform$scal = targetTransform.scale,
|
||||
scale = _targetTransform$scal === void 0 ? 1 : _targetTransform$scal;
|
||||
var axis = _objectSpread(_objectSpread({
|
||||
x: translateX + x * scale,
|
||||
y: translateY + y * scale
|
||||
|
@ -75,7 +75,14 @@ var Viewer = (_dec = Mixin(Render, Event, Shape, Helper), _dec(_class = /*#__PUR
|
||||
}, {
|
||||
key: "build",
|
||||
value: function build() {
|
||||
var _this$options = this.options,
|
||||
_this$options$width = _this$options.width,
|
||||
width = _this$options$width === void 0 ? 300 : _this$options$width,
|
||||
_this$options$height = _this$options.height,
|
||||
height = _this$options$height === void 0 ? 150 : _this$options$height;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width || canvas.width;
|
||||
canvas.height = height || canvas.height;
|
||||
addClass(canvas, CLASS_CANVAS);
|
||||
this.element.appendChild(canvas);
|
||||
this.canvas = canvas;
|
||||
|
@ -65,7 +65,6 @@ export default {
|
||||
});
|
||||
},
|
||||
initCanvas: function initCanvas() {
|
||||
if (!this.image) return;
|
||||
//通过样式设置 不依赖父元素的prosition
|
||||
var element = this.element,
|
||||
canvas = this.canvas,
|
||||
@ -83,7 +82,7 @@ export default {
|
||||
var fitTransform = this.calcFitScreen();
|
||||
this.targetTransform = Object.assign({}, this.targetTransform, fitTransform);
|
||||
dispatchEvent(this.element, EVENT_VIEWER_TRANSFORM_CHANGE, cloneDeep(this.targetTransform));
|
||||
//产品需求:fitscale 是minscale
|
||||
//产品需求:fitscale 是 minscale
|
||||
var _options$fitScaleAsMi = options.fitScaleAsMinScale,
|
||||
fitScaleAsMinScale = _options$fitScaleAsMi === void 0 ? false : _options$fitScaleAsMi;
|
||||
if (fitScaleAsMinScale) {
|
||||
@ -106,8 +105,9 @@ export default {
|
||||
};
|
||||
loop();
|
||||
},
|
||||
// 绘制画布
|
||||
renderCanvas: function renderCanvas(_ctx) {
|
||||
if (!this.image || !this.canvas) return;
|
||||
if (!this.canvas) return;
|
||||
var containerData = this.containerData,
|
||||
canvas = this.canvas,
|
||||
targetTransform = this.targetTransform,
|
||||
@ -128,14 +128,14 @@ export default {
|
||||
ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
// ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
//旋转
|
||||
var centerX = this.image.width / 2;
|
||||
var centerY = this.image.height / 2;
|
||||
var centerX = this.image ? this.image.width / 2 : canvas.width;
|
||||
var centerY = this.image ? this.image.height / 2 : canvas.height;
|
||||
ctx.translate(centerX, centerY);
|
||||
ctx.rotate(rotate / 180 * Math.PI);
|
||||
ctx.translate(-centerX, -centerY);
|
||||
|
||||
//图片
|
||||
ctx.drawImage(this.image, 0, 0);
|
||||
this.image && ctx.drawImage(this.image, 0, 0);
|
||||
ctx.restore();
|
||||
//画图形
|
||||
ctx.save();
|
||||
|
@ -14,13 +14,9 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
||||
import { isNil, isArray, isFunction } from '@zhst/func';
|
||||
import * as turf from '@turf/turf';
|
||||
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
||||
import { setNumberAccuracy } from "./helper";
|
||||
import { rectToPolygon } from "./helper";
|
||||
import { SHAPE_TYPE_RECT, SHAPE_TYPE_CIRCLE, EVENT_SHAPE_SELECT } from "./constants";
|
||||
import { dispatchEvent } from "../utils";
|
||||
function rectToPolygon(axisRect) {
|
||||
var polygon = turf.polygon([[[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)]]]);
|
||||
return polygon;
|
||||
}
|
||||
export default {
|
||||
//store
|
||||
shapeList: [],
|
||||
@ -47,20 +43,20 @@ export default {
|
||||
this.changeZoonAble(true);
|
||||
}
|
||||
},
|
||||
//method
|
||||
addShape: function addShape(shap) {
|
||||
//method:添加矩形
|
||||
addShape: function addShape(shape) {
|
||||
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : SHAPE_TYPE_RECT;
|
||||
this.color = shap.color ? shap.color : '';
|
||||
if (isNil(shap) || this.disableAdd) return;
|
||||
this.color = shape.color ? shape.color : '';
|
||||
if (isNil(shape) || this.disableAdd) return;
|
||||
var _this$shapeList = this.shapeList,
|
||||
preShapeList = _this$shapeList === void 0 ? [] : _this$shapeList;
|
||||
var shapList = isArray(shap) ? shap : [shap];
|
||||
shapList = shapList.map(function (v) {
|
||||
var _shapeList = isArray(shape) ? shape : [shape];
|
||||
_shapeList = _shapeList.map(function (v) {
|
||||
return _objectSpread(_objectSpread({}, v), {}, {
|
||||
__SHAPE_TYPE__: type
|
||||
});
|
||||
});
|
||||
this.shapeList = [].concat(_toConsumableArray(preShapeList), _toConsumableArray(shapList));
|
||||
this.shapeList = [].concat(_toConsumableArray(preShapeList), _toConsumableArray(_shapeList));
|
||||
},
|
||||
//
|
||||
setSelectShapId: function setSelectShapId(id) {
|
||||
@ -214,9 +210,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
// 绘制矩形
|
||||
renderRect: function renderRect(ctx, shape, type) {
|
||||
//算rect
|
||||
var axisRect = this.imgRectAxisToCanvasAxisRect(shape);
|
||||
var axisRect = this.imgRectAxisToCanvasAxisRect(_objectSpread(_objectSpread({}, shape), {}, {
|
||||
image: ctx.canvas
|
||||
}));
|
||||
var rect = {
|
||||
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
||||
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
||||
|
@ -1,4 +1,5 @@
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
@ -18,15 +19,14 @@ import { noop, get, addEventListenerWrapper, dataURLToBlob, nextTick, toRealNumb
|
||||
import Align from 'rc-align';
|
||||
import { useLatest, useUpdateEffect, useFullscreen, useUnmount } from '@zhst/hooks';
|
||||
import classNames from 'classnames';
|
||||
import download from 'downloadjs';
|
||||
import { Button, message } from '..';
|
||||
import { message } from '..';
|
||||
import { IconFont } from '@zhst/icon';
|
||||
import { Cropper, EVENT_CROP_START, EVENT_CROP_END } from "../ImageEditor";
|
||||
import { Cropper, EVENT_CROP_START, EVENT_CROP_END, Viewer } from "../ImageEditor";
|
||||
import FlvPlayer, { FLV_EVENT } from "./components/FlvPlayer";
|
||||
import Range from "./components/Progress";
|
||||
import Loading from "./components/Loading";
|
||||
import { CROP_TYPE } from "../utils/constants";
|
||||
import { getShowStatus } from "./videoPlayerHelper";
|
||||
import { downloadFrame, getShowStatus } from "./videoPlayerHelper";
|
||||
import "./index.less";
|
||||
var componentName = "zhst-image__video-view";
|
||||
var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
@ -42,6 +42,16 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
adjustY: true
|
||||
}
|
||||
} : _props$screenshotButt,
|
||||
_props$autoPlay = props.autoPlay,
|
||||
autoPlay = _props$autoPlay === void 0 ? false : _props$autoPlay,
|
||||
odList = props.odList,
|
||||
showOD = props.showOD,
|
||||
_props$width = props.width,
|
||||
width = _props$width === void 0 ? '100%' : _props$width,
|
||||
_props$height = props.height,
|
||||
height = _props$height === void 0 ? '532px' : _props$height,
|
||||
_props$backgroundColo = props.backgroundColor,
|
||||
backgroundColor = _props$backgroundColo === void 0 ? '#333' : _props$backgroundColo,
|
||||
_props$screenshotButt2 = props.screenshotButtonRender,
|
||||
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
@ -53,7 +63,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
}, "\u56DE\u8C03DOM");
|
||||
} : _props$screenshotButt2,
|
||||
onCropChange = props.onCropChange,
|
||||
defaultNormalizationRect = props.defautlNormalizationRect;
|
||||
defaultNormalizationRect = props.defautlNormalizationRect,
|
||||
playerProps = props.playerProps;
|
||||
// ========================== 播放 =========================
|
||||
//实例参数
|
||||
var containerRef = useRef(null); //容器ref
|
||||
@ -257,6 +268,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
// 重新加载
|
||||
var _reload = /*#__PURE__*/function () {
|
||||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
|
||||
var oldTime;
|
||||
@ -309,6 +322,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
return _ref.apply(this, arguments);
|
||||
};
|
||||
}();
|
||||
|
||||
// 进度条操作
|
||||
var seek = function seek(v) {
|
||||
if (videoInsRef.current && isVideoLoadFinished) {
|
||||
setPlayTime(parseFloat(v));
|
||||
@ -317,6 +332,7 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
message.warning('待视频加载完,才可操作进度条');
|
||||
}
|
||||
};
|
||||
|
||||
// ========================== 视频opt bar =========================
|
||||
var _useFullscreen = useFullscreen(containerRef, {
|
||||
pageFullscreen: true
|
||||
@ -354,17 +370,15 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
_useState22 = _slicedToArray(_useState21, 2),
|
||||
cropRect = _useState22[0],
|
||||
setCropRect = _useState22[1];
|
||||
useEffect(function () {
|
||||
var _videoInsRef$current4, _videoInsRef$current5;
|
||||
showCrop ? videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current4 = videoInsRef.current) === null || _videoInsRef$current4 === void 0 ? void 0 : _videoInsRef$current4.pause() : videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current5 = videoInsRef.current) === null || _videoInsRef$current5 === void 0 ? void 0 : _videoInsRef$current5.play();
|
||||
}, [showCrop]);
|
||||
|
||||
// 监听showCrop, isReady - 是否可编辑、视频播放组件是否挂载
|
||||
useEffect(function () {
|
||||
var handlerCropStart;
|
||||
var handlerCropEnd;
|
||||
setCropRect(null);
|
||||
if (!isReady) return;
|
||||
if (showCrop) {
|
||||
var _canvas$parentNode;
|
||||
var _canvas$parentNode, _videoInsRef$current4;
|
||||
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, function () {
|
||||
setCropRect(null);
|
||||
});
|
||||
@ -412,18 +426,41 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
};
|
||||
}
|
||||
isFirstFlagRef.current = false;
|
||||
|
||||
// 初始化圈选工具
|
||||
cropInsRef.current = new Cropper(corpContainerRef.current, {
|
||||
showMask: true,
|
||||
cropBoxLimited: cropBoxLimited,
|
||||
editAble: false,
|
||||
img: imageData,
|
||||
initialCropBoxData: initialCropBoxData
|
||||
});
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current4 = videoInsRef.current) === null || _videoInsRef$current4 === void 0 || _videoInsRef$current4.pause();
|
||||
} else {
|
||||
var _videoInsRef$current5;
|
||||
var _element = videoInsRef.current._mediaElement || {};
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current5 = videoInsRef.current) === null || _videoInsRef$current5 === void 0 || _videoInsRef$current5.play();
|
||||
// 挂载图片选择
|
||||
cropInsRef.current = new Viewer(corpContainerRef.current, {
|
||||
scaleAble: false,
|
||||
selectAble: false,
|
||||
dragAble: false,
|
||||
width: _element.clientWidth,
|
||||
height: _element.clientHeight,
|
||||
backgroundColor: 'transparent'
|
||||
});
|
||||
|
||||
// 判定是否存在od框
|
||||
showOD && (odList === null || odList === void 0 ? void 0 : odList.forEach(function (_od) {
|
||||
var _cropInsRef$current;
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current = cropInsRef.current) === null || _cropInsRef$current === void 0 || _cropInsRef$current.addShape(_od);
|
||||
}));
|
||||
}
|
||||
return function () {
|
||||
var _handlerCropStart, _handlerCropEnd, _cropInsRef$current, _cropInsRef$current$d;
|
||||
var _handlerCropStart, _handlerCropEnd, _cropInsRef$current2, _cropInsRef$current2$;
|
||||
(_handlerCropStart = handlerCropStart) === null || _handlerCropStart === void 0 || _handlerCropStart.remove();
|
||||
(_handlerCropEnd = handlerCropEnd) === null || _handlerCropEnd === void 0 || _handlerCropEnd.remove();
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current = cropInsRef.current) === null || _cropInsRef$current === void 0 || (_cropInsRef$current$d = _cropInsRef$current.destroy) === null || _cropInsRef$current$d === void 0 || _cropInsRef$current$d.call(_cropInsRef$current);
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current2 = cropInsRef.current) === null || _cropInsRef$current2 === void 0 || (_cropInsRef$current2$ = _cropInsRef$current2.destroy) === null || _cropInsRef$current2$ === void 0 || _cropInsRef$current2$.call(_cropInsRef$current2);
|
||||
cropInsRef.current = null;
|
||||
};
|
||||
}, [showCrop, isReady]);
|
||||
@ -502,7 +539,7 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
};
|
||||
}();
|
||||
|
||||
//回调
|
||||
// 监听showCrop、cropRect - 监听是否可编辑、绘制的矩形
|
||||
useEffect(function () {
|
||||
//计算归一化crop rect
|
||||
var normalizationRect = null;
|
||||
@ -528,41 +565,11 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
}, [showCrop, cropRect]);
|
||||
|
||||
// ========================== 截帧 =========================
|
||||
var downloadVideoframe = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
|
||||
var _videoInsRef$current6, _videoInsRef$current7, video, canvas, ctx, base64;
|
||||
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
||||
while (1) switch (_context4.prev = _context4.next) {
|
||||
case 0:
|
||||
try {
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current6 = videoInsRef.current) === null || _videoInsRef$current6 === void 0 || (_videoInsRef$current7 = _videoInsRef$current6.pause) === null || _videoInsRef$current7 === void 0 || _videoInsRef$current7.call(_videoInsRef$current6);
|
||||
video = videoRef.current;
|
||||
canvas = document.createElement('canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx === null || ctx === void 0 || ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx === null || ctx === void 0 || ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL();
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx === null || ctx === void 0 || ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL('image/png');
|
||||
}
|
||||
download(base64);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
case 1:
|
||||
case "end":
|
||||
return _context4.stop();
|
||||
}
|
||||
}, _callee4);
|
||||
})), []);
|
||||
var downloadVideoFrame = useCallback(function (opt) {
|
||||
var _videoInsRef$current6, _videoInsRef$current7;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current6 = videoInsRef.current) === null || _videoInsRef$current6 === void 0 || (_videoInsRef$current7 = _videoInsRef$current6.pause) === null || _videoInsRef$current7 === void 0 || _videoInsRef$current7.call(_videoInsRef$current6);
|
||||
downloadFrame(videoRef.current, opt);
|
||||
}, []);
|
||||
|
||||
// ============================== 暴露出去的方法 ===============================
|
||||
var latestIsReady = useLatest(isReady);
|
||||
@ -573,17 +580,31 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
setShowCrop: function setShowCrop(dispatch) {
|
||||
var isReady = latestIsReady.current;
|
||||
if (!isReady) return;
|
||||
_setShowCrop(dispatch);
|
||||
_setShowCrop === null || _setShowCrop === void 0 || _setShowCrop(dispatch);
|
||||
},
|
||||
downloadVideoframe: downloadVideoframe
|
||||
downloadVideoFrame: downloadVideoFrame,
|
||||
pause: function pause() {
|
||||
var _videoInsRef$current8, _videoInsRef$current9;
|
||||
(_videoInsRef$current8 = videoInsRef.current) === null || _videoInsRef$current8 === void 0 || (_videoInsRef$current9 = _videoInsRef$current8.pause) === null || _videoInsRef$current9 === void 0 || _videoInsRef$current9.call(_videoInsRef$current8);
|
||||
},
|
||||
play: function play() {
|
||||
var _videoInsRef$current10, _videoInsRef$current11;
|
||||
(_videoInsRef$current10 = videoInsRef.current) === null || _videoInsRef$current10 === void 0 || (_videoInsRef$current11 = _videoInsRef$current10.play) === null || _videoInsRef$current11 === void 0 || _videoInsRef$current11.call(_videoInsRef$current10);
|
||||
},
|
||||
reload: _reload
|
||||
};
|
||||
});
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName)),
|
||||
ref: containerRef
|
||||
}, url && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FlvPlayer, {
|
||||
ref: containerRef,
|
||||
style: {
|
||||
width: width,
|
||||
height: height,
|
||||
backgroundColor: backgroundColor
|
||||
}
|
||||
}, url && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FlvPlayer, _extends({
|
||||
playId: playSeq,
|
||||
autoPlay: true,
|
||||
autoPlay: autoPlay,
|
||||
className: classNames("".concat(componentName, "-flv")),
|
||||
type: url.startsWith('http') ? 'mp4' : 'flv',
|
||||
url: url,
|
||||
@ -594,12 +615,14 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
hasAudio: false,
|
||||
hasVideo: true
|
||||
},
|
||||
onCreat: initPlayer
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
onCreate: initPlayer
|
||||
}, playerProps)), /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "-crop-container")),
|
||||
ref: corpContainerRef,
|
||||
style: {
|
||||
display: isFullscreen ? 'none' : 'block'
|
||||
display: isFullscreen ? 'none' : 'block',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}
|
||||
}), showCrop && cropRect && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||
ref: alginContainerRef,
|
||||
@ -625,27 +648,26 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
cropType: CROP_TYPE['CUSTOM']
|
||||
}))), !showCrop && /*#__PURE__*/React.createElement("div", {
|
||||
className: "".concat(componentName, "-opt")
|
||||
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Button, {
|
||||
type: "text",
|
||||
onClick: function onClick() {
|
||||
if (!isPlay) {
|
||||
var _videoInsRef$current8;
|
||||
//播放中暂停
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current8 = videoInsRef.current) === null || _videoInsRef$current8 === void 0 || _videoInsRef$current8.play();
|
||||
_setShowCrop(false);
|
||||
} else {
|
||||
var _videoInsRef$current9;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current9 = videoInsRef.current) === null || _videoInsRef$current9 === void 0 || _videoInsRef$current9.pause();
|
||||
}
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
marginRight: '12px',
|
||||
color: '#fff',
|
||||
display: 'flex'
|
||||
},
|
||||
onIconClick: function onIconClick() {
|
||||
if (!isPlay) {
|
||||
var _videoInsRef$current12;
|
||||
//播放中暂停
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current12 = videoInsRef.current) === null || _videoInsRef$current12 === void 0 || _videoInsRef$current12.play();
|
||||
_setShowCrop(false);
|
||||
} else {
|
||||
var _videoInsRef$current13;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current13 = videoInsRef.current) === null || _videoInsRef$current13 === void 0 || _videoInsRef$current13.pause();
|
||||
}
|
||||
},
|
||||
color: "#1890ff",
|
||||
icon: !isPlay ? 'icon-shipinbofang' : 'icon-shipinzanting'
|
||||
}))), /*#__PURE__*/React.createElement("div", {
|
||||
icon: !isPlay ? 'icon-bofang3' : 'icon-zanting1'
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
className: "".concat(componentName, "-opt-range"),
|
||||
onClick: function onClick(e) {
|
||||
e.stopPropagation();
|
||||
@ -656,20 +678,19 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
max: showMaxDuration,
|
||||
showSlider: showSlider,
|
||||
onChange: seek
|
||||
}), /*#__PURE__*/React.createElement("div", null, formatDurationTime(playTime), "/", formatDurationTime(showMaxDuration))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Button, {
|
||||
type: "text",
|
||||
onClick: function onClick(e) {
|
||||
}), /*#__PURE__*/React.createElement("div", null, formatDurationTime(playTime), "/", formatDurationTime(showMaxDuration))), /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
display: 'flex',
|
||||
marginLeft: '12px'
|
||||
},
|
||||
color: "#fff",
|
||||
size: 18,
|
||||
onIconClick: function onIconClick(e) {
|
||||
e.stopPropagation();
|
||||
toggleFullscreen();
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
color: '#fff',
|
||||
display: 'flex'
|
||||
},
|
||||
size: 18,
|
||||
icon: isFullscreen ? 'icon-cancle_fullscreen' : 'icon-fullscreen'
|
||||
})))), !!showStatus && /*#__PURE__*/React.createElement(Loading, {
|
||||
icon: isFullscreen ? 'icon-suoxiao1' : 'icon-quanping1'
|
||||
})), !!showStatus && /*#__PURE__*/React.createElement(Loading, {
|
||||
status: showStatus,
|
||||
reload: function reload() {
|
||||
return _reload();
|
||||
|
@ -1,4 +1,4 @@
|
||||
var _excluded = ["className", "autoPlay", "config", "onCreat", "playId"];
|
||||
var _excluded = ["className", "autoPlay", "config", "onCreate", "playId"];
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
@ -45,12 +45,13 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
autoPlay = _this$props$autoPlay === void 0 ? true : _this$props$autoPlay,
|
||||
_this$props$config = _this$props.config,
|
||||
config = _this$props$config === void 0 ? {} : _this$props$config,
|
||||
onCreat = _this$props.onCreat,
|
||||
onCreate = _this$props.onCreate,
|
||||
playId = _this$props.playId,
|
||||
others = _objectWithoutProperties(_this$props, _excluded);
|
||||
if ($video) {
|
||||
if (flvjs.isSupported() && _this.props.url && _this.props.url) {
|
||||
var reload = function reload() {
|
||||
var _this$flvPlayer;
|
||||
if (_this.flvPlayer && _this.flvPlayer.destroy) {
|
||||
try {
|
||||
_this.flvPlayer.destroy();
|
||||
@ -65,7 +66,7 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
flvPlayer.load();
|
||||
_this.flvPlayer = flvPlayer;
|
||||
// @ts-ignore
|
||||
var controller = _this.flvPlayer._transmuxer._controller;
|
||||
var controller = (_this$flvPlayer = _this.flvPlayer) === null || _this$flvPlayer === void 0 || (_this$flvPlayer = _this$flvPlayer._transmuxer) === null || _this$flvPlayer === void 0 ? void 0 : _this$flvPlayer._controller;
|
||||
var wsLoader = controller._ioctl._loader;
|
||||
var oldWsOnCompleteFunc = wsLoader._onComplete;
|
||||
wsLoader._onComplete = function () {
|
||||
@ -82,10 +83,9 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
oldWsOnCompleteFunc();
|
||||
};
|
||||
_this.flvPlayer.reload = reload;
|
||||
onCreat && onCreat(_this.flvPlayer, $video);
|
||||
onCreate === null || onCreate === void 0 || onCreate(_this.flvPlayer, $video);
|
||||
};
|
||||
reload();
|
||||
onCreat && onCreat(_this.flvPlayer, $video);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -95,9 +95,9 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
key: "componentWillUnmount",
|
||||
value: function componentWillUnmount() {
|
||||
if (this.flvPlayer) {
|
||||
var _this$flvPlayer, _this$flvPlayer2;
|
||||
(_this$flvPlayer = this.flvPlayer) === null || _this$flvPlayer === void 0 || _this$flvPlayer.unload();
|
||||
(_this$flvPlayer2 = this.flvPlayer) === null || _this$flvPlayer2 === void 0 || _this$flvPlayer2.detachMediaElement();
|
||||
var _this$flvPlayer2, _this$flvPlayer3;
|
||||
(_this$flvPlayer2 = this.flvPlayer) === null || _this$flvPlayer2 === void 0 || _this$flvPlayer2.unload();
|
||||
(_this$flvPlayer3 = this.flvPlayer) === null || _this$flvPlayer3 === void 0 || _this$flvPlayer3.detachMediaElement();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
@ -119,13 +119,11 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
return /*#__PURE__*/React.createElement("video", {
|
||||
muted: true,
|
||||
preload: "metadata",
|
||||
className: className
|
||||
// controls={true}
|
||||
,
|
||||
style: Object.assign({
|
||||
className: className,
|
||||
style: _objectSpread({
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}, style ? style : {}),
|
||||
}, style),
|
||||
ref: this.initFlv
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ function _objectWithoutProperties(source, excluded) { if (source == null) return
|
||||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Slider } from 'antd';
|
||||
import { Slider, ConfigProvider } from 'antd';
|
||||
import "./index.less";
|
||||
var componentName = "zhst-image__range";
|
||||
export var Range = function Range(props) {
|
||||
@ -15,6 +15,15 @@ export var Range = function Range(props) {
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
style: style,
|
||||
className: classNames("".concat(componentName), !showSlider && "".concat(componentName, "--no-slider"), className)
|
||||
}, /*#__PURE__*/React.createElement(Slider, others));
|
||||
}, /*#__PURE__*/React.createElement(ConfigProvider, {
|
||||
theme: {
|
||||
components: {
|
||||
Slider: {
|
||||
railBg: 'rgba(255, 255, 255, 0.6)',
|
||||
railHoverBg: 'rgba(255, 255, 255, 0.6)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(Slider, others)));
|
||||
};
|
||||
export default Range;
|
@ -1,8 +1,6 @@
|
||||
.zhst-image__video-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 532px;
|
||||
background-color: #333;
|
||||
|
||||
// &-flv {
|
||||
@ -37,7 +35,7 @@
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
padding: 0 12px 0 24px;
|
||||
background-color: rgb(0 0 0 / 80%);
|
||||
line-height: 32px;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import download from "downloadjs";
|
||||
export function getShowStatus(isLoadingVideo, isEnd, isError) {
|
||||
var status = null;
|
||||
if (isLoadingVideo) {
|
||||
@ -10,4 +11,41 @@ export function getShowStatus(isLoadingVideo, isEnd, isError) {
|
||||
status = 'END';
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// 下载功能的可配置属性
|
||||
|
||||
// 视屏截帧、下载
|
||||
export var downloadFrame = function downloadFrame(_videoDom, opt) {
|
||||
var _ref = opt || {},
|
||||
_ref$downloadAble = _ref.downloadAble,
|
||||
downloadAble = _ref$downloadAble === void 0 ? true : _ref$downloadAble,
|
||||
_ref$fileName = _ref.fileName,
|
||||
fileName = _ref$fileName === void 0 ? 'image' : _ref$fileName,
|
||||
_ref$fileType = _ref.fileType,
|
||||
fileType = _ref$fileType === void 0 ? 'image/png' : _ref$fileType;
|
||||
try {
|
||||
var video = _videoDom;
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var base64;
|
||||
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx === null || ctx === void 0 || ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx === null || ctx === void 0 || ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx === null || ctx === void 0 || ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
base64 = canvas.toDataURL(fileType);
|
||||
downloadAble && download(base64, fileName);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/meta",
|
||||
"version": "0.14.0",
|
||||
"version": "0.15.0",
|
||||
"description": "原子组件",
|
||||
"keywords": [
|
||||
"meta",
|
||||
|
@ -30,21 +30,24 @@ export default {
|
||||
//method
|
||||
bind() {
|
||||
const { canvas, element, eventHandleList = [], options } = this;
|
||||
//图片事件
|
||||
// 鼠标滚轮事件
|
||||
const scaleAble = get(options, 'scaleAble', true);
|
||||
|
||||
if (scaleAble) {
|
||||
const handleWhele = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWhele);
|
||||
const handleWheel = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWheel);
|
||||
}
|
||||
|
||||
// 鼠标 - 拖拽事件
|
||||
const dragAble = get(options, 'dragAble', true);
|
||||
|
||||
if (dragAble) {
|
||||
const handleDragStart = addEventListenerWrapper(
|
||||
canvas,
|
||||
EVENT_POINTER_DOWN,
|
||||
this.onDragStart.bind(this)
|
||||
);
|
||||
eventHandleList.push(addEventListenerWrapper);
|
||||
eventHandleList.push(handleDragStart);
|
||||
const handleDragMove = addEventListenerWrapper(
|
||||
element.ownerDocument,
|
||||
EVENT_POINTER_MOVE,
|
||||
@ -53,23 +56,23 @@ export default {
|
||||
eventHandleList.push(handleDragMove);
|
||||
EVENT_POINTER_UP.trim()
|
||||
.split(REGEXP_SPACES)
|
||||
.forEach((eventName) => {
|
||||
.forEach((_eventName) => {
|
||||
const handleDragEnd = addEventListenerWrapper(
|
||||
element.ownerDocument,
|
||||
eventName,
|
||||
_eventName,
|
||||
this.onDragEnd.bind(this)
|
||||
);
|
||||
eventHandleList.push(handleDragEnd);
|
||||
});
|
||||
}
|
||||
|
||||
//rect事件
|
||||
const handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
// const handleLeveal = addEventListenerWrapper(canvas, EVENT_LEAVEL, this.onLeavel.bind(this));
|
||||
// eventHandleList.push(handleLeveal);
|
||||
// const handleEnter = addEventListenerWrapper(canvas, EVENT_ENTER, this.onEnter.bind(this));
|
||||
// eventHandleList.push(handleEnter);
|
||||
// 鼠标 - 点击事件
|
||||
const selectAble = get(options, 'selectAble', true);
|
||||
|
||||
if (selectAble) {
|
||||
const handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
}
|
||||
},
|
||||
unbind() {
|
||||
const { eventHandleList } = this;
|
||||
@ -83,7 +86,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/* 图片事件 */
|
||||
/* 鼠标滚轮事件 */
|
||||
onWheel(event, cropBox?) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
@ -123,6 +126,7 @@ export default {
|
||||
);
|
||||
},
|
||||
|
||||
// 鼠标拖拽 - 开始拖拽
|
||||
onDragStart(event) {
|
||||
event.stopPropagation();
|
||||
// This line is required for preventing page zooming in iOS browsers
|
||||
@ -150,6 +154,8 @@ export default {
|
||||
|
||||
addClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
|
||||
// 鼠标拖拽 - 拖拽中
|
||||
onDragMove(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
@ -175,6 +181,8 @@ export default {
|
||||
this.pointer.startX = this.pointer.endX;
|
||||
this.pointer.startY = this.pointer.endY;
|
||||
},
|
||||
|
||||
// 鼠标拖拽 - 停止拖拽
|
||||
onDragEnd(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
@ -190,14 +198,7 @@ export default {
|
||||
removeClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
|
||||
/* rect事件 */
|
||||
// onLeavel(event) {
|
||||
// const pointerCenter = this.windowToCanvasAxis(event);
|
||||
// this.highlightShape(pointerCenter);
|
||||
// },
|
||||
// onEnter(event) {
|
||||
// this.highlightShape(null);
|
||||
// },
|
||||
// 鼠标点击
|
||||
onClick(event) {
|
||||
event.stopPropagation();
|
||||
const pointerCenter = this.windowToCanvasAxis(event);
|
||||
|
@ -1,6 +1,21 @@
|
||||
//@ts-nocheck
|
||||
import * as turf from '@turf/turf';
|
||||
import { AXIS_TYPE_ORIGIN, AXIS_TYPE_CANVAS, AXIS_TYPE_IMAGE } from './constants';
|
||||
|
||||
export function rectToPolygon(axisRect: any) {
|
||||
const polygon = turf.polygon([
|
||||
[
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
[setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
[setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)],
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)],
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
],
|
||||
]);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
|
||||
//设置数据的精度
|
||||
//accuracy 表示精度 以原点为中心向左为正,向右为负,
|
||||
//isCeil 表示是否为向上取整
|
||||
@ -28,7 +43,7 @@ export default {
|
||||
targetTransform: {
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
scale: 0,
|
||||
scale: 1,
|
||||
rotate: 0,
|
||||
// rotate: 90,
|
||||
},
|
||||
@ -51,7 +66,7 @@ export default {
|
||||
},
|
||||
originAxisToCanvasAxis({ x, y, ...others }) {
|
||||
const { targetTransform } = this;
|
||||
const { translateX, translateY, scale } = targetTransform;
|
||||
const { translateX, translateY, scale = 1 } = targetTransform;
|
||||
const axis = {
|
||||
x: translateX + x * scale,
|
||||
y: translateY + y * scale,
|
||||
|
@ -28,6 +28,12 @@ export interface Option {
|
||||
*/
|
||||
dragAble?: boolean;
|
||||
|
||||
/*
|
||||
* 是否允许点击
|
||||
* @default: true
|
||||
*/
|
||||
selectAble?: boolean;
|
||||
|
||||
/*
|
||||
* fit scale 作为 最小缩放
|
||||
* @default: false
|
||||
|
@ -51,7 +51,6 @@ export default {
|
||||
},
|
||||
|
||||
initCanvas() {
|
||||
if (!this.image) return;
|
||||
//通过样式设置 不依赖父元素的prosition
|
||||
const { element, canvas, limit = {}, options } = this;
|
||||
const containerData = {
|
||||
@ -65,7 +64,7 @@ export default {
|
||||
const fitTransform = this.calcFitScreen();
|
||||
this.targetTransform = Object.assign({}, this.targetTransform, fitTransform);
|
||||
dispatchEvent(this.element, EVENT_VIEWER_TRANSFORM_CHANGE, cloneDeep(this.targetTransform));
|
||||
//产品需求:fitscale 是minscale
|
||||
//产品需求:fitscale 是 minscale
|
||||
const { fitScaleAsMinScale = false } = options;
|
||||
if (fitScaleAsMinScale) {
|
||||
this.limit = Object.assign({ minScale: this.targetTransform.scale }, this.limit);
|
||||
@ -86,8 +85,9 @@ export default {
|
||||
loop();
|
||||
},
|
||||
|
||||
// 绘制画布
|
||||
renderCanvas(_ctx) {
|
||||
if (!this.image || !this.canvas) return;
|
||||
if (!this.canvas) return;
|
||||
const { containerData, canvas, targetTransform, options } = this;
|
||||
const { translateX, translateY, scale, rotate } = targetTransform;
|
||||
const ctx = _ctx ? _ctx : canvas.getContext('2d');
|
||||
@ -102,14 +102,14 @@ export default {
|
||||
ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
// ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
//旋转
|
||||
const centerX = this.image.width / 2;
|
||||
const centerY = this.image.height / 2;
|
||||
const centerX = this.image ? this.image.width / 2 : canvas.width;
|
||||
const centerY = this.image ? this.image.height / 2 : canvas.height;
|
||||
ctx.translate(centerX, centerY);
|
||||
ctx.rotate((rotate / 180) * Math.PI);
|
||||
ctx.translate(-centerX, -centerY);
|
||||
|
||||
//图片
|
||||
ctx.drawImage(this.image, 0, 0);
|
||||
this.image && ctx.drawImage(this.image, 0, 0);
|
||||
|
||||
ctx.restore();
|
||||
//画图形
|
||||
|
@ -2,22 +2,10 @@
|
||||
import { isNil, isArray, isFunction } from '@zhst/func';
|
||||
import * as turf from '@turf/turf';
|
||||
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
||||
import { setNumberAccuracy } from './helper';
|
||||
import { rectToPolygon } from './helper';
|
||||
import { SHAPE_TYPE_RECT, SHAPE_TYPE_CIRCLE, EVENT_SHAPE_SELECT } from './constants';
|
||||
import { dispatchEvent } from '../utils';
|
||||
|
||||
function rectToPolygon(axisRect: any) {
|
||||
const polygon = turf.polygon([
|
||||
[
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
[setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
[setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)],
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)],
|
||||
[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)],
|
||||
],
|
||||
]);
|
||||
return polygon;
|
||||
}
|
||||
export interface Shape {
|
||||
id?: number | string; //uuid
|
||||
selectAble?: boolean;
|
||||
@ -64,14 +52,15 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
//method
|
||||
addShape(shap: Shape | Array<Shape>, type = SHAPE_TYPE_RECT) {
|
||||
this.color = shap.color ? shap.color : '';
|
||||
if (isNil(shap) || this.disableAdd) return;
|
||||
//method:添加矩形
|
||||
addShape(shape: Shape | Array<Shape>, type = SHAPE_TYPE_RECT) {
|
||||
this.color = shape.color ? shape.color : '';
|
||||
|
||||
if (isNil(shape) || this.disableAdd) return;
|
||||
const { shapeList: preShapeList = [] } = this;
|
||||
let shapList = isArray(shap) ? shap : [shap];
|
||||
shapList = shapList.map((v) => ({ ...v, __SHAPE_TYPE__: type }));
|
||||
this.shapeList = [...preShapeList, ...shapList];
|
||||
let _shapeList = isArray(shape) ? shape : [shape];
|
||||
_shapeList = _shapeList.map((v) => ({ ...v, __SHAPE_TYPE__: type }));
|
||||
this.shapeList = [...preShapeList, ..._shapeList];
|
||||
},
|
||||
//
|
||||
setSelectShapId(id: number) {
|
||||
@ -226,9 +215,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 绘制矩形
|
||||
renderRect(ctx, shape, type) {
|
||||
//算rect
|
||||
const axisRect = this.imgRectAxisToCanvasAxisRect(shape);
|
||||
const axisRect = this.imgRectAxisToCanvasAxisRect({ ...shape, image: ctx.canvas});
|
||||
const rect = {
|
||||
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
||||
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
||||
|
@ -7,25 +7,26 @@ import {
|
||||
nextTick,
|
||||
toRealNumber,
|
||||
getTransforms,
|
||||
formatDurationTime
|
||||
formatDurationTime,
|
||||
} from '@zhst/func';
|
||||
import Align from 'rc-align';
|
||||
import flvJs from 'flv.js'
|
||||
import { Rect, IScreenshotButtonProp, AlignType } from '@zhst/types'
|
||||
import { useLatest, useUpdateEffect, useFullscreen, useUnmount } from '@zhst/hooks';
|
||||
import classNames from 'classnames';
|
||||
import download from 'downloadjs';
|
||||
import { Button, message } from '..';
|
||||
import { message } from '..';
|
||||
import { IconFont } from '@zhst/icon';
|
||||
import {
|
||||
Cropper,
|
||||
EVENT_CROP_START,
|
||||
EVENT_CROP_END,
|
||||
Viewer,
|
||||
} from '../ImageEditor';
|
||||
import FlvPlayer, { FLV_EVENT } from './components/FlvPlayer';
|
||||
import Range from './components/Progress';
|
||||
import Loading from './components/Loading';
|
||||
import { CROP_TYPE } from '../utils/constants';
|
||||
import { getShowStatus } from './videoPlayerHelper'
|
||||
import { downloadFrame, DownloadFrameOptionProps, getShowStatus } from './videoPlayerHelper'
|
||||
import './index.less'
|
||||
|
||||
const componentName = `zhst-image__video-view`;
|
||||
@ -33,8 +34,21 @@ const componentName = `zhst-image__video-view`;
|
||||
export interface VideoViewProps {
|
||||
/* 播放地址 */
|
||||
url: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
backgroundColor?: string; // 背景颜色
|
||||
autoPlay?: boolean; // 自动播放
|
||||
showOD?: boolean;
|
||||
odList?: {
|
||||
id: string;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
selectAble?: boolean;
|
||||
}[]
|
||||
/* 播放总时间 */
|
||||
maxDuration?: number;
|
||||
maxDuration?: number; // 最大播放时长
|
||||
/* 截图渲染 */
|
||||
screenshotButtonAlign?: AlignType;
|
||||
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
|
||||
@ -42,13 +56,18 @@ export interface VideoViewProps {
|
||||
defautlNormalizationRect?: Rect;
|
||||
/* 截图回调 */
|
||||
onCropChange?: (showCrop: boolean, normalizationRect: null | Rect) => void;
|
||||
playerProps?: flvJs.Player
|
||||
}
|
||||
|
||||
|
||||
export interface VideoViewRef {
|
||||
/* 当前图片模式 */
|
||||
cropAble: boolean;
|
||||
setShowCrop: Dispatch<SetStateAction<boolean>>;
|
||||
downloadVideoframe: () => void;
|
||||
downloadVideoFrame: (opt?: DownloadFrameOptionProps) => void; // 视频截帧
|
||||
pause: () => void;
|
||||
play: () => void;
|
||||
reload: () => void; // 重新加载
|
||||
}
|
||||
|
||||
const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
@ -63,19 +82,26 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
adjustY: true,
|
||||
},
|
||||
},
|
||||
autoPlay = false,
|
||||
odList,
|
||||
showOD,
|
||||
width = '100%',
|
||||
height = '532px',
|
||||
backgroundColor = '#333',
|
||||
screenshotButtonRender = () => <div style={{ color: '#fff', width: '80px', top: 0 }}>回调DOM</div>,
|
||||
onCropChange,
|
||||
defautlNormalizationRect: defaultNormalizationRect,
|
||||
playerProps,
|
||||
} = props;
|
||||
// ========================== 播放 =========================
|
||||
//实例参数
|
||||
const containerRef: any = useRef(null); //容器ref
|
||||
const videoRef: any = useRef(null); //video 标签dom
|
||||
const videoInsRef: any = useRef(null); //flv 实例
|
||||
const [playSeq, setPlaySeq] = useState(0); // 通过重置playid使FLV组件重新渲染
|
||||
const videoRemoveListener = useRef(noop); //移除dom监听的中间函数
|
||||
const loadingTimeRef = useRef<number | null>(0); //最后一次加载时间
|
||||
const delayLoadingTimer: any = useRef(null); //算loading的定时器
|
||||
const containerRef: any = useRef(null); //容器ref
|
||||
const videoRef: any = useRef(null); //video 标签dom
|
||||
const videoInsRef: any = useRef(null); //flv 实例
|
||||
const [playSeq, setPlaySeq] = useState(0); // 通过重置playid使FLV组件重新渲染
|
||||
const videoRemoveListener = useRef(noop); //移除dom监听的中间函数
|
||||
const loadingTimeRef = useRef<number | null>(0); //最后一次加载时间
|
||||
const delayLoadingTimer: any = useRef(null); //算loading的定时器
|
||||
//状态参数
|
||||
const [isReady, setIsReady] = useState(false); //
|
||||
const [isPlay, setIsPlay] = useState(false); //当前是否播放
|
||||
@ -146,6 +172,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
|
||||
// 初始化
|
||||
const latestMaxDuration = useLatest(maxDuration);
|
||||
|
||||
const initPlayer = useCallback((ins: any, dom: any) => {
|
||||
videoRef.current = dom;
|
||||
videoInsRef.current = ins;
|
||||
@ -248,6 +275,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 重新加载
|
||||
const reload = async () => {
|
||||
if (videoInsRef.current) {
|
||||
let oldTime = videoInsRef.current.currentTime;
|
||||
@ -279,6 +307,8 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
setPlayTime(0);
|
||||
setIsEnd(false);
|
||||
};
|
||||
|
||||
// 进度条操作
|
||||
const seek = (v: number) => {
|
||||
if (videoInsRef.current && isVideoLoadFinished) {
|
||||
setPlayTime(parseFloat(v as any));
|
||||
@ -287,6 +317,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
message.warning('待视频加载完,才可操作进度条')
|
||||
}
|
||||
};
|
||||
|
||||
// ========================== 视频opt bar =========================
|
||||
const [isFullscreen, { toggleFullscreen }] = useFullscreen(containerRef, {
|
||||
pageFullscreen: true,
|
||||
@ -318,15 +349,14 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
const alignRef: any = useRef(null);
|
||||
const [cropRect, setCropRect] = useState<Rect| null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
showCrop ? videoInsRef?.current?.pause() : videoInsRef?.current?.play();
|
||||
}, [showCrop]);
|
||||
|
||||
// 监听showCrop, isReady - 是否可编辑、视频播放组件是否挂载
|
||||
useEffect(() => {
|
||||
let handlerCropStart: { remove: () => void; };
|
||||
let handlerCropEnd: { remove: () => void; };
|
||||
setCropRect(null);
|
||||
|
||||
if (!isReady) return;
|
||||
|
||||
if (showCrop) {
|
||||
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, () => {
|
||||
setCropRect(null);
|
||||
@ -384,12 +414,32 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
}
|
||||
isFirstFlagRef.current = false;
|
||||
|
||||
// 初始化圈选工具
|
||||
cropInsRef.current = new Cropper(corpContainerRef.current, {
|
||||
showMask: true,
|
||||
cropBoxLimited,
|
||||
editAble: false,
|
||||
img: imageData,
|
||||
initialCropBoxData,
|
||||
});
|
||||
videoInsRef?.current?.pause()
|
||||
} else {
|
||||
const _element = videoInsRef.current._mediaElement || {}
|
||||
videoInsRef?.current?.play()
|
||||
// 挂载图片选择
|
||||
cropInsRef.current = new Viewer(corpContainerRef.current!!, {
|
||||
scaleAble: false,
|
||||
selectAble: false,
|
||||
dragAble: false,
|
||||
width: _element.clientWidth,
|
||||
height: _element.clientHeight,
|
||||
backgroundColor: 'transparent'
|
||||
});
|
||||
|
||||
// 判定是否存在od框
|
||||
showOD && odList?.forEach(_od => {
|
||||
cropInsRef?.current?.addShape(_od);
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
handlerCropStart?.remove();
|
||||
@ -454,7 +504,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
};
|
||||
};
|
||||
|
||||
//回调
|
||||
// 监听showCrop、cropRect - 监听是否可编辑、绘制的矩形
|
||||
useEffect(() => {
|
||||
//计算归一化crop rect
|
||||
let normalizationRect = null;
|
||||
@ -484,32 +534,9 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
}, [showCrop, cropRect]);
|
||||
|
||||
// ========================== 截帧 =========================
|
||||
const downloadVideoframe = useCallback(async () => {
|
||||
try {
|
||||
const downloadVideoFrame = useCallback((opt?: DownloadFrameOptionProps) => {
|
||||
videoInsRef?.current?.pause?.();
|
||||
let video: any = videoRef.current;
|
||||
var canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d')
|
||||
let base64;
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx?.fillRect(0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL();
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL('image/png');
|
||||
}
|
||||
download(base64);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
downloadFrame(videoRef.current, opt)
|
||||
}, []);
|
||||
|
||||
// ============================== 暴露出去的方法 ===============================
|
||||
@ -520,18 +547,33 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
setShowCrop: (dispatch) => {
|
||||
const isReady = latestIsReady.current;
|
||||
if (!isReady) return;
|
||||
setShowCrop(dispatch);
|
||||
setShowCrop?.(dispatch);
|
||||
},
|
||||
downloadVideoframe,
|
||||
downloadVideoFrame,
|
||||
pause: () => {
|
||||
videoInsRef.current?.pause?.();
|
||||
},
|
||||
play: () => {
|
||||
videoInsRef.current?.play?.();
|
||||
},
|
||||
reload
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={classNames(`${componentName}`)} ref={containerRef}>
|
||||
<div
|
||||
className={classNames(`${componentName}`)}
|
||||
ref={containerRef}
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
backgroundColor
|
||||
}}
|
||||
>
|
||||
{url && (
|
||||
<>
|
||||
<FlvPlayer
|
||||
playId={playSeq}
|
||||
autoPlay={true}
|
||||
autoPlay={autoPlay}
|
||||
className={classNames(`${componentName}-flv`)}
|
||||
type={url.startsWith('http') ? 'mp4' : 'flv'}
|
||||
url={url}
|
||||
@ -542,7 +584,8 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
hasAudio: false,
|
||||
hasVideo: true,
|
||||
}}
|
||||
onCreat={initPlayer}
|
||||
onCreate={initPlayer}
|
||||
{...playerProps}
|
||||
/>
|
||||
{/* //截图 */}
|
||||
<div
|
||||
@ -550,10 +593,12 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
ref={corpContainerRef}
|
||||
style={{
|
||||
display: isFullscreen ? 'none' : 'block',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}}
|
||||
>
|
||||
{/* <div ref={corpRef}></div> */}
|
||||
</div>
|
||||
{/* OD控件工具 */}
|
||||
{showCrop && cropRect && (
|
||||
<>
|
||||
<div
|
||||
@ -587,32 +632,27 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
</Align>
|
||||
</>
|
||||
)}
|
||||
{/* 视频进度条 */}
|
||||
{/* 视频工具栏 */}
|
||||
{!showCrop && (
|
||||
<div className={`${componentName}-opt`}>
|
||||
<div>
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
if (!isPlay) {
|
||||
//播放中暂停
|
||||
videoInsRef?.current?.play();
|
||||
setShowCrop(false);
|
||||
} else {
|
||||
videoInsRef?.current?.pause();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<IconFont
|
||||
styles={{
|
||||
color: '#fff',
|
||||
display: 'flex',
|
||||
}}
|
||||
color="#1890ff"
|
||||
icon={!isPlay ? 'icon-shipinbofang' : 'icon-shipinzanting'}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<IconFont
|
||||
styles={{
|
||||
marginRight: '12px',
|
||||
color: '#fff',
|
||||
display: 'flex',
|
||||
}}
|
||||
onIconClick={() => {
|
||||
if (!isPlay) {
|
||||
//播放中暂停
|
||||
videoInsRef?.current?.play();
|
||||
setShowCrop(false);
|
||||
} else {
|
||||
videoInsRef?.current?.pause();
|
||||
}
|
||||
}}
|
||||
color="#1890ff"
|
||||
icon={!isPlay ? 'icon-bofang3' : 'icon-zanting1'}
|
||||
/>
|
||||
<div
|
||||
className={`${componentName}-opt-range`}
|
||||
onClick={(e) => {
|
||||
@ -631,24 +671,19 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||
{formatDurationTime(playTime)}/{formatDurationTime(showMaxDuration)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
type="text"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleFullscreen();
|
||||
}}
|
||||
>
|
||||
<IconFont
|
||||
styles={{
|
||||
color: '#fff',
|
||||
display: 'flex',
|
||||
}}
|
||||
size={18}
|
||||
icon={isFullscreen ? 'icon-cancle_fullscreen' : 'icon-fullscreen'}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<IconFont
|
||||
styles={{
|
||||
display: 'flex',
|
||||
marginLeft: '12px'
|
||||
}}
|
||||
color="#fff"
|
||||
size={18}
|
||||
onIconClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleFullscreen();
|
||||
}}
|
||||
icon={isFullscreen ? 'icon-suoxiao1' : 'icon-quanping1'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* mask */}
|
||||
|
@ -20,7 +20,7 @@ export interface VideoPlayerProps {
|
||||
filesize?: number;
|
||||
url?: string;
|
||||
autoPlay?: boolean;
|
||||
onCreat?: any;
|
||||
onCreate?: any;
|
||||
|
||||
/**
|
||||
* @see https://github.com/Bilibili/flv.js/blob/master/docs/api.md#config
|
||||
@ -33,7 +33,7 @@ export default class VideoPlayer extends Component<VideoPlayerProps, any> {
|
||||
curPlayUrl: '',
|
||||
shouldReinit: false,
|
||||
};
|
||||
flvPlayer: any = null;
|
||||
flvPlayer: flvjs.Player & { reload?: () => void; } | null = null;
|
||||
videoElement = null;
|
||||
|
||||
static getDerivedStateFromProps = (nextProps: { url?: any; playId?: any; }, prevState: { curPlayUrl?: any; playId?: any; }) => {
|
||||
@ -55,7 +55,7 @@ export default class VideoPlayer extends Component<VideoPlayerProps, any> {
|
||||
|
||||
initFlv = ($video: null) => {
|
||||
this.videoElement = $video;
|
||||
const { className, autoPlay = true, config = {}, onCreat, playId, ...others } = this.props;
|
||||
const { className, autoPlay = true, config = {}, onCreate, playId, ...others } = this.props;
|
||||
|
||||
if ($video) {
|
||||
|
||||
@ -77,27 +77,27 @@ export default class VideoPlayer extends Component<VideoPlayerProps, any> {
|
||||
flvPlayer.load();
|
||||
this.flvPlayer = flvPlayer;
|
||||
// @ts-ignore
|
||||
let controller = this.flvPlayer._transmuxer._controller
|
||||
let controller = this.flvPlayer?._transmuxer?._controller
|
||||
let wsLoader = controller._ioctl._loader
|
||||
const oldWsOnCompleteFunc = wsLoader._onComplete
|
||||
wsLoader._onComplete = function() {
|
||||
|
||||
if(!controller._remuxer) {
|
||||
controller._remuxer = {
|
||||
destroy: () => {
|
||||
console.log('组件销毁')
|
||||
},
|
||||
flushStashedSamples: () => {
|
||||
console.log("flushStashedSamples")
|
||||
console.log("flushStashedSamples")
|
||||
}
|
||||
}
|
||||
}
|
||||
oldWsOnCompleteFunc()
|
||||
}
|
||||
this.flvPlayer.reload = reload;
|
||||
onCreat && onCreat(this.flvPlayer, $video);
|
||||
onCreate?.(this.flvPlayer, $video);
|
||||
};
|
||||
reload();
|
||||
onCreat && onCreat(this.flvPlayer, $video);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -121,14 +121,11 @@ export default class VideoPlayer extends Component<VideoPlayerProps, any> {
|
||||
muted
|
||||
preload="metadata"
|
||||
className={className}
|
||||
// controls={true}
|
||||
style={Object.assign(
|
||||
{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
style ? style : {}
|
||||
)}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
...style
|
||||
}}
|
||||
ref={this.initFlv}
|
||||
/>
|
||||
);
|
||||
|
@ -0,0 +1,107 @@
|
||||
// @ts-nocheck
|
||||
import React, { forwardRef, useContext, useEffect, useImperativeHandle, useRef } from 'react'
|
||||
import flvJs from 'flv.js'
|
||||
import { ConfigProvider } from '../../..'
|
||||
|
||||
export interface FlvPlayerProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
autoPlay?: boolean;
|
||||
config?: flvJs.Config
|
||||
onCreate?: () => void;
|
||||
playId?: string;
|
||||
url: string;
|
||||
type: string;
|
||||
style?: React.CSSProperties
|
||||
}
|
||||
|
||||
export interface FlvPlayerRefProps {
|
||||
}
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
const FlvPlayer = forwardRef<FlvPlayerRefProps, FlvPlayerProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls
|
||||
} = props
|
||||
const {
|
||||
className,
|
||||
autoPlay = true,
|
||||
config = {},
|
||||
onCreate,
|
||||
url,
|
||||
style,
|
||||
type = 'flv',
|
||||
playId,
|
||||
...others
|
||||
} = props;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('cropper-view', customizePrefixCls);
|
||||
const flvPlayerRef = useRef<flvJs.Player>()
|
||||
|
||||
// 初始化播放器
|
||||
useEffect(() => {
|
||||
if (flvJs.isSupported() && url) {
|
||||
if (flvPlayerRef.current && flvPlayerRef.current.destroy) {
|
||||
try {
|
||||
flvPlayerRef.current.destroy()
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
let flvPlayer = flvJs.createPlayer({
|
||||
type: url.startsWith('http') ? 'mp4' : 'flv',
|
||||
...others
|
||||
}, {
|
||||
deferLoadAfterSourceOpen: false,
|
||||
...config
|
||||
});
|
||||
// @ts-ignore
|
||||
flvPlayer.attachMediaElement(flvPlayerRef.current);
|
||||
flvPlayer.load();
|
||||
flvPlayerRef.current = flvPlayer;
|
||||
// @ts-ignore
|
||||
let controller = flvPlayerRef.current?._transmuxer?._controller
|
||||
let wsLoader = controller._ioctl._loader
|
||||
const oldWsOnCompleteFunc = wsLoader._onComplete
|
||||
wsLoader._onComplete = function() {
|
||||
|
||||
if(!controller._remuxer) {
|
||||
controller._remuxer = {
|
||||
destroy: () => {
|
||||
console.log('组件销毁')
|
||||
},
|
||||
flushStashedSamples: () => {
|
||||
console.log("flushStashedSamples")
|
||||
}
|
||||
}
|
||||
}
|
||||
oldWsOnCompleteFunc()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
player: flvPlayerRef
|
||||
}))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={componentName}
|
||||
>
|
||||
<video
|
||||
muted
|
||||
preload="metadata"
|
||||
className={className}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
...style
|
||||
}}
|
||||
ref={flvPlayerRef}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default FlvPlayer
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Slider } from 'antd';
|
||||
import { Slider, ConfigProvider } from 'antd';
|
||||
import type { SliderSingleProps } from 'antd'
|
||||
import './index.less';
|
||||
|
||||
@ -24,7 +24,18 @@ export const Range: React.FC<RangeWrapperProps> = (props) => {
|
||||
)}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<Slider {...others}></Slider>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Slider: {
|
||||
railBg: 'rgba(255, 255, 255, 0.6)',
|
||||
railHoverBg: 'rgba(255, 255, 255, 0.6)',
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Slider {...others}></Slider>
|
||||
</ConfigProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,18 +1,44 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { VideoPlayer, Space, Button } from '@zhst/meta'
|
||||
import { VideoPlayer, Space, Button, VideoViewRef } from '@zhst/meta'
|
||||
import { VIDEO_URL } from './mock'
|
||||
|
||||
export default () => {
|
||||
const videoRef = useRef(null)
|
||||
const [url, setUrl] = useState(null)
|
||||
const videoRef = useRef<VideoViewRef>(null)
|
||||
const [url] = useState(VIDEO_URL)
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Space direction='vertical'>
|
||||
<Space>
|
||||
<Button onClick={() => setUrl('ws://10.0.0.120:9033/flv/HaikangNvr/45.flv?ip=10.0.2.103&stime=1712539148&etime=1712539168')}>播放</Button>
|
||||
<Button onClick={() => videoRef.current?.play()}>播放</Button>
|
||||
<Button onClick={() => videoRef.current?.pause()}>暂停</Button>
|
||||
<Button onClick={() => videoRef.current?.setShowCrop(true)}>截图</Button>
|
||||
<Button onClick={() => videoRef.current?.setShowCrop(false)}>取消</Button>
|
||||
<Button onClick={() => videoRef.current?.setShowCrop(false)}>退出截图</Button>
|
||||
<Button onClick={() => videoRef.current?.downloadVideoFrame()}>下载截图</Button>
|
||||
</Space>
|
||||
{url && <VideoPlayer ref={videoRef} url={url} />}
|
||||
<div style={{ width: '800px' }}>
|
||||
<VideoPlayer
|
||||
ref={videoRef}
|
||||
url={url}
|
||||
showOD
|
||||
odList={[
|
||||
{
|
||||
"id": "123",
|
||||
"x": 0.5519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
selectAble: false,
|
||||
},
|
||||
{
|
||||
"id": "456",
|
||||
"x": 0.58543766,
|
||||
"y": 0.3203356,
|
||||
"w": 0.052037954,
|
||||
"h": 0.2664015
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
1
packages/meta/src/VideoPlayer/demo/mock.ts
Normal file
1
packages/meta/src/VideoPlayer/demo/mock.ts
Normal file
@ -0,0 +1 @@
|
||||
export const VIDEO_URL = `ws://10.0.0.7:9033/flv/File/test/test_h264_${Math.floor(Math.random() * 6) + 1}.mp4.flv?ip=127.0.0.1`
|
@ -1,5 +1,6 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { VideoPlayer, Space, Button, Row, Col, InputNumber } from '@zhst/meta'
|
||||
import { VIDEO_URL } from './mock'
|
||||
|
||||
export default () => {
|
||||
const [urls, setUrls] = useState<string[]>([])
|
||||
@ -8,7 +9,7 @@ export default () => {
|
||||
const handlePlay = () => {
|
||||
let arr = []
|
||||
for (let i = 0; i < num; i++) {
|
||||
arr.push(`ws://10.0.0.7:9033/flv/File/test/test_h264_${Math.floor(Math.random() * 6) + 1}.mp4.flv?ip=127.0.0.1`)
|
||||
arr.push(VIDEO_URL)
|
||||
}
|
||||
setUrls(arr)
|
||||
}
|
||||
@ -16,12 +17,12 @@ export default () => {
|
||||
return (
|
||||
<div>
|
||||
<Space>
|
||||
<InputNumber value={num} onChange={(_num: React.SetStateAction<number>) => setNum(_num)} />
|
||||
<InputNumber value={num} onChange={(_num) => setNum(_num!!)} />
|
||||
<Button onClick={() => handlePlay()}>播放</Button>
|
||||
<Button onClick={() => setUrls([])}>停止</Button>
|
||||
</Space>
|
||||
<Row gutter={[16,16]}>
|
||||
{urls.map((url, idx) => (
|
||||
{urls.map((url) => (
|
||||
<Col span={8}>
|
||||
<VideoPlayer key={url} url={url} />
|
||||
</Col>
|
||||
|
29
packages/meta/src/VideoPlayer/demo/newFlv.tsx
Normal file
29
packages/meta/src/VideoPlayer/demo/newFlv.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Space, Button, VideoViewRef } from '@zhst/meta'
|
||||
import { VIDEO_URL } from './mock'
|
||||
import FlvPlayer from '../components/FlvPlayer/newFlvPlayer';
|
||||
|
||||
export default () => {
|
||||
const videoRef = useRef<VideoViewRef>(null)
|
||||
const [url] = useState(VIDEO_URL)
|
||||
|
||||
return (
|
||||
<Space direction='vertical'>
|
||||
<Space>
|
||||
<Button onClick={() => videoRef.current?.play()}>播放</Button>
|
||||
</Space>
|
||||
<div style={{ width: '800px' }}>
|
||||
<FlvPlayer
|
||||
ref={videoRef}
|
||||
url={url}
|
||||
config={{
|
||||
enableStashBuffer: true,
|
||||
stashInitialSize: 1024 * 700,
|
||||
isLive: true,
|
||||
hasVideo: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
)
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
.zhst-image__video-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 532px;
|
||||
background-color: #333;
|
||||
|
||||
// &-flv {
|
||||
@ -37,7 +35,7 @@
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
padding: 0 12px 0 24px;
|
||||
background-color: rgb(0 0 0 / 80%);
|
||||
line-height: 32px;
|
||||
|
||||
|
@ -8,15 +8,30 @@ demo:
|
||||
cols: 2
|
||||
---
|
||||
|
||||
# VideoPlayer 视频播放
|
||||
## VideoPlayer 视频播放
|
||||
|
||||
:::warning{title=注意}
|
||||
播放进度条操作还未完善,在播放结束和拖拽的过程中都有一定程度卡顿,目前逻辑待优化
|
||||
:::
|
||||
|
||||
### 功能支持
|
||||
|
||||
1. 视频播放:mp4、ws链接、直播流... ✔
|
||||
2. 视频操作:播放、暂停、全屏观看、进度条 ✔
|
||||
3. 视频截图 ✔
|
||||
4. 下载视频截图 ✔
|
||||
5. OD 跟随
|
||||
|
||||
### 实现思路
|
||||
|
||||
#### OD 跟随
|
||||
|
||||
根据传递的od框数据实时跟踪目标移动轨迹,目前的构想是通过底层的flvjs拉取视频流播放,再通过canvas截帧,同时传入 OD 对象数组 requestAnimationFrame 去绘制;
|
||||
|
||||
<code src="./demo/basic.tsx">基础</code>
|
||||
|
||||
<code src="./demo/multiple.tsx">测试视频播放压力</code>
|
||||
<!-- <code src="./demo/newFlv.tsx" debug>新flv播放器</code> -->
|
||||
|
||||
## API
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import download from "downloadjs";
|
||||
|
||||
export function getShowStatus(isLoadingVideo: boolean, isEnd: boolean, isError: boolean) {
|
||||
let status = null;
|
||||
@ -12,3 +13,44 @@ export function getShowStatus(isLoadingVideo: boolean, isEnd: boolean, isError:
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// 下载功能的可配置属性
|
||||
export interface DownloadFrameOptionProps {
|
||||
fileName?: string; // 文件名称
|
||||
downloadAble?: boolean; // 是否开启下载
|
||||
fileType?: string;
|
||||
}
|
||||
|
||||
// 视屏截帧、下载
|
||||
export const downloadFrame = (_videoDom: HTMLVideoElement, opt?: DownloadFrameOptionProps) => {
|
||||
const {
|
||||
downloadAble = true,
|
||||
fileName = 'image',
|
||||
fileType = 'image/png'
|
||||
} = opt || {}
|
||||
try {
|
||||
let video = _videoDom;
|
||||
var canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d')
|
||||
let base64;
|
||||
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx?.fillRect(0, 0, canvas.width, canvas.height);
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
base64 = canvas.toDataURL(fileType);
|
||||
downloadAble && download(base64, fileName);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ export interface CropperImageProps {
|
||||
lineConfig?: fabric.Line; // 线条配置
|
||||
editAble?: boolean; // 是否可编辑
|
||||
selectedItem?: RectPro
|
||||
selectAble?: boolean;
|
||||
// 是否可放大缩小
|
||||
scaleAble?: boolean;
|
||||
// 是否展示框选拓展框
|
||||
@ -77,6 +78,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
|
||||
onCropEnd,
|
||||
editAble,
|
||||
onShapeSelected,
|
||||
selectAble = true,
|
||||
showToast = false,
|
||||
customToast = () => <div>无</div>,
|
||||
type = 'ract',
|
||||
@ -106,6 +108,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
|
||||
viewerRef.current = new Viewer(imageRef.current!!, {
|
||||
image: url,
|
||||
scaleAble,
|
||||
selectAble,
|
||||
dragAble: false,
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,15 @@
|
||||
# @zhst/request
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 视频添加 OD 框,查看大图首次点击修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.10.2
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
30
packages/request/es/index.d.ts
vendored
30
packages/request/es/index.d.ts
vendored
@ -1,30 +0,0 @@
|
||||
export interface ReqConfigProps {
|
||||
timeout?: number;
|
||||
baseURL?: string;
|
||||
errorConfig?: {
|
||||
errorHandler?: (error: any, opts: any) => void;
|
||||
errorThrower?: (err: any) => void;
|
||||
};
|
||||
authorization?: string;
|
||||
showMsg?: boolean;
|
||||
onError: (error?: any) => void;
|
||||
}
|
||||
export declare const reqConfig: (config: ReqConfigProps) => {
|
||||
timeout: number;
|
||||
baseURL: string;
|
||||
errorConfig: {
|
||||
errorHandler?: ((error: any, opts: any) => void) | undefined;
|
||||
errorThrower?: ((err: any) => void) | undefined;
|
||||
};
|
||||
authorization?: string | undefined;
|
||||
showMsg?: boolean | undefined;
|
||||
onError: (error?: any) => void;
|
||||
requestInterceptors: (((url: any, options: any) => {
|
||||
url: any;
|
||||
options: any;
|
||||
}) | ((error: any) => Promise<never>))[][];
|
||||
responseInterceptors: ((response: {
|
||||
status: number;
|
||||
data: any;
|
||||
}) => any)[][];
|
||||
};
|
30
packages/request/lib/index.d.ts
vendored
30
packages/request/lib/index.d.ts
vendored
@ -1,30 +0,0 @@
|
||||
export interface ReqConfigProps {
|
||||
timeout?: number;
|
||||
baseURL?: string;
|
||||
errorConfig?: {
|
||||
errorHandler?: (error: any, opts: any) => void;
|
||||
errorThrower?: (err: any) => void;
|
||||
};
|
||||
authorization?: string;
|
||||
showMsg?: boolean;
|
||||
onError: (error?: any) => void;
|
||||
}
|
||||
export declare const reqConfig: (config: ReqConfigProps) => {
|
||||
timeout: number;
|
||||
baseURL: string;
|
||||
errorConfig: {
|
||||
errorHandler?: ((error: any, opts: any) => void) | undefined;
|
||||
errorThrower?: ((err: any) => void) | undefined;
|
||||
};
|
||||
authorization?: string | undefined;
|
||||
showMsg?: boolean | undefined;
|
||||
onError: (error?: any) => void;
|
||||
requestInterceptors: (((url: any, options: any) => {
|
||||
url: any;
|
||||
options: any;
|
||||
}) | ((error: any) => Promise<never>))[][];
|
||||
responseInterceptors: ((response: {
|
||||
status: number;
|
||||
data: any;
|
||||
}) => any)[][];
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/request",
|
||||
"version": "0.10.1",
|
||||
"version": "0.11.0",
|
||||
"description": "请求库",
|
||||
"keywords": [
|
||||
"request",
|
||||
|
@ -1,5 +1,11 @@
|
||||
# @zhst/slave
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.10.2
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/slave",
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"description": "微前端子应用方法库",
|
||||
"keywords": [
|
||||
"slave",
|
||||
|
Loading…
Reference in New Issue
Block a user