天天看點

百度地圖、ECharts整合HT for Web網絡拓撲圖應用 - RTdo

百度地圖、ECharts整合HT for Web網絡拓撲圖應用

2015-04-16 00:07 

RTdo 

閱讀(493) 

評論(0) 

編輯 

收藏 

舉報

直擊現場

百度地圖、ECharts整合HT for Web網絡拓撲圖應用

發表于3周前(2015-03-23 01:32)   閱讀(1320) | 評論(5) 78人收藏此文章, 我要收藏

贊8

慕課網,程式員升職加薪神器,點選免費學習

摘要 前一篇談及到了ECharts整合HT for Web的網絡拓撲圖應用,後來在ECharts的Demo中看到了有關空氣品質的相關報表應用,就想将百度地圖、ECharts和HT for Web三者結合起來也做一個類似空氣品質報告的報表+拓撲圖應用。

hightopo HTforWeb 網絡拓撲圖 ECharts 百度地圖

前一篇談及到了ECharts整合HT for Web的網絡拓撲圖應用,後來在ECharts的Demo中看到了有關空氣品質的相關報表應用,就想将百度地圖、ECharts和HT for Web三者結合起來也做一個類似空氣品質報告的報表+拓撲圖應用,于是有了下面的Demo:

百度地圖、ECharts整合HT for Web網絡拓撲圖應用 - RTdo

在這個Demo中,将GraphView拓撲圖元件添加到百度地圖元件中,覆寫在百度地圖元件之上,并且在百度地圖元件上和GraphView拓撲圖元件上分别添加事件監聽,互相同步經緯度和螢幕位置資訊,進而來控制拓撲圖上的元件位置固定在地圖上,并在節點和節點之間的連線上加上了流動屬性。右下角的圖示框是采用HT for Web的Panel面闆元件結合ECharts圖表元件完成的。

接下來我們來看看具體的代碼實作:

1. 百度地圖是如何與HT for Web元件結合的;

?

1

2

3

4

5

map = 

new

BMap.Map(

"map"

);

var

view = graphView.getView();

view.className = 

\'graphView\'

;

var

mapDiv = document.getElementById(

\'map\'

);

mapDiv.firstChild.firstChild.appendChild(view);

首先需要在body中存在id為map的div,再通過百度地圖的api來建立一個map地圖對象,然後建立GraphView拓撲圖元件,并擷取GraphView元件中的view,最後将view添加到id為map的div的第二代孩子節點中。這時候問題就來了,為什麼要将view添加到map的第二代孩子節點中呢,當你審查元素時你會發現這個div是百度地圖的遮罩層,将view添加到上面,會使view會是在地圖的頂層可見,不會被地圖所遮擋。

2. 百度地圖和GraphView的事件監聽;

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

map.addEventListener(

\'moveend\'

function

(e){

resetPosition();

});

map.addEventListener(

\'dragend\'

function

(e){

resetPosition();

});                                

map.addEventListener(

\'zoomend\'

function

(e){

resetPosition();

});

graphView.handleScroll = 

function

(){};

graphView.handlePinch = 

function

(){};

function

resetPosition(e){

graphView.tx(0);

graphView.ty(0);

dataModel.each(

function

(data){

var

lonLat, position;

if

(data 

instanceof

ht.HtmlNode){

if

(data.getId() != 

\'chartTotal\'

) {

position = data.getHost().getPosition();

position = {x: position.x + 168, y: position.y + 158};

data.setPosition(position.x, position.y);

}

else

if

(data 

instanceof

ht.Node){

lonLat = data.lonLat;

position = map.pointToPixel(lonLat);

data.setPosition(position.x,position.y);

}

});

}

首先監聽map的三個事件:moveend、 dragend、 zoomend,這三個事件做了同一件事--修改DataModel中所有data的position屬性,讓其在螢幕上的坐标與地圖同步,然後将GraphView的Scroll和Pinch兩個事件的執行函數設定為空函數,就是當監聽到Scroll或者Pinch事件時不做任何的處理,将這兩個事件交給map來處理。

在resetPosition函數中,做的事情很簡單:周遊DataModel中的data,根據它們各自在地圖上的經緯度來換算成螢幕坐标,并将坐标設定到相應的data中,進而達到GraphView中的節點能夠固定在地圖上的效果。

百度地圖、ECharts整合HT for Web網絡拓撲圖應用 - RTdo
百度地圖、ECharts整合HT for Web網絡拓撲圖應用 - RTdo

3. 建立右下角的圖表元件:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

ht.Chart = 

function

(option){

var

self = 

this

,

view = self._view = document.createElement(

\'div\'

);

view.style.position = 

\'absolute\'

;

view.style.setProperty(

\'box-sizing\'

\'border-box\'

null

);

self._option = option;

self._chart = echarts.init(self.getView());

if

(option)

self._chart.setOption(option);

self._FIRST = 

true

;

};

ht.Default.def(

\'ht.Chart\'

, Object, {

ms_v: 1,

ms_fire: 1,

ms_ac: [

\'chart\'

\'option\'

\'isFirst\'

\'view\'

],

validateImpl: 

function

(){

var

self = 

this

,

chart = self._chart;

chart.resize();

if

(self._FIRST){

self._FIRST = 

false

;

chart.restore();

}

},

setSize: 

function

(w, h){

var

view = 

this

._view;

view.style.width = w + 

\'px\'

;

view.style.height = h + 

\'px\'

;

}

});

function

createPanel(title, width, height){

chart = 

new

ht.Chart(option);

var

c = chart.getChart();

c.on(echarts.config.EVENT.LEGEND_SELECTED, legendSelectedFun);

var

chartPanel = 

new

ht.widget.Panel({

title: title,

restoreToolTip: 

"Overview"

,

width: width,

contentHeight: height,

narrowWhenCollapse: 

true

,

content: chart,

expanded: 

true

});

chartPanel.setPositionRelativeTo(

"rightBottom"

);

chartPanel.setPosition(0, 0);

chartPanel.getView().style.margin = 

\'10px\'

;

document.body.appendChild(chartPanel.getView());

}

首先定義了ht.Chart類,并實作了validateImpl方法,方法中處理的邏輯也很簡單:在每次方法執行的時候調用圖表的reset方法重新設定圖示的展示大小,如果該方法是第一次執行的話,就調用圖表的restore方法将圖表還原為最原始的狀态。會有這樣的設計是因為ht.Chart類中的view是動态建立的,在沒有添加到dom之前将一直存在于記憶體中,在記憶體中因為并沒有浏覽器寬高資訊,是以div的實際寬高均為0,是以chart将option内容繪制在寬高為0的div中,即使你resize了chart,如果沒用重置圖表狀态的話,圖表狀态将無法在圖表上正常顯示。

接下來就是建立panel圖表元件了,這是HT for Web的Panel元件的基本用法,其中content屬性的值可以是HT for Web的任何元件或div元素,如果是HT fro Web元件的話,該元件必須實作了validateImpl方法,因為在panel的屬性變化後将會調用content對應元件的validateImpl方法來重新布局元件内容。

4. ECharts和GraphView拓撲圖元件的互動:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

legendSelectedFun = 

function

(param) {

if

(chart._legendSelect){

delete

chart._legendSelect;

return

;

}

console.info(param);

var

id = nodeMap[param.target],

dm = graphView.dm(),

data = dm.getDataById(id),

sm = dm.sm(),

selection = sm.getSelection();

if

(param.selected[param.target]) {

sm.appendSelection([data]);

if

(selectionData.indexOf(param.target) < 0){

selectionData.push(param.target);

}

}

else

{

sm.removeSelection([data]);

var

index = selectionData.indexOf(param.target);

if

(index >= 0){

selectionData.splice(index, 1);

}

}

sm.setSelection(selection.toArray());

};

graphView.mi(

function

(e){

console.info(e.kind, e.data);

var

c = chart.getChart(),

legend = c.component.legend,

selectedMap = legend.getSelectedMap();

if

(e.kind === 

\'endRectSelect\'

){

chart._legendSelect = 

true

;

for

(

var

name 

in

notes){

legend.setSelected(name, 

false

);

}

notes = {};

graphView.dm().sm().each(

function

(data){

var

note = data.s(

\'note\'

);

if

(note)

notes[note] = 1;

});

for

(

var

name 

in

notes){

legend.setSelected(name, 

true

);

}

else

if

(e.kind === 

\'clickData\'

){

chart._legendSelect = 

true

;

var

data = e.data;

if

(data 

instanceof

ht.Node){

var

note = data.s(

\'note\'

);

if

(note){

var

selected = legend.isSelected(note);

if

(selected){

graphView.dm().sm().removeSelection([data]);

}

legend.setSelected(note, !selected);

}

}

}

});

legendSelectedFun函數是EChart圖表的legend插件選中事件監聽,其中處理的邏輯是:當legend插件中的某個節點被選中了,也選中在GraphView拓撲圖中對應的節點,當取消選中是,也取消選中GraphView拓撲圖中對應的節點。

在GraphView中添加互動監聽,如果在GraphView中做了框選操作,在框選結束後,将原本legend插件上被選中的節點取消選中,然後再擷取被選中節點,并在legend插件上選中對應節點;當GraphView上的節點被選中,則根據legend插件中對應節點選中情況來決定legend插件中的節點和graphView上的節點是否選中。

在GraphView互動中,我往chart執行個體中添加了_legendSelect變量,該變量的設定是為了阻止在GraphView互動中修改legend插件的節點屬性後回調legendSelectedFun回調函數做修改GraphView中節點屬性操作。

百度地圖、ECharts整合HT for Web網絡拓撲圖應用 - RTdo
今天就寫到這吧,希望這篇文章能夠幫到那些有地圖、拓撲圖、圖表相結合需求的朋友,在設計上可能想法還不夠成熟,希望大家不吝賜教。
  • 分類 App

    , Javascript