javascript - 如何执行 Google Maps 基于区域的聚类或标记重叠

标签 javascript google-maps google-maps-api-3 markerclusterer

这里是 OverlappingMarkerSpiderfier 的例子通过使用重叠标记 Spiderfier,它是基于距离的重叠标记,有没有什么方法可以实现基于区域的相同效果,例如一个国家的所有标记重叠并显示为一组标记,然后单击相同的扩展标记.

已编辑

我有搜索堆栈溢出和谷歌的可能性,但没有找到任何解决方案,如果有人有想法/摆弄如何使用使用多边形/区域的标记管理器手动进行聚类也很有帮助。

最佳答案

以前在堆栈溢出....

我的标记聚类方法

我应对这一挑战的方法是遵循@geocodezip 的建议。我会使用他在 https://stackoverflow.com/a/15422677/1337392 中提供的答案
创建区域 map 。

每个区域都会知道它有哪些标记。此外,如果您想关注 principle of least carnality ,您还可以让每个标记知道它属于哪个区域。为了实现这一点,我会使用 MarkerLibs ,或类似的东西。

一旦我们知道每个标记所属的位置,就可以直接对它们进行分组。 @geocodezip 再次推荐了一个不错的来源 https://developers.google.com/maps/articles/toomanymarkers ,但是,我建议谨慎,因为其中一些库已经过时且已停产(上次我在几个月前检查过)。

你也可以去所有Rambo mode在这个并自己编码。基本上,您需要一个 listener for the zoom level每次缩小时,您都可以计算是否要将上述区域内的所有制造商分组。

将上述标记分组意味着隐藏它们,并在它们的位置(您可以计算几何中心)放置一个 new (custom) marker那象征着一个群体。

我暂时没有代码,但我希望我的详细解释可以帮助您解决这个问题。

... 区域标记聚类的错觉

"Reality is that which, when you stop believing it, doesn't go away."

Philip K. Dick



用户查看标记聚类的最简单解决方案......不是进行标记聚类。

我们可以根据缩放级别隐藏和显示它们,而不是聚类标记,从而有效地创建标记被聚类的错觉。

算法/示例

如您所见,这种方法基于提供标记聚类的错觉。

在这个例子中,我有葡萄牙的所有地区(按颜色划分),每个地区都有一组 POI(兴趣点)。

就个人而言,我强烈建议您访问这个美丽的国家,这是我多年的家,您不会后悔(特别是食物!)

现在,每个 POI 都有一个名称、它所在的坐标以及它所属的区域。这一切都在数据集中:
const POIS = [{
    district: 'LISBOA',
    name: 'Torre de Belem',
    coords: {
        lat: 38.69383759999999,
        lng: -9.2127885
    }
}, {
    district: 'LISBOA',
    name: 'Mosteiro dos Jeronimos',
    coords: {
        lat: 38.69703519999999,
        lng: -9.2068921
    }
},
...
];

PS:Torre de Belem 和 Mosteiro 非常好!

如您所见,我遵循了之前解释的最小基数原则,并将其所属的区(地区)添加到每个 POI 中。

这里发生的是,当我初始化 map 时,我为每个 POI 创建了一个标记 - 但我没有显示它。

然后,我计算 centroid对于每个区(如果您考虑一下,每个区只不过是一个多边形!)并且我也为每个区的中心创建了另一个标记(但我再次没有显示它)。

我什么时候显示标记?

当用户放大或缩小时。为了帮助我解决这个问题,我最终使用了一个名为 markermanager 的库。它根据最大和最小缩放级别显示和隐藏标记!

结果是一张 map ,让您产生标记聚类的错觉!

为了给示例添加一些技巧,我还使用了 dynamic pins计算每个区域的 POI 数量,从而进一步加深错觉。

PS:不推荐使用动态引脚,但我使用它,因为目前我不知道更好的解决方案。

代码

代码看起来很大,但如果你深入研究,你会发现它非常简单。

一、index.html .此文件包含 div对于 map 和 JavaScript 引用:
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Simple Polygon</title>
    <link rel="stylesheet" type="text/css" href="mystyle.css">
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA7ZtEnzC81C1TnUI1Ri44JgJJIh5KaltM"></script>
  </head>
  <body>
    <div id="map"></div>
    <script src="markermanager.js"></script>
    <script src="districtData.js"></script>
    <script src="poiData.js"></script>
    <script src="myscript.js"></script>
  </body>
</html>

现在,我们有了应用程序的核心。 myscript.js文件。此文件使用 markermaner.js lib 前面提到过,并使用了两个数据文件,即 poiData.jsdistrictData.js .

该文件处理 map 的初始化,绘制区域多边形,计算每个多边形的质心,并初始化标记管理器。如果有一个功能我可以告诉您非常重要,那么该功能将是 setUpMarkerManager()大部分繁重的工作都在这里完成。
"use strict";

/*global google*/
/*global DISTRICTS*/
/*global POIS*/
/*global MarkerManager*/

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 5,
    center: {
      lat: 38.184,
      lng: -7.117
    },
    mapTypeId: 'terrain'
  });

  setUpMarkerManager(map);
  drawDistricts(map);
}

//Check https://github.com/googlemaps/v3-utility-library/blob/master/markermanager/docs/reference.html
function setUpMarkerManager(aMap) {
  let mgr = new MarkerManager(aMap);

  let poisPerDistrict = new Map();
  let allPOISArray = [];


  POIS.forEach(element => {

    let poiDistrict = element.district;
    if (poisPerDistrict.has(poiDistrict)) {
      let poiCount = poisPerDistrict.get(poiDistrict) + 1;
      poisPerDistrict.set(poiDistrict, poiCount);
    }
    else
      poisPerDistrict.set(poiDistrict, 1);

    allPOISArray.push(new google.maps.Marker({
      position: new google.maps.LatLng(element.coords.lat, element.coords.lng),
      title: element.name
    }));
  });

  let inverseCenter;
  let disctrictsCenter = [];
  DISTRICTS.forEach(element => {
    inverseCenter = getPolygonCenter(element.coords.coordinates[0]);

    if (poisPerDistrict.get(element.id))

      //For cool markers check https://developers.google.com/chart/image/docs/gallery/dynamic_icons#scalable_pins
      disctrictsCenter.push(new google.maps.Marker({
        position: new google.maps.LatLng(inverseCenter[1], inverseCenter[0]),
        icon: "https://chart.googleapis.com/chart?chst=d_map_spin&chld=0.6|0|FFFFFF|12|_|" + poisPerDistrict.get(element.id),
        title: element.name
      }));
  });

  google.maps.event.addListener(mgr, 'loaded', function() {
    mgr.addMarkers(allPOISArray, 9);
    mgr.addMarkers(disctrictsCenter, 0, 8);
    mgr.refresh();
  });
}

// https://stackoverflow.com/a/37472218/1337392
function getRandomColor() {
  return '#' + Math.random().toString(16).slice(2, 8);
}

function drawDistricts(aMap) {
  let randomColor;

  DISTRICTS.forEach(element => {
    randomColor = getRandomColor();

    new google.maps.Polygon({
      paths: getPolygonCoordinates(element.coords),
      strokeColor: randomColor,
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: randomColor,
      fillOpacity: 0.35,
      map: aMap
    });
  });
}

function getPolygonCoordinates(polygon) {
  let coords = polygon.coordinates[0];
  let result = [];

  coords.forEach(element => {
    result.push({
      lng: element[0],
      lat: element[1]
    });
  });

  return result;
}

//Check https://stackoverflow.com/a/16282685/1337392
//Check https://en.wikipedia.org/wiki/Centroid
function getPolygonCenter(coords) {
  var minX, maxX, minY, maxY;
  for (var i = 0; i < coords.length; i++) {
    minX = (coords[i][0] < minX || minX == null) ? coords[i][0] : minX;
    maxX = (coords[i][0] > maxX || maxX == null) ? coords[i][0] : maxX;
    minY = (coords[i][1] < minY || minY == null) ? coords[i][1] : minY;
    maxY = (coords[i][1] > maxY || maxY == null) ? coords[i][1] : maxY;
  }
  return [(minX + maxX) / 2, (minY + maxY) / 2];
}

initMap();

接下来是图书馆本身,markermanager.js .我可以把代码贴在这里,但这已经很长了,所以我只是简单地指出我使用的是 v1.1,你可以在 official place 下载它。或者通过检查我之前发布的项目的 URL。

考虑到这一点,我也会给你我的手工制作 手动更正 庞大的数据文件。是的,如果你想知道为什么我花了这么长时间,现在你有一个想法。

通常我会在这里复制和粘贴这些值,但由于 StackOverflow 有字符限制,我会将您链接到我的 GitHub 帐户所在的位置。
poiData.js首先是包含您应该看到的所有位置的文件!
链接:https://github.com/Fl4m3Ph03n1x/marker-cluster-polygon/blob/master/poiData.js

而现在,districtData.js与每个地区多边形的数据。
链接:https://github.com/Fl4m3Ph03n1x/marker-cluster-polygon/blob/master/districtData.js

还有 CSS 文件,但它确实没什么特别的。

您可以在我的 GitHub 帐户中查看完整的演示/项目:
https://github.com/Fl4m3Ph03n1x/marker-cluster-polygon

个人笔记

当我第一次开始这个时,我无法想象它会带我去哪里。

我不得不说的一件事是,当我开始编码时,我没有意识到我与最初的理论有多接近!事实上,作为一个彩蛋,我可以告诉你,我最初为这个答案发了一个不同的帖子,因为我认为它与我预测的初始算法非常不同:P

我想它会告诉你,在编写代码之前思考代码确实是值得的!

总的来说,我认为这种方法的效率是可以接受的,而且它确实很有趣并且(很多工作)可以创造。使用这种方法进行的大部分工作都将与处理数据有关,但是一旦完成,其余的工作就会变得快速且简单。

我的一部分人希望我可以早点完成以获得赏金,但由于我喜欢将自己视为信守 promise 的人,我最终还是做到了并发布了它!

我希望你现在明白为什么我花了这么长时间,但我真的希望这对你有帮助!

关于javascript - 如何执行 Google Maps 基于区域的聚类或标记重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39017995/

相关文章:

javascript - 在 Google map 中加载 KmlLayers 是否成功?

android - 用于测试的 Google Maps API KEY

javascript - 从字段进行搜索后如何将可拖动标记添加到谷歌地图

android - Google map 交互式折线的 API 级别?

javascript - for 循环中的回调完成后如何执行函数?

javascript - 谷歌地图标记阴影未显示

Javascript 对象没有值的键

javascript - 您应该从 Rails 服务器返回 javascript (.js.erb) 还是在 Ajax 调用后更新页面时使用 native JS 回调机制

javascript - 编写 jquery 添加/删除类的更好方法

javascript - HAML 中 Javascript 中的 Ruby 方法