文档章节

HT for Web整合OpenLayers实现GIS地图应用

xhload3d
 xhload3d
发布于 2014/12/02 02:52
字数 1546
阅读 8471
收藏 32

HT for Web作为逻辑拓扑图形组件自身没有GIS功能,但可以与各种GIS引擎即其客户端组件进行融合,各取所长实现逻辑拓扑和物理拓扑的无缝融合,本章将具体介绍HT for Web与开发免费的OpenLayers地图结合应用的关键技术点,该文介绍的结合的原理,其实还可推广到与ArcGIS、百度地图以及GoogleMap等众多GIS地图引擎融合的解决方案。

Screen Shot 2014-12-02 at 1.15.33 AM

以上抓图为本文介绍的例子最终运行效果,接下来我们一步步来实现,首选显示地图信息需要有城市经纬度数据,搜索了下感谢此篇博客提供的数据。这么大量的数据我采用的是《HT图形组件设计之道(四)》中介绍的getRawText函数方式,有了数据之后剩下就是呈现的问题了,我们需要将HT的GraphView组件与OpenLayers的map地图组件叠加在一起,也就是OpenLayers的tile地图图片在下方,GraphView的组件在上方,由于GraphView默认是透明的,因此非图元部分用户可穿透看到地图内容。找到合适的组件插入位置是头疼的事情,ArcGIS、百度地图包括GoogleMap几乎每个不同的GIS组件都需要尝试一番才能找到合适的插入位置,其他GIS引擎组件的整合以后章节再介绍,本文我们关注的OpenLayers的插入方式为map.viewPortDiv.appendChild(graphView.getView())。

HT和OpenLayers组件叠加在一起之后,剩下就是拓扑里面图元的摆放位置与经纬度结合的问题,常规网络拓扑图中存储在ht.Node图元的position是逻辑位置,和经纬度没有任何关系,因此在GIS应用中我们需要根据图元的经纬度信息换算出position的屏幕逻辑坐标信息,如果你知道投影算法也可以自己提供函数处理,但所有GIS组件都提供了类似的API函数供调用,当然这部分也没有标准化,不同的GIS组件需要调用的API都有差异,但基本原理是一致的,对于OpenLayers我们通过map.getPixelFromLonLat(data.lonLat)可以将经纬度信息转换成屏幕像素逻辑坐标,也就是ht.Node需要的position坐标信息。

细心的同学会想到转换是双向的,有可能用户需要拖动图元节点改变其经纬度信息,这时候我们就需要另外一个方向函数,即根据屏幕逻辑坐标转换成当前坐标对应的经纬度,在OpenLayers中我们通过map.getLonLatFromPixel(new OpenLayers.Pixel(x, y));可以搞定。

显示搞定后剩下就是交互的问题了,HT自己有套交互体系,OpenLayers也需要地图漫游和缩放的交互,两者如何结合呢?如果能保留住两者的功能那就最好了,答案时肯定的,我们只需要添加mousedown或touchstart事件监听,如果graphView.getDataAt(e)选中了图元我们就通过e.stopPropagation();停止事件的传播,这样map地图就不会响应,这时候HT接管了交互,如果没有选中图元则map接管地图操作的交互。

以上交互设计似乎很完美了,结果运行时发现了几处折腾了我很久才找到解决方案的坑:

  1. 设置map.events.fallThrough = true;否则map不会将事件透传到HT的GraphView组件

  2. graphView.getView().style.zIndex = 999; 需要指定一定的zIndex否则会被遮挡

  3. graphView.getView().className = ‘olScrollable’; 否则滚轮不会响应地图缩放

  4. 设置ht.Default.baseZIndex: 1000 否则ToolTip会被遮挡

为了让这个例子用户体验更友好,我还用心折腾了些技术点供参考:

  1. 采用开源免费的http://llllll.li/randomColor/随机颜色类库,该类库还有很多非常棒的颜色获取函数,我只是简单的为每个省份显示不一样的颜色

  2. 重载了isVisible、isNoteVisible和isLabelVisible仅在缩放达到一定级别才显示更详细的内容,否则缩小时所有城市信息都显示完全无法查看,多少也能提高显示性能

