图表讲清楚了数据,却讲不清品牌归属和一句话的结论。报告里常见的做法是在图表角上放一个标识,再在空白处标一句「线上销售合计 1208 万元」——把结论放在读者目光已经落着的地方,而不是另起一段正文。这类元素在 Excel 里属于图表自己的形状层,位置以图表为坐标系而不是以单元格为坐标系,用代码添加时这一点最容易出错。除此之外,绘图区那块默认的白底也可以整片换掉,用一张浅色纹理图当背景,让图表与报表其余部分归于同一套视觉。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成这些操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
在图表中插入图片
报告里的图表常常要带上品牌标识或产品图。图片放进图表内部之后,它就成了图表的一部分:图表挪位置、改尺寸,图片跟着走;把图表复制到别的文档或导出成图片,图片也不会掉队。相形之下,浮在单元格上方的那类图片,图表一经挪动位置便对不齐了。具体操作步骤如下:
- 将字体、测试数据文件与图片载入 VFS。
- 用
workbook.LoadFromFile加载工作簿,取第一个工作表上的第一张图表。 - 用
chart.Shapes.AddPicture把图片加进图表,返回值就是这个形状对象。 - 设置形状的
Left、Top、Width、Height。图表内形状的坐标以图表自身为基准,四个属性都以图表宽度(Left、Width)或高度(Top、Height)的 4000 分之一为单位。 - 用
workbook.SaveToFile保存工作簿。
以下为完整的代码示例,演示如何在 React 中在图表中插入图片:
function App() {
const addPictureInChart = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体、测试数据文件与图片载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ChartReport.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
await window.spire.FetchFileToVFS('logo.png', '', `${process.env.PUBLIC_URL}static/image/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 取第一个工作表与其中的图表
const sheet = workbook.Worksheets.get(0);
const chart = sheet.Charts.get(0);
// 将图片插入图表,返回的对象即图表中的这张图片
const picture = chart.Shapes.AddPicture('logo.png');
// 定位到图表右上角,并压到合适的大小。不设置时图片会按原始像素铺开,常常盖住大半个图表
picture.Left = 2850; // 距图表左边缘 2850/4000
picture.Top = 110; // 距图表上边缘 110/4000
picture.Width = 900; // 图片宽度 900/4000
picture.Height = 532; // 图片高度 532/4000,与源图 320×120 的比例一致
// 保存工作簿
const outputFileName = 'AddPictureInChart.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取结果文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>在图表中插入图片与文本框</h1>
<button id="add-picture-in-chart" onClick={addPictureInChart}>在图表中插入图片</button>
</div>
);
}
export default App;
运行后,在图表中插入图片的效果:

在图表中插入文本框
图表能表达趋势,却说不出一句结论。某个系列的合计数、一段同比说明、一处异常标注,都可以用文本框直接写在图上,让读者不必在正文里再找一遍数字。文本框与图片同属图表内部的形状,用的是同一套坐标,区别在于它的尺寸要照着文字长度留:宽度留窄了文字会折行,折下来的那一行会被框高裁掉,看上去就像文字丢了半截。具体操作步骤如下:
- 将字体与测试数据文件载入 VFS。
- 用
workbook.LoadFromFile加载工作簿,取第一个工作表上的第一张图表。 - 用
chart.Shapes.AddTextBox在图表里建立文本框。 - 按文字长度设置
Left、Top、Width、Height,让内容排成一行。 - 把要显示的文字写进
Text属性。 - 用
HAlignment、VAlignment让文字居中,取值分别来自xlsModule.CommentHAlignType与xlsModule.CommentVAlignType。 - 用
Fill.ForeColor、Line.ForeColor与Line.Weight设置底色、边框色与边框粗细,使文本框在图表上独立可辨。 - 用
workbook.SaveToFile保存工作簿。
以下为完整的代码示例,演示如何在 React 中在图表中插入文本框:
function App() {
const addTextBoxInChart = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体与测试数据文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ChartReport.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 取第一个工作表与其中的图表
const sheet = workbook.Worksheets.get(0);
const chart = sheet.Charts.get(0);
// 在图表中插入文本框
const textBox = chart.Shapes.AddTextBox();
// 设置文本框的位置与尺寸,单位同样是图表的 1/4000
textBox.Left = 450;
textBox.Top = 530;
textBox.Width = 2100;
textBox.Height = 340;
// 写入文字内容
textBox.Text = '线上销售合计 1208 万元';
// 文字居中,并加上浅黄底色与蓝色边框,使其在图表上独立可辨
textBox.HAlignment = xlsModule.CommentHAlignType.Center;
textBox.VAlignment = xlsModule.CommentVAlignType.Center;
textBox.Fill.ForeColor = xlsModule.Color.FromArgb(255, 255, 245, 214);
textBox.Line.ForeColor = xlsModule.Color.FromArgb(255, 46, 106, 176);
textBox.Line.Weight = 1;
// 保存工作簿
const outputFileName = 'AddTextBoxInChart.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取结果文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>在图表中插入图片与文本框</h1>
<button id="add-textbox-in-chart" onClick={addTextBoxInChart}>在图表中插入文本框</button>
</div>
);
}
export default App;
运行后,在图表中插入文本框的效果:

用图片填充绘图区
绘图区那块白底是图表的默认值,报表做久了容易显得千篇一律。把它换成一张浅色纹理图,柱子、网格线和坐标轴标签依旧清清楚楚,背景却有了质感,整张图表也和报表其他部分归到了同一套视觉里。填充图片与摆在图表上的图片形状互不干扰,两者可以同时使用。具体操作步骤如下:
- 将字体、测试数据文件与背景图载入 VFS。
- 用
workbook.LoadFromFile加载工作簿,取第一个工作表上的第一张图表。 - 用背景图构造一个
xlsModule.Stream内存流。 - 把它交给
chart.PlotArea.Fill.CustomPicture;第二个参数name用来指定工作簿里已有的纹理,没有现成纹理时传'None'。 - 用
workbook.SaveToFile保存工作簿。
以下为完整的代码示例,演示如何在 React 中用图片填充绘图区:
function App() {
const fillPlotAreaWithPicture = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体、测试数据文件与背景图载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ChartReport.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
await window.spire.FetchFileToVFS('background.png', '', `${process.env.PUBLIC_URL}static/image/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 取第一个工作表与其中的图表
const sheet = workbook.Worksheets.get(0);
const chart = sheet.Charts.get(0);
// 将背景图读入内存流,作为绘图区的填充图片
const background = new xlsModule.Stream('background.png');
chart.PlotArea.Fill.CustomPicture({ im: background, name: 'None' });
// 保存工作簿
const outputFileName = 'FillPlotAreaWithPicture.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取结果文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>在图表中插入图片与文本框</h1>
<button id="fill-plot-area" onClick={fillPlotAreaWithPicture}>用图片填充绘图区</button>
</div>
);
}
export default App;
运行后,用图片填充绘图区的效果:

常见问题
图表里能不能加箭头、标注线一类的形状
解决:带指向性的标注线、箭头没有专门的接口,可以用文本框代替:把文本框拉成细长条,去掉底色只留边框,摆到需要指示的位置即可。
用图片填充时,填的是绘图区还是整张图表
原因:PlotArea.Fill 与 ChartArea.Fill 是两个不同的对象。前者只覆盖坐标轴围起来的那块区域,图表标题、图例和坐标轴标签都留在图片之外;后者覆盖整个图表,标题和图例同样会落到图片上。
解决:按需要挑一个即可,填充完成后读 Fill.FillType,成功时返回 ShapeFillType.Picture:
// 只填绘图区:标题、图例和坐标轴标签保持原样
const background = new xlsModule.Stream('background.png');
chart.PlotArea.Fill.CustomPicture({ im: background, name: 'None' });
// 铺满整张图表:图片延伸到标题和图例底下
chart.ChartArea.Fill.CustomPicture({ im: new xlsModule.Stream('background.png'), name: 'None' });
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









