为传单中的标记分配 ID

Posted

技术标签:

【中文标题】为传单中的标记分配 ID【英文标题】:Assign ID to marker in leaflet 【发布时间】:2014-10-30 06:55:50 【问题描述】:

所以我尝试在foursquare上实现结果:https://foursquare.com/explore?cat=drinks&mode=url&near=Paris,当您单击地图上的标记时,它会滚动屏幕右侧列出的餐厅到临时餐厅,并通过 CSS 突出显示。相反,当您单击列表中的餐厅时,它会在地图上突出显示它。

我正在使用 skobbler/传单。我想我可以通过动态修改 CSS 来实现这一点,如下例所示:http://jsfiddle.net/gU4sw/7/ + 滚动到页面中已经存在的目标脚本。

然而,为了实现这一点,看起来我需要在标记内分配一个 ID(下面的 2 个标记):

var marker = L.marker([52.52112, 13.40554]).addTo(map);
marker.bindPopup("Hello world!<br>I am a popup1.",  offset: new L.Point(-1, -41) ).openPopup();

var marker = L.marker([52.53552, 13.41994]).addTo(map);
marker.bindPopup("Hello world!<br>I am a popup2.",  offset: new L.Point(-1, -41) ).openPopup();

问题是:如何分配标记 ID 以触发我的 html 页面中相应元素的 css 更改?

我对 JS 的了解非常有限,但可能有一个很好且简单的解决方案,谢谢

【问题讨论】:

知道我在这里很晚了,但您必须为每个标记提供一个 ID,如@markoletic 的回答中所述。同样在您的代码中,您的第二个标记会覆盖第一个标记,因为您将它们保存到相同的var marker。我在下面添加了更详细的答案。 【参考方案1】:

就我而言,我发现最好的方法是在创建 L.marker 的 Options 对象时生成唯一 ID 并将其传递给它。

const newMarker = L.marker([lat, lng],  uniqueID )

然后您可以将此标记添加到传单layerGroup

const newLayerGroup = L.layerGroup().addTo(map);
newLayerGroup.addLayer(newMarker);

您可以使用layer.options.uniqueID 访问 ID,这使我可以稍后查找和操作标记;我只需要 Leaflet 的 .eachLayer() 和 uniqueID。

我的后端(Cloud Firestore)已经生成了唯一的文档 ID,这使得实时同步我的 Leaflet 地图和后端变得非常容易,而不是重建和重新安装整个 layerGroup 或刷新页面。

//e.g. a callback which fires whenever a doc has been removed from my db

newLayerGroup.eachLayer((layer) => 
  if (deletedDocID === layer.options.uniqueID) 
    newLayerGroup.removeLayer(layer);
  
);

【讨论】:

【参考方案2】:

1.) 让我们创建具有唯一 ID 的标记...

L.marker([marker.lat, marker.lng],customID:'some ID',title:marker.title).on('click', this.markerClick).addTo(mymap);

2.) 转到 node_modules@types\leaflet\index.d.ts 并添加 customID?:string;

export interface MarkerOptions extends InteractiveLayerOptions 
    icon?: Icon | DivIcon;
    title?: string;

    ....

    autoPanSpeed?: number;
    customID:string;

3.) 在同一个文件中将 customID 添加到 LeafletMouseEvent

export interface LeafletMouseEvent extends LeafletEvent 
  latlng: LatLng;
  layerPoint: Point;
  containerPoint: Point;
  originalEvent: MouseEvent;
  customID:customID

4.) 创建 customID 类

export class customID 
  constructor(customID: string);
  customID: number;
 

5.) 在函数中获取您的标记 id

markerClick(e)
  console.log(e.sourceTarget.options.customID)

【讨论】:

【参考方案3】:

在传单地图对象中创建可点击标记数组的一种相当直接且简单的方法是通过向每个标记添加自定义递增类名称来操作已创建标记的类列表。然后很容易创建一个侦听器并知道单击了哪个标记。通过跳过或不跳过活动的,每个都有一个具有可靠 ID 的可检索点击事件。

  // creates markers, each with a leaflet supplied class
  if (length === 1) 
    for (i = 0; i < parks.length; ++i) 
      if (parks[i].parksNumber !== parks.parksNumber)
        L.marker([parks[i].latitude, parks[i].longitude], 
          icon: parks[i].iconMarker
        ).addTo(mymap);
    
  

  // select all of the leaflet supplied class
  let markers = document.querySelectorAll(".leaflet-marker-icon");

  // loop through those elements and first assign the indexed custom class
  for (i = 0; i < markers.length; ++i) 
    markers[i].classList.add("marker_" + parks[i].parksNumber);

    // then add a click listener to each one
    markers[i].addEventListener("click", e => 

      // pull the class list
      let id = String(e.target.classList);

      // pull your unique ID from the list, be careful cause this list could 
      // change orientation,  if so loop through and find it
      let parksNumber = id.split(" ");
      parksNumber = parksNumber[parksNumber.length - 1].replace("marker_", "");

      // you have your unique identifier to then do what you want with
      search_Number_input.value = parksNumber;
      HandleSearch();
    );
  

【讨论】:

【参考方案4】:
var MarkerIcon = L.Icon.extend(
    options: 
        customId: "",
        shadowUrl: 'leaf-shadow.png',
        iconSize: [64, 64],
        shadowSize: [50, 64],
        iconAnchor: [22, 94],
        shadowAnchor: [4, 62],
        popupAnchor: [-3, -76]
    
);

var greenIcon = new MarkerIcon(iconUrl: "/resources/images/marker-green.png"),            
    redIcon = new MarkerIcon(iconUrl: "/resources/images/marker-red.png"),
    orangeIcon = new MarkerIcon(iconUrl: "/resources/images/marker-orange.png");

var mymap = L.map('mapid').setView([55.7522200, 37.6155600], 13);

L.tileLayer('https://api.tiles.mapbox.com/v4/id/z/x/y.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', 
    maxZoom: 18,
    id: 'mapbox.streets'
).addTo(mymap);

// добавить маркер
L.marker([55.7522200, 37.6155600], customId:"010000006148", icon: greenIcon, title:setMarkerTitle("010000006148")).addTo(mymap).on('click', markerOnClick);
L.marker([55.7622200, 37.6155600], customId:"010053166625", icon: redIcon, title: setMarkerTitle("010053166625")).addTo(mymap).on('click', markerOnClick);

function markerOnClick(e) 
    var customId = this.options.customId;
    document.location.href = "/view/abonents/" + customId;


function setMarkerTitle(customId)
    var result = customId;
    result += "\nline2 ";
    result += "\nline3 ";
    return result;

【讨论】:

最好的方法是扩展基础L.Icon类,添加一个新字段,在本例中为字段customId,然后您可以访问此字段类似于this.options.customId【参考方案5】:

我一直在寻找一种很好的方法来做到这一点,据我所知,仍然没有内置的方法(使用传单)给标记一个 ID。 我知道我回答这个问题有点晚了,但希望它能帮助其他偶然发现这个问题的人。据我所知,这里有两个主要问题:

问题 #1: 除非您将标记保存到对象或地图中,如下所述,否则以后没有简单的编程方式可以访问它们。例如 - 用户在地图外单击与地图内标记相对应的内容。

问题 2: 当用户单击地图内部的标记时,没有内置方法可以检索该标记的 ID,然后使用它来突出显示相应的元素或触发地图外部的操作。

解决方案

使用其中一个或多个选项将有助于解决上述问题。我将从上一个答案中提到的那个开始。这是working pen,它包含下面找到的所有代码。

选项 #1: 使用硬编码或动态 ID 将每个标记保存在对象内 -

// Create or retrieve the data
var data = [
    
      name: 'Bob',
      latLng: [41.028, 28.975],
      id: '2342fc7'
    , ..., ...
];

// Add an object to save markers
var markers = ;

// Loop through the data
for (var i = 0; i < data.length; i++) 
  var person = data[i];

  // Create and save a reference to each marker
  markers[person.id] = L.marker(person.latLng, 
    ...
  ).addTo(map);

与其他答案类似,您现在可以使用 - 访问单个标记

var marker = markers.2342fc7; // or markers['2342fc7']

选项 #2:

虽然传单没有为标记提供内置的“id”选项,但您可以通过访问._icon 属性直接将 ID 添加到元素:

// Create and save a reference to each marker
markers[person.id] = L.marker(person.latLng, ...).addTo(map);

// Add the ID
markers[person.id]._icon.id = person.id;

现在,当您处理点击事件时,很容易获得该标记的 ID:

$('.leaflet-marker-icon').on('click', function(e) 
   // Use the event to find the clicked element
   var el = $(e.srcElement || e.target),
       id = el.attr('id');

    alert('Here is the markers ID: ' + id + '. Use it as you wish.')
);

选项 #3:

另一种方法是使用layerGroup 接口。它提供了一种方法,getLayer,听起来使用 ID 获取我们的标记是完美的。但是,目前,Leaflet 不提供任何方式来指定自定义 ID 或名称。 Github 上的 issue 讨论了应该如何做到这一点。但是,您可以像这样获取并保存任何标记(或iLayer)的自动生成 ID:

var group = L.layerGroup()

people.forEach(person => 
    // ... create marker
    group.addLayer( marker );
    person.marker_id = group.getLayerId(marker)
)

现在我们已经将每个标记的 ID 与数据数组中的每个支持对象一起保存,我们可以稍后轻松地获取标记,如下所示:

group.getLayer(person.marker_id)

完整示例请参见this pen...

选项 #4:

如果您有时间,最简洁的方法是扩展传单的标记类以干净地处理您的个人需求。您可以向选项添加 id 或将自定义 HTML 插入具有您的 id/class 的标记中。有关更多信息,请参阅documentation。

您也可以使用circleMarker,在path options 中,您会看到有一个className 选项,可以很好地设置相似标记组的样式。

样式:

几乎忘记了您最初的问题是为了造型而提出的......只需使用 ID 来访问各个元素:

.leaflet-marker-icon#2342fc7  ... 

结论

我还将提到图层和功能组提供了另一种与标记交互的好方法。这是一个question,稍微讨论了这个问题。随意修改或分叉first 或second pen,如果我遗漏了什么,请发表评论。

【讨论】:

【参考方案6】:

Leaflet 的className option 可以允许向对象添加标识符:

var onMouseover = function() 
  // returns all members of the specified class
  d3.selectAll(".mySpecialClass")
    .style("opacity", ".1");
;

// add desired class to pointer 
L.circleMarker([46.85, 2.35], className: "mySpecialClass")
  .addTo(map).on('mouseover', onMouseover);

// to select the marker(s) with a particular class, just use css selectors
// here's a d3.js solution
d3.selectAll(".mySpecialClass")
  .style("opacity", ".3")

【讨论】:

但是,您能否提供代码以通过className 进行过滤和选择? 当然,我更新了上面的代码。只需使用 css 选择器来定位给定元素,并使用您提供的类名来定位特定元素。这是一个示例:earlyeuropeanbooks.github.io(点击条形时,我们会从所有与给定条形没有关联的类的标记中移除不透明度)【参考方案7】:

一种简单的方法是将所有标记添加到具有唯一 ID 的列表中。

var markersObject = ;
markersObject["id1"] = marker1;
markersObject["id2"] = marker2;
markersObject["id3"] = marker3;

如果餐厅列表在单个餐厅的 html 元素中具有与添加的标记的 id 对应的属性。比如:

<a href="#" id="singleRestaurantItem" data-restaurantID="id1" data-foo="bar">Click</a>

然后添加点击事件,您将在其中传递餐厅的 ID(在本例中为“data-restaurantID”)并执行以下操作:

markersObject["passedValueFromTheClickedElement"].openPopup();

这样,一旦您单击列表中的项目,将打开一个标记弹出窗口,指示餐厅在地图上的位置。

【讨论】:

谢谢marko,我提供的JS代码有两个标记,我怎么知道哪个是marker1和marker2?

以上是关于为传单中的标记分配 ID的主要内容,如果未能解决你的问题,请参考以下文章

单击反应传单 v.3.x 中的标记时如何动态更改地图缩放?

在传单中的标记之间画线

使折线捕捉到传单中的道路

R小册子中的标记鼠标点击事件有光泽

以编程方式触发 R 传单中的标记鼠标单击事件以实现闪亮

如何在传单中的两个标记之间添加路线(折线)