自定义形状

SpreadJS 支持通过自定义形状模型创建任意形状,形状的位置、颜色等属性可以绑定单元格公式实现动态更新。本 Demo 以汽车保险理赔场景为例,展示了如何使用路径命令绘制复杂形状,并通过公式关联数据源。

概述 本 Demo 展示了如何使用自定义形状模型创建复杂形状。Demo 以汽车保险理赔为场景,创建了车身前部、前门、后门、后部、前轮、后轮等 6 个自定义形状,形状的位置和颜色通过公式引用数据表中的单元格值,实现了形状属性的动态绑定。 实现思路 创建主工作表("Car Insurance Claim")用于显示形状 创建数据工作表("Damage_Areas")存储形状的位置和颜色数据 为数据工作表添加表格并填充初始数据(区域名称、Left、Top、Color) 定义 6 个形状模型,使用 Canvas 风格的路径命令绘制形状轮廓 形状的 left、top、color 属性使用公式引用数据表中的单元格 使用 sheet.shapes.add() 方法将形状添加到工作表 禁用形状的移动和调整大小功能 代码解析 创建数据表并存储形状数据 这段代码创建了名为 "Damage_Areas" 的工作表,存储了各个形状的位置(Left、Top)和颜色数据,便于后续通过公式引用。 定义自定义形状模型 形状模型包含以下关键属性: left、top、width、height:形状的位置和尺寸 options.fill:填充样式,支持颜色和透明度 path:形状的路径定义,使用 Canvas 风格的命令数组 公式引用:left、top、color 使用 =Damage_Areas!B2 这样的公式语法,绑定到数据表的单元格 路径命令说明 本 Demo 使用了 M(移动)、L(直线)、A(圆弧)、Z(闭合)四种命令绘制车身轮廓和车轮。 添加形状到工作表 使用 sheet.shapes.add() 方法将自定义形状添加到工作表,第一个参数是形状名称,第二个参数是形状模型对象。 禁用形状的移动和调整大小 这段代码获取所有形状并禁用移动和调整大小功能,使形状保持固定位置。 运行效果 主工作表显示由 6 个自定义形状组成的汽车轮廓图 车身前部、前后车门、后部使用橙色半透明填充 前后车轮使用圆形路径绘制 所有形状的位置和颜色数据来源于 "Damage_Areas" 工作表 用户无法移动或调整形状大小 修改数据表中的值,形状会自动更新 API 参考 shapes.add() 方法 name:形状名称(字符串) autoShapeTypeOrModel:可以是内置形状类型枚举,或自定义形状模型对象(IShapeModel) left、top、width、height:可选的位置和尺寸参数 返回添加的 Shape 对象 形状模型(IShapeModel)结构 left、top、width、height:位置和尺寸(支持公式) options.fill:填充配置,包含 type(填充类型)、color(颜色,支持公式)、transparency(透明度) path:路径命令数组,每个命令为 [命令名, 参数...] 格式 路径命令 M:moveTo(x, y) - 移动画笔 L:lineTo(x, y) - 画直线 B:bezierCurveTo(cp1x, cp1y, cp2x, cpy2, x, y) - 贝塞尔曲线 Q:quadraticCurveTo(cpx, cpy, x, y) - 二次曲线 A:arc(x, y, r, startAngle, endAngle) - 圆弧 Z:closePath() - 闭合路径
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 }); var activeSheet = spread.getActiveSheet(); initDamageAreaShapes(spread); var workbookShapes = activeSheet.shapes.all(); for (var s = 0; s < workbookShapes.length; s++) { workbookShapes[s].allowMove(false); workbookShapes[s].allowResize(false); } activeSheet.setRowCount(30); activeSheet.setColumnCount(20); activeSheet.name("Car Insurance Claim"); }; function initDamageAreaShapes(spread) { var sheet = spread.getSheet(0); spread.addSheet(1, new GC.Spread.Sheets.Worksheet("Damage_Areas")); var damageAreaSheet = spread.getSheet(1); damageAreaSheet.setColumnWidth(0,120); var table = damageAreaSheet.tables.add("table1", 0, 0, 7, 4, GC.Spread.Sheets.Tables.TableThemes.medium4); table.filterButtonVisible(false); var damageAreas = ["Area", "Left", "Top", "Color"], carFront = ["carFront", 50, 50, "orange"], carFrontDoor = ["carFrontDoor", 197, 23, "orange"], carBackDoor = ["carBackDoor", 332, 23, "orange"], carBack = ["carBack", 405, 24, "orange"], carFrontWheel = ["carFrontWheel", 45, 64, "orange"], carBackWheel = ["carBackWheel", 361, 64, "orange"]; damageAreaSheet.setArray(0, 0, [ damageAreas, carFront, carFrontDoor, carBackDoor, carBack, carFrontWheel, carBackWheel ]); var carFrontModel = { left: "=Damage_Areas!B2", top: "=Damage_Areas!C2", width: 157, height: 85, options: { fill: { type: 1, color: "=Damage_Areas!D2", transparency: "0.5" } }, path: [ [ ["M", 6, 48], ["L", 21, 29], ["L", 59, 20], ["L", 136, 14], ["L", 157, 8], ["L", 150, 24], ["L", 148, 47], ["L", 150, 69], ["L", 157, 85], ["L", 140, 85], //Wheel well ["L", 136, 71], ["L", 128, 58], ["L", 119, 52], ["L", 107, 47], ["L", 94, 46], ["L", 83, 47], ["L", 68, 52], ["L", 60, 61], ["L", 54, 70], ["L", 50, 85], ["L", 21, 85], ["L", 13, 71], ["L", 2, 67], ["Z"] ] ] }; var carFrontDoorModel = { left: "=Damage_Areas!B3", top: "=Damage_Areas!C3", width: 140, height: 112, options: { fill: { type: 1, color: "=Damage_Areas!D3", transparency: "0.5" } }, path: [ [ ["M", 9, 36], ["L", 84, 2], ["L", 116, 0], ["L", 140, 0], ["L", 134, 74], ["L", 140, 112], ["L", 12, 112], ["L", 7, 105], ["L", 4, 96], ["L", 1, 81], ["L", 2, 64], ["L", 5, 49], ["Z"] ] ] }; var carBackDoorModel = { left: "=Damage_Areas!B4", top: "=Damage_Areas!C4", width: 121, height: 111, options: { fill: { type: 1, color: "=Damage_Areas!D4", transparency: "0.5" } }, path: [ [ ["M", 6, 0], ["L", 71, 1], ["L", 95, 20], ["L", 115, 44], ["L", 121, 53], ["L", 117, 62], ["L", 105, 68], ["L", 87, 85], ["L", 78, 100], ["L", 75, 111], ["L", 5, 111], ["L", 2, 97], ["L", 0, 79], ["L", 1, 61], ["L", 3, 38], ["Z"] ] ] }; var carBackModel = { left: "=Damage_Areas!B5", top: "=Damage_Areas!C5", width: 168, height: 110, options: { fill: { type: 1, color: "=Damage_Areas!D5", transparency: "0.5" } }, path: [ [ ["M", 0, 0], ["L", 51, 9], ["L", 110, 34], ["L", 154, 43], ["L", 163, 49], ["L", 166, 55], ["L", 152, 55], ["L", 149, 73], ["L", 168, 80], ["L", 168, 91], ["L", 164, 97], ["L", 159, 97], ["L", 153, 110], ["L", 100, 110], //Wheel well ["L", 96, 97], ["L", 86, 84], ["L", 69, 74], ["L", 60, 72], ["L", 50, 73], ["L", 40, 73], ["L", 32, 78], ["L", 24, 85], ["L", 19, 92], ["L", 14, 101], ["L", 13, 110], ["L", 3, 110], ["L", 9, 96], ["L", 17, 81], ["L", 31, 69], ["L", 44, 61], ["L", 49, 55], ["L", 44, 44], ["L", 29, 27], ["L", 14, 12], ["Z"] ] ] }; var carFrontWheelModel = { left: "=Damage_Areas!B6", top: "=Damage_Areas!C6", width: 168, height: 168, options: { fill: { type: 1, color: "=Damage_Areas!D6", transparency: "0.5" } }, path: [ [ ["A", 100, 75, 40, 0, 2 * Math.PI], ["Z"] ] ] }; var carBackWheelModel = { left: "=Damage_Areas!B7", top: "=Damage_Areas!C7", width: 168, height: 168, options: { fill: { type: 1, color: "=Damage_Areas!D7", transparency: "0.5" } }, path: [ [ ["A", 100, 75, 40, 0, 2 * Math.PI], ["Z"] ] ] }; sheet.shapes.add('carFront', carFrontModel); sheet.shapes.add('carFrontDoor', carFrontDoorModel); sheet.shapes.add('carBackDoor', carBackDoorModel); sheet.shapes.add('carBack', carBackModel); sheet.shapes.add('carFrontWheel', carFrontWheelModel); sheet.shapes.add('carBackWheel', carBackWheelModel); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture" content="zh-cn" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-resources-zh/dist/gc.spread.sheets.resources.zh.min.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> </div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: 100%; height: 100%; overflow: hidden; float: left; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }