From c5a467c417e1087eac36ad4b941a6102df30aa0e Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Mon, 17 Jun 2024 13:57:54 -0400 Subject: [PATCH] tooltip adjustments --- .../javascripts/dashboardVisualization.js | 75 +++++++------------ .../sass/uswds/_data-visualization.scss | 49 ++++++++---- app/templates/views/dashboard/dashboard.html | 32 ++++---- 3 files changed, 82 insertions(+), 74 deletions(-) diff --git a/app/assets/javascripts/dashboardVisualization.js b/app/assets/javascripts/dashboardVisualization.js index 3bc24b237..61015996c 100644 --- a/app/assets/javascripts/dashboardVisualization.js +++ b/app/assets/javascripts/dashboardVisualization.js @@ -9,28 +9,15 @@ const FONT_WEIGHT = 'bold'; const MAX_Y = 120; - let currentLabels = []; - let currentDeliveredData = []; - let currentFailedData = []; - - // Function to format the date - function formatDate(dateStr) { - const date = new Date(dateStr); - const month = date.getMonth() + 1; - const day = date.getDate(); - const year = date.getFullYear().toString().slice(-2); - return `${month}/${day}/${year}`; - } - // Function to create a stacked bar chart with animation using D3.js function createChart(containerId, labels, deliveredData, failedData) { - currentLabels = labels; - currentDeliveredData = deliveredData; - currentFailedData = failedData; - const container = d3.select(containerId); container.selectAll('*').remove(); // Clear any existing content + // Dynamically create tooltip element + const tooltip = container.append('div') + .attr('id', 'tooltip'); + const margin = { top: 60, right: 20, bottom: 40, left: 20 }; // Adjusted top margin for legend const width = container.node().getBoundingClientRect().width - margin.left - margin.right; const height = 400 - margin.top - margin.bottom; @@ -42,33 +29,36 @@ .attr('transform', `translate(${margin.left},${margin.top})`); // Create legend + const legend = svg.append('g') + .attr('class', 'legend') + .attr('transform', `translate(${width - 200},-40)`); // Adjust the position of the legend + const legendData = [ { label: 'Delivered', color: COLORS.delivered }, { label: 'Failed', color: COLORS.failed } ]; - const legend = d3.select('.chart-legend').selectAll('.legend-item') - .data(legendData); + const legendItem = legend.selectAll('.legend-item') + .data(legendData) + .enter() + .append('g') + .attr('class', 'legend-item') + .attr('transform', (d, i) => `translate(${i * 100},0)`); // Adjust the spacing between legend items - const legendEnter = legend.enter().append('div') - .attr('class', 'legend-item'); - - legendEnter.append('rect') + legendItem.append('rect') .attr('width', 18) .attr('height', 18) .attr('fill', d => d.color); - legendEnter.append('text') + legendItem.append('text') .attr('x', 24) .attr('y', 9) .attr('dy', '0.35em') .style('text-anchor', 'start') .text(d => d.label); - legend.exit().remove(); - const x = d3.scaleBand() - .domain(labels.map(formatDate)) // Format the dates + .domain(labels) .range([0, width]) .padding(0.1); @@ -95,7 +85,7 @@ // Data for stacking const stackData = labels.map((label, i) => ({ - label: formatDate(label), // Format the dates + label: label, delivered: deliveredData[i], failed: failedData[i] || 0 // Ensure there's a value for failed, even if it's 0 })); @@ -113,9 +103,6 @@ .domain(['delivered', 'failed']) .range([COLORS.delivered, COLORS.failed]); - // Create tooltip - const tooltip = d3.select('#tooltip'); - // Create bars with animation const barGroups = svg.selectAll('.bar-group') .data(series) @@ -132,18 +119,18 @@ .attr('y', height) .attr('height', 0) .attr('width', x.bandwidth()) - .on('mouseover', function (event, d) { + .on('mouseover', function(event, d) { const key = d3.select(this.parentNode).datum().key; const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1); tooltip.style('display', 'block') .html(`${d.data.label}
${capitalizedKey}: ${d.data[key]}`); }) - .on('mousemove', function (event) { + .on('mousemove', function(event) { const containerPosition = container.node().getBoundingClientRect(); - tooltip.style('left', `${event.clientX - containerPosition.left + 35}px`) - .style('top', `${event.clientY - containerPosition.top + 135}px`); + tooltip.style('left', `${event.clientX - containerPosition.left + 10}px`) + .style('top', `${event.clientY - containerPosition.top + 10}px`); }) - .on('mouseout', function () { + .on('mouseout', function() { tooltip.style('display', 'none'); }) .transition() @@ -177,7 +164,7 @@ labels.forEach((label, index) => { const row = document.createElement('tr'); const cellDay = document.createElement('td'); - cellDay.textContent = formatDate(label); // Format the dates + cellDay.textContent = label; row.appendChild(cellDay); const cellDelivered = document.createElement('td'); @@ -205,11 +192,11 @@ var socket = io(); var serviceId = ctx.getAttribute('data-service-id'); - socket.on('connect', function () { + socket.on('connect', function() { socket.emit('fetch_daily_stats', serviceId); }); - socket.on('daily_stats_update', function (data) { + socket.on('daily_stats_update', function(data) { var labels = []; var deliveredData = []; var failedData = []; @@ -224,7 +211,7 @@ createTable('weeklyTable', 'Weekly', labels, deliveredData, failedData); }); - socket.on('error', function (data) { + socket.on('error', function(data) { console.log('Error:', data); }); } @@ -251,13 +238,7 @@ } } - function updateChartSize() { - createChart('#weeklyChart', currentLabels, currentDeliveredData, currentFailedData); - } - - window.addEventListener('resize', updateChartSize); - - document.addEventListener('DOMContentLoaded', function () { + document.addEventListener('DOMContentLoaded', function() { // Initialize weekly chart and table with service data by default fetchServiceData(); diff --git a/app/assets/sass/uswds/_data-visualization.scss b/app/assets/sass/uswds/_data-visualization.scss index c8386fff4..7b34d25dd 100644 --- a/app/assets/sass/uswds/_data-visualization.scss +++ b/app/assets/sass/uswds/_data-visualization.scss @@ -107,19 +107,6 @@ $failed: color('orange-30v'); // padding: 10px; /* Replace units(1) with 10px */ // } -#chartsArea { - min-height: 400px; -} - -.chart-subtitle { - text-align: left; - width: 100%; - font-size: size("body", 6); - font-weight: bold; - padding: 0 units(1); - margin: 0; -} - .chart { display: flex; justify-content: center; @@ -127,6 +114,22 @@ $failed: color('orange-30v'); flex-direction: column; } +.chart-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 20px; +} + +.chart-subtitle { + font-size: size("body", 6); + font-weight: bold; + text-align: left; + width: 100%; + padding: 0; + margin: 0; +} + .axis text { font-size: size("body", 1); } @@ -147,6 +150,23 @@ $failed: color('orange-30v'); position: relative; } +.chart-legend { + display: flex; + align-items: center; +} + +.legend-item { + display: flex; + align-items: center; + margin-right: units(2); +} + +.legend-item rect { + width: units(2); + height: units(2); + margin-right: units(1); +} + #tooltip { position: absolute; display: none; @@ -157,5 +177,6 @@ $failed: color('orange-30v'); border-radius: units(1); pointer-events: none; z-index: 100; - font-size: size("body", 4); + font-size: size("body", 3); + line-height: 1.3; } diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index cef783043..340c2e842 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -22,6 +22,21 @@

{{ current_service.name }} Dashboard

+

+ Messages sent +

+ + + {{ ajax_block(partials, updates_url, 'inbox') }} + + {{ ajax_block(partials, updates_url, 'totals') }} + + {{ ajax_block(partials, updates_url, 'template-statistics') }} + +

+ Activity snapshot +

@@ -32,12 +47,14 @@
-
{{ current_service.name }} - Last 7 Days
+
+
{{ current_service.name }} - Last 7 Days
+
+
-
-

- Messages sent -

- - - {{ ajax_block(partials, updates_url, 'inbox') }} - - {{ ajax_block(partials, updates_url, 'totals') }} - - {{ ajax_block(partials, updates_url, 'template-statistics') }}

Recent Batches