按类别选择标记和适合可见标记的范围

Posted

技术标签:

【中文标题】按类别选择标记和适合可见标记的范围【英文标题】:select markers by category AND fitbounds to visible markers 【发布时间】:2016-04-30 16:37:31 【问题描述】:

我有一个代码用于按类别切换标记的可见性,效果很好(见下面的代码)。

我现在想添加但不知道如何添加:

每次显示/隐藏标记组后,我希望调整地图的缩放和中心以显示所有可见标记。 我找到了fitBounds() 的另一个代码,但没有设法让两者一起工作(我对javascript 完全陌生)。

我发现了仅将边界拟合到可见标记的示例,但没有与按类别显示/隐藏标记结合使用。 (例如Center/Set Zoom of Map to cover all visible Markers?)

这里是两个代码示例:

按类别显示/隐藏标记:

function xmlParse(str) 
    if (typeof ActiveXObject != 'undefined' && typeof GetObject != 'undefined') 
        var doc = new ActiveXObject('Microsoft.XMLDOM');
        doc.loadXML(str);
        return doc;
    

    if (typeof DOMParser != 'undefined') 
        return (new DOMParser()).parseFromString(str, 'text/xml');
    

    return createElement('div', null);

var infoWindow = new google.maps.InfoWindow();
var customIcons = 
    monumento: 
        icon: 'http://maps.google.com/mapfiles/ms/icons/blue.png'
    ,
    hotel: 
        icon: 'http://maps.google.com/mapfiles/ms/icons/green.png'
    ,
    restaurantes: 
        icon: 'http://maps.google.com/mapfiles/ms/icons/yellow.png'
    ,
    museus: 
        icon: 'http://maps.google.com/mapfiles/ms/icons/purple.png'
    
;

var markerGroups = 
    "museus": [],
    "monumentos": [],
    "restaurantes": [],
    "hotel": []
;

function load() 
    var map = new google.maps.Map(document.getElementById("mapCanvas"), 
        center: new google.maps.LatLng(38.639104, -8.210413),
        zoom: 12,
        mapTypeId: 'satellite'
    );
    var infoWindow = new google.maps.InfoWindow();



    map.set('styles', [
        zoomControl: false
    , 
        featureType: "road.highway",
        elementType: "geometry.fill",
        stylers: [
            color: "#ffd986"
        ]
    , 
        featureType: "road.arterial",
        elementType: "geometry.fill",
        stylers: [
            color: "#9e574f"
        ]
    , 
        featureType: "road.local",
        elementType: "geometry.fill",
        stylers: [
                color: "#d0cbc0"
            , 
                weight: 1.1
            

        ]
    , 
        featureType: 'road',
        elementType: 'labels',
        stylers: [
            saturation: -100
        ]
    , 
        featureType: 'landscape',
        elementType: 'geometry',
        stylers: [
            hue: '#ffff00'
        , 
            gamma: 1.4
        , 
            saturation: 82
        , 
            lightness: 96
        ]
    , 
        featureType: 'poi.school',
        elementType: 'geometry',
        stylers: [
            hue: '#fff700'
        , 
            lightness: -15
        , 
            saturation: 99
        ]
    ]);

    //         downloadUrl("markers.xml", function (data) 
    var xml = xmlParse('<markers><marker name="Castelo" address="Rua da Condessa de Valença" lat="38.64351973190569" lng="-8.216521812152905" type="monumento" /><marker name="Anta 1 de Tourais" address="Estrada Nacional 114" lat="38.64260059929888" lng="-8.159376865959189" type="monumento" /><marker name="Hotel da Ameira" address="Herdade da Ameira" lat="38.64109640475479" lng="-8.180432206726096" type="hotel" /><marker name="Hotel Montemor" address="Avenida Gago Coutinho 8, 7050-248 Montemor-o-Novo" lat="38.64925541964039" lng="-8.216489625644726" type="hotel" /><marker name="Restaurante Monte Alentejano" address="Av. Gago Coutinho 8" lat="38.6492329" lng="-8.216665" type="restaurantes" /><marker name="Restaurante A Ribeira" address="Rua de São Domingos" lat="38.6347498199708" lng="-8.206468892765088" type="restaurantes" /><marker name="Núcleo Museológico do Convento de S. Domingos" address="" lat="38.643139" lng="-8.212732" type="museus" /><marker name="Centro Interpretativo do Castelo de Montemor-o-Novo" address="Rua Condessa de Valença" lat="38.64258748216167" lng="-8.21467108793263" type="museus" /></markers>');
    // var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) 
        var name = markers[i].getAttribute("name");
        var address = markers[i].getAttribute("address");
        var type = markers[i].getAttribute("type");

        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var html = "<b>" + name + "</b> <br/>" + address;
        // var icon = customIcons[type] || ;
        var marker = createMarker(point, name, address, type, map);
        bindInfoWindow(marker, map, infoWindow, html);
    
    // );


