Newer
Older
import {line} from 'd3-shape';
import {select} from 'd3-selection';
Bucknell, Mary S.
committed
Bucknell, Mary S.
committed
import {appendTooltip} from 'd3render/tooltips';
Bucknell, Mary S.
committed
import {Actions} from 'ml/store/instantaneous-value-time-series-data';
Bucknell, Mary S.
committed
import {MASK_DESC} from './selectors/drawing-data';
import {SPARK_LINE_DIM, CIRCLE_RADIUS_SINGLE_PT} from './selectors/layout';
/**
* Draw a sparkline in a selected SVG element
*
* @param {Object} svgSelection
* @param {Array} of line segment Objects - seriesLineSegments
* @param {Object} scales - has x property for x scale and y property for y scale
export const addSparkLine = function(svgSelection, {seriesLineSegments, scales}) {
Bucknell, Mary S.
committed
if (seriesLineSegments.length === 0) {
return;
}
return scales.x(d.dateTime);
})
return scales.y(d.value);
});
const seriesDataMasks = seriesLineSegments.map(x => x.classes.dataMask);
if (seriesDataMasks.includes(null)) {
for (const lineSegment of seriesLineSegments) {
if (lineSegment.classes.dataMask === null) {
if (lineSegment.points.length === 1) {
svgSelection.append('circle')
.data(lineSegment.points)
.classed('spark-point', true)
.attr('cx', d => scales.x(d.dateTime))
.attr('cy', d => scales.y(d.value));
} else {
.attr('d', spark(lineSegment.points))
.classed('spark-line', true);
}
const elementWidth = svgElement.node().getBoundingClientRect().width;
const xLocation = (SPARK_LINE_DIM.width - elementWidth) / 2;
svgElement.attr('x', xLocation);
};
let svgText = svgSelection.append('text')
.attr('x', 0)
.attr('y', 0)
.classed('sparkline-text', true);
const maskDescs = seriesDataMasks.map(x => MASK_DESC[x.toLowerCase()]);
const maskDesc = maskDescs.length === 1 ? maskDescs[0] : 'Masked';
const maskDescWords = maskDesc.split(' ');
if (maskDescWords.length > 1) {
Array.from(maskDescWords.entries()).forEach(x => {
let tspan = svgText.append('tspan')
.attr('x', 0)
.attr('y', yPosition)
centerElement(svgText);
centerElement(tspan);
} else {
svgText.text(maskDesc)
.attr('y', '20');
Bucknell, Mary S.
committed
/**
* Draws a table with clickable rows of time series parameter codes. Selecting
* a row changes the active parameter code.
* @param {Object} elem d3 selection
* @param {String} siteno
Bucknell, Mary S.
committed
* @param {Object} availableParameterCodes parameter metadata to display
Bucknell, Mary S.
committed
* @param {Object} lineSegmentsByParmCd line segments for each parameter code
* @param {Object} timeSeriesScalesByParmCd scales for each parameter code
*/
Bucknell, Mary S.
committed
siteno,
Bucknell, Mary S.
committed
availableParameterCodes,
Bucknell, Mary S.
committed
lineSegmentsByParmCd,
timeSeriesScalesByParmCd
Bucknell, Mary S.
committed
// Get the position of the scrolled window before removing it so it can be set to the same value.
const lastTable = elem.select('#select-time-series table');
Bucknell, Mary S.
committed
const scrollTop = lastTable.size() ? lastTable.property('scrollTop') : null;
elem.select('#select-time-series').remove();
Bucknell, Mary S.
committed
if (!availableParameterCodes.length) {
const columnHeaders = [' ', 'Parameter', 'Preview', '#', 'Period of Record', 'WaterAlert'];
Bucknell, Mary S.
committed
const tableContainer = elem.append('div')
.attr('id', 'select-time-series');
Bucknell, Mary S.
committed
tableContainer.append('label')
.attr('id', 'select-time-series-label')
.text('Select a time series');
Bucknell, Mary S.
committed
const table = tableContainer.append('table')
.classed('usa-table', true)
.classed('usa-table--borderless', true)
.attr('aria-labelledby', 'select-time-series-label')
Bucknell, Mary S.
committed
.attr('tabindex', 0)
.attr('role', 'listbox');
table.append('thead')
.append('tr')
.selectAll('th')
.data(columnHeaders)
.enter().append('th')
.selectAll('tr')
Bucknell, Mary S.
committed
.data(availableParameterCodes)
.enter().append('tr')
.attr('id', param => `time-series-select-table-row-${param.parameterCode}`)
.attr('ga-on', 'click')
.attr('ga-event-category', 'selectTimeSeries')
.attr('ga-event-action', (param) => `time-series-parmcd-${param.parameterCode}`)
.classed('selected', param => param.selected)
.attr('aria-selected', param => param.selected)
Bucknell, Mary S.
committed
.on('click', function(event, param) {
if (!param.selected) {
store.dispatch(Actions.updateIVCurrentVariableAndRetrieveTimeSeries(siteno, param.variableID));
let paramSelectCol = tr.append('td');
.attr('id', param => `time-series-select-radio-button-${param.parameterCode}`)
.attr('name', 'param-select-radio-input')
.attr('class', 'usa-radio__input')
.property('checked', param => param.selected ? true : null);
paramSelectCol.append('label')
.attr('class', 'usa-radio__label');
paramCdCol.append('span')
.text(param => param.description)
.call(appendTooltip, param => `Parameter code: ${param.parameterCode}`);
tr.append('td')
.append('svg')
.attr('width', SPARK_LINE_DIM.width.toString())
.attr('height', SPARK_LINE_DIM.height.toString());
tr.append('td')
.text(param => `${config.uvPeriodOfRecord[param.parameterCode].begin_date} to ${config.uvPeriodOfRecord[param.parameterCode].end_date}`);
tr.append('td')
.append('a')
.attr('href', param => `${config.WATERALERT_SUBSCRIPTION}/?site_no=${siteno}&parm=${param.parameterCode}`)
.attr('class', 'usa-tooltip')
.attr('data-position', 'left')
.attr('data-classes', 'width-full tablet:width-auto')
.attr('title', 'Subscribe to text or email alerts based on thresholds that you set')
Bucknell, Mary S.
committed
table.property('scrollTop', scrollTop);
table.selectAll('tbody svg').each(function(d) {
const paramCd = d.parameterCode;
const lineSegments = lineSegmentsByParmCd[paramCd] ? lineSegmentsByParmCd[paramCd] : [];
for (const seriesLineSegments of lineSegments) {
selection.call(addSparkLine, {
seriesLineSegments: seriesLineSegments,