Skip to content

Commit

Permalink
Merge pull request OpenEnergyDashboard#1039 from nathang15/add-radar-…
Browse files Browse the repository at this point in the history
…graph-feature

Add radar graph feature
  • Loading branch information
huss authored Dec 3, 2023
2 parents d382a48 + d156b12 commit 85e9053
Show file tree
Hide file tree
Showing 23 changed files with 999 additions and 47 deletions.
92 changes: 60 additions & 32 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/client/app/actions/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { fetchGroupsDetailsIfNeeded } from './groups';
import { fetchNeededLineReadings } from './lineReadings';
import { fetchNeededBarReadings } from './barReadings';
import { fetchNeededCompareReadings } from './compareReadings';
import { fetchNeededRadarReadings } from './radarReadings';
import { TimeInterval } from '../../../common/TimeInterval';
import { Dispatch, Thunk, ActionType, GetState } from '../types/redux/actions';
import { State } from '../types/redux/state';
Expand Down Expand Up @@ -125,6 +126,7 @@ export function changeSelectedMeters(meterIDs: number[]): Thunk {
dispatch2(fetchNeededBarReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededCompareReadings(getState().graph.comparePeriod, getState().graph.selectedUnit));
dispatch2(fetchNeededMapReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededRadarReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededThreeDReadings());
});
return Promise.resolve();
Expand All @@ -140,6 +142,7 @@ export function changeSelectedGroups(groupIDs: number[]): Thunk {
dispatch2(fetchNeededBarReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededCompareReadings(getState().graph.comparePeriod, getState().graph.selectedUnit));
dispatch2(fetchNeededMapReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededRadarReadings(getState().graph.timeInterval, getState().graph.selectedUnit));
dispatch2(fetchNeededThreeDReadings());
});
return Promise.resolve();
Expand All @@ -154,6 +157,7 @@ export function changeSelectedUnit(unitID: number): Thunk {
dispatch2(fetchNeededBarReadings(getState().graph.timeInterval, unitID));
dispatch2(fetchNeededCompareReadings(getState().graph.comparePeriod, unitID));
dispatch2(fetchNeededMapReadings(getState().graph.timeInterval, unitID));
dispatch2(fetchNeededRadarReadings(getState().graph.timeInterval, unitID));
dispatch2(fetchNeededThreeDReadings());
});
return Promise.resolve();
Expand All @@ -165,6 +169,7 @@ function fetchNeededReadingsForGraph(timeInterval: TimeInterval, unitID: number)
dispatch(fetchNeededLineReadings(timeInterval, unitID));
dispatch(fetchNeededBarReadings(timeInterval, unitID));
dispatch(fetchNeededMapReadings(timeInterval, unitID));
dispatch(fetchNeededRadarReadings(timeInterval, unitID));
dispatch(fetchNeededThreeDReadings());
return Promise.resolve();
};
Expand Down
160 changes: 160 additions & 0 deletions src/client/app/actions/radarReadings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { TimeInterval } from '../../../common/TimeInterval';
import { ActionType, Thunk, Dispatch, GetState } from '../types/redux/actions';
import { State } from '../types/redux/state';
import * as t from '../types/redux/radarReadings';
import { readingsApi } from '../utils/api';
import { LineReadings } from '../types/readings';

/**
* @param state the Redux state
* @param meterID the ID of the meter to check
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
* @returns True if the readings for the given meter, time duration and unit are missing; false otherwise.
*/
function shouldFetchMeterRadarReadings(state: State, meterID: number, timeInterval: TimeInterval, unitID: number): boolean {
const timeIntervalIndex = timeInterval.toString();

const readingsForID = state.readings.line.byMeterID[meterID];
if (readingsForID === undefined) {
return true;
}

const readingsForTimeInterval = readingsForID[timeIntervalIndex];
if (readingsForTimeInterval === undefined) {
return true;
}

const readingsForUnit = readingsForTimeInterval[unitID];
if (readingsForUnit === undefined) {
return true;
}

return !readingsForUnit.isFetching;
}

/**
* @param state the Redux state
* @param groupID the ID of the group to check
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
* @returns True if the readings for the given group, time duration and unit are missing; false otherwise.
*/
function shouldFetchGroupRadarReadings(state: State, groupID: number, timeInterval: TimeInterval, unitID: number): boolean {
const timeIntervalIndex = timeInterval.toString();

const readingsForID = state.readings.line.byGroupID[groupID];
if (readingsForID === undefined) {
return true;
}

const readingsForTimeInterval = readingsForID[timeIntervalIndex];
if (readingsForTimeInterval === undefined) {
return true;
}

const readingsForUnit = readingsForTimeInterval[unitID];
if (readingsForUnit === undefined) {
return true;
}

return !readingsForUnit.isFetching;
}

