vue3 + MapTalks实现2.5D地图的绘制
一.准备工作
1.npm引入maptalks
我的maptalks版本: “maptalks”: “^1.0.0-rc.33”,
2.寻找省份的GeoJson数据,选择想要的省份直接下载即可:阿里DataV地图数据平台
3.在vue单页面中引入maptalks/maptalks.css/省份的GoJson数据
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>
// 地图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: '© <a href="http://osm.org">OpenStreetMap</a> contributors, © <a href="https://carto.com/">CARTO</a>', // 地图数据的归属说明
cssFilter: 'sepia(100%) invert(90%)'
}),
});
} else {
console.error('mapElement is null or undefined');
}
}
设置完中心点击后,地图就开启了(剩余风格自行探索,本期专耕2.5D效果,其余一笔带过)
三、2.5D绘制实现思路
所以如图所示,我们只要绘制一个盖住省份的平面,也就是红色的线+黄色的面,和一个有高度的绿色墙面,拆分着看,问题就迎刃而解了
四、具体代码
1.初始化常量
// 常量和初始数据
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.接下来绘制绿色的墙面
绘制墙体,首先要有边界线然后再给上面一个高度,!
那么开始画边界线:
-
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/