概述:
经过一个春节的休整,今天终于开始了!不论什么时候,都不要忘记学习,学习是一辈子的事情!今天,我来说说如何实现天地图的离线以及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中即可实现,代码如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="apple-mobile-web-app-capable" content="yes"> <title>OpenLayers MapQuest Demo</title> <link rel="stylesheet" href="../../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css"> <script src="../../../../plugin/OpenLayers-2.13.1/OpenLayers.js"></script> <script src="TiandituLayer-src.js"></script> <style type="text/css"> html, body, #map{ padding:0; margin:0; height:100%; width:100%; overflow: hidden; } </style> <script type="text/javascript"> var map; function init(){ var vec_c = new OpenLayers.Layer.TiandituLayer("vec_c", "http://localhost:8081/lzugis/tdttile",{ mapType:"vec_c", topLevel: 2, bottomLevel: 10, isBaseLayer:true, isOnline:false }); var cva_c = new OpenLayers.Layer.TiandituLayer("cva_c", "http://t0.tianditu.com/DataServer",{ mapType:"cva_c", topLevel: 0, bottomLevel: 18, isBaseLayer:false, isOnline:true }); map = new OpenLayers.Map({ div: "map", projection: "EPSG:4326", layers: [cva_c,vec_c,img_c], numZoomLevels:20, center: [103.847, 36.0473], zoom: 2 }); map.addControl(new OpenLayers.Control.LayerSwitcher()); map.addControl(new OpenLayers.Control.MousePosition()); } </script> </head> <body onload="init()"> <div id="map"></div> </body>说明:
1、代码中vec_c为天地图矢量层,cva_c为天地图标注层,与天地图的名称相一致;
2、vec_c为离线的地图,cva_c为在线的,通过参数isOnline区分其为离线还是在线;
完成后效果: