Switch to a new chart library (#19262)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2023-09-01 16:46:43 +08:00 committed by GitHub
parent aa5d9eb143
commit e2d088987c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 151 additions and 88 deletions

View File

@ -25,7 +25,7 @@
"@ngx-translate/core": "15.0.0",
"@ngx-translate/http-loader": "8.0.0",
"cron-validator": "^1.3.1",
"highcharts": "^11.1.0",
"echarts": "^5.4.3",
"js-yaml": "^4.1.0",
"ngx-clipboard": "^15.1.0",
"ngx-cookie": "^6.0.1",
@ -8126,6 +8126,20 @@
"safer-buffer": "^2.1.0"
}
},
"node_modules/echarts": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.3.tgz",
"integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.4.4"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -10030,11 +10044,6 @@
"integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==",
"optional": true
},
"node_modules/highcharts": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-11.1.0.tgz",
"integrity": "sha512-vhmqq6/frteWMx0GKYWwEFL25g4OYc7+m+9KQJb/notXbNtIb8KVy+ijOF7XAFqF165cq0pdLIePAmyFY5ph3g=="
},
"node_modules/hosted-git-info": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz",
@ -19341,6 +19350,19 @@
"dependencies": {
"tslib": "^2.3.0"
}
},
"node_modules/zrender": {
"version": "5.4.4",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.4.tgz",
"integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
"dependencies": {
"tslib": "2.3.0"
}
},
"node_modules/zrender/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
}
}

View File

@ -43,7 +43,7 @@
"@ngx-translate/core": "15.0.0",
"@ngx-translate/http-loader": "8.0.0",
"cron-validator": "^1.3.1",
"highcharts": "^11.1.0",
"echarts": "^5.4.3",
"js-yaml": "^4.1.0",
"ngx-clipboard": "^15.1.0",
"ngx-cookie": "^6.0.1",

View File

