echarts地圖制作
-
離線地圖下載地址https://datav.aliyun.com/tools/atlas/index.html
-
echarts檔案地址https://echarts.apache.org/zh/option.html
基于VUE撰寫,其他框架請自行轉換,大同小異
基礎配置
先讓地圖內容出來,npm安裝步驟省略,請參考官方檔案,創建的div必須設定寬度和高度,關于圖表的寬高自適應,參考我的另一篇文章
<template>
<div class="content">
<div ref="charts" style="width: 1000px; height: 800px"></div>
</div>
</template>
<script>
import * as echarts from "echarts";
import zhongguo from "@/assets/mapJson/data-city.json"
export default {
created () {
this.$nextTick(() => {
this.initCharts();
})
},
methods: {
initCharts() {
const charts = echarts.init(this.$refs["charts"]);
const option = {
// 背景顏色
backgroundColor: "#404a59",
// 提示浮窗樣式
tooltip: {
show: true,
trigger: "item",
alwaysShowContent: false,
backgroundColor: "#0C121C",
borderColor: "rgba(0, 0, 0, 0.16);",
hideDelay: 100,
triggerOn: "mousemove",
enterable: true,
textStyle: {
color: "#DADADA",
fontSize: "12",
width: 20,
height: 30,
overflow: "break",
},
showDelay: 100
},
// 地圖配置
geo: {
map: "china",
label: {
// 通常狀態下的樣式
normal: {
show: true,
textStyle: {
color: "#fff",
},
},
// 滑鼠放上去的樣式
emphasis: {
textStyle: {
color: "#fff",
},
},
},
// 地圖區域的樣式設定
itemStyle: {
normal: {
borderColor: "rgba(147, 235, 248, 1)",
borderWidth: 1,
areaColor: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.8,
colorStops: [
{
offset: 0,
color: "rgba(147, 235, 248, 0)", // 0% 處的顏色
},
{
offset: 1,
color: "rgba(147, 235, 248, .2)", // 100% 處的顏色
},
],
globalCoord: false, // 預設為 false
},
shadowColor: "rgba(128, 217, 248, 1)",
shadowOffsetX: -2,
shadowOffsetY: 2,
shadowBlur: 10,
},
// 滑鼠放上去高亮的樣式
emphasis: {
areaColor: "#389BB7",
borderWidth: 0,
},
},
},
};
// 地圖注冊,第一個引數的名字必須和option.geo.map一致
echarts.registerMap("china",zhongguo)
charts.setOption(option);
},
},
};
</script>
這是最基礎的配置,外加了一些我自己寫的樣式,使地圖美觀一些,如果你完全的復制,并且china.json檔案也引入了,那么你會看到如下的內容

這其中比較有意思的是,如果你注冊地圖時,還有option.geo.map的名字用的是china,南海諸島會如上圖以縮略圖展示,但是以此之外來命名地圖,則不會展示縮略圖,
再次宣告,如果二者名字不一致,將會導致例外,致使地圖無法顯示
資料渲染
實際開發中,往往需要將后臺的資料渲染到地圖里,我們在option里添加series屬性,以下是我的兩個示例,僅做參考:
series: [
{
type: "scatter",
coordinateSystem: "geo",
symbol: "pin",
legendHoverLink: true,
symbolSize: [60, 60],
// 這里渲染標志里的內容以及樣式
label: {
show: true,
formatter(value) {
return value.data.value[2];
},
color: "#fff",
},
// 標志的樣式
itemStyle: {
normal: {
color: "rgba(255,0,0,.7)",
shadowBlur: 2,
shadowColor: "D8BC37",
},
},
// 資料格式,其中name,value是必要的,value的前兩個值是資料點的經緯度,其他的資料格式可以自定義
// 至于如何展示,完全是靠上面的formatter來自己定義的
data: [
{ name: "西藏", value: [91.23, 29.5, 2333] },
{ name: "黑龍江", value: [128.03, 47.01, 1007] },
],
showEffectOn: "render",
rippleEffect: {
brushType: "stroke",
},
hoverAnimation: true,
zlevel: 1,
},
// {
// type: "effectScatter",
// coordinateSystem: "geo",
// effectType: "ripple",
// showEffectOn: "render",
// rippleEffect: {
// period: 10,
// scale: 10,
// brushType: "fill",
// },
// hoverAnimation: true,
// itemStyle: {
// normal: {
// color: "rgba(255, 235, 59, .7)",
// shadowBlur: 10,
// shadowColor: "#333",
// },
// },
// zlevel: 1,
// data: [
// { name: "西藏", value: [91.23, 29.5, 2333] },
// { name: "黑龍江", value: [128.03, 47.01, 1007] },
// ],
// },
],
兩種渲染方式如下:


