VUE 用ANTV 实现展示高亮需要的国家
·

用的是阿里的引擎 AntV L7 地理空间数据可视化引擎
1.在项目中引入 对应的包
pnpm install @antv/l7 @antv/l7-maps
2.在页面引入
import { GaodeMap } from '@antv/l7-maps'
import AllData from '@/assets/Map/All.json'
3.template 代码
<template>
<Spin :spinning="loadingStatus">
<div class="chartBox">
<div class="head">
<span>供应商地区分布情况</span>
<FSelect
:allow-clear="false"
v-model:value="searchDataType"
:options="countryList"
placeholder="请选择"
style="width: 80px"
@change="handleSearch"
></FSelect>
</div>
<div class="map-wrapper">
<!-- 地图容器(盒子) -->
<div class="map-container">
<div id="globalMap" class="map-content"></div>
</div>
</div>
</div>
</Spin>
</template>
4.script 代码
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import { Spin } from 'ant-design-vue'
import { LineLayer, PolygonLayer, Popup, Scene } from '@antv/l7'
import { GaodeMap } from '@antv/l7-maps'
import AllData from '@/assets/Map/All.json'
import { countryList } from '..'
// 中国
import ChinaData from '@/assets/Map/China.json'
// 泰国
import ThailandData from '@/assets/Map/Thailand.json'
// 越南
import VietnamData from '@/assets/Map/Vietnam.json'
//马来西亚
import MalaysiaData from '@/assets/Map/Malaysia.json'
//菲律宾
import PhilippinesData from '@/assets/Map/Philippines.json'
//日本
import JapanData from '@/assets/Map/Japan.json'
//美国
import AmericaData from '@/assets/Map/America.json'
// 印尼
import IndonesiaData from '@/assets/Map/Indonesia.json'
// 全球国家数据类型定义
interface CountryProperties {
name: string // 国家名称
[key: string]: any // 其他属性
}
// 中国省份数据类型定义
interface ProvinceProperties {
name: string // 省份名称
nameLength: number // 名称长度(动态计算)
[key: string]: any // 其他属性
}
// GeoJSON通用Feature类型
interface GeoFeature<T> {
type: 'Feature'
id?: string
properties: T
geometry: {
type: 'Polygon' | 'MultiPolygon'
coordinates: number[][][] | number[][][][] // 地理坐标
}
}
// GeoJSON FeatureCollection类型
interface GeoJSONFeatureCollection<T> {
type: 'FeatureCollection'
features: GeoFeature<T>[]
}
const mapListData: any = {
1: ChinaData,
2: ThailandData,
3: VietnamData,
4: MalaysiaData,
5: PhilippinesData,
6: AmericaData,
7: JapanData,
8: IndonesiaData,
}
// 对应国家中心经纬度
const mapCoordinateData: any = {
1: [105.0, 37.8],
2: [100.992541, 12.8],
3: [108.277199, 14.058324],
4: [101.98, 4.21],
5: [121.774017, 12.879721],
6: [-95.0, 37.0],
7: [138.25, 39.2],
8: [113.92, -0.79],
}
// 每个国家对应的缩放不同
const mapMultiple: any = {
1: 2.2,
2: 3.8,
3: 3.5,
4: 3.8,
5: 3.8,
6: 3,
7: 3.5,
8: 3.2,
}
// 地图实例引用
const sceneRef = ref<Scene | null>(null)
const loadingStatus = ref(false)
const searchDataType = ref(1)
const handleSearch = () => {
if (loadingStatus.value) return
loadingStatus.value = true
if (sceneRef.value) {
sceneRef.value.destroy()
sceneRef.value = null
}
initMap()
setTimeout(() => {
loadingStatus.value = false
}, 1000)
}
// 初始化地图
const initMap = () => {
// 创建地图场景(全球视角)
const scene = new Scene({
id: 'globalMap',
map: new GaodeMap({
style: 'light', // 浅色底图
center: mapCoordinateData[searchDataType.value], // 初始中心(中国视野)
zoom: mapMultiple[searchDataType.value], // 初始缩放级别
maxZoom: 12, // 最大缩放
minZoom: 1, // 最小缩放
}),
})
sceneRef.value = scene
// 地图加载完成后加载数据
scene.on('loaded', async () => {
try {
const [countryRes, provinceRes] = [
// 全球国家GeoJSON数据
AllData,
// 中国省份GeoJSON数据
mapListData[searchDataType.value],
]
// 解析数据
const countryData: GeoJSONFeatureCollection<CountryProperties> = countryRes as any
const provinceRawData: GeoJSONFeatureCollection<{ name: string }> = provinceRes as any
// 2. 处理中国省份数据(计算名称长度)
const provinceData: GeoJSONFeatureCollection<ProvinceProperties> = {
...provinceRawData,
features: provinceRawData.features.map(feature => ({
...feature,
properties: {
...feature.properties,
nameLength: feature.properties.name.length, // 计算名称长度
},
})),
}
console.log(provinceData, 'provinceData')
// 3. 创建全球国家填充图层(基础显示)
const countryLayer = new PolygonLayer({
zIndex: 1, // 底层显示
})
.source(countryData)
.color('#f0f0f0') // 浅灰色填充
.shape('fill')
.style({
opacity: 0.9, // 半透明
})
// 4. 创建全球国家边界图层
const countryBorderLayer = new LineLayer({
zIndex: 2,
})
.source(countryData)
.color('#cccccc') // 灰色边界
.size(0.6)
.style({
lineType: 'solid',
})
// 5. 创建中国省份高亮图层
const chinaProvinceLayer = new PolygonLayer({
zIndex: 3, // 覆盖在国家图层之上
})
.source(provinceData)
.scale('nameLength', {
type: 'linear',
domain: [2, 6], // 省份名称长度范围(2-6字)
})
.color('nameLength', ['#e6f7ff', '#bae7ff', '#91d5ff', '#69c0ff', '#40a9ff', '#1890ff']) // 蓝色系渐变
.shape('fill')
.active(true) // 鼠标悬停高亮
// 6. 创建中国省份边界图层
const chinaBorderLayer = new LineLayer({
zIndex: 4,
})
.source(provinceData)
.color('#ffffff') // 白色边界
.size(1.2)
.style({
lineType: 'solid',
})
// 添加所有图层到地图
scene.addLayer(countryLayer)
scene.addLayer(countryBorderLayer)
scene.addLayer(chinaProvinceLayer)
scene.addLayer(chinaBorderLayer)
// 7. 中国省份鼠标交互(显示弹窗)
chinaProvinceLayer.on('mousemove', (e: { lngLat: [number, number]; feature: GeoFeature<ProvinceProperties> }) => {
const { name, nameLength } = e.feature.properties
const popup = new Popup({
offsets: [0, -10],
closeButton: false,
}).setLnglat(e.lngLat).setHTML(`
<div style="padding: 8px 12px; background: rgba(255,255,255,0.9); border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.15)">
<p style="margin: 0; font-weight: 500">${name}</p>
<p style="margin: 4px 0 0; font-size: 12px; color: #666">名称长度: ${nameLength}</p>
</div>
`)
scene.addPopup(popup)
})
// 8. 全球国家鼠标交互(显示弹窗)
countryLayer.on('mousemove', (e: { lngLat: [number, number]; feature: GeoFeature<CountryProperties> }) => {
const { name } = e.feature.properties
const popup = new Popup({
offsets: [0, -10],
closeButton: false,
}).setLnglat(e.lngLat).setHTML(`
<div style="padding: 6px 10px; background: rgba(255,255,255,0.9); border-radius: 4px; box-shadow: 0 2px 6px rgba(0,0,0,0.1)">
<p style="margin: 0; font-size: 13px">${name}</p>
</div>
`)
scene.addPopup(popup)
})
} catch (error) {
console.error('地图初始化失败:', error)
}
})
}
// 组件挂载时初始化地图
onMounted(() => {
initMap()
})
// 组件卸载时销毁地图
onUnmounted(() => {
if (sceneRef.value) {
sceneRef.value.destroy()
sceneRef.value = null
}
})
// 处理窗口大小变化
const handleResize = () => {
handleSearch()
}
window.addEventListener('resize', handleResize)
</script>
5.CSS代码
<style scoped lang="scss">
.chartBox {
width: 100%;
height: 454px;
background-color: #ffffff;
padding: 24px;
margin-bottom: 16px;
overflow: hidden;
z-index: 1000;
.head {
font-weight: 500;
font-size: 16px;
color: #333333;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
}
.map-wrapper {
/* 外层容器,可控制整体大小 */
width: 100%;
height: 39vh;
margin: 0 auto; /* 居中显示 */
box-sizing: border-box;
}
.map-container {
/* 核心:地图盒子容器 */
width: 100%;
height: 100%;
position: relative; /* 作为地图的定位基准 */
overflow: hidden;
border: 1px solid #eee;
border-radius: 8px;
box-sizing: border-box;
}
.map-content {
/* 地图元素 */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0; /* 填满容器 */
}
:deep(.l7-control-logo-link) {
display: none;
}
</style>
对应国家的JSON文件可以看上一篇文章~
更多推荐
所有评论(0)