有时候在对硬件传送过来的数据进行处理后,需要将这些数据显示在折线图上,从而来观察这些数据是怎样变化的,这个好办,但有时候又要求需要将折线图上面显示的数据全部导出到一个文件中,并且有时候又要求在文件中改变数据后,再将文件中的数据重新导入到折线图中,哪有该如何写呢?
我的思路如下:
1.首先,我们需要实现将折线图上显示的数据导出到文件中,常见的文件格式可以选择为CSV(逗号分隔值),因为它易于读取和处理。(首先需要一个导出文件的按钮)
下面以电池实时电量变化和电池实时温度变化这两个数据为例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>变化分析图</title>
<!-- 引入 echarts.js -->
<script src="echarts.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<button onclick="exportDataToFile()">导出数据到文件</button>
<input type="file" id="fileInput" accept=".json" onchange="importDataFromFile(event)">
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例---------------有多个数据---即多条线,并且还有导入导出
//文件为csv
var myChart = echarts.init(document.getElementById('main'));
// 初始化图表的配置项
var option = {
title: {
text: '数据分析图'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data:['电池电量', '电池温度']
},
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value'
},
tooltip: {
trigger: 'axis', // 设置触发类型为坐标轴触发
axisPointer: {
type: 'cross' // 十字准星指示器,显示在坐标轴上
}
},
series: [
{
name: '电池电量',
type: 'line',
data: []
},
{
name: '电池温度',
type: 'line',
data: []
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
// 获取数据并更新图表
function fetchData() {
fetch('http://localhost:8080/mysql/getAllHistory1') // 修改为你的后端接口地址
.then(response => response.json())
.then(data => {
var timeData = [];
var c1Data = [];
var tem1Data = [];
data.forEach(item => {
/* var now=new Date();
var currentTime = [now.getHours(), now.getMinutes(), now.getSeconds()].map(num => num < 10 ? '0' + num : num).join(':');*/
timeData.push(item.time); // 时间
c1Data.push(item.c); //
tem1Data.push(item.tem); //
});
// 更新图表数据
myChart.setOption({
xAxis: {
data: timeData
},
series: [
{
name: '电量',
data: c1Data
},
{
name: '温度',
data: tem1Data
}
]
});
})
.catch(error => console.error('Error fetching data:', error));
}
// 初次加载数据
fetchData();
// 定期获取数据
setInterval(fetchData, 5000); // 每隔5秒钟获取一次数据
//导出图表数据到文件
function exportDataToFile() {
fetch("http://localhost:8080/mysql/getAllHistory1")
.then(response => response.json())
.then(data => {
// 将数据转换为 JSON 格式字符串
var jsonData = JSON.stringify(data, null, 2);
// 创建一个 Blob 对象
var blob = new Blob([jsonData], { type: 'application/json' });
// 创建一个下载链接
var url = URL.createObjectURL(blob);
// 创建一个下载链接的 <a> 元素
var a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'queue_data.json'; // 下载的文件名
// 添加到 DOM 并触发点击下载
document.body.appendChild(a);
a.click();
// 下载之后就清理
document.body.removeChild(a);
URL.revokeObjectURL(url);
})
.catch(error => console.error('Error exporting data:', error));
}
其中这段代码里面有些是固定代码,当你需要显示其他数据时,可以将这些固定代码直接抄过去,只需要改变后端请求路径: fetch("http://localhost:8080/mysql/getAllHistory1")----这里具体问题具体分析,根据自己的请求路径来写。
2.后端代码
我使用的是前后端不分离的情况,可能有所不同,接下来分享我的代码:
(1)controller层代码
package com.demo.controller;
import com.demo.pojo.Data1;
import com.demo.service.Data1Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@CrossOrigin(origins = "http://localhost:63342")
@RequestMapping("/mysql")
public class Data1Controller {
@Autowired
private Data1Service data1Service;
@GetMapping("/getAllHistory1")
public List<Data1> getAllHistory() {
List<Data1> allHistory = data1Service.getAllHistory();
Data1 data1 = allHistory.get(0);
return data1Service.getAllHistory();
}
}
(2)mapper层代码
@Mapper
public interface Data1Mapper extends BaseMapper<Data1> {
@Insert("insert into " +
"data1(id,c,tem,time) " +
"values " +
"(#{id},#{c},#{tem}, #{time})")
int insert(Data1 data1);//插入语句--这里在将数据存入数据库时需要用到,通常只需要改变字段和实体类名字(数据库名字)
@Select("select * from data1")
List<Data1> getAll();
}
(3)service层代码
public interface Data1Service extends IService<Data1> {
List<Data1> getAllHistory();//获取所有数据
}
通常只需要改变实体类名字就可以搬运了
(4)service实现类代码
@Service
public class Data1ServiceImpl extends ServiceImpl<Data1Mapper, Data1>
implements Data1Service {
@Autowired
private Data1Mapper data1Mapper;
@Autowired
public Data1ServiceImpl(Data1Mapper data1Mapper) {
this.data1Mapper = data1Mapper
;
}
@Override
public List<Data1> getAllHistory() {
QueryWrapper wrapper=new QueryWrapper<>();
List<Data1> data1s = data1Mapper.selectList(null);
return data1s;
}
}
注意:这里只需要导出到文件
2.如果还需要将文件中的数据改变之后,再将文件中的数据导入到折线图中,则需要在几个地方进行改变:
我的代码都是从数据库中获取数据,然后渲染到折线图中,所以,当在文件中改变数据时需要先在数据库中更新数据,然后前端发送请求给后端数据库,再重新获取数据渲染在页面上,具体代码如下:(即先点击导入文件按钮,点击事件发送之后,将文件内容转换为对象数组发送请求给后端,后端进行数据库更新,更新完之后,前端再重新获取数据渲染在折线图上)
//导入图表数据
function importDataFromFile(event) {
var file = event.target.files[0];
if (!file) {
console.error("没有选择文件");
return;
}
//利用reader读取文件里面的数据
var reader = new FileReader();
reader.onload = function (e) {
var contents = e.target.result;
try {
var importedDataArray = JSON.parse(contents); // 解析整个文件为一个数组
importedDataArray.forEach(importedData => {
// 确保每个 importedData 是一个对象
if (typeof importedData !== 'object' || Array.isArray(importedData)) {
throw new Error('File content is not valid JSON object');
}
// 发送数据到后端的逻辑
fetch("http://localhost:8080/Mysql/UpdateMessage1", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
mode: 'cors',
body: JSON.stringify(importedData)
})
.then(data => {
console.log('Success:', data);
// 更新图表数据(如果需要)
updateChartWithData(importedData);
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
});
} catch (error) {
console.error('Error parsing JSON:', error);
console.log(contents);
}
};
reader.readAsText(file);
}
</script>
</body>
</html>
后端代码-----更新数据库
(1)controller层代码
// 更新某条记录-----跟导入数据有关
//当在文件中改变的是某一个数据时,可以根据唯一的字段进行更新
@PostMapping("/UpdateMessage1")
//其中需要写实体类----在service中这个方法
public void updateLine(@RequestBody Data1 data1) {
data1Service.updateLine(data1);
}
//更新整个数据库---当数据库中的数据全部清空时--利用图表将数据导入到文件中,然后再导入到图表中
//注意,一定要在导入之前将数据库中的数据清空,即当导出文件时,数据库中的数据存在文件中,当在文件中修改数据时,修改之后保存文件,再导入到图中时,首先得把数据库中的数据清空再来导入,否则会报错
@PostMapping("/UpdateMessage3")
public void insert(@RequestBody data1 data1) {
data1Mapper.insert(data1);
}
注意:更新整个数据库用到的是插入语句,在导入文件前清空数据库是为了在利用insert语句更新数据库时,不会有重复的数据出现,即不会在现有的数据库中接着插入语句,就是本来数据库中有10个记录,当我修改其中的某几个记录后,在导入文件之前清空数据库,利用insert语句之后,还是10个记录,如果不清空的话,那么一共会有20个记录。
(2)service层代码:
//更新数据库中某条记录
void updateLine(data1 dat1);
(3)service实现类代码:
@Override
public void updateLine(Data1 data1) {
data1Mapper.updateById(data1); // 使用updateById更新数据
}
以上代码经供参考,如发现有错的的地方,欢迎指出