diff --git a/modules/cloud_service_providers/k8s/js/k8s_node_allocated_resources.js b/modules/cloud_service_providers/k8s/js/k8s_node_allocated_resources.js
index 8ae3d3f..130677a 100644
--- a/modules/cloud_service_providers/k8s/js/k8s_node_allocated_resources.js
+++ b/modules/cloud_service_providers/k8s/js/k8s_node_allocated_resources.js
@@ -3,18 +3,21 @@
'use strict';
if (!drupalSettings.k8s || !drupalSettings.k8s.metrics_enable) {
- $("#k8s_node_allocated_resources").parent().parent().hide();
+ $('#k8s_node_allocated_resources').parent().parent().hide();
return;
}
const FONT_FAMILY = 'Lucida Grande, -apple-system, BlinkMacSystemFont',
FONT_SIZE_RSC_ALLOCATION_RATIO = 19,
FONT_SIZE_RSC_USAGE = 15,
+ FONT_SIZE_TITLE = 19,
WIDTH = 250,
HEIGHT = 250,
+ TITLE_HEIGHT = 20,
RING_WIDTH = 50,
RADIUS = Math.min(WIDTH, HEIGHT) / 2,
- FOREGROUND_RING_WIDTH = 30;
+ FOREGROUND_RING_WIDTH = 30,
+ RECT_PX = 85;
// Create a dummy ... to measure the length (pixel) of a string.
$('', {id: 'rsc_allocation_ratio_width_check', appendTo: 'body'})
@@ -29,6 +32,12 @@
.css('position', 'absolute')
.css('white-space', 'nowrap');
+ $('', {id: 'title_width_check', appendTo: 'body'})
+ .css('font-size', FONT_SIZE_TITLE)
+ .css('visibility', 'hidden')
+ .css('position', 'absolute')
+ .css('white-space', 'nowrap');
+
let pie = d3.pie()
.sort(null).value(function (d) {
return d.value;
@@ -44,16 +53,102 @@
function createSvg(data) {
return d3.select(data.selector)
- .attr("align","center")
+ .attr('align', 'center')
.append('svg')
.attr('class', data.class)
.attr('width', WIDTH)
- .attr('height', HEIGHT)
+ .attr('height', HEIGHT + TITLE_HEIGHT)
.style('display', 'inline');
}
- function render(data) {
+ // Create a tooltip.
+ let tooltip = d3.select('body')
+ .append('div')
+ .style('opacity', 1)
+ .attr('class', 'tooltip')
+ .style('background-color', 'white')
+ .style('border', 'solid')
+ .style('border-width', '2px')
+ .style('border-radius', '5px')
+ .style('padding', '5px')
+ .style('display', 'none');
+
+ // Three function that change the tooltip when user hover / move / leave a cell.
+ let mouseover = function (pie) {
+ tooltip.style('display', 'block');
+
+ d3.select(this)
+ .style('stroke', pie.data.color)
+ .style('stroke-width', 5)
+ .style('opacity', 1);
+ };
+
+ let mousemove = function (pie) {
+ tooltip.html('' + pie.value + ' ' + pie.data.suffix + '')
+ .style('left', (d3.event.pageX + 10) + 'px')
+ .style('top', (d3.event.pageY - 120) + 'px');
+ };
+ let mouseleave = function (pie) {
+ tooltip.style('display', 'none');
+ d3.select(this)
+ .style('stroke', 'none')
+ .style('opacity', 0.8);
+ };
+
+ let drawLegend = function() {
+ let width = 600;
+ let height = 50;
+ let padding = 20;
+ let xpadding = 90;
+ let number = 20;
+ let svg = d3.select('#k8s_node_allocated_resources')
+ .append('svg')
+ .attr('width', width)
+ .attr('height', height)
+ .attr('viewBox', 0 + ' ' + 0 + ' ' + width + ' ' + height);
+
+ svg.append('text')
+ .attr('x', 10)
+ .attr('y', 25)
+ .style('font-family', FONT_FAMILY)
+ .style('font-size', 16)
+ .style('font-weight', 900)
+ .text('Legend');
+
+ let color = d3.interpolateSpectral;
+ let defs = svg.append('defs')
+ .append('linearGradient')
+ .attr('id', 'legendGradient');
+
+ for (let i = 0; i <= number; i++) {
+ defs.append('stop')
+ .attr('offset', (i * 100 / number) + '%')
+ .attr('stop-color', color((number - i) / number));
+ }
+
+ svg.append('rect')
+ .attr('x', xpadding)
+ .attr('y', 0)
+ .attr('width', width - 2 * xpadding)
+ .attr('height', height - padding)
+ .attr('fill', 'url(#legendGradient)');
+
+ let xScale = d3.scaleLinear()
+ .range([0, width - 2 * xpadding])
+ .domain([0, 1.0]);
+
+ let axis = svg.append('g')
+ .attr('transform', 'translate(' + xpadding + ',' + (height - padding) + ')')
+ .call(
+ d3.axisBottom(xScale)
+ .tickFormat(d3.format('.0%'))
+ );
+ axis.select('path')
+ .attr('opacity', 0.0)
+ };
+
+ function render(data) {
let svg = d3.select('svg.' + data.class);
// The normal pie chart.
@@ -83,6 +178,9 @@
.attr('fill', function(d, i) {
return d.data.color;
})
+ .on('mouseover', mouseover)
+ .on('mousemove', mousemove)
+ .on('mouseleave', mouseleave)
.attr('d', arc)
// Start transition.
.transition()
@@ -112,6 +210,11 @@
let rsc_allocation_ratio_height_check_px = $('#rsc_allocation_ratio_width_check')
.text(data.resourceAllocationRatio).get(0).offsetHeight;
+ let title_width_check_px = $('#title_width_check')
+ .text(data.title).get(0).offsetWidth;
+ let title_height_check_px = $('#title_width_check')
+ .text(data.title).get(0).offsetHeight;
+
// Remove the element.
$('#rsc_usage_width_check').empty();
$('#rsc_allocation_ratio_width_check').empty();
@@ -132,7 +235,7 @@
.text(data.resourceAllocationRatio);
svg.selectAll('.resource_usage')
- .remove();
+ .remove();
svg.append('text')
.attr('class', 'resource_usage')
@@ -142,6 +245,19 @@
.style('font-size', FONT_SIZE_RSC_USAGE)
.style('fill', d3.schemeSet3[8] + data.pieChart[0].color)
.text(data.resourceUsage);
+
+ // Add title.
+ svg.selectAll('.chart_title')
+ .remove();
+ svg.append('text')
+ .attr('class', '.chart_title')
+ .attr('x', WIDTH / 2 + title_width_check_px / -2)
+ .attr('y', HEIGHT - title_height_check_px + TITLE_HEIGHT)
+ .style('font-family', FONT_FAMILY)
+ .style('font-size', FONT_SIZE_TITLE)
+ .style('font-weight', 900)
+ .style('fill', d3.rgb(data.pieChart[0].color).darker(1))
+ .text(data.title);
}
const selectors = [{
@@ -178,57 +294,50 @@
pods_allocation += parseInt(node.podsAllocation);
});
- // Color scheme combination example for doughnut chart.
- // Pastel dark green.
- // color: d3.schemePastel2[0],
- // Pastel Light green.
- // color: d3.schemePastel2[4],
-
- // Paired dark blue.
- // color: d3.schemePaired[1],
- // Paired light blue.
- // color: d3.schemePaired[0],
-
- // Paired dark green.
- // color: d3.schemePaired[3],
- // Paired light green.
- // color: d3.schemePaired[2],
-
// CPU usage doughnut chart.
let cpu_request_ratio = cpu_request / cpu_capacity;
+ let cpu_request_rounded = cpu_request.toFixed(2);
render({
svg: svgs.pop(),
selector: '#k8s_node_allocated_resources',
class: 'k8s_node_cpu_usage',
pieChart: [{
color: d3.interpolateSpectral(1 - cpu_request_ratio),
- value: cpu_request
+ value: cpu_request_rounded,
+ suffix: 'Cores'
}, {
color: d3.interpolateSpectral(1 - cpu_request_ratio - 0.15),
- value: cpu_capacity - cpu_request
+ value: (cpu_capacity - cpu_request_rounded).toFixed(2),
+ suffix: 'Cores'
}],
- resourceUsage: cpu_request.toFixed(2) + ' / ' +
+ resourceUsage: cpu_request_rounded + ' / ' +
cpu_capacity + ' Cores',
- resourceAllocationRatio: (cpu_request_ratio * 100).toFixed(1) + '%'
+ resourceAllocationRatio: (cpu_request_ratio * 100).toFixed(1) + '%',
+ title: 'CPU Core Usage'
});
// Memory usage doughnut chart.
let memory_request_ratio = memory_request / memory_capacity;
+ let memory_request_rounded = (memory_request / 1024 / 1024 / 1024).toFixed(2);
+ let memory_capacity_rounded = (memory_capacity / 1024 / 1024 / 1024).toFixed(2);
render({
svg: svgs.pop(),
selector: '#k8s_node_allocated_resources',
class: 'k8s_node_memory_usage',
pieChart: [{
color: d3.interpolateSpectral(1 - memory_request_ratio),
- value: memory_request
+ value: memory_request_rounded,
+ suffix: 'GiB'
}, {
color: d3.interpolateSpectral(1 - memory_request_ratio - 0.15),
- value: memory_capacity - memory_request
+ value: (memory_capacity_rounded - memory_request_rounded).toFixed(2),
+ suffix: 'GiB'
}],
resourceUsage:
- (memory_request / 1024 / 1024 / 1024).toFixed(2) + ' / ' +
- (memory_capacity / 1024 / 1024 / 1024).toFixed(2) + ' GiB',
- resourceAllocationRatio: (memory_request_ratio * 100).toFixed(1) + '%'
+ memory_request_rounded + ' / ' +
+ memory_capacity_rounded + ' GiB',
+ resourceAllocationRatio: (memory_request_ratio * 100).toFixed(1) + '%',
+ title: 'Memory Usage'
});
// Pods allocation doughnut chart.
@@ -239,18 +348,22 @@
class: 'k8s_node_pods_allocation',
pieChart: [{
color: d3.interpolateSpectral(1 - pods_allocation_ratio),
- value: pods_allocation
+ value: pods_allocation,
+ suffix: 'Pods'
}, {
color: d3.interpolateSpectral(1 - pods_allocation_ratio - 0.15),
- value: pods_capacity - pods_allocation
+ value: pods_capacity - pods_allocation,
+ suffix: 'Pods'
}],
- resourceUsage: pods_allocation + ' / ' + pods_capacity + " Pods",
- resourceAllocationRatio: (pods_allocation_ratio * 100).toFixed(1) + '%'
+ resourceUsage: pods_allocation + ' / ' + pods_capacity + ' Pods',
+ resourceAllocationRatio: (pods_allocation_ratio * 100).toFixed(1) + '%',
+ title: 'Pods Allocation'
});
});
};
updateNodeAllocatedResources();
+ drawLegend();
let interval = drupalSettings.k8s.k8s_js_refresh_interval || 10;
setInterval(function() {
diff --git a/modules/cloud_service_providers/k8s/js/k8s_node_heatmap.js b/modules/cloud_service_providers/k8s/js/k8s_node_heatmap.js
index d1c279c..6b934f2 100644
--- a/modules/cloud_service_providers/k8s/js/k8s_node_heatmap.js
+++ b/modules/cloud_service_providers/k8s/js/k8s_node_heatmap.js
@@ -157,7 +157,6 @@
let mouseover = function (pod) {
tooltip.style('opacity', 1);
d3.select(this)
- .style('stroke', 'black')
.style('stroke', '#cc6600')
.style('opacity', 1);
};
@@ -167,6 +166,7 @@
.html('' + pod.name + '
'
+ pod.cpuUsage + '
'
+ pod.memoryUsage + ' MiB')
+ .style('display', 'block')
.style('left', (d3.mouse(this)[0] + y_axis_label_px + RECT_PX / 2.5) + 'px')
.style('top', node_names.length > 1
? (d3.mouse(this)[1] + RECT_PX / 2.5 + margin.top) + 'px'
@@ -175,7 +175,7 @@
};
let mouseleave = function (pod) {
- tooltip.style('opacity', 0);
+ tooltip.style('display', 'none');
d3.select(this)
.style('stroke', 'none')
.style('opacity', 0.8);
diff --git a/modules/cloud_service_providers/k8s/src/Controller/ApiController.php b/modules/cloud_service_providers/k8s/src/Controller/ApiController.php
index ba3e0ca..b7e4405 100644
--- a/modules/cloud_service_providers/k8s/src/Controller/ApiController.php
+++ b/modules/cloud_service_providers/k8s/src/Controller/ApiController.php
@@ -281,6 +281,7 @@ class ApiController extends ControllerBase implements ApiControllerInterface {
$pods = $this->entityTypeManager->getStorage('k8s_pod')
->loadByProperties([
'cloud_context' => $cloud_context,
+ 'node_name' => $node_name,
]);
foreach ($pods ?: [] as $pod) {