You can create a custom shape with a model, as shown below:
For path, the meaning of each parameter is:
"M": means moveTo(x,y)
"L": means lineTo(x,y)
"B": means bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
"Q": means quadraticCurveTo(cpx, cpy, x, y)
"A": means arc(x, y, r, startAngle, endAngle)
"A":' means arcTo(x1, y1, x2, y2, r)
"Z": means closePath
import { Component, NgModule, enableProdMode } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { SpreadSheetsModule } from '@mescius/spread-sheets-angular';
import GC from '@mescius/spread-sheets';
import "@mescius/spread-sheets-shapes";
import './styles.css';
@Component({
selector: 'app-component',
templateUrl: 'src/app.component.html'
})
export class AppComponent {
hostStyle = {
width: '100%',
height: '100%',
overflow: 'hidden',
float: 'left'
};
constructor() {
}
initSpread($event: any) {
let spread = $event.spread;
initDamageAreaShapes(spread);
let activeSheet = spread.getActiveSheet();
let workbookShapes = activeSheet.shapes.all();
for (let s = 0; s < workbookShapes.length; s++) {
workbookShapes[s].allowMove(false);
workbookShapes[s].allowResize(false);
}
}
}
function initDamageAreaShapes(spread: GC.Spread.Sheets.Workbook) {
let sheet = spread.getSheet(0);
let 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
]);
let 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"]
]
]
};
let 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"]
]
]
};
let 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"]
]
]
};
let 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"]
]
]
};
let 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"]
]
]
};
let 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);
}
@NgModule({
imports: [BrowserModule, SpreadSheetsModule],
declarations: [AppComponent],
exports: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
enableProdMode();
// Bootstrap application with hash style navigation and global services.
platformBrowserDynamic().bootstrapModule(AppModule);
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/angular/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<!-- Polyfills -->
<script src="$DEMOROOT$/en/angular/node_modules/core-js/client/shim.min.js"></script>
<script src="$DEMOROOT$/en/angular/node_modules/zone.js/fesm2015/zone.min.js"></script>
<!-- SystemJS -->
<script src="$DEMOROOT$/en/angular/node_modules/systemjs/dist/system.js"></script>
<script src="systemjs.config.js"></script>
<script>
// workaround to load 'rxjs/operators' from the rxjs bundle
System.import('rxjs').then(function (m) {
System.import('@angular/compiler');
System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators));
System.import('$DEMOROOT$/en/lib/angular/license.ts');
System.import('./src/app.component');
});
</script>
</head>
<body>
<app-component></app-component>
</body>
</html>
<div class="sample-tutorial">
<gc-spread-sheets class="sample-spreadsheets" [hostStyle]="hostStyle" (workbookInitialized)="initSpread($event)">
<gc-worksheet [name]="'Car Insurance Claim'"></gc-worksheet>
<gc-worksheet [name]="'Damage_Areas'"></gc-worksheet>
</gc-spread-sheets>
</div>
.sample-tutorial {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
(function (global) {
System.config({
transpiler: 'ts',
typescriptOptions: {
tsconfig: true
},
meta: {
'typescript': {
"exports": "ts"
},
'*.css': { loader: 'css' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
'core-js': 'npm:core-js/client/shim.min.js',
'zone': 'npm:zone.js/fesm2015/zone.min.js',
'rxjs': 'npm:rxjs/dist/bundles/rxjs.umd.min.js',
'@angular/core': 'npm:@angular/core/fesm2022',
'@angular/common': 'npm:@angular/common/fesm2022/common.mjs',
'@angular/compiler': 'npm:@angular/compiler/fesm2022/compiler.mjs',
'@angular/platform-browser': 'npm:@angular/platform-browser/fesm2022/platform-browser.mjs',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/fesm2022/platform-browser-dynamic.mjs',
'@angular/common/http': 'npm:@angular/common/fesm2022/http.mjs',
'@angular/router': 'npm:@angular/router/fesm2022/router.mjs',
'@angular/forms': 'npm:@angular/forms/fesm2022/forms.mjs',
'jszip': 'npm:jszip/dist/jszip.min.js',
'typescript': 'npm:typescript/lib/typescript.js',
'ts': './plugin.js',
'tslib':'npm:tslib/tslib.js',
'css': 'npm:systemjs-plugin-css/css.js',
'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js',
'@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js',
'@mescius/spread-sheets-shapes': 'npm:@mescius/spread-sheets-shapes/index.js',
'@mescius/spread-sheets-angular': 'npm:@mescius/spread-sheets-angular/fesm2020/mescius-spread-sheets-angular.mjs',
'@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
src: {
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
},
"node_modules": {
defaultExtension: 'js'
},
"node_modules/@angular": {
defaultExtension: 'mjs'
},
"@mescius/spread-sheets-angular": {
defaultExtension: 'mjs'
},
'@angular/core': {
defaultExtension: 'mjs',
main: 'core.mjs'
}
}
});
})(this);