以下为最终效果的抓图、视频和源代码:http://v.youku.com/v_show/id_XODM5Njk0NTU2.html

Screen Shot 2014-12-02 at 1.15.33 AM Screen Shot 2014-12-02 at 1.16.18 AM Screen Shot 2014-12-02 at 1.16.47 AM Screen Shot 2014-12-02 at 1.17.30 AM

function init(){                
	graphView = new ht.graph.GraphView();
	var view = graphView.getView();                 

	map = new OpenLayers.Map("map");
	var ol_wms = new OpenLayers.Layer.WMS(
		"OpenLayers WMS",
		"http://vmap0.tiles.osgeo.org/wms/vmap0",
		{layers: "basic"}
	);
	map.addLayers([ol_wms]);
	map.addControl(new OpenLayers.Control.LayerSwitcher());
	map.zoomToMaxExtent();                
	map.events.fallThrough = true;

	map.zoomToProxy = map.zoomTo;
	map.zoomTo =  function (zoom,xy){
		view.style.opacity = 0;
		map.zoomToProxy(zoom, xy);    
		console.log(zoom);
	};                

	map.events.register("movestart", this, function() {
	});
	map.events.register("move", this, function() {                   
	});
	map.events.register("moveend", this, function() {
		view.style.opacity = 1;
		reset();
	});                

	graphView.getView().className = 'olScrollable';
	graphView.setScrollBarVisible(false);
	graphView.setAutoScrollZone(-1);
	graphView.handleScroll = function(){};
	graphView.handlePinch = function(){};     
	graphView.mi(function(e){
		if(e.kind === 'endMove'){
			graphView.sm().each(function(data){
				if(data instanceof ht.Node){
				   var position = data.getPosition(),
					   x = position.x + graphView.tx(),
					   y = position.y + graphView.ty();  

				   data.lonLat = map.getLonLatFromPixel(new OpenLayers.Pixel(x, y));                                                                     
				}                            
			});
		}
	});
	graphView.enableToolTip();
	graphView.getToolTip = function(event){
		var data = this.getDataAt(event);
		if(data){
			return '城市:' + data.s('note') + '
经度:' + data.lonLat.lon + '
维度:' + data.lonLat.lat;
		}
		return null;
	};
	graphView.isVisible = function(data){
		return map.zoom > 1 || this.isSelected(data);
	};
	graphView.isNoteVisible = function(data){
		return map.zoom > 6 || this.isSelected(data);
	}; 
	graphView.getLabel = function(data){
		return '经度:' + data.lonLat.lon + '\n维度:' + data.lonLat.lat;
	};
	graphView.isLabelVisible = function(data){
		return map.zoom > 7 || this.isSelected(data);
	};                 

	view.addEventListener("ontouchend" in document ? 'touchstart' : 'mousedown', function(e){
		var data = graphView.getDataAt(e);
		if(data || e.metaKey || e.ctrlKey){
			e.stopPropagation();
		}                      
	}, false); 
	view.style.position = 'absolute';
	view.style.top = '0';
	view.style.left = '0';
	view.style.right = '0';
	view.style.bottom = '0';                
	view.style.zIndex = 999;
	map.viewPortDiv.appendChild(view);

	var color = randomColor();
	lines = china.split('\n');
	for(var i=0; i<lines.length; i++) {
		line = lines[i].trim();
		if(line.indexOf('【') === 0){
			//province = line.substring(1, line.length-1);                
			color = randomColor();
		}else{
			var ss = line.split(' ');
			if(ss.length === 3){
				createNode(parseFloat(ss[1].substr(3)), parseFloat(ss[2].substr(3)), ss[0].substr(3), color);                                                      
			}
		}
	}                                
}

function reset(){
	graphView.tx(0);
	graphView.ty(0);
	graphView.dm().each(function(data){                    
		if(data.lonLat){                            
			data.setPosition(map.getPixelFromLonLat(data.lonLat));                           
		}
	});
	graphView.validate();
}

