本帖最后由 Ellia.Duan 于 2025-5-8 11:57 编辑
在SpreadJS中如何将指定单元格区域中的数据保存为图片?本文将介绍两种方法,分别通过Canvas、区域快照复刻单元格区域中的数据后保存为图片。
1. Canvas保存图片
1.1. 将部分指定区域保存为图片(纯Canvas)
熟悉SpreadJS的朋友都知道SpreadJS sheet中的单元格并非DOM元素,而是由横纵网格线绘制形成的效果。同样地,创建一个新Canvas实例为容器,将目标保存区域复刻至新Canvas中,以此作为实际的图数据容器。
那么,为什么不直接从作为sheet的Canvas实例保存图片呢?一般情况下,需要导出的仅是sheet中的部分单元格区域,而Canvas的toDataURL将Canvas上下文中的所有数据封装为图片。与此相比,在新Canvas实例上操作的可控性更好,且数据安全也有所保障。如下代码所示:
- function saveImageWithCanvas(spread, startRow, startCol, width, height) {
- var sheet = spread.getActiveSheet();
- var hostCanvas = spread.getHost().querySelector('canvas[gcuielement]');
- var ctx = hostCanvas.getContext('2d');
- var cellRect = sheet.getCellRect(startRow, startCol);
- // 截取待导出区域为图片数据
- var imageData = ctx.getImageData(cellRect.x, cellRect.y, width, height);
-
- // 创建临时canvas,令其容纳图片数据,用以实际保存图片
- var tempCanvas = document.createElement('canvas');
- var tempCtx = tempCanvas.getContext('2d');
- // 调整临时canvas尺寸为图片大小,确保能够完整保存图片数据
- tempCanvas.width = width;
- tempCanvas.height = height;
- tempCtx.putImageData(imageData, 0, 0);
- setTimeout(function() {
- var dataUrl = tempCanvas.toDataURL('image/png');
- var link = document.createElement('a');
- link.href = dataUrl;
- link.download = 'canvas-image.png';
- link.click();
- }, 100);
- }
复制代码
上述代码运行效果如图1所示。
图1. Canvas保存图片
1.2. 将整个sheet保存为图片(BeforePrint) SpreadJS的打印功能的作用区域为sheet中所有已被使用的区域形成的最大区域,通过BeforePrint事件的监听参数ifram可以获取到完整的打印区域,之后将其封装在临时Canvas中,由该Canvas导出为图片,如下代码所示:
- /**
- * 保存sheet内容为图片
- */
- function saveImage(spread) {
- document.getElementById('saveImgBtn').addEventListener('click', function() {
- var sheet = spread.getActiveSheet();
- var oldPrintInfo = sheet.printInfo();
- // 绑定BeforePrint事件,辅助获取图片内容并导出
- spread.bind(GC.Spread.Sheets.Events.BeforePrint, function(e, args) {
- var iframe = args.iframe;
- saveImageWithCanvas(iframe, '.png');
- args.cancel = true;
- // 导出后解绑BeforePring事件,防止正常的打印功能
- setTimeout(function() {
- spread.unbind(GC.Spread.Sheets.Events.BeforePrint);
- sheet.printInfo(oldPrintInfo);
- }, 10);
- });
- setPrintInfo(sheet);
- spread.print();
- });
- }
- /**
- * 保存图片为指定类型
- */
- function saveImageWithCanvas(iframe, imgType) {
- var imgs = iframe.contentWindow.document.getElementsByTagName('img');
- var index = 0;
- for (var i = 0; i < imgs.length; i++) {
- var img = imgs[i];
- var canvas = document.createElement('canvas');
- canvas.width = img.naturalWidth;
- canvas.height = img.naturalHeight;
- var ctx = canvas.getContext('2d');
- ctx.fillStyle = '#fff';
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- ctx.drawImage(img, 0, 0);
- canvas.toBlob(blob => {
- saveAs(blob, index + imgType);
- });
- index++;
- }
- }
复制代码
参考附件导出内容图片BeforePrint.html了解详情。
2. 区域快照保存图片(CameraShape)
在SpreadJS中,能够支持保存为图片的元素是形状。作为一种形状,区域快照引用单元格区域,同步单元格区域中的数据变化。那么,可以引用目标保存区域创建区域快照,通过区域快照获取图片源,进一步将图片源封装为指定图片类型,如图2所示。
图2. 区域快照保存图片
- function saveImageWithCameraShape(spread, referRange) {
- var sheet = spread.getActiveSheet();
- // 将待导出单元格区域转为单元格引用形式
- var cellRangeRefer = GC.Spread.Sheets.CalcEngine.rangeToFormula(referRange);
- // 引用待导出单元格区域,并创建区域快照
- var shape = sheet.shapes.addCameraShape('myCameraShape', sheet.name() + '!' + cellRangeRefer, 1000, 1000);
- var shapeStyle = shape.style();
- shapeStyle.line.lineStyle = GC.Spread.Sheets.Shapes.PresetLineDashStyle.dashDot;
- shape.style(shapeStyle);
- setTimeout(function() {
- var dataUrl = shape.toImageSrc();
- var link = document.createElement('a');
- link.href = dataUrl;
- link.download = 'camera-shape-image.png';
- link.click();
- sheet.shapes.remove(shape.name());
- }, 100);
- }
复制代码
3. 性能对比
针对上述导图区域为图片的方法,使用不同数据量分别测试了时间性能(单位为ms),如图3所示。纯Canvas方案直接从sheet所在Canvas中获取图片数据,区域局限于浏览器视窗内可见部分,不可见部分无法获取。因此,在浏览器缩放比例和sheet缩放比例均为100%时,视窗内仅能显示32行。那么,以32行*19列和100行*20列为测试数据量,BeforePrint因打印功能而耗时最多,纯Canvas耗时最少,CameraShape耗时明显少于BeforePrint,比纯Canvas耗时高出约4至5倍。对1000行*20列和10000行*20列数据量而言,纯Canvas无法获取这么大范围,测试数据无参考价值,BeforePrint方案耗时约为CameraShape方案的3倍。CameraShape耗时206908.92ms(约3.44分钟)成功导出100000*20列范围为图片,BeforePrint因耗时而导致页面卡顿。
图3. 性能对比
综合而言,CameraShape最灵活,可以自由导出sheet中任意范围,且耗时可观。在实际使用时,依据具体场景选择合适的方案即可。
关于区域快照的使用限制,可以参考如下链接中的博客了解:
附上Demo,以供参考。 |
|