概述:
经过一个春节的休整,今天终于开始了!不论什么时候,都不要忘记学习,学习是一辈子的事情!今天,我来说说如何实现天地图的离线以及Openlayers加载离线数据实现天地图数据的展示。
实现:
1、获取天地图的数据
可以通过网络上下载各大地图的工具将天地图的数据下载下来,并制作成mbtiles文件。制作过程在此就不详述,将已经制作好的一个文件上传到了百度网盘,需要的童鞋可以下载哦~~~~
下载链接:http://pan.baidu.com/s/1dEmNtnF 密码:xqd8
2、读取mbtiles并返回到页面
mbtiles其实就是一个sqllite数据库, 其详细可移步至http://www.cnblogs.com/i-gps/p/3919475.html查看详细。在此方案中,我用了一个servlet,具体的实现代码如下:
package com.lzugis.web;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Administrator on 2016/2/27.
*/
@WebServlet(description = "tian ditu tile", urlPatterns = {"/tdttile"})
public class TiandituTile extends HttpServlet {
private String tilepath = "D:/data/tdt/";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String tile_column = request.getParameter("X");
String tile_row = request.getParameter("Y");
String zoom_level = request.getParameter("L");
String layer = request.getParameter("T");
// TODO Auto-generated method stub
try {
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("数据库驱动未找到!");
}
// 得到连接 会在你所填写的目录建一个你命名的文件数据库
Connection conn;
try {
String conurl = "jdbc:sqlite:"+tilepath+layer+".mbtiles";
conn = DriverManager.getConnection(conurl,null,null);
// 设置自动提交为false
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
//判断表是否存在
ResultSet rsTables = conn.getMetaData().getTables(null, null, "tiles", null);
if(!rsTables.next()){
System.out.println("表不存在");
}
// 得到结果集
String sql = "SELECT * FROM tiles WHERE zoom_level = "+zoom_level+
" AND tile_column = "+tile_column+
" AND tile_row = "+tile_row;
ResultSet rs = stmt.executeQuery(sql);
if(rs.next()) {
byte[] imgByte = (byte[]) rs.getObject("tile_data");
InputStream is = new ByteArrayInputStream(imgByte);
OutputStream os = response.getOutputStream();
try {
int count = 0;
byte[] buffer = new byte[1024 * 1024];
while ((count = is.read(buffer)) != -1) {
os.write(buffer, 0, count);
}
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
os.close();
is.close();
}
}
else{
System.out.println(sql);
System.out.println("未找到图片!");
}
rs.close();
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
System.out.println("SQL异常!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
}
其中,请求地址为:http://localhost:8081/lzugis/tdttile?T=vec_c&L=5&X=25&Y=3,请求的结果如下所示:
3、openlayers调用
从网上拔了下openlayers加载天地图的代码,并稍作修改,扩展了一个openlayers图层TiandituLayer,其代码如下:
OpenLayers.Layer.TiandituLayer = OpenLayers.Class(OpenLayers.Layer.Grid,{
mapType : null,
mirrorUrls : null,
topLevel : null,
bottomLevel : null,
//用于标识是本地天地图切片库还是访问在线天地图
isOnline:true,
topLevelIndex : 0,
bottomLevelIndex : 20,
topTileFromX : -180,
topTileFromY : 90,
topTileToX : 180,
topTileToY : -270,
isBaseLayer : true,
initialize : function(name, url, options) {
options.topLevel = options.topLevel ? options.topLevel
: this.topLevelIndex;
options.bottomLevel = options.bottomLevel ? options.bottomLevel
: this.bottomLevelIndex;
options.maxResolution = this
.getResolutionForLevel(options.topLevel);
options.minResolution = this
.getResolutionForLevel(options.bottomLevel);
var newArguments = [ name, url, {}, options ];
OpenLayers.Layer.Grid.prototype.initialize.apply(this,
newArguments);
},
clone : function(obj) {
if (obj == null) {
obj = new OpenLayers.Layer.TiandituLayer(this.name,
this.url, this.options);
}
obj = OpenLayers.Layer.Grid.prototype.clone
.apply(this, [ obj ]);
return obj;
},
getURL : function(bounds) {
var level = this.getLevelForResolution(this.map.getResolution());
var coef = 360 / Math.pow(2, level);
var x_num = this.topTileFromX < this.topTileToX ? Math
.round((bounds.left - this.topTileFromX) / coef) : Math
.round((this.topTileFromX - bounds.right) / coef);
var y_num = this.topTileFromY < this.topTileToY ? Math
.round((bounds.bottom - this.topTileFromY) / coef)
: Math.round((this.topTileFromY - bounds.top) / coef);
var type = this.mapType;
var url = this.url;
if (this.mirrorUrls != null) {
url = this.selectUrl(x_num, this.mirrorUrls);
}
return this.getFullRequestString({
T : type,
X : x_num,
Y : y_num,
L : level
}, url);
},
getFullRequestString: function(params, url){
url = url+'?T='+params.T+'&L='+params.L+'&X='+params.X+'&Y='+params.Y;
return url;
},
selectUrl : function(a, b) {
return b[a % b.length]
},
getLevelForResolution : function(res) {
var ratio = this.getMaxResolution() / res;
if (ratio < 1)
return 0;
for ( var level = 0; ratio / 2 >= 1;) {
level++;
ratio /= 2;
}
return level;
},
getResolutionForLevel : function(level) {
return 360 / 256 / Math.pow(2, level);
},
getMaxResolution : function() {
return this.getResolutionForLevel(this.topLevelIndex)
},
getMinResolution : function() {
return this.getResolutionForLevel(this.bottomLevelIndex)
},
CLASS_NAME : "OpenLayers.Layer.TiandituLayer"
});
在代码中新建一个TiandituLayer,并添加到map中即可实现,代码如下:
OpenLayers MapQuest Demo
说明:
1、代码中vec_c为天地图矢量层,cva_c为天地图标注层,与天地图的名称相一致;
2、vec_c为离线的地图,cva_c为在线的,通过参数isOnline区分其为离线还是在线;
完成后效果: