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

以上抓图为本文介绍的例子最终运行效果,接下来我们一步步来实现,首选显示地图信息需要有城市经纬度数据,搜索了下感谢此篇博客提供的数据。这么大量的数据我采用的是《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接管地图操作的交互。
以上交互设计似乎很完美了,结果运行时发现了几处折腾了我很久才找到解决方案的坑:
- 设置map.events.fallThrough = true;否则map不会将事件透传到HT的GraphView组件
- graphView.getView().style.zIndex = 999; 需要指定一定的zIndex否则会被遮挡
- graphView.getView().className = ‘olScrollable’; 否则滚轮不会响应地图缩放
- 设置ht.Default.baseZIndex: 1000 否则ToolTip会被遮挡
为了让这个例子用户体验更友好,我还用心折腾了些技术点供参考:
- 采用开源免费的http://llllll.li/randomColor/随机颜色类库,该类库还有很多非常棒的颜色获取函数,我只是简单的为每个省份显示不一样的颜色
- 重载了isVisible、isNoteVisible和isLabelVisible仅在缩放达到一定级别才显示更详细的内容,否则缩小时所有城市信息都显示完全无法查看,多少也能提高显示性能
以下为最终效果的抓图、视频和源代码:http://v.youku.com/v_show/id_XODM5Njk0NTU2.html

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;
}
HTML5 网络拓扑图整合 OpenLayers 实现 GIS 地图应用的更多相关文章
- HT for Web整合OpenLayers实现GIS地图应用
HT for Web作为逻辑拓扑图形组件自身没有GIS功能,但可以与各种GIS引擎即其客户端组件进行融合,各取所长实现逻辑拓扑和物理拓扑的无缝融合,本章将具体介绍HT for Web与开发免费的Ope ...
- 快速开发基于 HTML5 网络拓扑图应用
采用 HT 开发网络拓扑图非常容易,例如<入门手册>的第一个小例子麻雀虽小五脏俱全:http://www.hightopo.com/guide/guide/core/beginners/e ...
- 矢量Chart图表嵌入HTML5网络拓扑图的应用
使用 HT for Web (以下简称 HT)开发HTML5网络拓扑图的开发者有 Chart 需求的项目的时候,感觉很痛苦,HT 集成的 Chart 组件中,并不包含有坐标,在展现方面不是很直观,但是 ...
- HTML5 网络拓扑图性能优化
HTML5 中的 Canvas 对文本的渲染(fillText,strokeText)性能都不太好,比如设置字体(font).文本旋转(rotation),如果绘制较多的文本时,一些交互操作会手动很大 ...
- 快速开发基于 HTML5 网络拓扑图应用1
今天开始我们就从最基础解析如何构建 HTML5 Canvas 拓扑图应用,HT 内部封装了一个拓扑图形组件 ht.graph.GraphView(以下简称 GraphView)是 HT 框架中 2D ...
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(一)
计算机网络的拓扑结构是引用拓扑学中研究与大小,形状无关的点.线关系的方法.把网络中的计算机和通信设备抽象为一个点,把传输介质抽象为一条线,由点和线组成的几何图形就是计算机网络的拓扑结构.网络的拓扑结构 ...
- 快速开发基于 HTML5 网络拓扑图应用--入门篇(二)
上一篇我们绘制了一个 graphView 场景,在场景之上通过 graphView.dm() 获取数据容器,并通过 graphView.dm().add() 函数添加了两个 Node 节点,并通过 s ...
- 快速开发基于 HTML5 网络拓扑图应用之 DataBinding 数据绑定篇
前言 发现大家对于我从 json 文件中直接操作节点属性来控制界面的动态变化感到比较好奇,所以这篇就针对数据绑定以及如何使用这些绑定的数据做一篇说明,我写了一个简单的例子,基于机房工控的服务器上设备的 ...
- 百度地图、ECharts整合HT for Web网络拓扑图应用
前一篇谈及到了ECharts整合HT for Web的网络拓扑图应用,后来在ECharts的Demo中看到了有关空气质量的相关报表应用,就想将百度地图.ECharts和HT for Web三者结合起来 ...
随机推荐
- 两个 viewports 的故事-第二部分
原文链接:A tale of two viewports — part two 译者:nzbin 在这个迷你系列中,我将解释 viewports 和各种重要元素的宽度是如何工作的,比如说 <ht ...
- .net Elasticsearch 学习入门笔记
一. es安装相关1.elasticsearch安装 运行http://localhost:9200/2.head插件3.bigdesk插件安装(安装细节百度:windows elasticsear ...
- 算法与数据结构(十六) 快速排序(Swift 3.0版)
上篇博客我们主要聊了比较高效的归并排序算法,本篇博客我们就来介绍另一种高效的排序算法:快速排序.快速排序的思想与归并排序类似,都是采用分而治之的方式进行排序的.快速排序的思想主要是取出无序序列中第一个 ...
- Ajax实现原理,代码封装
都知道实现页面的异步操作需要使用Ajax,那么Ajax到是怎么实现异步操作的呢? 首先需要认识一个对象 --> XMLHttpRequest 对象 --> Ajax的核心.它有许多的属性和 ...
- GOF23设计模式归类
创建型模式:-单例模式.工厂模式.抽象工厂模式.建造者模式.原型模式结构型模式:-适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式行为型模式:-模板方法模式.命令模式.迭代器模式 ...
- 信息安全-1:python之playfair密码算法详解[原创]
转发注明出处: http://www.cnblogs.com/0zcl/p/6105825.html 一.基本概念 古典密码是基于字符替换的密码.加密技术有:Caesar(恺撒)密码.Vigenere ...
- mysql 大表拆分成csv导出
最近公司有一个几千万行的大表需要按照城市的id字段拆分成不同的csv文件. 写了一个自动化的shell脚本 在/home/hdh 下面 linux-xud0:/home/hdh # lltotal 1 ...
- sqlyog导出json数据格式支持mysql数据转存mongodb
<!-------------知识的力量是无限的(当然肯定还有更简单的方法)-----------!> 当我考虑将省市区三级联动数据从mysql转入mongodb时遇到了网上无直接插入mo ...
- AutoIt实现Webdriver自动化测试文件上传
在运用WebDriver进行自动化测试时,由于WebDriver自身的限制,对于上传文件时Windows弹出的文件选择窗口无法控制,通过在网上查找资料锁定使用AutoIt来控制文件上传窗口. Auto ...
- Xamarin.Android快速入门
一.准备工作 1.创建一个空的解决方案,并命名为Phoneword 2.右击解决方案 新建->新建项目 并命名为Phoneword_Droid 二.界面 1.打开Resources文件夹-> ...