@ -8,7 +8,7 @@ import {
ViewChild,
} from '@angular/core';
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
import * as Highcharts from 'highcharts';
import * as echarts from 'echarts/core';
@Component({
selector: 'app-single-bar',
@ -30,61 +30,71 @@ export class SingleBarComponent implements OnChanges {
}
initChart() {
(Highcharts as any).chart(this.container.nativeElement, {
credits: {
enabled: false,
},
chart: {
backgroundColor: 'transparent',
type: 'bar',
},
const chart = echarts.init(this.container.nativeElement);
chart.setOption({
color: ['red', '#e64524', 'orange'],
title: {
text: '',
},
tooltip: {
pointFormat: '{series.data.name}{point.y}',
style: {
fontSize: 12,
formatter: '{b}: {c}',
textStyle: {
fontSize: '12px',
whiteSpace: 'nowrap',
},
},
plotOptions: {
pie: {
startAngle: -90,
endAngle: 90,
dataLabels: {
enabled: true,
distance: -8,
style: {
fontSize: '8px',
fontWeight: 1,
},
pointFormat: '{point.y}',
},
size: 50,
borderWidth: 0,
borderRadius: 2,
},
legend: {
show: false,
},
series: [
{
type: 'pie',
radius: '65%',
name: 'Severity',
// adjust the start angle
startAngle: 180,
itemStyle: {
borderRadius: 2,
borderWidth: 1,
},
labelLine: {
show: false,
},
label: {
show: true,
position: 'inside',
formatter: '{c}',
fontSize: '9px',
},
data: [
{
name: 'Critical',
y: this.dangerousArtifact?.critical_cnt || 0,
color: 'red',
value: this.dangerousArtifact?.critical_cnt || 0,
},
{
name: 'High',
y: this.dangerousArtifact?.high_cnt || 0,
color: '#e64524',
value: this.dangerousArtifact?.high_cnt || 0,
},
{
name: 'Medium',
y: this.dangerousArtifact?.medium_cnt || 0,
color: 'orange',
value: this.dangerousArtifact?.medium_cnt || 0,
},
{
// make a record to fill the bottom 50%
value:
this.dangerousArtifact?.critical_cnt +
this.dangerousArtifact?.high_cnt +
this.dangerousArtifact?.medium_cnt || 0,
itemStyle: {
// stop the chart from rendering this piece
color: 'none',
decal: {
symbol: 'none',
},
},
label: {
show: false,
},
},
],
},

View File

@ -96,7 +96,7 @@
</div>
<div class="clr-row" [hidden]="!securitySummary?.total_vuls">
<div class="placeholder">
<div class="pie-chart" id="pie-chart"></div>
<div #pieChart class="pie-chart" id="pie-chart"></div>
</div>
</div>
</div>

View File

@ -1,15 +1,16 @@
import {
Component,
ElementRef,
EventEmitter,
HostListener,
OnDestroy,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { SecurityhubService } from '../../../../../../../ng-swagger-gen/services/securityhub.service';
import { SecuritySummary } from '../../../../../../../ng-swagger-gen/models/security-summary';
import { MessageHandlerService } from '../../../../../shared/services/message-handler.service';
import * as Highcharts from 'highcharts';
import highchartsAccessibility from 'highcharts/modules/accessibility';
import { getDigestLink, severityText, VUL_ID } from '../security-hub.interface';
import { HAS_STYLE_MODE, StyleMode } from '../../../../../services/theme';
import { Subscription } from 'rxjs';
@ -19,7 +20,7 @@ import {
} from '../../../../../services/event-service/event.service';
import { TranslateService } from '@ngx-translate/core';
import { DangerousArtifact } from '../../../../../../../ng-swagger-gen/models/dangerous-artifact';
highchartsAccessibility(Highcharts);
import * as echarts from 'echarts/core';
@Component({
selector: 'app-vulnerability-summary',
@ -36,6 +37,9 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
readonly severityText = severityText;
readonly getDigestLink = getDigestLink;
harborEventSub: Subscription;
chart: any;
@ViewChild('pieChart', { static: true })
pieChartEle: ElementRef;
constructor(
private securityHubService: SecurityhubService,
private messageHandler: MessageHandlerService,
@ -44,6 +48,7 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
) {}
ngOnInit() {
this.chart = echarts.init(this.pieChartEle.nativeElement);
this.getSummary();
if (!this.harborEventSub) {
this.harborEventSub = this.event.subscribe(
@ -91,79 +96,74 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
'UNKNOWN',
];
this.translate.get([severity, c, h, m, l, n, u]).subscribe(res => {
Highcharts.chart('pie-chart', {
credits: {
enabled: false,
},
chart: {
backgroundColor: 'transparent',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
},
this.chart.setOption({
color: ['red', '#e64524', 'orange', '#007CBB', 'grey', 'green'],
title: {
text: '',
},
tooltip: {
pointFormat: '<b>{point.percentage:.1f}%</b>',
},
plotOptions: {
pie: {
dataLabels: {
enabled: false,
},
showInLegend: true,
borderWidth: 0,
},
formatter: '<b>{b}: {d}%</b>',
},
legend: {
align: 'left',
floating: true,
symbolRadius: 2,
itemStyle: {
fontSize: '12px',
fontWeight: '100',
left: 5,
bottom: 5,
formatter: '{a|{name}}',
textStyle: {
color: this.getColorByTheme(),
width: 50,
backgroundColor: 'transparent',
rich: {
a: {
fontWeight: '100',
fontSize: '12px',
verticalAlign: 'bottom',
height: 12,
lineHeight: 15,
},
},
},
width: '60%',
itemWidth: 12,
itemHeight: 12,
width: '50%',
},
series: [
{
innerSize: '60%',
itemStyle: {
borderRadius: 3,
borderWidth: 1,
},
label: {
show: false,
},
radius: ['50%', '80%'],
name: res[severity],
type: 'pie',
center: ['80%', '50%'],
center: ['68%', '50%'],
data: [
{
name: res[c],
y: summary?.critical_cnt || 0,
color: 'red',
value: summary?.critical_cnt || 0,
},
{
name: res[h],
y: summary?.high_cnt || 0,
color: '#e64524',
value: summary?.high_cnt || 0,
},
{
name: res[m],
y: summary?.medium_cnt || 0,
color: 'orange',
value: summary?.medium_cnt || 0,
},
{
name: res[l],
y: summary?.low_cnt || 0,
color: '#007CBB',
value: summary?.low_cnt || 0,
},
{
name: res[u],
y: summary?.unknown_cnt || 0,
color: 'grey',
value: summary?.unknown_cnt || 0,
},
{
name: res[n],
y: summary?.none_cnt || 0,
color: 'green',
value: summary?.none_cnt || 0,
},
],
},
@ -185,4 +185,9 @@ export class VulnerabilitySummaryComponent implements OnInit, OnDestroy {
? '#000'
: '#fff';
}
@HostListener('window:resize', ['$event'])
onResize(event: any) {
this.chart.resize();
}
}

View File

@ -76,9 +76,35 @@ import { HarborDatetimePipe } from './pipes/harbor-datetime.pipe';
import { RemainingTimeComponent } from './components/remaining-time/remaining-time.component';
import { LabelSelectorComponent } from './components/label-selector/label-selector.component';
import { ScrollSectionDirective } from './directives/scroll/scroll-section.directive';
import { ScrollManagerService } from './directives/scroll/scroll-manager.service';
import { ScrollAnchorDirective } from './directives/scroll/scroll-anchor.directive';
import { AppLevelAlertsComponent } from './components/app-level-alerts/app-level-alerts.component';
// import echarts
import * as echarts from 'echarts/core';
import { PieChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
LegendComponent,
} from 'echarts/components';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
// register necessary components
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
PieChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
LegendComponent,
]);
// ClarityIcons is publicly accessible from the browser's window object.
declare const ClarityIcons: ClarityIconsApi;