function createMarker(point, name, address, type, map) 
    var icon = customIcons[type] || ;
    var marker = new google.maps.Marker(
        map: map,
        position: point,
        icon: icon.icon,
        // shadow: icon.shadow,
        type: type
    );
    if (!markerGroups[type]) markerGroups[type] = [];
    markerGroups[type].push(marker);
    var html = "<b>" + name + "</b> <br/>" + address;
    bindInfoWindow(marker, map, infoWindow, html);
    return marker;


function toggleGroup(type) 
    for (var i = 0; i < markerGroups[type].length; i++) 
        var marker = markerGroups[type][i];
        if (!marker.getVisible()) 
            marker.setVisible(true);
         else 
            marker.setVisible(false);
        
    



function bindInfoWindow(marker, map, infoWindow, html) 
    google.maps.event.addListener(marker, 'click', function() 
        infoWindow.setContent(html);
        infoWindow.open(map, marker);

    );


function downloadUrl(url, callback) 
    var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

    request.onreadystatechange = function() 
        if (request.readyState == 4) 
            request.onreadystatechange = doNothing;
            callback(request, request.status);
        
    ;

    request.open('GET', url, true);
    request.send(null);


function doNothing() 
google.maps.event.addDomListener(window, 'load', load);

fitBounds() 到可见标记:

function fitBoundsToVisibleMarkers() 

   var bounds = new google.maps.LatLngBounds();

   for (var i = 0; i < markers.length; i++) 
       if (markers[i].getVisible()) 
           bounds.extend(markers[i].getPosition());
       
   

   map.fitBounds(bounds);

【问题讨论】:

Center/Set Zoom of Map to cover all markers visible Markers? 的可能重复项。另外,您能否使用这些示例创建一个 sn-p 或 bin,以便我们为您提供帮助? 嗨 Mosh Feu,谢谢您的评论!这是第一个代码的 jsfiddle:jsfiddle.net/YEPB7/6 这有帮助吗? 【参考方案1】:

你的代码有问题:

    您遇到错误:Uncaught TypeError: map.fitBounds is not a function。那是因为您需要在函数load 之外设置map 变量。 您需要收集所有可见标记,然后对它们运行map.fitBounds

工作代码:

function xmlParse(str) 
  if (typeof ActiveXObject != 'undefined' && typeof GetObject != 'undefined') 
    var doc = new ActiveXObject('Microsoft.XMLDOM');
    doc.loadXML(str);
    return doc;
  

  if (typeof DOMParser != 'undefined') 
    return (new DOMParser()).parseFromString(str, 'text/xml');
  

  return createElement('div', null);

var infoWindow = new google.maps.InfoWindow();
var customIcons = 
  monumento: 
    icon: 'http://maps.google.com/mapfiles/ms/icons/blue.png'
  ,
  hotel: 
    icon: 'http://maps.google.com/mapfiles/ms/icons/green.png'
  ,
  restaurantes: 
    icon: 'http://maps.google.com/mapfiles/ms/icons/yellow.png'
  ,
  museus: 
    icon: 'http://maps.google.com/mapfiles/ms/icons/purple.png'
  
;

var markerGroups = 
  "museus": [],
  "monumentos": [],
  "restaurantes": [],
  "hotel": []
;

var ctr = new google.maps.LatLng(38.639104, -8.210413),
    zoom = 12;

