這兩天接到一個資料視覺化的需求,要求展示當前選擇的省、市到其他省市的產品遷徙資料,需求並不難,而且地圖的視覺化也比較成熟,echarts也有對應的例子,我們先看下預覽圖。
預覽圖:
簡介
為什麼要這篇筆記呢,有兩個原因:
- 防止下次再去找這些配置項,自己以前用過echarts,時間久了,導致接到echart的需求後,以前一些有關聯的配置項沒有記錄,就需要重新過一遍api或者google百度,很浪費時間。
- 大資料技術越來越多,用到地圖視覺化的效果也越來越多,把做地圖遷徙效果的思路寫一下,防止走彎路,如果大家看完後哪怕能提高十分鐘或者五分鐘的效率,這個筆記也就有一丟丟的價值了。
需求描述
我們的需求如下
-
- 預設進去後地圖展示各個省的遷出量
-
- 選中某一個省後展示當前省到其他省的遷出量
-
- 選中省的某一個市後,展示當前市到其他省的遷出量
-
- 點選到其他省後,彈出柱狀圖顯示當前城市到省會下所有城市的遷出量。
需求確定後,首先後端夥伴就是要資料格式,我們先要知道自己需要哪些資料,才能給到後端夥伴的格式。
開發步驟
1. 建立地理座標系
建立div、樣式這部分略過,然後建立geo地理座標系元件,地理座標系元件什麼意思呢?官網這麼說的,
地理座標系元件用於地圖的繪製,支援在地理座標系上繪製散點圖,線集。
官網文件,也就是我們可以在這個元件繪散點圖和線圖。
官網暫時不提供地圖下載了,說部分資料不符合國家《測繪法》規定,API例子裡拔了一下china.js
檔案,就是地圖的資料檔案,可以用,先看下效果。
var mapOption = {
// 地圖示題
title : {
text: 'XX城S端車源流向',
subtext: '日期:2018-10-11',
left: 'left',
textStyle : {
color: '#fff',
fontSize:30
},
top:20,
left:20
},
// 插入地圖座標系元件
geo: {
// 地圖座標系資料
map: 'china',
show:true,
itemStyle: {
// 背景色
areaColor: '#000000',
emphasis: {
label:{
show:false
}
}
}
}
};
// 建立例項
myChart = echarts.init(document.getElementById('map'));
// 設定資料
myChart.setOption(mapOption);
複製程式碼
2. 建立地圖系列色塊
接下來我們再畫一下地圖根據數值來顯示不同的顏色,這塊大家可能會有點疑惑,怎麼還畫地圖,不是已經出來了嗎?
是這樣,echart有區分元件和系列,元件有很多,比如title標題元件、legend圖例元件、xAxis資料軸元件、tooltip提示框元件等等,其中就有我們剛才上面提到的地理座標系元件
,系列官網是這麼解釋的是
系列列表。每個系列通過 type 決定自己的圖表型別
官網文件。
系列資料放在series配置下,可以放置多種型別,折線/面積圖、柱狀/條形圖、餅圖、散點圖等。
這塊剛接觸的同學可能不太好理解,舉個例子,座標元件就相當於超市的貨架,echarts提供多種貨架,有口香糖貨架,廚房用品貨架、文具用品貨架,而貨架上方的東西雖然都是一類,但是有區分品牌,比如口香糖有綠箭、益達、炫邁等,品牌就是系列。
地理座標系元件相當於口香糖貨架,綠箭、益達、炫邁相當於地圖系列、散點系列、線圖系列。
系列資料放在serise
屬性裡,我們先建立map地圖系列,根據value值大小展示不同顏色,一般設計稿不會用外掛預設的主題,配置主題色要用到visualMap
視覺對映元件並設定其下的inRange
屬性,想把資料分成幾段就設定幾個就可以了,**但是必須設定max
屬性最大值,**程式碼如下。
// 增加地圖系列
mapOption.series.push({
name: '地圖色塊',
// 系列型別
type: 'map',
mapType: 'china',
// 禁用縮放
roam: false,
// 隱藏label
label: {
normal: {
show: false
},
emphasis: {
show: false
}
},
// 禁用提示框
tooltip:{
show:false,
},
itemStyle:{
// 預設顏色樣式
areaColor:'#0b1835',
borderWidth:2,
borderColor:'#244388',
opacity:1
},
data:[
{name: "山東",value: 541},
{name: "山東",value: 341},
{name: "西藏",value: 405},
{name: "浙江",value: 380},
{name: "廣東",value: 371},
{name: "貴州",value: 364},
{name: "四川",value: 287},
{name: "河南",value: 251},
{name: "上海",value: 218},
{name: "山西",value: 206}
]
}
});
// 增加視覺對映元件
mapOption.visualMap.push({
{
type:'piecewise',
// 不顯示元件
show:false,
// 最大值 MaxArr為data重抽出的value陣列
max:Math.max.apply(null,MaxArr),
// 僅對mapOption.series陣列內下標為index系列資料生效
seriesIndex:0,
bottom:20,
left:30,
textStyle:{
color:'#fff'
},
// 顏色值
inRange: {
color: ['#5c8eb1', '#0574ab','#055c9b']
}
}
})
複製程式碼
3. 建立散點系列動畫
設定選中省到其他省的遷徙效果,遷徙效果需要用三個系列組合,才能出現遷徙效果。
-
- 散點,在各個省會位置顯示散點動畫
-
- 實線,從當前城市指向目標城市帶箭頭的曲線。
-
- 特效線,從當前城市指向目標城市帶箭頭的曲線。
散點繪製需要座標,網上只找到了城市的座標,沒有省的,我自己把省會城市複製了一遍,然後改為省名稱,省坐與省會城市一致,程式碼如下:
// 省會與城市座標
var geoCoordMap = {
"海門":[121.15,31.89],
"鄂爾多斯":[109.781327,39.608266],
"招遠":[120.38,37.35],
"舟山":[122.207216,29.985295],
"齊齊哈爾":[123.97,47.33],
"鹽城":[120.13,33.38],
"赤峰":[118.87,42.28],
"青島":[120.33,36.07],
"乳山":[121.52,36.89],
"金昌":[102.188043,38.520089],
"泉州":[118.58,24.93],
"萊西":[120.53,36.86],
"日照":[119.46,35.42],
"膠南":[119.97,35.88],
"南通":[121.05,32.08],
"西藏":[91.11,29.97],
"拉薩":[91.11,29.97],
"雲浮":[112.02,22.93],
"梅州":[116.1,24.55],
"文登":[122.05,37.2],
"上海":[121.48,31.22],
"上海":[121.48,31.22],
"攀枝花":[101.718637,26.582347],
"威海":[122.1,37.5],
"承德":[117.93,40.97],
"廈門":[118.1,24.46],
"汕尾":[115.375279,22.786211],
"潮州":[116.63,23.68],
"丹東":[124.37,40.13],
"太倉":[121.1,31.45],
"曲靖":[103.79,25.51],
"煙臺":[121.39,37.52],
"福建":[119.3,26.08],
"福州":[119.3,26.08],
"瓦房店":[121.979603,39.627114],
"即墨":[120.45,36.38],
"撫順":[123.97,41.97],
"玉溪":[102.52,24.35],
"張家口":[114.87,40.82],
"陽泉":[113.57,37.85],
"萊州":[119.942327,37.177017],
"湖州":[120.1,30.86],
"汕頭":[116.69,23.39],
"崑山":[120.95,31.39],
"寧波":[121.56,29.86],
"湛江":[110.359377,21.270708],
"揭陽":[116.35,23.55],
"榮成":[122.41,37.16],
"連雲港":[119.16,34.59],
"葫蘆島":[120.836932,40.711052],
"常熟":[120.74,31.64],
"東莞":[113.75,23.04],
"河源":[114.68,23.73],
"淮安":[119.15,33.5],
"泰州":[119.9,32.49],
"南寧":[108.33,22.84],
"營口":[122.18,40.65],
"惠州":[114.4,23.09],
"江陰":[120.26,31.91],
"蓬萊":[120.75,37.8],
"韶關":[113.62,24.84],
"嘉峪關":[98.289152,39.77313],
"廣東":[113.23,23.16],
"廣州":[113.23,23.16],
"延安":[109.47,36.6],
"山西":[112.53,37.87],
"太原":[112.53,37.87],
"清遠":[113.01,23.7],
"中山":[113.38,22.52],
"雲南":[102.73,25.04],
"昆明":[102.73,25.04],
"壽光":[118.73,36.86],
"盤錦":[122.070714,41.119997],
"長治":[113.08,36.18],
"深圳":[114.07,22.62],
"珠海":[113.52,22.3],
"宿遷":[118.3,33.96],
"咸陽":[108.72,34.36],
"銅川":[109.11,35.09],
"平度":[119.97,36.77],
"佛山":[113.11,23.05],
"海南":[110.35,20.02],
"海口":[110.35,20.02],
"江門":[113.06,22.61],
"章丘":[117.53,36.72],
"肇慶":[112.44,23.05],
"大連":[121.62,38.92],
"臨汾":[111.5,36.08],
"吳江":[120.63,31.16],
"石嘴山":[106.39,39.04],
"遼寧":[123.38,41.8],
"瀋陽":[123.38,41.8],
"蘇州":[120.62,31.32],
"茂名":[110.88,21.68],
"嘉興":[120.76,30.77],
"吉林":[125.35,43.88],
"長春":[125.35,43.88],
"膠州":[120.03336,36.264622],
"寧夏":[106.27,38.47],
"銀川":[106.27,38.47],
"張家港":[120.555821,31.875428],
"三門峽":[111.19,34.76],
"錦州":[121.15,41.13],
"江西":[115.89,28.68],
"南昌":[115.89,28.68],
"柳州":[109.4,24.33],
"三亞":[109.511909,18.252847],
"自貢":[104.778442,29.33903],
"吉林":[126.57,43.87],
"陽江":[111.95,21.85],
"瀘州":[105.39,28.91],
"西寧":[101.74,36.56],
"青海":[101.74,36.56],
"宜賓":[104.56,29.77],
"內蒙古":[111.65,40.82],
"呼和浩特":[111.65,40.82],
"四川":[104.06,30.67],
"成都":[104.06,30.67],
"大同":[113.3,40.12],
"江蘇":[119.44,32.2],
"鎮江":[119.44,32.2],
"廣西":[110.28,25.29],
"桂林":[110.28,25.29],
"張家界":[110.479191,29.117096],
"宜興":[119.82,31.36],
"北海":[109.12,21.49],
"陝西":[108.95,34.27],
"西安":[108.95,34.27],
"金壇":[119.56,31.74],
"東營":[118.49,37.46],
"牡丹江":[129.58,44.6],
"遵義":[106.9,27.7],
"紹興":[120.58,30.01],
"揚州":[119.42,32.39],
"常州":[119.95,31.79],
"濰坊":[119.1,36.62],
"重慶":[106.54,29.59],
"重慶":[106.54,29.59],
"台州":[121.420757,28.656386],
"江蘇":[118.78,32.04],
"南京":[118.78,32.04],
"濱州":[118.03,37.36],
"貴州":[106.71,26.57],
"貴陽":[106.71,26.57],
"無錫":[120.29,31.59],
"本溪":[123.73,41.3],
"克拉瑪依":[84.77,45.59],
"渭南":[109.5,34.52],
"馬鞍山":[118.48,31.56],
"寶雞":[107.15,34.38],
"焦作":[113.21,35.24],
"句容":[119.16,31.95],
"北京":[116.46,39.92],
"北京":[116.46,39.92],
"徐州":[117.2,34.26],
"衡水":[115.72,37.72],
"包頭":[110,40.58],
"綿陽":[104.73,31.48],
"新疆":[87.68,43.77],
"烏魯木齊":[87.68,43.77],
"棗莊":[117.57,34.86],
"浙江":[120.19,30.26],
"杭州":[120.19,30.26],
"淄博":[118.05,36.78],
"鞍山":[122.85,41.12],
"溧陽":[119.48,31.43],
"庫爾勒":[86.06,41.68],
"安陽":[114.35,36.1],
"開封":[114.35,34.79],
"山東":[117,36.65],
"濟南":[117,36.65],
"德陽":[104.37,31.13],
"溫州":[120.65,28.01],
"九江":[115.97,29.71],
"邯鄲":[114.47,36.6],
"臨安":[119.72,30.23],
"甘肅":[103.73,36.03],
"蘭州":[103.73,36.03],
"滄州":[116.83,38.33],
"臨沂":[118.35,35.05],
"南充":[106.110698,30.837793],
"天津":[117.2,39.13],
"天津":[117.2,39.13],
"富陽":[119.95,30.07],
"泰安":[117.13,36.18],
"諸暨":[120.23,29.71],
"河南":[113.65,34.76],
"鄭州":[113.65,34.76],
"黑龍江":[126.63,45.75],
"哈爾濱":[126.63,45.75],
"聊城":[115.97,36.45],
"蕪湖":[118.38,31.33],
"唐山":[118.02,39.63],
"平頂山":[113.29,33.75],
"邢臺":[114.48,37.05],
"德州":[116.29,37.45],
"濟寧":[116.59,35.38],
"荊州":[112.239741,30.335165],
"宜昌":[111.3,30.7],
"義烏":[120.06,29.32],
"麗水":[119.92,28.45],
"洛陽":[112.44,34.7],
"秦皇島":[119.57,39.95],
"株洲":[113.16,27.83],
"河北":[114.48,38.03],
"石家莊":[114.48,38.03],
"萊蕪":[117.67,36.19],
"常德":[111.69,29.05],
"保定":[115.48,38.85],
"湘潭":[112.91,27.87],
"金華":[119.64,29.12],
"岳陽":[113.09,29.37],
"湖南":[113,28.21],
"長沙":[113,28.21],
"衢州":[118.88,28.97],
"廊坊":[116.7,39.53],
"菏澤":[115.480656,35.23375],
"安徽":[117.27,31.86],
"合肥":[117.27,31.86],
"武漢":[114.31,30.52],
"湖北":[114.31,30.52],
"大慶":[125.03,46.58]
};
複製程式碼
echart要求的散點系列要求的資料格式如下:
{
"name":"安徽",
"value":220,
"tooltip":"遷出人效:0.22臺\/人<br>總遷出量:220<br>總遷入量:149"
}
複製程式碼
需要省會名和value,使用symbolSize
回撥根據value設定散點大小,預設圖示科技感不強,用symbol
設定成自己做的png圖片,然後在label的formatter
方法設定一下要顯示的label欄位。
// 資料格式
var pan = [
{"name":"安徽","value":220,"tooltip":"遷出人效:0.22臺\/人<br>總遷出量:220<br>總遷入量:149"},
{"name":"山東","value":24,"tooltip":"超值車數量:12<br>非超值數量:12<br>總數量:24"},
{"name":"浙江","value":22,"tooltip":"超值車數量:17<br>非超值數量:5<br>總數量:22"},
{"name":"廣東","value":22,"tooltip":"超值車數量:14<br>非超值數量:8<br>總數量:22"},
{"name":"西藏","value":15,"tooltip":"超值車數量:14<br>非超值數量:1<br>總數量:15"},
{"name":"四川","value":14,"tooltip":"超值車數量:10<br>非超值數量:4<br>總數量:14"},
{"name":"河南","value":14,"tooltip":"超值車數量:10<br>非超值數量:4<br>總數量:14"},
{"name":"河北","value":9,"tooltip":"超值車數量:5<br>非超值數量:4<br>總數量:9"},
{"name":"江西","value":8,"tooltip":"超值車數量:5<br>非超值數量:3<br>總數量:8"},
{"name":"湖北","value":8,"tooltip":"超值車數量:7<br>非超值數量:1<br>總數量:8"},
{"name":"陝西","value":8,"tooltip":"超值車數量:5<br>非超值數量:3<br>總數量:8"}
];
// 新增系列資料
mapOption.series.push(
{
name: '圓盤',
type: 'effectScatter',
coordinateSystem: 'geo',
zlevel: 0,
// 散點動畫
rippleEffect: {
scale:3,
brushType: 'stroke',
},
// 散點圖示
symbol:'image://images/symbol1.png',
// 顯示文字
label: {
normal: {
show: true,
position: 'right',
color:'#fff',
fontSize:10,
// 會名稱 + value
formatter: function(e){
return e.name +':'+ e.data.value[2]
},
opacity:1
},
},
// 根據value控制散點大小
symbolSize: function (val) {
return val[2] / 25;
},
itemStyle: {
borderWidth:1,
opacity:1,
shadowColor: '#fff',
},
data: pan.map(function (dataItem) {
return {
name: dataItem.name,
value:geoCoordMap[dataItem.name].concat([dataItem.value]),
tooltip:dataItem.name + '<br>' +dataItem.tooltip
};
})
}
)
複製程式碼
4. 建立線條系列實線與特效線
一條為實線,一條帶動畫的特效線,疊加在一起,效果就出來了。
echarts要求的lines系列資料格式如下:
// linses
{
fromName: "安徽",
toName: "浙江",
coords: [
[117.27, 31.86], // 起點座標
[120.19, 30.26] // 末尾座標
]
}
複製程式碼
**這樣來看我們就需要當前省的座標和目標省座標,**我們之前已經準備好座標資料了,等於介面返回給我們當前省名稱和目標省名稱,我們自己再遍歷取一下座標就可以了,使用symbolSize
調整剪頭合適的大小。
畫線的時候顏色需要注意下,實線深色,動畫線淺色,這樣有對比,效果要稍微好一些。
我們要求得到的資料如下:
var linesData = [
[{"name":"安徽"},{"name":"浙江"}],
[{"name":"安徽"},{"name":"上海"],
[{"name":"安徽"},{"name":"西藏"],
[{"name":"安徽"},{"name":"四川"],
[{"name":"安徽"},{"name":"河南"],
[{"name":"安徽"},{"name":"山西"],
[{"name":"安徽"},{"name":"廣東"],
[{"name":"安徽"},{"name":"山東"],
[{"name":"安徽"},{"name":"貴州"]
]
複製程式碼
遍歷資料獲取座標,把資料塞進系列裡
// lines資料遍歷方法
var convertData = function (data) {
var res = [];
for (var i = 0; i < data.length; i++) {
var dataItem = data[i];
var fromCoord = geoCoordMap[dataItem[0].name];
var toCoord = geoCoordMap[dataItem[1].name];
if (fromCoord && toCoord) {
res.push({
fromName: dataItem[0].name,
toName: dataItem[1].name,
coords: [fromCoord, toCoord],
});
}
}
return res;
};
// 塞入資料
mapOption.series.push(
// step3 實體線
{
name: '實體線',
type: 'lines',
zlevel: 1,
symbol: ['none', 'arrow'],
symbolSize: 5,
lineStyle: {
opacity: 0.1,
normal: {
color: '#67035a',
width: 1,
curveness: 0.2
}
},
tooltip:{
show:false,
},
data: convertData(linesData)
},
// step4 發光線
{
name: '發光',
type: 'lines',
zlevel: 2,
// 特效配置
effect: {
show: true,
period: 7,
trailLength: 0.7,
color: '#ff69ec',
symbolSize: 3
},
tooltip:{
show:false,
},
lineStyle: {
normal: {
color: '#fbff82',
width: 0,
curveness: 0.2
}
},
data: convertData(linesData)
}
)
複製程式碼
效果已經出來了。
5. 當前城市到目標省城,點選目標省彈出柱狀圖
城市到省就更簡單了,把省的名稱換成城市就好了,不再贅述。
簡單說一下點選目標省出現當前省下所有城市的柱狀圖的思路。
給echart物件新增點選事件,只有echart物件可以新增點選事件,系列和元件都家布行,需要通過params
判斷點選的型別,如果是點選的散點,就展示div,建立一個chart就好了。
myChart.on('click', function (params) {
if(params.componentSubType == "effectScatter"){
$('.tootip,.mark').show();
let option = {
// some data
};
let Chart = echarts.init(document.getElementById('tootip'));
Chart.setOption(option);
}
});
$('.clsBtn').click(function(){
$('.tootip,.mark').hide();
});
複製程式碼
基本就實現了,下邊是一些echart配置的關聯項,翻文件或者搜尋翻出來的,記錄一下,熟悉的直接略過就可以了。
視覺對映元件的縱軸配置 dimension
在做左側條形圖的時候碰到一個問題,設定視覺對映元件後不生效,和預期不一樣,見下圖(左側實際,右側預期):
原因是對映元件的資料維度指向錯誤,調整一下dimension
指向就好了。
視覺對映元件僅對某一組系列資料生效 seriesIndex
在做地圖的時候,希望資料對映元件只對地圖系列生效,對散點不生效,以為是用id來繫結,後來翻了一下文件,用seriesIndex
指向mapOption.series
的下標,就只對當前下標生效了。
系列元件tooltip的顯示與隱藏
需求是隻有經過散點圖的時候才顯示tooltip元件,所以需要給tooltip.trigger
屬性為item
,然後給不需要展示的系列增加tooltip.show
屬性為false
。
總結
基本上就這些了,按照掘金的原則:
很多技術內容的講解,尤其是一些新的技術,最先要講明白背後的概念,讓讀者對這個內容有了一個概括性的瞭解,然後再深入背後的細節完成實體的內容。
如果大家覺得哪裡講解的不是很清楚,希望提出來,我修改為可讀性更高的筆記,筆記也需要迭代?,共同交流學習。