Add VideoDataChart

This commit is contained in:
Yang Luo 2023-05-29 01:36:05 +08:00
parent 0a08cf05b9
commit ccd01ab604
4 changed files with 155 additions and 50 deletions

View File

@ -13,7 +13,7 @@
"copy-to-clipboard": "^3.3.1",
"craco-less": "2.0.0",
"d3-force": "^3.0.0",
"echarts": "^5.4.0",
"echarts": "^5.4.2",
"echarts-for-react": "^3.0.2",
"file-saver": "^2.0.2",
"i18next": "^19.8.9",

94
web/src/VideoDataChart.js Normal file
View File

@ -0,0 +1,94 @@
import React, { Component } from "react";
import ReactEcharts from 'echarts-for-react';
class VideoDataChart extends Component {
drawPic(data, nowTime) {
const xAxisData = data.map(item => Number(item.time));
const seriesData = data.map(item => ({
value: Number(item.data),
error: Number(item.confidence)
}));
let dataMax = -Infinity;
let dataMin = Infinity;
for (let i = 0; i < seriesData.length; i++) {
const value = seriesData[i].value;
if (value > dataMax) {
dataMax = value;
}
if (value < dataMin) {
dataMin = value;
}
}
const option = {
grid: {
top: '5%',
left: '3%',
right: '4%',
bottom: '8%',
containLabel: true
},
xAxis: {
type: 'category',
data: xAxisData
},
yAxis: {
type: 'value',
min: dataMin,
max: dataMax
},
series: [
{
name: 'Data',
type: 'line',
data: seriesData
}
],
markLine: {
symbol: 'none',
lineStyle: {
color: 'red'
},
data: [
{
xAxis: nowTime,
yAxis: dataMin,
symbol: 'none',
lineStyle: {
color: 'red'
}
},
{
xAxis: nowTime,
yAxis: dataMax,
symbol: 'none',
lineStyle: {
color: 'red'
}
}
]
}
};
return (
<ReactEcharts
option={option}
style={{ height: '200px' }}
/>
);
}
render() {
const nowTime = 285;
return (
<div>
{this.drawPic(this.props.data, nowTime)}
</div>
);
}
}
export default VideoDataChart;

View File

