diff --git a/src/ServicePulse.Host/app/css/particular.css b/src/ServicePulse.Host/app/css/particular.css index 331529894f..cfd97653ea 100644 --- a/src/ServicePulse.Host/app/css/particular.css +++ b/src/ServicePulse.Host/app/css/particular.css @@ -3526,4 +3526,58 @@ g.error .node-text .lead.saga { g.error .node-text a:hover { text-decoration: underline; +} + +:root { + --avg-tooltip-background-color: #000; + } + +div.avg-tooltip { + position: absolute; + text-align: left; + padding: .5rem; + line-height: 1; + background: var(--avg-tooltip-background-color); + color: #ffffff; + border-radius: 8px 1px 1px 8px; + pointer-events: none; + font-size: 11px; + white-space: nowrap; +} + +div.avg-tooltip.left { + border-radius: 1px 8px 8px 1px; +} + +div.avg-tooltip:before { + content: ''; + display: block; + z-index: -1; + right: 0; + position: absolute; + top: 50%; + background-color: var(--avg-tooltip-background-color); + width: 24px; + height: 24px; + margin-top: -12px; + margin-right: -12px; + + transform: rotate(45deg); +} + +div.avg-tooltip.left:before { + right: inherit; + margin-right: inherit; + margin-left: -12px; + left:0; +} + +div.avg-tooltip .value { + font-size: 14px; + font-weight: bold; +} + +div.avg-tooltip .value span { + font-size: 11px; + font-weight: normal; } \ No newline at end of file diff --git a/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.arrowLabel.js b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.arrowLabel.js new file mode 100644 index 0000000000..b377f50ebf --- /dev/null +++ b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.arrowLabel.js @@ -0,0 +1,50 @@ +export default function ArrowLabel({ pointToTheLeft = false, caption = '' }) { + + var div = document.createElement('div'); + div.style.position = 'absolute'; + div.style.zIndex = 10; + div.style.visibility = 'hidden'; + div.classList = `avg-tooltip${pointToTheLeft && ' left' || ''}`; + div.innerHTML = `
+ ${caption} +
+
+ 0 +
`; + document.body.appendChild(div); + + return { + displayAt: function ({ x, y, color}) { + var lableDimensions = getComputedStyle(div); + //align the label vertically. + div.style.top = `${Math.trunc(y - lableDimensions.height.replace('px', '') / 2)}px`; + + //align the label horizontally. + //get the label tip dimensions. The label tip is composed by a roated square of the ::before pseudo-element. + var labelTipWidth = getComputedStyle(div, ':before').width.replace('px', ''); + var labelTipHeight = getComputedStyle(div, ':before').height.replace('px', ''); + var lalbeTipHypotenuse = Math.trunc(Math.hypot(labelTipWidth, labelTipHeight)); + + if (pointToTheLeft == false) { + div.style.left = 'inherit'; + div.style.right = `calc(100% - ${x}px + ${lalbeTipHypotenuse / 2}px)`; + } else { + div.style.right = 'inherit'; + div.style.left = `${x + (lalbeTipHypotenuse / 2)}px`; + } + + div.style.visibility = 'visible'; + div.style.setProperty('--avg-tooltip-background-color', color); //by using properties the color of the 'before' content pseudo element can be updated. + }, + + hide: function () { + div.style.visibility = 'hidden'; + }, + + value: function (value, unit) { + div.querySelector('.value').innerHTML = `${value} ${unit}`; + }, + + pointingToTheLeft: pointToTheLeft + }; +} \ No newline at end of file diff --git a/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.graph.js b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.graph.js index be903726fb..3cd031d72e 100644 --- a/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.graph.js +++ b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.graph.js @@ -1,18 +1,33 @@ -(function(window, angular, d3) { +import ArrowLabel from './ui.particular.arrowLabel'; + +(function(window, angular, d3) { 'use strict'; + const averageDecimalsDefault = 2; + const avgLabelColorDefault = '#2700CB'; + const avgLabelSuffixDefault = ''; + + var averageLabelToTheRight = ArrowLabel({pointToTheLeft: false, caption: 'AVG'}); + + angular.module('ui.particular.graph', []) .directive('graph', - function() { + function(formatter) { return { restrict: 'E', scope: { plotData: '=', formatter: '&', - minimumYaxis: '@' + minimumYaxis: '@', + isDurationGraph: '=isDurationGraph', + avgDecimals: '@' }, template: '', link: function link(scope, element, attrs) { + attrs.avgLabelColor = attrs.avgLabelColor || avgLabelColorDefault; + attrs.metricSuffix = attrs.metricSuffix || avgLabelSuffixDefault; + scope.avgDecimals = scope.avgDecimals || averageDecimalsDefault; + scope.plotData = scope.plotData || { points: [], average: 0 }; scope.$watch('plotData', @@ -92,13 +107,39 @@ .attr('class', 'graph-data-line'); } - chart.append('path') + var averageLine = chart.append('path') .datum(Array(numberOfPoints).fill(average)) .attr('d', line) .attr('class', 'graph-avg-line'); + + var displayAverageLabel = function(averageLine, label, value, color, unit) { + var {x, y, width} = averageLine.node().getBoundingClientRect(); + label.value(value, unit); + + if (label.pointingToTheLeft) { + label.displayAt({x:x + width + window.pageXOffset, y:y + window.pageYOffset, color}); + } else { + label.displayAt({x:x + window.pageXOffset, y:y + window.pageYOffset, color}); + } + } + + chart.on("mouseover", function() { + var value = `${formatter.formatLargeNumber(average,scope.avgDecimals)}`; + var suffix = attrs.metricSuffix; + + if (scope.isDurationGraph) { + value = `${formatter.formatTime(average).value}`; + suffix = formatter.formatTime(average).unit.toUpperCase(); + } + + displayAverageLabel(averageLine, averageLabelToTheRight, value, attrs.avgLabelColor, suffix); + }) + .on("mouseout", function(){ + averageLabelToTheRight.hide(); + }); }); } }; - }); + }); }(window, window.angular, window.d3)); \ No newline at end of file diff --git a/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.largeGraph.js b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.largeGraph.js index 6f08070f2d..6350ced1a5 100644 --- a/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.largeGraph.js +++ b/src/ServicePulse.Host/app/modules/monitoring/js/directives/ui.particular.largeGraph.js @@ -1,6 +1,14 @@ -(function(window, angular, d3) { +import ArrowLabel from './ui.particular.arrowLabel'; + +(function(window, angular, d3) { 'use strict'; + const averageDecimalsDefault = 2; + const avgLabelSuffixDefault = ''; + + var averageLabelToTheRight = ArrowLabel({pointToTheLeft: false, caption: 'AVG'}); + var averageLabelToTheLeft = ArrowLabel({pointToTheLeft: true, caption: 'AVG'}); + function drawDataSeries(chart, data, color, fillColor, scaleX, scaleY) { var area = d3.area() @@ -40,13 +48,15 @@ var group = chart.append('g').attr('class', 'dataAverage'); - group.append('path') + var avgLine = group.append('path') .datum(Array(data.points.length).fill(data.average)) .attr('d', line) .attr('stroke', color) .attr('stroke-width', 1.5) .attr('opacity', 0.5) .attr('stroke-dasharray', '10,10'); + + return avgLine; } function padToWholeValue(value) { @@ -78,10 +88,14 @@ isDurationGraph: '=isDurationGraph', minimumYaxis: '@', width: '=plotWidth', - height: '=plotHeight' + height: '=plotHeight', + avgDecimals: '@' }, template: '', - link: function link(scope, element, attrs) { + link: function link(scope, element, attrs) { + scope.avgDecimals = scope.avgDecimals || averageDecimalsDefault; + attrs.metricSuffix = attrs.metricSuffix || avgLabelSuffixDefault; + scope.$watch('firstDataSeries', function () { var svg = element.find('svg')[0]; @@ -163,7 +177,18 @@ } var drawAverage = function(data, lineColor, fillColor) { - drawAverageLine(chart, data, lineColor, fillColor, scaleX, scaleY); + return drawAverageLine(chart, data, lineColor, fillColor, scaleX, scaleY); + } + + var displayAverageLabel = function(averageLine, label, value, color, unit) { + var {x, y, width} = averageLine.node().getBoundingClientRect(); + label.value(value, unit); + + if (label.pointingToTheLeft) { + label.displayAt({x:x + width + window.pageXOffset, y:y + window.pageYOffset, color}); + } else { + label.displayAt({x:x + window.pageXOffset, y:y + window.pageYOffset, color}); + } } drawSeries(firstSeries, attrs.firstSeriesColor, attrs.firstSeriesFillColor); @@ -172,14 +197,43 @@ drawSeries(secondSeries, attrs.secondSeriesColor,attrs.secondSeriesFillColor); } - drawAverage(firstSeries, attrs.firstSeriesColor, attrs.firstSeriesFillColor ); + var firstAverageLine = drawAverage(firstSeries, attrs.firstSeriesColor, attrs.firstSeriesFillColor ); + + var secondAverageLine = null; if (secondSeries) { - drawAverage(secondSeries, attrs.secondSeriesColor, attrs.secondSeriesFillColor); + secondAverageLine = drawAverage(secondSeries, attrs.secondSeriesColor, attrs.secondSeriesFillColor); } + + chart.on("mouseover", function() { + var value = `${formatter.formatLargeNumber(firstSeries.average, scope.avgDecimals)}`; + var suffix = attrs.metricSuffix; + + if (scope.isDurationGraph) { + value = `${formatter.formatTime(firstSeries.average).value}`; + suffix = formatter.formatTime(firstSeries.average).unit.toUpperCase(); + } + + displayAverageLabel(firstAverageLine, averageLabelToTheRight, value, attrs.firstSeriesColor, suffix); + + if (secondAverageLine && secondSeries.points.length > 0) { + value = `${formatter.formatLargeNumber(secondSeries.average, scope.avgDecimals)}`; + + if (scope.isDurationGraph) { + value = `${formatter.formatTime(secondSeries.average).value}`; + suffix = formatter.formatTime(secondSeries.average).unit.toUpperCase(); + } + + displayAverageLabel(secondAverageLine, averageLabelToTheLeft, value, attrs.secondSeriesColor, suffix); + } + }) + .on("mouseout", function() { + averageLabelToTheRight.hide(); + averageLabelToTheLeft.hide(); + }); }); } }; }); -}(window, window.angular, window.d3)); +}(window, window.angular, window.d3)); \ No newline at end of file diff --git a/src/ServicePulse.Host/app/modules/monitoring/views/endpoint_details.html b/src/ServicePulse.Host/app/modules/monitoring/views/endpoint_details.html index 1485364f17..a0a014b456 100644 --- a/src/ServicePulse.Host/app/modules/monitoring/views/endpoint_details.html +++ b/src/ServicePulse.Host/app/modules/monitoring/views/endpoint_details.html @@ -49,6 +49,8 @@

plot-height="200" first-series-color="#EA7E00" first-series-fill-color="#EADDCE" + avg-decimals="0" + metric-suffix="MSGS" class="large-graph pull-left"> @@ -87,7 +89,8 @@

first-series-color="#176397" first-series-fill-color="#CADCE8" second-series-color="#CC1252" - second-series-fill-color="#E9C4D1" + second-series-fill-color="#E9C4D1" + metric-suffix="MSGS/S" class="large-graph pull-left"> @@ -147,7 +150,7 @@

first-series-color="#2700CB" first-series-fill-color="#C4BCE5" second-series-color="#258135" - second-series-fill-color="#BEE6C5" + second-series-fill-color="#BEE6C5" is-duration-graph="true" class="large-graph pull-left"> @@ -288,7 +291,7 @@

- +
{{(instance.isStale == true || instance.isScMonitoringDisconnected == true) ? "" : instance.metrics.throughput.displayValue}} @@ -299,7 +302,7 @@
- +
{{(instance.isStale == true || instance.isScMonitoringDisconnected == true) ? "" : instance.metrics.retries.displayValue}} @@ -310,7 +313,7 @@
- +
{{(instance.isStale == true || instance.isScMonitoringDisconnected == true) ? "" : instance.metrics.processingTime.displayValue.value}} @@ -324,7 +327,7 @@
- +
{{(instance.isStale == true || instance.isScMonitoringDisconnected == true) ? "" : instance.metrics.criticalTime.displayValue.value}} @@ -428,7 +431,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : messageType.metrics.throughput.displayValue}} @@ -439,7 +442,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : messageType.metrics.retries.displayValue}} @@ -450,7 +453,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : messageType.metrics.processingTime.displayValue.value}} @@ -464,7 +467,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : messageType.metrics.criticalTime.displayValue.value}} diff --git a/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list.html b/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list.html index 77577ee1ea..28d019341e 100644 --- a/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list.html +++ b/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list.html @@ -79,7 +79,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.queueLength.displayValue}} @@ -90,7 +90,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.throughput.displayValue}} @@ -101,7 +101,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.retries.displayValue}} @@ -112,7 +112,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.processingTime.displayValue.value}} @@ -124,7 +124,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.criticalTime.displayValue.value}} diff --git a/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list_grouped.html b/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list_grouped.html index 6a1c19ec7b..fbadfed6ee 100644 --- a/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list_grouped.html +++ b/src/ServicePulse.Host/app/modules/monitoring/views/monitored_endpoints_list_grouped.html @@ -81,7 +81,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.queueLength.displayValue}} @@ -92,7 +92,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.throughput.displayValue}} @@ -103,7 +103,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.retries.displayValue}} @@ -114,7 +114,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.processingTime.displayValue.value}} @@ -126,7 +126,7 @@
- +
{{(endpoint.isStale == true || endpoint.isScMonitoringDisconnected == true) ? "" : endpoint.metrics.criticalTime.displayValue.value}}