Skip to content

Commit 0c6787c

Browse files
authored
Merge branch 'develop' into feature/peformanceLogsIndentationDepth
2 parents 8ebc5c5 + b220f90 commit 0c6787c

24 files changed

+938
-158
lines changed

frontend/src/app/modules/aggregation/services/aggregation-chart-data.service.ts

Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {SpinnerService} from '../../shared/services/spinner.service';
1111
import {ActivatedRoute, Params, Router} from '@angular/router';
1212
import {ResultSelectionStore} from '../../result-selection/services/result-selection.store';
1313
import {TranslateService} from '@ngx-translate/core';
14+
import {MeasurandColorService} from '../../shared/services/measurand-color.service';
1415

1516
@Injectable({
1617
providedIn: 'root'
@@ -30,37 +31,6 @@ export class AggregationChartDataService {
3031
uniqueSideLabels: string[] = [];
3132
hasComparativeData = false;
3233

33-
loadingTimeColors: Array<string> = [
34-
'#1660A7',
35-
'#558BBF',
36-
'#95b6d7',
37-
'#d4e2ef'
38-
];
39-
countOfRequestColors: Array<string> = [
40-
'#E41A1C',
41-
'#eb5859',
42-
'#f29697',
43-
'#fad5d5'
44-
];
45-
sizeOfRequestColors: Array<string> = [
46-
'#F18F01',
47-
'#f4ad46',
48-
'#f8cc8b',
49-
'#fcead0'
50-
];
51-
csiColors: Array<string> = [
52-
'#59B87A',
53-
'#86cb9e',
54-
'#b3dec2',
55-
'#e0f2e6'
56-
];
57-
58-
trafficColors = [
59-
'#5cb85c',
60-
'#f0ad4e',
61-
'#d9534f'
62-
];
63-
6434
measurandOrder: string[] = [
6535
'CS_BY_WPT_VISUALLY_COMPLETE',
6636
'CS_BY_WPT_DOC_COMPLETE',
@@ -84,18 +54,6 @@ export class AggregationChartDataService {
8454
'DOC_COMPLETE_REQUESTS'
8555
];
8656

87-
speedIndexColors: Array<string> = this.loadingTimeColors;
88-
89-
measurandGroupColorCombination = {
90-
'ms': this.loadingTimeColors,
91-
's': this.loadingTimeColors,
92-
'#': this.countOfRequestColors,
93-
'KB': this.sizeOfRequestColors,
94-
'MB': this.sizeOfRequestColors,
95-
'%': this.csiColors,
96-
'': this.speedIndexColors
97-
};
98-
9957
barchartAverageData$: BehaviorSubject<any> = new BehaviorSubject<any>([]);
10058
barchartMedianData$: BehaviorSubject<any> = new BehaviorSubject<any>([]);
10159
ascSelected = true;
@@ -106,7 +64,8 @@ export class AggregationChartDataService {
10664
private router: Router,
10765
private resultSelectionStore: ResultSelectionStore,
10866
private spinnerService: SpinnerService,
109-
private translateService: TranslateService
67+
private translateService: TranslateService,
68+
private measurandColorService: MeasurandColorService
11069
) {
11170
route.queryParams.subscribe((params: Params) => {
11271
this.selectedFilter = params.selectedFilter ? params.selectedFilter : this.selectedFilter;
@@ -150,10 +109,9 @@ export class AggregationChartDataService {
150109
});
151110
}
152111

153-
reloadPercentile(
154-
percentile: number,
155-
resultSelectionCommand: ResultSelectionCommand,
156-
remainingResultSelection: RemainingResultSelection
112+
reloadPercentile(percentile: number,
113+
resultSelectionCommand: ResultSelectionCommand,
114+
remainingResultSelection: RemainingResultSelection
157115
): void {
158116
this.percentileValue = percentile;
159117
this.barchartDataService.fetchBarchartData<any>(
@@ -231,12 +189,12 @@ export class AggregationChartDataService {
231189
measurandData.isDeterioration = firstSeries.isDeterioration;
232190

233191
if (measurandData.isImprovement || measurandData.isDeterioration) {
234-
const color = this.getColorScaleForTrafficLight()(measurandData.isImprovement ? 'good' : 'bad');
192+
const color = this.measurandColorService.getColorScaleForTrafficLight()(measurandData.isImprovement ? 'good' : 'bad');
235193
measurandData.color = color.toString();
236194
} else {
237195
const unit = measurandData.unit;
238196
const colorScales = {};
239-
colorScales[unit] = colorScales[unit] || this.getColorScaleForMeasurandGroup(unit, this.hasComparativeData);
197+
colorScales[unit] = colorScales[unit] || this.measurandColorService.getColorScaleForMeasurandGroup(unit, this.hasComparativeData);
240198
measurandData.color = colorScales[unit](measurands.indexOf(measurand));
241199
}
242200
});
@@ -354,27 +312,6 @@ export class AggregationChartDataService {
354312
});
355313
}
356314

357-
getColorScaleForMeasurandGroup(measurandUnit: string, skipFirst: boolean) {
358-
const colors = this.measurandGroupColorCombination[measurandUnit].slice(skipFirst ? 1 : 0);
359-
return scaleOrdinal()
360-
.domain(this.createDomain(colors.length))
361-
.range(colors);
362-
}
363-
364-
getColorScaleForTrafficLight() {
365-
return scaleOrdinal()
366-
.domain(['good', 'ok', 'bad'] as ReadonlyArray<string>)
367-
.range(this.trafficColors);
368-
}
369-
370-
createDomain(arrayLength: number): ReadonlyArray<string> {
371-
const array = [];
372-
for (let i = 0; i < arrayLength; i++) {
373-
array.push(i);
374-
}
375-
return array as ReadonlyArray<string>;
376-
}
377-
378315
public setComparativeData(series: AggregationChartSeries[]) {
379316
const comparativeData: AggregationChartSeries[] = [];
380317
series.forEach(datum => {

frontend/src/app/modules/aggregation/services/barchart-data.service.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@ export class BarchartDataService {
3333
});
3434
}
3535

36-
fetchBarchartData<T>(
37-
resultSelectionCommand: ResultSelectionCommand,
38-
remainingResultSelection: RemainingResultSelection,
39-
aggregationValue: (string | number),
40-
url: string
36+
fetchBarchartData<T>(resultSelectionCommand: ResultSelectionCommand,
37+
remainingResultSelection: RemainingResultSelection,
38+
aggregationValue: (string | number),
39+
url: string
4140
): Observable<T> {
4241
const getBarchartCommand = BarchartDataService.buildGetBarchartCommand(
4342
resultSelectionCommand,
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
export default class ChartLabelUtil {
2+
static groupingDelimiter = ' | ';
3+
static delimiter = ', ';
4+
5+
static processWith(series): ChartLabelProcessing {
6+
return new ChartLabelProcessing(series);
7+
}
8+
}
9+
10+
class ChartLabelProcessing {
11+
seriesData = null;
12+
uniquePages = [];
13+
uniqueJobGroups = [];
14+
uniqueMeasurands = [];
15+
uniqueBrowsers = [];
16+
17+
constructor(series) {
18+
this.seriesData = series;
19+
this.deduceUniqueEntries();
20+
}
21+
22+
deduceUniqueEntries(): void {
23+
this.seriesData.forEach(series => {
24+
if (series.grouping && !series.page && !series.jobGroup && !series.browser) {
25+
const splittedIdentifier = series.grouping.split(ChartLabelUtil.groupingDelimiter);
26+
series.page = splittedIdentifier[0];
27+
series.jobGroup = splittedIdentifier[1];
28+
series.browser = splittedIdentifier[2];
29+
}
30+
31+
if (series.page && this.uniquePages.indexOf(series.page) === -1) {
32+
this.uniquePages.push(series.page);
33+
}
34+
if (series.jobGroup && this.uniqueJobGroups.indexOf(series.jobGroup) === -1) {
35+
this.uniqueJobGroups.push(series.jobGroup);
36+
}
37+
if (series.measurand && this.uniqueMeasurands.indexOf(series.measurand) === -1) {
38+
this.uniqueMeasurands.push(series.measurand);
39+
}
40+
if (series.browser && this.uniqueBrowsers.indexOf(series.browser) === -1) {
41+
this.uniqueBrowsers.push(series.browser);
42+
}
43+
});
44+
}
45+
46+
setLabelInSeriesData(omitMeasurands): void {
47+
this.seriesData.forEach(series => {
48+
const labelParts = [];
49+
if (this.uniquePages.length > 1) {
50+
labelParts.push(series.page);
51+
}
52+
if (this.uniqueJobGroups.length > 1) {
53+
labelParts.push(series.jobGroup);
54+
}
55+
if (!omitMeasurands && this.uniqueMeasurands.length > 1) {
56+
labelParts.push(series.measurand);
57+
}
58+
if (this.uniqueBrowsers.length > 1) {
59+
labelParts.push(series.browser);
60+
}
61+
series.label = labelParts.join(ChartLabelUtil.delimiter);
62+
});
63+
}
64+
65+
getCommonLabelParts(omitMeasurands = null): string {
66+
const commonPartsHeader = [];
67+
if (this.uniqueJobGroups.length === 1) {
68+
commonPartsHeader.push(this.uniqueJobGroups[0]);
69+
}
70+
if (this.uniquePages.length === 1) {
71+
commonPartsHeader.push(this.uniquePages[0]);
72+
}
73+
if (this.uniqueMeasurands.length === 1 && !omitMeasurands) {
74+
commonPartsHeader.push(this.uniqueMeasurands[0]);
75+
}
76+
return commonPartsHeader.join(ChartLabelUtil.delimiter);
77+
}
78+
79+
getSeriesWithShortestUniqueLabels(): void {
80+
this.setLabelInSeriesData(this.seriesData);
81+
}
82+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<div class="card">
2+
<div class="violin-chart-component">
3+
<osm-spinner [spinnerId]="'violin-chart-spinner'"></osm-spinner>
4+
5+
<div class="settings-row">
6+
<input (ngModelChange)="drawChart()" [(ngModel)]="dataTrimValue"
7+
[max]="maxValueForInputField"
8+
[step]="stepForInputField" class="form-control settings-element max-value-input-field"
9+
min="0" placeholder="{{'frontend.de.iteratec.osm.distribution.chart.settings.maximum' | translate}}"
10+
type="number">
11+
12+
<button aria-expanded="false" aria-haspopup="true"
13+
class="btn btn-default btn-sm dropdown-toggle settings-element filter-button"
14+
data-toggle="dropdown"
15+
id="filter-dropdown"
16+
type="button">{{'frontend.de.iteratec.osm.distribution.chart.settings.filter' | translate }} <span
17+
class="caret"></span>
18+
</button>
19+
<ul class="dropdown-menu pull-right">
20+
<li class="dropdown-header" id="all-bars-header">
21+
{{'frontend.de.iteratec.osm.distribution.chart.settings.sort' | translate }}
22+
</li>
23+
<li>
24+
<a (click)="setSortingRule('desc')" class="chart-filter"><i
25+
[ngClass]="selectedSortingRule === 'desc' ? 'fas fa-check' : 'fas fa-check filter-inactive'"></i>
26+
{{'frontend.de.iteratec.osm.distribution.chart.settings.sort.desc' | translate }}
27+
</a>
28+
</li>
29+
<li>
30+
<a (click)="setSortingRule('asc')" class="chart-filter"><i
31+
[ngClass]="selectedSortingRule === 'asc' ? 'fas fa-check' : 'fas fa-check filter-inactive'"></i>
32+
{{'frontend.de.iteratec.osm.distribution.chart.settings.sort.asc' | translate }}
33+
</a>
34+
</li>
35+
<ng-container *ngIf="hasFilterRules()">
36+
<li class="dropdown-header" id="customer-journey-header">
37+
{{'frontend.de.iteratec.osm.barchart.filter.customerJourneyHeader' | translate}}
38+
</li>
39+
<li *ngFor="let filterRule of filterRules | keyvalue">
40+
<a (click)="setFilterRule(filterRule.key)" class="chart-filter">
41+
<i
42+
[ngClass]="filterRule.key === selectedFilterRule ? 'fas fa-check' : 'fas fa-check filter-inactive'"></i>
43+
{{filterRule.key}}
44+
</a>
45+
</li>
46+
</ng-container>
47+
</ul>
48+
</div>
49+
50+
<div class="svg-container" id="svg-container"></div>
51+
</div>
52+
</div>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
.violin-chart-component {
2+
position: relative;
3+
min-height: 100px;
4+
}
5+
6+
.svg-container {
7+
width: auto;
8+
text-align: center;
9+
}
10+
11+
@media screen and (max-width: 1650px) {
12+
.settings-row {
13+
display: flex;
14+
justify-content: flex-end;
15+
align-items: center;
16+
z-index: 2;
17+
padding: 6px 12px;
18+
}
19+
}
20+
21+
@media screen and (min-width: 1651px) {
22+
.settings-row {
23+
display: flex;
24+
align-items: center;
25+
position: absolute;
26+
top: 4px;
27+
right: 0;
28+
z-index: 2;
29+
padding: 6px 12px;
30+
}
31+
}
32+
33+
.settings-row {
34+
.settings-element {
35+
margin-right: .5em;
36+
}
37+
38+
.max-value-input-field {
39+
width: 10em;
40+
}
41+
42+
.filter-button {
43+
height: 34px;
44+
}
45+
46+
ul > li > a {
47+
cursor: pointer;
48+
}
49+
50+
.filter-inactive {
51+
visibility: hidden;
52+
}
53+
}
54+
55+
.x-axis-label {
56+
font-size: 12px;
57+
text-rendering: geometricPrecision;
58+
}
59+
60+
.y-axis-left-label {
61+
fill: #606060;
62+
font-size: 14px;
63+
}
64+
65+
.d3chart-y-axis-line {
66+
shape-rendering: crispEdges;
67+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2+
3+
import {ViolinChartComponent} from './violin-chart.component';
4+
import {SharedModule} from '../../../shared/shared.module';
5+
import {SharedMocksModule} from '../../../../testing/shared-mocks.module';
6+
7+
describe('ViolinChartComponent', () => {
8+
let component: ViolinChartComponent;
9+
let fixture: ComponentFixture<ViolinChartComponent>;
10+
11+
beforeEach(async(() => {
12+
TestBed.configureTestingModule({
13+
declarations: [ViolinChartComponent],
14+
imports: [SharedModule, SharedMocksModule]
15+
})
16+
.compileComponents();
17+
}));
18+
19+
beforeEach(() => {
20+
fixture = TestBed.createComponent(ViolinChartComponent);
21+
component = fixture.componentInstance;
22+
fixture.detectChanges();
23+
});
24+
25+
it('should create', () => {
26+
expect(component).toBeTruthy();
27+
});
28+
});

0 commit comments

Comments
 (0)