需求場景
用品牌持機量和品牌凈流入量兩個維度來幫助運營分析所選品牌的競爭能力健康度舟舒。
最終實現效果如下圖所示:
- 競爭能力健康度:判斷品牌具備正向競爭能力付材,還是處于危險狀態(tài)肛循。
- 維度呈現
橫坐標:品牌持機量,中心點為取所有11個品牌持機量的中位數(注:一期為取“平均數”)峭咒;
縱坐標:品牌凈流入量=本月流入量-本月流出量烹卒,中心點為0狱掂,即向上為凈流入量增加穆刻,向下為凈流入量減少;
四個象限:分別表示“上升品牌”消约、“潛力品牌”肠鲫、“高危品牌”、“下滑品牌”或粮。
品牌健康度分析最終效果圖
需求拆解(從實現的角度)
- 確定使用的基本圖表類型及數據格式:以散點圖為基礎导饲;每個散點的數據對應一個(品牌)名稱和(坐標)值。
- 四象限劃分:確定橫氯材、縱軸的分割臨界點渣锦。
- 確定散點的樣式、交互效果:每個散點大小一致氢哮;處于不同象限的散點使用指定不同顏色區(qū)分(此時注意考慮散點處于臨界點的情況)袋毙;散點上顯示名稱,hover時顯示對應維度值信息冗尤。
- 使用圖例展示對應象限表示的含義听盖。
問題及解決方案
- 后續(xù)示例基于以下模擬數據做調整:
let data = [ { name: '三星', value: [10.0, -6.04], }, { name: '一加', value: [8.0, 1.95], }, { name: '華為', value: [12.0, 7.58], }, { name: '蘋果', value: [15.0, -7.81], } ]
問題一:四象限的劃分,用ECharts原生提供的xAxis裂七、yAxis屬性無法做到皆看。
因為x軸、y軸的位置是不可按具體值靈活控制的碍讯。
例如y軸在左側時,如果x軸上的最小值<=0扯躺,則y軸位于x=0上捉兴;否則按xAxis.min的設定規(guī)則(即坐標軸刻度最小值,不設置時會自動計算最小值保證坐標軸刻度的均勻分布)計算录语。
幾種情況的效果示例如下圖所示:
x軸上的最小值<=0時
x軸上的值均大于0倍啥,且無設置xAxis.min時x軸上的值均大于0,且設置了xAxis.min時
- 思路:利用其它屬性來模擬軸澎埠?
- 方案:由于markLine屬性的位置完全可控虽缕,可使用markLine模擬劃分象限的軸。參考文檔series-scatter.markLine.data中笛卡爾坐標系的相關配置說明蒲稳。
- 相關代碼片段:
const median = 11.0 // 實際值由后臺計算給出氮趋,為固定值 /* 隱藏默認的x軸和y軸 */ xAxis: { show: false }, yAxis: { show: false }, /* 注:以下配置項位于series內 */ label: { show: true, formatter: (param) => param.name || '未命名' }, // 顯示名稱 symbolSize: 50, // 散點大小 type: 'scatter', data, markLine: { lineStyle: { normal: { color: '#555555', type: 'solid' } }, data: [ { xAxis: median, // 注釋為一期實現 // type: 'average', // valueDim: 'x', label: { normal: { show: true, formatter: '品牌凈流入量', }, } }, { yAxis: 0, label: { normal: { show: true, formatter: '品牌持機量', } } }, ] },
-
腦洞成果:
問題二:左側視野出現的大片空白伍派,在本圖中無意義。
- 思路:將y軸偏移到所有數據的橫軸最小值剩胁。
- 方案:利用問題一總結出來的規(guī)則即可解決诉植。
- 相關代碼片段:
xAxis: { min: 'dataMin' // 取數據在該軸上的最小值作為最小刻度 },
-
腦洞成果:
問題三:處于不同象限的散點使用指定不同顏色區(qū)分
- 思路:通過對每個點表示的坐標值分別與臨界值比較,從而確定所在區(qū)間昵观,設置相應的顏色值晾腔。
- 方案:與產品經理確認,處于臨界值的點按偏“右啊犬、上”規(guī)則處理灼擂。
- 相關代碼片段:
const xSeparate = median const ySeparate = 0 const getAreaPointColor = (value = [0, 0]) => { const [x, y] = value switch ([x, y]) { case (x >= xSeparate && y >= ySeparate): return '#3583FF' case (x < xSeparate && y >= ySeparate): return '#33BB7B' case (x < xSeparate && y < ySeparate): return '#FB7962' case (x >= xSeparate && y < ySeparate): return '#8560C5' } } data = data.map(d => ({ ...d, itemStyle: { color: getAreaPointColor(d.value) } }))
-
腦洞成果:
問題四:使用不同顏色圖例展示對應不同象限的含義的實現方式及其限制。
首先觉至,查看圖例legend的配置規(guī)則:“圖例組件展現了不同系列的標記(symbol)剔应,顏色和名字”,這說明了展示多個圖例需要依賴于有多組series康谆。
- 基于一期需求(橫坐標以所選品牌持機量的平均數來分割)领斥,參考series-scatter.markLine.data.0.type可知,取平均數是基于設置了markLine的該組數據計算的沃暗,此時數據只能放在一組series中才有意義月洛,否則橫坐標的分割線會永遠處于加了平均數配置的那組數據的平均值上(可看以下反例幫助理解),因此圖例的展示就不能用ECharts提供的legend屬性實現了孽锥。
反例1:series的每項都加上平均數配置時
出現多條“縱軸”- 反例2:只給其中一個子項加上平均數配置時
只有一條軸嚼黔,但效果顯然不是我們想要的
- 思路:在不需要圖例的任何交互的情況下,可簡單地通過將圖例作為渲染的Canvas以外的dom元素來實現惜辑;否則需要考慮更復雜的實現(衡量實現成本)唬涧。
- 方案:直接用html+css實現。
- 基于第二版需求(橫坐標以所選固定的11個品牌持機量的中位數來分割)
- 思路:由于markLine.xAxis取固定值盛撑,因此根據象限拆分多組series變得可行了碎节。
- 方案:實現一個根據象限拆分多組series的函數,圖例信息從series獲取即可抵卫。
問題五:將散點整體縮小后狮荔,由于markLine層級過高,導致散點文字被遮擋介粘。
- 思路:將散點元素的層級調高或調低markLine的層級殖氏。
- 方案:markLine層級暫無法調整,使用series-scatter.z將散點層級適當調高即可姻采。
- 相關代碼片段:
label: { show: true, fontSize: 8, formatter: (params) => params.name }, symbolSize: 28, z: 9, // 將散點層級調高至不被markLine遮擋
-
腦洞成果:
效果樣例
可直接粘貼在https://echarts.apache.org/examples/zh/editor.html?c=line-simple
查看效果雅采。
- 樣例1:簡版配置(省略legend、tooltip),可作為研究基礎
const median = 11.0
option = {
title: {
text: '品牌健康度分析',
},
xAxis: {
min: 'dataMin',
show: false
},
yAxis: {
show: false
},
series: [{
label: {
show: true,
formatter: (param) => param.name || '未命名'
},
symbolSize: 50,
z: 9,
data: [
{
name: '三星',
value: [10.0, -6.04],
itemStyle: {
color: '#FB7962'
}
},
{
name: '一加',
value: [8.0, 1.95],
itemStyle: {
color: '#33BB7B'
}
},
{
name: '華為',
value: [12.0, 7.58],
itemStyle: {
color: '#3583FF'
}
},
{
name: '蘋果',
value: [15.0, -7.81],
itemStyle: {
color: '#8560C5'
}
},
// [9.0, 8.81],
// [11.0, 8.33],
// [14.0, 9.96],
// [6.0, 7.24],
// [4.0, -4.26],
// [12.0, 10.84],
// [7.0, 4.82],
// [5.0, 5.68]
],
type: 'scatter',
markLine: {
lineStyle: {
normal: {
color: '#555555',
type: 'solid'
}
},
data: [
{
xAxis: median,
label: {
normal: {
show: true,
formatter: '品牌凈流入量',
},
}
},
{
yAxis: 0,
label: {
normal: {
show: true,
formatter: '品牌持機量',
}
}
},
]
},
}]
}
- 樣例2:最終版
// 思路已在本文提供婚瓜,具體業(yè)務代碼不公開