提交 60b6f528 作者: 方治民

feat: 重构地图组件,初始化相关配置项

上级 e8352fbf
<script setup lang="ts">
import { checkUpgrade } from '@/utils/upgrade'
// 本地
import './static/iconfont.css'
// import * as Push from '@/utils/push'
onLaunch(() => {
......
<script>
export default {
data() {
return {
loading: true,
}
},
created() {
Message.loading()
},
methods: {
changeOption() {},
onViewClick(options) {
console.log(options)
},
maploaded() {
Message.hideLoading()
},
},
}
</script>
<script module="echarts" lang="renderjs">
import { mapOpts,mapStyles } from './style'
import { appendScript, appendStylesheet } from '/@/utils/dom'
import { accessToken, defaultStyle, loadMapControl, PopupImage, buildTdtTileUrl, EmptyImage, CustomControl } from '/@/components/Map/Mapbox'
let mapInstance
export default {
mounted () {
if (typeof window.mapInstance === 'function') {
this.initMap()
} else {
this.loadMaplibs().then(() =>{
this.initMap()
})
}
},
methods: {
loadMaplibs(){
const id = 'mapbox-gl'
const resource = 'static/js/mapbox-gl-js/mapbox-gl.'
return Promise.all([appendScript(id,`${resource}js`),appendStylesheet(id,`${resource}css`)])
},
initMap() {
mapInstance = new mapboxgl.Map({
accessToken,
container: 'echarts',
...mapOpts,
style: Object.assign({
...mapStyles,
})
})
mapInstance.on('load',()=>{
this.$ownerInstance.callMethod('maploaded')
})
},
onClick(event, ownerInstance) {
// 调用 service 层的方法
// ownerInstance.callMethod('onViewClick', {
// test: 'test'
// })
}
// updateEcharts(newValue, oldValue, ownerInstance, instance) {
// // 监听 service 层数据变更
// },
}
}
</script>
<template>
<view class="content">
<!-- #ifdef APP-PLUS || H5 -->
<view id="echarts" class="w-100% h-100%" />
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
<view>非 APP、H5 环境不支持</view>
<!-- #endif -->
</view>
</template>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
</style>
<script>
import { nanoid } from 'nanoid'
// FIXED: 重要说明
// renderjs 组件暂不支持 setup 组件写法,对 ts 支持也不友好,这里的写法需要参考 vue2 的写法
// 总共分为两块 script
// 1. 逻辑层 Script
// 2. 视图层 Script
// 通信方式
// 1. 通过在逻辑层 data 中设置的属性向视图层传递数据
// 2. 通过在逻辑层 methods 定义方法,在视图层调用传递参数(注意:只能传递可进行 JSON 序列化的数据)
export default {
props: {
style: {
type: Object,
default: () => ({}),
},
},
data() {
return {
id: nanoid(),
options: {},
}
},
created() {
Message.loading()
},
mounted() {
this.options = {
container: this.id,
style: this.style,
}
},
methods: {
onMapLoad(data) {
Message.hideLoading()
console.log('✨ Map Loaded', data)
},
},
}
</script>
<!-- renderjs 视图层模块 -->
<script module="mapbox" lang="renderjs" src="./mapbox.module.js"></script>
<template>
<!-- #ifdef APP-PLUS || H5 -->
<view class="map wrap" :id="id" :options="options" :change:options="mapbox.changeOptions" />
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
<view class="empty wrap">非 APP、H5 环境不支持</view>
<!-- #endif -->
</template>
<style lang="less" scoped>
page {
height: 100%;
}
.wrap {
display: flex;
width: 100%;
height: 100%;
/* #ifdef APP */
height: 100vh;
/* #endif */
}
.empty {
justify-content: center;
align-items: center;
}
</style>
import { merge } from 'lodash-es'
import { accessToken, defaultStyle, loadMapControl, loadMapboxLibs } from '/@/components/Map/Mapbox'
// renderjs 官方文档
// https://uniapp.dcloud.io/tutorial/renderjs.html
// renderjs 的一些细节问题
// https://juejin.cn/post/7049185827582115870
export default {
mounted() {},
methods: {
loadLibs: loadMapboxLibs,
initMap(options) {
// 移除地图
if (this.map && this.map.remove) {
this.map.remove()
}
// 加载地图
const mapboxgl = window.mapboxgl
const map = new mapboxgl.Map({
accessToken,
container: options.container,
style: merge({
...defaultStyle,
...options?.style,
}),
})
// 绑定作用域
this.map = map
// 加载地图控件
map.on('load', () => {
// #ifdef APP-PLUS
if (options?.control?.geolocate) {
window.navigator.permissions = undefined
options.control.geolocate = {
geolocation: {
getCurrentPosition: (onPositionSuccess, _onPositionError, options) => {
this.onPositionSuccess = onPositionSuccess
this.$ownerInstance.callMethod('getCurrentPosition', options)
},
},
}
}
// #endif
// 加载地图图层
this.initMapLayers()
.then(() => {
// 调用逻辑层方法
this.loaded = true
this.$ownerInstance.callMethod('onMapLoad', {
center: map.getCenter(),
})
// 加载地图控件
loadMapControl(mapboxgl, map, options?.control)
})
.catch(console.error)
})
},
initMapLayers() {
// TODO: 加载地图图层
return Promise.resolve()
},
changeOptions(options) {
if (!options.container) {
return
}
if (typeof window.mapboxgl === 'object') {
this.initMap(options)
} else {
this.loadLibs().then(() => {
this.initMap(options)
})
}
},
},
}
/**
* 页面分享 Hook
* @param index 分享按钮索引
* @param cb 自定义回调
* @returns 分享函数
*/
export function useShare(index = 0, cb?: (e: Page.NavigationBarButtonTapOption) => void) {
/**
* 分享
*/
function share() {
// TODO
// 1. 获取需要分享的类型,如: 图片、链接、文本
// 2. 根据类型,获取需要分享的内容(图片通常是页面截屏)
// 3. 实现截屏功能
// 4. 实现分享功能
Message.toast('分享功能暂未实现')
}
onNavigationBarButtonTap((e) => {
if (e.index === index) {
share()
}
// 自定义回调
cb?.(e)
})
return {
share,
}
}
......@@ -68,7 +68,7 @@
},
// 降水实况
{
"path": "pages/business/monitor/rain",
"path": "pages/business/monitor/rain/index",
"style": {
"navigationBarTitleText": "降水监测",
"enablePullDownRefresh": false,
......
<script setup lang="ts">
onNavigationBarButtonTap((e) => {
if (e.index === 0) {
uni.showToast({
title: '你点了分享按钮',
icon: 'none',
})
}
})
</script>
<template>
<view class="bg h-100vh">
<CustomPicker />
<Map style="height: 100%" />
</view>
</template>
// 页面通用配置信息或一些抽象方法
<!-- 页面组件 -->
<script setup lang="ts">
import { useShare } from '@/hooks/page/useShare'
useShare()
</script>
<template>
<view class="bg h-100vh">
<!-- 地图组件 -->
<Mapbox style="height: 100%" />
<!-- 交互组件集 -->
<view class="interaction">
<!-- -->
</view>
</view>
</template>
<style lang="scss" scoped>
//
</style>
.mapboxgl-popup-content {
box-shadow: 0 1px 5px #6e6e6e !important;
}
.mapboxgl-popup-content .mapboxgl-custom-popup {
position: relative;
}
.mapboxgl-custom-popup .popup-title {
font-weight: bold;
}
.mapboxgl-ctrl-logo {
display: none !important;
}
.mapboxgl-ctrl-bottom-left {
display: flex;
bottom: 0;
left: 2px;
}
.mapboxgl-ctrl-lnglat {
background: rgb(0 0 0 / 40%);
color: white;
line-height: 2em;
padding: 0 10px;
box-shadow: 0 0 0 2px rgba(0,0,0,.1);
border-radius: 4px;
}
.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon {
background-image: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"%3E%3Cpath fill="currentColor" d="M3.75 3a.75.75 0 0 0-.75.75V5.5a.5.5 0 0 1-1 0V3.75C2 2.784 2.784 2 3.75 2H5.5a.5.5 0 0 1 0 1H3.75ZM10 2.5a.5.5 0 0 1 .5-.5h1.75c.966 0 1.75.784 1.75 1.75V5.5a.5.5 0 0 1-1 0V3.75a.75.75 0 0 0-.75-.75H10.5a.5.5 0 0 1-.5-.5ZM2.5 10a.5.5 0 0 1 .5.5v1.75c0 .414.336.75.75.75H5.5a.5.5 0 0 1 0 1H3.75A1.75 1.75 0 0 1 2 12.25V10.5a.5.5 0 0 1 .5-.5Zm11 0a.5.5 0 0 1 .5.5v1.75A1.75 1.75 0 0 1 12.25 14H10.5a.5.5 0 0 1 0-1h1.75a.75.75 0 0 0 .75-.75V10.5a.5.5 0 0 1 .5-.5Z"%2F%3E%3C%2Fsvg%3E') !important;
}
.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon {
background-image: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"%3E%3Cpath fill="currentColor" d="M11 4a1 1 0 0 0 1 1h1.5a.5.5 0 0 1 0 1H12a2 2 0 0 1-2-2V2.5a.5.5 0 0 1 1 0V4Zm0 8a1 1 0 0 1 1-1h1.5a.5.5 0 0 0 0-1H12a2 2 0 0 0-2 2v1.5a.5.5 0 0 0 1 0V12Zm-7-1a1 1 0 0 1 1 1v1.5a.5.5 0 0 0 1 0V12a2 2 0 0 0-2-2H2.5a.5.5 0 0 0 0 1H4Zm1-7a1 1 0 0 1-1 1H2.5a.5.5 0 0 0 0 1H4a2 2 0 0 0 2-2V2.5a.5.5 0 0 0-1 0V4Z"%2F%3E%3C%2Fsvg%3E') !important;
}
.mapboxgl-ctrl .mapboxgl-ctrl-reset-button .mapboxgl-ctrl-icon {
background-image: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="20" height="20" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="M12 16c1.671 0 3-1.331 3-3s-1.329-3-3-3s-3 1.331-3 3s1.329 3 3 3z"%2F%3E%3Cpath fill="currentColor" d="M20.817 11.186a8.94 8.94 0 0 0-1.355-3.219a9.053 9.053 0 0 0-2.43-2.43a8.95 8.95 0 0 0-3.219-1.355a9.028 9.028 0 0 0-1.838-.18V2L8 5l3.975 3V6.002c.484-.002.968.044 1.435.14a6.961 6.961 0 0 1 2.502 1.053a7.005 7.005 0 0 1 1.892 1.892A6.967 6.967 0 0 1 19 13a7.032 7.032 0 0 1-.55 2.725a7.11 7.11 0 0 1-.644 1.188a7.2 7.2 0 0 1-.858 1.039a7.028 7.028 0 0 1-3.536 1.907a7.13 7.13 0 0 1-2.822 0a6.961 6.961 0 0 1-2.503-1.054a7.002 7.002 0 0 1-1.89-1.89A6.996 6.996 0 0 1 5 13H3a9.02 9.02 0 0 0 1.539 5.034a9.096 9.096 0 0 0 2.428 2.428A8.95 8.95 0 0 0 12 22a9.09 9.09 0 0 0 1.814-.183a9.014 9.014 0 0 0 3.218-1.355a8.886 8.886 0 0 0 1.331-1.099a9.228 9.228 0 0 0 1.1-1.332A8.952 8.952 0 0 0 21 13a9.09 9.09 0 0 0-.183-1.814z"%2F%3E%3C%2Fsvg%3E') !important;
}
.mapboxgl-ctrl .mapboxgl-ctrl-layer-button .mapboxgl-ctrl-icon {
background-image: url('data:image/svg+xml,%3Csvg xmlns="http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" width="24" height="24" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"%3E%3Cpath fill="currentColor" d="m13.387 3.425l6.365 4.243a1 1 0 0 1 0 1.664l-6.365 4.244a2.5 2.5 0 0 1-2.774 0L4.248 9.332a1 1 0 0 1 0-1.664l6.365-4.243a2.5 2.5 0 0 1 2.774 0Zm6.639 8.767a2.002 2.002 0 0 1-.577.598l-6.05 4.084a2.5 2.5 0 0 1-2.798 0l-6.05-4.084a2 2 0 0 1-.779-2.29l6.841 4.56a2.5 2.5 0 0 0 2.613.098l.16-.098l6.841-4.56a1.996 1.996 0 0 1-.201 1.692Zm0 3.25a2.002 2.002 0 0 1-.577.598l-6.05 4.084a2.5 2.5 0 0 1-2.798 0l-6.05-4.084a2 2 0 0 1-.779-2.29l6.841 4.56a2.5 2.5 0 0 0 2.613.098l.16-.098l6.841-4.56a1.996 1.996 0 0 1-.201 1.692Z"%2F%3E%3C%2Fsvg%3E') !important;
}
.mapboxgl-ctrl button.-active svg {
color: #4264fb;
}
.mapboxgl-ctrl-layer-button {
z-index: 1;
}
.mapboxgl-ctrl-layer-wrap {
z-index: 100;
display: flex;
justify-items: center;
align-items: center;
position: absolute;
top: 0;
left: -220px;
visibility: hidden;
padding: 10px;
border-radius: 3px;
box-shadow: 0 0 3px #333;
background-color: #fff;
}
.mapboxgl-ctrl-layer {
width: 60px;
height: 60px;
display: flex;
justify-content: center;
border: 2px solid #fff;
position: relative;
}
.mapboxgl-ctrl-layer.active {
border-color: #3385ff;
}
.mapboxgl-ctrl-layer img {
width: 100%;
height: 100%;
}
.mapboxgl-ctrl-layer span {
display: inline-flex;
justify-content: center;
background-color: rgb(0 0 0 / 60%);
color: white;
position: absolute;
bottom: 0;
width: 100%;
}
.mapboxgl-ctrl-layer-button.-active .mapboxgl-ctrl-layer-wrap {
visibility: visible;
}
.mapboxgl-ctrl-bottom-left,
.mapboxgl-ctrl-bottom-right {
padding-bottom: 0;
/* stylelint-disable-next-line function-no-unknown */
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
@font-face {
font-family: "iconfont"; /* Project id */
src: url('iconfont.ttf?t=1667453284784') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-daohang:before {
content: "\e797";
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -11,7 +11,7 @@ export const liveModules: navItemType[] = [
label: '降水监测',
value: 'rain-m',
navigate: {
url: '/pages/business/monitor/rain',
url: '/pages/business/monitor/rain/index',
},
},
{
......
......@@ -137,6 +137,7 @@ declare module 'vue' {
Header: typeof import('./../src/components/Layout/Header.vue')['default']
Icon: typeof import('./../src/components/Icon/index.vue')['default']
Map: typeof import('./../src/components/Map/Mapbox/Map.vue')['default']
Mapbox: typeof import('./../src/components/Map/Mapbox/index.vue')['default']
MenuHeader: typeof import('./../src/components/Layout/MenuHeader.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论