Geojson AJAX 调用干扰 onEachFeature 函数
Geojson AJAX calls interfere with onEachFeature functions
地图的用途是当用户选择 HTML 输入时,它会提取一个 geojson 文件并将邮政编码信息放置在该州的地图上。然后第二个 geojson 文件将拉出状态边界并将其放在地图上并缩放到该状态。目前我正在尝试通过两次 Geojson AJAX 调用来完成此操作。一个叫做 geojson
,另一个是 statelay
(见下文)。当我只有地图 运行 只有 geojson
对象时,它 运行 很好并且与邮政编码 运行 的交互很顺利。但是,当我添加 statelay
时,交互性不再适用于第一个 geosjon
调用。下面是交互性工作时的样子:https://www.freepropertycalc.com/maps.
具体问题如下:
-为什么在下面添加 statelay
对象会干扰其他 geojson
调用的交互性?
- 我怎样才能简单地从 statelay
获取边界并使地图缩放到那些状态边界?
代码:
<select id="select" >
<option value="">State </option>
<option value="{{url_for('static', filename= 'AK.js' )}}">AK</option>
<option value="{{url_for('static', filename= 'AL.js' )}}">AL</option>
<!-- a whole bunch more states -->
</select>
</div>
<div id="map2" class = "content-section middle toppad" ></div>
<script type="text/javascript">
var state = '/static/state.js';
var select = document.getElementById('select') ;
select.addEventListener('change', function(){
var ourRequest = new XMLHttpRequest();
var strUser = select.options[select.selectedIndex].text;
ourRequest.open('GET',select.value)
ourRequest.onload = function(){
document.getElementById('map2').innerHTML = "<div id='llmap'></div>";
var TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
var MB_ATTR = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
map = L.map('llmap', {});
L.tileLayer(TILE_URL, {attribution: MB_ATTR}).addTo(map);
map.setView(new L.LatLng(38.500000, -98.000000), 4);
function onLocationError(e) {
alert(e.message);
}
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h6>Market Info by ZIP Code</h6>' + (props ?
'<b>' + 'ZIP: ' + props.ZIP + '</b><br />' +
'Median Home Property Value, May 2020: ' + props.valmay2020 + '<br />' +
'Median Home Sale Price, March 2020: ' + props.salemarch2020 + '<br />' +
'Median Rent, April 2020: ' + props.rentapr2020 + ', City Level Only' + '<br / >' +
'1yr. House Value Change: ' + props.chg1yrpropval +'%' + '<br />'
: 'Hover over a ZIP Code');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 400000 ? '#800026' :
d > 300000 ? '#BD0026' :
d > 200000 ? '#E31A1C' :
d > 150000 ? '#FC4E2A' :
d > 100000 ? '#FD8D3C' :
d > 50000 ? '#FEB24C' :
d > 25000 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.valmay2020)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
click: highlightFeature,
mouseout: resetHighlight,
dbblick: zoomToFeature
});
}
var geojson = new L.GeoJSON.AJAX(select.value, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
var statelay = new L.GeoJSON.AJAX(state, {
filter: statefilter
}).addTo(map);
function statefilter(feature) {
if (feature.properties.STUSPS == strUser) return true
}
map.attributionControl.addAttribution('Housing and Rental data © Zillow');
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 25000, 50000, 100000, 150000, 200000, 300000, 400000],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
froml = grades[i]/1000 + 'k';
tol = grades[i +1]/1000 + 'k';
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
froml + (to ? '–' + tol : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
};
ourRequest.send();
});
这很容易修复。
- 您的交互性消失了,因为您在交互性 geojson 之上添加了状态 geojson。两种解决方案:
- 想显示区域/边框时调用
statelay.bringToBack()
- 如果不想显示,请不要将其添加到地图中。从
var statelay = new L.GeoJSON.AJAX(...).addTo(map)
中删除 .addTo(map)
- 缩放到边界:等到加载 geojson 并调用
fitBounds
statelay.on('data:loaded', function() {
map.fitBounds(statelay.getBounds())
})
但是你会遇到缩放到边界的问题,例如 AK
,因为形状不正确(但我无法修复):
这很懒,因为这是一个非常大的文件...所以我建议您使用另一种方法来放大该区域:
缩放到geojson
层的边界,然后在加载交互形状后直接缩放。
geojson.on('data:loaded', function() {
map.fitBounds(geojson.getBounds())
})
地图的用途是当用户选择 HTML 输入时,它会提取一个 geojson 文件并将邮政编码信息放置在该州的地图上。然后第二个 geojson 文件将拉出状态边界并将其放在地图上并缩放到该状态。目前我正在尝试通过两次 Geojson AJAX 调用来完成此操作。一个叫做 geojson
,另一个是 statelay
(见下文)。当我只有地图 运行 只有 geojson
对象时,它 运行 很好并且与邮政编码 运行 的交互很顺利。但是,当我添加 statelay
时,交互性不再适用于第一个 geosjon
调用。下面是交互性工作时的样子:https://www.freepropertycalc.com/maps.
具体问题如下:
-为什么在下面添加 statelay
对象会干扰其他 geojson
调用的交互性?
- 我怎样才能简单地从 statelay
获取边界并使地图缩放到那些状态边界?
代码:
<select id="select" >
<option value="">State </option>
<option value="{{url_for('static', filename= 'AK.js' )}}">AK</option>
<option value="{{url_for('static', filename= 'AL.js' )}}">AL</option>
<!-- a whole bunch more states -->
</select>
</div>
<div id="map2" class = "content-section middle toppad" ></div>
<script type="text/javascript">
var state = '/static/state.js';
var select = document.getElementById('select') ;
select.addEventListener('change', function(){
var ourRequest = new XMLHttpRequest();
var strUser = select.options[select.selectedIndex].text;
ourRequest.open('GET',select.value)
ourRequest.onload = function(){
document.getElementById('map2').innerHTML = "<div id='llmap'></div>";
var TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
var MB_ATTR = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
map = L.map('llmap', {});
L.tileLayer(TILE_URL, {attribution: MB_ATTR}).addTo(map);
map.setView(new L.LatLng(38.500000, -98.000000), 4);
function onLocationError(e) {
alert(e.message);
}
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h6>Market Info by ZIP Code</h6>' + (props ?
'<b>' + 'ZIP: ' + props.ZIP + '</b><br />' +
'Median Home Property Value, May 2020: ' + props.valmay2020 + '<br />' +
'Median Home Sale Price, March 2020: ' + props.salemarch2020 + '<br />' +
'Median Rent, April 2020: ' + props.rentapr2020 + ', City Level Only' + '<br / >' +
'1yr. House Value Change: ' + props.chg1yrpropval +'%' + '<br />'
: 'Hover over a ZIP Code');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 400000 ? '#800026' :
d > 300000 ? '#BD0026' :
d > 200000 ? '#E31A1C' :
d > 150000 ? '#FC4E2A' :
d > 100000 ? '#FD8D3C' :
d > 50000 ? '#FEB24C' :
d > 25000 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.valmay2020)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
click: highlightFeature,
mouseout: resetHighlight,
dbblick: zoomToFeature
});
}
var geojson = new L.GeoJSON.AJAX(select.value, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
var statelay = new L.GeoJSON.AJAX(state, {
filter: statefilter
}).addTo(map);
function statefilter(feature) {
if (feature.properties.STUSPS == strUser) return true
}
map.attributionControl.addAttribution('Housing and Rental data © Zillow');
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 25000, 50000, 100000, 150000, 200000, 300000, 400000],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
froml = grades[i]/1000 + 'k';
tol = grades[i +1]/1000 + 'k';
labels.push(
'<i style="background:' + getColor(from + 1) + '"></i> ' +
froml + (to ? '–' + tol : '+'));
}
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
};
ourRequest.send();
});
这很容易修复。
- 您的交互性消失了,因为您在交互性 geojson 之上添加了状态 geojson。两种解决方案:
- 想显示区域/边框时调用
statelay.bringToBack()
- 如果不想显示,请不要将其添加到地图中。从
var statelay = new L.GeoJSON.AJAX(...).addTo(map)
中删除
.addTo(map)
- 缩放到边界:等到加载 geojson 并调用
fitBounds
statelay.on('data:loaded', function() {
map.fitBounds(statelay.getBounds())
})
但是你会遇到缩放到边界的问题,例如 AK
,因为形状不正确(但我无法修复):
这很懒,因为这是一个非常大的文件...所以我建议您使用另一种方法来放大该区域:
缩放到geojson
层的边界,然后在加载交互形状后直接缩放。
geojson.on('data:loaded', function() {
map.fitBounds(geojson.getBounds())
})