如何从地图外部与传单标记层进行交互?
Posted
技术标签:
【中文标题】如何从地图外部与传单标记层进行交互?【英文标题】:How to interact with leaflet marker layer from outside the map? 【发布时间】:2012-10-11 20:06:00 【问题描述】:我有一张传单地图,显示公共艺术作品的点,从GeoJSON 渲染。在地图旁边,我使用相同的 GeoJSON 数据创建了一个片段列表,并且希望能够单击地图外部列表中的一个项目,并在地图上显示相关标记的弹出窗口。
如何通过点击事件将项目列表链接到它们各自的标记?
我的 map.js 文件如下所示:
var map;
var pointsLayer;
$(document).ready(function ()
map = new L.Map('mapContainer');
var url = 'http://s.tiles.mapbox.com/v3/mapbox.mapbox-streets/z/x/y.png';
var copyright = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade';
var tileLayer = new L.TileLayer(url,
attribution: copyright
);
var startPosition = new L.LatLng(41.883333, - 87.633333);
map.on('load', function (e)
requestUpdatedPoints(e.target.getBounds())
);
map.setView(startPosition, 13).addLayer(tileLayer);
map.on('moveend', function (e)
requestUpdatedPoints(e.target.getBounds())
)
);
function requestUpdatedPoints(bounds)
$.ajax(
type: 'GET',
url: '/SeeAll',
dataType: 'json',
data: JSON.stringify(bounds),
contentType: 'application/json; charset=utf-8',
success: function (result)
parseNewPoints(result);
addToList(result)
,
error: function (req, status, error)
alert('what happen? did you lose conn. to server ?')
)
function addToList(data)
for (var i = 0; i < data.features.length; i++)
var art = data.features[i];
$('div#infoContainer').append('<a href="#" class="list-link" title="' + art.properties.descfin + '"><div class="info-list-item">' + '<div class="info-list-txt">' + '<div class="title">' + art.properties.wrknm + '</div>' + '<br />' + art.properties.location + '</div>' + '<div class="info-list-img">' + art.properties.img_src + '</div>' + '<br />' + '</div></a>')
$('a.list-link').click(function (e)
alert('now you see what happens when you click a list item!');
e.preventDefault()
)
function parseNewPoints(data)
if (pointsLayer != undefined)
map.removeLayer(pointsLayer)
pointsLayer = new L.GeoJSON();
var geojsonMarkerOptions =
radius: 8,
fillColor: "#FF6788",
color: "YELLOW",
weight: 1,
opacity: 1,
fillOpacity: 0.5
;
L.geoJson(data,
pointToLayer: function (feature, latlng)
return L.circleMarker(latlng, geojsonMarkerOptions)
,
onEachFeature: function (feature, pointsLayer)
pointsLayer.bindPopup(feature.properties.img_src + "<br />" + feature.properties.wrknm + "<br />" + feature.properties.artist + "<br />" + feature.properties.location + '<div class="description">' + feature.properties.descfin + '</div>')
).addTo(map)
【问题讨论】:
我会创建一个哈希映射identifier -> marker
,然后在您单击某个项目时按 ID 查找标记。
【参考方案1】:
Felix Kling 是对的,但我会稍微扩展他的评论......
由于 L.LayerGroup 和 L.FeatureGroup(从 L.GeoJSON 扩展而来)没有检索各个图层的方法,因此您需要从 L.GeoJSON 扩展并添加这样的方法,或者保留您自己的单独映射从 GeoJSON 到 CircleMarker 的唯一 ID。
GeoJSON 不需要唯一 ID,但我假设您的提要中的标记具有称为“id”的唯一 ID 属性。您需要将此唯一 ID 添加到用户可以单击的链接中,以便链接可以选择地图上的正确标记。然后,您需要将 id 映射存储到标记,以便检索标记以在地图上选择它。
markerMap = ; // a global variable unless you extend L.GeoJSON
// Add the marker id as a data item (called "data-artId") to the "a" element
function addToList(data)
for (var i = 0; i < data.features.length; i++)
var art = data.features[i];
$('div#infoContainer').append('<a href="#" class="list-link" data-artId=\"'+art.id+'\" title="' + art.properties.descfin + '"><div class="info-list-item">' + '<div class="info-list-txt">' + '<div class="title">' + art.properties.wrknm + '</div>' + '<br />' + art.properties.location + '</div>' + '<div class="info-list-img">' + art.properties.img_src + '</div>' + '<br />' + '</div></a>')
$('a.list-link').click(function (e)
alert('now you see what happens when you click a list item!');
//Get the id of the element clicked
var artId = $(this).data( 'artId' );
var marker = markerMap[artId];
//since you're using CircleMarkers the OpenPopup method requires
//a latlng so I'll just use the center of the circle
marker.openPopup(marker.getLatLng());
e.preventDefault()
)
当您从服务器获取数据时,您需要构建markerMap。您的 pointToLayer 方法可以修改为:
L.geoJson(data,
pointToLayer: function (feature, latlng)
var marker = new L.CircleMarker( latlng, geojsonMarkerOptions );
markerMap[feature.id] = marker;
return marker;
,...
【讨论】:
这是一个非常有用的解释。感谢您抽出宝贵时间。 我想知道使用当前最新版本的 LeafletJS 是否有更简单的方法。 我知道这已经很晚了,但我在下面添加了一个答案,使用最新版本的 Leaflet 中的方法来实现同样的目标。【参考方案2】:我知道这是一个较老的问题,但 Leaflet 是 on it's way 提供内置解决方案,并且现在有一种(某种)内置方式来实现它......
方法是使用layerGroup
接口。它提供了一个方法,getLayer
,这听起来就像使用 ID 获取我们的标记是完美的。但是,目前,Leaflet不提供任何方式来指定自定义 ID 或名称。
Github 上的 issue 讨论了应该如何做到这一点。话虽如此,您可以像这样获取并保存任何标记(或iLayer
)的自动生成的ID:
let people = [...],
group = L.layerGroup()
people.forEach(person =>
let marker = // ... create marker
group.addLayer( marker );
person.marker_id = group.getLayerId(marker)
)
现在我们已经将每个标记的 ID 与数据数组中的每个支持对象一起保存,我们可以稍后轻松地获取标记,如下所示:
group.getLayer(person.marker_id)
完整示例请参见this pen,更多选项请参见this question...
【讨论】:
从那以后有关于这个功能的消息吗? 似乎没有,不幸的是,我链接的问题现已关闭(尽管您可以看到正在进行一些讨论)。我自己目前使用的传单不多,但我添加了comment 来强调需要并希望能激发更多的活动。 @SirBeethoven 我建议您订阅该线程(并可能在您的用例中添加评论)。以上是关于如何从地图外部与传单标记层进行交互?的主要内容,如果未能解决你的问题,请参考以下文章