php - 服务器端标记聚类

时间:2013-11-28 15:24:48

标签: php google-maps google-maps-api-3

我目前在我的网站上有一个显示50,000个标记的地图。由于混乱,这些对用户来说是不可读的,因此我使用google的markerclusterer实现了一个群集解决方案。这样做没问题,但是由于标记的数量,加载速度非常慢。

我想以php的形式使用服务器端解决方案,但无法找到最佳方法。这是我目前的设置

外部php文件markers-xml.php

<?php
$SQL = "SELECT MarkerName, Lat, Lng FROM TableName WHERE MarkerName !=''";
$Query = mysql_query($SQL);
$NumRows = mysql_num_rows($Query);
?>
<markers>
<?php       
for($i = 0; $i < $NumRows; $i++)
{
    $row = mysql_fetch_assoc($Query);
    $Lat = $row['Lat'];
    $Lng = $row['Lng'];
    $MarkerName = $row['MarkerName'];

    echo "<marker Lat='$Lat' Lng='$Lng' MarkerName='$MarkerName'> </marker>\n";
}
?>
</markers>

主文件包含地图

function initialize(mapvars) {
        var xmldata = "markers-xml.php";

        downloadUrl(xmldata, function(doc) {
            var xml = xmlParse(doc);
            var markersInfo = xml.documentElement.getElementsByTagName("marker");
            var markers = []; 
            var bounds = new google.maps.LatLngBounds();
            for (var i = 0; i < markersInfo.length; i++) {
                var Lat = parseFloat(markersInfo[i].getAttribute("Lat"));
                var Lng = parseFloat(markersInfo[i].getAttribute("Lng"));
                var point = new google.maps.LatLng(Lat,Lng);
                var MarkerName = markersInfo[i].getAttribute("MarkerName");  

                var marker = new google.maps.Marker({
                    position: point,
                    map: map,
                    title: MarkerName,
                    MarkerName: MarkerName
                });

            markers.push(marker);
            bounds.extend(point);
        }

        var markerCluster = new MarkerClusterer(map, markers);
    }

2 个答案:

答案 0 :(得分:1)

我认为服务器端解决方案不会改善性能。可以在视口的每次更改时请求过滤数据以减少已使用标记的数量,但是您将始终要求新数据需要一些时间。

我认为最好的解决方案是使用FusionTableLayer,它可以毫无问题地使用多达100000个标记。


可能的方法(与评论相关):

当地图的视口发生变化时,将视口和缩放级别的边界发送到服务器。

数据库查询应该

  1. 根据给定的界限过滤结果
  2. 围绕lat和lng(圆角的精确度必须与缩放级别相关)
  3. 通过舍入的latlngs
  4. 对结果进行分组
  5. 返回舍入的latLng和此latlng的项目数
  6. 将这些数据发送回客户端并创建标记(您可以使用服务器端解决方案动态创建标记图像或使用自定义叠加层)

答案 1 :(得分:1)

客户端: 生成一个get请求并传入视口的边界

getclusters.php?&lat2=62_676438&lon2=-63_2085681&lat1=10_6655205&lon1=-135_7183337

服务器端: 将您的lat lon数据存储在具有pk和POINT数据结构的表中,这样您就可以使用mysql空间索引(使用r-trees而不是b-trees,因此将50K点分组为秒而不是分钟):

CREATE TABLE location (
 id int(11) unsigned NOT NULL
 , p POINT NOT NULL, PRIMARY KEY (id)
 , SPATIAL INDEX(p)) ENGINE=MyISAM;

从另一个表加载:

INSERT INTO location 
select id, PointFromWKB(Point(latitude, longitude))
from table_with_lat_long

从csv加载:

LOAD DATA LOCAL INFILE 'data.csv'
INTO TABLE location
COLUMNS TERMINATED BY ',' LINES TERMINATED BY '\r\n'
(id, @dummy, ..., @dummy, @latitude, @longitude)
set p = PointFromText(CONCAT('POINT(',@latitude,' ',@longitude,')'));

通过将视口细分为相等的较小方块或基于视口大小的点之间的一些最小距离,将适当的SQL写入组。只要您使用SPATIAL索引,它就应该快速运行

您的客户端群集标记javascript应根据计数呈现标记(对于群集,单个标记2为1或更多)