vue3 + MapTalks实现2.5D地图的绘制

herry xiao 2024-09-09 15:03:03 阅读 91

一.准备工作

1.npm引入maptalks

我的maptalks版本:  "maptalks": "^1.0.0-rc.33",

2.寻找省份的GeoJson数据,选择想要的省份直接下载即可 :阿里DataV地图数据平台

3.在vue单页面中引入maptalks/maptalks.css/省份的GoJson数据

<code>import 'maptalks/dist/maptalks.css';

import * as maptalks from 'maptalks';

import { ref, onMounted } from 'vue';

import tianjinGeoJSON from '@/assets/js/tj.json'; // 导入 GeoJSON 天津市数据

 二、基本地图的绘制:根据官网案例实现平面地图

使用官网案例即可:

maptalks官网

<div ref="mapElement" class="map"></div>code>

// 地图dom元素

const mapElement = ref(null);

// mapInstance 用来引用 MapTalks 的地图实例

const mapInstance = ref(null);

onMounted(() => {

initMap();

});

const initMap = () => {

if (mapElement.value) {

const url = 'https://api.mapbox.com/styles/v1/ling13/cjpv0upr10vc52sodrbmtrmrb/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibGluZzEzIiwiYSI6ImNqbHozcGRwZDBzMHIzcXBqNXV2dGR4dHAifQ.32-e7GIttC0FriVwvJ0GqA#6.1/27.044989/106.588086/0';

mapInstance.value = new maptalks.Map(mapElement.value, {

center: [117.4, 39.4], // 天津中心的经纬度

zoom: 9,

pitch: 45, // 设置倾斜角度为45度,实现2.5D效果

resizeEnable: true, // 开启resize功能

attribution: false, // 关闭图例

zoomControl: false, // 关闭缩放控件

scaleControl: false, // 关闭比例尺控件

overviewControl: false, // 关闭 overview 控件

baseLayer: new maptalks.TileLayer('base', {

urlTemplate: url,

subdomains: ['a', 'b', 'c', 'd'],

attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>', // 地图数据的归属说明code>

cssFilter: 'sepia(100%) invert(90%)'

}),

});

} else {

console.error('mapElement is null or undefined');

}

}

设置完中心点击后,地图就开启了(剩余风格自行探索,本期专耕2.5D效果,其余一笔带过)

 

 三、2.5D绘制实现思路

所以如图所示,我们只要绘制一个盖住省份的平面,也就是红色的线+黄色的面,和一个有高度的绿色墙面,拆分着看,问题就迎刃而解了

四、具体代码

1.初始化常量

<code>// 常量和初始数据

const edgeColor = '#4682B4'; // 多边形和线条的边缘颜色

const polygonColors = ["#C0C0C0", "#87CEFA"]; // 多边形填充颜色(默认和悬停)

const altitude = 15000; // 显示在地图上的高度

const polygons = ref([]);// 存储多边形对象的数组

const limitLines = ref([]); // 存储线条对象的数组

2.绘制多边形线

altitude是面的高度配置

使用 maptalks.MultiPolygon 创建多边形对象,传入 coordinates 和配置对象。(传入的对象在下方函数,因为JavaScript引擎宏任务,故此函数需要提升顺序在绘制面函数之前)

将绘制好的多边形对象 polygon 添加到 polygons.value 数组中,用于后续添加到地图图层。

const drawPolygons = (idx, coordinates, properties) => {

const polygon = new maptalks.MultiPolygon(coordinates, {

// 边线配置

symbol: {

lineWidth: 1,

lineColor: edgeColor, // 多边形边线颜色,通过常量 edgeColor 定义

polygonFill: polygonColors[1], // 默认填充颜色,通过常量 polygonColors 定义

polygonOpacity: 0.7 // 多边形的透明度

},

// 2.5D效果

properties: {

altitude: altitude, // 设置多边形的高度(2.5D效果)

id: properties.id, // 多边形的标识符

index: idx, // 多边形在数组中的索引

properties: properties // 多边形的其他属性

}

})

polygons.value.push(polygon); // 将多边形对象添加到 polygons 数组中

}

3.绘制多边形区域的方法 

forEach 遍历每个 GeoJSON 数据中的多边形,调用 drawPolygons 函数绘制每个多边形。创建一个 maptalks.VectorLayer 矢量图层,将绘制好的多边形对象数组 polygons.value 添加到图层中。将矢量图层 polygonsLayer 添加到地图实例 mapInstance.value 中,以显示在地图上。

