Shape Arrow Head

In SpreadJS, you can add connector shapes using different kind of arrows, including: the normal arrow (no side is pointed), the basic arrow (with both sides pointed), the open arrow, the stealth arrow, the oval arrow and the diamond arrow.

You can customize the properties of connectorShapes using the ConnectorShape API: style: Gets or sets the style of the connector shape.
import { Component, NgModule, enableProdMode } from '@angular/core'; import { FormsModule } from '@angular/forms'; 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'; function getEnumList(enumObject: object) { let names = []; for (var name in enumObject) { if (name === "none" || (parseInt(<any>name, 10)) == <any>name) { continue; } names.push({ name: name, value: enumObject[name] }); } names.sort(function(a, b) { return a.name > b.name ? 1 : -1 }); return names; } const arrowheadLength = { "short": 0, "medium": 1, "long": 2 }; const arrowheadWidth = { "narrow": 0, "medium": 1, "wide": 2 }; @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { spread: GC.Spread.Sheets.Workbook; hostStyle = { width: 'calc(100% - 280px)', height: '100%', overflow: 'hidden', float: 'left' }; showConnectorPropPanel = false; beginStyle = 3; beginWidth = 1; beginLength = 2; endStyle = 3; endWidth = 1; endLength = 2; arrowHeadLengthList = getEnumList(arrowheadLength); arrowHeadWidthList = getEnumList(arrowheadWidth); arrowHeadStyle = getEnumList(GC.Spread.Sheets.Shapes.ArrowheadStyle); initSpread($event: any) { let spread = this.spread = $event.spread; var line1 = spread.getActiveSheet().shapes.addConnector("line", GC.Spread.Sheets.Shapes.ConnectorType.straight, 20, 40, 200, 110); var line2 = spread.getActiveSheet().shapes.addConnector("line", GC.Spread.Sheets.Shapes.ConnectorType.straight, 20, 110, 200, 190); var line3 = spread.getActiveSheet().shapes.addConnector("line", GC.Spread.Sheets.Shapes.ConnectorType.elbow, 300, 40, 500, 90); var line4 = spread.getActiveSheet().shapes.addConnector("line", GC.Spread.Sheets.Shapes.ConnectorType.elbow, 300, 130, 500, 190); var lineShapeStyle = line1.style(); lineShapeStyle.line.width = 3; lineShapeStyle.line.color = "#82BC00"; line1.style(lineShapeStyle); line2.style(lineShapeStyle); line3.style(lineShapeStyle); line4.style(lineShapeStyle); this.bindSpreadEvent(); } bindSpreadEvent() { let spread = this.spread, self = this; spread.bind(GC.Spread.Sheets.Events.ShapeSelectionChanged, function() { let sheet = spread.getActiveSheet(); var selectedShape = sheet.shapes.all().filter(function(sp: GC.Spread.Sheets.Shapes.ShapeBase) { return sp.isSelected(); }); var isShapeSelected = false, isConnectorSelected = false; if (selectedShape.length > 0) { selectedShape.forEach((shape: GC.Spread.Sheets.Shapes.ShapeBase) => { if (!isShapeSelected && shape instanceof GC.Spread.Sheets.Shapes.Shape) { isShapeSelected = true; } else if (!isConnectorSelected && shape instanceof GC.Spread.Sheets.Shapes.ConnectorShape) { isConnectorSelected = true; } }); self.setConnectorPropVisibility(isConnectorSelected); } else { self.setConnectorPropVisibility(false); } }) } setConnectorPropVisibility(isShow: boolean) { this.showConnectorPropPanel = isShow; } updateConnectorShapeStyle(action: string, value: any) { let sheet = this.spread.getActiveSheet(); let activeShape = sheet.shapes.all().filter(function(sp: GC.Spread.Sheets.Shapes.ShapeBase) { return sp.isSelected() && sp instanceof GC.Spread.Sheets.Shapes.ConnectorShape; }); if (activeShape.length > 0) { activeShape.forEach((shape: GC.Spread.Sheets.Shapes.ShapeBase) => { this._setConnectorShapeStyle(shape, action, value); }); sheet.repaint(); } } _setConnectorShapeStyle(shape: GC.Spread.Sheets.Shapes.ShapeBase, action: string, value: any) { let shapeStyle = shape.style(); let shapeStyleLine = shapeStyle.line; switch (action) { case "beginStyle": { shapeStyleLine.beginArrowheadStyle = value; break; } case "beginWidth": { shapeStyleLine.beginArrowheadWidth = value; break; } case "beginLength": { shapeStyleLine.beginArrowheadLength = value; break; } case "endStyle": { shapeStyleLine.endArrowheadStyle = value; break; } case "endWidth": { shapeStyleLine.endArrowheadWidth = value; break; } case "endLength": { shapeStyleLine.endArrowheadLength = value; break; } } shape.style(shapeStyle); } } @NgModule({ imports: [BrowserModule, SpreadSheetsModule, FormsModule], declarations: [AppComponent], exports: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { } enableProdMode(); 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 [hostStyle]="hostStyle" (workbookInitialized)="initSpread($event)"> </gc-spread-sheets> <div class="options-container"> <div class="option-row"> Select a shape and change the arrow-head properties to see the effect. </div> <div id="divideLine" class="divide-line"></div> <div *ngIf="showConnectorPropPanel" class="option-row"> <label for="beginArrowheadStyle">Begin Arrowhead Style:</label> <select [(ngModel)]="beginStyle" class="shapeSelect"> <option *ngFor="let item of arrowHeadStyle" [value]="item.value|number"> {{item.name}} </option> </select> <input (click)="updateConnectorShapeStyle('beginStyle', beginStyle)" type="button" class='arrow-action-button' value="Set" /> <label>Begin Arrowhead Width:</label> <select [(ngModel)]="beginWidth" class="shapeSelect"> <option *ngFor="let item of arrowHeadWidthList" [value]="item.value|number"> {{item.name}} </option> </select> <input type="button" (click)="updateConnectorShapeStyle('beginWidth', beginWidth)" class='arrow-action-button' value="Set" /> <label>Begin Arrowhead Length:</label> <select [(ngModel)]="beginLength" class="shapeSelect"> <option *ngFor="let item of arrowHeadLengthList" [value]="item.value|number"> {{item.name}} </option> </select> <input type="button" (click)="updateConnectorShapeStyle('beginLength', beginLength)" class='arrow-action-button' value="Set" /> <label for="endArrowheadStyle">End Arrowhead Style:</label> <select [(ngModel)]="endStyle" class="shapeSelect"> <option *ngFor="let item of arrowHeadStyle" [value]="item.value|number"> {{item.name}} </option> </select> <input type="button" (click)="updateConnectorShapeStyle('endStyle', endStyle)" class='arrow-action-button' value="Set" /> <label>End Arrowhead Width:</label> <select [(ngModel)]="endWidth" class="shapeSelect"> <option *ngFor="let item of arrowHeadWidthList" [value]="item.value|number"> {{item.name}} </option> </select> <input type="button" (click)="updateConnectorShapeStyle('endWidth', endWidth)" class='arrow-action-button' value="Set" /> <label>End Arrowhead Length:</label> <select [(ngModel)]="endLength" class="shapeSelect"> <option *ngFor="let item of arrowHeadLengthList" [value]="item.value|number"> {{item.name}} </option> </select> <input type="button" (click)="updateConnectorShapeStyle('endLength', endLength)" class='arrow-action-button' value="Set" /> </div> </div> </div>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding-left: 5px; } .divide-line { width: 100%; height: 1px; background: #cbcbcb; margin-top: 10px; margin-bottom: 3px; } .title { text-align: center; font-weight: bold; } label { display: block; margin-top: 15px; margin-bottom: 5px; } p { padding: 2px 10px; background-color: #F4F8EB; } input { width: 160px; margin-left: 10px; display: inline; } input[type=button] { width: 50px; margin-left: 1px; } select { width: 160px; margin-left: 10px; display: inline; } textarea { width: 160px; margin-left: 10px; } 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);