diff --git a/src/app/graphs/item-detail.ts b/src/app/graphs/item-detail.ts index 583d1d60..3dd3c87e 100644 --- a/src/app/graphs/item-detail.ts +++ b/src/app/graphs/item-detail.ts @@ -204,6 +204,56 @@ export const customChartSettings = () => { }; }; +export const responseTimeDistribution = (data) => { + return { + chart: { + type: "column" + }, + title: { + text: "" + }, + subtitle: { + text: "" + }, + legend:{ enabled:false }, + xAxis: { + crosshair: true, + type: "category", + min: 0, + categories: data.map((value, index) => index * 100) + }, + yAxis: { + min: 0, + title: { + text: "" + } + }, + tooltip: { + shared: true, + useHTML: true, + valueSuffix: "", + valueDecimals: 0, + formatter: function () { + return `${this.y} responses were between ${this.x} and ${this.x + 100} ms`; + } + }, + plotOptions: { + column: { + pointPadding: 0, + borderWidth: 0, + groupPadding: 0, + shadow: false + } + }, + series: [{ + data, + type: "column", + id: "histogram", + name: "Response times" + }] + } +} + export const threadLineSettings: any = { color: "grey", diff --git a/src/app/item-detail/analyze-charts/analyze-charts.component.ts b/src/app/item-detail/analyze-charts/analyze-charts.component.ts index 14822e95..e36ec8cf 100644 --- a/src/app/item-detail/analyze-charts/analyze-charts.component.ts +++ b/src/app/item-detail/analyze-charts/analyze-charts.component.ts @@ -146,8 +146,8 @@ export class AnalyzeChartsComponent implements OnInit { // hide all axis this.customChartsOptions.yAxis.forEach(axis => axis.visible = false) // display only actual axis - chartSeries.forEach(serie => { - this.customChartsOptions.yAxis[serie.yAxis].visible = true + chartSeries.forEach(series => { + this.customChartsOptions.yAxis[series.yAxis].visible = true }) this.customChartsOptions.series = JSON.parse(JSON.stringify(chartSeries)); this.updateLabelChartFlag = true; diff --git a/src/app/item-detail/item-detail.component.html b/src/app/item-detail/item-detail.component.html index fcc92928..59112b67 100644 --- a/src/app/item-detail/item-detail.component.html +++ b/src/app/item-detail/item-detail.component.html @@ -310,7 +310,7 @@
Overall Chart
-
+
Status Codes Chart
diff --git a/src/app/item-detail/item-detail.component.ts b/src/app/item-detail/item-detail.component.ts index 74e9ea15..dbfd1120 100644 --- a/src/app/item-detail/item-detail.component.ts +++ b/src/app/item-detail/item-detail.component.ts @@ -37,6 +37,7 @@ export class ItemDetailComponent implements OnInit, OnDestroy { plot: null, extraPlotData: null, reportStatus: null, + histogramPlotData: null, hostname: null, statistics: [], name: null, @@ -121,11 +122,6 @@ export class ItemDetailComponent implements OnInit, OnDestroy { this.overallChartOptions = { ...overallChartSettings("ms") }; - - - - - } ngOnDestroy() { diff --git a/src/app/item-detail/label-chart/label-chart.component.html b/src/app/item-detail/label-chart/label-chart.component.html index dd788810..37a7c02b 100644 --- a/src/app/item-detail/label-chart/label-chart.component.html +++ b/src/app/item-detail/label-chart/label-chart.component.html @@ -22,7 +22,7 @@
-
diff --git a/src/app/item-detail/label-chart/label-chart.component.ts b/src/app/item-detail/label-chart/label-chart.component.ts index d392517a..e0c129d0 100644 --- a/src/app/item-detail/label-chart/label-chart.component.ts +++ b/src/app/item-detail/label-chart/label-chart.component.ts @@ -1,9 +1,10 @@ -import { Component, Input, OnChanges, SimpleChanges } from "@angular/core"; +import { Component, Input, OnChanges, SimpleChanges, ViewChild } from "@angular/core"; import * as Highcharts from "highcharts"; -import { commonGraphSettings } from "src/app/graphs/item-detail"; +import { commonGraphSettings, responseTimeDistribution } from "src/app/graphs/item-detail"; import * as deepmerge from "deepmerge"; import { ChartLine } from "src/app/_services/item-chart.service"; import { Metrics } from "../metrics"; +import { ResponseTimePerLabelDistribution } from "../../items.service.model"; @Component({ selector: "app-label-chart", @@ -15,17 +16,19 @@ export class LabelChartComponent implements OnChanges { @Input() chartLines: ChartLine; @Input() label: string; @Input() activated: boolean; + @Input() histogramData: ResponseTimePerLabelDistribution[]; + @ViewChild("labelChart") componentRef; + Highcharts: typeof Highcharts = Highcharts; chartMetric = "Response Times"; - labelCompareChartMetric; - labelChartOptions = commonGraphSettings("reqs/s"); + labelChartOptions = commonGraphSettings("ms"); // default empty chart for rendering updateLabelChartFlag = false; chartKeys; chartShouldExpand = false; chart: Highcharts.Chart; chartCallback; labelCharts = new Map(); - expanded = false + expanded = false; private responseTimeMetricGroup: string[]; metricChartMap = new Map([ @@ -54,19 +57,19 @@ export class LabelChartComponent implements OnChanges { // chart expanded if (!changes.activated?.previousValue && changes.activated?.currentValue) { - this.setChartAggregation() + this.setChartAggregation(); this.getChartsKey(); + this.setHistogramChart(); this.changeChart({ target: { innerText: this.chartMetric } }); this.chart.reflow(); - this.expanded = true + this.expanded = true; } // aggregation changed, we need to refresh the data but only for opened charts if (changes.chartLines?.currentValue && this.expanded) { - this.chartLines = changes.chartLines.currentValue - this.setChartAggregation() + this.chartLines = changes.chartLines.currentValue; + this.setChartAggregation(); this.changeChart({ target: { innerText: this.chartMetric } }); } - } private setChartAggregation() { @@ -77,23 +80,40 @@ export class LabelChartComponent implements OnChanges { const labelMetricsData = this.chartLines.labels.get(metric).find(data => data.name === this.label); const chartSettings = this.metricChartMap.get(metric); if (this.responseTimeMetricGroup.includes(metric)) { - responseTimesSeries.push({ data: labelMetricsData.data, suffix: labelMetricsData.suffix, name: metric, yAxis: 0 }); + responseTimesSeries.push({ data: labelMetricsData.data, suffix: labelMetricsData.suffix, name: metric, yAxis: 0, id: metric }); } else { - this.labelCharts.set(metric, { ...chartSettings, series: [{ data: labelMetricsData.data, suffix: labelMetricsData.suffix, name: metric }, threadLine] }); + this.labelCharts.set(metric, { + ...chartSettings, + series: [{ data: labelMetricsData.data, suffix: labelMetricsData.suffix, name: metric, id: metric }, threadLine] + }); } }); this.labelCharts.set("Response Times", { ...commonGraphSettings("ms"), series: [...responseTimesSeries, threadLine] }); } + private setHistogramChart() { + if (this.histogramData) { + this.chartKeys.push("Histogram"); + const histogram = this.histogramData.find(data => data.label === this.label); + this.labelCharts.set("Histogram", responseTimeDistribution(histogram.values)); + } + } + private getChartsKey() { this.chartKeys = Array.from(this.labelCharts.keys()); + } changeChart(event) { this.chartMetric = event.target.innerText; + if(this.chart) { + this.chart.destroy(); + this.componentRef.chart = null; + } this.labelChartOptions = deepmerge(this.labelCharts.get(this.chartMetric), {}); + console.log(this.labelChartOptions) this.updateLabelChartFlag = true; } diff --git a/src/app/item-detail/request-stats/request-stats-compare.component.html b/src/app/item-detail/request-stats/request-stats-compare.component.html index fd14e777..65e291d8 100644 --- a/src/app/item-detail/request-stats/request-stats-compare.component.html +++ b/src/app/item-detail/request-stats/request-stats-compare.component.html @@ -157,7 +157,7 @@
Request Statistics - + diff --git a/src/app/items.service.model.ts b/src/app/items.service.model.ts index a1c58612..5ad8222a 100644 --- a/src/app/items.service.model.ts +++ b/src/app/items.service.model.ts @@ -39,6 +39,9 @@ export interface ItemDetail { environment: string; plot: ItemDataPlot; extraPlotData: ItemExtraPlot[]; + histogramPlotData?: { + responseTimePerLabelDistribution?: ResponseTimePerLabelDistribution[] + } statistics: ItemStatistics[]; thresholds?: { passed: boolean, @@ -286,3 +289,8 @@ export interface UpsertItemChartSettings { data: [number, number]; }]; } + +export interface ResponseTimePerLabelDistribution { + label: string + values: number[] +}