标题: 并解决开启FVS数据更新推送功能下嵌入Echarts图表后无法一起更新的问题.
前言: 此贴参考了论坛中的帖子: fineReport整合echarts制作桑基图-我的帆软 (fanruan.com); 并将其和FVS结合, 解决了数据更新同步的问题.项目背景:
有车间的工单转出需要绘制热力图, 但整体看板是使用FVS制作的, 所以如何在FVS中嵌入Echarts复杂图标就是个问题了
FVS表格自带的Echarts引入, 仅支持简单的 key->value 形式数据的解析, 而不支持像热力图这样的 x,y,value 的复杂数据类型的数据自解析
思路
图表如何绘制?
使用js进行页面元素的插入和数据处理, 渲染操作. 但这时有一个问题, FVS的表格是没有初始化JS的(或许我不知道), 所以我们这里需要在决策报表里面绘制, 然后通过FVS网页框将决策报表引入到FVS大屏.
数据如何获取,更新?
特别是在FVS有数据联动的情况下, 比如我的工单的转出数据是按照天, 周, 月, 年的时间段进行抽取出来的数据, 那我在FVS中更改了筛选条件后, 如何让决策报表里面的热力图数据也同步更新?
FVS有推送更新, 决策报表如何一样即时更新?
如果是用网页框的监控刷新选项, 1. 网页框会整体刷新, 白屏然后展示, 观感上不好. 2. 测试出网页框的监控刷新和FVS的数据推送刷新互斥, 实际上无法使用, 决策报表的初始化JS倒是不互斥, 但是依然有1. 的问题, 太难看.
既然用了JS, 那么干脆用JS的 setInterval 方法算了, 按指定时间轮训重复从数据集获取数据.(注意, 这里不去查SQL, 所以影响的只是网页端的性能. 可以看后续代码部分.).
最后效果:
前期准备
导入 Echarts.js 文件.
下载Echarts: 在此页面 快速上手 - 使用手册 - Apache ECharts 按照说明下载 echarts.js文件. 下面这个链接是截止2024.0913时间的最新Echart.js链接: cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js
导入到FineReport: 将下载好的js文件, 放置在 FineReport服务器 的 webroot 文件夹中, 和WEB_INF同级(注意,这里我测试放到WEB_INF里面引入的时候获取不到, 可能是权限问题, 感兴趣的可以自测下. )
引入到FineReport:
创建数据集
这里需要注意的是, 这里的变量是要加到全局参数里面, 后面会有用, 切记!
FVS设置
网页框组件, 设置参数:
注意, 参数名称一定要和决策报表中的全局参数名称一样.
参数内容一定是绑定了参数的全局参数,
这样设置后, FVS页面通过下拉框/选择按钮修改了数据后, 因为绑定了全局参数, 所以全局参数进行了变化, 这个变化会同步到网页框关联的决策报表的全局参数中, 而网页框的全局参数变化, 会使得数据集的结果变化. 而JS中在循环中通过Value获取的数据也会发生变化.
编写JS代码.
插入标签控件: ,
控件名称自定义:
添加初始化后事件:
添加JS:
初始化变量: 这里主要是获取指定sql查询出的数据集. 不使用SQL函数, 所以不影响数据库性能.
var cs0 = "VALUE('查询指定厂的全部车间',1)"
var cs1 = "VALUE('查询指定时间段的转出数据',1)"
var cs2 = "VALUE('查询指定时间段的转出数据',2)"
var cs3 = "VALUE('查询指定时间段的转出数据',3)"
初始化Echarts组件 清空Label控件内容, 并在Label控件中添加div标签: 注意, LABEL0是FR中label的控件名称. 第二句的id名称需要和第三局getElementById的值相同!
$("div").empty();
// 往标签控件里添加div,指定id
$("div").append("
");
var myChart = echarts.init(document.getElementById("echa"));
数据处理: 用js将数据集数据转换为Echarts所需数据. 按照Echarts不同图标自己处理即可.
// 获取车间数据, 以及所需的三列值
var dept = FR.remoteEvaluate(cs0);
var d1 = FR.remoteEvaluate(cs1);
var d2 = FR.remoteEvaluate(cs2);
var d3 = FR.remoteEvaluate(cs3);
// 定义所需值的数组容器
var data = ;
// 通过三列查询数据拼接中间数据(转出车间-转入车间-数量)
var rawData = ;
// 热力图的展示最大值, 默认10
var maxCount = 10;
// 如果有比10更大的, 就使用最大值
// 获取rawData
for (i = 0; i < d1.length; i++) {
counti = d3;
if (maxCount < counti) {
maxCount = counti;
}
rawData.push(, d2, counti]);
}
// 将rawData转换为(x, y, value)
rawData.forEach(function(item) {
// 找到每个部门在 dept 数组中的索引位置作为 y 轴坐标
var indexx = dept.indexOf(item.toString());
var indexy = dept.indexOf(item.toString());
if (indexx !== -1 && indexy !== -1) {
data.push(]);
}
});
Echarts配置: 注意, 我这里的字体都调的是白色的, 需要自己调整即可.
// 以下为echarts正常配置
var option = {
title: {
text: '转出数据热力图',
left: 'center',
top: 20,
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
tooltip: {
position: 'top'
},
grid: {
height: '85%',
top: '5%'
},
xAxis: {
type: 'category',
// 这里是转换出的数组
data: dept,
splitArea: {
show: false
}
},
yAxis: {
type: 'category',
// 这里是转换出的数组
data: dept,
splitArea: {
show: false
}
},
visualMap: {
min: 0,
max: maxCount,
calculable: true,
orient: 'vertical',
right: '10px', // 将visualMap放置在图表的右侧
top: 'center', // 确保垂直居中
bottom: '0%',
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
series: [{
name: '测试图表',
type: 'heatmap',
// 这里是转换出的数组
data: data,
label: {
show: true, // 显示标签
position: 'inside', // 标签位置,默认为 'inside'
formatter: function(params) {
// 自定义标签内容
return params.value;
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
整体JS:
要把整个数据处理-解析在setInterval之前重复一遍, 因为setInterval不会开始即运行, 而是指定时间后运行(如这里设置的5s).
setInterval设置的是5s, 自行调整.
var cs0 = "VALUE('查询指定厂的全部车间',1)"
var cs1 = "VALUE('查询指定时间段的转出数据',1)"
var cs2 = "VALUE('查询指定时间段的转出数据',2)"
var cs3 = "VALUE('查询指定时间段的转出数据',3)"
// 先初始化一次
// 清空标签控件里的内容
$("div").empty();
// 往标签控件里添加div,指定id
$("div").append("
");
var myChart = echarts.init(document.getElementById("echa"));
// 获取车间数据, 以及所需的三列值
var dept = FR.remoteEvaluate(cs0);
var d1 = FR.remoteEvaluate(cs1);
var d2 = FR.remoteEvaluate(cs2);
var d3 = FR.remoteEvaluate(cs3);
// 定义所需值的数组容器
var data = ;
// 通过三列查询数据拼接中间数据(转出车间-转入车间-数量)
var rawData = ;
// 热力图的展示最大值, 默认10
var maxCount = 10;
// 如果有比10更大的, 就使用最大值
// 获取rawData
for (i = 0; i < d1.length; i++) {
counti = d3;
if (maxCount < counti) {
maxCount = counti;
}
rawData.push(, d2, counti]);
}
// 将rawData转换为(x, y, value)
rawData.forEach(function(item) {
// 找到每个部门在 dept 数组中的索引位置作为 y 轴坐标
var indexx = dept.indexOf(item.toString());
var indexy = dept.indexOf(item.toString());
if (indexx !== -1 && indexy !== -1) {
data.push(]);
}
});
// 以下为echarts正常配置
var option = {
title: {
text: '转出数据热力图',
left: 'center',
top: 20,
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
tooltip: {
position: 'top'
},
grid: {
height: '85%',
top: '5%'
},
xAxis: {
type: 'category',
data: dept,
splitArea: {
show: false
}
},
yAxis: {
type: 'category',
data: dept,
splitArea: {
show: false
}
},
visualMap: {
min: 0,
max: maxCount,
calculable: true,
orient: 'vertical',
right: '10px', // 将visualMap放置在图表的右侧
top: 'center', // 确保垂直居中
bottom: '0%',
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
series: [{
name: '测试图表',
type: 'heatmap',
data: data,
label: {
show: true, // 显示标签
position: 'inside', // 标签位置,默认为 'inside'
formatter: function(params) {
// 自定义标签内容
return params.value;
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
// 设置图表选项
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
setInterval(function() {
// 清空标签控件里的内容
// $("div").empty();
// 往标签控件里添加div,指定id
// $("div").append("
");
// var myChart = echarts.init(document.getElementById("echa"));
// 获取车间数据, 以及所需的三列值
var dept = FR.remoteEvaluate(cs0);
var d1 = FR.remoteEvaluate(cs1);
var d2 = FR.remoteEvaluate(cs2);
var d3 = FR.remoteEvaluate(cs3);
// 定义所需值的数组容器
var data = ;
// 通过三列查询拼接中间数据(转出车间-转入车间-数量)
var rawData = ;
// 热力图的展示最大值, 默认10
var maxCount = 10;
// 如果有比10更大的, 就使用最大值
// 获取rawData
for (i = 0; i < d1.length; i++) {
counti = d3;
if (maxCount < counti) {
maxCount = counti;
}
rawData.push(, d2, counti]);
}
// 将rawData转换为(x, y, value)
rawData.forEach(function(item) {
// 找到每个部门在 dept 数组中的索引位置作为 y 轴坐标
var indexx = dept.indexOf(item.toString());
var indexy = dept.indexOf(item.toString());
if (indexx !== -1 && indexy !== -1) {
data.push(]);
}
});
// 以下为echarts正常配置
var option = {
title: {
text: '转出数据热力图',
left: 'center',
top: 20,
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
tooltip: {
position: 'top'
},
grid: {
height: '85%',
top: '5%'
},
xAxis: {
type: 'category',
data: dept,
splitArea: {
show: false
}
},
yAxis: {
type: 'category',
data: dept,
splitArea: {
show: false
}
},
visualMap: {
min: 0,
max: maxCount,
calculable: true,
orient: 'vertical',
right: '10px', // 将visualMap放置在图表的右侧
top: 'center', // 确保垂直居中
bottom: '0%',
textStyle: { // 设置字体颜色为白色
color: '#fff'
}
},
series: [{
name: '测试图表',
type: 'heatmap',
data: data,
label: {
show: true, // 显示标签
position: 'inside', // 标签位置,默认为 'inside'
formatter: function(params) {
// 自定义标签内容
return params.value;
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
// 设置图表选项
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
}, 5000);