vue3 使用echarts实现中国地图动态标点定位
·
1.效果图:


2. 安装echarts:
npm install echarts --save
3.引入中国地图JSONDataV.GeoAtlas地理小工具系列

4.代码如下:
<template>
<div class="map-container">
<div id="map-chart" class="map" tabindex="0"></div>
<div class="input-card">
<div class="mt5">
<el-avatar
:size="20"
src="xxx"
/>
一级代理店
</div>
<div class="mt5">
<el-avatar
:size="20"
src="xx"
/>
二级代理店
</div>
<div class="mt5">
<el-avatar
:size="20"
src="xxx"
/>
三级代理店
</div>
</div>
<div class="info">
<div class="input-item">
<el-input
v-model="addressInput"
placeholder="请输入地址"
@keyup.enter="handleSearch"
>
<template #append>
<el-button @click="handleSearch" icon="search">查询</el-button>
</template>
</el-input>
</div>
</div>
</div>
</template>
<script>
import { onMounted, ref, onBeforeUnmount } from "vue";
import * as echarts from "echarts";
import "echarts/extension/bmap/bmap";
import chinaJson from "./china.json"; //中国地图(省份)自行下载
export default {
name: "AgentMapEcharts",
setup() {
const addressInput = ref("");
let chartInstance = null;
let originalData = []; // 保存原始数据
// 店铺类型配置
const shopTypeConfig = {
一级代理店: {
color: "#fcb715",
icon: "xxx",
symbolSize: 18,
},
二级代理店: {
color: "#00862b",
icon: "xxx",
symbolSize: 16,
},
三级代理店: {
color: "#015aef",
icon: "xxx",
symbolSize: 16,
},
};
// 初始化地图和图表
const initMap = () => {
chartInstance = echarts.init(document.getElementById("map-chart"));
// 注册中国地图数据(核心修改)
echarts.registerMap("china", chinaJson);
// 初始配置 - 简化地图样式配置
const option = {
animation: true,
tooltip: {
trigger: "item",
formatter: (params) => {
if (params.data) {
const data = params.data;
return `
<div style="padding: 5px; min-width: 150px; color: ${
shopTypeConfig[data.type]?.color || "#333"
}">
<div>店号:${data.code || "无"}</div>
<div>店主:${data.name || "无"}</div>
<div>地址:${data.address || "无"}</div>
<div>类型:${data.type || "无"}</div>
</div>
`;
}
return "";
},
},
geo: {
// 替换原有的bmap配置
map: "china",
roam: true,
zoom: 2,
center: [104.114129, 37.550339], // 中国中心点坐标
label: {
show: true,
color: "#333",
},
itemStyle: {
areaColor: "#f0f8ff", // 浅蓝色背景
borderColor: "#00868B", // 青色边框
},
emphasis: {
itemStyle: {
areaColor: "#e6f7ff", // 高亮时浅蓝色
},
},
},
series: [
{
name: "代理店",
type: "scatter",
coordinateSystem: "geo",
data: [],
symbolSize: function (val) {
return shopTypeConfig[val.type]?.symbolSize || 10;
},
itemStyle: {
color: function (val) {
return shopTypeConfig[val.data?.type]?.color || "#333";
},
},
emphasis: {
itemStyle: {
color: function (val) {
return shopTypeConfig[val.data?.type]?.color || "#333";
},
borderWidth: 2,
borderColor: "#fff",
},
},
},
],
};
chartInstance.setOption(option);
loadAgentData();
};
// 加载代理店数据
const loadAgentData = async () => {
try {
let shops = [
{
FDLDName: "聂xx",
FAdr: "内蒙古兴安盟乌兰浩特xxx",
FDLDCode2: "0720",
FType: "一级代理店",
FLong: "122.0832190000",
FLat: "46.0744950000",
FId: 1749,
},
{
FDLDName: "郑xx",
FAdr: "河北省石家庄新乐市邯xxx",
FDLDCode2: "2063",
FType: "一级代理店",
FLong: "114.7235690000",
FLat: "38.3414250000",
FId: 4993,
},
{
FDLDName: "姚xx",
FAdr: "xxx",
FDLDCode2: "0071CD",
FType: "二级代理店",
FLong: "122.9915890000",
FLat: "41.1202170000",
FId: 1306,
},
{
FDLDName: "任xx",
FAdr: "辽宁省开原市八宝镇金xxx",
FDLDCode2: "0002AF",
FType: "二级代理店",
FLong: "124.7318630000",
FLat: "42.7378750000",
FId: 1303,
},
{
FDLDName: "梁xx",
FAdr: "四川省西昌市宁远桥光xxx",
FDLDCode2: "0376AO",
FType: "二级代理店",
FLong: "102.2518450000",
FLat: "27.8949840000",
FId: 1301,
},
{
FDLDName: "史xx",
FAdr: "河南省焦作市解放区上xxx",
FDLDCode2: "0439AC",
FType: "二级代理店",
FLong: "113.2055600000",
FLat: "35.2501130000",
FId: 1302,
},
{
FDLDName: "周xx",
FAdr: "xxx",
FDLDCode2: "0550AB",
FType: "二级代理店",
FLong: "122.1258080000",
FLat: "40.8342490000",
FId: 1299,
},
{
FDLDName: "付xx",
FAdr: "xxx",
FDLDCode2: "0298AM",
FType: "二级代理店",
FLong: "103.4487120000",
FLat: "30.6189520000",
FId: 1300,
},
{
FDLDName: "刘xx",
FAdr: "xxx",
FDLDCode2: "0572",
FType: "二级代理店",
FLong: "119.1280900000",
FLat: "36.7201900000",
FId: 1327,
},
{
FDLDName: "甄xx",
FAdr: "xxx",
FDLDCode2: "0018AI",
FType: "二级代理店",
FLong: "125.8612620000",
FLat: "42.6425390000",
FId: 1329,
},
{
FDLDName: "杜xx",
FAdr: "xxx",
FDLDCode2: "0018AH",
FType: "二级代理店",
FLong: "125.8612620000",
FLat: "42.6425390000",
FId: 1330,
},
];
// 转换数据格式
originalData = shops
.filter((shop) => {
const lng = parseFloat(shop.FLong) || 0;
const lat = parseFloat(shop.FLat) || 0;
return lng !== 0 && lat !== 0;
})
.map((shop) => {
const type = shop.FType || "一级代理店";
return {
name: shop.FDLDName,
code: shop.FDLDCode2,
address: shop.FAdr,
type: type,
value: [
parseFloat(shop.FLong),
parseFloat(shop.FLat),
shop.FDLDName,
],
symbol: `image://${shopTypeConfig[type]?.icon}`,
symbolSize: shopTypeConfig[type]?.symbolSize || 10,
itemStyle: {
color: shopTypeConfig[type]?.color || "#333",
},
// 添加原始大小记录
originalSize: shopTypeConfig[type]?.symbolSize || 10,
};
});
// 更新图表数据
updateChartData(originalData);
} catch (error) {
console.error("加载代理店数据失败:", error);
}
};
// 更新图表数据
const updateChartData = (data) => {
chartInstance.setOption({
series: [
{
data: data,
},
],
});
};
const handleSearch = async () => {
if (!addressInput.value) {
// 如果搜索框为空,恢复原始数据显示
updateChartData(originalData);
return;
}
// 创建新的数据数组
const newData = originalData.map((shop) => {
// 默认使用原始大小
const size = shop.originalSize;
// 如果地址匹配,放大图标
if (shop.address && shop.address.includes(addressInput.value)) {
return {
...shop,
symbolSize: size * 5, // 放大5倍
};
}
return shop;
});
// 查找匹配的店铺
const foundShops = newData.filter(
(shop) => shop.address && shop.address.includes(addressInput.value)
);
if (foundShops.length > 0) {
// 定位到第一个匹配的店铺
const firstShop = foundShops[0];
chartInstance.setOption({
geo: {
center: firstShop.value.slice(0, 2),
zoom: 12, // 适当的缩放级别
},
series: [
{
data: newData,
},
],
});
} else {
console.log("未找到匹配的店铺");
// 可以添加提示
updateChartData(originalData); // 恢复原始数据
}
};
// 窗口大小变化时重新调整图表大小
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
onMounted(() => {
initMap();
window.addEventListener("resize", handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
if (chartInstance) {
chartInstance.dispose();
}
});
return {
handleSearch,
addressInput,
};
},
};
</script>
<style>
.map-container {
position: relative;
height: 100vh;
width: 100vw;
}
.map {
height: 100%;
width: 100%;
}
.input-card {
position: absolute;
bottom: 100px;
right: 20px;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5);
z-index: 10;
}
.info {
position: absolute;
top: 20px;
right: 20px;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5);
z-index: 10;
width: 300px;
}
.input-item {
margin-bottom: 10px;
}
</style>
更多推荐
所有评论(0)