Mapbox GL JS getBounds()/fitBounds()
Posted
技术标签:
【中文标题】Mapbox GL JS getBounds()/fitBounds()【英文标题】: 【发布时间】:2016-06-05 19:27:24 【问题描述】:我正在使用 Mapbox GL JS v0.14.2,我已经通过文档进行了高低搜索,对此知之甚少。
如果您使用标准的 JS API,使用他们提供的示例(https://www.mapbox.com/mapbox.js/example/v1.0.0/fit-map-to-markers/)“将地图拟合到标记”非常清楚;但是使用 GL api 时的设置是完全不同的。 GL API 有 getBounds()
(https://www.mapbox.com/mapbox-gl-js/api/#Map.getBounds) 但因为你没有像标准 JS API 这样的命名层,所以我正在努力研究如何使用 getBounds()
。
我找到了这个 (Mapbox GL JS API Set Bounds),但肯定不是正确答案吗?
这是我的大部分设置;不包括 JSON 设置和其他选项。
mapboxgl.accessToken = '<myaccesstoken>';
var markers = <?php echo $programme_json; ?>;
var map = new mapboxgl.Map(
container: 'map',
style: 'mapbox://styles/richgc/cikyo5bse00nqb0lxebkfn2bm',
center: [-1.470085, 53.381129],
zoom: 15
);
map.on('style.load', function()
map.addSource('markers',
'type': 'geojson',
'data': markers
);
map.addLayer(
"id": "markers",
"interactive": true,
"type": "symbol",
"source": "markers",
"layout":
"icon-image": "venue-map-icon-blue",
'icon-size': 0.5,
"icon-allow-overlap": true
);
map.scrollZoom.disable();
);
我尝试了以下方法:
alert(map.getBounds()); // LngLatBounds(LngLat(-1.4855345239256508, 53.37642500812015), LngLat(-1.4546354760740883, 53.38583247227842))
var bounds = [[-1.4855345239256508, 53.37642500812015],[-1.4546354760740883, 53.38583247227842]]
map.fitBounds(bounds);
所以我知道如何拟合边界,但我不确定如何获取它们map.getBounds()
似乎只是返回设置的中心位置 lng/lat。
标记 JSON:
var markers = "type":"FeatureCollection","features":["type":"Feature","properties":"title":"Site Gallery","url":"\/Freelance\/art-sheffield-2016\/programme\/site-gallery\/","summary":"Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Donec id justo. Aenean tellus metus, bibendum sed, posuere ac, mattis non, nunc. Suspendisse feugiat. Etiam rhoncus.","image":"\/Freelance\/art-sheffield-2016\/site\/assets\/files\/1032\/site_gallery.jpg","marker-symbol":"venue-map-icon-blue","colour":"blue","geometry":"type":"Point","coordinates":["-1.466439","53.376842"],"type":"Feature","properties":"title":"Moore Street Substation","url":"\/Freelance\/art-sheffield-2016\/programme\/moore-street-substation\/","summary":"","image":null,"marker-symbol":"venue-map-icon-green","colour":"green","geometry":"type":"Point","coordinates":["-1.477881","53.374798"],"type":"Feature","properties":"title":"S1 Artspace","url":"\/Freelance\/art-sheffield-2016\/programme\/s1-artspace\/","summary":"","image":null,"marker-symbol":"venue-map-icon-red","colour":"red","geometry":"type":"Point","coordinates":["-1.459620","53.380562"]];
【问题讨论】:
"map.getBounds() 似乎只是返回设置的中心位置 lng/lat" 不是返回你的边界框的左下角和右上角坐标吗? 【参考方案1】:改进的解决方案(基于 @timur 解决方案)通过使用 while 循环和 promise 来处理大型数据集
setBounds()
return new Promise((resolve, reject) =>
const bounds = new mapboxgl.LngLatBounds();
let i = 0;
while (i < GEO_JSON.length)
bounds.extend(GEO_JSON[i].geometry.coordinates/OR/Markers_ARRAY);
i++;
if (bounds)
resolve(bounds);
else
reject(`error:$ bounds`);
);
,
fitBoundsToMarkers()
this.setBounds().then((bounds) =>
map.fitBounds(bounds,
padding:
top: 100,
bottom: 100,
left: 100,
right: 100,
,
maxZoom: 14,
);
);
,
【讨论】:
【参考方案2】:如果这里有人使用React-Map-GL,有两个以上的标记,并且想在加载地图和检索 Mapbox 实例之前找出边界,您可以这样做:
const lat = myCoordinatesArray.map(location => parseFloat(location.lat));
const lng = myCoordinatesArray.map(location => parseFloat(location.lng));
// Note that WebMercatorViewport requires this format [lng, lat]
const minCoords = [Math.min.apply(null, lng), Math.min.apply(null, lat)];
const maxCoords = [Math.max.apply(null, lng), Math.max.apply(null, lat)];
const formattedGeoData = [minCoords, maxCoords];
const vPort = new WebMercatorViewport(this.state.viewport).fitBounds(formattedGeoData,
padding: 100
);
const latitude, longitude, zoom = vPort;
源:https://***.com/a/40506115/1259863
您可以在渲染函数之前以构造函数的方式完成所有这些操作,并为插件 init 获取值。
【讨论】:
【参考方案3】:这是我基于来自 Mapbox example 的 reduce 操作的解决方案。
它适用于包含点特征和多点特征(如线)的geojson。
let bounds = geoJSON.features.reduce(function(bounds, feature)
if(!Array.isArray(feature.geometry.coordinates[0])) // point feature
return bounds.extend(feature.geometry.coordinates);
else
return feature.geometry.coordinates.reduce(function(bounds, coord)
return bounds.extend(coord);
, bounds);
, new mapboxgl.LngLatBounds());
map.fitBounds(bounds,
maxZoom: 12,
padding: 30, // in px, to make markers on the top edge visible
)
【讨论】:
如果我将 GeoJson 构建为map.on('load', function() map.addSource('points', 'type': 'geojson', 'data': 'type': 'FeatureCollection', 'features': [
等,我该怎么做【参考方案4】:
有关适用于所有 GeoJSON 对象(而不仅仅是一组标记)的解决方案,请查看 Mapbox 的Turf.js。
这段代码对我很有帮助:https://bl.ocks.org/danswick/83a8ddff7fb9193176a975a02a896792
但只是为了重复基础知识,以防链接失效:
var bounds = turf.bbox(markers);
map.fitBounds(bounds, padding: 20);
链接代码中提到的extent
方法已被bbox
弃用,但结果是一样的。
【讨论】:
【参考方案5】:Mapbox 自己的geojson-extent 插件可以解决问题。假设您的 markers
对象是 valid GeoJSON,您可以简单地将其传递给 geojsonExtent()
函数以获取一组边界,然后您可以将其传递给 fitBounds()
。
一旦您加载了geojson-extent.js 文件(例如,通过在您的html 代码中使用<script>
标记),您应该能够这样做以使您的地图适合您的GeoJSON markers
对象的边界:
map.fitBounds(geojsonExtent(markers));
更新
GeoJSONLint 报告您的 markers
对象不是有效的 GeoJSON,因为每个位置的元素都被解释为字符串,而不是数字。如果您从 lon-lat 坐标中删除引号,它应该可以正常工作:
var markers =
"type": "FeatureCollection",
"features": [
"type": "Feature",
"properties":
"title": "Site Gallery",
"url": "\/Freelance\/art-sheffield-2016\/programme\/site-gallery\/",
"summary": "Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Donec id justo. Aenean tellus metus, bibendum sed, posuere ac, mattis non, nunc. Suspendisse feugiat. Etiam rhoncus.",
"image": "\/Freelance\/art-sheffield-2016\/site\/assets\/files\/1032\/site_gallery.jpg",
"marker-symbol": "venue-map-icon-blue",
"colour": "blue"
,
"geometry":
"type": "Point",
"coordinates": [
-1.466439,
53.376842
]
,
"type": "Feature",
"properties":
"title": "Moore Street Substation",
"url": "\/Freelance\/art-sheffield-2016\/programme\/moore-street-substation\/",
"summary": "",
"image": null,
"marker-symbol": "venue-map-icon-green",
"colour": "green"
,
"geometry":
"type": "Point",
"coordinates": [
-1.477881,
53.374798
]
,
"type": "Feature",
"properties":
"title": "S1 Artspace",
"url": "\/Freelance\/art-sheffield-2016\/programme\/s1-artspace\/",
"summary": "",
"image": null,
"marker-symbol": "venue-map-icon-red",
"colour": "red"
,
"geometry":
"type": "Point",
"coordinates": [
-1.459620,
53.380562
]
]
;
【讨论】:
感谢您的帮助。我在控制台Uncaught Error: Invalid LngLat object: (NaN, 1)
中收到此错误 - 我确实相信它是有效的geoJSON,因为地图正在运行,但我猜markers
返回的不仅仅是坐标,所以也许我只需要将坐标传递到geojsonExtent。
基于这个使用静态地图而不是 GL JS 地图的示例 (mapbox.com/mapbox.js/example/v1.0.0/…),看来我的 geoJSON 是有效的。【参考方案6】:
如果您想使地图适合标记,您可以创建包含所有标记的边界。
var bounds = new mapboxgl.LngLatBounds();
markers.features.forEach(function(feature)
bounds.extend(feature.geometry.coordinates);
);
map.fitBounds(bounds);
【讨论】:
这行得通!无论如何我可以为此添加填充吗? 通常当调用 fitBounds 时,地图会在此边界上添加填充,以防止地图 ui 元素(如缩放加/减按钮、徽标等)与边界重叠。如果您想添加更多的填充,您可以使用map.setZoom(map.getZoom() - 1)
将地图缩小一点,但它看起来像是一个小技巧。
可以使用填充:map.fitBounds(bounds, padding: 100 );
请注意,fitBounds 不适用于单个纬度/经度 - 因此,如果您只有一个标记,您的 bounds
对象将无用(这确实有意义)。
当 FeatureCollection 中的某些几何图形不是点时,这对我来说会中断。使用 turf.js 信封(),这对我有用:map.fitBounds(envelope(myfeaturecollection).bbox)以上是关于Mapbox GL JS getBounds()/fitBounds()的主要内容,如果未能解决你的问题,请参考以下文章
我可以像在(mapbox-gl-js 文档)中那样使用 react-map-gl 添加 GeoJSON 行吗?
mapbox-gl-js 围绕 lat/lng 创建一个扇区?