在谷歌地图结果中添加“搜索区域”轮廓

Posted

技术标签:

【中文标题】在谷歌地图结果中添加“搜索区域”轮廓【英文标题】:Add "Search Area" outline onto google maps result 【发布时间】:2012-03-31 04:17:56 【问题描述】:

去年,Google 在其产品中添加了搜索区域轮廓,这在许多地方都有报道,并且在 Google 地图本身上可见。比如here,并报here和here。

明确地说,这是谷歌添加与搜索查询相关的大纲的时候。如果您要搜索城镇、邮政编码或邮政编码,Google 会在地图上突出显示该区域。示例:

这显然无法通过 API 获得,只能通过 Google 自己的网络资产获得。

最近,我注意到一些其他域使用此功能,例如 Twitter。

Twitter 和其他大型组织是否正在使用单独的 API?是否已添加此功能,但尚未记录在案?还是我只是错过了公告而找不到任何文档?

【问题讨论】:

您选择的答案说他们已存储,但我看到 redfin.com(房地产网站)不仅可以为邮政编码执行此操作,还可以为单个属性执行此操作。在this redfin link,单击房屋别针,然后单击右侧的“快速地图”,然后注意物业地址周围的多边形。我非常怀疑他们是否为每个单独的房产地址存储了多边形。他们是怎么做到的? 【参考方案1】:

这有点麻烦,但您可以使用 BING maps api 来获取详细的多边形。他们很难从他们的 api 中弄清楚,但 this blog post 帮助了我。一旦他们将数据发送给您,您就必须对其进行解压缩。他们在那篇文章中使用 bing maps api 绘制形状,但我将其转换为 geojson。我就是这样做的。

 function getBingMapsGeometry(latitude, longitude, entityType) 
   //api docs: https://docs.microsoft.com/en-us/bingmaps/spatial-data-services/geodata-api
        let baseUrl =
                "http://platform.bing.com/geo/spatial/v1/public/geodata?SpatialFilter=",
            levelOfDetail = 3,
            getAllPolygons = 1,
            getEntityMetadata = 1,
            culture = "en-us",
            userRegion = "US",
            preferCuratedPolygons = 1,
            responseFormat = "json",
            key = "your_api_key";
        return fetch(`$baseUrlGetBoundary($latitude,$longitude,$levelOfDetail,'$entityType',$getAllPolygons,$getEntityMetadata,'$culture','$userRegion')&PreferCuratedPolygons=$preferCuratedPolygons&$format=$responseFormat&key=$key`
        ).then(res => 
            res.json().then(result => 
                var entity = result.d.results[0];
                if (!entity) 
                    alert("no results");
                    return;
                
            // much help from this post: https://blogs.bing.com/maps/2013/06/25/retrieving-boundaries-from-the-bing-spatial-data-services-preview
                var entityMetadata = entity.EntityMetadata;
                entityMetadata.name = entity.Name.EntityName;
                var primitives = entity.Primitives;
                var boundaryVertices = null;
                var numOfVertices = 0;
                var multyiPolygonArray = [];
                var singlePolygonArray;
                for (var i = 0; i < primitives.length; i++) 
                    var ringStr = primitives[i].Shape;
                    var ringArray = ringStr.split(",");

                    for (var j = 1; j < ringArray.length; j++) 
                        var polygonArray = new Array();
                        var array = ParseEncodedValue(ringArray[j]);

                        if (array.length > numOfVertices) 
                            numOfVertices = array.length;
                            boundaryVertices = array;
                        
                        polygonArray.push(array);
                        if (ringArray.length > 1)
                            multyiPolygonArray.push(polygonArray);
                        else singlePolygonArray = polygonArray;
                    
                
                let geojson = 
                    type: "FeatureCollection",
                    features: [
                        
                            type: "Feature",
                            properties: entityMetadata,
                            geometry: 
                                type: singlePolygonArray
                                    ? "Polygon"
                                    : "MultiPolygon",
                                coordinates: singlePolygonArray
                                    ? singlePolygonArray
                                    : multyiPolygonArray
                            
                        
                    ]
                ;
return geojson;
            );
        );
    

 function ParseEncodedValue(value) 
        var safeCharacters =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
        var list = new Array();
        var index = 0;
        var xsum = 0;
        var ysum = 0;
        var max = 4294967296;

        while (index < value.length) 
            var n = 0;
            var k = 0;

            while (1) 
                if (index >= value.length) 
                    return null;
                
                var b = safeCharacters.indexOf(value.charAt(index++));
                if (b == -1) 
                    return null;
                
                var tmp = (b & 31) * Math.pow(2, k);

                var ht = tmp / max;
                var lt = tmp % max;

                var hn = n / max;
                var ln = n % max;

                var nl = (lt | ln) >>> 0;
                n = (ht | hn) * max + nl;
                k += 5;
                if (b < 32) break;
            

            var diagonal = parseInt((Math.sqrt(8 * n + 5) - 1) / 2);
            n -= (diagonal * (diagonal + 1)) / 2;
            var ny = parseInt(n);
            var nx = diagonal - ny;
            nx = (nx >> 1) ^ -(nx & 1);
            ny = (ny >> 1) ^ -(ny & 1);
            xsum += nx;
            ysum += ny;
            var lat = ysum * 0.00001;
            var lon = xsum * 0.00001;
            list.push([lon, lat]);
        
        return list;
    

【讨论】:

【参考方案2】:

twitter api 地理端点不会给你城市边界,

他们为您提供的只是 5 点(纬度、经度)的边界框

这是我从旧金山的 twitter api geo 得到的

【讨论】:

【参考方案3】:

由于 Maps API 还没有提供任何解决方案,而且手动填写坐标是没人管的事,所以这里有一个很好的替代方案。在 GIS 网站上找到了这个答案——绝对的救星(会为 jurihandl 节省很多时间来绘制卡尔加里,上面 ;D):

您可以在 json 中获取多边形坐标以用于 googlemaps 使用openstreetmap。转到http://nominatim.openstreetmap.org/。搜索 像“加利福尼亚州旧金山”这样的地方

点击“详情”

查找 OSM ID 并复制(control+c),例如:2018776

粘贴 ID http://polygons.openstreetmap.fr/index.py 并下载 JSON 文件

来源:GIS

【讨论】:

这太棒了!但是,目前尚不清楚 ID 是否会出现在所有呼叫中,而且它似乎只适用于某些类别的位置。原始问题示例导致:nominatim.openstreetmap.org/details.php?place_id=160424228,没有“关系 ID”可呈现给后续请求。仍然很棒,现在有人只需要将这一切包装到一个 API 调用中! :-) @dazbradbury 我完全同意。听起来像一个有趣的项目...我可能会得到这个.. 我喜欢这个,但我希望他们能提供更纤薄的多边形模型。对奎松省(菲律宾)的快速打击给了我 0.5 mb 的坐标!甚至边界上的直线也有大约 100 多个坐标。不过,非常好。 伙计,这太棒了......太糟糕了,他们没有邮政编码的关系! (至少,我要找的那个,这意味着充其量对那些人来说是不一致的——可能他们只是不可用。悲伤的一天。) 这是当今最好的解决方案。 openstreetmap 仍然有很多缺失的边界定义,因为它是由用户填充的。【参考方案4】:

你在那里看到的大纲来自推特,他们一定已经存储了它们。

查看调用 twitter 页面时请求的 json 文件: http://api.twitter.com/1/geo/id/c3f37afa9efcf94b.json

我试过了,geometry.coordinates[0][0] 定义了一个精细的多边形(猜猜奥斯汀的轮廓)。

当你尝试的时候,注意这对的顺序是lng,lat而不是lat,lng

所以twitter-geo-API 可能是实施大纲的良好开端,幸运的是 twitter 支持 JSONP 作为客户端解决方案。

查看示例:http://jsfiddle.net/doktormolle/MRYm3/

&lt;edit&gt;

twitter-API 已更改,示例不再工作(需要身份验证)

&lt;/edit&gt;

【讨论】:

你说得对。与谷歌结果 (maps.google.com/maps?q=Austin%2C+Texas%2C+US) 的快速比较可能会使叠加层略有不同。不过他们让我上当了。感谢您的建议! 听起来可能是个愚蠢的问题,但是.. Twitter 是如何获得多边形的?基于位置推文随时间生成的用户? 还注意到许多位置都丢失了(温哥华 BC,这是我的家,在 jSfiddle 页面中没有返回任何内容)。如何克服这一点? 无法像在 Google 地图官方网站中那样工作。它不会在智利找到任何城市,并且多边形被填充,而不仅仅是轮廓。 人们可能会做某事,而不是请求某事。 twitter 返回的折线是用户创建的,当人们不为智利或印度创建这些折线时,就没有。【参考方案5】:

我找到了一个非常好的绘制城市边界的解决方案。

这是一个非常酷的工具,您可以在其中绘制城市边界。你可以随心所欲: http://www.birdtheme.org/useful/v3tool.html

在右侧,您可以实时预览您的代码。您可以在 KML 和 javascript 之间进行选择。切换到 JavaScript。然后复制你的坐标。

这是您可以看到布鲁塞尔(欧洲)边界的完整网站。

<!DOCTYPE html>
<html lang="en-US">
 <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>::Maps ::</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&key=AIzaSyD0X4v7eqMFcWCR-VZAJwEMfb47id9IZao"></script>
    <script type="text/javascript">
        var map;

        //COORDS
        var brussels = [
        new google.maps.LatLng(50.835866,4.258575),
        new google.maps.LatLng(50.818083,4.244499),
        new google.maps.LatLng(50.811358,4.276428),
        new google.maps.LatLng(50.813094,4.302177),
        new google.maps.LatLng(50.773162,4.338226),
        new google.maps.LatLng(50.764259,4.384918),
        new google.maps.LatLng(50.793132,4.482422),
        new google.maps.LatLng(50.810274,4.450836),
        new google.maps.LatLng(50.821120,4.476585),
        new google.maps.LatLng(50.852342,4.462852),
        new google.maps.LatLng(50.866861,4.421310),
        new google.maps.LatLng(50.895021,4.430580),
        new google.maps.LatLng(50.911692,4.413757),
        new google.maps.LatLng(50.912342,4.395561),
        new google.maps.LatLng(50.898486,4.377708),
        new google.maps.LatLng(50.900868,4.328957),
        new google.maps.LatLng(50.889174,4.293251),
        new google.maps.LatLng(50.880294,4.297028),
        new google.maps.LatLng(50.861878,4.279175),
        new google.maps.LatLng(50.855593,4.288788),
        new google.maps.LatLng(50.837817,4.282608),
        new google.maps.LatLng(50.835866,4.259605)
        ];

        $(document).ready(function () 
            //WHERE TO CENTER YOUR MAP
            var latlng = new google.maps.LatLng(50.834999,4.387665);
            var myOptions = 
                zoom: 10,
                center: latlng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            ;
            map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

            var BrusselsHightlight;

            //DRAW THE POLYGON OR POLYLINE
            BrusselsHightlight = new google.maps.Polygon(
                paths: brussels,
                strokeColor: "#6666FF",
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: "#6666FF",
                fillOpacity: 0.35
            );
            BrusselsHightlight.setMap(map);

        );

    </script>
    <style type="text/css">
        html,body  height: 100%; margin: 0px; padding: 0px; 
        #map_canvas 
            width:600px;
            height:400px;
               
    </style>
</head>
<body >
<div id="map_canvas">

</div>
<!--main-->
<div id="map_cord"></div>
</body> 
</html>

这对我来说真的很棒。

【讨论】:

以上是关于在谷歌地图结果中添加“搜索区域”轮廓的主要内容,如果未能解决你的问题,请参考以下文章

如何在谷歌地图中添加两种类型的标记

怎么在谷歌地图上做标记呀

无法在谷歌地图中添加多个标记(颤振)

当位置返回多个结果时,在谷歌地图中选择第一个匹配静态

如何在谷歌地图中添加推荐地点?

如何在谷歌地图上添加多个标记