Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix periodic domain handling #455

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ import {
import { themeVal } from '../../../styles/utils/general';
import { utcDate, bisectByDate } from '../../../utils/utils';

const getClosestDate = (data, date, timeUnit) => {
// If we're working with a discrete domain, get the closest value.
if (data.length > 2) {
return bisectByDate(data, date, d => utcDate(d));
} else {
const getClosestDate = (data, date, timeUnit, isPeriodic) => {
if (isPeriodic) {
// If we only have start and end, round based on time unit.
if (timeUnit === 'day') {
const h = getHours(date);
Expand All @@ -30,6 +27,9 @@ const getClosestDate = (data, date, timeUnit) => {
? startOfMonth(add(date, { months: 1 }))
: startOfMonth(date);
}
// If we're working with a discrete domain, get the closest value.
} else {
return bisectByDate(data, date, d => utcDate(d));
}
};

Expand Down Expand Up @@ -72,7 +72,7 @@ export default {
.style('pointer-events', 'all')
.on('mouseover', function () {
const xPos = d3.mouse(this)[0];
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit, ctx.props.isPeriodic);
const xPosSnap = ctx.xScale(date);
bisectorG.select('.bisector-interact').style('display', '');
ctx.onInternalAction('bisector.show', { date, x: xPosSnap });
Expand All @@ -83,7 +83,7 @@ export default {
})
.on('mousemove', function () {
const xPos = d3.mouse(this)[0];
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit, ctx.props.isPeriodic);
const xPosSnap = ctx.xScale(date);
const { height } = ctx.getSize();
bisectorG.select('.bisector-interact')
Expand All @@ -95,7 +95,7 @@ export default {
})
.on('click', function () {
const xPos = d3.mouse(this)[0];
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit);
const date = getClosestDate(ctx.props.xDomain, ctx.xScale.invert(xPos), ctx.props.timeUnit, ctx.props.isPeriodic);
ctx.props.onAction('date.set', { date });
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,12 @@ export default {

const dataSeries = dataCanvas.select('.data-extent');

const isDiscrete = props.xDomain.length > 2;

// When we have more than 2 date points, we are showing the individual dates
// When we have non periodic points, we are showing the individual dates
// that are available.
// These are represented as circles. Continuous data is represented as
// a line.
if (isDiscrete) {
dataSeries.selectAll('.line').style('display', 'none');
const points = dataSeries.selectAll('.point').data(props.xDomain);

// Remove old.
points.exit().remove();
// Handle new.
points
.enter()
.append('circle')
.attr('r', 4)
.attr('class', 'point')
.merge(points)
// Update current.
.style('display', '')
.attr('cx', d => xScale(utcDate(d)))
.attr('cy', d => height - 8);
} else {
dataSeries.selectAll('.poin').style('display', 'none');
if (props.isPeriodic) {
dataSeries.selectAll('.point').style('display', 'none');
const dateDomain = xScale.domain();
const lines = dataSeries.selectAll('.line').data([dateDomain]);

Expand All @@ -72,6 +53,23 @@ export default {
.attr('y1', height - 8)
.attr('x2', d => xScale(utcDate(d[1])))
.attr('y2', height - 8);
} else {
dataSeries.selectAll('.line').style('display', 'none');
const points = dataSeries.selectAll('.point').data(props.xDomain);

// Remove old.
points.exit().remove();
// Handle new.
points
.enter()
.append('circle')
.attr('r', 4)
.attr('class', 'point')
.merge(points)
// Update current.
.style('display', '')
.attr('cx', d => xScale(utcDate(d)))
.attr('cy', d => height - 8);
}
}
};
26 changes: 14 additions & 12 deletions app/assets/scripts/components/common/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@ const checkSameDate = (date, compareDate, interval) => {
}
};

const getNextDate = (domain, date, timeUnit) => {
const getNextDate = (domain, date, timeUnit, isPeriodic) => {
// If we only have start and end, round based on time unit.
if (isPeriodic) {
return add(date, getOperationParam(timeUnit));
// If we're working with a discrete domain, get the closest value.
if (domain.length > 2) {
} else {
const currIdx = domain.findIndex(d => isSameDay(d, date));
if (currIdx < 0 || currIdx >= domain.length - 1) return null;
return domain[currIdx + 1];
} else {
// If we only have start and end, round based on time unit.
return add(date, getOperationParam(timeUnit));
}
};

const getPrevDate = (domain, date, timeUnit) => {
const getPrevDate = (domain, date, timeUnit, isPeriodic) => {
// If we only have start and end, round based on time unit.
if (isPeriodic) {
return sub(date, getOperationParam(timeUnit));
// If we're working with a discrete domain, get the closest value.
if (domain.length > 2) {
} else {
const currIdx = domain.findIndex(d => isSameDay(d, date));
if (currIdx <= 0) return null;
return domain[currIdx - 1];
} else {
// If we only have start and end, round based on time unit.
return sub(date, getOperationParam(timeUnit));
}
};

Expand Down Expand Up @@ -161,6 +161,7 @@ class Timeline extends React.Component {
const swatch = layers[0].swatch.color;

const timeUnit = layers[0].timeUnit || 'month';
const isPeriodic = layers[0].isPeriodic || false;

return (
<ExploreDataBrowser>
Expand Down Expand Up @@ -196,7 +197,7 @@ class Timeline extends React.Component {
title='Previous entry'
hideText
onClick={() =>
onAction('date.set', { date: getPrevDate(dateDomain, date, timeUnit) })}
onAction('date.set', { date: getPrevDate(dateDomain, date, timeUnit, isPeriodic) })}
>
Previous entry
</Button>
Expand All @@ -208,7 +209,7 @@ class Timeline extends React.Component {
title='Next entry'
hideText
onClick={() =>
onAction('date.set', { date: getNextDate(dateDomain, date, timeUnit) })}
onAction('date.set', { date: getNextDate(dateDomain, date, timeUnit, isPeriodic) })}
>
Next entry
</Button>
Expand All @@ -222,6 +223,7 @@ class Timeline extends React.Component {
timeUnit={timeUnit}
onAction={onAction}
xDomain={dateDomain}
isPeriodic={isPeriodic}
swatch={swatch}
/>
</DataBrowserBodyScroll>
Expand Down
6 changes: 3 additions & 3 deletions app/assets/scripts/utils/map-explore-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,9 @@ export function toggleLayerCompare (layer) {
}
}

function isDateInDomain (date, domain) {
function isDateInDomain (date, domain, isPeriodic) {
if (!date) return false;
if (domain.length === 2) {
if (isPeriodic) {
// Start and end, check if between dates.
const [s, e] = domain;
return isWithinInterval(date, { start: utcDate(s), end: utcDate(e) });
Expand All @@ -381,7 +381,7 @@ export function toggleLayerRasterTimeseries (layer) {
this.setState(state => {
// Init the timeline date.
const timelineDate = state.timelineDate &&
isDateInDomain(state.timelineDate, layer.domain)
isDateInDomain(state.timelineDate, layer.domain, layer.isPeriodic)
? state.timelineDate
: utcDate(layer.domain[layer.domain.length - 1]);

Expand Down