Skip to content

Commit

Permalink
Fall back to start_date and end_date
Browse files Browse the repository at this point in the history
  • Loading branch information
1ec5 committed Aug 6, 2024
1 parent 2451ee1 commit 1f005ff
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 68 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ The stylesheet must be backed by a vector tileset, such as [OpenHistoricalMap’

Property | Type | Description
----|----|----
`start_decdate` | Number | The date the feature came into existence in decimal year format.
`end_decdate` | Number | The date the feature went out of existence in decimal year format.
`start_date` | String | The date the feature came into existence as a date string.
`start_decdate` | Number | The date the feature came into existence as a decimal year.
`end_date` | String | The date the feature went out of existence as a date string.
`end_decdate` | Number | The date the feature went out of existence as a decimal year.

Decimal year format is defined as a floating-point number in the proleptic Gregorian calendar, such that each integer represents midnight on New Year’s Day. As there is no Year Zero, the value 1.0 falls on New Year’s Day of 1 CE, the value 0.0 falls on 1 BCE, the value -1.0 falls on 2 BCE, etc. An implementation of decimal year conversion functions is available [for PL/pgSQL ](https://github.com/OpenHistoricalMap/DateFunctions-plpgsql/).
A date string is a date in `YYYY`, `YYYY-MM`, or `YYYY-MM-DD` format, similar to ISO 8601-1 format. A decimal year is a floating-point number such that each integer represents midnight on New Year’s Day. An implementation of decimal year conversion functions is available [for PL/pgSQL](https://github.com/OpenHistoricalMap/DateFunctions-plpgsql/).

All properties are optional, but the plugin will only have an effect if one or more of these properties is present in the tileset. For performance reasons, if a given feature has a `start_decdate` or `end_decdate` property, this plugin prefers it over the `start_date` or `end_date` property.

Regardless of the data type, all dates are interpreted according to the proleptic Gregorian calendar. As there is no Year Zero, the value 1.0 falls on New Year’s Day of 1 CE, the value 0.0 falls on 1 BCE, the value -1.0 falls on 2 BCE, etc.

## Installation

Expand Down Expand Up @@ -73,7 +79,7 @@ Parameter | Type | Description
----|----|----
`date` | `Date` or date string | The date to filter by.

A date string is defined as a date in `YYYY`, `YYYY-MM`, or `YYYY-MM-DD` format, similar to ISO 8601-1 format. Negative years are supported as described in “[Requirements](#requirements)”.
A date string is defined as a date in `YYYY`, `YYYY-MM`, or `YYYY-MM-DD` format, similar to ISO 8601-1 format. If the date is only given to year precision, every feature overlapping that year is included; likewise, if the date is given to month precision, every feature overlapping that month is included. Negative years are supported as described in “[Requirements](#requirements)”.

## Feedback

Expand Down
162 changes: 125 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ function dateRangeFromDate(date) {
let dateRange;
if (typeof date === 'string') {
dateRange = dateRangeFromISODate(date);
} else if (date instanceof Date) {
let decimalYear = !isNaN(date) && decimalYearFromDate(date);
} else if (date instanceof Date && !isNaN(date)) {
let decimalYear = decimalYearFromDate(date);
let isoDate = date.toISOString().split('T')[0];
dateRange = {
startDate: date,
startDecimalYear: decimalYear,
startISODate: isoDate,
endDate: date,
endDecimalYear: decimalYear,
endISODate: isoDate,
};
}
return dateRange;
Expand Down Expand Up @@ -84,8 +87,10 @@ function dateRangeFromISODate(isoDate) {
return {
startDate: !isNaN(startDate) && startDate,
startDecimalYear: !isNaN(startDate) && decimalYearFromDate(startDate),
startISODate: !isNaN(startDate) && startDate.toISOString().split('T')[0],
endDate: !isNaN(endDate) && endDate,
endDecimalYear: !isNaN(endDate) && decimalYearFromDate(endDate),
endISODate: !isNaN(endDate) && endDate.toISOString().split('T')[0],
};
}

Expand Down Expand Up @@ -152,12 +157,27 @@ function constrainFilterByDateRange(filter, dateRange) {
* previously been passed into this function, it surgically updates the filter.
*/
function constrainLegacyFilterByDateRange(filter, dateRange) {
if (filter[0] === 'all' && filter[1] && filter[1][0] === 'any') {
if (filter[1][2] && filter[1][2][0] === '<' && filter[1][2][1] === 'start_decdate') {
filter[1][2][2] = dateRange.endDecimalYear;
if (filter[0] === 'all' &&
filter[2] && filter[1][0] === 'any' && filter[2][0] === 'any') {
if (filter[1][1] && filter[1][1][0] === 'all' &&
filter[1][1][2] && filter[1][1][2][0] === '<' &&
filter[1][1][2][1] === 'start_decdate') {
filter[1][1][2][2] = dateRange.endDecimalYear;
}
if (filter[2][2] && filter[2][2][0] === '>=' && filter[2][2][1] === 'end_decdate') {
filter[2][2][2] = dateRange.startDecimalYear;
if (filter[1][2] && filter[1][2][0] === 'all' &&
filter[1][2][2] && filter[1][2][2][0] === '<' &&
filter[1][2][2][1] === 'start_date') {
filter[1][2][2][2] = dateRange.endISODate;
}
if (filter[2][1] && filter[2][1][0] === 'all' &&
filter[2][1][2] && filter[2][1][2][0] === '>=' &&
filter[2][1][2][1] === 'end_decdate') {
filter[2][1][2][2] = dateRange.startDecimalYear;
}
if (filter[2][2] && filter[2][2][0] === 'all' &&
filter[2][2][2] && filter[2][2][2][0] === '>=' &&
filter[2][2][2][1] === 'end_date') {
filter[2][2][2][2] = dateRange.startISODate;
}
return filter;
}
Expand All @@ -166,13 +186,39 @@ function constrainLegacyFilterByDateRange(filter, dateRange) {
'all',
[
'any',
['!has', 'start_decdate'],
['<', 'start_decdate', dateRange.endDecimalYear]
[
'all',
['has', 'start_decdate'],
['<', 'start_decdate', dateRange.endDecimalYear],
],
[
'all',
['has', 'start_date'],
['<', 'start_date', dateRange.endISODate],
],
[
'all',
['!has', 'start_decdate'],
['!has', 'start_date'],
],
],
[
'any',
['!has', 'end_decdate'],
['>=', 'end_decdate', dateRange.startDecimalYear]
[
'all',
['has', 'end_decdate'],
['>=', 'end_decdate', dateRange.startDecimalYear],
],
[
'all',
['has', 'end_date'],
['>=', 'end_date', dateRange.startISODate],
],
[
'all',
['!has', 'end_decdate'],
['!has', 'end_date'],
],
],
filter,
];
Expand All @@ -191,44 +237,64 @@ function constrainLegacyFilterByDateRange(filter, dateRange) {
*/
function constrainExpressionFilterByDateRange(filter, dateRange) {
const startDecimalYearVariable = `${variablePrefix}__startDecimalYear`;
const startISODateVariable = `${variablePrefix}__startISODate`;
const endDecimalYearVariable = `${variablePrefix}__endDecimalYear`;
const endISODateVariable = `${variablePrefix}__endISODate`;
if (filter[0] === 'let') {
let startVariableIndex = filter.indexOf(startDecimalYearVariable);
if (startVariableIndex !== -1 && startVariableIndex % 2 === 1) {
filter[startVariableIndex + 1] = dateRange.startDecimalYear;
} else {
filter.splice(-1, 0, startDecimalYearVariable, dateRange.startDecimalYear);
}

let endVariableIndex = filter.indexOf(endDecimalYearVariable);
if (endVariableIndex !== -1 && endVariableIndex % 2 === 1) {
filter[endVariableIndex + 1] = dateRange.endDecimalYear;
} else {
filter.splice(-1, 0, endDecimalYearVariable, dateRange.endDecimalYear);
}

updateVariable(filter, startDecimalYearVariable, dateRange.startDecimalYear);
updateVariable(filter, startISODateVariable, dateRange.startISODate);
updateVariable(filter, endDecimalYearVariable, dateRange.endDecimalYear);
updateVariable(filter, endISODateVariable, dateRange.endISODate);
return filter;
}

let allExpression = [
'all',
[
'any',
['!', ['has', 'start_decdate']],
['<', ['get', 'start_decdate'], ['var', endDecimalYearVariable]]
[
'all',
['has', 'start_decdate'],
['<', ['get', 'start_decdate'], ['var', endDecimalYearVariable]],
],
[
'all',
['has', 'start_date'],
['<', ['get', 'start_date'], ['var', endISODateVariable]],
],
[
'all',
['!', ['has', 'start_decdate']],
['!', ['has', 'start_date']]
],
],
[
'any',
['!', ['has', 'end_decdate']],
['>=', ['get', 'end_decdate'], ['var', startDecimalYearVariable]]
[
'all',
['has', 'end_decdate'],
['>=', ['get', 'end_decdate'], ['var', startDecimalYearVariable]],
],
[
'all',
['has', 'end_decdate'],
['>=', ['get', 'end_date'], ['var', startISODateVariable]],
],
[
'all',
['!', ['has', 'end_decdate']],
['!', ['has', 'end_date']]
],
],
filter,
];

return [
'let',
startDecimalYearVariable, dateRange.startDecimalYear,
startISODateVariable, dateRange.startISODate,
endDecimalYearVariable, dateRange.endDecimalYear,
endISODateVariable, dateRange.endISODate,
allExpression,
];
}
Expand Down Expand Up @@ -285,19 +351,41 @@ function isLegacyFilter(filter) {
}
}

/**
* Mutates a `let` expression to have a new value for the variable by the given
* name.
*
* @param letExpression A `let` expression.
* @param name The name of the variable to mutate.
* @param newValue The variable’s new value.
*/
function updateVariable(letExpression, name, newValue) {
if (letExpression[0] !== 'let') {
return;
}

let variableIndex = letExpression.indexOf(name);
if (variableIndex !== -1 && variableIndex % 2 === 1) {
letExpression[variableIndex + 1] = newValue;
} else {
letExpression.splice(-1, 0, name, newValue);
}
}

if (typeof window !== 'undefined' && 'maplibregl' in window) {
maplibregl.Map.prototype.filterByDate = function (date) {
filterByDate(this, date);
};
} else if (typeof module !== 'undefined') {
module.exports = {
filterByDate: filterByDate,
dateRangeFromDate: dateRangeFromDate,
decimalYearFromDate: decimalYearFromDate,
dateRangeFromISODate: dateRangeFromISODate,
constrainFilterByDateRange: constrainFilterByDateRange,
constrainLegacyFilterByDateRange: constrainLegacyFilterByDateRange,
constrainExpressionFilterByDateRange: constrainExpressionFilterByDateRange,
isLegacyFilter: isLegacyFilter,
filterByDate,
dateRangeFromDate,
decimalYearFromDate,
dateRangeFromISODate,
constrainFilterByDateRange,
constrainLegacyFilterByDateRange,
constrainExpressionFilterByDateRange,
isLegacyFilter,
updateVariable,
};
}
Loading

0 comments on commit 1f005ff

Please sign in to comment.