|
@@ -0,0 +1,398 @@
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ class="home"
|
|
|
+ >
|
|
|
+ <div id="map" />
|
|
|
+
|
|
|
+ <div class="panel">
|
|
|
+ <el-select
|
|
|
+ v-model="timeInDay"
|
|
|
+ placeholder="Select"
|
|
|
+ size="large"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in timeOptions"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-checkbox
|
|
|
+ v-model="isShowLabels"
|
|
|
+ label="show labels"
|
|
|
+ size="large"
|
|
|
+ />
|
|
|
+ <el-checkbox
|
|
|
+ v-model="isShowTerrain"
|
|
|
+ label="show terrain"
|
|
|
+ size="large"
|
|
|
+ />
|
|
|
+ <el-checkbox
|
|
|
+ v-model="isShowFog"
|
|
|
+ label="show fog"
|
|
|
+ size="large"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, watch, onMounted } from "vue"
|
|
|
+import { useRoute, useRouter } from "vue-router"
|
|
|
+import { useStore } from "vuex"
|
|
|
+import mapboxgl from 'mapbox-gl'
|
|
|
+
|
|
|
+const route = useRoute()
|
|
|
+const router = useRouter()
|
|
|
+const store = useStore()
|
|
|
+
|
|
|
+mapboxgl.accessToken = 'pk.eyJ1IjoiamlidmFnIiwiYSI6ImNsdDVibmxvZDAwbjcyanAzNmpzOHpoeHUifQ.KKYv3iK0IiL37rNDYkb-dQ'
|
|
|
+
|
|
|
+let map = null
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ map = new mapboxgl.Map({
|
|
|
+ container: 'map', // container ID
|
|
|
+ center: [2.294444, 48.858056], // starting position [lng, lat]
|
|
|
+ zoom: 16, // starting zoom
|
|
|
+ pitch: 65,
|
|
|
+ maxBounds: [
|
|
|
+ [2.25, 48.80, ], // 西南角
|
|
|
+ [2.35, 48.92, ], // 东北角
|
|
|
+ ]
|
|
|
+ })
|
|
|
+ map.on('style.load', () => {
|
|
|
+ // 隐藏标签。
|
|
|
+ map.setConfigProperty('basemap', 'showPlaceLabels', false)
|
|
|
+ map.setConfigProperty('basemap', 'showRoadLabels', false)
|
|
|
+ map.setConfigProperty('basemap', 'showPointOfInterestLabels', false)
|
|
|
+ map.setConfigProperty('basemap', 'showTransitLabels', false)
|
|
|
+
|
|
|
+ // 准备 3D terrain source
|
|
|
+ map.addSource('mapbox-dem', {
|
|
|
+ 'type': 'raster-dem',
|
|
|
+ 'url': 'mapbox://mapbox.terrain-rgb',
|
|
|
+ 'tileSize': 512,
|
|
|
+ 'maxzoom': 14
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // todo: 自动旋转开关
|
|
|
+ // map.on('idle', () => {
|
|
|
+ // let lastFrameTime = 0.0
|
|
|
+ // let animationTotalTime = 0.0
|
|
|
+ // const initialBearing = map.getBearing()
|
|
|
+
|
|
|
+ // function frameTask(timeStamp) {
|
|
|
+ // animationTotalTime += ((timeStamp - lastFrameTime) / 1000.0)
|
|
|
+ // const rotation = initialBearing + animationTotalTime * 2.0
|
|
|
+ // map.setBearing(rotation % 360)
|
|
|
+ // lastFrameTime = timeStamp
|
|
|
+ // window.requestAnimationFrame(frameTask)
|
|
|
+ // }
|
|
|
+ // window.requestAnimationFrame(frameTask)
|
|
|
+ // })
|
|
|
+
|
|
|
+ map.on('click', (e) => {
|
|
|
+ console.log(e.lngLat.wrap())
|
|
|
+ })
|
|
|
+
|
|
|
+ map.on('load', () => {
|
|
|
+ // todo: 操控
|
|
|
+ // 桥梁高亮
|
|
|
+ map.addSource('bridge-demo-1', {
|
|
|
+ 'type': 'geojson',
|
|
|
+ 'data': {
|
|
|
+ 'type': 'Feature',
|
|
|
+ 'properties': {},
|
|
|
+ 'geometry': {
|
|
|
+ 'type': 'LineString',
|
|
|
+ 'coordinates': [
|
|
|
+ [
|
|
|
+ 2.291370903863708,
|
|
|
+ 48.860291730262816
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 2.2926683589130334,
|
|
|
+ 48.85941742662925
|
|
|
+ ],
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addSource('bridge-demo-2', {
|
|
|
+ 'type': 'geojson',
|
|
|
+ 'data': {
|
|
|
+ 'type': 'Feature',
|
|
|
+ 'properties': {},
|
|
|
+ 'geometry': {
|
|
|
+ 'type': 'LineString',
|
|
|
+ 'coordinates': [
|
|
|
+ [
|
|
|
+ 2.2867527694825185,
|
|
|
+ 48.85655006915218
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 2.28846012300869,
|
|
|
+ 48.85483140541177
|
|
|
+ ],
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addSource('bridge-demo-3', {
|
|
|
+ 'type': 'geojson',
|
|
|
+ 'data': {
|
|
|
+ 'type': 'Feature',
|
|
|
+ 'properties': {},
|
|
|
+ 'geometry': {
|
|
|
+ 'type': 'LineString',
|
|
|
+ 'coordinates': [
|
|
|
+ [
|
|
|
+ 2.3016957824563633,
|
|
|
+ 48.86404969411541
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 2.3018487764027213,
|
|
|
+ 48.862882778017564
|
|
|
+ ],
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addLayer({
|
|
|
+ 'id': 'bridge-demo-1',
|
|
|
+ 'type': 'line',
|
|
|
+ 'source': 'bridge-demo-1',
|
|
|
+ 'layout': {
|
|
|
+ 'line-join': 'round',
|
|
|
+ 'line-cap': 'round'
|
|
|
+ },
|
|
|
+ 'paint': {
|
|
|
+ 'line-color': 'rgba(244, 208, 133, 0.8)',
|
|
|
+ 'line-width': 40,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addLayer({
|
|
|
+ 'id': 'bridge-demo-2',
|
|
|
+ 'type': 'line',
|
|
|
+ 'source': 'bridge-demo-2',
|
|
|
+ 'layout': {
|
|
|
+ 'line-join': 'round',
|
|
|
+ 'line-cap': 'round'
|
|
|
+ },
|
|
|
+ 'paint': {
|
|
|
+ 'line-color': 'rgba(244, 208, 133, 0.8)',
|
|
|
+ 'line-width': 40,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addLayer({
|
|
|
+ 'id': 'bridge-demo-3',
|
|
|
+ 'type': 'line',
|
|
|
+ 'source': 'bridge-demo-3',
|
|
|
+ 'layout': {
|
|
|
+ 'line-join': 'round',
|
|
|
+ 'line-cap': 'round'
|
|
|
+ },
|
|
|
+ 'paint': {
|
|
|
+ 'line-color': 'rgba(244, 208, 133, 0.8)',
|
|
|
+ 'line-width': 40,
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // todo:操控
|
|
|
+ // 操场高亮
|
|
|
+ // Add a data source containing GeoJSON data.
|
|
|
+ map.addSource('playground', {
|
|
|
+ 'type': 'geojson',
|
|
|
+ 'data': {
|
|
|
+ 'type': 'Feature',
|
|
|
+ 'geometry': {
|
|
|
+ 'type': 'Polygon',
|
|
|
+ // These coordinates outline playground.
|
|
|
+ 'coordinates': [
|
|
|
+ [
|
|
|
+ [2.290685454637469, 48.85648212786501],
|
|
|
+ [2.290678167471242, 48.85674317251818],
|
|
|
+ [2.2909987705963886, 48.856988869994325],
|
|
|
+ [2.2913584104396705, 48.85706691648497],
|
|
|
+ [2.2926340590652217, 48.856240774123734],
|
|
|
+ [2.2926899302722177, 48.85607261804398],
|
|
|
+ [2.291903329216666, 48.85567435087097],
|
|
|
+ [2.2916458346767286, 48.855731990701315],
|
|
|
+ ]
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ map.addLayer({
|
|
|
+ 'id': 'playground',
|
|
|
+ 'type': 'fill',
|
|
|
+ 'source': 'playground', // reference the data source
|
|
|
+ 'layout': {},
|
|
|
+ 'paint': {
|
|
|
+ 'fill-color': '#0080ff', // blue color fill
|
|
|
+ 'fill-opacity': 0.5
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+// 时间选择
|
|
|
+const timeOptions = [
|
|
|
+ {
|
|
|
+ label: 'dusk',
|
|
|
+ value: 'dusk',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'day',
|
|
|
+ value: 'day',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'dawn',
|
|
|
+ value: 'dawn',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'night',
|
|
|
+ value: 'night',
|
|
|
+ },
|
|
|
+]
|
|
|
+const timeInDay = ref(timeOptions[1].value)
|
|
|
+watch(timeInDay, (v) => {
|
|
|
+ map.setConfigProperty('basemap', 'lightPreset', v) // dusk, dawn, day, and night
|
|
|
+ if (isShowFog.value) {
|
|
|
+ if (timeInDay.value === 'day') {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': 'white',
|
|
|
+ 'high-color': '#add8e6',
|
|
|
+ 'space-color': '#d8f2ff',
|
|
|
+ 'star-intensity': 0.0
|
|
|
+ })
|
|
|
+ } else if (timeInDay.value === 'dusk' || timeInDay.value === 'dawn') {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': '#999',
|
|
|
+ 'high-color': '#add8e6',
|
|
|
+ 'space-color': '#d8f2ff',
|
|
|
+ 'star-intensity': 0.4
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': '#242B4B',
|
|
|
+ 'high-color': '#161B36',
|
|
|
+ 'space-color': '#0B1026',
|
|
|
+ 'star-intensity': 0.8
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// 标签开关
|
|
|
+const isShowLabels = ref(false)
|
|
|
+watch(isShowLabels, (v) => {
|
|
|
+ map.setConfigProperty('basemap', 'showPlaceLabels', v)
|
|
|
+ map.setConfigProperty('basemap', 'showRoadLabels', v)
|
|
|
+ map.setConfigProperty('basemap', 'showPointOfInterestLabels', v)
|
|
|
+ map.setConfigProperty('basemap', 'showTransitLabels', v)
|
|
|
+})
|
|
|
+
|
|
|
+// 地形开关
|
|
|
+const isShowTerrain = ref(false)
|
|
|
+watch(isShowTerrain, (v) => {
|
|
|
+ if (v) {
|
|
|
+ map.setTerrain({
|
|
|
+ 'source': 'mapbox-dem',
|
|
|
+ 'exaggeration': 1
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ map.setTerrain(null)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 雾开关
|
|
|
+const isShowFog = ref(false)
|
|
|
+watch(isShowFog, (v) => {
|
|
|
+ if (v) {
|
|
|
+ if (timeInDay.value === 'day') {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': 'white',
|
|
|
+ 'high-color': '#add8e6',
|
|
|
+ 'space-color': '#d8f2ff',
|
|
|
+ 'star-intensity': 0.0
|
|
|
+ })
|
|
|
+ } else if (timeInDay.value === 'dusk' || timeInDay.value === 'dawn') {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': '#999',
|
|
|
+ 'high-color': '#add8e6',
|
|
|
+ 'space-color': '#d8f2ff',
|
|
|
+ 'star-intensity': 0.4
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ map.setFog({
|
|
|
+ 'range': [-1, 2],
|
|
|
+ 'horizon-blend': 0.3,
|
|
|
+ 'color': '#242B4B',
|
|
|
+ 'high-color': '#161B36',
|
|
|
+ 'space-color': '#0B1026',
|
|
|
+ 'star-intensity': 0.8
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ map.setFog(null)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 一种style可有多个layer,每个layer有对应的source。
|
|
|
+
|
|
|
+// todo: 日照控件
|
|
|
+
|
|
|
+// todo: 道路显隐控件
|
|
|
+// map.setPaintProperty('route', 'line-opacity', 0.9);
|
|
|
+
|
|
|
+// 添加自定义图层。同一个slot内的各个图层用beforeId参数指定顺序。
|
|
|
+// map.addLayer({ type: 'line', slot: 'middle' /* ... */ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 移除图层
|
|
|
+//
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.home {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ #map{
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ .panel{
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ padding: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|