Determine country rules by enclosing boundary
This commit is contained in:
parent
3037fb8f17
commit
b5d87fe8d1
3 changed files with 132 additions and 82 deletions
|
|
@ -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;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
1
resources/boundaries/countries.topo.json
Normal file
1
resources/boundaries/countries.topo.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue