Skip to content
Snippets Groups Projects
Commit adb3e9cb authored by Fry, Janell's avatar Fry, Janell
Browse files

IOW-307 Partnering with Mary.

parent 8d126b9a
No related branches found
No related tags found
No related merge requests found
// functions to facilitate DV legend creation for a d3 plot
import memoize from 'fast-memoize';
import {createSelector, createStructuredSelector} from 'reselect';
import {createStructuredSelector} from 'reselect';
import {defineLineMarker, defineTextOnlyMarker} from '../../d3-rendering/markers';
import {defineLineMarker} from '../../d3-rendering/markers';
import {getLayout} from './selectors/layout';
import {getCurrentTimeSeriesLineSegments} from './selectors/time-series-lines';
import {getLegendMarkerRows} from './selectors/legend-data';
import config from '../../config';
import { mediaQuery } from '../../utils';
import {link} from '../../lib/d3-redux';
const tsLineMarkers = function(tsKey, lineClasses) {
let result = [];
if (lineClasses.default) {
result.push(defineLineMarker(null, `line-segment ts-${tsKey}`, 'Provisional'));
}
if (lineClasses.approved) {
result.push(defineLineMarker(null, `line-segment approved ts-${tsKey}`, 'Approved'));
}
if (lineClasses.estimated) {
result.push(defineLineMarker(null, `line-segment estimated ts-${tsKey}`, 'Estimated'));
}
return result;
};
/**
* create elements for the legend in the svg
*
* @param {Object} displayItems - Object containing keys for each ts. The current and compare will contain an
* object that has a masks property containing the Set of masks that are currently displayed.
* The median property will contain the metadata for the median statistics
* @return {Object} - Each key represents a ts and contains an array of markers to show.
*/
const createLegendMarkers = function(displayItems) {
const legendMarkers = [];
if (displayItems.current) {
const currentMarkers = [
...tsLineMarkers('current', displayItems.current)
];
if (currentMarkers.length) {
legendMarkers.push([
defineTextOnlyMarker('', null, 'ts-legend-current-text'),
...currentMarkers
]);
}
}
return legendMarkers;
};
/**
* Create a simple legend
......@@ -125,55 +84,11 @@ export const drawSimpleLegend = function(div, {legendMarkerRows, layout}) {
};
const uniqueClassesSelector = memoize(tsKey => createSelector(
getCurrentTimeSeriesLineSegments,
(tsLineSegments) => {
let result = {
default: false,
approved: false,
estimated: false
};
tsLineSegments.forEach((segment) => {
result.approved = result.approved || segment.approvals.includes('Approved');
result.estimated = result.estimated || segment.approvals.includes('Estimated');
result.default = result.default || segment.approvals.length === 0;
});
return result;
}
));
/**
* Select attributes from the state useful for legend creation
*/
const legendDisplaySelector = createSelector(
(state) => state.timeSeriesState.showSeries,
uniqueClassesSelector('current'),
uniqueClassesSelector('compare'),
(showSeries, medianSeries, currentClasses) => {
return {
current: showSeries.current ? currentClasses : undefined
};
}
);
/*
* Factory function that returns an array of array of markers to be used for the
* time series graph legend
* @return {Array of Array} of markers
*/
export const legendMarkerRowsSelector = createSelector(
legendDisplaySelector,
displayItems => createLegendMarkers(displayItems)
);
export const drawTimeSeriesLegend = function(elem, store) {
elem.append('div')
.classed('hydrograph-container', true)
.call(link(store, drawSimpleLegend, createStructuredSelector({
legendMarkerRows: legendMarkerRowsSelector,
legendMarkerRows: getLegendMarkerRows,
layout: getLayout
})));
};
......
import {createSelector} from 'reselect';
import {getCurrentTimeSeriesLineSegments} from './time-series-data';
import {defineLineMarker, defineTextOnlyMarker} from '../../../d3-rendering/markers';
const tsLineMarkers = function(lineClasses) {
let result = [];
if (lineClasses.default) {
result.push(defineLineMarker(null, `line-segment ts-dv`, 'Provisional'));
}
if (lineClasses.approved) {
result.push(defineLineMarker(null, `line-segment approved ts-dv`, 'Approved'));
}
if (lineClasses.estimated) {
result.push(defineLineMarker(null, `line-segment estimated ts-dv`, 'Estimated'));
}
return result;
};
/**
* create elements for the legend in the svg
*
* @param {Object} displayItems - Object containing Object containing default, estimated and approved properties.
* @return {Array} - Returns an array of markers.
*/
const createLegendMarkers = function(displayItems) {
const legendMarkers = [];
if (displayItems) {
const currentMarkers = [
...tsLineMarkers(displayItems)
];
if (currentMarkers.length) {
legendMarkers.push([
defineTextOnlyMarker('', null, 'ts-legend-current-text'),
...currentMarkers
]);
}
}
return legendMarkers;
};
export const getUniqueClasses = createSelector(
getCurrentTimeSeriesLineSegments,
(tsLineSegments) => {
let result = {
default: false,
approved: false,
estimated: false
};
tsLineSegments.forEach((segment) => {
result.approved = result.approved || segment.approvals.includes('Approved');
result.estimated = result.estimated || segment.approvals.includes('Estimated');
result.default = result.default || segment.approvals.length === 0;
});
return result;
}
);
/*
* Factory function that returns an array of array of markers to be used for the
* time series graph legend
* @return {Array of Array} of markers
*/
export const getLegendMarkerRows = createSelector(
getUniqueClasses,
displayItems => {
return createLegendMarkers(displayItems)
}
);
\ No newline at end of file
import {DateTime} from 'luxon';
import isEqual from 'lodash/isEqual';
import {createSelector} from 'reselect';
import {getCurrentObservationsTimeSeries} from '../../../selectors/observations-selector';
const TWO_DAYS = 1000 * 60 * 60 * 24 * 2; // In milliseconds
/*
* Returns selector function which returns an array of Objects which include the data needed to render the line.
* The time series data is broken into line segments. The points in a line segment will be shown as continuous and
* the data has the same approvals.
* Each Object contains the following properties
* @prop {Array of Object} points - each object has date (in milliseconds) and value {Number} properties
* @prop {Array of String} approvals - The approvals for this line segment
* The time series
*/
export const getCurrentTimeSeriesLineSegments = createSelector(
getCurrentObservationsTimeSeries,
(timeSeries) => {
if (!timeSeries) {
return [];
}
const timeStepInMillis = timeSeries.properties.timeStep.map((t) => new DateTime.fromISO(t, {zone: 'UTC'}).toMillis());
let lineSegments = [];
let previousDate = timeStepInMillis[0];
let previousApprovals = timeSeries.properties.approvals[0];
let segment = {
points: [],
approvals: timeSeries.properties.approvals[0]
};
timeStepInMillis.forEach(function(date, index) {
const resultValue = parseFloat(timeSeries.properties.result[index]);
const hasGap = date - previousDate >= TWO_DAYS;
const hasDifferentApprovals = !isEqual(timeSeries.properties.approvals[index], previousApprovals);
if (hasDifferentApprovals && !hasGap) {
// Add the current point to the last segment so that line is continuous
segment.points.push({
value: resultValue,
date: date
});
}
if (hasGap || hasDifferentApprovals) {
lineSegments.push(segment);
segment = {
points: [],
approvals: timeSeries.properties.approvals[index]
};
previousApprovals = timeSeries.properties.approvals[index];
}
segment.points.push({
value: parseFloat(resultValue),
date: date
});
previousDate = date;
});
lineSegments.push(segment);
return lineSegments;
}
);
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment