自创Google地图

毕业了进了公司 就接触了一个超图(supermap)的地图项目。那个项目是基于超图的二次开发。超图的技术和服务那是没有什么话说,但是就是地图的质量不是很高。在这也不是诋毁超图,因为我是开发的,也知道公司就出了那么些钱买地图数据,一分钱一分货,对买回来的数据肯定是要经过美工的处理,然而这个处理那就是个无底洞了,听超图的陈工跟我说,什么土地什么局的,一个10人的团队花了一年的时间来修图。我了了个去的,我们公司就一个美工,而且就我一个人负责这个项目,别说一年,就是十年,也就这样了。当然,最后也就稍微做了些美化,在上面的几级数据基本上看起来和还凑合,但是最后的几级数据,就有点不是很爽了,把其他行业能略去的数据都给略去了,一些医院集中的地方还是会集中到一起造成重叠(也没有精力去弄什么分层显示什么的),因为实在就一个人,搞得就有点皮了。但是自己心里还是在想着,要是哪天能有google的地图api,那是几爽的一件事情。于是就酝酿着,做一个google的地图。当然也只是过过自己的瘾,在这里和大家分享一下过程,希望大家多多的指点一下,完善一下。仅供交流和学习使用,大家不要用到什么商业用途中去了,我只是自己研究提供算法,地图的数据还是down的google!

  说了这么多,下面就说一下这个地图吧。(因为说的比较抽象,如果只是刚接触地图可以直接跳过到最后看看代码和实例图,慢慢了解)开始我想的还是蛮简单的,不就是把地图的图片放到文件夹里,然后把地图的图片取出来,放到一个div中,加上一些移动啊什么的事件,也就了事了。但是做到后面,这样那样的问题那是一大堆。

  我总结分为两类大题,一类是google的地图图片这块,二是组织编写javascript语言。

 首先说第一个,得到google地图图片,少量的(前十级吧)应该还算是容易,编个程序,从google服务器当下来。一般稍微看一下google地图的每个类型每个图片的地址都能推算出来地址,于是我就这样写了个程序,开始速度还是可以,但是一旦下载到十级以上(其实第7级第8级就差不多了),速度就有时候很慢,而且经常会超时,我想那肯定是google为了防止别人恶意down他的地图,做了手脚。所以后来找了几个软件(至于什么软件我就不说了,要是要的话,qq里可以交流)帮着down。因为我想图片只是自己练手的一个工具,不必计较怎么来的,能得到就可以了。得到图片之后按照他们的经度纬度的顺序,将他们直接用java转成二进制存到数据库中。这里要插一句,google的地图图片是按照级数来分,把整个世界分成一块块的256*256的png图片。第0级是4的0次方个,第1级是4的1次方个,第2级是4的2次方个。。。依此类推,每次在经度和纬度方向扩一倍的数量,到10级那就是4的十次方(1048576),这里就出现了个问题,好像一个xp系统的文件夹里,最多只能放十几万个图片,具体数字我不记得了,因为我开始是把前期在数据库中的准备好的地图数据转成缓存图片保存在服务器中,一个级一个文件夹,但是好像是在第9级还是第10级的时候,就报错了,后来一查原来是放不下了。于是乎很自然想到文件夹在分,一个级下面分了16*16个文件夹,至于怎么分的,方法很多,我是把对于x方向和y方向的第n个图片除以16的余数来分。(我这里只是down的中国范围的地图,世界范围的只是down到五六级的样子,而且,我是在湖北,具体的十级以后的数据也只down了湖北的,因为数据量实在是太大了)。

 好了地图数据准备好了,接下来就是编程了,当然主要的是javascript的脚本语言,也正是想好好地补补javascript知识,因为之前在工作中涉及的javascript,无非就是一些function定义的方法,很简单。这之前,我先看了一下google的api。里面地图这块主要是一个GMap类,GControl(放大缩小,地图类型控件),GInfoWindow(点击图片显示的窗口),GBounds(显示地图边框的四个边位置信息),GLatLng(经纬度信息),GPoint(点位置信息),GSize(尺寸)。。。等等。那么我也就照着他的结构,依葫芦画瓢,来编写我的地图。因为我姓朱,所以我命名ZMap等等。。。这里说的就多了,自己也有点乱了。写程序写多了也不是很善于表达了,悲剧。我把最基本的思路屡一下,说白了就是把当前LatLng(经纬度)和Zoom(级数)下的放在16*16个文件夹的图片搬到div中来显示,根据一开始定义的Center and zoom的经纬度和级数,转换成像素,再根据像素计算得到中心图片是在x方向和y方向的第几个图片。然后根据在ZMap中定义的cashlevel(以中心点为圆心向xy方向扩展的图片个数)得到左右上下要显示的图片,然后取得图片显示。放大缩小平移的基本思路也是这样,说白了就是像素和经纬度之间的转换。具体的算法我这里也就不说了,因为说到算法不免是让人很犯困的一件事情,而且一开始自己写的算法,等我写完了回头一看,有时甚至都不知道当时自己是怎么想的。根据这样的思路我就把Zmap类(生成map的html代码),Zmap_Actions(事件在里面定义),ZMap_Commons.js(一些工具类和基本对象),ZMap_Define(命名空间)给完成了。非常的艰辛啊。

  我这里就几个我觉得很难的记忆很深的问题和大家分享讨论一下:

1、像素和经纬度的换算。google在经度上没有做什么加密,按照正常的思路来,把360°的世界分成了2的n次方(n是zoom级数),每个图片是256*256的尺寸,那么每个经纬度对应的像素相信大家没有什么多的疑问。但是纬度上就奇葩了,按照我们学的地理知识来说,纬度分为北纬南纬,从赤道0°开始,上下都是90°。其实不是,google的北纬和南纬最北和最南只有85°,不是90°。85°就到了南极北极的顶端了。所以这里的算法就没有那么简单了。既然讨论就把算法和大家分享了,js 的算法:

 //纬度到像素Y
 latToPixel:function(lat, zoom) {

  var siny = Math.sin(lat * Math.PI / 180);
 
  var y = Math.log((1 + siny) / (1 - siny));
 
  return (128 << zoom) * (1 - y / (2 * Math.PI));

 },
 
 //像素Y到纬度
 pixelToLat:function(pixelY,zoom) {
  
  var y = 2 * Math.PI * (1 - pixelY / (128 << zoom));

  var z = Math.pow(Math.E, y);

  var siny = (z - 1) / (z + 1);

  return Math.asin(siny) * 180 / Math.PI;

 },
 

2、google的地图是由整个世界拼接而成的,你缩小到第一二级的时候可以看见有连续的世界拼接而成,在任意一个位置上放大,都能正常放大。可能这里听得有点别捏。很简单的一个逻辑,看似很简单的问题,细想想其实很复杂,但是再仔细想想又很简单,很纠结吧!很多复杂的问题不过就是由一两根茂密的树枝遮着你的眼睛,掐了这两个树枝就光明了。在根据经纬度计算得到像素的时候,做个验证,如果经纬度小于0就加上经纬度方向的最大的像素,如果超过了最大的像素(当前级数的图片的最大像素)就减去最大的像素。很简单吧。这里我要补充一下,google地图的图片在纬度方向是从北纬85度西经180开始作为起点向右下开始扩展,像素的计算起点也就在这里。这是对于拼接图片。

  对于放大图片,如何保证你在这块中国板块上放大,和在隔壁的一块中国的板块上放大效果一样的呢。怎么计算?其实也是很简单,关键只要得到当前鼠标所在的位置的正确的位置信息。要得到图片就是要得到像素信息,如果越界那就要检查你的得到的像素是否超过最大的像素或者小于0。处理和上面一样。

 

在其它的环节中大大小小的问题也都有,但是主要的第一个问题自己屡清楚了,也都差不多可以迎刃而解了,像在地图上放定位图标啦,点击定位图标显示一个窗口啦,地图类型的切换,地图放大缩小的控件啦,等等。。。以后有必要的话再慢慢更新吧。

上面说的可能有点抽象,如果没有真正的深入研究过Gis可能看的也是一头雾水。实在是包含包含。本人能力有限。下面我将最简单的一个demo.html贴出来:有兴趣的欢迎找我索取源代码,一起研究讨论学习。qq:461372681  邮箱461372681@qq.com 

 

<html>
<head>
 <!-- 地图的几个必须的包 -->
 <script type="text/javascript" src="scripts/ZMap_Define.js"></script>
 <script type="text/javascript" src="scripts/ZMap_Commons.js"></script>
 <script type="text/javascript" src="scripts/ZMap_Actions.js"></script>
 <script type="text/javascript" src="scripts/ZMap.js"></script>
 <script type="text/javascript" src="scripts/jquery-1.4.2.js"></script>
 <script type="text/javascript" src="scripts/jquerypugin/jquery.skygqOneDblClick.1.1.js"></script>
 <script language="javascript">
  function initlize(){
    //test为显示地图的div的id
    var mapp=new ZMap("test");
    //设置中心点的位置和级数
    mapp.setCenterAndZoom(new ZLatLng(30.42641061,108.7953084),5);
    //增加地图类型切换控件(包含普通和卫星图)
    mapp.addControl(new TypeControl());
    //增加放大缩小平移控件
    mapp.addControl(new ZoomControl());
    //定义点信息 使用的是默认图标,点击没有事件,可以根据业务需要添加
    var marker=new ZMarker(new ZLatLng(30.42641061,108.7953084));
    ZMap.addMarker(marker);
    
  }
 </script>
</head>

<body onLoad="initlize()">
 <div id='test' style="border:1px;width:50%;height:50%;overflow:hidden"></div>
</body>

</html>

 

样式浏览 和google的基本是一样的吧:

 

 

其他样式浏览:

infowindow:

 

自己添加的图层信息:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值