In this article, we will be exploring how easy it is adding custom code into a tile.
It is easy to add custom tiles should you require more fine grain control over your UI elements.
Implementation
Task: Create a custom tile with a chart to display a simple graph of fish counts. Here we will use ChartJS for charts and graphs.
For this example, we must create a page and custom tile (named ‘Stats’) in our project through the Codebots Build section and ask SpringBot to rebuild the application.
Once we have created our new custom tile, we will be required to interact with the following files to complete this task.
File Name | Description |
---|---|
package.json | Where we will install our new graph library |
stats.tile.component.html | HTML file where we define our new chart with graphs |
stats.tile.component.ts | TypeScript file that accompanies the HTML file, allowing us to define functionality |
stats.tile.component.scss | SCSS file that contains styling for our new chart |
stats.tile.component.module.ts | TypeScript file to include our component as a single module |
To install ChartJS:
- Open a terminal and navigate to
clientside
-
Run
npm install --save chart.js
andnpm install --save-dev @types/chart.js
@types/chart.js
is a type definition file for TypeScript
Now that we have added everything we need, we can now add and display our graph in our tile:
-
Locate
stats.tile.component.html
and insert the following code into the protected region:Remember to turn on the protected regions
<div>
<canvas #myChart></canvas>
</div>
The wrapping
div
element is required as without it ChartJS will not be able to create a chart for us.
- Locate
stats.tile.component.ts
. - Modify the import statements to inside
Add any additional imports here
protected region:
// % protected region % [Add any additional imports here] off begin
import {ElementRef, ViewChild} from '@angular/core';
import {Chart} from 'chart.js';
import {Store} from '@ngrx/store';
import {
getFishCollectionModels,
getFishCollectionState
} from '../../../models/fish/fish.model.selector';
import {Observable} from 'rxjs';
import {FishModel} from '../../../models/fish/fish.model';
import * as modelAction from '../../../models/fish/fish.model.action';
import {QueryOperation} from '../../../lib/services/http/interfaces';
import { FishModelState } from 'src/app/models/fish/fish.model.state';
// % protected region % [Add any additional imports here] end
- Insert the following code block inside the protected region
Add any additional class fields here
:
// % protected region % [Add any additional class fields here] on begin
aliveFishes: Observable<FishModel[]>;
aliveFishesCount: number = 0;
aliveFishesId = 'alive-fish';
deadFishes: Observable<FishModel[]>;
deadFishesCount: number = 0;
deadFishesId = 'dead-fish';
constructor(
private readonly store: Store<{ model: FishModelState }>,
) {
this.store.dispatch(new modelAction.InitialiseFishCollectionState({
collectionId: this.aliveFishesId
}));
this.aliveFishes = this.store.select(getFishCollectionModels, this.aliveFishesId);
this.store.dispatch(new modelAction.FetchFishModelsWithQuery({
queryParams: {
pageIndex: 0,
pageSize: 1000,
where: [
[
{
path: 'fishAlive',
operation: QueryOperation.EQUAL,
value: 'true'
}
]
]
},
collectionId: this.aliveFishesId
},
));
this.store.select(getFishCollectionState, this.aliveFishesId).subscribe(collectionStatus => {
this.aliveFishesCount = collectionStatus.collectionCount;
this.updateChart();
});
// Get Dead Fish
this.store.dispatch(new modelAction.InitialiseFishCollectionState({
collectionId: this.deadFishesId
}));
this.aliveFishes = this.store.select(getFishCollectionModels, this.deadFishesId);
this.store.dispatch(new modelAction.FetchFishModelsWithQuery({
queryParams: {
pageIndex: 0,
pageSize: 1000,
where: [
[
{
path: 'fishAlive',
operation: QueryOperation.EQUAL,
value: 'false'
}
]
]
},
collectionId: this.deadFishesId
},
));
this.store.select(getFishCollectionState, this.deadFishesId).subscribe(collectionStatus => {
this.deadFishesCount = collectionStatus.collectionCount;
this.updateChart();
});
}
updateChart() {
if (this.chart) {
this.chart.data.datasets[0].data = [
this.aliveFishesCount,
this.deadFishesCount,
];
this.chart.update();
}
}
@ViewChild('canvas')
canvasEl: ElementRef;
chart: Chart;
ngAfterViewInit() {
const ctx = (this.canvasEl.nativeElement as HTMLCanvasElement).getContext('2d');
this.chart = new Chart(ctx, {
// The type of chart we want to create
type: 'bar',
// The data for our dataset
data: {
labels: ['Alive', 'Dead'],
datasets: [{
label: 'Fish count',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [this.aliveFishesCount, this.deadFishesCount]
}]
},
// Configuration options go here
options: {
title: {
text: 'Fish Count',
display: true
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true,
ticks: {
beginAtZero: true
}
}],
}
}
});
}
// % protected region % [Add any additional class fields here] end
- Open the file
stats.tile.component.html found
inclientside/src/app/tiles/custom/stats/stats.tile.component.html.
- Find the protected region [Add any additional HTML structure here], turn it on and paste the following into it.
<div>
<canvas #canvas></canvas>
</div>