/**
* @param meterIDs the IDs of the meters to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
*/
function requestMeterRadarReadings(meterIDs: number[], timeInterval: TimeInterval, unitID: number): t.RequestMeterRadarReadingAction {
return { type: ActionType.RequestMeterLineReadings, meterIDs, timeInterval, unitID };
}

/**
* @param groupIDs the IDs of the groups to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
*/
function requestGroupRadarReadings(groupIDs: number[], timeInterval: TimeInterval, unitID: number): t.RequestGroupRadarReadingAction {
return { type: ActionType.RequestGroupLineReadings, groupIDs, timeInterval, unitID };
}
/**
* @param meterIDs the IDs of the meters to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
* @param readings the readings for the given meters
*/
function receiveMeterRadarReadings(
meterIDs: number[], timeInterval: TimeInterval, unitID: number, readings: LineReadings): t.ReceiveMeterRadarReadingAction {
return { type: ActionType.ReceiveMeterLineReadings, meterIDs, timeInterval, unitID, readings };
}

/**
* @param groupIDs the IDs of the groups to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
* @param readings the readings for the given groups
*/
function receiveGroupLineReadings(
groupIDs: number[], timeInterval: TimeInterval, unitID: number, readings: LineReadings): t.ReceiveGroupRadarReadingAction {
return { type: ActionType.ReceiveGroupLineReadings, groupIDs, timeInterval, unitID, readings };
}

/**
* @param meterIDs the IDs of the meters to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
*/
function fetchMeterRadarReadings(meterIDs: number[], timeInterval: TimeInterval, unitID: number): Thunk {
return async (dispatch: Dispatch) => {
dispatch(requestMeterRadarReadings(meterIDs, timeInterval, unitID));
const meterLineReadings = await readingsApi.meterRadarReadings(meterIDs, timeInterval, unitID);
dispatch(receiveMeterRadarReadings(meterIDs, timeInterval, unitID, meterLineReadings));
};
}

/**
* @param groupIDs the IDs of the groups to get readings
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
*/
function fetchGroupRadarReadings(groupIDs: number[], timeInterval: TimeInterval, unitID: number): Thunk {
return async (dispatch: Dispatch) => {
dispatch(requestGroupRadarReadings(groupIDs, timeInterval, unitID));
const groupLineReadings = await readingsApi.groupRadarReadings(groupIDs, timeInterval, unitID);
dispatch(receiveGroupLineReadings(groupIDs, timeInterval, unitID, groupLineReadings));
};
}
/**
* Fetches readings for the radar chart of all selected meters and groups, if needed.
* @param timeInterval the interval over which to check
* @param unitID the ID of the unit for which to check
*/
export function fetchNeededRadarReadings(timeInterval: TimeInterval, unitID: number): Thunk {
return (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const promises: Array<Promise<any>> = [];

// Determine which meters are missing data for this time interval
const meterIDsToFetchForLine = state.graph.selectedMeters.filter(
id => shouldFetchMeterRadarReadings(state, id, timeInterval, unitID)
);
if (meterIDsToFetchForLine.length > 0) {
promises.push(dispatch(fetchMeterRadarReadings(meterIDsToFetchForLine, timeInterval, unitID)));
}

// Determine which groups are missing data for this time interval
const groupIDsToFetchForLine = state.graph.selectedGroups.filter(
id => shouldFetchGroupRadarReadings(state, id, timeInterval, unitID)
);
if (groupIDsToFetchForLine.length > 0) {
promises.push(dispatch(fetchGroupRadarReadings(groupIDsToFetchForLine, timeInterval, unitID)));
}

return Promise.all(promises);
};
}
15 changes: 10 additions & 5 deletions src/client/app/components/ChartSelectComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ export default function ChartSelectComponent() {
<FormattedMessage id={useSelector((state: State) => state.graph.chartToRender)} />
</DropdownToggle>
<DropdownMenu>
<DropdownItem
onClick={() => dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.line })}
>
<FormattedMessage id='line' />
</DropdownItem>
<DropdownItem
onClick={() => dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.bar })}
>
Expand All @@ -59,6 +54,11 @@ export default function ChartSelectComponent() {
>
<FormattedMessage id='compare' />
</DropdownItem>
<DropdownItem
onClick={() => dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.line })}
>
<FormattedMessage id='line' />
</DropdownItem>
<DropdownItem
onClick={() => {
dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.map });
Expand All @@ -70,6 +70,11 @@ export default function ChartSelectComponent() {
>
<FormattedMessage id='map' />
</DropdownItem>
<DropdownItem
onClick={() => dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.radar })}
>
<FormattedMessage id='radar' />
</DropdownItem>
<DropdownItem
onClick={() => dispatch({ type: 'CHANGE_CHART_TO_RENDER', chartType: ChartTypes.threeD })}
>
Expand Down
Loading

0 comments on commit 85e9053

Please sign in to comment.