使用備注的部分時,需要在option.tooltip里添加formatter屬性,我寫的如下:
const option = {
// ...
tooltip: {
// ...
formatter(params) {
return `地區:${params.name}</br>數值:${params.value[2]}`;
}
}
}
更多的方式還要自己多試驗,這是個費時且需要耐心的活,你甚至可以將柱狀圖放上去,有更花里胡哨的效果,也請分享給我,
嵌入文字
使用option.graphic可以實作簡單的水印效果
const option = {
// ...
graphic:{
// 水印型別
type: 'text',
// 相對于容器的位置
left:'10%',
top: '10%',
// 樣式設定
style: {
// 文本內容
text: "create by cRack_cLick",
// 字體粗細、大小、字體
font: 'bolder 1.5rem "Microsoft YaHei", sans-serif',
// 字體顏色
fill: "#fff"
}
}
}
效果如下:

利用graphic的type=“group”,還可以組合出一些有意思的效果(抄官方檔案的效果):
graphic: {
type: "group",
rotation: Math.PI / 4,
bounding: "raw",
left: 110,
top: 110,
z: 100,
children: [
{
type: "rect",
left: "center",
top: "center",
z: 100,
shape: {
width: 400,
height: 50,
},
style: {
fill: "rgba(0,0,0,0.3)",
},
},
{
type: "text",
left: "center",
top: "center",
z: 100,
style: {
fill: "#ddd",
text: "create by cRack_cLick",
font: 'bolder 1.5rem "Microsoft YaHei", sans-serif',
},
},
],
},

地圖下鉆
往往還有一種需求,在我們點擊一個省的時候,需要切換到這個省的詳細地圖,甚至還可以下鉆到市、縣等等,
為了試下點擊下鉆,我們需要先了解echarts中的點擊事件,檔案參考
以目前的功能來說,我們暫時不需要加入其它的業務邏輯以及省級的資料渲染,僅僅只做地圖的切換,所以點擊事件里我們需要實作獲取點擊的省份名稱,然后根據省份名稱,來選擇地圖的JSON檔案,最后重新渲染echarts圖表,下面是我的簡單示例:
// 新增加北京的地圖JSON檔案
import beijing from "@/assets/mapJson/data-beijing.json";
// ...
initCharts(){
const charts = echarts.init(this.$refs["charts"]);
// ...
// 注意這里是echarts的實體物件,而不是echarts組件本身,
charts.on('click', ({name}) => {
if (name === "北京") {
// 修改option的配置,可以繼續自定義
option.geo.zoom = 0.8
// 就像上面提到的,這里必須要和注冊地圖時的名字一致
option.geo.map = "beijing"
// 注冊地圖
echarts.registerMap("beijing", beijing)
// 重新渲染
charts.setOption(option, true)
}
})
}
需要注意的是,在重新setOption的時候,我們加入了第二個引數,按照官方檔案的說法:
引數:
呼叫方式:
chart.setOption(option, notMerge, lazyUpdate);
或者
chart.setOption(option, {
notMerge: ...,
lazyUpdate: ...,
silent: ...
});
-
option圖表的配置項和資料,
-
notMerge可選,是否不跟之前設定的
option進行合并,默認為false,即合并, -
lazyUpdate可選,在設定完
option后是否不立即更新圖表,默認為false,即立即更新, -
silent可選,阻止呼叫
setOption時拋出事件,默認為false,即拋出事件,
第二個從引數設定為true來讓圖表重新渲染,而不合并配置,當然,這一點具體需要看你顯示開發的需求,我在這里僅是為了演示,絕不是偷懶
另外在echarts v3.x的版本里,切換地圖默認是有過渡影片的,而v4.x和v5.x的版本里則沒有過渡影片,如果知道怎么加上的,可以私信我,
上面雖然可以實作地圖切換,但很顯然開發中這么寫要被打死,下鉆三十多個地圖要寫三十多個if,顯然是一種不理智的開發方式,一種方式我們可以通過axios或者ajax異步請求,但是這樣需要你在生產環境和運維協商好,否則會導致請求不到JSON檔案,
下面是我在前端寫的一個簡單的工具方法,僅供參考:
import zhongguo from "@/assets/mapJson/data-city.json";
import neimenggu from "@/assets/mapJson/data-neimenggu.json";
import beijing from "@/assets/mapJson/data-beijing.json";
// ...
const mapDict = {
"北京": "beijing",
"內蒙古": "neimenggu",
// ...
}
const mapData = {
beijing,
neimenggu,
// ...
}
export function getMap(mapName) {
const cityName = mapDict[mapName]
if(cityName){
return [cityName, mapData[cityName]]
}
return ['china', zhongguo]
}
需要建立兩個字典,一個是漢字和拼音的對照映射,一個是拼音和JSON檔案的映射,這個可靈活配置,并非唯一,
優化一下上面的的代碼:
// 洗掉地圖json檔案的參考,修改為上面的工具方法
import { getMap } from "./maputil";
methods: {
initCharts() {
const charts = echarts.init(this.$refs["charts"]);
const option = {
// ...
};
// 不傳name默認會回傳中國地圖
const [mapName, mapJson] = getMap();
option.geo.map = mapName;
// 地圖注冊,第一個引數的名字必須和option.geo.map一致
echarts.registerMap(mapName, mapJson);
charts.setOption(option);
charts.on("click", ({ name }) => {
// 這里和上面一樣,其實還可以再優化一下,為了方便閱讀,這里不再封裝,
const [mapName, mapJson] = getMap(name);
option.geo.zoom = 0.8;
option.geo.map = mapName;
echarts.registerMap(mapName, mapJson);
charts.setOption(option, true);
});
}
}
效果如下:

