彭玲
3 years ago
1 changed files with 203 additions and 0 deletions
@ -0,0 +1,203 @@ |
|||||
|
# Web侧高频数据 chart 展示预研说明文档 |
||||
|
|
||||
|
Author: 彭玲 CreatedTime: 2021/5/11 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
[TOC] |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 背景 |
||||
|
|
||||
|
目前,光纤光栅、振动连续采集、动应变、GNSS 实时动态解析等的采样频率高达到 1~100Hz(或更高)。针对高频采样,之前接入侧常采用”降低采样频率“”分时段采样(振动)“等处理方式,但存在数据”丢失“的必然结果。 |
||||
|
|
||||
|
为满足客户对高频数据接入的需求,针对高频数据采集进行了专项处理:平台侧接收原始采集粒度数据、存储于 HDFS 文件系统中,并提供 HDFS 查询服务和可视化 (不限于平台)。 |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 功能说明 |
||||
|
|
||||
|
Web侧将平台接入的高频数据以图表形式进行展示。 |
||||
|
|
||||
|
### 输入 |
||||
|
|
||||
|
输入为:chart 图片的 Base64 地址 (Data URLs) |
||||
|
|
||||
|
- Data URLs:`data:image/png;base64,<image-data>` |
||||
|
- Base64 图片来源:平台 PyRpcService (http://10.8.30.22/FS-Anxinyun/trunk/codes/services/PyRpcService) 接口查询服务`high_frequency_chart`(查询 HDFS 存储数据) |
||||
|
|
||||
|
### 输出 |
||||
|
|
||||
|
输出为:chart 图片 |
||||
|
|
||||
|
必要的查询组件:**结构物**选择器、**起止时间**选择框 |
||||
|
|
||||
|
![](E:\WorkSpace\iFS-Backend\高频数据接入\assets\高频数据展示-web-demo.png) |
||||
|
|
||||
|
|
||||
|
|
||||
|
## Postman 请求 |
||||
|
|
||||
|
参数说明: |
||||
|
|
||||
|
- HDFS 文件地址,包括:结构物 id,HDFS 文件夹 `<年份>`,HDFS 文件夹 `<月份>` |
||||
|
- 查询起止时间:Unix 时间戳 (ms) |
||||
|
|
||||
|
![](E:\WorkSpace\iFS-Backend\高频数据接入\assets\Postman RPC:high_frequency_chart.png) |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 关键代码 |
||||
|
|
||||
|
### web-api |
||||
|
|
||||
|
```js |
||||
|
const request = require('superagent') |
||||
|
|
||||
|
module.exports = { |
||||
|
entry: function (app, router, opts) { |
||||
|
|
||||
|
const RPC_SVR_URL = opts.highFrequencyChartRpcSvrUrl || `http://localhost:15000/api`; |
||||
|
|
||||
|
let fetchHighFrequencyChartData = async function (ctx, next) { |
||||
|
const params = ctx.request.body; |
||||
|
try { |
||||
|
const reqBody = { |
||||
|
"jsonrpc": "2.0", |
||||
|
"id": "myid", |
||||
|
"method": "high_frequency_chart", |
||||
|
"params": params, |
||||
|
// "params": { |
||||
|
// "url": "/anxinyun/structure_data/structure_854/raw/2021/2/gxwd1-1.csv", |
||||
|
// "gte": 1613810269584, |
||||
|
// "lt": 1613810706956 |
||||
|
// } |
||||
|
} |
||||
|
const proxyReq = request.post(RPC_SVR_URL).send(reqBody) |
||||
|
const res = await proxyReq |
||||
|
|
||||
|
ctx.status = res.status |
||||
|
ctx.body = { data: res.body.result } |
||||
|
} catch (e) { |
||||
|
let errMsg = `fetch high_frequency_chart data error: ${e}` |
||||
|
ctx.status = 500; |
||||
|
ctx.fs.logger.error(errMsg) |
||||
|
ctx.body = { err: errMsg } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
router.post('/_high_frequency_chart', fetchHighFrequencyChartData) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
||||
|
### web |
||||
|
|
||||
|
```js |
||||
|
import React, { Component } from 'react' |
||||
|
|
||||
|
import { Select, DatePicker } from 'antd' |
||||
|
const Option = Select.Option |
||||
|
const { RangePicker } = DatePicker |
||||
|
|
||||
|
const request = require('superagent') |
||||
|
|
||||
|
class HighFrequencyChart extends Component { |
||||
|
constructor(props) { |
||||
|
super(props) |
||||
|
|
||||
|
this.state = { |
||||
|
chartData: null |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fetchHighFrequencyChartData = () => { |
||||
|
let structId = 854 |
||||
|
let hdfsDirYear = '2021', |
||||
|
hdrsDirMonth = '2' |
||||
|
let filterBegin = 1613810269584, // 2021-02-20 16:37:49 |
||||
|
fiterEnd = 1613810706956 // 2021-02-20 16:45:06 |
||||
|
|
||||
|
const params = { |
||||
|
// Example: /anxinyun/structure_data/structure_854/raw/2021/2/gxwd1-1.csv |
||||
|
"url": `/anxinyun/structure_data/structure_${structId}/raw/${hdfsDirYear}/${hdrsDirMonth}/gxwd1-1.csv`, |
||||
|
"gte": filterBegin, // begin time for part of the HDFS resource |
||||
|
"lt": fiterEnd // end time for part of the HDFS resource |
||||
|
} |
||||
|
|
||||
|
request.post('_high_frequency_chart').send(params).end((err, res) => { |
||||
|
if (!err) { |
||||
|
let chartData = res.body.data |
||||
|
this.setState({ chartData }) |
||||
|
} else { |
||||
|
// handle err msg... |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
componentDidMount() { |
||||
|
this.fetchHighFrequencyChartData() |
||||
|
} |
||||
|
|
||||
|
renderStructures = () => { |
||||
|
return ( |
||||
|
<Select |
||||
|
showSearch |
||||
|
style={{ width: 200 }} |
||||
|
placeholder="Select a structure" |
||||
|
optionFilterProp="children" |
||||
|
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} |
||||
|
> |
||||
|
<Option value="bridge">桥梁 #1</Option> |
||||
|
<Option value="slope">边坡 #2</Option> |
||||
|
</Select> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
renderRangePicker = () => { |
||||
|
return ( |
||||
|
<RangePicker |
||||
|
showTime={{ format: 'HH:mm' }} |
||||
|
format="YYYY-MM-DD HH:mm" |
||||
|
placeholder={['Start Time', 'End Time']} |
||||
|
/> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
renderHighFrequencyChart = () => { |
||||
|
let data = this.state.chartData |
||||
|
if (data) { |
||||
|
return <img src={data} width='1000' height='500' /> |
||||
|
} |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
return ( |
||||
|
<div> |
||||
|
<section style={{ padding: '32px 0' }}> |
||||
|
<span>结构物选择:</span>{this.renderStructures()} |
||||
|
<span style={{ paddingLeft: '24px' }}>起止时间选择:</span>{this.renderRangePicker()} |
||||
|
</section> |
||||
|
|
||||
|
{/* HighFrequencyChart Module */} |
||||
|
<section> |
||||
|
{this.renderHighFrequencyChart()} |
||||
|
</section> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default HighFrequencyChart |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
Loading…
Reference in new issue