"node_modules/ngx-toastr/toastr.css",
"src/styles.scss"
],
- "scripts": [
- "node_modules/chart.js/dist/Chart.bundle.js"
- ],
"stylePreprocessorOptions": {
"includePaths": [
"src"
"@types/file-saver": "2.0.1",
"async-mutex": "0.2.4",
"bootstrap": "5.2.3",
- "chart.js": "2.9.4",
+ "chart.js": "4.4.0",
+ "chartjs-adapter-moment": "1.0.1",
"detect-browser": "5.2.0",
"file-saver": "2.0.2",
"fork-awesome": "1.1.7",
"moment": "2.29.4",
"ng-block-ui": "3.0.2",
"ng-click-outside": "7.0.0",
- "ng2-charts": "2.4.2",
+ "ng2-charts": "4.1.1",
"ngx-pipe-function": "1.0.0",
"ngx-toastr": "17.0.2",
"rxjs": "6.6.3",
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+ },
"node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-SaU/Kgp6z40CiF9JxlsrSrBEa+8YIry9IiCPhhYSNekeEhIAkY7iyu9aZ+5dSQIdo7mf86MUVvxWYm5GAzB/0g==",
"dev": true
},
- "node_modules/@types/chart.js": {
- "version": "2.9.38",
- "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.38.tgz",
- "integrity": "sha512-rLoHHprkVEDpAXqke/xHalyXR+5Nv+3tfViwT/UnJZ41Wp/XPaSRlJKw2PU3S3tTCqKKyjkYai+VpeHoti79XQ==",
- "dependencies": {
- "moment": "^2.10.2"
- }
- },
"node_modules/@types/connect": {
"version": "3.4.36",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz",
}
},
"node_modules/chart.js": {
- "version": "2.9.4",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz",
- "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==",
- "dependencies": {
- "chartjs-color": "^2.1.0",
- "moment": "^2.10.2"
- }
- },
- "node_modules/chartjs-color": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
- "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
- "dependencies": {
- "chartjs-color-string": "^0.6.0",
- "color-convert": "^1.9.3"
- }
- },
- "node_modules/chartjs-color-string": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
- "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
+ "integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
"dependencies": {
- "color-name": "^1.0.0"
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=7"
}
},
- "node_modules/chartjs-color/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
+ "node_modules/chartjs-adapter-moment": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.1.tgz",
+ "integrity": "sha512-Uz+nTX/GxocuqXpGylxK19YG4R3OSVf8326D+HwSTsNw1LgzyIGRo+Qujwro1wy6X+soNSnfj5t2vZ+r6EaDmA==",
+ "peerDependencies": {
+ "chart.js": ">=3.0.0",
+ "moment": "^2.10.2"
}
},
- "node_modules/chartjs-color/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
"node_modules/check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
}
},
"node_modules/ng2-charts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-2.4.2.tgz",
- "integrity": "sha512-mY3C2uKCaApHCQizS2YxEOqQ7sSZZLxdV6N1uM9u/VvUgVtYvlPtdcXbKpN52ak93ZE22I73DiLWVDnDNG4/AQ==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-4.1.1.tgz",
+ "integrity": "sha512-iHwXDbmX86lfeH8VRcsaW2tJATsuAZo4kvvC/Yk2l35zOHjevja1qBvO6BAibiDazi9r9aS6ZRJOqWPsz1pP2w==",
"dependencies": {
- "@types/chart.js": "^2.9.24",
"lodash-es": "^4.17.15",
- "tslib": "^2.0.0"
+ "tslib": "^2.3.0"
},
"peerDependencies": {
- "@angular/common": ">=7.2.0",
- "@angular/core": ">=7.2.0",
- "chart.js": "^2.9.3",
- "rxjs": "^6.3.3"
+ "@angular/cdk": ">=14.0.0",
+ "@angular/common": ">=14.0.0",
+ "@angular/core": ">=14.0.0",
+ "chart.js": "^3.4.0 || ^4.0.0",
+ "rxjs": "^6.5.3 || ^7.4.0"
}
},
"node_modules/ngx-pipe-function": {
"@types/file-saver": "2.0.1",
"async-mutex": "0.2.4",
"bootstrap": "5.2.3",
- "chart.js": "2.9.4",
+ "chart.js": "4.4.0",
+ "chartjs-adapter-moment": "1.0.1",
"detect-browser": "5.2.0",
"file-saver": "2.0.2",
"fork-awesome": "1.1.7",
"moment": "2.29.4",
"ng-block-ui": "3.0.2",
"ng-click-outside": "7.0.0",
- "ng2-charts": "2.4.2",
+ "ng2-charts": "4.1.1",
"ngx-pipe-function": "1.0.0",
"ngx-toastr": "17.0.2",
"rxjs": "6.6.3",
import { NgbDropdownModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { ComponentsModule } from '~/app/shared/components/components.module';
import { RbdConfigurationEntry } from '~/app/shared/models/configuration';
RouterTestingModule,
ComponentsModule,
NgbDropdownModule,
- ChartsModule,
+ NgChartsModule,
SharedModule,
NgbTooltipModule
],
#chartCanvas
[datasets]="chart.datasets"
[options]="chart.options"
- [chartType]="chart.chartType">
+ [type]="chart.chartType">
</canvas>
<div class="chartjs-tooltip"
#chartTooltip>
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { configureTestBed } from '~/testing/unit-test-helper';
import { CephfsChartComponent } from './cephfs-chart.component';
+import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer';
describe('CephfsChartComponent', () => {
let component: CephfsChartComponent;
];
configureTestBed({
- imports: [ChartsModule],
+ imports: [NgChartsModule],
declarations: [CephfsChartComponent]
});
'mds_mem.ino': counter,
name: 'a'
};
+ if (typeof window !== 'undefined') {
+ window.ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
+ }
fixture.detectChanges();
});
import { Component, ElementRef, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
-import { ChartDataSets, ChartOptions, ChartPoint, ChartType } from 'chart.js';
import _ from 'lodash';
import moment from 'moment';
+import 'chartjs-adapter-moment';
import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
rhsCounter = 'mds_server.handle_client_request';
chart: {
- datasets: ChartDataSets[];
- options: ChartOptions;
- chartType: ChartType;
+ datasets: any[];
+ options: any;
+ chartType: any;
} = {
datasets: [
{
label: this.lhsCounter,
yAxisID: 'LHS',
data: [],
- lineTension: 0.1
+ tension: 0.1,
+ fill: {
+ target: 'origin'
+ }
},
{
label: this.rhsCounter,
yAxisID: 'RHS',
data: [],
- lineTension: 0.1
+ tension: 0.1,
+ fill: {
+ target: 'origin'
+ }
}
],
options: {
- title: {
- text: '',
- display: true
+ plugins: {
+ title: {
+ text: '',
+ display: true
+ },
+ tooltip: {
+ enabled: false,
+ mode: 'index',
+ intersect: false,
+ position: 'nearest',
+ callbacks: {
+ // Pick the Unix timestamp of the first tooltip item.
+ title: (context: any): string => {
+ let ts = '';
+ if (context.length > 0) {
+ ts = context[0].label;
+ }
+ return moment(ts).format('LTS');
+ }
+ }
+ },
+ legend: {
+ position: 'top'
+ }
},
responsive: true,
maintainAspectRatio: false,
- legend: {
- position: 'top'
- },
scales: {
- xAxes: [
- {
- position: 'top',
- type: 'time',
- time: {
- displayFormats: {
- quarter: 'MMM YYYY'
- }
- },
- ticks: {
- maxRotation: 0
+ x: {
+ position: 'top',
+ type: 'time',
+ time: {
+ displayFormats: {
+ quarter: 'MMM YYYY'
}
- }
- ],
- yAxes: [
- {
- id: 'LHS',
- type: 'linear',
- position: 'left'
},
- {
- id: 'RHS',
- type: 'linear',
- position: 'right'
- }
- ]
- },
- tooltips: {
- enabled: false,
- mode: 'index',
- intersect: false,
- position: 'nearest',
- callbacks: {
- // Pick the Unix timestamp of the first tooltip item.
- title: (tooltipItems, data): string => {
- let ts = 0;
- if (tooltipItems.length > 0) {
- const item = tooltipItems[0];
- const point = data.datasets[item.datasetIndex].data[item.index] as ChartPoint;
- ts = point.x as number;
- }
- return ts.toString();
+ ticks: {
+ maxRotation: 0
}
+ },
+ LHS: {
+ type: 'linear',
+ position: 'left'
+ },
+ RHS: {
+ type: 'linear',
+ position: 'right'
}
}
},
(tooltip: any) => tooltip.caretX + 'px',
(tooltip: any) => tooltip.caretY - tooltip.height - 23 + 'px'
);
- chartTooltip.getTitle = (ts) => moment(ts, 'x').format('LTS');
chartTooltip.checkOffset = true;
- const chartOptions: ChartOptions = {
+ const chartOptions: any = {
title: {
text: this.mdsCounter.name
},
- tooltips: {
- custom: (tooltip) => chartTooltip.customTooltips(tooltip)
+ tooltip: {
+ external: (context: any) => chartTooltip.customTooltips(context)
}
};
- _.merge(this.chart, { options: chartOptions });
+ _.merge(this.chart, { options: { plugins: chartOptions } });
}
private updateChart() {
- const chartDataSets: ChartDataSets[] = [
+ const chartDataset: any[] = [
{
data: this.convertTimeSeries(this.mdsCounter[this.lhsCounter])
},
}
];
_.merge(this.chart, {
- datasets: chartDataSets
+ datasets: chartDataset
});
this.chart.datasets = [...this.chart.datasets]; // Force angular to update
}
import { TreeModule } from '@circlon/angular-tree-component';
import { NgbNavModule, NgbTooltipModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { AppRoutingModule } from '~/app/app-routing.module';
import { SharedModule } from '~/app/shared/shared.module';
CommonModule,
SharedModule,
AppRoutingModule,
- ChartsModule,
+ NgChartsModule,
TreeModule,
NgbNavModule,
FormsModule,
} from '~/testing/unit-test-helper';
import { OsdReweightModalComponent } from '../osd-reweight-modal/osd-reweight-modal.component';
import { OsdListComponent } from './osd-list.component';
+import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer';
describe('OsdListComponent', () => {
let component: OsdListComponent;
close: jest.fn()
});
orchService = TestBed.inject(OrchestratorService);
+ if (typeof window !== 'undefined') {
+ window.ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
+ }
});
it('should create', () => {
<canvas baseChart
[datasets]="chartData.dataset"
[options]="options"
- [chartType]="'line'"
+ [type]="'line'"
[plugins]="chartAreaBorderPlugin">
</canvas>
</div>
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
import { DimlessBinaryPerSecondPipe } from '~/app/shared/pipes/dimless-binary-per-second.pipe';
import { FormatterService } from '~/app/shared/services/formatter.service';
-import { BaseChartDirective, PluginServiceGlobalRegistrationAndOptions } from 'ng2-charts';
+import { BaseChartDirective } from 'ng2-charts';
import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
import { NumberFormatterService } from '~/app/shared/services/number-formatter.service';
+import 'chartjs-adapter-moment';
@Component({
selector: 'cd-dashboard-area-chart',
maxConvertedValueUnits?: string;
chartDataUnits: string;
- chartData: any = {};
- options: any = {};
+ chartData: any;
+ options: any;
- public chartAreaBorderPlugin: PluginServiceGlobalRegistrationAndOptions[] = [
+ public chartAreaBorderPlugin: any[] = [
{
- beforeDraw(chart: Chart) {
+ beforeDraw(chart: any) {
if (!chart.options.plugins.borderArea) {
return;
}
const {
ctx,
- chartArea: { left, top, right, bottom }
+ chartArea: { left, top, width, height }
} = chart;
ctx.save();
ctx.strokeStyle = chart.options.plugins.chartAreaBorder.borderColor;
ctx.lineWidth = chart.options.plugins.chartAreaBorder.borderWidth;
ctx.setLineDash(chart.options.plugins.chartAreaBorder.borderDash || []);
ctx.lineDashOffset = chart.options.plugins.chartAreaBorder.borderDashOffset;
- ctx.strokeRect(left, top, right - left - 1, bottom);
+ ctx.strokeRect(left, top, width, height);
ctx.restore();
}
}
pointBackgroundColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-blue'),
borderColor: this.cssHelper.propertyValue('chart-color-strong-blue'),
- borderWidth: 1
+ borderWidth: 1,
+ fill: {
+ target: 'origin'
+ }
},
{
label: '',
pointBackgroundColor: this.cssHelper.propertyValue('chart-color-orange'),
backgroundColor: this.cssHelper.propertyValue('chart-color-translucent-yellow'),
borderColor: this.cssHelper.propertyValue('chart-color-orange'),
- borderWidth: 1
+ borderWidth: 1,
+ fill: {
+ target: 'origin'
+ }
}
]
};
this.options = {
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ mode: 'index',
+ external: function (tooltipModel: any) {
+ tooltipModel.tooltip.x = 10;
+ tooltipModel.tooltip.y = 0;
+ }.bind(this),
+ intersect: false,
+ displayColors: true,
+ backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
+ callbacks: {
+ title: function (tooltipItem: any): any {
+ return tooltipItem[0].xLabel;
+ },
+ label: (context: any) => {
+ return (
+ ' ' +
+ context.dataset.label +
+ ' - ' +
+ context.formattedValue +
+ ' ' +
+ this.chartDataUnits
+ );
+ }
+ }
+ },
+ borderArea: true,
+ chartAreaBorder: {
+ borderColor: this.cssHelper.propertyValue('chart-color-slight-dark-gray'),
+ borderWidth: 1
+ }
+ },
responsive: true,
maintainAspectRatio: false,
animation: false,
radius: 0
}
},
- legend: {
- display: false
- },
- tooltips: {
- mode: 'index',
- custom: function (tooltipModel: { x: number; y: number }) {
- tooltipModel.x = 10;
- tooltipModel.y = 0;
- }.bind(this),
- intersect: false,
- displayColors: true,
- backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
- callbacks: {
- title: function (tooltipItem: any): any {
- return tooltipItem[0].xLabel;
- },
- label: (tooltipItems: any, data: any) => {
- return (
- ' ' +
- data.datasets[tooltipItems.datasetIndex].label +
- ' - ' +
- tooltipItems.value +
- ' ' +
- this.chartDataUnits
- );
- }
- }
- },
hover: {
intersect: false
},
scales: {
- xAxes: [
- {
- display: false,
- type: 'time',
- gridLines: {
- display: false
- },
- time: {
- tooltipFormat: 'DD/MM/YYYY - HH:mm:ss'
- }
+ x: {
+ display: false,
+ type: 'time',
+ grid: {
+ display: false
+ },
+ time: {
+ tooltipFormat: 'DD/MM/YYYY - HH:mm:ss'
}
- ],
- yAxes: [
- {
- afterFit: (scaleInstance: any) => (scaleInstance.width = 100),
- gridLines: {
- display: false
- },
- ticks: {
- beginAtZero: true,
- maxTicksLimit: 4,
- callback: (value: any) => {
- if (value === 0) {
- return null;
- }
- return this.convertUnits(value);
- }
- }
+ },
+ y: {
+ afterFit: (scaleInstance: any) => (scaleInstance.width = 100),
+ grid: {
+ display: false
+ },
+ beginAtZero: true,
+ ticks: {
+ maxTicksLimit: 4
}
- ]
- },
- plugins: {
- borderArea: true,
- chartAreaBorder: {
- borderColor: this.cssHelper.propertyValue('chart-color-slight-dark-gray'),
- borderWidth: 1
}
}
};
private setChartTicks() {
if (!this.chart) {
+ this.chartDataUnits = '';
return;
}
let maxValue = 0;
let maxValueDataUnits = '';
- let extraRoom = 1.2;
if (this.data) {
let maxValueData = Math.max(...this.data.map((values: any) => values[1]));
[maxValue, maxValueDataUnits] = this.convertUnits(maxValue).split(' ');
}
- const yAxesTicks = this.chart.chart.options.scales.yAxes[0].ticks;
- yAxesTicks.suggestedMax = maxValue * extraRoom;
- yAxesTicks.suggestedMin = 0;
- yAxesTicks.callback = (value: any) => {
+ const yAxesTicks = this.chart.chart.options.scales.y;
+ yAxesTicks.ticks.callback = (value: any) => {
if (value === 0) {
return null;
}
<canvas baseChart
#chartCanvas
[datasets]="chartConfig.dataset"
- [chartType]="chartConfig.chartType"
+ [type]="chartConfig.chartType"
[options]="chartConfig.options"
[labels]="chartConfig.labels"
- [colors]="chartConfig.colors"
[plugins]="doughnutChartPlugins"
class="chart-canvas">
</canvas>
import * as Chart from 'chart.js';
import _ from 'lodash';
-import { PluginServiceGlobalRegistrationAndOptions } from 'ng2-charts';
import { CssHelper } from '~/app/shared/classes/css-helper';
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
color: string;
- chartConfig: any = {};
+ chartConfig: any;
- public doughnutChartPlugins: PluginServiceGlobalRegistrationAndOptions[] = [
+ public doughnutChartPlugins: any[] = [
{
id: 'center_text',
- beforeDraw(chart: Chart) {
+ beforeDraw(chart: any) {
const cssHelper = new CssHelper();
const defaultFontFamily = 'Helvetica Neue, Helvetica, Arial, sans-serif';
- Chart.defaults.global.defaultFontFamily = defaultFontFamily;
+ Chart.defaults.font.family = defaultFontFamily;
const ctx = chart.ctx;
if (!chart.options.plugins.center_text || !chart.data.datasets[0].label) {
return;
}
],
options: {
- cutoutPercentage: 70,
+ cutout: '70%',
events: ['click', 'mouseout', 'touchstart'],
- legend: {
- display: true,
- position: 'right',
- labels: {
- boxWidth: 10,
- usePointStyle: false,
- generateLabels: (chart: any) => {
- const labels = { 0: {}, 1: {}, 2: {} };
- labels[0] = {
- text: $localize`Used: ${chart.data.datasets[1].data[2]}`,
- fillStyle: chart.data.datasets[1].backgroundColor[0],
- strokeStyle: chart.data.datasets[1].backgroundColor[0]
- };
- labels[1] = {
- text: $localize`Warning: ${chart.data.datasets[0].data[0]}%`,
- fillStyle: chart.data.datasets[0].backgroundColor[1],
- strokeStyle: chart.data.datasets[0].backgroundColor[1]
- };
- labels[2] = {
- text: $localize`Danger: ${
- chart.data.datasets[0].data[0] + chart.data.datasets[0].data[1]
- }%`,
- fillStyle: chart.data.datasets[0].backgroundColor[2],
- strokeStyle: chart.data.datasets[0].backgroundColor[2]
- };
-
- return labels;
- }
- }
- },
+ aspectRatio: 2,
plugins: {
- center_text: true
- },
- tooltips: {
- enabled: true,
- displayColors: false,
- backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
- cornerRadius: 0,
- bodyFontSize: 14,
- bodyFontStyle: '600',
- position: 'nearest',
- xPadding: 12,
- yPadding: 12,
- filter: (tooltipItem: any) => {
- return tooltipItem.datasetIndex === 1;
+ center_text: true,
+ legend: {
+ display: true,
+ position: 'right',
+ labels: {
+ boxWidth: 10,
+ usePointStyle: false,
+ generateLabels: (chart: any) => {
+ let labels = chart.data.labels.slice(0, this.chartConfig.labels.length);
+ labels[0] = {
+ text: $localize`Used: ${chart.data.datasets[1].data[2]}`,
+ fillStyle: chart.data.datasets[1].backgroundColor[0],
+ strokeStyle: chart.data.datasets[1].backgroundColor[0]
+ };
+ labels[1] = {
+ text: $localize`Warning: ${chart.data.datasets[0].data[0]}%`,
+ fillStyle: chart.data.datasets[0].backgroundColor[1],
+ strokeStyle: chart.data.datasets[0].backgroundColor[1]
+ };
+ labels[2] = {
+ text: $localize`Danger: ${
+ chart.data.datasets[0].data[0] + chart.data.datasets[0].data[1]
+ }%`,
+ fillStyle: chart.data.datasets[0].backgroundColor[2],
+ strokeStyle: chart.data.datasets[0].backgroundColor[2]
+ };
+
+ return labels;
+ }
+ }
},
- callbacks: {
- label: (item: Record<string, any>, data: Record<string, any>) => {
- let text = data.labels[item.index];
- if (!text.includes('%')) {
- text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
+ tooltip: {
+ enabled: true,
+ displayColors: false,
+ backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
+ cornerRadius: 0,
+ bodyFontSize: 14,
+ bodyFontStyle: '600',
+ position: 'nearest',
+ xPadding: 12,
+ yPadding: 12,
+ filter: (tooltipItem: any) => {
+ return tooltipItem.datasetIndex === 1;
+ },
+ callbacks: {
+ label: (item: Record<string, any>, data: Record<string, any>) => {
+ let text = data.labels[item.index];
+ if (!text.includes('%')) {
+ text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
+ }
+ return text;
}
- return text;
}
+ },
+ title: {
+ display: false
}
- },
- title: {
- display: false
}
}
};
import { RouterModule } from '@angular/router';
import { NgbNavModule, NgbPopoverModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { SimplebarAngularModule } from 'simplebar-angular';
import { SharedModule } from '~/app/shared/shared.module';
CommonModule,
NgbNavModule,
SharedModule,
- ChartsModule,
+ NgChartsModule,
RouterModule,
NgbPopoverModule,
NgbTooltipModule,
import { RouterModule } from '@angular/router';
import { NgbNavModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { SharedModule } from '~/app/shared/shared.module';
import { DashboardV3Module } from '../dashboard-v3/dashboard-v3.module';
CommonModule,
NgbNavModule,
SharedModule,
- ChartsModule,
+ NgChartsModule,
RouterModule,
NgbPopoverModule,
FormsModule,
<canvas baseChart
#chartCanvas
[datasets]="chartConfig.dataset"
- [chartType]="chartConfig.chartType"
+ [type]="chartConfig.chartType"
[options]="chartConfig.options"
[labels]="chartConfig.labels"
- [colors]="chartConfig.colors"
[plugins]="doughnutChartPlugins"
class="chart-canvas">
</canvas>
import * as Chart from 'chart.js';
import _ from 'lodash';
-import { PluginServiceGlobalRegistrationAndOptions } from 'ng2-charts';
import { CssHelper } from '~/app/shared/classes/css-helper';
import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
@Output()
prepareFn = new EventEmitter();
- chartConfig: any = {};
+ chartConfig: any;
- public doughnutChartPlugins: PluginServiceGlobalRegistrationAndOptions[] = [
+ public doughnutChartPlugins: any[] = [
{
id: 'center_text',
- beforeDraw(chart: Chart) {
+ beforeDraw(chart: any) {
const cssHelper = new CssHelper();
const defaultFontFamily = 'Helvetica Neue, Helvetica, Arial, sans-serif';
- Chart.defaults.global.defaultFontFamily = defaultFontFamily;
+ Chart.defaults.font.family = defaultFontFamily;
const ctx = chart.ctx;
if (!chart.options.plugins.center_text || !chart.data.datasets[0].label) {
return;
dataset: [
{
label: null,
- borderWidth: 0
- }
- ],
- colors: [
- {
+ borderWidth: 0,
backgroundColor: [
this.cssHelper.propertyValue('chart-color-green'),
this.cssHelper.propertyValue('chart-color-yellow'),
}
],
options: {
- cutoutPercentage: 90,
+ cutout: '90%',
events: ['click', 'mouseout', 'touchstart'],
- legend: {
- display: true,
- position: 'right',
- labels: {
- boxWidth: 10,
- usePointStyle: false
- }
- },
+ aspectRatio: 2,
plugins: {
- center_text: true
- },
- tooltips: {
- enabled: true,
- displayColors: false,
- backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
- cornerRadius: 0,
- bodyFontSize: 14,
- bodyFontStyle: '600',
- position: 'nearest',
- xPadding: 12,
- yPadding: 12,
- callbacks: {
- label: (item: Record<string, any>, data: Record<string, any>) => {
- let text = data.labels[item.index];
- if (!text.includes('%')) {
- text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
+ center_text: true,
+ legend: {
+ display: true,
+ position: 'right',
+ labels: {
+ boxWidth: 10,
+ usePointStyle: false
+ }
+ },
+ tooltips: {
+ enabled: true,
+ displayColors: false,
+ backgroundColor: this.cssHelper.propertyValue('chart-color-tooltip-background'),
+ cornerRadius: 0,
+ bodyFontSize: 14,
+ bodyFontStyle: '600',
+ position: 'nearest',
+ xPadding: 12,
+ yPadding: 12,
+ callbacks: {
+ label: (item: Record<string, any>, data: Record<string, any>) => {
+ let text = data.labels[item.index];
+ if (!text.includes('%')) {
+ text = `${text} (${data.datasets[item.datasetIndex].data[item.index]}%)`;
+ }
+ return text;
}
- return text;
}
+ },
+ title: {
+ display: false
}
- },
- title: {
- display: false
}
}
};
ngOnInit() {
this.clientStatsConfig = {
- colors: [
+ dataset: [
{
backgroundColor: [
this.cssHelper.propertyValue('chart-color-cyan'),
};
this.rawCapacityChartConfig = {
- colors: [
+ dataset: [
{
backgroundColor: [
this.cssHelper.propertyValue('chart-color-blue'),
} else {
this.color = 'chart-color-blue';
}
- this.rawCapacityChartConfig.colors[0].backgroundColor[0] = this.cssHelper.propertyValue(
+ this.rawCapacityChartConfig.dataset[0].backgroundColor[0] = this.cssHelper.propertyValue(
this.color
);
NgbTooltipModule
} from '@ng-bootstrap/ng-bootstrap';
import { ClickOutsideModule } from 'ng-click-outside';
-import { ChartsModule } from 'ng2-charts';
+import { NgChartsModule } from 'ng2-charts';
import { SimplebarAngularModule } from 'simplebar-angular';
import { MotdComponent } from '~/app/shared/components/motd/motd.component';
NgbPopoverModule,
NgbProgressbarModule,
NgbTooltipModule,
- ChartsModule,
+ NgChartsModule,
ReactiveFormsModule,
PipesModule,
DirectivesModule,
[ngStyle]="style">
<canvas baseChart
#sparkCanvas
- [labels]="labels"
- [datasets]="datasets"
+ [data]="chartData"
[options]="options"
- [colors]="colors"
- [chartType]="'line'">
+ [type]="'line'">
</canvas>
<div class="chartjs-tooltip"
#sparkTooltip>
import { FormatterService } from '~/app/shared/services/formatter.service';
import { configureTestBed } from '~/testing/unit-test-helper';
import { SparklineComponent } from './sparkline.component';
+import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer';
describe('SparklineComponent', () => {
let component: SparklineComponent;
beforeEach(() => {
fixture = TestBed.createComponent(SparklineComponent);
component = fixture.componentInstance;
+ if (typeof window !== 'undefined') {
+ window.ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
+ }
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
- expect(component.options.tooltips.custom).toBeDefined();
+ expect(component.options.plugins.tooltip.external).toBeDefined();
});
it('should update', () => {
- expect(component.datasets).toEqual([{ data: [] }]);
- expect(component.labels.length).toBe(0);
+ expect(component.datasets[0].data).toEqual([]);
+ expect(component.chartData.labels.length).toBe(0);
component.data = [11, 22, 33];
component.ngOnChanges({ data: new SimpleChange(null, component.data, false) });
- expect(component.datasets).toEqual([{ data: [11, 22, 33] }]);
- expect(component.labels.length).toBe(3);
+ expect(component.datasets[0].data).toEqual([11, 22, 33]);
+ expect(component.chartData.labels.length).toBe(3);
});
it('should not transform the label, if not isBinary', () => {
component.isBinary = false;
- const result = component.options.tooltips.callbacks.label({ yLabel: 1024 });
+ const result = component.options.plugins.tooltip.callbacks.label({ parsed: { y: 1024 } });
expect(result).toBe(1024);
});
it('should transform the label, if isBinary', () => {
component.isBinary = true;
- const result = component.options.tooltips.callbacks.label({ yLabel: 1024 });
+ const result = component.options.plugins.tooltip.callbacks.label({ parsed: { y: 1024 } });
expect(result).toBe('1 KiB');
});
});
ViewChild
} from '@angular/core';
+import { BaseChartDirective } from 'ng2-charts';
import { ChartTooltip } from '~/app/shared/models/chart-tooltip';
import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
chartCanvasRef: ElementRef;
@ViewChild('sparkTooltip', { static: true })
chartTooltipRef: ElementRef;
+ @ViewChild(BaseChartDirective) chart: BaseChartDirective;
@Input()
data: any;
@Input()
isBinary: boolean;
- public colors: Array<any> = [
- {
- backgroundColor: 'rgba(40,140,234,0.2)',
- borderColor: 'rgba(40,140,234,1)',
- pointBackgroundColor: 'rgba(40,140,234,1)',
- pointBorderColor: '#fff',
- pointHoverBackgroundColor: '#fff',
- pointHoverBorderColor: 'rgba(40,140,234,0.8)'
- }
- ];
-
options: Record<string, any> = {
+ plugins: {
+ legend: {
+ display: false
+ },
+ tooltip: {
+ enabled: false,
+ mode: 'index',
+ intersect: false,
+ custom: undefined,
+ callbacks: {
+ label: (tooltipItem: any) => {
+ if (!tooltipItem.parsed) return;
+ if (this.isBinary) {
+ return this.dimlessBinaryPipe.transform(tooltipItem.parsed.y);
+ } else {
+ return tooltipItem.parsed.y;
+ }
+ },
+ title: () => ''
+ }
+ }
+ },
animation: {
duration: 0
},
responsive: true,
maintainAspectRatio: false,
- legend: {
- display: false
- },
elements: {
line: {
borderWidth: 1
}
},
- tooltips: {
- enabled: false,
- mode: 'index',
- intersect: false,
- custom: undefined,
- callbacks: {
- label: (tooltipItem: any) => {
- if (this.isBinary) {
- return this.dimlessBinaryPipe.transform(tooltipItem.yLabel);
- } else {
- return tooltipItem.yLabel;
- }
- },
- title: () => ''
- }
- },
scales: {
- yAxes: [
- {
- display: false
- }
- ],
- xAxes: [
- {
- display: false
- }
- ]
+ y: {
+ display: false
+ },
+ x: {
+ display: false
+ }
}
};
public datasets: Array<any> = [
{
- data: []
+ data: [],
+ backgroundColor: 'rgba(40,140,234,0.2)',
+ borderColor: 'rgba(40,140,234,1)',
+ pointBackgroundColor: 'rgba(40,140,234,1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(40,140,234,0.8)'
}
];
public labels: Array<any> = [];
+ chartData: {
+ datasets: any[];
+ labels: any[];
+ } = {
+ datasets: this.datasets,
+ labels: this.labels
+ };
+
constructor(private dimlessBinaryPipe: DimlessBinaryPipe) {}
ngOnInit() {
const getStyleTop = (tooltip: any) => {
- return tooltip.caretY - tooltip.height - tooltip.yPadding - 5 + 'px';
+ return tooltip.caretY - tooltip.height - 6 - 5 + 'px';
};
const getStyleLeft = (tooltip: any, positionX: number) => {
);
chartTooltip.customColors = {
- backgroundColor: this.colors[0].pointBackgroundColor,
- borderColor: this.colors[0].pointBorderColor
+ backgroundColor: this.datasets[0].pointBackgroundColor,
+ borderColor: this.datasets[0].pointBorderColor
};
- this.options.tooltips.custom = (tooltip: any) => {
+ this.options.plugins.tooltip.external = (tooltip: any) => {
chartTooltip.customTooltips(tooltip);
};
}
ngOnChanges(changes: SimpleChanges) {
- this.datasets[0].data = changes['data'].currentValue;
- this.labels = [...Array(changes['data'].currentValue.length)];
+ this.chartData.datasets[0].data = changes['data'].currentValue;
+ this.chartData.labels = [...Array(changes['data'].currentValue.length).fill('')];
+ if (this.chart) {
+ this.chart.chart.update();
+ }
}
}
* @param {any} tooltip
* @memberof ChartTooltip
*/
- customTooltips(tooltip: any) {
+ customTooltips(context: any) {
+ const tooltip = context.tooltip;
// Hide if no tooltip
if (tooltip.opacity === 0) {
this.tooltipEl.style.opacity = 0;
this.tooltipEl.style.fontFamily = tooltip._fontFamily;
this.tooltipEl.style.fontSize = tooltip.fontSize;
this.tooltipEl.style.fontStyle = tooltip._fontStyle;
- this.tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
+ this.tooltipEl.style.padding = 6 + 'px ' + 6 + 'px';
}
getBody(body: string) {