赞
踩
本文以echarts展示成都地图为例子。
悬浮点击后高亮
注意:目前成都市geojson数据没有新增的几大区(高新区,天府新区,东部新区),若需要可以在博士的资源下载,或者关注一波,私信可免费获得。
npm install echarts
注意:Echarts版本号超过4.9就不能使用地图软件了,所以需要先卸载高版本再安装
// 卸载echarts运行:
npm uninstall echarts
// 安装4.9版本的echarts
npm install echarts@4.9.0 --save
//vue3+ts
<div ref="centerChartmap" ></div>
//其他
<div id="centerChartmap" ></div>
import {ref,onMounted,markRaw,defineEmits} from "vue";
import * as echarts from "echarts";
import arrMap from "./map.json"; //地图json数据
const emit = defineEmits(["clickChild"]); //地图点击后传入父组件点击数据
let chartInstance = ref();// 初始化图表对象
onMounted(() => {
initChart(); // 图表初始化
});
const initChart = () => {
// 定义实例 vue3用ref定义echarts要使用markRaw 后文有解释
chartInstance.value =markRaw(echarts.init(centerChartmap.value, "myTheme"));
//或chartInstance.value=echarts.init(document.getElementById('centerChartmap')
echarts.registerMap("china", { geoJSON: arrMap });
//注册可用的地图并添加geojson数据,只在 geo组件或者 map 图表类型中使用。
let optionMap = {
geo: {
map: "china",
roam: true,
center: [ 103.909956,30.775001], //定义中心点
layoutSize: "100%",
selectedMode: "single",
regions: [ //隐藏南海诸岛
{
name: "南海诸岛",
itemStyle: {
// 隐藏地图
normal: {
opacity: 0, // 为 0 时不绘制该图形
},
},
label: {
show: false, // 隐藏文字
},
},
],
zoom: 12,
//点击后颜色样式设置
select: {
itemStyle: {
borderWidth: 2.5,
areaColor: "rgb(8, 207, 221)",
shadowColor: "rgba(255, 255, 255, 0.3)",
shadowBlur: 10,
shadowOffsetX: 4,
shadowOffsetY: 4,
},
},
//图形上的文本标签,可用于说明图形的一些数据信息
label: {
normal: {
show: true,
fontSize: "10",
color: "#fff",
},
},
//地图区域的多边形 图形样式,有 normal 和 emphasis 两个状态
itemStyle: {
//normal 是图形在默认状态下的样式;
normal: {
areaColor: "rgb(5,66,200,0.8)",
borderColor: "#26e3ff", //线
},
//emphasis 是图形在高亮状态下的样式,比如在鼠标悬浮或者图例联动高亮时。
emphasis: {
areaColor: "#26e3ff",
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
colorBy: "series",
series: [
{
name: "信息量",
type: "map",
mapType: "china",
geoIndex: 0,
data: [], //可设置初始选中值[{ name: '武侯区', selected: true }],
},
],
};
chartInstance.value.setOption(optionMap);
chartInstance.value.on("click", function (params) {
//将点击的区域数据传递给父组件
emit("clickChild", params.name);
});
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘type‘)
你可以有选择地退出默认的深度响应式/只读转换模式,并将原始的,未被代理的对象嵌入状态图中。它们可以根据情况灵活运用:
有些值不应该是响应式的,例如复杂的第三方类实例或 Vue 组件对象。(第三方实例)
当渲染具有不可变数据源的大列表时,跳过 proxy 转换可以提高性能。
在实例化echart时,将其指定为非响应式的
import { markRaw } from 'vue'
chartInstance.value = markRaw(echarts.init(centerChartmap.value, "myTheme"));
toRaw | markRaw |
---|---|
将一个由reactive生成的响应式对象转为普通对象。 | 标记一个对象,使其永远不会再成为响应式对象。 |
用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。 | 有些值不应被设置为响应式的,例如复杂的第三方类库等。当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。 |
let optionMap = {
...
geo: {
...
regions: [
{
name: "南海诸岛",
itemStyle: {
normal: {
opacity: 0, // 为 0 时不绘制该图形
},
},
label: {
show: false, // 隐藏文字
},
},
],
...
},
...
}
let optionMap = {
...
// 提示浮窗样式
tooltip: {
show: true,
trigger: "item", //坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
alwaysShowContent: false,
backgroundColor: "rgba(36, 215, 209, 1)", //提示框背景色
borderColor: "rgba(255, 255, 255, 1)",
triggerOn: "mousemove",
enterable: true, //鼠标是否可进入提示框浮层中
textStyle: {
fontSize: "12",
overflow: "break",
},
formatter: function (params) {
//提示框显示的内容
let str = "";
str = `<div> ` + params.name + `</div>`;
return str;
},
},
...
}
下钻简而言之,在地图的点击事件回调中,加载了另一份地图的json并注册地图,然后再setOption中更改了地图名字,可以前端保存json数据,但最好还是后端返回,点击时前端请求比较好。
chartInstance.value.on("click", function (params) {
...
if (params.componentSubType == 'map') {
goDown(params.name,optionMap)
}
});
const goDown=(name,optionMap)=>{
if (!echarts.getMap(name)) {
const newMapJson = echarts.registerMap(name, { geoJSON: import('./map/'+name+'.json')})
optionMap.geo.map = mapname
optionMap.series[0].map = mapname
chartInstance.value.setOption(optionMap);
}
}
与下钻一个意思,不过回钻是往回走,我们只要把每一次地图的显示存入一个数组,回钻时取最后一个就行了。
//用来存放当前的地图名字
let currentName =ref('')
//用来存放下钻的历史记录
let history =ref([])
...
chartInstance.value.on("click", function (params) {
...
if (params.componentSubType == 'map') {
goDown(params.name,optionMap)
}
});
const goDown=(name,optionMap)=>{
if (!echarts.getMap(name)) {
const newMapJson = echarts.registerMap(name, { geoJSON: import('./map/'+name+'.json')})
optionMap.geo.map = mapname
optionMap.series[0].map = mapname
history.push(currentName) //点击时存入
chartInstance.value.setOption(optionMap);
currentName = name
}
}
const returnUpLevel=(optionMap)=>{
//先判断history有没有数据,能不能返回
if(history.length == 0){
return false
}
//取出要返回的那个名字
const name = history.pop() //pop删除数组最后一个元素并返回该元素。
const currentJson = echarts.getMap(mapname).geoJson
//修改地图配置重新绘制地图
//因为之前地图是已经绘制了的,只是把后面的遮盖了,所以数据是存在的,我们不需要在重新设置数据源了
optionMap.geo.map = mapname
optionMap.series[0].map = mapname
chart.setOption(optionMap)
//修改当前的层级,名字
currentName = name
}
let optionMap={
...
series: [
{
type: "scatter",
zoom: 1,
coordinateSystem: "geo",
data: [
{
name: "天府新区",
value: [104.11399841308594, 30.407471430197215], //图标坐标及大小
type: "iconData",
},
{
name: "东部新区",
value: [104.35875962495804, 30.32959455353757],
type: "iconData",
},
{
name: "高新南区",
value: [104.04893657684326, 30.608679048796095],
type: "iconData",
},
],
symbol:'image://data:image/png;base64,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',//图片路劲,必须用BASE64编码格式!!!!
z: 2,
// symbolOffset: [0, -40], //偏移量
symbolSize: [20, 30], // symbols图标大小
},
...
}
import baseBg from ‘./baseBg.jpg’
let markImg=‘image://’+baseBg
//这段代码可以分为两个部分,第一部分为统一的image:// ;第二部分为你的图片路径。
let optionMap = {
...
//图形上的文本标签,可用于说明图形的一些数据信息
label: {
normal: {
formatter: (params) => {
if (
params.name == "天府新区" ||
params.name == "高新南区" ||
params.name == "东部新区"
) {
return params.name;
} else {
return "";
}
},
show: true,
fontSize: "10",
color: "#fff",
},
},
...
}
let optionMap = {
...
visualMap: {
min: 0,
max: 100000,
left: 26,
bottom: 40,
showLabel: !0,
textStyle: {
color: "#fff",
},
pieces: [
{
gte: 1,
lt: 100,
color: "red",
},
{
gte: 101,
lt: 200,
color: "yellow",
},
{
gte: 201,
lt: 300,
color: "blue",
},
{
gte: 301,
lt: 400,
color: "green",
},
],
// show: false, 是否展示左上角的图例
},
...
series: [
{
name: "信息量",
type: "map",
mapType: "china",
geoIndex: 0,
data: [
{ name: "天府新区",value: 10,},
{ name: "东部新区", value: 101 },
{ name: "高新南区", value: 201 },
{ name: "双流区", value: 301 },
],
},
],
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。