前面跟大家分享过百度地图2.0离线版的修改制作,许多人问怎样获得瓦片,这个过程其实并不复杂。稍微追踪一下代码就可以获得瓦片。
由于想下载瓦片需要联网,但需要修改代码,因此不能直接用百度地图的js。js需要下载下来修改使用,因此还是参考前作《百度地图2.0离线版的制作》吧,不过只需要下载下来加载到自己的html页面中就可以了。前文中的修改都是不必要的了,需要新修改代码达到获取瓦片地址,然后通过工具可以下载。下载工具我就不提供了。
第一步,修改“a_”方法
如果不出意外的话,搜索方法定义“a_”应该能且只能找到一处,其调用者也只有一处,两个都要改,我们先来改“a_”定义。
a_:function(a,b,c,d){var e=this;e.h1=b;var f=this.map.ta(),g=e.SD(a,c),i=f.k.Ob,b=[a[0]*i+b[0],(-1-a[1])*i+b[1]],k=this.wg[g];k&&k.Gb?(vb(k.Gb,b),d&&(d=new Q(a[0],a[1]),f=this.map.K.te?this.map.K.te.style:"normal",d=c.getTilesUrl(d,a[2],f),k.loaded=q,Fc(k,d)),k.loaded?this.vf():Gc(k,function(){e.vf()})):(k=this.fj[g])&&k.Gb?(c.Pb.insertBefore(k.Gb,c.Pb.lastChild),this.wg[g]=k,vb(k.Gb,b),d&&(d=new Q(a[0],a[1]),f=this.map.K.te?this.map.K.te.style:"normal",d=c.getTilesUrl(d,a[2],f),k.loaded= q,Fc(k,d)),k.loaded?this.vf():Gc(k,function(){e.vf()})):(k=i*Math.pow(2,f.qm()-a[2]),new H(a[0]*k,a[1]*k),d=new Q(a[0],a[1]),f=this.map.K.te?this.map.K.te.style:"normal",d=c.getTilesUrl(d,a[2],f),k=new Hc(this,d,b,a,c),Gc(k,function(){e.vf()}),k.$n(),this.wg[g]=k)},
这个太长了,也不好看哈,不过修改非常简单,在最后增加一句“return d;”就好了。这样我们可以找到瓦片的地址等信息。
我给这段代码稍加翻译了一下,可以看得更清楚一些。为了方便,我将大多数的逗号表达式改成多语句,将问号冒号三元表达改成了if/else结构。
a_:function(a,b,c,d){
var e=this;
e.h1=b;
var f=this.map.va();
var g=e.SD(a,c);//名字,TILE-2-3-4-5,基本上是version-x-y-z
var i=f.k.Ob;
var b=[a[0]*i+b[0],(-1-a[1])*i+b[1]];//left和top的计算
var k=this.wg[g];//这个是个缓存结构看起来,是一个map
//d似乎永远都是undefined,因此下面跟d相关的代码都未执行。
if(k&&k.Gb){//找到缓存,k.Gb是具体的tile对应的image节点
vb(k.Gb,b);//设置image的位置,具体的位置在b中存储了,两个维度分别是left和top
if(!!d){
console.log("====any here?? k.Gb="+k.Gb.src)
d=new Q(a[0],a[1]);
f=this.map.M.se?this.map.M.se.style:"normal";
d=c.getTilesUrl(d,a[2],f);
k.loaded=q;
Fc(k,d);
}
k.loaded?this.vf():Gc(k,function(){e.vf()})
}else{
k=this.fj[g];//这个不知道是什么,看起来这里永远取不到数据
if(!!k&&!!k.Gb){//这一块代码也就废掉了
c.Pb.insertBefore(k.Gb,c.Pb.lastChild);
this.wg[g]=k;
vb(k.Gb,b);
if(d){
console.log("====any here?????????? k.Gb="+k.Gb.src)
d=new Q(a[0],a[1]);
f=this.map.M.se?this.map.M.se.style:"normal";
d=c.getTilesUrl(d,a[2],f);
k.loaded= q;
Fc(k,d);
}
k.loaded?this.vf():Gc(k,function(){e.vf()})
}else{
//未缓存的数据都走的这个地方,但只有未缓存的数据走的这里
console.log("----all is here?");
k=i*Math.pow(2,f.qm()-a[2]);
new H(a[0]*k,a[1]*k);
d=new Q(a[0],a[1]);//Q是一个对象,x,y两个属性
f=this.map.M.se?this.map.M.se.style:"normal";
d=c.getTilesUrl(d,a[2],f);//第二个参数是z,因此a数组里面原本就是[x,y,z]
k=new Hc(this,d,b,a,c);
Gc(k,function(){e.vf()});
k.$n();
this.wg[g]=k;
}
}
return d;
},
最后一句是增加的,其他的注释也好,输出也好,都是探查和验证的。具体不解释了。这里只是为了说明,a_方法的目的就是随时获取瓦片的地址,并设置其展示位置。瓦片可能已经下载了,是不需要请求的。如果你的鼠标在拖动地图,这个方法会疯狂的执行。但由于缓存的存在,因此浏览器还是受得了的。
然后顺着“a_”的调用方,我们需要修改的是“cI”方法。这个方法我不知道名字会不会变动,就像a_一样,不知道会不会在不同的版本文件里会变化,我看这几次的代码这两个方法的名字是没变的。
第二步,修改a_的调用方法
cI方法太长了,贴不过来,也看不过来,我贴相关的一部分吧
for(k=0;k<i;k++)this.a_([v[k][0],v[k][1],n],u,e,a)
哈哈,就这样,这部分也太简单了:-)
不过我们要修改成别的样子,把瓦片地址输出出来。这个其实不用我来讲了吧,大家都心里有数了。这也是为什么我上面修改了a_方法,让他返回瓦片地址。
有两点大家要注意,第一,不是每次调用a_方法都会获得瓦片地址,缓存了的瓦片地址是不返回瓦片地址的(undefined),只有新加载的瓦片会返回地址比如拖动或缩放了地图。第二,a_方法不是只计算瓦片地址,还包括加载瓦片、移动瓦片,使得显示符合用户要求。
for(k=0;k<i;k++){
var url = this.a_([v[k][0],v[k][1],n],u,e,a);
if(!!url&&window["$collector$"]&&window["$collector$"].appendTile){
var path="tiles/"+n+"/"+v[k][0]+"/"+v[k][1]+".png";
window["$collector$"].appendTile(path, url);
}
}
我把它修改成这样了,这要求我们定义一个全局变量对象$collector$,然后要求提供一个appendTile方法,然后把地址、路径等信息输出出来。我是这样写的,同时也是为了对应《百度地图2.0离线版的制作》文章,给出了瓦片在离线版中的位置。
第三步,编写瓦片输出代码
这个更简单了,大家可以随意发挥了。接口上面定义了,定义也是简单粗暴的。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>百度离线版2.0DEMO</title>
<script type="text/javascript" src="js/apiv2.0.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/bmap.css"/>
</head>
<body>
<div style="width:520px;height:340px;border:1px solid gray" id="container"></div>
<div id="list"></div>
</body>
</html>
<script type="text/javascript">
var $collector$ = {
appendTile: function(path, url){
addUrls(path, url);
}
};
function addUrls(path, url){
var div = document.getElementById("list");
var anchor = document.createElement("a");
anchor.href = url;
anchor.innerHTML = path;
div.appendChild(anchor);
var br = document.createElement("br");
div.appendChild(br);
}
var map = new BMap.Map("container",{mapType: BMAP_NORMAL_MAP}); //设置卫星图为底图
var point = new BMap.Point(111.404, 40.915); // 创建点坐标
map.centerAndZoom(point,5); // 初始化地图,设置中心点坐标和地图级别。
//map.addControl(new BMap.MapTypeControl());
map.addControl(new BMap.NavigationControl());
map.enableScrollWheelZoom(); // 启用滚轮放大缩小。
map.enableKeyboard(); // 启用键盘操作。
//map.setCurrentCity("北京"); // 设置地图显示的城市 此项是必须设置的
var marker = new BMap.Marker(point);
map.addOverlay(marker);
var polyline = new BMap.Polyline([
new BMap.Point(111.404, 40.915),
new BMap.Point(112.404, 42.915),
new BMap.Point(113.404, 39.915),
new BMap.Point(114.404, 42.915),
new BMap.Point(115.404, 39.915),
new BMap.Point(116.404, 42.915)
], {strokeColor:"blue", strokeWeight:2, strokeOpacity:0.5});
map.addOverlay(polyline);
</script>
效果图:
超链接的文本是离线版瓦片应该放的位置,链接地址是瓦片实际的网络地址。下载吧!
本方法修改简单,缺点是不能像前一版那样,窗口内的瓦片批量以此获取,这次是窗口移动到哪里,瓦片加载到哪里。
之所以没有像以前那样,主要是2.0的版本修改比较大,很多原先能获取到的数据现在都获取不到了。但地图的理论不变,计算方法不变。由于数据获取不到,因此光有理论也没用了。
1.3版的瓦片在2.0里面是直接可用的。