function createNode(lon, lat, name, color){
	var node = new ht.Node();
	node.s({
		'shape': 'circle',
		'shape.background': color,
		'note': name,                    
		'label.background': 'rgba(255, 255, 0, 0.5)',                    
		'select.type': 'circle'
	});
	node.setSize(10, 10);
	var lonLat = new OpenLayers.LonLat(lon, lat);
	lonLat.transform('EPSG:4326', map.getProjectionObject());
	node.setPosition(map.getPixelFromLonLat(lonLat));
	node.lonLat = lonLat;
	graphView.dm().add(node);
	return node;
}


© 著作权归作者所有

xhload3d
粉丝 194
博文 174
码字总数 362206
作品 0
崇明
私信 提问
加载中

评论(3)

xhload3d
xhload3d 博主

引用来自“粗粮贩子”的评论

效果很炫,业务逻辑就应该不依赖于地图sdk。但是像路径搜索等等交给Baidu的服务器做还是不错,所以地图服务api也很是推荐。
是的,各取所长,GIS的核心功能还是应该让GIS做,非GIS相关的逻辑功能留给HT
粗粮贩子
效果很炫,业务逻辑就应该不依赖于地图sdk。但是像路径搜索等等交给Baidu的服务器做还是不错,所以地图服务api也很是推荐。
i
ittech
好文,马克!
百度地图与HT for Web结合的GIS网络拓扑应用

在《HT for Web整合OpenLayers实现GIS地图应用》篇中介绍了HT for Web与OpenLayers的整合,不少朋友反应国内用得比较多的还是百度地图,虽然HT整合百度地图原理与OpenLayers一致,但不同GIS...

xhload3d
2014/12/04
1K
0
基于HTML5的网络拓扑图(2)-结合OpenLayers实现地图背景的拓扑图

地图应用分三种级别:示意地图(Map Chart),地图(Map),地理信息系统(GIS),第一种通常使用相对坐标系,后两种则为真实的地理坐标,其中第二种以谷歌地图为代表,日常生活中普遍使用,...

nosand
2014/04/21
4.2K
3
OpenLayers 6.0.0 发布,高性能开源地图引擎

OpenLayers 是一个高性能、功能丰富的库,用于在 Web 上创建交互式地图。它可以显示从任何来源加载的地图图块、矢量数据和标记。6.0.0 版本内容如下: 能够使用不同的渲染器类型组成层:以前...

afterer
09/29
2.6K
0
OpenLayers 4.5 发布,高性能开源地图引擎

OpenLayers 是一个高性能、功能丰富的库,用于在 Web 上创建交互式地图。它可以显示从任何来源加载的地图图块、矢量数据和标记。 OpenLayers 4.5 包含 50 项左右用户提交的改进和修复。Headl...

王练
2017/11/14
5.1K
1
公司内部培训OpenLayers的资料

OpenLayers技术比较火热 简介:本课程旨在快速搭建地理信息展示系统。主要目的在于让学员了解OpenLayers的基本概念及关键API、掌握内网离线地图优化项目实战技巧以及结合地理信息系统展示的特...

小java哈
2013/10/22
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

500行代码,教你用python写个微信飞机大战

这几天在重温微信小游戏的飞机大战,玩着玩着就在思考人生了,这飞机大战怎么就可以做的那么好,操作简单,简单上手。 帮助蹲厕族、YP族、饭圈女孩在无聊之余可以有一样东西让他们振作起来!...

上海小胖
41分钟前
6
0
关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
7
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0
Docker容器实战(七) - 容器中进程视野下的文件系统

前两文中,讲了Linux容器最基础的两种技术 Namespace 作用是“隔离”,它让应用进程只能看到该Namespace内的“世界” Cgroups 作用是“限制”,它给这个“世界”围上了一圈看不见的墙 这么一...

JavaEdge
今天
8
0
文件访问和共享的方法介绍

在上一篇文章中,你了解到文件有三个不同的权限集。拥有该文件的用户有一个集合,拥有该文件的组的成员有一个集合,然后最终一个集合适用于其他所有人。在长列表(ls -l)中这些权限使用符号...

老孟的Linux私房菜
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部