转载

百度地图、ECharts整合HT for Web网络拓扑图应用

前一篇谈及到了 ECharts 整合 HT for Web 的 网络拓扑图 应用,后来在 ECharts 的 Demo 中看到了有关空气质量的相关报表应用,就想将百度地图、 ECharts 和 HT for Web 三者结合起来也做一个类似空气质量报告的报表 + 拓扑图应用,于是有了下面的 Demo :

百度地图、ECharts整合HT for Web网络拓扑图应用

在这个 Demo 中,将 GraphView 拓扑图组件添加到百度地图组件中,覆盖在百度地图组件之上,并且在百度地图组件上和 GraphView 拓扑图组件上分别添加事件监听,相互同步经纬度和屏幕位置信息,从而来控制拓扑图上的组件位置固定在地图上,并在节点和节点之间的连线上加上了流动属性。右下角的图标框是采用 HT for Web 的 Panel 面板组件结合 ECharts 图表组件完成的。

接下来我们来看看具体的代码实现:

1 . 百度地图是如何与 HT for Web 组件结合的;

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 的事件监听;

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网络拓扑图应用

百度地图、ECharts整合HT for Web网络拓扑图应用

3 . 创建右下角的图表组件:

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 拓扑图组件 的交互:

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网络拓扑图应用

今天就写到这吧,希望这篇文章能够帮到那些有地图、 拓扑图 、图表相结合需求的朋友,在设计上可能想法还不够成熟,希望大家不吝赐教。

正文到此结束
Loading...