結合水印制作級聯效果
現在的地圖可以下鉆了,但是似乎操作起來還有些別扭,
我們現在想要的效果是:我們需要每下鉆一層,水印部分就會加上當前地區的名稱,點擊水印地區的名稱,就會跳轉到當前地區的地圖,我們要來改造一下echarts示例的click事件,
首先option.graphic的默認值修改為中國地圖,這里為了方便閱讀,僅使用text格式演示:
// ...
graphic: [
{
type: "text",
left: "10%",
top: "10%",
style: {
text: "中國",
font: 'bolder 1.5rem "Microsoft YaHei", sans-serif',
fill: "#fff",
},
},
],
以陣列的形勢撰寫后,思路就明顯了,只要在click事件的時候,將下鉆地圖的資訊push進來,并且為了防止重合,稍微移動一下定位即可,我的示例如下:
charts.on("click", ({ name }) => {
const [mapName, mapJson] = getMap(name);
option.geo.zoom = 0.8;
option.geo.map = mapName;
// 為了重新定位,這里使用了length
const idx = option.graphic.length + 1;
option.graphic.push({
type: "text",
left: `${idx * 10}%`,
top: "10%",
style: {
text: name,
font: 'bolder 1.5rem "Microsoft YaHei", sans-serif',
fill: "#fff",
},
});
echarts.registerMap(mapName, mapJson);
charts.setOption(option, true);
});
點擊后效果如下:

現在還有問題,就是點擊地區名字沒有回應,所以我們還要為option.graphic子元素加上click事件
這個click事件功能也類似,獲取地圖名稱,獲取地圖資料,重新渲染,但是這個click事件需要注意,比如我點擊了北京,那么在陣列里是需要將密云區的元素洗掉掉的,同理,點擊中國,則后面的元素都要洗掉,在這里我就不把相同的部分抽離出來了:
// 防止graph里頻繁添加click事件,在添加click事件之前先全部清空掉,
charts.off()
charts.on("click", ({name}) => {
// 如果option.graphic里已經有了城市名稱,則不進行任何操作,防止頻繁點擊
const index = option.graphic.findIndex(i => i.style.text === name);
if (!name || index !== -1) return
const [mapName, mapJson] = getMap(name);
option.geo.zoom = 0.8;
option.geo.map = mapName;
// 為了重新定位,這里使用了length
const idx = option.graphic.length + 1;
option.graphic.push({
type: "text",
left: `${idx * 10}%`,
top: "10%",
style: {
text: name,
font: 'bolder 1.5rem "Microsoft YaHei", sans-serif',
fill: "#fff",
},
onclick: () => {
// 利用函式的作用域,可以直接拿上面的name來用
const [grahpName, graphJson] = getMap(name);
const index = option.graphic.findIndex(i => i.style.text === name);
// 點擊元素之后的所有元素全部洗掉
option.graphic.splice(index + 1);
// 很多操作重復了,你可以將公共部分抽離出來
option.geo.map = mapName;
echarts.registerMap(grahpName, graphJson);
charts.setOption(option, true);
},
});
echarts.registerMap(mapName, mapJson);
charts.setOption(option, true);
});
這里會有個坑,在給graph添加click事件后,點擊時會同時觸發我們上面charts.on的click事件,想了很久也沒有找到好一點的方式來解決這個事件沖突,最后只好判斷了一下name是否為空來暫時解決,如果有更好的辦法,也請留言,最終效果如下:

至此繪制地圖已經完畢,更多是依靠自己的業務需求來進行更靈活的配置和渲染,它的API沒有什么太復雜的,只是我們缺少了一點耐心去實驗,
visualMap
首先來看效果

增加visualMap來讓地圖的資料渲染更有層次感,實作起來也很簡單,只需要在option里增加visualMap配置即可:
const option = {
// ...
visualMap: {
// 是否展示左下角,即是是false,也僅是不顯示,不影響資料的映射
show: true,
// 上下端文字
text: ["高", "低"],
// 最小值和最大值,必須指定
min: 0,
max: 6000,
// 位置
left: "10%",
bottom: "10%",
// 是否展示滑塊
calculable: true,
// 指定映射的資料,對應的是option.series,這里根據自己的實際需要進行配置
seriesIndex: [0],
// 從下到上的顏色
inRange: {
color: ['#00467F', '#A5CC82'],
},
//字體顏色
textStyle: {
color: "#fff",
map: "china",
},
}
}
如果你的代碼是跟著我從上面一直寫下來的,那么此時你應該發現只是定位的圖示變了,相應的地圖區域并未變色,所以我們還要把地圖的資料映射上去,所以在option.series里再加一個元素,使其type=“map”,內容與geo一致即可,但是要多加data屬性,渲染的資料和定位圖示一致,并將seriesIndex的索引做好映射,即可實作,
const option = {
// ...
visualMap: {
// 是否展示左下角,即是是false,也僅是不顯示,不影響資料的映射
show: true,
// 上下端文字
text: ["高", "低"],
// 最小值和最大值,必須指定
min: 0,
max: 6000,
// 位置
left: "10%",
bottom: "10%",
// 是否展示滑塊
calculable: true,
// 指定映射的資料,對應的是option.series,這里根據自己的實際需要進行配置
seriesIndex: [0],
// 從下到上的顏色
inRange: {
color: ['#00467F', '#A5CC82'],
},
//字體顏色
textStyle: {
color: "#fff",
map: "china",
},
}
}
如果你的代碼是跟著我從上面一直寫下來的,那么此時你應該發現只是定位的圖示變了,相應的地圖區域并未變色,所以我們還要把地圖的資料映射上去,所以在option.series里再加一個元素,使其type=“map”,內容與geo一致即可,但是要多加data屬性,渲染的資料和定位圖示一致,并將seriesIndex的索引做好映射,即可實作,
如果出現了縮放重影,說明生成了兩個地圖組件,需要在新的series里加上geoIndex屬性,值是geo里的索引,這樣就只會共享一個組件,不會出現縮放重影的問題了
以下為源檔案:
默認情況下,map series 會自己生成內部專用的 geo 組件,但是也可以用這個 geoIndex 指定一個 geo組件,這樣的話,map 和 其他 series(例如散點圖)就可以共享一個 geo組件了,并且,geo組件的顏色也可以被這個 map series 控制,從而用 visualMap來更改,
當設定了 geoIndex 后,series-map.map屬性,以及 series-map.itemStyle等樣式配置不再起作用,而是采用 geo中的相應屬性,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/354657.html
標籤:其他
下一篇:【20】資料可視化+爬蟲+分析:基于 Echarts + Python + Pandas 實作的動態實時大屏范例 - Forbes全球富豪榜
