From ce7988b10d0fbb3acb9b94ba1a6d499f0c2d82bd Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 5 Jan 2026 13:40:13 -0600 Subject: [PATCH] Show traffic as mirrored bar chart with outbound above and inbound below zero axis --- assets/js/app.js | 45 ++++++++++++-------- lib/towerops_web/live/equipment_live/show.ex | 8 ++-- lib/towerops_web/live/graph_live/show.ex | 8 ++-- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index 653f4308..8b9bf377 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -53,6 +53,7 @@ const SensorChart = { const unit = this.el.dataset.unit || '%' const autoScale = this.el.dataset.autoScale === 'true' const showZeroLine = this.el.dataset.showZeroLine === 'true' + const chartType = unit === 'bps' ? 'bar' : 'line' // Generate colors for each dataset const colors = [ @@ -66,26 +67,36 @@ const SensorChart = { 'rgb(249, 115, 22)', // orange ] - const datasets = data.datasets.map((dataset, index) => ({ - ...dataset, - borderColor: colors[index % colors.length], - backgroundColor: colors[index % colors.length].replace('rgb', 'rgba').replace(')', ', 0.1)'), - borderWidth: 2, - tension: 0.4, - pointRadius: 0, - pointHoverRadius: 4, - })) + const datasets = data.datasets.map((dataset, index) => { + const baseConfig = { + ...dataset, + borderColor: colors[index % colors.length], + backgroundColor: colors[index % colors.length].replace('rgb', 'rgba').replace(')', ', 0.5)'), + borderWidth: chartType === 'bar' ? 0 : 2, + } + + // Add line-specific properties + if (chartType === 'line') { + baseConfig.tension = 0.4 + baseConfig.pointRadius = 0 + baseConfig.pointHoverRadius = 4 + } + + return baseConfig + }) // Format bits per second into human-readable units const formatBps = (bps) => { - if (bps >= 1_000_000_000) { - return (bps / 1_000_000_000).toFixed(2) + ' Gbps' - } else if (bps >= 1_000_000) { - return (bps / 1_000_000).toFixed(2) + ' Mbps' - } else if (bps >= 1_000) { - return (bps / 1_000).toFixed(2) + ' Kbps' + // Use absolute value for display (inbound is negative, but we show it as positive) + const absBps = Math.abs(bps) + if (absBps >= 1_000_000_000) { + return (absBps / 1_000_000_000).toFixed(2) + ' Gbps' + } else if (absBps >= 1_000_000) { + return (absBps / 1_000_000).toFixed(2) + ' Mbps' + } else if (absBps >= 1_000) { + return (absBps / 1_000).toFixed(2) + ' Kbps' } else { - return bps.toFixed(2) + ' bps' + return absBps.toFixed(2) + ' bps' } } @@ -133,7 +144,7 @@ const SensorChart = { } this.chart = new Chart(ctx, { - type: 'line', + type: chartType, data: { datasets }, options: { responsive: true, diff --git a/lib/towerops_web/live/equipment_live/show.ex b/lib/towerops_web/live/equipment_live/show.ex index 2c23ead3..77d1c613 100644 --- a/lib/towerops_web/live/equipment_live/show.ex +++ b/lib/towerops_web/live/equipment_live/show.ex @@ -300,6 +300,7 @@ defmodule ToweropsWeb.EquipmentLive.Show do nil else # Calculate bits per second from counter differences + # Inbound shown as negative (below zero axis) in_data = all_stats |> Enum.chunk_every(2, 1, :discard) @@ -309,10 +310,11 @@ defmodule ToweropsWeb.EquipmentLive.Show do %{ x: DateTime.to_unix(t2, :millisecond), - y: bps + y: -bps } end) + # Outbound shown as positive (above zero axis) out_data = all_stats |> Enum.chunk_every(2, 1, :discard) @@ -327,8 +329,8 @@ defmodule ToweropsWeb.EquipmentLive.Show do end) datasets = [ - %{label: "Inbound", data: in_data}, - %{label: "Outbound", data: out_data} + %{label: "Outbound", data: out_data}, + %{label: "Inbound", data: in_data} ] Jason.encode!(%{datasets: datasets}) diff --git a/lib/towerops_web/live/graph_live/show.ex b/lib/towerops_web/live/graph_live/show.ex index f30819c3..a059f464 100644 --- a/lib/towerops_web/live/graph_live/show.ex +++ b/lib/towerops_web/live/graph_live/show.ex @@ -185,6 +185,7 @@ defmodule ToweropsWeb.GraphLive.Show do nil else # Calculate bits per second from counter differences + # Inbound shown as negative (below zero axis) in_data = all_stats |> Enum.chunk_every(2, 1, :discard) @@ -194,10 +195,11 @@ defmodule ToweropsWeb.GraphLive.Show do %{ x: DateTime.to_unix(t2, :millisecond), - y: bps + y: -bps } end) + # Outbound shown as positive (above zero axis) out_data = all_stats |> Enum.chunk_every(2, 1, :discard) @@ -212,8 +214,8 @@ defmodule ToweropsWeb.GraphLive.Show do end) datasets = [ - %{label: "Inbound", data: in_data}, - %{label: "Outbound", data: out_data} + %{label: "Outbound", data: out_data}, + %{label: "Inbound", data: in_data} ] Jason.encode!(%{datasets: datasets})