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", "copy-to-clipboard": "^3.3.1",
"craco-less": "2.0.0", "craco-less": "2.0.0",
"d3-force": "^3.0.0", "d3-force": "^3.0.0",
"echarts": "^5.4.0", "echarts": "^5.4.2",
"echarts-for-react": "^3.0.2", "echarts-for-react": "^3.0.2",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"i18next": "^19.8.9", "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 Video from "./Video";
import LabelTable from "./LabelTable"; import LabelTable from "./LabelTable";
import * as Papa from "papaparse"; import * as Papa from "papaparse";
import VideoDataChart from "./VideoDataChart";
const { Option } = Select; const { Option } = Select;
@ -20,6 +21,7 @@ class VideoEditPage extends React.Component {
player: null, player: null,
screen: null, screen: null,
videoObj: null, videoObj: null,
videoData: null,
}; };
this.labelTable = React.createRef(); this.labelTable = React.createRef();
@ -38,7 +40,7 @@ class VideoEditPage extends React.Component {
}); });
if (video.dataUrl !== "") { if (video.dataUrl !== "") {
this.parseCsv(video.dataUrl); this.getDataAndParse(video.dataUrl);
} }
}); });
} }
@ -89,34 +91,34 @@ class VideoEditPage extends React.Component {
}; };
return ( return (
<Affix offsetTop={100}> <div style={{marginTop: "10px"}}>
<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>
<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}
<Video task={task} labels={this.state.video.labels} onUpdateTime={(time) => {this.setState({currentTime: time})}}
onUpdateTime={(time) => {this.setState({currentTime: time})}} onCreatePlayer={(player) => {this.setState({player: player})}}
onCreatePlayer={(player) => {this.setState({player: player})}} onCreateScreen={(screen) => {this.setState({screen: screen})}}
onCreateScreen={(screen) => {this.setState({screen: screen})}} onCreateVideo={(videoObj) => {this.setState({videoObj: videoObj})}}
onCreateVideo={(videoObj) => {this.setState({videoObj: videoObj})}} onPause={() => {this.onPause()}}
onPause={() => {this.onPause()}} />
/> <div style={{fontSize: 16, marginTop: "10px"}}>
<div style={{fontSize: 16, marginTop: "10px"}}> {i18next.t("video:Current time (second)")}: {" "}
{i18next.t("video:Current time (second)")}: {" "} {
{ this.state.currentTime
this.state.currentTime }
}
</div>
</div> </div>
</Affix> </div>
) )
} }
parseCsv(dataUrl) { getDataAndParse(dataUrl) {
fetch(dataUrl, { fetch(dataUrl, {
method: "GET", method: "GET",
}).then(res => res.text()) }).then(res => res.text())
.then(res => { .then(res => {
const results = Papa.parse(res, { header: true }); const result = Papa.parse(res, { header: true });
console.log(results); this.setState({
videoData: result.data,
});
}); });
} }
@ -200,24 +202,33 @@ class VideoEditPage extends React.Component {
{i18next.t("video:Video")}: {i18next.t("video:Video")}:
</Col> </Col>
<Col span={11} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}> <Col span={11} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}>
{ <React.Fragment>
this.state.video !== null ? this.renderVideoContent() : null <Affix offsetTop={50}>
} {
<Row style={{marginTop: '20px'}} > this.state.video !== null ? this.renderVideoContent() : null
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}> }
{i18next.t("general:Data")}: <Row style={{marginTop: '20px'}} >
</Col> <Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
<Col span={22} > {i18next.t("general:Data")}:
<Select virtual={false} style={{width: '100%'}} value={this.state.video.dataUrl} onChange={(value => { </Col>
this.parseCsv(value); <Col span={22} >
this.updateVideoField('dataUrl', value); <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> this.state.video.dataUrls?.map((dataUrl, index) => <Option key={index} value={dataUrl}>{dataUrl.split("/").pop()}</Option>)
</Col> }
</Row> </Select>
</Col>
</Row>
{
this.state.videoData === null ? null : (
<VideoDataChart data={this.state.videoData} />
)
}
</Affix>
</React.Fragment>
</Col> </Col>
<Col span={1}> <Col span={1}>
</Col> </Col>

View File

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