Skip to content

Commit

Permalink
Very rough unfinished container but displays data.
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseVarGar committed Aug 7, 2023
1 parent 84ac3a9 commit 1275abf
Showing 1 changed file with 127 additions and 61 deletions.
188 changes: 127 additions & 61 deletions src/client/app/containers/RadarChartContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,56 +11,45 @@ import translate from '../utils/translate';
import Plot from 'react-plotly.js';
import Locales from '../types/locales';
import { DataType } from '../types/Datasources';
//Make your own radarUnitLabel later. Lets see if this works first.
import { lineUnitLabel } from '../utils/graphics';
// Make your own radarUnitLabel later. Lets see if this works first
import { barUnitLabel } from '../utils/graphics';
import { AreaUnitType, getAreaUnitConversion } from '../utils/getAreaUnitConversion';

function mapStateToProps(state: State) {
const timeInterval = state.graph.timeInterval;
const unitID = state.graph.selectedUnit;
const datasets: any[] = [];
const barDuration = state.graph.barDuration;
//For largest and smallest usage in reading.reading.
let minR: number | undefined;
let maxR: number | undefined;
// The unit label depends on the unit which is in selectUnit state.
const graphingUnit = state.graph.selectedUnit;
// The current selected rate
/* Might want to go back and change this currentSelectedRate */
const currentSelectedRate = state.graph.lineGraphRate;
let unitLabel = '';
let needsRateScaling = false;
// variables to determine the slider min and max
let minTimestamp: number | undefined;
let maxTimestamp: number | undefined;
// If graphingUnit is -99 then none selected and nothing to graph so label is empty.
// This will probably happen when the page is first loaded.
if (graphingUnit !== -99) {
const selectUnitState = state.units.units[state.graph.selectedUnit];
if (selectUnitState !== undefined) {
// Determine the y-axis label and if the rate needs to be scaled.
/** Might want to go back and change this lineUnitLabel function */
const returned = lineUnitLabel(selectUnitState, currentSelectedRate, state.graph.areaNormalization, state.graph.selectedAreaUnit);
unitLabel = returned.unitLabel
needsRateScaling = returned.needsRateScaling;
// Determine the r-axis label.
unitLabel = barUnitLabel(selectUnitState, state.graph.areaNormalization, state.graph.selectedAreaUnit);
}
}
// The rate will be 1 if it is per hour (since state readings are per hour) or no rate scaling so no change.
const rateScaling = needsRateScaling ? currentSelectedRate.rate : 1;

// Add all valid data from existing meters to the radar plot
for (const meterID of state.graph.selectedMeters) {
const byMeterID = state.readings.radar.byMeterID[meterID];
// Make sure have the meter data. If you already have the meter, unselect, change
// the timeInterval via another meter and then reselect then this new timeInterval
// may not yet be in state so verify with the second condition on the if.
// Note the second part may not be used based on next checks but do here since simple.
if (byMeterID !== undefined && byMeterID[timeInterval.toString()] !== undefined) {
const meterArea = state.meters.byMeterID[meterID].area;
const byMeterID = state.readings.bar.byMeterID[meterID];
if (byMeterID !== undefined && byMeterID[timeInterval.toString()] !== undefined &&
byMeterID[timeInterval.toString()][barDuration.toISOString()] !== undefined) {
let meterArea = state.meters.byMeterID[meterID].area;
// We either don't care about area, or we do in which case there needs to be a nonzero area.
if (!state.graph.areaNormalization || (meterArea > 0 && state.meters.byMeterID[meterID].areaUnit != AreaUnitType.none)) {
// Convert the meter area into the proper unit if normalizing by area or use 1 if not so won't change reading values.
const areaScaling = state.graph.areaNormalization ?
meterArea * getAreaUnitConversion(state.meters.byMeterID[meterID].areaUnit, state.graph.selectedAreaUnit) : 1;
// Divide areaScaling into the rate so have complete scaling factor for readings.
const scaling = rateScaling / areaScaling;
const readingsData = byMeterID[timeInterval.toString()][unitID];
if (state.graph.areaNormalization) {
// convert the meter area into the proper unit, if needed
meterArea *= getAreaUnitConversion(state.meters.byMeterID[meterID].areaUnit, state.graph.selectedAreaUnit);
}
const readingsData = byMeterID[timeInterval.toString()][barDuration.toISOString()][unitID];
if (readingsData !== undefined && !readingsData.isFetching) {
const label = state.meters.byMeterID[meterID].identifier;
const colorID = meterID;
Expand All @@ -80,24 +69,29 @@ function mapStateToProps(state: State) {
const st = moment.utc(reading.startTimestamp);
// Time reading is in the middle of the start and end timestamp
const timeReading = st.add(moment.utc(reading.endTimestamp).diff(st) / 2);
thetaData.push(timeReading.format('YYYY-MM-DD HH:mm:ss'));
const readingValue = reading.reading * scaling;
// thetaData.push(timeReading.format('YYYY-MM-DD HH:mm:ss'));
thetaData.push(timeReading.format('ddd, ll LTS'));
let readingValue = reading.reading;
if (state.graph.areaNormalization) {
readingValue /= meterArea;
}
rData.push(readingValue);
hoverText.push(`<b> ${timeReading.format('ddd, ll LTS')} </b> <br> ${label}: ${readingValue.toPrecision(6)} ${unitLabel}`);
// only display a range of dates for the hover text if there is more than one day in the range
let timeRange: string = `${moment.utc(reading.startTimestamp).format('ll')}`;
if (barDuration.asDays() != 1) {
// subtracting one extra day caused by day ending at midnight of the next day.
// Going from DB unit timestamp that is UTC so force UTC with moment, as usual.
timeRange += ` - ${moment.utc(reading.endTimestamp).subtract(1, 'days').format('ll')}`;
}
hoverText.push(`<b> ${timeRange} </b> <br> ${label}: ${readingValue.toPrecision(6)} ${unitLabel}`);
});

/*
get the min and max timestamp of the meter, and compare it to the global values
TODO: If we know the interval and frequency of meter data, these calculations should be able to be simplified
*/
if (readings.length > 0) {
if (minTimestamp == undefined || readings[0]['startTimestamp'] < minTimestamp) {
minTimestamp = readings[0]['startTimestamp'];
}
if (maxTimestamp == undefined || readings[readings.length - 1]['endTimestamp'] >= maxTimestamp) {
// Need to add one extra reading interval to avoid range truncation. The max bound seems to be treated as non-inclusive
maxTimestamp = readings[readings.length - 1]['endTimestamp'] + (readings[0]['endTimestamp'] - readings[0]['startTimestamp']);
}
//Find the largest and smallest usage in rData.
if (minR == undefined || minR > Math.min(...rData)) {
minR = Math.min(...rData);
}
if (maxR == undefined || maxR < Math.max(...rData)) {
maxR = Math.max(...rData);
}

// This variable contains all the elements (x and y values, line type, etc.) assigned to the data parameter of the Plotly object
Expand All @@ -120,25 +114,96 @@ function mapStateToProps(state: State) {
}
}

/**
*
*ADD GROUPS FOR RADAR!!!!!!!!!!
*/
//THIS DOES NOT WORK YET AND IT'S STILL USING RADAR READINGS I MOVED TO BAR READINGS
// for (const groupID of state.graph.selectedGroups) {
// const byGroupID = state.readings.line.byGroupID[groupID];
// if (byGroupID !== undefined && byGroupID[timeInterval.toString()] !== undefined) {
// let groupArea = state.groups.byGroupID[groupID].area;
// if (!state.graph.areaNormalization || (groupArea > 0 && state.groups.byGroupID[groupID].areaUnit != AreaUnitType.none)) {
// if (state.graph.areaNormalization) {
// // convert the meter area into the proper unit, if needed
// groupArea *= getAreaUnitConversion(state.groups.byGroupID[groupID].areaUnit, state.graph.selectedAreaUnit);
// }
// const readingsData = byGroupID[timeInterval.toString()][unitID];
// if (readingsData !== undefined && !readingsData.isFetching) {
// const label = state.groups.byGroupID[groupID].name;
// const colorID = groupID;
// if (readingsData.readings === undefined) {
// throw new Error('Unacceptable condition: readingsData.readings is undefined.');
// }

// set the bounds for the slider
if (minTimestamp == undefined) {
minTimestamp = 0;
maxTimestamp = 0;
}
const root: any = document.getElementById('root');
root.setAttribute('min-timestamp', minTimestamp);
root.setAttribute('max-timestamp', maxTimestamp);
// // Create two arrays for the x and y values. Fill the array with the data from the line readings
// const thetaData: string[] = [];
// const rData: number[] = [];
// const hoverText: string[] = [];
// const readings = _.values(readingsData.readings);
// // Check if reading needs scaling outside of the loop so only one check is needed
// // Results in more code but SLIGHTLY better efficiency :D
// if (needsRateScaling) {
// const rate = currentSelectedRate.rate;
// readings.forEach(reading => {
// // As usual, we want to interpret the readings in UTC. We lose the timezone as this as the start/endTimestamp
// // are equivalent to Unix timestamp in milliseconds.
// const st = moment.utc(reading.startTimestamp);
// // Time reading is in the middle of the start and end timestamp
// const timeReading = st.add(moment.utc(reading.endTimestamp).diff(st) / 2);
// // thetaData.push(timeReading.utc().format('YYYY-MM-DD HH:mm:ss'));
// thetaData.push(timeReading.utc().format('ddd, ll LTS'));
// rData.push(reading.reading * rate);
// hoverText.push(`<b> ${timeReading.format('ddd, ll LTS')} </b> <br> ${label}: ${(reading.reading * rate).toPrecision(6)} ${unitLabel}`);
// });
// }
// else {
// readings.forEach(reading => {
// // As usual, we want to interpret the readings in UTC. We lose the timezone as this as the start/endTimestamp
// // are equivalent to Unix timestamp in milliseconds.
// const st = moment.utc(reading.startTimestamp);
// // Time reading is in the middle of the start and end timestamp
// const timeReading = st.add(moment.utc(reading.endTimestamp).diff(st) / 2);
// // thetaData.push(timeReading.utc().format('YYYY-MM-DD HH:mm:ss'));
// thetaData.push(timeReading.utc().format('ddd, ll LTS'));
// let readingValue = reading.reading;
// if (state.graph.areaNormalization) {
// readingValue /= groupArea;
// }
// rData.push(readingValue);
// hoverText.push(`<b> ${timeReading.format('ddd, ll LTS')} </b> <br> ${label}: ${readingValue.toPrecision(6)} ${unitLabel}`);
// });
// }

// //Find the largest and smallest usage in rData.
// if (minR == undefined || minR > Math.min(...rData)) {
// minR = Math.min(...rData);
// }
// if (maxR == undefined || maxR < Math.max(...rData)) {
// maxR = Math.max(...rData);
// }

// Use the min/max time found for the readings (and shifted as desired) as the
// x-axis range for the graph.
// Avoid pesky shifting timezones with utc.
const start = moment.utc(minTimestamp).toISOString(); // Need this????????????????????????????????????????????????????
const end = moment.utc(maxTimestamp).toISOString();
// // This variable contains all the elements (x and y values, line type, etc.) assigned to the data parameter of the Plotly object
// datasets.push({
// name: label,
// x: thetaData,
// y: rData,
// text: hoverText,
// hoverinfo: 'text',
// type: 'scatterpolar',
// mode: 'lines',
// line: {
// shape: 'spline',
// width: 2,
// color: getGraphColor(colorID, DataType.Group)
// }
// });
// }
// }
// }
// }

// No range if minR or maxR is undefined.
if (minR == undefined || maxR == undefined) {
minR = 0;
maxR = 0;
}

let layout: any;
// Customize the layout of the plot
Expand Down Expand Up @@ -180,7 +245,8 @@ function mapStateToProps(state: State) {
polar: {
radialaxis: {
title: unitLabel,
range: [start, end], // Specifies the start and end points of visible part of graph
// Specifies the start and end points of the usage.
range: [minR, maxR],
showgrid: true,
gridcolor: '#ddd'
}
Expand Down

1 comment on commit 1275abf

@JesseVarGar
Copy link
Contributor Author

@JesseVarGar JesseVarGar commented on 1275abf Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an update on the container. Few things to note:

  1. I don't plan on sticking with bar readings in the radar container but I like the idea of the bar duration. It helps display data cleaner on the radar graph. I plan on implementing something similar to radar readings.
  2. thetaData.push(timeReading.format('YYYY-MM-DD HH:mm:ss')); does not allow the radar to display data so i had to change it to thetaData.push(timeReading.format('ddd, ll LTS'));. I plan on coming back and trying to get the former to work.
  3. The groups don't work at all and I haven't updated it to bar readings. I plan on doing group readings after I figure out meter readings.

Please sign in to comment.