前言

在构建WebGIS的应用系统中,通常会遇到以下的建设需求。功能点如下:

  • 实现影像地图的展示,可以放大、缩小和浏览地图。
  • 地图的拖拽范围需要控制在合理的经纬度范围内。
  • 在影像地图侧边实现某乡镇级行政区的信息展示,包括名称,级别;以及支持在影像地图上进行矢量数据的展示,同时在显示的边界内展示乡镇信息。

通过以上的信息分析,大致的技术点和关键技术其实在个人博客中已经有一定的涉及。比如关于Leafletjs的二维WebGIS系统开发、如何在LeafLet上叠加影像地图、Leaflet如何限制地图的拖动范围、空间矢量数据如何导入PostGIS数据库、MybatisPlus中操作Geometry字段信息、LeafLet中展示GeoJSON数据。

系列文章地址如下表所示:

序号 博客地址
1 gis信息可视化之一Leaflet组件介绍
2 layerGroup在LeafLet中的实战
3 postgis空间数据导入及可视化
4 基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用
5 基于Leaflet的leaflet-sidebar侧边栏组件集成
6 Leaflet中如何限制地图的拖动范围
7 玩转Leaflet-带你吃透Control知识
8 LeafLet实战-扩展工具栏指南

本文将采用Leafletjs地图开发组件,围绕GeoJSON的可视化展示,以湖南省乡镇行政区划数据的查询,空间定位作为实践案例,完整讲述一个基础的WebGIS小功能,最后形成一个GeoJSON的可视化工具。

一、WebGIS可视化工具系统分析及设计

1、需求分析

在上面的前言部分,简单的对功能需求进行了分析。其实功能很简单,是最常见的WebGIS功能点。主要包括影像地图的展示、地图的放大和缩小,平移;影像底图图层和标签图层的叠加展示、湖南省乡镇行政区划数据的展示和空间定位,对GeoJSON数据进行地图定位,叠加自定义Marker对象,显示乡镇名称和自定义样式等功能。

2、业务架构

业务架构比较简单,针对简单的业务需求设计简单的架构。主要包含以下三层:

        数据层:数据层主要包含业务数据库,用于存储用户信息、权限数据等;矢量数据库主要包含湖南省乡镇行政区划矢量信息;影像底图就是瓦片和标签瓦片信息等;

        服务层:服务层在数据层的基础上,主要提供相应的数据查询服务能力,包含空间数据查询服务、空间分析服务、用户管理服务、地图展示服务;通过服务层,将相关底层的调用封装起来,供上层的应用层进行调用。

        应用层:应用层主要面向具体的使用用户。将直接调用服务层的服务组装成用户需要的功能。主要包含行政区划展示、空间数据定位展示、项目管理及用户管理功能。

3、技术架构

同样基于简单的业务需求,以及简单的应用架构,这里采用简单的单体架构模式。在此基础上可以进行架构的迭代和升级,保证业务的扩展性。

        前端技术栈:这里的前端依然采用最简单的es5架构,使用Jquery+Html5+css等经典原生开发模式。主要采用的技术如下:

序号 技术点 说明
1 Leaflet.js WebGIS 地图展示组件
2 leaflet-sidebar.js 基于Leaflet的侧边栏展示组件
3 thymeleaf 前端模板引擎
4 bootstrap 前端bootstrap组件库
5 bootstrap-table 基于bootstrap的表格组件库
6 jquery Dom操作和Ajax的操作库

后端技术栈:后端是经过改造的Ruoyi单体框架,主要改造点是完全的兼容PostgreSQL,很多原来MySQL的语法在迁移到PG后有很多的不兼容问题,在此基础上进行了升级和改造。

序号 技术点 说明
1 Springboot 基础技术框架
2 Mybatis-plus 操作数据库的ORM框架
3 flywaydb 自动管理数据组件
4 postgis-jdbc postgis数据库支持驱动
5 spring-boot-admin springboot监控组件
6 shiro shiro开源安全认证框架

空间数据库:空间数据库中不仅仅包含空间数据的存储,还有普通业务数据的存储。这里完全采用PostgreSQL和扩展PostGIS进行空间数据存储和分析需求。

二、WebGIS可视化工具空间数据处理

1、基础数据准备

在进行系统研发之前,需要提前准备湖南省的乡镇行政区划shp数据。这里使用的实例数据从互联网下载而成,仅供学习使用。

2、shp数据导入空间数据库

由于系统要实现将湖南省的所有乡镇信息全部导入到空间数据库PostGIS中,这里我们采用PostGIS自带的客户端工具进行导入的方式。具体操作方式略,有兴趣的朋友可以看之前写得博文或者自行查询搜索引擎查阅相关资料。

将数据导入空间数据库后,会在数据库中形成一张biz_hn_town的表,其中,biz_hn_town是在导入的时候自动把shp的文件名当成了表名。

可以查看一下这张表的物理结构,如下sql所示:

-- ----------------------------
-- Table structure for biz_hn_town
-- ----------------------------
DROP TABLE IF EXISTS "public"."biz_hn_town";
CREATE TABLE "public"."biz_hn_town" ("gid" int4 NOT NULL DEFAULT nextval('biz_hn_town_gid_seq'::regclass),"gml_id" varchar(80) COLLATE "pg_catalog"."default","name" varchar(80) COLLATE "pg_catalog"."default","layer" varchar(80) COLLATE "pg_catalog"."default","code" varchar(80) COLLATE "pg_catalog"."default","grade" int4,"geom" "public"."geometry"
);-- ----------------------------
-- Indexes structure for table biz_hn_town
-- ----------------------------
CREATE INDEX "biz_hn_town_geom_idx" ON "public"."biz_hn_town" USING gist ("geom" "public"."gist_geometry_ops_2d"
);-- ----------------------------
-- Primary Key structure for table biz_hn_town
-- ----------------------------
ALTER TABLE "public"."biz_hn_town" ADD CONSTRAINT "biz_hn_town_pkey" PRIMARY KEY ("gid");

3、乡镇行政区划数据查询

通过查询语句,我们可以看到

select * from biz_hn_town;

三、WebGIS可视化工具后端开发实现

1、相关类图设计

2、控制器类关键代码

package com.yelang.project.extend.map.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yelang.framework.web.controller.BaseController;
import com.yelang.framework.web.domain.AjaxResult;
import com.yelang.framework.web.page.TableDataInfo;
import com.yelang.project.extend.map.domain.HnTown;
import com.yelang.project.extend.map.service.IHnTownService;/***地图Controller* @author yelangking* @date 2023-5-7*/
@Controller
@RequestMapping("/extend/map")
public class MapController extends BaseController{private String prefix = "extend/map";@Autowiredprivate IHnTownService hnTownService;@RequiresPermissions("extend:map:view")@GetMapping()public String map(){return prefix + "/map";}@RequiresPermissions("extend:map:list")@PostMapping("/list")@ResponseBodypublic TableDataInfo list(HnTown hnTown){startPage();List<HnTown> list = hnTownService.selectList(hnTown);return getDataTable(list);}@RequiresPermissions("extend:map:geom")@GetMapping("/geojson/{id}")@ResponseBodypublic AjaxResult editSave(@PathVariable("id") Long id){HnTown hnTown = hnTownService.findGeoJsonById(id, null);return AjaxResult.success().put("data", hnTown.getGeomJson());}
}

3、Mapper关键代码

mapper这里采用了自定义的sql脚本,并有mybatis执行引擎来进行执行。将空间字段geom采用st_asgeojson方法转换成geojson字符串,并由前端leaflet.js进行渲染。

package com.yelang.project.extend.map.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yelang.project.extend.map.domain.HnTown;public interface HnTownMapper extends BaseMapper<HnTown>{static final String FIND_GEOJSON_SQL="<script>"+ "select st_asgeojson(geom) as geomJson from biz_hn_town "+ "where gid = #{gid} "+ "<if test='null != name'>and name like concat('%', #{name}, '%')</if>"+ "</script>";@Select(FIND_GEOJSON_SQL)HnTown findGeoJsonById(@Param("gid")Long gid,@Param("name")String name);
}
package com.yelang.project.extend.map.domain;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.handler.PgGeometryTypeHandler;import lombok.*;@TableName(value ="biz_hn_town",autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class HnTown {@TableId(value="gid")private Long gId;@TableField(value="gml_id")private String gmlId;private String name;private String layer;private String code;private Integer grade;@TableField(typeHandler = PgGeometryTypeHandler.class)private String geom;@TableField(exist=false)private String geomJson;
}

四、WebGIS可视化工具前端开发实现

1、地图定义

$("#mapid").height($(window).height());//动态设置高度L.CRS.CustomEPSG4326 = L.extend({}, L.CRS.Earth, {code: 'EPSG:4326',projection: L.Projection.LonLat,transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5),scale: function (zoom) {return 256 * Math.pow(2, zoom - 1);}
});//限制地图的拖动范围是正负90到正负180,这样才合理。
var maxBounds = L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180)); //构建视图限制范围 第一个参数是左上角经纬度 第二个参数是右下点经纬度
var mymap = L.map('mapid',{crs:L.CRS.CustomEPSG4326,maxBounds:maxBounds,attributionControl:false}).setView([29.052934, 104.0625], 5);
var showLayerGroup =L.featureGroup().addTo(mymap);L.tileLayer('http://localhost:8086/data/basemap_nowater/1_10_tms/{z}/{x}/{y}.jpg', {minZoom:1,
maxZoom: 16,
id: 'baseMap-nowater',
tileSize: 256,
zoomOffset: -1
}).addTo(mymap);//标签
L.tileLayer('http://localhost:8086/data/basemap_nowater/1-10label/{z}/{x}/{y}.png', {maxZoom: 10,minZoom:1,id: 'mapbox/label',tileSize: 256,zoomOffset: -1
}).addTo(mymap);var popup = L.popup();function onMapClick(e) {popup.setLatLng(e.latlng).setContent("当前坐标为:" + e.latlng.toString()).openOn(mymap);
}mymap.on('click', onMapClick);

2、初始化侧边栏

function initSidebar(){//初始化sidebar页面var sidebar = L.control.sidebar('sidebar', {position: 'right'}).addTo(mymap);//默认sidebar打开,并展示一个tab页sidebar.open();$("#xz_info").addClass("active");$("#home").addClass("active");//初始化行政区划表格initHnTownTable();}function initHnTownTable(){var options = {url: prefix + "/list",createUrl: prefix + "/add",updateUrl: prefix + "/edit/{id}",modalName: "乡镇行政区划",columns: [{checkbox: true},,{title: '操作',align: 'center',formatter: function(value, row, index) {var actions = [];actions.push('<a class="btn btn-success btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="previewTown(\'' + row.gid + '\',\''+row.name+'\')"><i class="fa fa-paper-plane"></i>定位</a>');return actions.join('');}}]};$.table.init(options);
}

3、空间预览定位

function previewTown(gid,name){var myStyle = {color:"red",weight:8,"opacity":0.6};$.ajax({  type:"get",  url:prefix + "/geojson/" + gid,  data:{},  dataType:"json",  cache:false,processData:false,success:function(result){if(result.code == web_status.SUCCESS){var areaLayer = L.geoJSON(JSON.parse(result.data),{style:myStyle}).addTo(mymap);var content = "<div>名称:"+name+"</div>" +"<div>时间:2020-05-04</div>" +"<div>面积:8.52 K㎡</div>";var myIcon = L.divIcon({html: "<div style='color:#fff;'>"+content+"</div>",className: 'my-div-icon',iconSize: 100});showLayerGroup.clearLayers();showLayerGroup.addLayer(areaLayer);mymap.fitBounds(areaLayer.getBounds());//中心点位L.marker(areaLayer.getBounds().getCenter(), { icon: myIcon}).addTo(showLayerGroup);}},error:function(){$.modal.alertWarning("获取空间信息失败");}});}

五、WebGIS可视化工具效果及使用体会

1、行政区划列表展示

在实际工 具的展示中可以看到,底图实现了自定义影像地图的加载,以及侧边栏表格的数据展示。在表格中展示了乡镇名称、级别以及定位操作按钮。点击定位按钮可以进行乡镇区划定位。

2、行政区划搜索及定位

点击列表中的定位按钮,可以实现当前乡镇空间的自动定位,并在地图中进行高亮展示定位。同时在列表中实现按照乡镇名字进行检索的功能,具体如下图所示(以中寨镇为例):

3、使用体会

通过这个简单的程序,集中演示了WebGIS乡镇行政区划数据可视化工具的基本功能,重点围绕WebGIS的相关技术,讲解如何开发可视化工具。基于该工具,基本满足我们的预期业务需求,实现了乡镇行政区划数据的展示及空间定位。对于掌握WebGIS的开发和实现空间数据可视化提供了良好的基础知识讲解。

总结

以上就是本文的主要内容,本文将重点讲解如何采用Leafletjs地图开发组件,围绕GeoJSON的可视化展示,以湖南省乡镇行政区划数据的查询,空间定位作为实践案例,完整讲述一个基础的WebGIS小功能,最后形成一个GeoJSON的可视化工具。希望这个可视化工具实现的技术路径可以作为您开发WebGIS程序的一些参考。行文仓促,如有问题,欢迎批评指针,更加环境在文章的最后留下您的宝贵意见和评论。

基于Leaflet的乡镇行政区划在WebGIS中的可视化工具实践相关推荐

  1. 在NS-3中安装可视化工具NeAnim

    在NS-3中安装可视化工具NeAnim NetAnim 是一个独立的,基于Qt4的离线动画演示工具,在ns-3的仿真过程中生成XML格式的trace文件,仿真结束后NetAnim读取该文件显示网络拓扑 ...

  2. 在NS-3中安装可视化工具pyviz的一些问题的解决

    转载声明:本文为寻同学原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 原文链接:https://blog.csdn.net/qq_31676673/article ...

  3. PyTorch中的可视化工具

    目录 一.网络结构的可视化 1.1 通过HiddenLayer可视化网络 1.2 通过PyTorchViz可视化网络 二.训练过程可视化 2.1 通过tensorboardX可视化训练过程 2.2 H ...

  4. python如何画出多个独立的图片_如何使用python语言中的可视化工具绘制多个图

    在使用的matplotlib第三方包的过程中,可以在画布上绘制一个图形之外,还可以绘制多个图形,根据分布来构成图形.下面利用具体的实例说明如何实现,操作如下: 工具/原料 python 截图工具 方法 ...

  5. python语言实现lassocv中的可视化显示_Python可视化神器Yellowbrick使用

    码农那点事儿 关注我们,一起学习进步 作者:Together_CZ 链接:https://blog.csdn.net/Together_CZ/article/details/86640784 在机器学 ...

  6. 从底层谈webgis原理设计与实现(九)WebGIS中的矢量查询(针对AGS和GeoServer)

    1.前言 在第七章里我们知道了WebGIS中要素的本质是UIComponent,而矢量图层的本质是包含了n(n>=0)个UIComponent的Canvas.我们在UIComponent的gra ...

  7. WebGIS学习(九)WebGIS中的矢量查询(针对AGS和GeoServer)

    1.前言 在第七章里我们知道了WebGIS中要素的本质是UIComponent,而矢量图层的本质是包含了n(n>=0)个UIComponent的Canvas.我们在UIComponent的gra ...

  8. 基于Leaflet的leaflet-sidebar侧边栏组件集成

    如果你需要在Leaflet地图中增加一个侧边栏,以此来做一个额外的数据处理,那么您可以使用现成的leaflet-sidebar组件来帮助您加快开发速度,同时,该组件基于leaflet进行了扩展,更加灵 ...

  9. 端午屈夫子祭-基于LeafLet的夫子一生时空轨迹纵览

    目录 前言 一.要素整理 1.屈夫子的相关资料 2.人物轨迹时间线 3.四维导图整理 二.时空轨迹界面设计 1.界面设计 2.可视化采用组件 三.时空轨迹展示实现 1.创建一个Html文件骨架文件 2 ...

最新文章

  1. ORM武器:NHibernate(三)五个步骤+简单对象CRUD+HQL
  2. 2016年度工作总结
  3. Linux下的下载工具 axel
  4. vivado的ip核使用-pll
  5. 病理分析常见数据集及常用模型方法总结
  6. 刷手识别:确认过“掌静脉”找到对的人
  7. php 61850,南瑞内部61850培训教程很好很强大-系统集成文档类资源
  8. linux 占用缓存前10_Linux 中的零拷贝技术
  9. python使用什么来表示不同级别的语句块-Python
  10. 【采用】风控老客户续贷业务知识
  11. Tomcat部署Maven的JavaWeb项目——这样我们写完程序把程序打包为war包,拿到用户那边启动服务器就可以运行了,简单轻松
  12. php ascii hex编码
  13. 本地音频播放,使用AVFoundation.framework中的AVAudioPlayer来实现
  14. Ionic--再次打开自动填充用户名和密码的问题解决方法
  15. 小程序真机调试访问不了接口_24小时从0到1开发阴阳师小程序
  16. android中播放gif动画之一
  17. 163的在线编辑器简析和配置使用
  18. [MATLAB]基本介绍
  19. wow工程修理机器人图纸_wow修理机器人74a型介绍及图纸怎么得
  20. 几种凹凸贴图(Bump Mapping)的学习记录

热门文章

  1. 深澜系统服务器架构,深澜基于用户策略的高性能校园网认证计费系统
  2. html点击图片翻转效果,jquery+css 点击图片旋转特效
  3. 微信小程序语音转化为文字
  4. 分布式profinet网络总线模块分线盒
  5. factorio蓝图代码_异星工厂 自制MOD代码修改教程
  6. SOHO中国董事长潘石屹的昨天今天和明天
  7. 古董VS2002安装
  8. 数据分析工具有哪些?
  9. 在java中String a=a,b=a;a==b为什么返回true?
  10. 哪种副业挣钱多?副业通过什么方式赚钱的呢?