Skip to content

Commit 632efc4

Browse files
authored
Merge branch 'develop' into feature/legendLabelsInTimeSeriesChart
2 parents 4f28141 + 8a23f68 commit 632efc4

File tree

7 files changed

+85
-36
lines changed

7 files changed

+85
-36
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ buildscript {
3636
}
3737
}
3838

39-
version "5.3.2"
39+
version "5.3.3"
4040
group "OpenSpeedMonitor"
4141

4242
apply plugin: "eclipse"

frontend/src/app/enums/chart-commons.enum.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ export enum ChartCommons {
66
CHART_HEADER_HEIGHT = 40,
77
COLOR_PREVIEW_SIZE = 10,
88
COLOR_PREVIEW_MARGIN = 5,
9-
LABEL_HEIGHT = 30
9+
LABEL_HEIGHT = 18
1010
}

frontend/src/app/modules/time-series/components/time-series-line-chart/time-series-line-chart.component.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ osm-time-series-line-chart {
6767
.summary-label {
6868
font-weight: normal;
6969
}
70+
71+
.legend-entry {
72+
cursor: pointer;
73+
}
74+
75+
.legend-text {
76+
font-size: 12px;
77+
}

frontend/src/app/modules/time-series/services/line-chart.service.ts

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838

3939
import 'd3-transition';
4040

41-
import {brushX as d3BrushX} from 'd3-brush';
41+
import {BrushBehavior, brushX as d3BrushX} from 'd3-brush';
4242
import {EventResultDataDTO} from 'src/app/modules/time-series/models/event-result-data.model';
4343
import {EventResultSeriesDTO} from 'src/app/modules/time-series/models/event-result-series.model';
4444
import {EventResultPointDTO} from 'src/app/modules/time-series/models/event-result-point.model';
@@ -63,13 +63,17 @@ export class LineChartService {
6363
// D3 margin conventions
6464
// > With this convention, all subsequent code can ignore margins.
6565
// see: https://bl.ocks.org/mbostock/3019563
66-
private _margin = {top: 40, right: 70, bottom: 40, left: 60};
67-
private _width = 600 - this._margin.left - this._margin.right;
68-
private _height = 550 - this._margin.top - this._margin.bottom;
69-
private _labelGroupHeight;
70-
private _legendGroupTop = this._margin.top + this._height + 50;
71-
private legendDataMap = {};
72-
private brush;
66+
private _margin: any = {top: 40, right: 70, bottom: 40, left: 60};
67+
private _width: number = 600 - this._margin.left - this._margin.right;
68+
private _height: number = 550 - this._margin.top - this._margin.bottom;
69+
private _labelGroupHeight: number;
70+
private _legendGroupTop: number = this._margin.top + this._height + 50;
71+
private _legendGroupHeight: number;
72+
private _legendGroupColumnWidth: number;
73+
private _legendGroupColumns: number;
74+
private legendDataMap: Object = {};
75+
private brush: BrushBehavior<{}>;
76+
private focusedLegendEntry: string;
7377

7478
// Map that holds all points clustered by their x-axis values
7579
private _xAxisCluster: any = {};
@@ -78,7 +82,6 @@ export class LineChartService {
7882
private _mouseEventCatcher: D3Selection<D3BaseType, {}, D3ContainerElement, {}>;
7983
private _markerTooltip: D3Selection<HTMLDivElement, {}, D3ContainerElement, {}>;
8084

81-
8285
constructor(private translationService: TranslateService) {
8386
}
8487

@@ -98,19 +101,17 @@ export class LineChartService {
98101
* Draws a line chart for the given data into the given svg
99102
*/
100103
public drawLineChart(incomingData: EventResultDataDTO): void {
101-
102-
let data: TimeSeries[] = this.prepareData(incomingData);
103-
104-
if (data.length == 0) {
104+
if (incomingData.series.length == 0) {
105105
return;
106106
}
107107

108+
let data: TimeSeries[] = this.prepareData(incomingData);
108109
let chart: D3Selection<D3BaseType, {}, D3ContainerElement, {}> = d3Select('g#time-series-chart-drawing-area');
109110
let xScale: D3ScaleTime<number, number> = this.getXScale(data);
110111
let yScale: D3ScaleLinear<number, number> = this.getYScale(data);
111-
this._labelGroupHeight = data.length * ChartCommons.LABEL_HEIGHT;
112+
this.calculateLegendDimensions();
112113
d3Select('osm-time-series-line-chart').transition().duration(500).style('visibility', 'visible');
113-
d3Select('svg#time-series-chart').transition().duration(500).attr('height', this._height + this._labelGroupHeight + this._margin.top + this._margin.bottom);
114+
d3Select('svg#time-series-chart').transition().duration(500).attr('height', this._height + this._legendGroupHeight + this._margin.top + this._margin.bottom);
114115
d3Select('.x-axis').transition().call(this.updateXAxis, xScale);
115116
d3Select('.y-axis').transition().call(this.updateYAxis, yScale, this._width, this._margin);
116117
this.brush = d3BrushX().extent([[0, 0], [this._width, this._height]]);
@@ -135,6 +136,10 @@ export class LineChartService {
135136
* Set the data for the legend after the incoming data is received
136137
*/
137138
public setLegendData(incomingData: EventResultDataDTO) {
139+
if (incomingData.series.length == 0) {
140+
return;
141+
}
142+
138143
let labelDataMap = {};
139144
incomingData.series.forEach((data: EventResultSeriesDTO) => {
140145
if (incomingData.summaryLabels.length > 0 && incomingData.summaryLabels[0].key != "measurand") {
@@ -209,6 +214,7 @@ export class LineChartService {
209214
.attr('transform', `translate(${this._margin.left}, ${this._margin.top})`); // translates the origin to the top left corner (default behavior of D3)
210215

211216
svg.append('g')
217+
.attr('id', 'time-series-chart-legend')
212218
.attr('class', 'legend-group')
213219
.attr('transform', `translate(${this._margin.left}, ${this._legendGroupTop})`);
214220

@@ -314,6 +320,34 @@ export class LineChartService {
314320
.nice();
315321
}
316322

323+
private calculateLegendDimensions(): void {
324+
let maximumLabelWidth: number = 1;
325+
let labels = Object.keys(this.legendDataMap);
326+
327+
d3Select('g#time-series-chart-legend')
328+
.append('g')
329+
.attr('id', 'renderToCalculateMaxWidth')
330+
.selectAll('.renderToCalculateMaxWidth')
331+
.data(labels)
332+
.enter()
333+
.append('text')
334+
.attr('class', 'legend-text')
335+
.text(datum => this.legendDataMap[datum].text)
336+
.each((datum, index, groups) => {
337+
Array.from(groups).forEach((text) => {
338+
if (text) {
339+
maximumLabelWidth = Math.max(maximumLabelWidth, text.getBoundingClientRect().width)
340+
}
341+
});
342+
});
343+
344+
d3Select('g#renderToCalculateMaxWidth').remove();
345+
346+
this._legendGroupColumnWidth = maximumLabelWidth + ChartCommons.COLOR_PREVIEW_SIZE + 30;
347+
this._legendGroupColumns = Math.floor(this._width / this._legendGroupColumnWidth);
348+
this._legendGroupHeight = Math.ceil(labels.length / this._legendGroupColumns) * ChartCommons.LABEL_HEIGHT + 30;
349+
}
350+
317351
private getMaxValue(data: TimeSeries[]): number {
318352
return d3Max(data, (dataItem: TimeSeries) => {
319353
return d3Max(dataItem.values, (point: TimeSeriesPoint) => {
@@ -825,29 +859,36 @@ export class LineChartService {
825859
.style('opacity', 0)
826860
.remove()
827861
)
828-
.attr("transform", (datum, index) => this.position(index))
862+
.attr("transform", (datum, index) => this.getPosition(index))
829863
.on('click', (datum) => this.onMouseClick(datum, incomingData));
830864
}
831865

832-
private position(index: number): string {
833-
const columns = 3;
834-
const columnWidth = 550;
835-
const xMargin = 10;
836-
const yMargin = 10;
837-
838-
const x = index % columns * columnWidth + xMargin;
839-
const y = Math.floor(index / columns) * ChartCommons.LABEL_HEIGHT + yMargin;
866+
private getPosition(index: number): string {
867+
const x = index % this._legendGroupColumns * this._legendGroupColumnWidth;
868+
const y = Math.floor(index / this._legendGroupColumns) * ChartCommons.LABEL_HEIGHT + 12;
840869

841870
return "translate(" + x + "," + y + ")";
842871
}
843872

844873
private onMouseClick(labelKey: string, incomingData: EventResultDataDTO): void {
845-
if (d3Event.metaKey) {
846-
this.legendDataMap[labelKey].show ? this.legendDataMap[labelKey].show = false : this.legendDataMap[labelKey].show = true;
874+
if (d3Event.metaKey || d3Event.ctrlKey) {
875+
this.legendDataMap[labelKey].show = !this.legendDataMap[labelKey].show;
847876
} else {
848-
Object.keys(this.legendDataMap).forEach((legend) => {
849-
this.legendDataMap[legend].show = legend === labelKey;
850-
});
877+
if (labelKey == this.focusedLegendEntry) {
878+
Object.keys(this.legendDataMap).forEach((legend) => {
879+
this.legendDataMap[legend].show = true;
880+
});
881+
this.focusedLegendEntry = "";
882+
} else {
883+
Object.keys(this.legendDataMap).forEach((legend) => {
884+
if (legend === labelKey) {
885+
this.legendDataMap[legend].show = true;
886+
this.focusedLegendEntry = legend;
887+
} else {
888+
this.legendDataMap[legend].show = false;
889+
}
890+
});
891+
}
851892
}
852893
this.drawLineChart(incomingData);
853894
}

grails-app/controllers/de/iteratec/osm/csi/CsiBenchmarkController.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class CsiBenchmarkController extends ExceptionHandlerController {
5353
}
5454

5555
String selectedCsiType = params.csiType == "visuallyComplete" ? 'csByWptVisuallyCompleteInPercent' : 'csByWptDocCompleteInPercent'
56-
List<JobGroup> allJobGroups = JobGroup.findAllByNameInList(cmd.jobGroups)
56+
List<JobGroup> allJobGroups = JobGroup.findAllByIdInList(cmd.jobGroups)
5757

5858
CsiAggregationInterval interval = CsiAggregationInterval.findByIntervalInMinutes(CsiAggregationInterval.DAILY)
5959

grails-app/controllers/de/iteratec/osm/result/PageComparisonController.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ class PageComparisonController extends ExceptionHandlerController {
6464
BarchartDatum comparativeSeries = mapToSeriesFor(aggregation.comperativeAggregation)
6565
return new BarchartSeries(
6666
stacked: false,
67-
dimensionalUnit: aggregation.baseAggregation.selectedMeasurand.getMeasurandGroup().unit.label,
67+
dimensionalUnit: aggregation.baseAggregation.unit,
6868
data: [baseSeries, comparativeSeries]
6969
)
7070
}
7171

7272
private BarchartDatum mapToSeriesFor(BarchartAggregation aggregation) {
7373
return new BarchartDatum(
74-
measurand: i18nService.msg("de.iteratec.isr.measurand.${aggregation.selectedMeasurand.name}", aggregation.selectedMeasurand.name),
74+
measurand: i18nService.msg("de.iteratec.isr.measurand.${aggregation.measurandName}", aggregation.measurandName),
7575
value: aggregation.value,
7676
aggregationValue: aggregation.aggregationValue,
7777
grouping: "${aggregation.jobGroup.name} | ${aggregation.page.name}")

grails-app/views/csiBenchmark/show.gsp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@
106106
data: {
107107
from: selectedTimeFrame[0].toISOString(),
108108
to: selectedTimeFrame[1].toISOString(),
109-
selectedJobGroups: JSON.stringify($.map($("#folderSelectHtmlId option:selected"), function (e) {
110-
return $(e).text()
109+
jobGroups: JSON.stringify($.map($("#folderSelectHtmlId option:selected"), function (e) {
110+
return parseInt(e.value);
111111
})),
112112
csiType: $('input[name=csiTypeRadios]:checked').val()
113113
},

0 commit comments

Comments
 (0)