转载

百度地图、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...