var map;
function load() 
  map = new google.maps.Map(document.getElementById("map"), 
    center: ctr,
    zoom: zoom,
    mapTypeId: 'roadmap'
  );

  var infoWindow = new google.maps.InfoWindow();

  map.set('styles', [
    zoomControl: false
  , 
    featureType: "road.highway",
    elementType: "geometry.fill",
    stylers: [
      color: "#ffd986"
    ]
  , 
    featureType: "road.arterial",
    elementType: "geometry.fill",
    stylers: [
      color: "#9e574f"
    ]
  , 
    featureType: "road.local",
    elementType: "geometry.fill",
    stylers: [
      color: "#d0cbc0"
    , 
      weight: 1.1
    ]
  , 
    featureType: 'road',
    elementType: 'labels',
    stylers: [
      saturation: -100
    ]
  , 
    featureType: 'landscape',
    elementType: 'geometry',
    stylers: [
      hue: '#ffff00'
    , 
      gamma: 1.4
    , 
      saturation: 82
    , 
      lightness: 96
    ]
  , 
    featureType: 'poi.school',
    elementType: 'geometry',
    stylers: [
      hue: '#fff700'
    , 
      lightness: -15
    , 
      saturation: 99
    ]
  ]);

  //         downloadUrl("markers.xml", function (data) 
  var xml = xmlParse('<markers><marker name="Castelo" address="Rua da Condessa de Valença" lat="38.64351973190569" lng="-8.216521812152905" type="monumento" /><marker name="Anta 1 de Tourais" address="Estrada Nacional 114" lat="38.64260059929888" lng="-8.159376865959189" type="monumento" /><marker name="Hotel da Ameira" address="Herdade da Ameira" lat="38.64109640475479" lng="-8.180432206726096" type="hotel" /><marker name="Hotel Montemor" address="Avenida Gago Coutinho 8, 7050-248 Montemor-o-Novo" lat="38.64925541964039" lng="-8.216489625644726" type="hotel" /><marker name="Restaurante Monte Alentejano" address="Av. Gago Coutinho 8" lat="38.6492329" lng="-8.216665" type="restaurantes" /><marker name="Restaurante A Ribeira" address="Rua de São Domingos" lat="38.6347498199708" lng="-8.206468892765088" type="restaurantes" /><marker name="Núcleo Museológico do Convento de S. Domingos" address="" lat="38.643139" lng="-8.212732" type="museus" /><marker name="Centro Interpretativo do Castelo de Montemor-o-Novo" address="Rua Condessa de Valença" lat="38.64258748216167" lng="-8.21467108793263" type="museus" /></markers>');
  // var xml = data.responseXML;
  var markers = xml.documentElement.getElementsByTagName("marker");
  for (var i = 0; i < markers.length; i++) 
    var name = markers[i].getAttribute("name");
    var address = markers[i].getAttribute("address");
    var type = markers[i].getAttribute("type");

    var point = new google.maps.LatLng(
      parseFloat(markers[i].getAttribute("lat")),
      parseFloat(markers[i].getAttribute("lng")));
    var html = "<b>" + name + "</b> <br/>" + address;
    // var icon = customIcons[type] || ;
    var marker = createMarker(point, name, address, type, map);
    bindInfoWindow(marker, map, infoWindow, html);
  
  // );
  //fitMap();


function createMarker(point, name, address, type, map) 
  var icon = customIcons[type] || ;
  var marker = new google.maps.Marker(
    map: map,
    position: point,
    icon: icon.icon,
    // shadow: icon.shadow,
    type: type,
    visible:false
  );
  if (!markerGroups[type]) markerGroups[type] = [];
  markerGroups[type].push(marker);
  var html = "<b>" + name + "</b> <br/>" + address;
  bindInfoWindow(marker, map, infoWindow, html);
  return marker;


function toggleGroup(type) 
  for (var i = 0; i < markerGroups[type].length; i++) 
    var marker = markerGroups[type][i];
    if (!marker.getVisible()) 
      marker.setVisible(true);
     else 
      marker.setVisible(false);
    
  

  if (document.querySelectorAll(':checked').length == 0) 
    map.setCenter(ctr);
    map.setZoom(zoom);
  
  else 
    fitMap();
  



function fitMap() 
  var visibleMarkers = [];
  for (var i in markerGroups) 
    for (var j = 0; j < markerGroups[i].length; j++) 
      var marker = markerGroups[i][j];
      if (marker.getVisible()) 
        visibleMarkers.push(marker);
      
    
  

  var bounds = new google.maps.LatLngBounds();
  for (var i = 0; i < visibleMarkers.length; i++) 
    bounds.extend(visibleMarkers[i].getPosition());
  

  map.fitBounds(bounds);  


function bindInfoWindow(marker, map, infoWindow, html) 
  google.maps.event.addListener(marker, 'click', function () 
    infoWindow.setContent(html);
    infoWindow.open(map, marker);
  );


function downloadUrl(url, callback) 
  var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

  request.onreadystatechange = function () 
    if (request.readyState == 4) 
      request.onreadystatechange = doNothing;
      callback(request, request.status);
    
  ;

  request.open('GET', url, true);
  request.send(null);


function doNothing() 
google.maps.event.addDomListener(window, 'load', load);
html, body, #map, #map_wrap 
  height: 100%;
  width:100%;
<script src="https://maps.googleapis.com/maps/api/js?v=3&ext=.js"></script>
<div class="map_wrap">
  <div class="siderbarmap">
    <ul>
      <input id="monumentoCheckbox" type="checkbox" onclick="toggleGroup('monumento')" />
      <input id="museusCheckbox" type="checkbox" onclick="toggleGroup('museus')"  />
      <input id="restaurantesCheckbox" type="checkbox" onclick="toggleGroup('restaurantes')" />
      <input id="hotelCheckbox" type="checkbox" onclick="toggleGroup('hotel')" />
    </ul>
  </div>
  <div id="map" style="width:100%;height:585px; z-index: 1;"></div>
</div>

更新:

    我稍微更改了代码,所以现在找到可见标记的函数是独立的,因此我们可以在页面加载和复选框更改后调用它(现在在对要求 2 的注释中。要使用它,只需删除评论//)。 在用户单击checkbox 之后,在开始时没有一个markers 可见 如果所有复选框都不是:checked,则地图将重置为起点zoomcenter

【讨论】:

我的荣幸!祝你好运! 嗨 Mosh Feu,另一个问题:现在它仅在第一次单击类别后才适合可见标记的边界,而不是在页面加载时。我需要改变什么才能在一开始就调整地图大小?也许您可以帮助我添加另一个小补充:如果我希望标记在开始时隐藏并且仅在选中复选框时切换可见,我需要添加/更改什么? 我刚刚更新了我的答案。一个思考点:第一个请求与第二个冲突。因为如果没有任何标记可见,您将无法根据它们将map 居中。 谢谢,我现在看到了问题。另外,如果我取消选中所有这些,地图以海洋为中心......你认为当所有标记都不可见时,是否可以将起始缩放和中心设置为 latlang?【参考方案2】:

它只需要对您的 toggleGroup 功能稍作调整。此时您已经设置了标记的可见性;只需在此处添加几行即可将这些可见标记添加到 LatLngBounds 对象。然后在调整完所有标记后,更新地图以适应新的边界。

function toggleGroup(type) 
    var bounds = new google.maps.LatLngBounds();

    for (var i = 0; i < markerGroups[type].length; i++) 
        var marker = markerGroups[type][i];
        if (!marker.getVisible()) 
            marker.setVisible(true);
            bounds.extend(marker.getPosition());
         else 
            marker.setVisible(false);
        
    

    map.fitBounds(bounds);

您唯一需要做的另一件事是使您的 map 变量成为全局变量;现在它只是 load() 函数的本地函数。

【讨论】:

以上是关于按类别选择标记和适合可见标记的范围的主要内容,如果未能解决你的问题,请参考以下文章

如何在定义的范围内显示标记?

sql SQL按类别,标记或发布格式选择发布数据

如何居中/设置地图缩放以覆盖 Xamarin.Forms 上可见的所有标记?

SVG 标记方向箭头出现在 DOM 中,但标记本身不可见

设置可见后标记簇没有改变

在 google_maps_flutter 中获取可见标记