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.
<template> <div class="sample-tutorial"> <gc-spread-sheets class="sample-spreadsheets" @workbookInitialized="initSpread"> </gc-spread-sheets> <shape-panel @updateConnectorShapeStyle="updateConnectorShapeStyle" :showConnectorPropPanelRef="showConnectorPropPanelRef"> </shape-panel> </div> </template> <script setup> import GC from "@mescius/spread-sheets"; import { ref, createApp } from "vue"; import "@mescius/spread-sheets-vue"; import '@mescius/spread-sheets-shapes'; const spreadRef = ref(null); const showConnectorPropPanelRef = ref(false); const updateConnectorShapeStyle = (action, value) => { let sheet = spreadRef.value.getActiveSheet(); let activeShape = sheet.shapes.all().filter(function (sp) { return sp.isSelected() && sp instanceof GC.Spread.Sheets.Shapes.ConnectorShape; }); if (activeShape.length > 0) { activeShape.forEach((shape) => { _setConnectorShapeStyle(shape, action, value); }); sheet.repaint(); } } const _setConnectorShapeStyle = (shape, action, value) => { 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); } const bindSpreadEvent = () => { spreadRef.value.bind(GC.Spread.Sheets.Events.ShapeSelectionChanged, function () { let sheet = spreadRef.value.getActiveSheet(); var selectedShape = sheet.shapes.all().filter(function (sp) { return sp.isSelected(); }); var isShapeSelected = false, isConnectorSelected = false; if (selectedShape.length > 0) { selectedShape.forEach((shape) => { if (!isShapeSelected && shape instanceof GC.Spread.Sheets.Shapes.Shape) { isShapeSelected = true; } else if (!isConnectorSelected && shape instanceof GC.Spread.Sheets.Shapes.ConnectorShape) { isConnectorSelected = true; } }); setConnectorPropVisibility(isConnectorSelected); } else { setConnectorPropVisibility(false); } }) } const setConnectorPropVisibility = (isShow) => { showConnectorPropPanelRef.value = isShow; } const initSpread = (spread) => { spreadRef.value = 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); bindSpreadEvent(); } </script> <style scoped> .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; } #app { height: 100%; } </style>
<template> <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 v-show="props.showConnectorPropPanelRef" class="option-row"> <label for="beginArrowheadStyle">Begin Arrowhead Style:</label> <select v-model="beginStyleRef" id="beginArrowheadStyle" class="shapeSelect"> <option :value="item.value" v-for="item in arrowHeadStyleRef" :key="item.name"> {{ item.name }}</option> </select> <input @click="_handleConnectorShapeStyleSetting('beginStyle', beginStyleRef)" type="button" class='arrow-action-button' value="Set" /> <label>Begin Arrowhead Width:</label> <select v-model="beginWidthRef" class="shapeSelect"> <option :value="item.value" v-for="item in arrowHeadWidthListRef" :key="item.name"> {{ item.name }}</option> </select> <input type="button" @click="_handleConnectorShapeStyleSetting('beginWidth', beginWidthRef)" class='arrow-action-button' value="Set" /> <label>Begin Arrowhead Length:</label> <select v-model="beginLengthRef" class="shapeSelect"> <option :value="item.value" v-for="item in arrowHeadLengthListRef" :key="item.name"> {{ item.name }}</option> </select> <input type="button" @click="_handleConnectorShapeStyleSetting('beginLength', beginLengthRef)" class='arrow-action-button' value="Set" /> <label for="endArrowheadStyle">End Arrowhead Style:</label> <select v-model="endStyleRef" id="endArrowheadStyle" class="shapeSelect"> <option :value="item.value" v-for="item in arrowHeadStyleRef" :key="item.name"> {{ item.name }}</option> </select> <input type="button" @click="_handleConnectorShapeStyleSetting('endStyle', endStyleRef)" class='arrow-action-button' value="Set" /> <label>End Arrowhead Width:</label> <select v-model="endWidthRef" class="shapeSelect"> <option v-bind:value="item.value" v-for="item in arrowHeadWidthListRef" :key="item.name">{{ item.name }} </option> </select> <input type="button" @click="_handleConnectorShapeStyleSetting('endWidth', endWidthRef)" class='arrow-action-button' value="Set" /> <label>End Arrowhead Length:</label> <select v-model="endLengthRef" class="shapeSelect"> <option v-bind:value="item.value" v-for="item in arrowHeadLengthListRef" :key="item.name">{{ item.name }} </option> </select> <input type="button" @click="_handleConnectorShapeStyleSetting('endLength', endLengthRef)" class='arrow-action-button' value="Set" /> </div> </div> </template> <script setup> import GC from "@mescius/spread-sheets"; import "@mescius/spread-sheets-shapes"; import { defineEmits, defineProps, ref } from 'vue'; let arrowheadLength = { "short": 0, "medium": 1, "long": 2 }; let arrowheadWidth = { "narrow": 0, "medium": 1, "wide": 2 }; const beginStyleRef = ref(3); const beginWidthRef = ref(1); const beginLengthRef = ref(2); const endStyleRef = ref(3); const endWidthRef = ref(1); const endLengthRef = ref(2); const arrowHeadLengthListRef = ref(getEnumList(arrowheadLength)); const arrowHeadWidthListRef = ref(getEnumList(arrowheadWidth)); const arrowHeadStyleRef = ref(getEnumList(GC.Spread.Sheets.Shapes.ArrowheadStyle)); const props = defineProps({ showConnectorPropPanelRef: Boolean }); const emits = defineEmits(['updateConnectorShapeStyle']); const _handleConnectorShapeStyleSetting = (action, value) => { emits("updateConnectorShapeStyle", action, value); } function getEnumList(enumObject) { let names = []; for (var name in enumObject) { if (name === "none" || (parseInt(name, 10)) == name) { continue; } names.push({ name: name, value: enumObject[name] }); } names.sort(function (a, b) { return a.name > b.name ? 1 : -1 }); return names; } </script> <style scoped></style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/spread/source/data/inventory-tracker.js" type="text/javascript"></script> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="./systemjs.config.js"></script> <script src="./compiler.js" type="module"></script> <script> var System = SystemJS; System.import("./src/app.js"); System.import('$DEMOROOT$/en/lib/vue3/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.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-vue': 'npm:@mescius/spread-sheets-vue/index.js' }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);