b35019c7ce
* Changed my name * Added PHP 7 dependency * Improved translations * Added Spanish translations * Avoid regex pattern for file name * Whitespaces fixed * Optimized code for compressing GPX files * JavaScript code changed for Geo-JSON version 3 and better readability * Added *.map files * Only add done gpx tracks to the total sum * Update event_osm to 0.4.0 * Only add done gpx tracks to the total sum * Added missing *.map files * JavaScript code changed for Geo-JSON version 3 and better readability * Optimized code for compressing GPX files * Whitespaces fixed * Avoid regex pattern for file name * Added Spanish translations * Improved translations * Added PHP 7 dependency * Changed my name --------- Co-authored-by: surrim <root@surrim.org>
192 lines
5.9 KiB
JavaScript
192 lines
5.9 KiB
JavaScript
const dateToColor = date => {
|
|
const minDate = new Date(date.getFullYear(), date.getMonth() - 1, 0);
|
|
const maxDate = new Date(date.getFullYear(), date.getMonth(), 0);
|
|
return "hsl(" + ((date.getTime() - minDate.getTime()) / (maxDate.getTime() - minDate.getTime())).toFixed(3) + "turn, 100%, 50%)";
|
|
};
|
|
|
|
window.addEventListener("load", () => {
|
|
document.querySelectorAll("div.map").forEach(divMap => {
|
|
const popup = document.createElement("div");
|
|
popup.setAttribute("class", "ol-popup");
|
|
const overlay = new ol.Overlay({
|
|
element: popup
|
|
});
|
|
popup.onclick = () => {
|
|
overlay.setPosition(undefined);
|
|
};
|
|
|
|
const dataset = divMap.dataset;
|
|
const articles = geo.articles
|
|
.filter(article => ["all", "none"].includes(dataset.category) || article.categories.includes(parseInt(dataset.category)));
|
|
const tracks = geo.tracks
|
|
.filter(track => dataset.path.split("\n").some(y => track.url.startsWith(y)));
|
|
const features = articles.map((article, id) => {
|
|
const feature = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(article.location.reverse())));
|
|
feature.setId(id);
|
|
return feature;
|
|
});
|
|
|
|
const osmSource = new ol.source.OSM();
|
|
const layers = [
|
|
new ol.layer.Tile({source: osmSource, preload: Infinity}),
|
|
new ol.layer.Vector({
|
|
source: new ol.source.Vector({features: features}),
|
|
style: feature => {
|
|
const id = feature.getId();
|
|
const article = articles[id];
|
|
const date = new Date(article.date * 1000);
|
|
|
|
return new ol.style.Style({
|
|
image: new ol.style.Circle({
|
|
radius: 6,
|
|
fill: new ol.style.Fill({color: dateToColor(date)})
|
|
})
|
|
});
|
|
},
|
|
zIndex: Infinity
|
|
})
|
|
];
|
|
const unixTime = Date.now() / 1000;
|
|
for (const track of tracks) {
|
|
const source = new ol.source.Vector({
|
|
url: track.url,
|
|
format: new ol.format.GPX()
|
|
});
|
|
source.on("featuresloadend", event => {
|
|
track.distance = event.features
|
|
.filter(feature => feature.getGeometry().getType() === "MultiLineString")
|
|
.map(feature => ol.sphere.getLength(feature.getGeometry()))
|
|
.reduce((a, b) => a + b, 0);
|
|
});
|
|
const color = dateToColor(new Date(track.date * 1000));
|
|
const lineDash = track.date > unixTime ? [3, 6] : undefined;
|
|
const layer = new ol.layer.VectorImage({
|
|
source: source,
|
|
style: feature => feature.getGeometry().getType() === "MultiLineString"
|
|
? new ol.style.Style({
|
|
stroke: new ol.style.Stroke({
|
|
color: color,
|
|
width: 3,
|
|
lineDash: lineDash
|
|
})
|
|
})
|
|
: undefined
|
|
});
|
|
layers.push(layer);
|
|
}
|
|
const map = new ol.Map({
|
|
controls: ol.control.defaults.defaults({rotate: false}).extend([
|
|
new ol.control.FullScreen(),
|
|
new ol.control.OverviewMap({
|
|
layers: [
|
|
new ol.layer.Tile({source: osmSource})
|
|
]
|
|
}),
|
|
new ol.control.ScaleLine({
|
|
bar: true,
|
|
minWidth: 120
|
|
})
|
|
]),
|
|
interactions: ol.interaction.defaults.defaults({
|
|
altShiftDragRotate: false,
|
|
pinchRotate: false
|
|
}),
|
|
layers: layers,
|
|
overlays: [overlay],
|
|
target: divMap,
|
|
view: new ol.View({
|
|
center: ol.proj.fromLonLat([dataset.longitude, dataset.latitude]),
|
|
zoom: dataset.zoom
|
|
})
|
|
});
|
|
|
|
map.on("singleclick", event => {
|
|
const makeItem = object => {
|
|
const title = document.createTextNode(object.title);
|
|
const li = document.createElement("li");
|
|
li.appendChild(object.url !== null
|
|
? (() => {
|
|
const a = document.createElement("a");
|
|
a.appendChild(title);
|
|
a.setAttribute("href", object.url);
|
|
a.setAttribute("title",
|
|
(object.author !== undefined ? object.author + ", " : "")
|
|
+
|
|
new Date(object.date * 1000).toLocaleString(undefined, {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "2-digit",
|
|
hour: "2-digit",
|
|
minute: "2-digit"
|
|
})
|
|
+
|
|
(object.distance !== undefined
|
|
? ", " + (object.distance / 1000).toLocaleString(undefined, {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
}) + "km"
|
|
: ""
|
|
)
|
|
);
|
|
return a;
|
|
})()
|
|
: title
|
|
)
|
|
return li;
|
|
};
|
|
|
|
const foundArticles = [];
|
|
const foundTracks = [];
|
|
map.forEachFeatureAtPixel(event.pixel, (feature, layer) => {
|
|
const id = feature.getId();
|
|
if (id !== undefined) {
|
|
foundArticles.push(id);
|
|
} else {
|
|
const url = layer.getSource().getUrl();
|
|
const id = tracks.findIndex(track => track.url === url);
|
|
foundTracks.push(id);
|
|
}
|
|
}, {hitTolerance: 10});
|
|
foundArticles.sort();
|
|
foundTracks.sort();
|
|
|
|
if (foundArticles.length || foundTracks.length) {
|
|
const initUl = title => {
|
|
const ul = document.createElement("ul");
|
|
ul.setAttribute("data-title", title);
|
|
return ul;
|
|
};
|
|
const ulArticles = foundArticles
|
|
.map(x => makeItem(articles[x]))
|
|
.reduce((x, y) => {x.appendChild(y); return x;}, initUl("Articles"));
|
|
const ulTracks = foundTracks
|
|
.map(x => makeItem(tracks[x]))
|
|
.reduce((x, y) => {x.appendChild(y); return x;}, initUl("Tracks"));
|
|
popup.innerHTML = (foundArticles.length ? ulArticles.outerHTML : "") + (foundTracks.length ? ulTracks.outerHTML : "");
|
|
overlay.setPosition(foundArticles.length ? ol.proj.fromLonLat(
|
|
[0, 1].map(latLon => foundArticles
|
|
.map(x => articles[x].location[latLon])
|
|
.reduce((x, y) => x + y, 0) / foundArticles.length
|
|
)
|
|
) : event.coordinate);
|
|
} else {
|
|
overlay.setPosition(undefined);
|
|
}
|
|
});
|
|
map.on("pointermove", event => {
|
|
const pixel = map.getEventPixel(event.originalEvent);
|
|
const hit = map.hasFeatureAtPixel(pixel, {hitTolerance: 10});
|
|
divMap.style.cursor = hit ? "pointer" : "";
|
|
});
|
|
map.on("rendercomplete", event => {
|
|
const distance = tracks
|
|
.filter(track => track.date < unixTime)
|
|
.map(track => track.distance)
|
|
.reduce((a, b) => a + b, 0);
|
|
document.querySelectorAll("span.distance-counter[data-category=\"" + dataset.category + "\"]").forEach(span => {
|
|
span.innerHTML = (distance / 1000).toFixed(0);
|
|
});
|
|
});
|
|
});
|
|
});
|