我们在做webgis开发的过程中,应该经常会去加载一些类似白膜的数据,但是呢,如何实现对楼房分分层这个问题不知道大家有没有思考过,在cesium中是可以实现这个操作的,但是过程十分复杂繁琐;今天呢给大家介绍一种简单的,利用mapbox实现楼层分层单体化。
先展示一下效果图
初始状态
鼠标经过
顺便也跟大家讲一下vue3中引入mapbox库的简单过程。
一、创建项目
1、
2、
3、把创建完成的项目用vscode打开,提示一下,我这里使用的是vite脚手架,如果你用的是其他脚手架,就按照你熟悉的方式创建项目即可
4、同时按住 ctrl + ~键(就是esc下面的那个键)调出终端
ok,到这里项目创建完成,在终端输入pnpm dev再回车即可看到项目已经可以运行。
5、准备工作
清理不需要的文件
现在在运行一下项目,可以看见是一个空白的页面,很好,接下来就是引入mapbox
二、引入mapbox,这里我是利用CDN的形式引入的
找到项目中的index.html文件,将mapbox的CDN引入,就一个css文件和一个js文件,大家也可以去下载下来,放在src下面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
rel="icon"
href="/favicon.ico"
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<link
href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css"
rel="stylesheet"
/>
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script
type="module"
src="/src/main.js"
></script>
</body>
</html>
然后到app.vue中初始化地图
<template>
<!-- 设置地图容器 -->
<div id="map"></div>
</template>
<script setup>
import { onMounted } from 'vue'
let map
// 在onmounted生命周期钩子中初始化地图
onMounted(() => {
mapboxgl.accessToken = '你的token'
map = new mapboxgl.Map({
container: 'map', // container ID
// style: 'mapbox://styles/mapbox/streets-v12', // style URL
// 我这里使用的是高德地图的样式
style: {
version: 8,
sources: {
'raster-tiles': {
type: 'raster',
tiles: ['http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'],
tileSize: 256
}
},
layers: [
{
id: 'simple-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 16,
maxzoom: 20
}
]
},
center: [114.124064, 30.463405],
zoom: 16,
pitch: 45,
projection: 'globe'
})
})
</script>
<style scoped>
/* 一定记得给地图容器设置宽高,不然地图无法显示 */
#map {
width: 100%;
height: 100vh;
}
</style>
ok,到这里地图初始化完成,几个点注意一下,token大家自己去申请,地图容器记得给尺寸,在onmounted生命周期钩子中去挂在地图
三、准备数据
推荐使用L7 Editor - 基于 L7 的地理数据绘制工具
把准备好的数据在项目中存起来
然后这个数据我们需要修改一下,就是加几个字段,楼层索引floorIndex、楼层高度height、楼层颜色color,然后把它复制几份就ok了。具体示例如下
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"height": 5,
"floorIndex": 1,
"color": "#aa3542"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
114.122747,
30.463958
],
[
114.123847,
30.464461
],
[
114.124024,
30.464168
],
[
114.122947,
30.463627
],
[
114.122747,
30.463958
]
]
]
}
},
{
"type": "Feature",
"properties": {
"height": 10,
"floorIndex": 2,
"color": "#00ff00"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
114.122747,
30.463958
],
[
114.123847,
30.464461
],
[
114.124024,
30.464168
],
[
114.122947,
30.463627
],
[
114.122747,
30.463958
]
]
]
}
},
{
"type": "Feature",
"properties": {
"height": 15,
"floorIndex": 3,
"color": "#0000ff"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
114.122747,
30.463958
],
[
114.123847,
30.464461
],
[
114.124024,
30.464168
],
[
114.122947,
30.463627
],
[
114.122747,
30.463958
]
]
]
}
}
]
}
四、实现楼栋分层,并且鼠标经过不同楼层,楼层变色
主要三件事
1、楼层分层显示
2、鼠标移入移出事件
3、鼠标移入楼层、对应楼层变色高亮
代码直接给大家,逻辑很清晰,看一下就知道了,如果不了解为什么这样写,可以去我的mapbox专辑中去看,我会进行讲解。目前对于mapbox我也在摸索中。希望大家多多点赞收藏。
<template>
<div id="map"></div>
<button @click="test"></button>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import buildJson from '../src/data/test.json'
let map
onMounted(() => {
mapboxgl.accessToken = '你的token'
map = new mapboxgl.Map({
container: 'map', // container ID
// style: 'mapbox://styles/mapbox/streets-v12', // style URL
style: {
version: 8,
sources: {
'raster-tiles': {
type: 'raster',
tiles: ['http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'],
tileSize: 256
}
},
layers: [
{
id: 'simple-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 16,
maxzoom: 20
}
]
},
center: [114.124064, 30.463405],
zoom: 16,
pitch: 45,
projection: 'globe'
})
map.on('load', () => {
map.addSource('buildings', {
type: 'geojson',
data: buildJson
})
map.addLayer({
id: '3d-buildings',
source: 'buildings',
type: 'fill-extrusion',
paint: {
'fill-extrusion-color': ['get', 'color'],
'fill-extrusion-height': ['get', 'height'],
'fill-extrusion-base': ['-', ['*', ['get', 'floorIndex'], 5], 5],
'fill-extrusion-opacity': 0.6
}
})
// 临时高亮图层
map.addLayer({
id: 'highlight',
source: 'buildings',
type: 'fill-extrusion',
paint: {
'fill-extrusion-color': '#ff0000',
'fill-extrusion-height': ['get', 'height'],
'fill-extrusion-base': ['-', ['*', ['get', 'floorIndex'], 5], 5],
'fill-extrusion-opacity': 0.6
},
filter: ['==', 'floorIndex', 0]
})
map.on('mouseenter', '3d-buildings', function (e) {
map.getCanvas().style.cursor = 'pointer'
let feature = e.features[0]
// 高亮
map.setFilter('highlight', ['==', 'floorIndex', feature.properties.floorIndex])
})
map.on('mouseleave', '3d-buildings', function () {
map.getCanvas().style.cursor = ''
map.setFilter('highlight', ['==', 'floorIndex', 0])
})
})
})
</script>
<style scoped>
#map {
width: 100%;
height: 100vh;
}
</style>
标签:map,style,extrusion,mapbox,height,楼层,vue3,type
From: https://blog.csdn.net/qq_45751819/article/details/143507584