基于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实现地图遮罩。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/287463.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ansys Speos | Light Expert Group探测器组使用技巧

附件下载 联系工作人员获取附件 概述 相机挡板的设计需要在光路的不同位置同步多个照度图&#xff0c;以尽量减少杂散光。2023R2 Speos提供了一种新的探测器&#xff0c;用于高阶杂散光分析&#xff0c;可以同时对多个探测器进行光线追迹。Light Expert工具可以即时过滤3D视…

SQLite数据库成为内存中数据库(三)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 下一篇&#xff1a;SQLite中的原子提交&#xff08;四) ​​ SQLite数据库通常存储在单个普通磁盘中文件。但是&#xff0c;在某些情况下&#xff0c;数据库可能…

业务服务:xss攻击

文章目录 前言一、使用注解预防1. 添加依赖2. 自定义注解3. 自定义校验逻辑4. 使用 二、使用过滤器1. 添加配置2. 创建配置类3. 创建过滤器4. 创建过滤器类5. 使用 前言 xss攻击时安全领域中非常常见的一种方法&#xff0c;保证我们的系统安全是非常重要的 xss攻击简单来说就…

代码随想录 图论-并查集

代码随想录 (programmercarl.com) 寻找图中是否存在路径这道题中的类可看做并查集的标准类 目录 1971.寻找图中是否存在路径 684.冗余连接 685.冗余连接II 1971.寻找图中是否存在路径 1971. 寻找图中是否存在路径 已解答 简单 相关标签 相关企业 有一个具有 n 个顶…

使用ai智能写作场景之gpt整理资料,如何ai智能写作整理资料

Ai智能写作助手&#xff1a;Ai智能整理资料小助手 Ai智能整理资料小助手可试用3天&#xff01; 通俗的解释一下怎么用ChatGPT来进行资料整理&#xff1a; 搜寻并获取指定数量的特定领域文章&#xff1a; 想像你在和我说话一样&#xff0c;告诉我你想要多少篇关于某个话题的文…

Flask python :logging日志功能使用

logging日志的使用 一、了解flask日志1.1、Loggers记录器1.2、Handlers 处理器1.3、Formatters 格式化器 二、使用日志2.1、官网上的一个简单的示例2.2、基本配置2.3、具体使用示例2.4、运行 三、写在最后 一、了解flask日志 日志是一种非常重要的工具&#xff0c;可以帮助开发…

【双指针】Leetcode 查找总价格为目标值的两个商品

题目解析 LCR 179. 查找总价格为目标值的两个商品 本题很友好&#xff0c;只需要返回任意一个 算法讲解 这道题很显然就是使用对撞双指针&#xff0c;一个从左边&#xff0c;一个从右边&#xff0c;两边进行和target比较来移动 代码编写 class Solution { public:vector<…

谷粒商城——缓存——SpringCache

1. 配置使用 首先需要导入相关的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency> 随后在配置文件中进行配置&#xff1a; spring:cache:t…

C语言文件操作(详细)

⽬录 一. 为什么使⽤⽂件&#xff1f; 二. 什么是⽂件&#xff1f; 三. ⼆进制⽂件和⽂本⽂件&#xff1f; 四. ⽂件的打开和关闭 五. ⽂件的顺序读写 六. ⽂件的随机读写 七. ⽂件读取结束的判定 八. ⽂件缓冲区 一. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#…

STM32技术打造:智能考勤打卡系统 | 刷卡式上下班签到自动化解决方案

文章目录 一、简易刷卡式打卡考勤系统&#xff08;一&#xff09;功能简介原理图设计程序设计 哔哩哔哩&#xff1a; https://www.bilibili.com/video/BV1NZ421Y79W/?spm_id_from333.999.0.0&vd_sourcee5082ef80535e952b2a4301746491be0 一、简易刷卡式打卡考勤系统 &…

docker拉取镜像

docker 拉取镜像 命令格式 docker pull 仓库名称[:标签] 从下载过程可以看出&#xff1a; &#xff08;1&#xff09;镜像文件是由若干层组成&#xff0c;即&#xff1a;AUFS联合文件系统。这是实现增量保存与更新的基础 &#xff08;2&#xff09;下载过程会输出各层镜像的信…

界面控件DevExpress WinForms/WPF v23.2 - 电子表格支持表单控件

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

String类(三)

文章目录 string类&#xff08;三&#xff09;string类的模拟实现&#xff1a;1.默认成员变量和函数2.string的长度和下表引用3.字符串拷贝构造4. 赋值拷贝5.字符串比较6.字符串的增添操作7.insert插入操作8.遍历字符 string类&#xff08;三&#xff09; string类的模拟实现&…

Django(二)-搭建第一个应用(1)

一、项目环境和结构 1、项目环境 2、项目结构 二、编写项目 1、创建模型 代码示例: import datetimefrom django.db import models from django.utils import timezone# Create your models here.class Question(models.Model):question_text models.CharField(max_length2…

ES6 基础

文章目录 1. 初识 ES62. let 声明变量3. const 声明常量4. 解构赋值 1. 初识 ES6 ECMAScript6.0(以下简称ES6)是JavaScript语言的下一代标准&#xff0c;已经在2015年6月正式发布了。它的目标&#xff0c;是使得」JavaScript语言可以用来编写复杂的大型应用程序&#xff0c;成为…

【环境配置】Ubuntu MySQL 8.0.28 安装并允许外部客户端连接

文章目录 MySQL 安装步骤配置 MySQL Server 允许外部连接 MySQL 安装步骤 步骤一&#xff1a;在 MySQL 官网找到 apt 仓库&#xff0c;下载最新的仓库 点击 Download&#xff1a; 输入如下命令&#xff1a; sudo wget -c https://dev.mysql.com/get/mysql-apt-config_0.8…

Java拆装箱及128陷阱

有以下一段代码&#xff1a; Integer a 123; Integer b 123; int c 123; int d 123; System.out.println(c d); System.out.println(a b); System.out.println(a c); 这段代码运行的结果是什么呢&#xff1f; c d 一定为True。 由于Java中存在自动拆装箱&#xff0…

【Spring】Spring框架中的一个核心接口ApplicationContext 简介,以及入口 Run() 的源码分析

一、简介 ApplicationContext 是Spring框架中的一个核心接口&#xff0c;它是Spring IoC容器的实现之一&#xff0c;用于管理和组织应用程序中的各种Bean&#xff0c;同时提供了一系列功能来支持依赖注入、AOP等特性。 简单来说&#xff0c;ApplicationContext 是一个大型的、…

如何备考2025年AMC8竞赛?吃透2000-2024年600道真题(免费送题)

最近有家长朋友问我&#xff0c;现在有哪些类似于奥数的比赛可以参加&#xff1f;我的建议可以关注下AMC8的竞赛&#xff0c;类似于国内的奥数&#xff0c;但是其难度要比国内的奥数低一些&#xff0c;而且比赛门槛更低&#xff0c;考试也更方便。比赛的题目尤其是应用题比较有…

FPGA之组合逻辑与时序逻辑

数字逻辑电路根据逻辑功能的不同&#xff0c;可以分成两大类&#xff1a;组合逻辑电路和时序逻辑电路&#xff0c;这两种电路结构是FPGA编程常用到的&#xff0c;掌握这两种电路结构是学习FPGA的基本要求。 1.组合逻辑电路 组合逻辑电路概念&#xff1a;任意时刻的输出仅仅取决…