rs-location/main.mjs

242 lines
7.3 KiB
JavaScript

//
// License: Do whatever you want with it. I'm not liable.
//
import ApiKeys from './lib/rs-module-api-keys.mjs';
import Geocoder from './lib/geocode.mjs';
import initializeSettings from './lib/settings.mjs';
import initializeProfileUpdates from './lib/profile.mjs';
import { showElement, hideElement, renderImage } from './lib/dom-helpers.mjs';
const remoteStorage = new RemoteStorage({ modules: [ApiKeys] });
remoteStorage.access.claim('profile', 'rw');
remoteStorage.access.claim('api-keys', 'rw');
remoteStorage.caching.enable('/profile/');
remoteStorage.caching.enable('/public/profile/');
const widget = new Widget(remoteStorage, {
modalBackdrop: true,
skipInitial: true
});
widget.attach('rs-widget-container');
document.querySelector('.rs-account .disconnect').addEventListener('click', e => {
remoteStorage.disconnect();
});
let data = {
currentUserLocation: {
coords: null,
openCageResult: null
},
currentCity: {
coords: null,
openCageResult: null,
geoJSON: null,
imageBlob: null,
imageObjectURL: null
}
};
data.currentUserLocation = new Proxy(data.currentUserLocation, {
set (obj, prop, value) {
obj[prop] = value;
switch(prop) {
case 'coords':
renderCoordinates();
break;
case 'openCageResult':
renderFormattedResult();
break;
}
return true;
}
});
data.currentCity = new Proxy(data.currentCity, {
set (obj, prop, value) {
obj[prop] = value;
switch(prop) {
case 'coords':
fetchMapImage();
break;
case 'openCageResult':
renderFormattedCityResult();
createGeoJSON();
break;
case 'geoJSON':
break;
case 'imageBlob':
break;
case 'imageObjectURL':
renderMapImage();
break;
}
return true;
}
});
remoteStorage.on('not-connected', () => {
showElement('.view.disconnected');
});
remoteStorage.on('connected', () => {
hideElement('.view.disconnected');
showElement('.view.connected');
document.querySelector('.rs-account .user-address').innerHTML = remoteStorage.remote.userAddress;
initializeSettings(remoteStorage);
initializeProfileUpdates(remoteStorage, data);
});
remoteStorage.on('disconnected', () => {
hideElement('.view.connected');
showElement('.view.disconnected');
});
const geocoder = new Geocoder(remoteStorage);
const mapBoxStyle = 'v1/mapbox/streets-v10'
const imageSize = '260x100@2x'
document.querySelector('button.get-coordinates').addEventListener('click', () => {
console.debug('Getting current/GPS location...');
navigator.geolocation.getCurrentPosition(async position => {
console.debug('Location data:', position);
data.currentUserLocation.coords = {
lat: position.coords.latitude.toFixed(4),
lng: position.coords.longitude.toFixed(4)
};
await geocodeUserLocation();
geocodeNearestCity();
});
})
document.querySelector('form.get-location').addEventListener('submit', e => {
e.preventDefault();
console.debug('Geocoding supplied location...');
geocodeLocationInput().catch(err => window.alert(err));
})
async function geocodeUserLocation () {
console.debug('Geocoding coordinates...');
const { lat, lng } = data.currentUserLocation.coords;
return geocoder.reverse(lat, lng).then(res => {
const result = res.results[0];
console.debug('Result:', result);
data.currentUserLocation.openCageResult = result;
})
}
function geocodeNearestCity () {
console.debug('Geocoding nearest city...');
const result = data.currentUserLocation.openCageResult;
let { city, town, village, hamlet, county } = result.components;
if (!city) { city = town || village || hamlet || county; }
const query = `${city}, ${result.components.state}, ${result.components['ISO_3166-1_alpha-2']}&no_record=1&min_confidence=3`;
return geocoder.geocode(query).then(res => {
const result = res.results[0];
console.debug('Result:', result);
data.currentCity.coords = {
lat: result.geometry.lat.toFixed(4),
lng: result.geometry.lng.toFixed(4)
};
data.currentCity.openCageResult = result;
})
}
function geocodeLocationInput () {
console.debug('Geocoding supplied location...');
const input = document.querySelector('input.location').value;
const query = `${input},&no_record=1&min_confidence=3`;
return geocoder.geocode(query).then(res => {
return new Promise((resolve, reject) => {
const result = res.results[0];
console.debug('Result:', result);
if (result) {
data.currentCity.coords = {
lat: result.geometry.lat.toFixed(4),
lng: result.geometry.lng.toFixed(4)
};
data.currentCity.openCageResult = result;
resolve();
} else {
reject('Nothing found');
}
});
})
}
function createGeoJSON () {
const res = data.currentCity.openCageResult;
const { city, town, village, hamlet, county } = res.components;
data.currentCity.geoJSON = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [res.geometry.lng, res.geometry.lat]
},
"city": city || town || village || hamlet,
"state": res.components.state,
"country": res.components.country,
"timezone": res.annotations.timezone
}
console.debug('Created GeoJSON object:', data.currentCity.geoJSON);
}
async function fetchMapImage () {
const mapBoxToken = await remoteStorage.apiKeys.get('mapbox').then(c => c.token);
const zoomFactor = localStorage.getItem('rs-location:map-zoom-factor');
const { lat, lng } = data.currentCity.coords;
const url = encodeURI(`https://api.mapbox.com/styles/${mapBoxStyle}/static/pin-s-harbor+fff(${lng},${lat})/${lng},${lat},${zoomFactor}/${imageSize}?access_token=${mapBoxToken}`)
console.debug('Fetching map image...');
return fetch(url)
.then(response => response.blob())
.then(imageData => {
const url = URL.createObjectURL(imageData);
data.currentCity.imageBlob = imageData;
data.currentCity.imageObjectURL = url
return fetch(url)
.then(res => res.arrayBuffer())
.then(arrayBuffer => {
data.currentCity.imageArrayBuffer = arrayBuffer;
})
});
}
function renderMapImage () {
const url = data.currentCity.imageObjectURL;
renderImage('section.current-city .map', url, '260x100');
}
function renderCoordinates () {
showElement('section.current-location');
const coordsEl = document.querySelector('section.current-location .coords');
const coords = data.currentUserLocation.coords;
coordsEl.innerHTML = `Latitude: ${coords.lat}<br>Longitude: ${coords.lng}`;
}
function renderFormattedResult () {
const el = document.querySelector('section.current-location .formatted-result');
el.innerHTML = data.currentUserLocation.openCageResult.formatted;
}
function renderFormattedCityResult () {
showElement('section.current-city');
const coordsEl = document.querySelector('section.current-city .coords');
const coords = data.currentCity.coords;
coordsEl.innerHTML = `Latitude: ${coords.lat}<br>Longitude: ${coords.lng}`;
const result = data.currentCity.openCageResult;
const el = document.querySelector('section.current-city .formatted-result');
const { city, town, village, hamlet, county } = result.components;
el.innerHTML = `${city || town || village || hamlet || county}, ${result.components.country}`;
}