Determine country rules by enclosing boundary

This commit is contained in:
Norbert Renner 2021-01-23 12:43:13 +01:00
parent 3037fb8f17
commit b5d87fe8d1
3 changed files with 132 additions and 82 deletions

View file

@ -150,6 +150,10 @@ BR.Util = {
} }
// fallback when country not available // fallback when country not available
return lang[0] === language; if (language) {
return lang[0] === language;
}
return false;
}, },
}; };

View file

@ -2,11 +2,13 @@ BR.CircleGoArea = L.Control.extend({
circleLayer: null, circleLayer: null,
boundaryLayer: null, boundaryLayer: null,
outsideAreaRenderer: L.svg({ padding: 1 }), outsideAreaRenderer: L.svg({ padding: 1 }),
countries: null,
states: null, states: null,
statesLoading: false,
options: { options: {
radius: 1000, // in meters radius: 1000, // in meters
stateRules: false, countriesUrl: BR.conf.countriesUrl || 'dist/boundaries/countries.topo.json',
statesUrl: BR.conf.statesUrl || 'dist/boundaries/germany-states.topo.json', statesUrl: BR.conf.statesUrl || 'dist/boundaries/germany-states.topo.json',
overpassBaseUrl: BR.conf.overpassBaseUrl || 'https://overpass-api.de/api/interpreter?data=', overpassBaseUrl: BR.conf.overpassBaseUrl || 'https://overpass-api.de/api/interpreter?data=',
shortcut: { shortcut: {
@ -58,16 +60,22 @@ BR.CircleGoArea = L.Control.extend({
], ],
}); });
if (this.options.stateRules) { this.drawButton.disable();
this.drawButton.disable(); this.once(
this._loadStates( 'countries:loaded',
L.bind(function () { function () {
this.drawButton.enable(); this.drawButton.enable();
if (this.marker && !this.marker.dragging.enabled()) { if (this.marker && !this.marker.dragging.enabled()) {
this.marker.dragging.enable(); this.marker.dragging.enable();
} }
}, this) },
); this
);
this._loadCountries();
// preload states in parallel, before clicked country is known, using browser language as indicator
if (BR.Util.isCountry('DE')) {
this._loadStates();
} }
map.on('routing:draw-start', function () { map.on('routing:draw-start', function () {
@ -126,17 +134,11 @@ BR.CircleGoArea = L.Control.extend({
var url = this.options.overpassBaseUrl + encodeURIComponent(query); var url = this.options.overpassBaseUrl + encodeURIComponent(query);
this.marker.setIcon(this.iconSpinner); this.marker.setIcon(this.iconSpinner);
BR.Util.get( BR.Util.getJson(
url, url,
L.bind(function (err, data) { 'boundary for coordinate "' + center + '"',
if (err) { L.bind(function (err, osmJson) {
BR.message.showError('Error getting boundary for coordinate "' + center + '": ' + err); if (!err) {
return;
}
try {
var osmJson = JSON.parse(data);
if (osmJson.elements.length === 0) { if (osmJson.elements.length === 0) {
if (adminLevel === 8 || adminLevel === 7) { if (adminLevel === 8 || adminLevel === 7) {
// admin_level 6 (kreisfreie Stadt) // admin_level 6 (kreisfreie Stadt)
@ -150,14 +152,9 @@ BR.CircleGoArea = L.Control.extend({
var geoJson = osmtogeojson(osmJson); var geoJson = osmtogeojson(osmJson);
this._setBoundary(geoJson); this._setBoundary(geoJson);
this.marker.setIcon(this.icon);
} catch (err) {
BR.message.showError('Error parsing boundary: ' + err);
console.error(err);
} finally {
this.marker.setIcon(this.icon);
} }
this.marker.setIcon(this.icon);
}, this) }, this)
); );
}, },
@ -196,21 +193,29 @@ BR.CircleGoArea = L.Control.extend({
this.setOutsideArea(ring); this.setOutsideArea(ring);
}, },
_getState: function (center) { _getPolygonForPoint: function (center, featureCollection) {
var state = null; var polygon = null;
var point = turf.point(center); var point = turf.point(center);
var features = this.states.features; var features = featureCollection.features;
for (var i = 0; i < features.length; i++) { for (var i = 0; i < features.length; i++) {
var feature = features[i]; var feature = features[i];
var inside = turf.booleanPointInPolygon(point, feature); var inside = turf.booleanPointInPolygon(point, feature);
if (inside) { if (inside) {
state = feature; polygon = feature;
break; break;
} }
} }
return state; return polygon;
},
_getState: function (center) {
return this._getPolygonForPoint(center, this.states);
},
_getCountry: function (center) {
return this._getPolygonForPoint(center, this.countries);
}, },
_applyStateRules: function (center) { _applyStateRules: function (center) {
@ -244,6 +249,42 @@ BR.CircleGoArea = L.Control.extend({
} }
}, },
_applyCountryRules: function (center) {
var country = this._getCountry(center);
if (country) {
var name = country.properties.name;
if (name === 'Germany') {
this.options.radius = 15000;
if (!this.states) {
this.marker.setIcon(this.iconSpinner);
this.once(
'states:loaded',
function () {
this.marker.setIcon(this.icon);
if (this.states) {
this._applyStateRules(center);
}
},
this
);
this._loadStates();
} else {
this._applyStateRules(center);
}
} else if (name === 'Metropolitan France') {
this.options.radius = 20000;
this._setNogoCircle(center);
} else {
console.error('unhandled country: ' + name);
}
} else {
// TODO message: no rules implemented for this location
}
},
// debugging // debugging
_logStates: function (states) { _logStates: function (states) {
for (var i = 0; i < states.features.length; i++) { for (var i = 0; i < states.features.length; i++) {
@ -255,19 +296,22 @@ BR.CircleGoArea = L.Control.extend({
}, },
// debugging // debugging
_addStatesLayer: function (states) { _addGeoJsonLayer: function (states, options) {
// delay, otherwise triggers premature hash update through mapmove // delay, otherwise triggers premature hash update through mapmove
setTimeout( setTimeout(
L.bind(function () { L.bind(function () {
L.geoJson(states, { L.geoJson(states, {
style: function (feature) { style: function (feature) {
return { return L.extend(
weight: 1, {
color: 'navy', weight: 1,
opacity: 0.8, color: 'navy',
fill: false, opacity: 0.8,
interactive: false, fill: false,
}; interactive: false,
},
options
);
}, },
}).addTo(this.map); }).addTo(this.map);
}, this), }, this),
@ -275,22 +319,41 @@ BR.CircleGoArea = L.Control.extend({
); );
}, },
_loadStates: function (cb) { _loadStates: function () {
if (this.statesLoading) return;
this.statesLoading = true;
BR.Util.getGeoJson( BR.Util.getGeoJson(
this.options.statesUrl, this.options.statesUrl,
'states', 'states',
L.bind(function (err, data) { L.bind(function (err, data) {
// TODO spinner aus?, mit ringgo parameter testen if (!err) {
this.states = data;
// debugging
//this._logStates(this.states);
//this._addGeoJsonLayer(this.states);
}
this.statesLoading = false;
this.fire('states:loaded');
}, this)
);
},
_loadCountries: function () {
BR.Util.getGeoJson(
this.options.countriesUrl,
'countries',
L.bind(function (err, data) {
if (err) return; if (err) return;
this.states = data; this.countries = data;
// debugging // debugging
//this._logStates(this.states); //this._addGeoJsonLayer(this.countries, { color: 'darkgreen', opacity: 1 });
//this._addStatesLayer(this.states);
this.fire('states:loaded'); this.fire('countries:loaded');
cb();
}, this) }, this)
); );
}, },
@ -318,23 +381,19 @@ BR.CircleGoArea = L.Control.extend({
this._removeNogo(); this._removeNogo();
if (center) { if (center) {
if (this.options.stateRules) { if (!this.countries) {
if (!this.states) { // wait for countries to be loaded (when circlego hash parameter without polylines)
// wait for states to be loaded (when circlego hash parameter without polylines) this.marker.setIcon(this.iconSpinner);
this.marker.setIcon(this.iconSpinner); this.once(
this.once( 'countries:loaded',
'states:loaded', function () {
function () { this.marker.setIcon(this.icon);
this._applyStateRules(center); this._applyCountryRules(center);
this.marker.setIcon(this.icon); },
}, this
this );
);
} else {
this._applyStateRules(center);
}
} else { } else {
this._setNogoCircle(center); this._applyCountryRules(center);
} }
} }
}, },
@ -420,8 +479,8 @@ BR.CircleGoArea = L.Control.extend({
this.clear(); this.clear();
marker.addTo(this.circleLayer); marker.addTo(this.circleLayer);
if (this.options.stateRules && !this.states) { // prevent editing (when called by hash) until countries are loaded, see _loadCountries call in onAdd
// prevent editing (when called by hash) until states are loaded, see _loadStates call in onAdd if (!this.countries) {
marker.dragging.disable(); marker.dragging.disable();
} }
@ -531,19 +590,5 @@ BR.CircleGoArea = L.Control.extend({
BR.CircleGoArea.include(L.Evented.prototype); BR.CircleGoArea.include(L.Evented.prototype);
BR.circleGoArea = function (routing, nogos, pois) { BR.circleGoArea = function (routing, nogos, pois) {
var circleGo = null; return new BR.CircleGoArea(routing, nogos, pois);
var options = {};
if (BR.Util.isCountry('FR', 'fr')) {
options.radius = 20000;
} else if (BR.Util.isCountry('DE', 'de')) {
options.radius = 15000;
options.stateRules = true;
}
if (options) {
circleGo = new BR.CircleGoArea(routing, nogos, pois, options);
}
return circleGo;
}; };

File diff suppressed because one or more lines are too long