From 14d2f0a108b0b8a93b895ce518583a9584a752ac Mon Sep 17 00:00:00 2001 From: Pedro Gonzalez Gomez Date: Thu, 21 Sep 2023 16:36:45 +0200 Subject: [PATCH] mgr/dashboard: chartjs and ng2-charts version pugrade Fixes:https://tracker.ceph.com/issues/63160 Signed-off-by: Pedro Gonzalez Gomez --- .../mgr/dashboard/frontend/angular.json | 3 - .../mgr/dashboard/frontend/package-lock.json | 83 ++++------ .../mgr/dashboard/frontend/package.json | 5 +- .../rbd-configuration-list.component.spec.ts | 4 +- .../cephfs-chart/cephfs-chart.component.html | 2 +- .../cephfs-chart.component.spec.ts | 8 +- .../cephfs-chart/cephfs-chart.component.ts | 117 +++++++------- .../src/app/ceph/cephfs/cephfs.module.ts | 4 +- .../osd/osd-list/osd-list.component.spec.ts | 4 + .../dashboard-area-chart.component.html | 2 +- .../dashboard-area-chart.component.ts | 147 +++++++++--------- .../dashboard-pie.component.html | 3 +- .../dashboard-pie/dashboard-pie.component.ts | 118 +++++++------- .../ceph/dashboard-v3/dashboard-v3.module.ts | 4 +- .../app/ceph/dashboard/dashboard.module.ts | 4 +- .../health-pie/health-pie.component.html | 3 +- .../health-pie/health-pie.component.ts | 76 +++++---- .../ceph/dashboard/health/health.component.ts | 6 +- .../shared/components/components.module.ts | 4 +- .../sparkline/sparkline.component.html | 6 +- .../sparkline/sparkline.component.spec.ts | 18 ++- .../sparkline/sparkline.component.ts | 101 ++++++------ .../src/app/shared/models/chart-tooltip.ts | 5 +- 23 files changed, 355 insertions(+), 372 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/angular.json b/src/pybind/mgr/dashboard/frontend/angular.json index e1cb4c29fc324..9d26d5876b9fa 100644 --- a/src/pybind/mgr/dashboard/frontend/angular.json +++ b/src/pybind/mgr/dashboard/frontend/angular.json @@ -99,9 +99,6 @@ "node_modules/ngx-toastr/toastr.css", "src/styles.scss" ], - "scripts": [ - "node_modules/chart.js/dist/Chart.bundle.js" - ], "stylePreprocessorOptions": { "includePaths": [ "src" diff --git a/src/pybind/mgr/dashboard/frontend/package-lock.json b/src/pybind/mgr/dashboard/frontend/package-lock.json index 15aaff89db927..7ce746060f9af 100644 --- a/src/pybind/mgr/dashboard/frontend/package-lock.json +++ b/src/pybind/mgr/dashboard/frontend/package-lock.json @@ -28,7 +28,8 @@ "@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", @@ -36,7 +37,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", @@ -4950,6 +4951,11 @@ "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", @@ -6568,14 +6574,6 @@ "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", @@ -9504,44 +9502,25 @@ } }, "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", @@ -21161,19 +21140,19 @@ } }, "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": { diff --git a/src/pybind/mgr/dashboard/frontend/package.json b/src/pybind/mgr/dashboard/frontend/package.json index 3205888f57082..6e19fff3aaa81 100644 --- a/src/pybind/mgr/dashboard/frontend/package.json +++ b/src/pybind/mgr/dashboard/frontend/package.json @@ -62,7 +62,8 @@ "@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", @@ -70,7 +71,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", diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component.spec.ts index f54ad02720c52..03c40a9e03ed9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component.spec.ts @@ -5,7 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing'; 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'; @@ -27,7 +27,7 @@ describe('RbdConfigurationListComponent', () => { RouterTestingModule, ComponentsModule, NgbDropdownModule, - ChartsModule, + NgChartsModule, SharedModule, NgbTooltipModule ], diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html index b81bc20ba1cff..e7a106d550759 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html @@ -3,7 +3,7 @@ #chartCanvas [datasets]="chart.datasets" [options]="chart.options" - [chartType]="chart.chartType"> + [type]="chart.chartType">
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts index 4ba20fa896638..070f8ef98e822 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts @@ -1,9 +1,10 @@ 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; @@ -17,7 +18,7 @@ describe('CephfsChartComponent', () => { ]; configureTestBed({ - imports: [ChartsModule], + imports: [NgChartsModule], declarations: [CephfsChartComponent] }); @@ -29,6 +30,9 @@ describe('CephfsChartComponent', () => { 'mds_mem.ino': counter, name: 'a' }; + if (typeof window !== 'undefined') { + window.ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill; + } fixture.detectChanges(); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts index 7f3c9437d47d0..7a161f076842b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts @@ -1,8 +1,8 @@ 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'; @@ -24,78 +24,78 @@ export class CephfsChartComponent implements OnChanges, OnInit { 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' } } }, @@ -124,21 +124,20 @@ export class CephfsChartComponent implements OnChanges, OnInit { (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]) }, @@ -147,7 +146,7 @@ export class CephfsChartComponent implements OnChanges, OnInit { } ]; _.merge(this.chart, { - datasets: chartDataSets + datasets: chartDataset }); this.chart.datasets = [...this.chart.datasets]; // Force angular to update } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts index a83e0f16870fc..3dca9993c61e3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs.module.ts @@ -4,7 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 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'; @@ -25,7 +25,7 @@ import { CephfsSubvolumegroupFormComponent } from './cephfs-subvolumegroup-form/ CommonModule, SharedModule, AppRoutingModule, - ChartsModule, + NgChartsModule, TreeModule, NgbNavModule, FormsModule, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts index d6f865471481b..83d00665025fd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.spec.ts @@ -33,6 +33,7 @@ import { } 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; @@ -121,6 +122,9 @@ describe('OsdListComponent', () => { close: jest.fn() }); orchService = TestBed.inject(OrchestratorService); + if (typeof window !== 'undefined') { + window.ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill; + } }); it('should create', () => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html index cb8b9dadb2837..cebfcf9037810 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.html @@ -31,7 +31,7 @@
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts index 70157ab6fa5cf..cbf97691d27dc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-area-chart/dashboard-area-chart.component.ts @@ -4,9 +4,10 @@ import { CssHelper } from '~/app/shared/classes/css-helper'; 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', @@ -41,25 +42,25 @@ export class DashboardAreaChartComponent implements OnChanges { 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(); } } @@ -82,7 +83,10 @@ export class DashboardAreaChartComponent implements OnChanges { 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: '', @@ -91,12 +95,50 @@ export class DashboardAreaChartComponent implements OnChanges { 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, @@ -105,74 +147,29 @@ export class DashboardAreaChartComponent implements OnChanges { 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 } } }; @@ -269,12 +266,12 @@ export class DashboardAreaChartComponent implements OnChanges { 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])); @@ -287,10 +284,8 @@ export class DashboardAreaChartComponent implements OnChanges { [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; } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.html index c013ab5404b4b..25473cb05313e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.html @@ -2,10 +2,9 @@ diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts index 716ca3500ba02..4680fb850a144 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts @@ -2,7 +2,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; 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'; @@ -22,15 +21,15 @@ export class DashboardPieComponent implements OnChanges, OnInit { 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; @@ -80,66 +79,67 @@ export class DashboardPieComponent implements OnChanges, OnInit { } ], 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, data: Record) => { - 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, data: Record) => { + 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 } } }; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts index 50db430906e27..73b4f9fa840fb 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts @@ -4,7 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 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'; @@ -21,7 +21,7 @@ import { PgSummaryPipe } from './pg-summary.pipe'; CommonModule, NgbNavModule, SharedModule, - ChartsModule, + NgChartsModule, RouterModule, NgbPopoverModule, NgbTooltipModule, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard.module.ts index 81164d15b9d90..c779feb3156ff 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard.module.ts @@ -4,7 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 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'; @@ -26,7 +26,7 @@ import { OsdSummaryPipe } from './osd-summary.pipe'; CommonModule, NgbNavModule, SharedModule, - ChartsModule, + NgChartsModule, RouterModule, NgbPopoverModule, FormsModule, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.html index 0a2535fc9142a..a159dddc29e96 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.html @@ -2,10 +2,9 @@ diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts index 3b04714c55bd2..63e15f5776dd4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health-pie/health-pie.component.ts @@ -11,7 +11,6 @@ import { 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'; @@ -42,15 +41,15 @@ export class HealthPieComponent implements OnChanges, OnInit { @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; @@ -88,11 +87,7 @@ export class HealthPieComponent implements OnChanges, OnInit { dataset: [ { label: null, - borderWidth: 0 - } - ], - colors: [ - { + borderWidth: 0, backgroundColor: [ this.cssHelper.propertyValue('chart-color-green'), this.cssHelper.propertyValue('chart-color-yellow'), @@ -103,41 +98,42 @@ export class HealthPieComponent implements OnChanges, OnInit { } ], 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, data: Record) => { - 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, data: Record) => { + 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 } } }; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts index b11d12e496902..8210a4c810371 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts @@ -60,7 +60,7 @@ export class HealthComponent implements OnInit, OnDestroy { ngOnInit() { this.clientStatsConfig = { - colors: [ + dataset: [ { backgroundColor: [ this.cssHelper.propertyValue('chart-color-cyan'), @@ -71,7 +71,7 @@ export class HealthComponent implements OnInit, OnDestroy { }; this.rawCapacityChartConfig = { - colors: [ + dataset: [ { backgroundColor: [ this.cssHelper.propertyValue('chart-color-blue'), @@ -171,7 +171,7 @@ export class HealthComponent implements OnInit, OnDestroy { } 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 ); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index 17f418d1e148f..f4880e655905f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -13,7 +13,7 @@ import { 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'; @@ -61,7 +61,7 @@ import { CardRowComponent } from './card-row/card-row.component'; NgbPopoverModule, NgbProgressbarModule, NgbTooltipModule, - ChartsModule, + NgChartsModule, ReactiveFormsModule, PipesModule, DirectivesModule, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.html index c823605d12a9d..d66efd2d006b1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.html @@ -2,11 +2,9 @@ [ngStyle]="style"> + [type]="'line'">
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.spec.ts index b8e731d6e24f0..27d170190de5e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.spec.ts @@ -5,6 +5,7 @@ import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe'; 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; @@ -19,34 +20,37 @@ describe('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'); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.ts index e2f5af5e0f96d..7b791af0ecfa2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/sparkline/sparkline.component.ts @@ -8,6 +8,7 @@ import { 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'; @@ -21,6 +22,7 @@ export class SparklineComponent implements OnInit, OnChanges { chartCanvasRef: ElementRef; @ViewChild('sparkTooltip', { static: true }) chartTooltipRef: ElementRef; + @ViewChild(BaseChartDirective) chart: BaseChartDirective; @Input() data: any; @@ -32,74 +34,76 @@ export class SparklineComponent implements OnInit, OnChanges { @Input() isBinary: boolean; - public colors: Array = [ - { - 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 = { + 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 = [ { - 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 = []; + 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) => { @@ -114,17 +118,20 @@ export class SparklineComponent implements OnInit, OnChanges { ); 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(); + } } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/chart-tooltip.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/chart-tooltip.ts index 93a259e79d62d..c1312fa3ae6d3 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/chart-tooltip.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/chart-tooltip.ts @@ -37,7 +37,8 @@ export class ChartTooltip { * @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; @@ -102,7 +103,7 @@ export class ChartTooltip { 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) { -- 2.39.5