diff --git a/package-lock.json b/package-lock.json index 488cf84c..f1846d01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@material/mwc-top-app-bar": "^0.27.0", "@material/web": "^1.4.0", "@mdi/js": "^7.4.47", + "@openhistoricalmap/maplibre-gl-dates": "^1.2.1", "@types/leaflet": "^1.9.12", "d3": "^7.8.2", "d3-array": "^3.2.4", @@ -3677,6 +3678,15 @@ "lit-html": "^1.0.0" } }, + "node_modules/@openhistoricalmap/maplibre-gl-dates": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@openhistoricalmap/maplibre-gl-dates/-/maplibre-gl-dates-1.2.1.tgz", + "integrity": "sha512-I1hgLTcrRn6FrnyhS2hCYwTe4filNsJ+xbe3eXOH5RJGrsq2XufowMVWWl011fakd5liBXE8Cu7ELw1mcUafBA==", + "license": "CC0-1.0", + "peerDependencies": { + "maplibre-gl": ">=3.0.0" + } + }, "node_modules/@popperjs/core": { "version": "2.11.7", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", @@ -19700,6 +19710,12 @@ "lit-html": "^1.0.0" } }, + "@openhistoricalmap/maplibre-gl-dates": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@openhistoricalmap/maplibre-gl-dates/-/maplibre-gl-dates-1.2.1.tgz", + "integrity": "sha512-I1hgLTcrRn6FrnyhS2hCYwTe4filNsJ+xbe3eXOH5RJGrsq2XufowMVWWl011fakd5liBXE8Cu7ELw1mcUafBA==", + "requires": {} + }, "@popperjs/core": { "version": "2.11.7", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", diff --git a/package.json b/package.json index 5318ee8b..81be6062 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "@material/mwc-top-app-bar": "^0.27.0", "@material/web": "^1.4.0", "@mdi/js": "^7.4.47", + "@openhistoricalmap/maplibre-gl-dates": "^1.2.1", "@types/leaflet": "^1.9.12", "d3": "^7.8.2", "d3-array": "^3.2.4", @@ -126,4 +127,4 @@ "pwa-helpers": "^0.9.1", "tippy.js": "^6.3.7" } -} \ No newline at end of file +} diff --git a/src/components/GrampsjsMap.js b/src/components/GrampsjsMap.js index 1f0b3916..b95cd575 100644 --- a/src/components/GrampsjsMap.js +++ b/src/components/GrampsjsMap.js @@ -2,9 +2,10 @@ import {html, LitElement} from 'lit' import 'leaflet' import 'maplibre-gl' import '@maplibre/maplibre-gl-leaflet' +import '@openhistoricalmap/maplibre-gl-dates' import './GrampsjsMapOverlay.js' import './GrampsjsMapMarker.js' -import {fireEvent, filterByDecimalYear} from '../util.js' +import {fireEvent} from '../util.js' import '../LocateControl.js' const {L} = window @@ -136,7 +137,7 @@ class GrampsjsMap extends LitElement { if (this._currentLayer === 'OpenHistoricalMap') { const mapLibreMap = this._gl.getMaplibreMap() mapLibreMap.on('styledata', () => - filterByDecimalYear(mapLibreMap, this.year) + mapLibreMap.filterByDate(`${this.year}`) ) } fireEvent(this, 'map:layerchange', {layer: this._currentLayer}) @@ -159,7 +160,7 @@ class GrampsjsMap extends LitElement { this.year > 0 && this._currentLayer === 'OpenHistoricalMap' ) { - filterByDecimalYear(this._gl.getMaplibreMap(), this.year) + this._gl.getMaplibreMap().filterByDate(`${this.year}`) return } if ( diff --git a/src/util.js b/src/util.js index 2e7c416a..fbf2c8ab 100644 --- a/src/util.js +++ b/src/util.js @@ -611,123 +611,6 @@ export function linkUrls(text, textOnly = true) { )}` } -// OpenHistoricalMap functions - -/** - * Returns a `Date` object representing the given UTC date components. - * - * @param year A one-based year in the proleptic Gregorian calendar. - * @param month A zero-based month. - * @param day A one-based day. - * @returns A date object. - */ -function dateFromUTC(year, month, day) { - const date = new Date(Date.UTC(year, month, day)) - // Date.UTC() treats a two-digit year as an offset from 1900. - date.setUTCFullYear(year) - return date -} - -/** - * Converts the given ISO 8601-1 date to a decimal year. - * - * @param isoDate A date string in ISO 8601-1 format. - * @returns A floating point number of years since year 0. - */ -function decimalYearFromISODate(isoDate) { - // Require a valid YYYY, YYYY-MM, or YYYY-MM-DD date, but allow the year - // to be a variable number of digits or negative, unlike ISO 8601-1. - if (!isoDate || !/^-?\d{1,4}(?:-\d\d){0,2}$/.test(isoDate)) return undefined - - const ymd = isoDate.split('-') - // A negative year results in an extra element at the beginning. - if (ymd[0] === '') { - ymd.shift() - ymd[0] *= -1 - } - const year = +ymd[0] - const date = dateFromUTC(year, +ymd[1] - 1, +ymd[2]) - if (Number.isNaN(date)) return undefined - - // Add the year and the fraction of the date between two New Year’s Days. - const nextNewYear = dateFromUTC(year + 1, 0, 1).getTime() - const lastNewYear = dateFromUTC(year, 0, 1).getTime() - return year + (date.getTime() - lastNewYear) / (nextNewYear - lastNewYear) -} - -/** - * Returns a modified version of the given filter that only evaluates to - * true if the feature coincides with the given decimal year. - * - * @param filter The original layer filter. - * @param decimalYear The decimal year to filter by. - * @returns A filter similar to the given filter, but with added conditions - * that require the feature to coincide with the decimal year. - */ -function constrainFilterByDate(filter, decimalYear) { - const newFilter = filter - if (filter && filter[0] === 'all' && filter[1] && filter[1][0] === 'any') { - if ( - filter[1][2] && - filter[1][2][0] === '<' && - filter[1][2][1] === 'start_decdate' - ) { - newFilter[1][2][2] = decimalYear + 1 - } - if ( - newFilter[2][2] && - newFilter[2][2][0] === '>=' && - newFilter[2][2][1] === 'end_decdate' - ) { - newFilter[2][2][2] = decimalYear - } - return newFilter - } - - const dateFilter = [ - 'all', - ['any', ['!has', 'start_decdate'], ['<', 'start_decdate', decimalYear + 1]], - ['any', ['!has', 'end_decdate'], ['>=', 'end_decdate', decimalYear]], - ] - if (filter) { - dateFilter.push(filter) - } - return dateFilter -} - -/** - * Filters the map’s features by the `date` data attribute. - * - * @param map The MapboxGL map object to filter the style of. - * @param year The numeric ear to filter by - */ -export function filterByDecimalYear(map, decimalYear) { - // eslint-disable-next-line array-callback-return - map.getStyle().layers.map(layer => { - if (!('source-layer' in layer)) return - - const filter = constrainFilterByDate(map.getFilter(layer.id), decimalYear) - map.setFilter(layer.id, filter) - }) -} - -/** - * Filters the map’s features by the `date` data attribute. - * - * @param map The MapboxGL map object to filter the style of. - * @param date The date to filter by in YYYY-MM-DD format. - */ -export function filterByDate(map, dateP) { - let date = dateP - if (date === null || date === '') { - ;[date] = new Date().toISOString().split('T') - } - const decimalYear = date && decimalYearFromISODate(date) - if (!decimalYear) return - - filterByDecimalYear(map, decimalYear) -} - export function getGregorianYears(date) { const MOD_TEXTONLY = 6 if (