To create a custom header cell type, create a custom header cell type based on the RowHeader or ColumnHeader, or another built-in CellType. For example:
For your custom header cell type, provide the following methods to process mouse events.
getHitInfo: Gets an object that contains hit information that will be provided to processMouse methods.
processMouseDown: Provides the action to perform for mouse button down.
processMouseMove: Provides the action to perform for mouse move.
processMouseUp: Provides the action to perform for mouse button up.
processMouseEnter: Provides the action to perform for mouse enter.
processMouseLeave: Provides the action to perform for mouse leave.
Here's a sample that uses the getHitInfo method.
The ButtonClicked event is available for CheckBox, Button, and HyperLink on row and column header cells after overriding the getHitInfo method.
You can process the ButtonClicked event by binding to Spread or Sheet. For example:
// @ts-ignore
import { Component, NgModule, enableProdMode } from '@angular/core';
// @ts-ignore
import { BrowserModule } from '@angular/platform-browser';
// @ts-ignore
import { FormsModule } from '@angular/forms';
// @ts-ignore
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
// @ts-ignore
import { SpreadSheetsModule } from '@mescius/spread-sheets-angular';
// @ts-ignore
import GC from '@mescius/spread-sheets';
import { HighlightColumnItemsCellType, TopItemsCellType, HeaderCheckBoxCellType, SortHyperlinkCellType, HighlightRowItemsCellType } from "./app.data";
import './styles.css';
const spreadNS = GC.Spread.Sheets;
@Component({
selector: 'app-component',
templateUrl: 'src/app.component.html'
})
export class AppComponent {
spread: GC.Spread.Sheets.Workbook;
hostStyle = {
width: '100%',
height: '100%',
overflow: 'hidden',
float: 'left'
};
initSpread($event: any) {
const spread = $event.spread;
var rowCount = 50, columnCount = 20;
var sheet = spread.getSheet(0);
sheet.suspendPaint();
sheet.setRowCount(rowCount);
sheet.setColumnCount(columnCount);
sheet.setColumnWidth(0, 60, spreadNS.SheetArea.rowHeader);
this.fillSampleData(sheet, new spreadNS.Range(0, 0, rowCount, columnCount));
sheet.setCellType(0, 1, new HighlightColumnItemsCellType(), spreadNS.SheetArea.colHeader);
sheet.setCellType(0, 3, new TopItemsCellType(10), spreadNS.SheetArea.colHeader);
sheet.setCellType(0, 5, new HeaderCheckBoxCellType(120), spreadNS.SheetArea.colHeader);
sheet.setCellType(0, 7, new SortHyperlinkCellType(), spreadNS.SheetArea.colHeader);
sheet.setCellType(9, 0, new HighlightRowItemsCellType(), spreadNS.SheetArea.rowHeader);
sheet.resumePaint();
spread.bind(spreadNS.Events.ButtonClicked, (e: MouseEvent, args: any) => {
var sheet = args.sheet, sheetArea = args.sheetArea,
row = args.row, col = args.col,
tag = sheet.getTag(row, col, sheetArea),
cellType = sheet.getCellType(row, col, sheetArea);
if (cellType instanceof TopItemsCellType) {
var count = cellType.count;
sheet.setTag(row, col, !tag, sheetArea);
var range = new spreadNS.Range(-1, col, -1, 1);
var rowFilter = new spreadNS.Filter.HideRowFilter(range);
sheet.rowFilter(rowFilter);
rowFilter.filterButtonVisible(false);
var condition = new spreadNS.ConditionalFormatting.Condition(spreadNS.ConditionalFormatting.ConditionType.top10Condition, {
type: spreadNS.ConditionalFormatting.Top10ConditionType.top,
expected: count
});
rowFilter.addFilterItem(col, condition);
if (!tag) {
rowFilter.filter();
} else {
rowFilter.unfilter();
}
}
});
}
fillSampleData(sheet: GC.Spread.Sheets.Worksheet, range: GC.Spread.Sheets.Range) {
for (var i = 0; i < range.rowCount; i++) {
for (var j = 0; j < range.colCount; j++) {
sheet.setValue(range.row + i, range.col + j, Math.ceil(Math.random() * 300) - 100);
}
}
}
}
@NgModule({
imports: [BrowserModule, SpreadSheetsModule, FormsModule],
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 [hostStyle]="hostStyle" (workbookInitialized)="initSpread($event)">
<gc-worksheet></gc-worksheet>
</gc-spread-sheets>
</div>
import GC from "@mescius/spread-sheets";
const spreadNS = GC.Spread.Sheets;
// Define highlight cell types
export class HighlightColumnItemsCellType extends spreadNS.CellTypes.ColumnHeader {
constructor() {
super();
this.RADIUS = 10;
this.HIGHLIGHT_COLOR = "rgb(40, 171, 240)";
this.NORMAL_COLOR = "rgb(128, 255, 255)";
this.HIGHLIGHT_TIP = "Remove highlight.";
this.NORMAL_TIP = "Highlight negative numbers.";
spreadNS.CellTypes.ColumnHeader.apply(this);
}
paint (ctx, value, x, y, width, height, style, context) {
spreadNS.CellTypes.ColumnHeader.prototype.paint.apply(this, arguments);
var tag = context.sheet.getTag(context.row, context.col, context.sheetArea);
var RADIUS = this.RADIUS;
ctx.save();
ctx.beginPath();
ctx.arc(x + width - RADIUS, y + height / 2, RADIUS / 2, 0, Math.PI * 2);
ctx.fillStyle = (tag && tag.color) || this.NORMAL_COLOR;
ctx.fill();
ctx.restore();
};
getHitInfo (x, y, cellStyle, cellRect, context) {
var RADIUS = this.RADIUS;
var centerX = cellRect.x + cellRect.width - RADIUS,
centerY = cellRect.y + cellRect.height / 2;
var hitInfo = {x: x, y: y, row: context.row, col: context.col, cellRect: cellRect, sheetArea: context.sheetArea, sheet: context.sheet};
if (Math.abs(x - centerX) <= RADIUS && Math.abs(y - centerY) <= RADIUS) {
hitInfo.isReservedLocation = true;
}
return hitInfo;
};
processMouseDown (hitInfo) {
this._hideTip();
};
processMouseMove (hitInfo) {
if (hitInfo.isReservedLocation) {
var sheet = hitInfo.sheet;
var offset = {
top:sheet.getParent().getHost().offsetTop,
left:sheet.getParent().getHost().offsetLeft
}
var tag = sheet.getTag(hitInfo.row, hitInfo.col, hitInfo.sheetArea);
this._showTip(offset.top + hitInfo.y + 20, offset.left + hitInfo.x + 20, (tag && tag.tip) || this.NORMAL_TIP);
} else {
this._hideTip();
}
};
processMouseUp (hitInfo) {
if (hitInfo.isReservedLocation) {
var sheet = hitInfo.sheet;
var tag = sheet.getTag(hitInfo.row, hitInfo.col, hitInfo.sheetArea);
if (!tag) {//first time
tag = {color: this.HIGHLIGHT_COLOR, tip: this.HIGHLIGHT_TIP};
sheet.setTag(hitInfo.row, hitInfo.col, tag, hitInfo.sheetArea);
var style = new spreadNS.Style();
style.foreColor = "red";
var ranges = [new spreadNS.Range(-1, hitInfo.col, -1, 1)];
var rule = sheet.conditionalFormats.addCellValueRule(spreadNS.ConditionalFormatting.ComparisonOperators.lessThan, 0, 0, style, ranges);
tag.rule = rule;
tag.isHighlighed = true;
} else if (!tag.isHighlighed) {
tag.color = this.HIGHLIGHT_COLOR;
tag.tip = this.HIGHLIGHT_TIP;
sheet.conditionalFormats.addRule(tag.rule);
tag.isHighlighed = true;
} else {
tag.color = this.NORMAL_COLOR;
tag.tip = this.NORMAL_TIP;
sheet.conditionalFormats.removeRule(tag.rule);
tag.isHighlighed = false;
}
var offset = {
top:sheet.getParent().getHost().offsetTop,
left:sheet.getParent().getHost().offsetLeft
}
this._showTip(offset.top + hitInfo.y + 20, offset.left + hitInfo.x + 20, (tag && tag.tip) || this.NORMAL_TIP);
}
};
processMouseEnter (hitInfo) {
};
processMouseLeave (hitInfo) {
this._hideTip();
};
_showTip (top, left, tip) {
if (!this._tipElement) {
var span = document.createElement("span");
span.style.position = "absolute";
span.style.background = "#EEEEEE";
span.style.border = "1px solid black";
span.style.boxShadow = "5px 5px 5px rgba(0,0,0,0.4)";
span.style.fontSize = "14px";
document.body.insertBefore(span, null);
this._tipElement = span;
}
var tipElement = this._tipElement;
tipElement.textContent = tip;
var spanStyle = tipElement.style;
spanStyle.top = top + "px";
spanStyle.left = left + "px";
};
_hideTip () {
if (this._tipElement) {
document.body.removeChild(this._tipElement);
this._tipElement = undefined;
}
};
}
export class HighlightRowItemsCellType extends spreadNS.CellTypes.RowHeader {
constructor() {
super();
this.RADIUS = 10;
this.HIGHLIGHT_COLOR = "rgb(40, 171, 240)";
this.NORMAL_COLOR = "rgb(128, 255, 255)";
this.HIGHLIGHT_TIP = "Remove highlight.";
this.NORMAL_TIP = "Highlight negative numbers.";
spreadNS.CellTypes.RowHeader.apply(this);
}
paint (ctx, value, x, y, width, height, style, context) {
spreadNS.CellTypes.RowHeader.prototype.paint.apply(this, arguments);
var tag = context.sheet.getTag(context.row, context.col, context.sheetArea);
var RADIUS = this.RADIUS;
ctx.save();
ctx.beginPath();
ctx.arc(x + width - RADIUS, y + height / 2, RADIUS / 2, 0, Math.PI * 2);
ctx.fillStyle = (tag && tag.color) || this.NORMAL_COLOR;
ctx.fill();
ctx.restore();
};
getHitInfo (x, y, cellStyle, cellRect, context) {
var RADIUS = this.RADIUS;
var centerX = cellRect.x + cellRect.width - RADIUS, centerY = cellRect.y + cellRect.height / 2;
var hitInfo = {x: x, y: y, row: context.row, col: context.col, cellRect: cellRect, sheetArea: context.sheetArea, sheet: context.sheet};
if (Math.abs(x - centerX) <= RADIUS && Math.abs(y - centerY) <= RADIUS) {
hitInfo.isReservedLocation = true;
}
return hitInfo;
};
processMouseDown (hitInfo) {
this._hideTip();
};
processMouseMove (hitInfo) {
if (hitInfo.isReservedLocation) {
var sheet = hitInfo.sheet;
var offset = {
top:sheet.getParent().getHost().offsetTop,
left:sheet.getParent().getHost().offsetLeft
}
var tag = sheet.getTag(hitInfo.row, hitInfo.col, hitInfo.sheetArea);
this._showTip(offset.top + hitInfo.y + 20, offset.left + hitInfo.x + 20, (tag && tag.tip) || this.NORMAL_TIP);
} else {
this._hideTip();
}
};
processMouseUp (hitInfo) {
if (hitInfo.isReservedLocation) {
var sheet = hitInfo.sheet;
var tag = sheet.getTag(hitInfo.row, hitInfo.col, hitInfo.sheetArea);
if (!tag) {//first time
tag = {color: this.HIGHLIGHT_COLOR, tip: this.HIGHLIGHT_TIP};
sheet.setTag(hitInfo.row, hitInfo.col, tag, hitInfo.sheetArea);
var style = new spreadNS.Style();
style.foreColor = "red";
var ranges = [new spreadNS.Range(hitInfo.row, -1, 1, -1)];
var rule = sheet.conditionalFormats.addCellValueRule(spreadNS.ConditionalFormatting.ComparisonOperators.lessThan, 0, 0, style, ranges);
tag.rule = rule;
tag.isHighlighed = true;
} else if (!tag.isHighlighed) {
tag.color = this.HIGHLIGHT_COLOR;
tag.tip = this.HIGHLIGHT_TIP;
sheet.conditionalFormats.addRule(tag.rule);
tag.isHighlighed = true;
} else {
tag.color = this.NORMAL_COLOR;
tag.tip = this.NORMAL_TIP;
sheet.conditionalFormats.removeRule(tag.rule);
tag.isHighlighed = false;
}
var offset = {
top:sheet.getParent().getHost().offsetTop,
left:sheet.getParent().getHost().offsetLeft
}
this._showTip(offset.top + hitInfo.y + 20, offset.left + hitInfo.x + 20, (tag && tag.tip) || this.NORMAL_TIP);
}
};
processMouseEnter (hitInfo) {
};
processMouseLeave (hitInfo) {
this._hideTip();
};
_showTip (top, left, tip) {
if (!this._tipElement) {
var span = document.createElement("span");
span.style.position = "absolute";
span.style.background = "#EEEEEE";
span.style.border = "1px solid black";
span.style.boxShadow = "5px 5px 5px rgba(0,0,0,0.4)";
span.style.fontSize = "14px";
document.body.insertBefore(span, null);
this._tipElement = span;
}
var tipElement = this._tipElement;
tipElement.textContent = tip;
var spanStyle = tipElement.style;
spanStyle.top = top + "px";
spanStyle.left = left + "px";
};
_hideTip () {
if (this._tipElement) {
document.body.removeChild(this._tipElement);
this._tipElement = undefined;
}
};
}
// Define button cell type
export class TopItemsCellType extends spreadNS.CellTypes.Button {
constructor(count) {
super();
spreadNS.CellTypes.Button.apply(this);
count = +count || 10;
if (!count || isNaN(count) || count < 0) {
count = 10;
}
this.count = count;
this.text("Top " + count);
}
getHitInfo (x, y, cellStyle, cellRect, context) {
var self = this;
var leftX = cellRect.x + self.marginLeft(),
rightX = cellRect.x + cellRect.width - self.marginRight(),
topY = cellRect.y + self.marginTop(),
bottomY = cellRect.y + cellRect.height - self.marginBottom();
var info = {x: x, y: y, row: context.row, col: context.col, cellRect: cellRect, sheetArea: context.sheetArea, sheet: context.sheet};
if (leftX <= x && x <= rightX && topY <= y && y <= bottomY) {
info.isReservedLocation = true;
}
return info;
};
}
// Define checkbox cell type
var basePaint = spreadNS.CellTypes.CheckBox.prototype.paint;
export class HeaderCheckBoxCellType extends spreadNS.CellTypes.CheckBox {
constructor(value) {
super();
spreadNS.CellTypes.CheckBox.apply(this);
value = +value || 100;
if (!value || isNaN(value) || value < 0) {
value = 100;
}
this.value = value;
this.caption(">" + value);
}
paint (ctx, value, x, y, width, height, style, context) {
var tag = !!(context.sheet.getTag(context.row, context.col, context.sheetArea) || false);
basePaint.apply(this, [ctx, tag, x, y, width, height, style, context]);
};
getHitInfo (x, y, cellStyle, cellRect, context) {
if (context) {
return {x: x, y: y, row: context.row, col: context.col, cellRect: cellRect, sheetArea: context.sheetArea, isReservedLocation: true, sheet: context.sheet};
}
return null;
};
createEditorElement(){
return null;
}
processMouseDown (hitInfo) {
this._isMouseDown = true;
};
processMouseUp (hitInfo) {
if (this._isMouseDown) {
this.doFilter(hitInfo);
this._isMouseDown = false;
}
return true;
};
doFilter (hitInfo) {
var value = this.value, sheet = hitInfo.sheet, row = hitInfo.row, col = hitInfo.col, sheetArea = hitInfo.sheetArea;
var tag = sheet.getTag(row, col, sheetArea);
sheet.setTag(row, col, !tag, sheetArea);
var rowFilter = new spreadNS.Filter.HideRowFilter(new spreadNS.Range(-1, col, -1, 1));
sheet.rowFilter(rowFilter);
rowFilter.filterButtonVisible(false);
var condition = new spreadNS.ConditionalFormatting.Condition(spreadNS.ConditionalFormatting.ConditionType.numberCondition, {
compareType: spreadNS.ConditionalFormatting.GeneralComparisonOperators.greaterThan,
expected: value
});
rowFilter.addFilterItem(col, condition);
if (!tag) {
rowFilter.filter();
} else {
rowFilter.unfilter();
}
};
}
// Define hyperlink cell type
export class SortHyperlinkCellType extends spreadNS.CellTypes.HyperLink {
constructor() {
super();
spreadNS.CellTypes.HyperLink.apply(this);
this.text("Sort");
}
getHitInfo (x, y, cellStyle, cellRect, context) {
if (context) {
return {
x: x,
y: y,
row: context.row,
col: context.col,
cellRect: cellRect,
cellStyle: cellStyle,
sheetArea: context.sheetArea,
isReservedLocation: true,
sheet: context.sheet
};
}
return null;
};
processMouseDown (hitInfo) {
};
processMouseMove (hitInfo) {
};
processMouseUp (hitInfo) {
var sheet = hitInfo.sheet, sheetArea = hitInfo.sheetArea,
row = hitInfo.row, col = hitInfo.col;
var tag = !(sheet.getTag(row, col, sheetArea) || false);
sheet.setTag(row, col, tag, sheetArea);
sheet.sortRange(0, 0, sheet.getRowCount(), sheet.getColumnCount(), true, [{
index: col,
ascending: tag
}]);
};
processMouseEnter (hitInfo) {
};
processMouseLeave (hitInfo) {
};
}
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets{
height: 100%;
}
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-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);