Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions frontend/src/charts/UniversalChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { getNonStreamTimeDomain } from './timeDomain';
import ChartWrapper from './ChartWrapper';
import { chartPlugins } from './plugins';
import { getVwcAxisBounds } from './VwcChart/vwcAxis';

export default function UniversalChart({ data, stream, chartId, measurements, units, axisIds, axisPolicy, startDate, endDate, onResampleChange }) {
import { formatElectricalUnit, formatSensorValue } from "../pages/dashboard/components/unifiedChartUtils";
export default function UniversalChart({ data, stream, chartId, sensorName, measurements, units, axisIds, axisPolicy, startDate, endDate, onResampleChange }) {
// Build chart options dynamically based on measurements
const buildChartOptions = () => {
const nonStreamXDomain = getNonStreamTimeDomain(stream, startDate, endDate);
Expand Down Expand Up @@ -86,6 +86,13 @@ export default function UniversalChart({ data, stream, chartId, measurements, un
max: leftYMax,
}),
};
scales.y.ticks = scales.y.ticks || {};
scales.y.ticks.callback = function(value) {
if (sensorName === 'POWER_VOLTAGE' || sensorName === 'POWER_CURRENT') {
return formatElectricalUnit(value, sensorName);
}
return value;
};
}
// Handle dual measurements (left and right axes)
else if (measurements.length === 2) {
Expand Down Expand Up @@ -136,12 +143,33 @@ export default function UniversalChart({ data, stream, chartId, measurements, un
};
}

const activePlugins = measurements.length > 1 ? structuredClone(chartPlugins) : {};

activePlugins.tooltip = {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
if (sensorName === 'POWER_VOLTAGE' || sensorName === 'POWER_CURRENT') {
label += formatElectricalUnit(context.parsed.y, sensorName);
} else {
label += context.parsed.y; // Default behavior for other sensors
}
}
return label;
}
}
};

return {
maintainAspectRatio: false,
responsive: true,
parsing: false,
scales,
...(measurements.length > 1 && { plugins: structuredClone(chartPlugins) }),
plugins: activePlugins,
};
};

Expand All @@ -160,6 +188,7 @@ UniversalChart.propTypes = {
units: PropTypes.arrayOf(PropTypes.string).isRequired,
axisIds: PropTypes.arrayOf(PropTypes.string).isRequired,
axisPolicy: PropTypes.string,
sensorName: PropTypes.string,
startDate: PropTypes.object,
endDate: PropTypes.object,
onResampleChange: PropTypes.func,
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/pages/dashboard/components/UnifiedChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const CHART_CONFIGS = {
power_voltage: {
sensor_name: 'POWER_VOLTAGE',
measurements: ['Voltage'],
units: ['mV'],
units: ['V'],
axisIds: ['y'],
chartId: 'powerVoltage',
},
power_current: {
sensor_name: 'POWER_CURRENT',
measurements: ['Current'],
units: ['uA'],
units: ['A'],
axisIds: ['y'],
chartId: 'powerCurrent',
},
Expand Down Expand Up @@ -443,6 +443,7 @@ function UnifiedChart({ type, cells, startDate, endDate, stream, liveData, proce
data={sensorChartData}
stream={stream}
chartId={chartId}
sensorName={sensor_name}
measurements={measurements}
units={units}
axisIds={axisIds}
Expand Down
45 changes: 45 additions & 0 deletions frontend/src/pages/dashboard/components/unifiedChartUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,48 @@ export function normalizeUnifiedStreamValue(sensorName, measurementLabel, value)
}
return value;
}

export const formatElectricalUnit = (value, type) => {
if (value === null || value === undefined) return 'N/A';

const absVal = Math.abs(value);

if (type === 'POWER_CURRENT') {
if (absVal < 0.001) return `${(value * 1000000).toFixed(3)} µA`;
if (absVal < 1) return `${(value * 1000).toFixed(3)} mA`;
return `${value.toFixed(3)} A`;
}

if (type === 'POWER_VOLTAGE') {
if (absVal < 1) return `${(value * 1000).toFixed(3)} mV`;
return `${value.toFixed(3)} V`;
}

return typeof value === 'number' ? value.toFixed(3) : value;
};

/**
* Dynamically scales and formats sensor values based on their magnitude.
* @param {number} value - The raw decimal value from the backend.
* @param {string} type - The sensor type (e.g., 'POWER_VOLTAGE', 'POWER_CURRENT').
* @returns {string} The formatted value with appropriate units.
*/
export const formatSensorValue = (value, type) => {
if (value === null || value === undefined) return '-';

const absValue = Math.abs(value);

if (type === 'POWER_CURRENT') {
if (absValue < 0.001) return `${(value * 1000000).toFixed(2)} µA`;
if (absValue < 1) return `${(value * 1000).toFixed(2)} mA`;
return `${value.toFixed(2)} A`;
}

if (type === 'POWER_VOLTAGE') {
if (absValue < 1) return `${(value * 1000).toFixed(2)} mV`;
return `${value.toFixed(2)} V`;
}

// Fallback for other sensor types (just limit decimals)
return typeof value === 'number' ? value.toFixed(2) : value;
};
Loading