解锁 SpreadJS 扩展能力:ECharts 集成与自定义渲染实战

背景

SpreadJS 是一款企业级纯前端表格控件,不仅完整兼容 Excel 的核心功能,更提供了强大的深度定制与二次开发能力。在实际项目中,用户往往不满足于原生功能,需要将表格与其他前端生态无缝整合。

为什么需要集成第三方图表?

  • 原生图表局限:SpreadJS 虽兼容 Excel 图表,但复杂可视化场景(如动态交互、自定义样式、特殊图表类型)需要更灵活的方案。
  • 生态整合需求:前端项目中已广泛使用 ECharts、AntV 等图表库,重复造轮子成本高。
  • 定制化场景:金融看板、量化报表、数据大屏等场景需要表格与高级图表深度联动。

SpreadJS 的扩展优势:

  • 浮动对象机制:支持嵌入任意 DOM 内容,为第三方控件提供容器。
  • 事件系统完善ValueChangedTopRowChanged 等事件支持精细化的交互控制。
  • API 开放度高:从数据绑定到导出渲染,各环节均可自定义扩展。

本文以 ECharts 为例,演示如何将主流图表库与 SpreadJS 深度集成,实现数据联动、可见性同步及 PDF 导出。该方案同样适用于其他 DOM 依赖型控件,展现 SpreadJS 作为前端表格基座的生态整合能力。

核心方案:容器嵌套

利用 SpreadJS 的 FloatingObject 支持嵌入 HTML 内容的特性,为 ECharts 提供 DOM 容器。

1. 创建浮动容器

通过 FloatingObject.content() 将 div 插入表格指定单元格区域。

JavaScript 复制代码
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

容器挂载后,实例化图表。

JavaScript 复制代码
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 事件监听单元格修改,实现表格驱动图表更新。

实现逻辑

  1. 监听全局 ValueChanged 事件。
  2. 校验修改位置是否命中图表数据源区域。
  3. 命中则提取新数据,调用 chart.setOption 刷新。
JavaScript 复制代码
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数据的方法,这里就展示详细的内部实现了。

可见性同步:模拟原生滚动渲染

SpreadJS 原生图表具备可视区域自动渲染机制(滚动到可见区域才渲染),但嵌入的自定义 DOM 内容不会自动触发此逻辑。若不处理,滚动到图表位置时会发现内容为空。

监听滚动事件

需手动监听 TopRowChanged 事件,当图表行进入可视区附近时,触发初始化。

JavaScript 复制代码
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 的 DOM 节点无法被 SpreadJS 原生 PDF 导出功能捕获。解决方案:临时 Workbook + 图片转换

导出流程

  1. 克隆 Workbook:深拷贝当前 JSON 配置到临时实例,隔离操作。
  2. 强制渲染:确保临时实例中图表已初始化。
  3. 转图片 :调用 echarts.getDataURL() 获取 Base64。
  4. 替换对象:移除 FloatingObject,在原位置添加 Picture Shape。
  5. 生成 PDF :调用临时实例的 savePDF。 1.
JavaScript 复制代码
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');
    });
});

总结

通过本文的实践,我们验证了 SpreadJS 在深度定制与生态整合方面的强大能力:

集成维度 实现方式 扩展价值
容器嵌入 FloatingObject.content() 嵌入 DOM 可集成任意前端控件(图表、地图、富文本等)
数据联动 ValueChanged 事件监听 实现表格与外部组件的双向数据同步
渲染同步 TopRowChanged 事件模拟原生逻辑 保持与 SpreadJS 原生组件一致的用户体验
导出扩展 临时 Workbook + 图片转换 突破原生导出限制,支持自定义内容输出

核心价值:

  1. 不重复造轮子:直接复用 ECharts 等成熟图表库,降低开发成本。
  2. 保持体验一致:通过事件监听模拟原生行为,用户无感知切换。
  3. 方案可迁移:该集成模式适用于其他 DOM 依赖型第三方控件。

SpreadJS 不仅是一个表格控件,更是一个可扩展的前端数据交互基座。通过开放的事件系统与 API,开发者可以将表格与现有前端生态无缝融合,快速构建满足复杂业务需求的在线报表系统。

完整demo请查看:在SpreadJS中集成ECharts并导出为PDF

相关推荐
来一颗砂糖橘2 小时前
CSS 清除浮动深度解析:从 clear: both 到现代布局方案
前端·css·clearboth·清除浮动
南宫码农2 小时前
Node.js和npm本地安装详细教程(全系统适配)
前端·npm·node.js
我命由我123452 小时前
前端开发 - this 指向问题(直接调用函数、对象方法、类方法)
开发语言·前端·javascript·vue.js·react.js·html5·js
小黑的铁粉2 小时前
ecahrts图形多的页面,怎么解决数据量大的渲染问题?
前端·echarts
低保和光头哪个先来2 小时前
TinyEditor 篇1:实现工具栏按钮向服务器上传图片
服务器·开发语言·前端·javascript·vue.js·前端框架
A黄俊辉A2 小时前
webstorm+vue+esLint+pretter配置
前端·vue.js·webstorm
TYFHVB122 小时前
2026六大主流CRM横评,五大核心维度深度解析
大数据·前端·数据结构·人工智能
LiuMingXin2 小时前
断网也能装包? 我在物理隔离内网搭了一套完整的私有npm仓库
前端·面试·npm
CHU7290352 小时前
趣味抽赏,解锁惊喜——扭蛋机盲盒抽赏小程序前端功能解析
前端·小程序