基于SpringBoot和Leaflet的行政区划地图掩膜效果实战

本文主要是介绍基于SpringBoot和Leaflet的行政区划地图掩膜效果实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

一、掩膜小知识

1、GIS掩膜的实现原理

2、图层掩膜流程 

二、使用插件

1、leaflet-mask介绍

2、核心代码解释 

三、完整实例实现

1、后台逻辑实现

2、省级行政区划查询实现

3、行政区划定位及掩膜实现 

4、成果展示

总结


前言

        在之前的博客提过按空间矢量范围下载遥感,有兴趣的同学可以参考已下的博文地址:基于QGIS的研究区域遥感影像裁切下载方法-以岳麓区为例。在这篇博客中采用的是Qgis软件,这是 一款桌面端的GIS软件。在这里,首先简单解释一下gis中掩膜的相关概念。掩膜在制图中是一种遮盖工具,用于处理要素在显示上的冲突。掩膜可以理解为一种看不见的面要素,它遮挡住了不需要显示的图形。用这个工具可以将影像按面要素周长裁剪。

        存在两种类型的掩膜策略:一是:图层掩膜 - 是指在地图或场景中,某一要素图层或掩膜图层可以掩盖另一图层中的任何重叠要素。二是要素级掩膜 - 是指按照两图层间关系类所指定的方式对各相关要素进行的掩膜。无论采用哪种掩膜方式,掩膜要素的几何均会掩盖被掩膜要素的符号系统。 即使掩膜要素的符号化形状与几何不同,(例如,如果应用了符号缓冲),要素几何的形状会进行掩膜。 然而,被掩膜要素的符号系统会受到影响。 被掩膜要素看起来可能存在孔洞,但它们只是可见符号中的孔洞。 要素几何并未更改。

        本文讲解的是一种图层级的掩膜,即使用行政区划图层来进行掩膜。使用场景为,用户只需要在地图页面中展示目标行政区划内的影像信息,对于行政边界外的影像,则不展示。这就是WebGIS中掩膜的一种表达方式。本文重点讲解在Webgis中如何进行行政区划掩膜实现,通过代码实战的方式对功能进行详细的实现,采用网友编写一个掩膜组件,不仅避免了自己的区域绘制太小,也避免了不同行政区划切换时,有部分缝隙的问题。如果您目前也有WebGIS掩膜可视化需求,不妨来看看博客。

一、掩膜小知识

        在讲解地图之前,如果了解前端的朋友一定知道,在HTML5的应用中,可能会存在两个DIV,可能由于其内容和位置的设置存在空间重叠,有一部分区域会被另一个DIV进行遮盖。这种效果就是掩膜。(以上不是官网的定义,只是翻译成了大白话,易于大家理解)。通过上面的解释可以看出,在这个场景中涉及的图层起码有两个,而且存在空间折叠的关系。而实现效果就是通过叠加,使用遮罩这种方式来进行。

1、GIS掩膜的实现原理

        与上述Html的实现原始一致的,在这个场景当中。首先我们会使用栅格底图(一般是遥感影像)。然后在展示行政区划时,自动将行政区划外的地图遮住。比如在展示湖南省的行政区划时,只展示湖南省区域内的影像,对于湖南省外的区域则不展示,以空白的方式展现出来。先来看一下实际的效果。

2、图层掩膜流程 

        对于图层掩膜的流程,使用流程图描述如下:

         第一步是在地图上加载原始的遥感影像,可以是WMS或者XYZ瓦片。第二步是输入要叠加的升级行政区划范围,这里一般是采用GeoJSON的方式进行获取。第三步是从GeoJSON中解析出空间面信息,构建出遮罩范围,通过绘制遮罩面,设置遮罩面的透明度。同时将无需遮罩的范围留空,这样就能实现空间掩膜的效果。

二、使用插件

        在实现这个需求时,可以完全不用外部的插件,通过Leaflet自己构建Polygon面来实现遮罩掩膜的效果即可。但是使用自己绘制的面时,进行地图缩放时,会有一些不顺畅的原因。因此在开源社区找了一款开源的组件。通过组件来实现地图遮罩,方便又美观。

1、leaflet-mask介绍

        leaflet-mask是一个简单的地图遮罩层控件,继承自L.polygon。我们很多时候希望只显示某块区域内的内容,隐藏或者模糊区域外内容。此插件可以实现传入polygon的latlngs创建对应的遮罩图层。其gitee地址是leaflet-mask。大家可以将代码下载到本地,然后运行其官方的实例即可。

2、核心代码解释 

        对于这个插件来说,核心代码其实非常少,也是很容易看懂的。在下载的源代码中,可以直接打开来看,在src目录下有leaflet-Mask.js。使用文本编辑器或者javascript脚本编辑器打开这个脚本。

/*** 遮罩*/
L.Mask = L.Polygon.extend({options: {isRect: true,    //是否为矩形遮罩,如果为是,则使用northWest,northEast,sourthEast,sourthWest创建矩形遮罩层外边界,如果为false,则使用传入的坐标数组作为遮罩层外边界northWest: { lat: 180.0, lng: -180.0 },  //遮罩层西北角坐标northEast: { lat: 180.0, lng: 180.0 },  //遮罩层东北角坐标sourthEast: { lat: -180.0, lng: 180.0 }, //遮罩层东南角sourthWest: { lat: -180.0, lng: -180.0 }, //遮罩层西南角maskBoundary: null,    //遮罩层边界坐标showPolygons: []    //显示区域},initialize(options) {L.Util.setOptions(this, options);let latlngs = this.getMaskLatLngs();this._setLatLngs(latlngs);},/*** 画遮蔽层的相关方法*思路: 创建一个矩形作为遮罩层,构造函数传入的坐标作为内环* @see https://blog.csdn.net/mapmonster/article/details/104455516* * @param {*} latlngs */getMaskLatLngs() {let latlngs = [];//是矩形遮罩,则使用northWest,northEast,sourthEast,sourthWest创建矩形遮罩层外边界if (this.options.isRect) {this.options.maskBoundary = [];this.options.maskBoundary.push(this.options.northWest);this.options.maskBoundary.push(this.options.sourthWest);this.options.maskBoundary.push(this.options.sourthEast);this.options.maskBoundary.push(this.options.northEast);this.options.maskBoundary.push(this.options.northWest);}latlngs.push(this.options.maskBoundary);for (let i = 0; i < this.options.showPolygons.length; i++) {latlngs = latlngs.concat(this.options.showPolygons[i].getLatLngs());}return latlngs;}
});/*** 合乎leaflet语法* @param {*} options * @returns */
L.mask = function (latlngs, options) {return new L.Mask(latlngs, options);
};

        所有代码加起来,包括注释仅仅有52行,而且采用符合Leaflet的语法方式进行展示。可以看到这里的遮罩层是一个扩展自Polygon类的子类。这里设置了其默认的范围,即四个边界点。

三、完整实例实现

        本节重点将对实例进行完整的介绍,首先我们将遥感影像完整的展示出来。同时在界面右边展示行政区划信息,支持按省级行政区划名称进行检索。点击所在省份,将查询后台的接口返回GeoJSON格式的行政区划边界数据,然后调用leaflet-mask的掩膜对象,实现行政区域的遮罩。

1、后台逻辑实现

        这里介绍省级行政区划列表和查询省级行政区划GeoJson边界信息接口。包括控制层代码和数据库访问层代码。核心代码如下:

package com.yelang.project.extend.earthquake.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.ui.ModelMap;
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.earthquake.domain.EarthQuakeProvinceStatVO;
import com.yelang.project.extend.earthquake.domain.EarthquakeInfo;
import com.yelang.project.extend.earthquake.domain.Province;
import com.yelang.project.extend.earthquake.service.IEarthquakeInfoService;
import com.yelang.project.extend.earthquake.service.IProvinceService;@Controller
@RequestMapping("/eq/province")
public class ProvinceController extends BaseController{private String prefix = "earthquake/province";@Autowiredprivate IProvinceService provinceService;@Autowiredprivate IEarthquakeInfoService earthQuakeInfoService;@RequiresPermissions("eq:province:view")@GetMapping()public String map(){return prefix + "/map";}@RequiresPermissions("eq:province:list")@PostMapping("/list")@ResponseBodypublic TableDataInfo list(Province province){startPage();List<Province> list = provinceService.selectList(province);return getDataTable(list);}@RequiresPermissions("eq:province:geom")@GetMapping("/geojson/{id}")@ResponseBodypublic AjaxResult getGeojson(@PathVariable("id") Long id){Province province = provinceService.findGeoJsonById(id, null);return AjaxResult.success().put("data", province.getGeomJson());}}

        根据省份id查询省份行政区划边界GeoJSON的数据库访问层核心代码如下:

package com.yelang.project.extend.earthquake.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.earthquake.domain.Province;/*** 省级行政区划数据接口* @author wuzuhu**/
public interface ProvinceMapper extends BaseMapper<Province>{static final String FIND_GEOJSON_SQL="<script>"+ "select st_asgeojson(geom) as geomJson from biz_province "+ "where id = #{id} "+ "<if test='null != name'>and name like concat('%', #{name}, '%')</if>"+ "</script>";@Select(FIND_GEOJSON_SQL)Province findGeoJsonById(@Param("id")Long id,@Param("name")String name);}

2、省级行政区划查询实现

        在地图上我们需要首先展示行政区划列表,这里采用sidebar的组件进行展示。同时在列表中支持按照省级行政区划名称进行模糊查询。

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},{field: 'id',title: '',visible: false},{field: 'name',title: '省份'},{field: 'type',title: '类别'},{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.id + '\',\''+row.name+'\')"><i class="fa fa-paper-plane"></i>定位</a>');return actions.join('');}}]};$.table.init(options);
}

3、行政区划定位及掩膜实现 

        点击行政区划列表操作栏中的“定位”按钮,可以实现行政区划定位,以及进行区域掩膜。点击定位的时候,会通过后台的查询接口获取当前点击的行政区划的GeoJSON数据信息。关键方法如下:

function previewTown(gid,name){var myStyle = {color:"white",weight:5,"opacity":1};$.ajax({  type:"get",  url:prefix + "/geojson/" + gid,  data:{},  dataType:"json",  cache:false,processData:false,success:function(result){if(result.code == web_status.SUCCESS){var geojson = JSON.parse(result.data);var areaLayer = L.geoJSON(geojson,{style:myStyle}).addTo(mymap);showLayerGroup.clearLayers();showLayerGroup.addLayer(areaLayer);mymap.setView(areaLayer.getBounds().getCenter(),8);showMask(geojson);}},error:function(){$.modal.alertWarning("获取空间信息失败");}});
}

        通过获取GeoJson的接口获取行政区划的空间位置之后,再调用leaflet-mask的构造方法将遮罩面渲染出来。首先来看一下获取的行政区划GeoJSON数据信息:

function showMask(geojson){var showPolygons = [];var pArray = [];for (var i = 0; i < geojson.coordinates.length; i++) {var points = [];$.each(geojson.coordinates[i],function(k,v){points.push({lat:v[1],lng:v[0]});});//将闭合区域加到遮蔽层上,每次添加完后要再加一次西北角作为下次添加的起点和最后一次的终点pArray = pArray.concat(points);pArray.push(pArray[0]);}var polygon = L.polygon(pArray, { color: 'green' });showPolygons.push(polygon);var mask = L.mask({showPolygons: showPolygons,color: '#C0C0C0',fillOpacity: 1,renderer: L.canvas({ padding: 1 })  //解决遮罩层拖拽与缩放显示不全的Bug});showLayerGroup.addLayer(mask);}

        通过以上的代码即可完成按照行政区划进行掩膜可视化的效果。

4、成果展示

        最后我们来看一下最终生成的省级行政区划掩膜可视化效果。通过点击分析按钮,进行当前省份信息的掩膜可视化。闲言少叙,上图为证。

天津市掩膜效果图 

湖北省掩膜效果图

云南省掩膜效果图 

 贵州省掩膜效果图 

总结

        以上就是本文的主要内容,本文讲解的是一种图层级的掩膜,即使用行政区划图层来进行掩膜。使用场景为,用户只需要在地图页面中展示目标行政区划内的影像信息,对于行政边界外的影像,则不展示。这就是WebGIS中掩膜的一种表达方式。行文仓促,难免有误,欢迎各位专家朋友批评指正,不甚感谢。

本文写作过程中参考以下博客,站在巨人的肩膀上,才能看得更高。

1、Leaflet实现地图按照行政区划遮罩。

2、Leaflet添加掩膜。

3、leaflet实现地图遮罩。

这篇关于基于SpringBoot和Leaflet的行政区划地图掩膜效果实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/851555

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory