カスタムヘッダセル型を作成するには、RowHeaderまたはColumnHeader、あるいはその他の組み込みセル型に基づき、独自のヘッダセル型を作成します。次に、例を示します。
作成したカスタムヘッダセル型に対し、マウスイベントを処理するための以下のメソッドを実装します。
getHitInfo:
processMouseメソッドに提供されるヒット情報を含んだオブジェクトを取得します。
processMouseDown:
マウスボタンダウンアクションを提供します。
processMouseMove:
マウスボタンムーヴアクションを提供します。
processMouseUp:
マウスボタンアップアクションを提供します。
processMouseEnter:
マウスエンターアクションを提供します。
processMouseLeave:
マウスリーヴアクションを提供します。
次に、getHitInfoメソッドの使用例を示します。
getHitInfoメソッドをオーバーライドすると、行および列ヘッダセルのCheckBox、Button、およびHyperLinkに対し、ButtonClickedイベントが有効になります。
ButtonClickedイベントは、Spreadまたはシートに連結して処理できます。次に、例を示します。
// @ts-ignore
import { Component, NgModule, enableProdMode } from '@angular/core';
// @ts-ignore
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import '@mescius/spread-sheets-resources-ja';
GC.Spread.Common.CultureManager.culture("ja-jp");
// @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({
standalone: true,
imports: [BrowserModule, SpreadSheetsModule, FormsModule],
selector: 'app-component',
templateUrl: 'src/app.component.html'
})
export class AppComponent {
spread: GC.Spread.Sheets.Workbook;
hostStyle = {
height: '100%',
};
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);
}
}
}
}
enableProdMode();
bootstrapApplication(AppComponent);
<!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$/ja/angular/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<!-- Polyfills -->
<script src="$DEMOROOT$/ja/angular/node_modules/core-js/client/shim.min.js"></script>
<script src="$DEMOROOT$/ja/angular/node_modules/zone.js/fesm2015/zone.min.js"></script>
<!-- SystemJS -->
<script src="$DEMOROOT$/ja/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$/ja/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;
}
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',
'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',
'tslib':'npm:tslib/tslib.js',
'@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js',
'@mescius/spread-sheets-resources-ja': 'npm:@mescius/spread-sheets-resources-ja/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',
meta: {
"*.component.ts": {
loader: "system.component-loader.js"
}
}
},
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);