-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathembed-map-single-year.js
168 lines (150 loc) · 5.37 KB
/
embed-map-single-year.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
var attribution = '<a href="https://www.openhistoricalmap.org/copyright">OpenHistoricalMap</a>';
var stylesByLayer = {
/* Historic */
O: 'https://openhistoricalmap.github.io/map-styles/ohm_timeslider_tegola/tegola-ohm.json',
/* Japanese Scroll */
J: 'https://openhistoricalmap.github.io/map-styles/japanese_scroll/ohm-japanese-scroll-map.json',
/* Woodblock */
W: 'https://openhistoricalmap.github.io/map-styles/woodblock/woodblock.json',
};
addEventListener('load', function () {
let
params = new URLSearchParams(location.hash.substring(1)),
style = stylesByLayer[params.get('layer') || ''] || stylesByLayer.O
;
window.map = new maplibregl.Map({
container: 'map',
hash: 'map',
style: style,
attributionControl: false,
customAttribution: attribution,
});
map.addControl(new maplibregl.NavigationControl(), 'top-left');
map.addControl(new maplibregl.FullscreenControl(), 'top-left');
map.addControl(new maplibregl.AttributionControl({
customAttribution: attribution,
}));
let
markerLongitude = parseFloat(params.get('mlon')),
markerLatitude = parseFloat(params.get('mlat')),
bbox = params.get('bbox')
;
// A bbox is provided in the Share=>HTML generated in ohm-website's side panel. It is used
// for the initial bounding of an embedded map so that the view will be roughly equivalent,
// and then the standard hash mechanism takes over.
if (bbox && bbox.split(',').length === 4) {
let bounds = new maplibregl.LngLatBounds(bbox.split(','));
map.fitBounds(bounds, {duration:0});
}
if (markerLongitude && markerLatitude) {
new maplibregl.Marker()
.setLngLat([markerLongitude, markerLatitude])
.addTo(map);
}
map.once('styledata', function (event) {
filterByDate(map, params.get('date'));
});
addEventListener('hashchange', function (event) {
upgradeLegacyHash();
var oldParams = new URLSearchParams(new URL(event.oldURL).hash.substring(1));
var newParams = new URLSearchParams(new URL(event.newURL).hash.substring(1));
var oldDate = oldParams.get('date');
var newDate = newParams.get('date');
if (oldDate !== newDate) {
filterByDate(map, newDate);
}
});
});
function upgradeLegacyHash() {
var hash = location.hash.substring(1);
if (!hash.includes('=')) {
hash = '#map=' + hash;
}
location.hash = hash;
}
/**
* 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.
*/
function filterByDate(map, date) {
if (date === null || date === '') {
date = new Date().toISOString().split('T')[0];
}
var decimalYear = date && decimalYearFromISODate(date);
if (!decimalYear) return;
map.getStyle().layers.map(function (layer) {
if (!('source-layer' in layer)) return;
var filter = constrainFilterByDate(layer.filter, decimalYear);
map.setFilter(layer.id, filter);
});
}
/**
* 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;
var ymd = isoDate.split('-');
// A negative year results in an extra element at the beginning.
if (ymd[0] === '') {
ymd.shift();
ymd[0] *= -1;
}
var year = +ymd[0];
var date = dateFromUTC(year, +ymd[1] - 1, +ymd[2]);
if (isNaN(date)) return;
// Add the year and the fraction of the date between two New Year’s Days.
var nextNewYear = dateFromUTC(year + 1, 0, 1).getTime();
var lastNewYear = dateFromUTC(year, 0, 1).getTime();
return year + (date.getTime() - lastNewYear) / (nextNewYear - lastNewYear);
}
/**
* 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) {
var 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;
}
/**
* 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) {
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') {
filter[1][2][2] = decimalYear;
}
if (filter[2][2] && filter[2][2][0] === '>=' && filter[2][2][1] === 'end_decdate') {
filter[2][2][2] = decimalYear;
}
return filter;
}
var dateFilter = [
'all',
['any', ['!has', 'start_decdate'], ['<=', 'start_decdate', decimalYear]],
['any', ['!has', 'end_decdate'], ['>=', 'end_decdate', decimalYear]],
];
if (filter) {
dateFilter.push(filter);
}
return dateFilter;
}