彭玲
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