const drawRegion = () => {

let MapData = tianjinGeoJSON.features; // 获取天津的GeoJSON数据

polygons.value = []; // 清空 polygons 数组

// 遍历 GeoJSON 数据中的每个多边形

MapData.forEach((g, i) => {

const properties = g.properties;

const coordinates = g.geometry.coordinates;

drawPolygons(i, coordinates, properties); // 绘制每个多边形

});

// 创建一个 MapTalks 矢量图层来展示多边形,并添加到地图中(让天津高亮)

const polygonsLayer = new maptalks.VectorLayer(

"vector-polygon", // 图层的名称

polygons.value, // 添加的多边形对象数组

{ enableAltitude: true } // 开启高度效果,必须开启以支持2.5D效果

);

mapInstance.value.addLayer(polygonsLayer); // 将图层添加到地图实例中

}

3.红色的线+黄色的面绘制完成,看效果

onMounted(() => {

initMap();

drawRegion();//调用绘制区域函数

});

 

效果不错,继续继续! 

4.接下来绘制绿色的墙面

绘制墙体,首先要有边界线然后再给上面一个高度,!

那么开始画边界线:

<code>drawBorderLines 函数用于创建一个多段线对象 (MultiLineString),表示地图上的边界线或墙体。使用 maptalks.MultiLineString 构造函数创建多段线对象,传入 coordinates 和配置对象。设置线条的样式,包括颜色、宽度以及文本的放置方式。使用 properties 对象存储线条的额外信息,例如高度、标识符等。将创建好的线条对象 outLine 添加到 limitLines.value 数组中,以便稍后添加到地图的图层中。

const drawBorderLines = (coordinates, properties) => {

const outLine = new maptalks.MultiLineString(coordinates, {

symbol: {

lineColor: '#5EAEEE', // 线条颜色

lineWidth: 1, // 线条宽度

textPlacement: "vertex" // 文本放置方式

},

properties: {

altitude: altitude, // 高度属性(用于2.5D效果)

id: properties.id, // 边界线的标识符

properties: properties // 边界线的其他属性

}

});

limitLines.value.push(outLine); // 将线条对象添加到 limitLines 数组中

}

接下来和绘制面一样:

drawWall 函数用于绘制边界线或墙体,基于从 tianjinGeoJSON 中获取的地理数据。遍历 borderFeatures 数组中的每个 feature,每个 feature 通常代表一个边界或墙体。对每个 feature,从其 geometry.coordinates 中提取路径坐标,然后调用 drawBorderLines 函数绘制边界线。创建一个 maptalks.VectorLayer 矢量图层 (limitLinesLayer),将存储在 limitLines.value 中的线条对象数组添加到图层中。配置图层的 drawAltitude 选项,包括填充颜色、透明度和线条宽度等。最后,将创建好的图层 limitLinesLayer 添加到地图实例 mapInstance.value 中,以在地图上显示绘制的边界线或墙体。

const drawWall = () => {

limitLines.value = []; // 清空 limitLines 数组

// 获取包含边界线坐标和属性的 JSON 数据

const borderFeatures = tianjinGeoJSON.features;

// 遍历每个 feature,这里假设每个 feature 都代表一个边界

borderFeatures.forEach(feature => {

const properties = feature.properties;

// 从 JSON 数据中提取路径坐标

const pathCoordinates = feature.geometry.coordinates.map(d => { return d[0] });

drawBorderLines(pathCoordinates, properties); // 调用绘制边界线的函数

});

// 创建一个 MapTalks 矢量图层来展示线条,并添加到地图中

const limitLinesLayer = new maptalks.VectorLayer(

"vector-line",

limitLines.value,

{

enableAltitude: true, // 启用高度效果,用于2.5D效果

drawAltitude: {

polygonFill: 'edgeColor', // 设置正确的填充颜色,比如橙色

polygonOpacity: 0.3,

lineWidth: 0

}

}

);

mapInstance.value.addLayer(limitLinesLayer); // 将图层添加到地图实例中

}

完成,看效果:

 只显示省外边界:

1.合并地图边界:

https://juejin.cn/post/7140454398634754055

2.合并网站:

https://mapshaper.org/

 

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。