Chinaunix首页 | 论坛 | 博客
  • 博客访问: 938488
  • 博文数量: 110
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1997
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-15 22:39
个人简介

HT for Web 3D. HT for modern web and mobile app development. www.hightopo.com

文章分类

全部博文(110)

文章存档

2020年(1)

2018年(28)

2017年(21)

2016年(10)

2015年(28)

2014年(19)

2013年(3)

我的朋友

分类: HTML5

2015-03-23 02:22:20

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


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

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

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

点击(此处)折叠或打开

  1. map = new BMap.Map("map");
  2. var view = graphView.getView();
  3. view.className = 'graphView';
  4. var mapDiv = document.getElementById('map');
  5. mapDiv.firstChild.firstChild.appendChild(view);

首先需要在body中存在idmapdiv,再通过百度地图的api来创建一个map地图对象,然后创建拓扑图组件,并获取GraphView组件中的view,最后将view添加到idmapdiv的第二代孩子节点中。这时候问题就来了,为什么要将view添加到map的第二代孩子节点中呢,当你审查元素时你会发现这个div是百度地图的遮罩层,将view添加到上面,会使view会是在地图的顶层可见,不会被地图所遮挡。

2.百度地图和GraphView的事件监听;

点击(此处)折叠或打开

  1. map.addEventListener('moveend', function(e){
  2.    resetPosition();
  3. });
  4. map.addEventListener('dragend', function(e){
  5.    resetPosition();
  6. });
  7. map.addEventListener('zoomend', function(e){
  8.     resetPosition();
  9. });

  10. graphView.handleScroll = function(){};
  11. graphView.handlePinch = function(){};

  12. function resetPosition(e){
  13.     graphView.tx(0);
  14.     graphView.ty(0);
  15.     dataModel.each(function(data){
  16.         var lonLat, position;
  17.         if(data instanceof ht.HtmlNode){
  18.             if(data.getId() != 'chartTotal') {
  19.                 position = data.getHost().getPosition();
  20.                 position = {x: position.x + 168, y: position.y + 158};
  21.                 data.setPosition(position.x, position.y);
  22.             }
  23.         } else if(data instanceof ht.Node){
  24.             lonLat = data.lonLat;
  25.             position = map.pointToPixel(lonLat);
  26.             data.setPosition(position.x,position.y);
  27.         }
  28.     });
  29. }

首先监听map的三个事件:moveend dragend zoomend,这三个事件做了同一件事--修改DataModel中所有dataposition属性,让其在屏幕上的坐标与地图同步,然后将GraphViewScrollPinch两个事件的执行函数设置为空函数,就是当监听到Scroll或者Pinch事件时不做任何的处理,将这两个事件交给map来处理。

在resetPosition函数中,做的事情很简单:遍历DataModel中的data,根据它们各自在地图上的经纬度来换算成屏幕坐标,并将坐标设置到相应的data中,从而达到中的节点能够固定在地图上的效果。


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

点击(此处)折叠或打开
  1. ht.Chart = function(option){
  2.     var self = this,
  3.             view = self._view = document.createElement('div');
  4.     view.style.position = 'absolute';
  5.     view.style.setProperty('box-sizing', 'border-box', null);
  6.     self._option = option;
  7.     self._chart = echarts.init(self.getView());
  8.     if(option)
  9.         self._chart.setOption(option);
  10.     self._FIRST = true;
  11. };
  12. ht.Default.def('ht.Chart', Object, {
  13.     ms_v: 1,
  14.     ms_fire: 1,
  15.     ms_ac: ['chart', 'option', 'isFirst', 'view'],
  16.     validateImpl: function(){
  17.         var self = this,
  18.                 chart = self._chart;
  19.         chart.resize();
  20.         if(self._FIRST){
  21.             self._FIRST = false;
  22.             chart.restore();
  23.         }
  24.     },
  25.     setSize: function(w, h){
  26.         var view = this._view;
  27.         view.style.width = w + 'px';
  28.         view.style.height = h + 'px';
  29.     }
  30. });

  31. function createPanel(title, width, height){
  32.     chart = new ht.Chart(option);
  33.     var c = chart.getChart();
  34.     c.on(echarts.config.EVENT.LEGEND_SELECTED, legendSelectedFun);
  35.     var chartPanel = new ht.widget.Panel({
  36.         title: title,
  37.         restoreToolTip: "Overview",
  38.         width: width,
  39.         contentHeight: height,
  40.         narrowWhenCollapse: true,
  41.         content: chart,
  42.         expanded: true
  43.     });
  44.     chartPanel.setPositionRelativeTo("rightBottom");
  45.     chartPanel.setPosition(0, 0);
  46.     chartPanel.getView().style.margin = '10px';

  47.     document.body.appendChild(chartPanel.getView());
  48. }

首先定义了ht.Chart类,并实现了validateImpl方法,方法中处理的逻辑也很简单:在每次方法执行的时候调用图表的reset方法重新设定图标的展示大小,如果该方法是第一次执行的话,就调用图表的restore方法将图表还原为最原始的状态。会有这样的设计是因为ht.Chart类中的view是动态创建的,在没有添加到dom之前将一直存在于内存中,在内存中因为并没有浏览器宽高信息,所以div的实际宽高均为0,因此chart将option内容绘制在宽高为0的div中,即使你resize了chart,如果没用重置图表状态的话,图表状态将无法在图表上正常显示。

接下来就是创建panel图表组件了,这是Panel组件的基本用法,其中content属性的值可以是HT for Web的任何组件或div元素,如果是HT fro Web组件的话,该组件必须实现了validateImpl方法,因为在panel的属性变化后将会调用content对应组件的validateImpl方法来重新布局组件内容。

 

4.ECharts的交互:

点击(此处)折叠或打开

  1. legendSelectedFun = function(param) {
  2.     if(chart._legendSelect){
  3.         delete chart._legendSelect;
  4.         return;
  5.     }
  6.     console.info(param);
  7.     var id = nodeMap[param.target],
  8.             dm = graphView.dm(),
  9.             data = dm.getDataById(id),
  10.             sm = dm.sm(),
  11.             selection = sm.getSelection();

  12.     if(param.selected[param.target]) {
  13.         sm.appendSelection([data]);
  14.         if(selectionData.indexOf(param.target) < 0){
  15.             selectionData.push(param.target);
  16.         }
  17.     }else {
  18.         sm.removeSelection([data]);
  19.         var index = selectionData.indexOf(param.target);
  20.         if(index >= 0){
  21.             selectionData.splice(index, 1);
  22.         }
  23.     }
  24.     sm.setSelection(selection.toArray());
  25. };

  26. graphView.mi(function(e){
  27.     console.info(e.kind, e.data);
  28.     var c = chart.getChart(),
  29.             legend = c.component.legend,
  30.             selectedMap = legend.getSelectedMap();

  31.     if(e.kind === 'endRectSelect'){
  32.         chart._legendSelect = true;
  33.         for(var name in notes){
  34.             legend.setSelected(name, false);
  35.         }
  36.         notes = {};
  37.         graphView.dm().sm().each(function(data){
  38.             var note = data.s('note');
  39.             if(note)
  40.                 notes[note] = 1;
  41.         });
  42.         for(var name in notes){
  43.             legend.setSelected(name, true);
  44.         }
  45.     } else if(e.kind === 'clickData'){
  46.         chart._legendSelect = true;
  47.         var data = e.data;
  48.         if(data instanceof ht.Node){
  49.             var note = data.s('note');

  50.             if(note){
  51.                 var selected = legend.isSelected(note);
  52.                 if(selected){
  53.                     graphView.dm().sm().removeSelection([data]);
  54.                 }
  55.                 legend.setSelected(note, !selected);
  56.             }
  57.         }
  58.     }
  59. });

legendSelectedFun函数是EChart图表的legend插件选中事件监听,其中处理的逻辑是:当legend插件中的某个节点被选中了,也选中在拓扑图中对应的节点,当取消选中是,也取消选中GraphView拓扑图中对应的节点。

在GraphView中添加交互监听,如果在GraphView中做了框选操作,在框选结束后,将原本legend插件上被选中的节点取消选中,然后再获取被选中节点,并在legend插件上选中对应节点;当GraphView上的节点被选中,则根据legend插件中对应节点选中情况来决定legend插件中的节点和graphView上的节点是否选中。

GraphView交互中,我往chart实例中添加了_legendSelect变量,该变量的设定是为了阻止在GraphView交互中修改legend插件的节点属性后回调legendSelectedFun回调函数做修改GraphView中节点属性操作。


今天就写到这吧,希望这篇文章能够帮到那些有地图、、图表相结合需求的朋友,在设计上可能想法还不够成熟,希望大家不吝赐教。
阅读(3224) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~