@ -7,6 +7,7 @@ import {LinkOutlined} from "@ant-design/icons";
import Video from "./Video";
import LabelTable from "./LabelTable";
import * as Papa from "papaparse";
import VideoDataChart from "./VideoDataChart";
const { Option } = Select;
@ -20,6 +21,7 @@ class VideoEditPage extends React.Component {
player: null,
screen: null,
videoObj: null,
videoData: null,
};
this.labelTable = React.createRef();
@ -38,7 +40,7 @@ class VideoEditPage extends React.Component {
});
if (video.dataUrl !== "") {
this.parseCsv(video.dataUrl);
this.getDataAndParse(video.dataUrl);
}
});
}
@ -89,34 +91,34 @@ class VideoEditPage extends React.Component {
};
return (
<Affix offsetTop={100}>
<div style={{marginTop: "10px"}}>
<div className="screen" style={{position: "absolute", zIndex: 100, pointerEvents: "none", width: '440px', height: '472px', marginLeft: '200px', marginRight: '200px', backgroundColor: "rgba(255,0,0,0)" }}></div>
<Video task={task} labels={this.state.video.labels}
onUpdateTime={(time) => {this.setState({currentTime: time})}}
onCreatePlayer={(player) => {this.setState({player: player})}}
onCreateScreen={(screen) => {this.setState({screen: screen})}}
onCreateVideo={(videoObj) => {this.setState({videoObj: videoObj})}}
onPause={() => {this.onPause()}}
/>
<div style={{fontSize: 16, marginTop: "10px"}}>
{i18next.t("video:Current time (second)")}: {" "}
{
this.state.currentTime
}
</div>
<div style={{marginTop: "10px"}}>
<div className="screen" style={{position: "absolute", zIndex: 100, pointerEvents: "none", width: '440px', height: '472px', marginLeft: '200px', marginRight: '200px', backgroundColor: "rgba(255,0,0,0)" }}></div>
<Video task={task} labels={this.state.video.labels}
onUpdateTime={(time) => {this.setState({currentTime: time})}}
onCreatePlayer={(player) => {this.setState({player: player})}}
onCreateScreen={(screen) => {this.setState({screen: screen})}}
onCreateVideo={(videoObj) => {this.setState({videoObj: videoObj})}}
onPause={() => {this.onPause()}}
/>
<div style={{fontSize: 16, marginTop: "10px"}}>
{i18next.t("video:Current time (second)")}: {" "}
{
this.state.currentTime
}
</div>
</Affix>
</div>
)
}
parseCsv(dataUrl) {
getDataAndParse(dataUrl) {
fetch(dataUrl, {
method: "GET",
}).then(res => res.text())
.then(res => {
const results = Papa.parse(res, { header: true });
console.log(results);
const result = Papa.parse(res, { header: true });
this.setState({
videoData: result.data,
});
});
}
@ -200,24 +202,33 @@ class VideoEditPage extends React.Component {
{i18next.t("video:Video")}:
</Col>
<Col span={11} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}>
{
this.state.video !== null ? this.renderVideoContent() : null
}
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Data")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: '100%'}} value={this.state.video.dataUrl} onChange={(value => {
this.parseCsv(value);
this.updateVideoField('dataUrl', value);
})}>
{
this.state.video.dataUrls?.map((dataUrl, index) => <Option key={index} value={dataUrl}>{dataUrl.split("/").pop()}</Option>)
}
</Select>
</Col>
</Row>
<React.Fragment>
<Affix offsetTop={50}>
{
this.state.video !== null ? this.renderVideoContent() : null
}
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{i18next.t("general:Data")}:
</Col>
<Col span={22} >
<Select virtual={false} style={{width: '100%'}} value={this.state.video.dataUrl} onChange={(value => {
this.getDataAndParse(value);
this.updateVideoField('dataUrl', value);
})}>
{
this.state.video.dataUrls?.map((dataUrl, index) => <Option key={index} value={dataUrl}>{dataUrl.split("/").pop()}</Option>)
}
</Select>
</Col>
</Row>
{
this.state.videoData === null ? null : (
<VideoDataChart data={this.state.videoData} />
)
}
</Affix>
</React.Fragment>
</Col>
<Col span={1}>
</Col>

View File

@ -4219,19 +4219,19 @@ duplexer@^0.1.2:
echarts-for-react@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1"
resolved "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1"
integrity sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==
dependencies:
fast-deep-equal "^3.1.3"
size-sensor "^1.0.1"
echarts@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.4.0.tgz#a9a8e5367293a397408d3bf3e2638b869249ce04"
integrity sha512-uPsO9VRUIKAdFOoH3B0aNg7NRVdN7aM39/OjovjO9MwmWsAkfGyeXJhK+dbRi51iDrQWliXV60/XwLA7kg3z0w==
echarts@^5.4.2:
version "5.4.2"
resolved "https://registry.npmjs.org/echarts/-/echarts-5.4.2.tgz#9f38781c9c6ae323e896956178f6956952c77a48"
integrity sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==
dependencies:
tslib "2.3.0"
zrender "5.4.0"
zrender "5.4.3"
ee-first@1.1.1:
version "1.1.1"
@ -10614,9 +10614,9 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zrender@5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.4.0.tgz#d4f76e527b2e3bbd7add2bdaf27a16af85785576"
integrity sha512-rOS09Z2HSVGFs2dn/TuYk5BlCaZcVe8UDLLjj1ySYF828LATKKdxuakSZMvrDz54yiKPDYVfjdKqcX8Jky3BIA==
zrender@5.4.3:
version "5.4.3"
resolved "https://registry.npmjs.org/zrender/-/zrender-5.4.3.tgz#41ffaf835f3a3210224abd9d6964b48ff01e79f5"
integrity sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==
dependencies:
tslib "2.3.0"