概述
在前面的文章中,讲述了通过“抽稀+后台生成图片”的方式解决大量POI点展示的一种思路,后面看了tilestache的矢量切片方式,自己仔细思考了下,提出了本文大量POI点的展示解决方案。
tilestache
大概看了下tilestache,理解了下,大概解决思路是这样的:随着地图四至范围的变换,实时的去请求数据,并将数据在前段渲染,这样就大大提升了大量点的展示的效率问题。
效果
实现代码
1、后台实现
后台实现非常简单,通过servlet返回查询结果,根据四至作为条件进行查询,代码如下:
- package com.lzugis.web;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.util.List;
- import java.util.Map;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import net.sf.json.JSON;
- import net.sf.json.JSONArray;
- import org.springframework.jdbc.core.JdbcTemplate;
- import com.lzugis.db.SpringUtil;
- /**
- * Servlet implementation class PoiServlet
- */
- @WebServlet(description = "poi servlet", urlPatterns = {"/getpois"})
- public class PointsServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- /**
- * @see javax.servlet.http.HttpServlet#HttpServlet()
- */
- public PointsServlet() {
- super();
- // TODO Auto-generated constructor stub
- }
- /**
- * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
- */
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // TODO Auto-generated method stub
- this.doPost(request, response);
- }
- /**
- * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
- */
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // TODO Auto-generated method stub
- String bbox= request.getParameter("bbox");
- int z = Integer.parseInt(request.getParameter("z").toString());
- System.out.println(z+","+bbox);
- String[] extent = bbox.split(",");
- double xmin = Double.parseDouble(extent[0]),
- ymin = Double.parseDouble(extent[1]),
- xmax = Double.parseDouble(extent[2]),
- ymax = Double.parseDouble(extent[3]);
- JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringUtil.getBean("jdbcTemplate");
- String sqlQuery = "select * from county where x>=? and x<=? and y>=? and y<=?";
- List<Map<String, Object>> list = jdbcTemplate.queryForList(sqlQuery, new Object[]{xmin,xmax,ymin,ymax});
- JSON json = JSONArray.fromObject(list);
- response.setContentType("text/html;charset=utf-8");
- PrintWriter out = response.getWriter();
- out.println(json);
- out.flush();
- out.close();
- }
- }
2、前台实现
- <!DOCTYPE html>
- <html>
- <head lang="en">
- <meta charset="UTF-8">
- <title>openlayers map</title>
- <link rel="stylesheet" href="http://localhost:63342/lzugis/plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">
- <style>
- html, body, #map{
- padding:0;
- margin:0;
- height:100%;
- width:100%;
- overflow: hidden;
- }
- </style>
- <script src="http://localhost:63342/lzugis/plugin/OpenLayers-2.13.1/OpenLayers.js"></script>
- <script src="http://localhost:63342/lzugis/plugin/jquery/jquery-1.8.3.js"></script>
- <script src="http://localhost:63342/lzugis/example/openlayers/ol2/extend/Grid.js"></script>
- <script>
- var map, sld;
- $(window).load(function() {
- var format = 'image/png';
- var bounds = new OpenLayers.Bounds(
- 73.45100463562233, 18.16324718764174,
- 134.97679764650596, 53.531943152223576
- );
- var options = {
- controls: [],
- maxExtent: bounds,
- maxResolution: 0.2403351289487642,
- projection: "EPSG:4326",
- units: 'degrees'
- };
- map = new OpenLayers.Map('map', options);
- var tiled = new OpenLayers.Layer.WMS(
- "Geoserver layers - Tiled",
- "http://localhost:8088/geoserver/lzugis/wms",
- {
- "LAYERS": 'province',
- "STYLES": '',
- format: format
- },
- {
- buffer: 0,
- displayOutsideMaxExtent: true,
- isBaseLayer: true,
- yx : {'EPSG:4326' : true}
- }
- );
- map.addLayers([tiled]);
- OpenLayers.INCHES_PER_UNIT["千米"] = OpenLayers.INCHES_PER_UNIT["km"];
- OpenLayers.INCHES_PER_UNIT["米"] = OpenLayers.INCHES_PER_UNIT["m"];
- OpenLayers.INCHES_PER_UNIT["英里"] = OpenLayers.INCHES_PER_UNIT["mi"];
- OpenLayers.INCHES_PER_UNIT["英寸"] = OpenLayers.INCHES_PER_UNIT["ft"];
- //比例尺
- map.addControl(new OpenLayers.Control.ScaleLine({topOutUnits:"千米",topInUnits:"米",bottomOutUnits:"英里",
- bottomInUnits:"英寸"
- }));
- map.addControl(new OpenLayers.Control.Zoom());
- map.addControl(new OpenLayers.Control.Navigation());
- map.addControl(new OpenLayers.Control.OverviewMap());
- map.zoomToExtent(bounds);
- var baseName = "http://localhost:8081/lzugis/getpois";
- var protocol = new OpenLayers.Protocol.HTTP({
- url: baseName
- });
- var strategy = new OpenLayers.Strategy.Grid();
- var vectors = new OpenLayers.Layer.Vector("Vector", {
- strategies: [strategy],
- protocol: protocol
- });
- map.addLayer(vectors);
- var options = {
- hover: true
- };
- var select = new OpenLayers.Control.SelectFeature(vectors, options);
- map.addControl(select);
- select.activate();
- });
- </script>
- </head>
- <body>
- <div id="map">
- </div>
- </body>
- </html>
在此处,调用了一个扩展的Strategy,该Strategy里实现了数据的实时调用与数据展示,扩展Grid.js代码如下:
- OpenLayers.Strategy.Grid = OpenLayers.Class(OpenLayers.Strategy, {
- grid: null,
- buffer: 1,
- loadedBounds: null,
- zoom: null,
- geometryFeatureMap: {},
- tiles: {},
- initialize: function(options) {
- OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
- },
- destroy: function() {
- this.clearGrid();
- this.grid = null;
- this.tileSize = null;
- OpenLayers.Strategy.prototype.destroy.apply(this, arguments);
- },
- activate: function() {
- var activated = OpenLayers.Strategy.prototype.activate.call(this);
- if(activated) {
- this.layer.events.on({
- "moveend": this.update,
- "refresh": this.update,
- scope: this
- });
- if(this.layer.visibility == true || this.preload) {
- this.update();
- }
- else {
- this.layer.events.on({
- "visibilitychanged": this.load,
- scope: this
- });
- }
- }
- return activated;
- },
- deactivate: function() {
- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
- if(deactivated) {
- this.layer.events.un({
- "moveend": this.update,
- "refresh": this.update,
- "visibilitychanged": this.load,
- scope: this
- });
- }
- return deactivated;
- },
- loadData: function(bbox,zoom) {
- var scope = this;
- var url = scope.layer.protocol.url+"?bbox="+bbox+"&z="+zoom;
- $.ajax({
- type : "POST",
- cache: false,
- url : url,
- async : false,
- success : function(data) {
- scope.readDone(data);
- }
- });
- },
- update: function() {
- var bounds = this.layer.map.getExtent();
- if (bounds == null) return;
- var map = this.layer.map
- var curZoom = map.zoom;
- if (curZoom != this.zoom) {
- this.layer.destroyFeatures();
- this.geometryFeatureMap = {};
- this.tiles = {};
- this.zoom = curZoom
- }
- this.loadData(bounds.toBBOX(),curZoom);
- },
- readDone: function(data) {
- this.merge(data, this.options);
- },
- merge: function(data, options) {
- var data = eval("("+data+")");
- console.log("供查询到"+data.length+"条数据");
- if(data.length > 0) {
- var features = [];
- for(var i=0, len=data.length; i<len; ++i) {
- var d = data[i];
- var feature = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(d.x, d.y),
- d
- );
- features.push(feature);
- }
- this.layer.addFeatures(features);
- }
- },
- CLASS_NAME: "OpenLayers.Strategy.Grid"
- });