前端离线地图 - 热力图

设计图

设计图涉及的功能点

  • 需要通过下载GeoJson数据来只显示自己想要显示地图模块
  • 绘制行政区区分虚线
  • 给每个行政区添加文字标识
  • 根据数据的区间来显示区块的颜色
  • 根据坐标点来绘制热力图

初始化地图

因为项目中可能有多个地方需要使用。我创建了一个class来初始化地图。代码如下

less 复制代码
 // 基础leaflet
 npm i leaflet
 // 需要下载相关包如下
 npm i leaflet-boundary-canvas  // 只显示边界
 ​
 npm i heatmap.js/plugins/leaflet-heatmap // 热力图
 ​
ini 复制代码
 import L from 'leaflet';
 import 'leaflet-boundary-canvas';
 import HeatmapOverlay from 'heatmap.js/plugins/leaflet-heatmap';
 ​
 export default class LMap {
     map: L.Map;
     dom: HTMLElement;
     url = '/roadmap/{z}/{x}/{y}.png';
     geojson?: any;
     nameTagLayer?: any;
     mapDefaultColor = 'rgba(171, 205, 255, 1)';
     textLayerGroup?: L.LayerGroup;
     baseLayer?: any;
     shiyanCode = [420303, 420302];
     constructor(dom: HTMLElement, opt?: L.MapOptions) {
       this.dom = dom;
       // 初始化地图
       this.map = L.map(dom, {
           ...{
                 center: [36.67, 105.17],
                 zoom: 4.4,
                 zoomControl: false,
                 attributionControl: false,
             },
             ...opt,
         });
     }
 }

代码解析

  • 创建一个自定义地图对象
  • 初始化一个map对象。具体option选项可以参考官网文档

保留特定的行政区块

通过上面的GeoJson网站来下载到GeoJson的json包之后。利用leaflet-boundary-canvas插件来绘制边界。

kotlin 复制代码
    drawBoundary(geojson) {
         this.geojson = geojson;
         this.baseLayer = L.TileLayer.boundaryCanvas(this.url, {
             boundary: geojson,
         }).addTo(this.map);
     }

代码解析

对行政区块做虚线区分

php 复制代码
    drawBoundaryLine(geojson?: any, style?: any) {
         // 绘制geojson的区域线
         return L.geoJSON(geojson || China, {
             ...{
                 stroke: true,
                 color: '#62F6E5',
                 weight: 1,
                 fillColor: '#053B39',
                 fillOpacity: 1,
                 dashArray: 10
             },
             ...style,
         }).addTo(this.map);
     }

代码解析

  • 对行政区的分界线进行自定义。具体可以参考svg的属性说明
  • 其中配置dashArray来绘制虚线
  • color属性为线的颜色
  • fillColor为行政区颜色区分

添加文字标识

ini 复制代码
     drawTextLayer(data: any, unit?: any) {
         // 文字
         const textLayer: any = [];
         this.map.eachLayer((layer: any) => {
             if (layer && layer.feature) {
                 const { adcode, center, name } = layer.feature.properties;
                 const item = data.find((item: any) => item.administrativeDivisionCode == adcode);
                 const myIcon = L.divIcon({
                     className: 'location-tag',
                     html: `<div class="province-title fs14 color-white text-center mapPointText">
                          
                           <div class="fs12 color-white">${this.shiyanCode.indexOf(adcode) > -1 ? '城区' : name}</div>
                            <div class="color-white fs12">(${item ? item.nums : 0}${unit || '人'})</div>
                           </div>`,
                     iconSize: [120, 20],
                 });
                 if (center && name) {
                     if (this.shiyanCode.indexOf(adcode) > -1) {
                         textLayer.push(L.marker([32.627576, 110.784317], { icon: myIcon }));
                     } else {
                         textLayer.push(L.marker([center[1], center[0]], { icon: myIcon }));
                     }
                 }
             }
         });
         this.textLayerGroup = L.layerGroup(textLayer).addTo(this.map);
     }

代码解析

  • 因为返回的数据为数组,所以我们需要将返回的数据的相关数据绑定至页面的行政区块。
  • 添加文字的原理就是在每个行政区的GeoJson的center中心点处添加一个DivIcon点击查看文档
  • 我们可以一个一个添加DivIcon,但是在需要清楚这些元素的时候会很麻烦。所以我们直接添加一个layerGroup图层。在我们需要移除的时候直接layer.remove()移除。

区块区分颜色显示

typescript 复制代码
     drawLayerFillColor(data: any, clear?: boolean) {
         // 区块上色
         this.map.eachLayer((layer: any) => {
             if (layer && layer.feature) {
                 const { adcode } = layer.feature.properties;
                 const item = data.find((item: any) => item.administrativeDivisionCode == adcode);
                 if (item) {
                     layer.setStyle({
                         fillColor: clear
                             ? this.mapDefaultColor
                             : marketStatus[item.rank]
                               ? marketStatus[item.rank].color
                               : this.mapDefaultColor,
                     });
                 } else {
                     layer.setStyle({
                         fillColor: this.mapDefaultColor,
                     });
                 }
             }
         });
     }

代码解析

  • 遍历由刚刚的GeoJson创建的layer然后给layer对象设定自定义颜色。其中需要注意的是layer为svg对象。可以使用svg的相关属性

绘制热力图

kotlin 复制代码
     drawHeatMap(data: any) {
         // 创建热力图的 Pane,并设置 zIndex 确保热力图位于顶层
         this.map.createPane('heatmapPane');
         (this.map.getPane('heatmapPane') as any).style.zIndex = 300;
         const cfg = {
             radius: 0.1, // 热力图半径
             maxOpacity: 1,
             scaleRadius: true,
             useLocalExtrema: true,
             latField: 'lat', // 自定义data字段
             lngField: 'lng', // 自定义data 字段
             valueField: 'count',
             pane: 'heatmapPane',
             // gradient: { // 热力颜色自定义
             //     0.1: 'rgba(13,251,198,0.5)',
             //     0.2: 'rgba(13,251,198,0.8)',
             //     0.3: 'rgba(255,241,46,0.5)',
             //     0.4: 'rgba(255,241,46,0.7)',
             //     0.5: 'rgba(255,241,46,0.8)',
             //     0.6: 'rgba(255,241,46,0.9)',
             //     0.7: 'rgba(255,170,0,0.5)',
             //     0.8: 'rgba(255,170,0,0.7)',
             //     0.9: 'rgba(255,170,0,0.9)',
             //     1.0: 'rgba(255,170,0,1)',
             // },
         };
 ​
         // 创建热力图图层
         this.heatmapLayer = new HeatmapOverlay(cfg); //  创建热力图实例
         this.heatmapLayer.addTo(this.map);     // 将热力图添加至地图
 ​
         const heatmapElement = this.heatmapLayer._heatmap._renderer.canvas;
         heatmapElement.style.zIndex = 9999; 
         const testData = {
             data,
         };
 ​
         this.heatmapLayer.setData(testData);
     }

代码解析

  • 这里创建一个pane用于渲染热力图。创建pane的原因是因为默认创建的热力图则层级会在默认默认创建的地图层级之下。故为了让它显示在地图之上。需要创建一个pane来自定义层级显示在地图上面。
  • 去看heatmapjs文档对相关属性进行个性化配置
  • 部分属性解释查看代码注释。

特殊注意

因为heatmap.js为非ts库。故在ts项目中会出现ts报错。只需要在项目src根目录创建heatmap.js.d.ts文件,文件内容如下

typescript 复制代码
 // src/heatmap.js.d.ts
 declare module 'heatmap.js/plugins/leaflet-heatmap' {
     import * as L from 'leaflet';
 ​
     interface HeatmapConfiguration {
         radius?: number;
         maxOpacity?: number;
         scaleRadius?: boolean;
         useLocalExtrema?: boolean;
         latField?: string;
         lngField?: string;
         valueField?: string;
         gradient?: { [key: number]: string };
         pane?: string;
     }
 ​
     interface HeatmapDataPoint {
         lat: number;
         lng: number;
         count: number;
     }
 ​
     interface HeatmapData {
         max?: number;
         data: HeatmapDataPoint[];
     }
 ​
     export default class HeatmapOverlay extends L.Layer {
         constructor(config: HeatmapConfiguration);
         setData(data: HeatmapData): void;
         addData(point: HeatmapDataPoint): void;
     }
 }
相关推荐
浮游本尊3 分钟前
Nginx配置:如何在一个域名下运行两个网站
前端·javascript
m0_748239833 分钟前
前端bug调试
前端·bug
m0_748232925 分钟前
[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结
前端·搜索引擎
新中地GIS开发老师11 分钟前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
m0_7482495413 分钟前
前端:base64的作用
前端
html组态19 分钟前
web组态可视化编辑器
前端·物联网·编辑器·web组态·组态·组态软件
~央千澈~26 分钟前
如果你的网站是h5网站,如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈
前端·apache
m0_7482398339 分钟前
基于web的音乐网站(Java+SpringBoot+Mysql)
java·前端·spring boot
时雨h43 分钟前
RuoYi-ue前端分离版部署流程
java·开发语言·前端
爱喝奶茶的企鹅1 小时前
Next.js 14 性能优化:从首屏加载到运行时优化的最佳实践
react.js