概述
本 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;
}