feat(图表): 支持腾讯地图

This commit is contained in:
ulleo
2025-03-27 18:58:44 +08:00
committed by xuwei-fit2cloud
parent 35d7877b55
commit 4e33a205b0
9 changed files with 222 additions and 39 deletions

View File

@@ -2064,7 +2064,8 @@ export default {
map_type: 'Map Provider',
map_type_gaode: 'Gaode Map',
map_type_tianditu: 'Tianditu',
map_type_baidu: 'Baidu Map'
map_type_baidu: 'Baidu Map',
map_type_tencent: 'QQ Map'
},
dataset: {
field_value: 'Field Value',

View File

@@ -2007,7 +2007,8 @@ export default {
map_type: '地圖提供商',
map_type_gaode: '高德地圖',
map_type_tianditu: '天地圖',
map_type_baidu: '百度地圖'
map_type_baidu: '百度地圖',
map_type_tencent: '騰訊地圖'
},
dataset: {
field_value: '欄位值',

View File

@@ -2013,7 +2013,8 @@ export default {
map_type: '地图提供商',
map_type_gaode: '高德地图',
map_type_tianditu: '天地图',
map_type_baidu: '百度地图'
map_type_baidu: '百度地图',
map_type_tencent: '腾讯地图'
},
dataset: {
field_value: '字段值',

View File

@@ -21,6 +21,7 @@ import { useMapStoreWithOut } from '@/store/modules/map'
import { queryMapKeyApi } from '@/api/setting/sysParameter'
import {
gaodeMapStyleOptions,
qqMapStyleOptions,
tdtMapStyleOptions
} from '@/views/chart/components/js/panel/charts/map/common'
@@ -292,6 +293,8 @@ const mapStyleOptions = computed(() => {
switch (mapType.value) {
case 'tianditu':
return tdtMapStyleOptions
case 'qq':
return qqMapStyleOptions
default:
return gaodeMapStyleOptions
}

View File

@@ -72,6 +72,11 @@ export const tdtMapStyleOptions = [
{ name: t('chart.map_style_darkblue'), value: 'indigo' }
]
export const qqMapStyleOptions = [
{ name: t('chart.map_style_normal'), value: 'normal' },
{ name: t('commons.custom'), value: 'custom' }
]
export declare type MapMouseEvent = MouseEvent & {
feature: GeoJSON.Feature
}

View File

@@ -35,14 +35,16 @@ import type { Plot } from '@antv/g2plot'
import type { PickOptions } from '@antv/g2plot/lib/core/plot'
import { defaults, find } from 'lodash-es'
import { useI18n } from '@/hooks/web/useI18n'
const { t: tI18n } = useI18n()
import { isMobile } from '@/utils/utils'
import { GaodeMap, TMap } from '@antv/l7-maps'
import { GaodeMap, TMap, TencentMap } from '@antv/l7-maps'
import {
gaodeMapStyleOptions,
qqMapStyleOptions,
tdtMapStyleOptions
} from '@/views/chart/components/js/panel/charts/map/common'
const { t: tI18n } = useI18n()
export function getPadding(chart: Chart): number[] {
if (chart.drill) {
return [0, 10, 22, 10]
@@ -1242,38 +1244,55 @@ export function configL7Zoom(
if (!scene?.getControlByName('zoom')) {
if (!scene.map) {
scene.once('loaded', () => {
if (
mapKey?.mapType === 'tianditu' &&
scene.map?.defaultMapType?.name === 'TMAP_NORMAL_MAP'
) {
//天地图
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
const center =
basicStyle.autoFit === false
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
: [scene.map.getCenter().getLng(), scene.map.getCenter().getLat()]
const newZoomOptions = {
initZoom: initZoom,
center: center,
buttonColor: basicStyle.zoomButtonColor,
buttonBackground: basicStyle.zoomBackground
} as any
scene.addControl(new CustomZoom(newZoomOptions))
} else {
scene.map.on('complete', () => {
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
const center =
basicStyle.autoFit === false
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
: [scene.map.getCenter().lng, scene.map.getCenter().lat]
const newZoomOptions = {
initZoom: initZoom,
center: center,
buttonColor: basicStyle.zoomButtonColor,
buttonBackground: basicStyle.zoomBackground
} as any
scene.addControl(new CustomZoom(newZoomOptions))
})
switch (mapKey?.mapType) {
case 'tianditu':
//天地图
{
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
const center =
basicStyle.autoFit === false
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
: [scene.map.getCenter().getLng(), scene.map.getCenter().getLat()]
const newZoomOptions = {
initZoom: initZoom,
center: center,
buttonColor: basicStyle.zoomButtonColor,
buttonBackground: basicStyle.zoomBackground
} as any
scene.addControl(new CustomZoom(newZoomOptions))
}
break
case 'qq':
{
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
const center =
basicStyle.autoFit === false
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
: [scene.map.getCenter().lng, scene.map.getCenter().lat]
const newZoomOptions = {
initZoom: initZoom,
center: center,
buttonColor: basicStyle.zoomButtonColor,
buttonBackground: basicStyle.zoomBackground
} as any
scene.addControl(new CustomZoom(newZoomOptions))
}
break
default:
scene.map.on('complete', () => {
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
const center =
basicStyle.autoFit === false
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
: [scene.map.getCenter().lng, scene.map.getCenter().lat]
const newZoomOptions = {
initZoom: initZoom,
center: center,
buttonColor: basicStyle.zoomButtonColor,
buttonBackground: basicStyle.zoomBackground
} as any
scene.addControl(new CustomZoom(newZoomOptions))
})
}
})
} else {
@@ -1408,6 +1427,16 @@ export function getMapStyle(
mapStyle = basicStyle.mapStyle
}
break
case 'qq':
if (
!find(qqMapStyleOptions, s => s.value === basicStyle.mapStyle) ||
basicStyle.mapStyle === 'normal'
) {
mapStyle = 'normal'
} else {
mapStyle = basicStyle.mapStyleUrl
}
break
default:
if (!find(gaodeMapStyleOptions, s => s.value === basicStyle.mapStyle)) {
basicStyle.mapStyle = 'normal'
@@ -1457,6 +1486,14 @@ export async function getMapScene(
}
scene.map.showLabel = !(basicStyle.showLabel === false)
if (mapKey.mapType === 'qq') {
scene.map.setBaseMap({
//底图设置参数为VectorBaseMap对象
type: 'vector', //类型:失量底图
features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined
//仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
})
}
}
if (basicStyle.autoFit === false) {
scene.setZoomAndCenter(basicStyle.zoomLevel, center)
@@ -1465,6 +1502,15 @@ export async function getMapScene(
mapRendering(container)
scene.once('loaded', () => {
mapRendered(container)
if (mapKey.mapType === 'qq') {
scene.map.setBaseMap({
//底图设置参数为VectorBaseMap对象
type: 'vector', //类型:失量底图
features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined
//仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
})
scene.setMapStyle(mapStyle)
}
// 去除天地图自己的缩放按钮
if (mapKey.mapType === 'tianditu') {
if (mapStyle === 'normal') {
@@ -1526,6 +1572,18 @@ export function getMapObject(
preserveDrawingBuffer: true
}
})
case 'qq':
return new TencentMap({
token: mapKey?.key ?? undefined,
style: mapStyle,
pitch: miscStyle.mapPitch,
center,
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : 12,
showLabel: !(basicStyle.showLabel === false),
WebGLParams: {
preserveDrawingBuffer: true
}
})
default:
return new GaodeMap({
token: mapKey?.key ?? undefined,

View File

@@ -17,6 +17,7 @@
<el-option value="gaode" :label="t('chart.map_type_gaode')" />
<el-option value="tianditu" :label="t('chart.map_type_tianditu')" />
<!-- <el-option value="baidu" :label="t('chart.map_type_baidu')" />-->
<el-option value="qq" :label="t('chart.map_type_tencent')" />
</el-select>
</div>
<div class="map-item">
@@ -54,6 +55,11 @@
v-if="!mapLoading && mapLoaded && mapEditor.key && mapEditor.mapType === 'tianditu'"
:map-key="mapEditor.key"
/>
<OnlineMapQQ
v-if="!mapLoading && mapLoaded && mapEditor.key && mapEditor.mapType === 'qq'"
:map-key="mapEditor.key"
:security-code="mapEditor.securityCode"
/>
<EmptyBackground
v-if="!mapLoaded"
img-type="noneWhite"
@@ -71,6 +77,7 @@ import { ElMessage } from 'element-plus-secondary'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import OnlineMapTdt from './OnlineMapTdt.vue'
import OnlineMapGaode from './OnlineMapGaode.vue'
import OnlineMapQQ from './OnlineMapQQ.vue'
const { t } = useI18n()
const mapEditor = reactive({

View File

@@ -0,0 +1,107 @@
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
const domId = ref('de-map-container')
const mapInstance = ref(null)
const mapReloading = ref(false)
const props = defineProps<{
mapKey: string
securityCode?: string
}>()
const loadMap = () => {
if (!props.mapKey) {
return
}
const mykey = props.mapKey
const url = `https://map.qq.com/api/gljs?v=1.exp&key=${mykey}`
loadScript(url)
.then(() => {
if (mapInstance.value) {
mapInstance.value?.destroy()
mapInstance.value = null
mapReloading.value = true
setTimeout(() => {
domId.value = domId.value + '-de-'
mapReloading.value = false
nextTick(() => {
createMapInstance()
})
}, 1500)
return
}
createMapInstance()
})
.catch(e => {
console.error(e)
if (mapInstance.value) {
mapInstance.value.destroy()
mapInstance.value = null
}
})
}
const createMapInstance = () => {
if (window.TMap) {
const center = new window.TMap.LatLng(39.90923, 116.397428)
mapInstance.value = new window.TMap.Map(document.getElementById(domId.value), {
viewMode: '2D',
zoom: 11,
center: center
})
mapInstance.value?.removeControl(window.TMap.constants.DEFAULT_CONTROL_ID.ZOOM)
mapInstance.value?.removeControl(window.TMap.constants.DEFAULT_CONTROL_ID.ROTATION)
mapInstance.value?.removeControl(window.TMap.constants.DEFAULT_CONTROL_ID.SCALE)
}
}
const loadScript = (url: string) => {
return new Promise(function (resolve, reject) {
const scriptId = 'de-qq-script-id'
let dom = document.getElementById(scriptId)
if (dom) {
dom.parentElement?.removeChild(dom)
dom = null
window.TMap = null
}
const script = document.createElement('script')
script.id = scriptId
script.onload = function () {
return resolve(null)
}
script.onerror = function () {
return reject(new Error('Load script from '.concat(url, ' failed')))
}
script.src = url
const head = document.head || document.getElementsByTagName('head')[0]
;(document.body || head).appendChild(script)
})
}
onMounted(() => {
loadMap()
})
onBeforeUnmount(() => {
const scriptId = 'de-qq-script-id'
let dom = document.getElementById(scriptId)
if (dom) {
dom.parentElement?.removeChild(dom)
dom = null
window.TMap = null
}
})
</script>
<template>
<div class="de-map-container" v-if="!mapReloading" :id="domId" />
</template>
<style scoped lang="less">
.de-map-container {
height: 100%;
width: 100%;
position: relative;
}
</style>

View File

@@ -58,7 +58,7 @@ const createMapInstance = () => {
}
const loadScript = (url: string) => {
return new Promise(function (resolve, reject) {
const scriptId = 'de-gaode-script-id'
const scriptId = 'de-tdt-script-id'
let dom = document.getElementById(scriptId)
if (dom) {
dom.parentElement?.removeChild(dom)
@@ -84,7 +84,7 @@ onMounted(() => {
loadMap()
})
onBeforeUnmount(() => {
const scriptId = 'de-gaode-script-id'
const scriptId = 'de-tdt-script-id'
let dom = document.getElementById(scriptId)
if (dom) {
dom.parentElement?.removeChild(dom)