解锁 SpreadJS 扩展能力:ECharts 集成与自定义渲染实战
SpreadJS 是一款企业级纯前端表格控件,不仅完整兼容 Excel 的核心功能,更提供了强大的深度定制与二次开发能力。在实际项目中,用户往往不满足于原生功能,需要将表格与其他前端生态无缝整合。 为什么需要集成第三方图表? SpreadJS 的扩展优势: 本文以 ECharts 为例,演示如何将主流图表库与 SpreadJS 深度集成,实现数据联动、可见性同步及 PDF 导出。该方案同样适用于其他 DOM 依赖型控件,展现 SpreadJS 作为前端表格基座的生态整合能力。 利用 SpreadJS 的 通过 容器挂载后,实例化图表。 利用 SpreadJS 原生图表具备可视区域自动渲染机制(滚动到可见区域才渲染),但嵌入的自定义 DOM 内容不会自动触发此逻辑。若不处理,滚动到图表位置时会发现内容为空。 需手动监听 ECharts 的 DOM 节点无法被 SpreadJS 原生 PDF 导出功能捕获。解决方案:临时 Workbook + 图片转换。 生成 PDF:调用临时实例的 通过本文的实践,我们验证了 SpreadJS 在深度定制与生态整合方面的强大能力: 核心价值: SpreadJS 不仅是一个表格控件,更是一个可扩展的前端数据交互基座。通过开放的事件系统与 API,开发者可以将表格与现有前端生态无缝融合,快速构建满足复杂业务需求的在线报表系统。 完整demo请查看:在SpreadJS中集成ECharts并导出为PDF背景
ValueChanged、TopRowChanged 等事件支持精细化的交互控制。核心方案:容器嵌套
FloatingObject 支持嵌入 HTML 内容的特性,为 ECharts 提供 DOM 容器。1. 创建浮动容器
FloatingObject.content() 将 div 插入表格指定单元格区域。function initFloatingObject(sheet, chart) {
let floatObj = new GC.Spread.Sheets.FloatingObjects.FloatingObject(chart.id);
floatObj.startRow(chart.startRow);
floatObj.endRow(chart.endRow);
floatObj.startColumn(chart.startColumn);
floatObj.endColumn(chart.endColumn);
let div = document.createElement('div');
div.innerHTML = `<div id="${chart.id}" style="width:100%;height:100%;"></div>`;
floatObj.content(div);
sheet.floatingObjects.add(floatObj);
}
2. 初始化 ECharts
function initBarECharts(chart) {
let dom = document.getElementById(chart.id);
if (!dom) return;
let myChart = echarts.init(dom);
let data = getChartDataFromTables(chart.source);
myChart.setOption({
xAxis: { data: data.categories },
series: [{
type: 'bar',
data: data.data,
animation: true
}]
});
return myChart;
}
数据双向绑定
ValueChanged 事件监听单元格修改,实现表格驱动图表更新。实现逻辑
ValueChanged 事件。chart.setOption 刷新。spread.bind(GC.Spread.Sheets.Events.ValueChanged, function (e, info) {
for (let key in charts) {
let range = new GC.Spread.Sheets.Range(
charts[key].table.row, charts[key].table.col,
charts[key].table.rowCount, charts[key].table.colCount
);
// 判断修改是否在当前图表数据范围内
if (range.contains(info.row, info.col, 1, 1)) {
refreshCharts(charts[key].id, getChartDataFromTables(charts[key].source));
break;
}
}
});refreshCharts方法是用于动态设置ECharts数据的方法,这里就展示详细的内部实现了。
可见性同步:模拟原生滚动渲染
监听滚动事件
TopRowChanged 事件,当图表行进入可视区附近时,触发初始化。spread.bind(GC.Spread.Sheets.Events.TopRowChanged, function (s, e) {
let newTopRow = e.newTopRow;
// 判断图表起始行是否进入可视区,且尚未初始化
if ((charts["line"].startRow - 5 < newTopRow) && (!charts["line"].echart)) {
initCharts(charts["line"]);
}
});
难点突破:导出 PDF
导出流程
echarts.getDataURL() 获取 Base64。savePDF。document.getElementById("saveAsPdf").addEventListener("click", function () {
// 1. 克隆临时实例
let tempSpread = new GC.Spread.Sheets.Workbook();
tempSpread.fromJSON(JSON.parse(JSON.stringify(spread.toJSON({ includeBindingSource: true }))));
let tempSheet = tempSpread.getSheet(0);
// 2. 图表转图片
for (let key in charts) {
// 确保图表已渲染
if (!charts[key].echart) {
// 触发初始化逻辑...
}
let imgData = charts[key].echart.getDataURL();
tempSheet.floatingObjects.remove(charts[key].id); // 移除 DOM 容器
// 添加图片形状
let pic = tempSheet.shapes.addPictureShape(charts[key].id, imgData, 0, 0, 100, 100);
pic.startRow(charts[key].startRow);
pic.endRow(charts[key].endRow);
}
// 3. 导出
tempSpread.savePDF(function (blob) {
saveAs(blob, 'report.pdf');
});
});
总结
集成维度 实现方式 扩展价值 容器嵌入 FloatingObject.content() 嵌入 DOM 可集成任意前端控件(图表、地图、富文本等) 数据联动 ValueChanged 事件监听 实现表格与外部组件的双向数据同步 渲染同步 TopRowChanged 事件模拟原生逻辑 保持与 SpreadJS 原生组件一致的用户体验 导出扩展 临时 Workbook + 图片转换 突破原生导出限制,支持自定义内容输出