`
xhload3d
  • 浏览: 209182 次
社区版块
存档分类
最新评论

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地图引擎融合的解决方案。

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;
}

 

 

2
0
分享到:
评论

相关推荐

    openlayers 调用百度地图

    在OpenLayers中调用百度地图是一项常见的需求,特别是在构建Web GIS应用时,用户可能希望结合OpenLayers的强大功能和百度地图的丰富数据。OpenLayers是一个开源JavaScript库,用于创建交互式的地图应用,而百度地图...

    使用openlayers加载离线地图实例

    在IT行业中,前端开发是构建Web应用程序的关键部分,而OpenLayers是一个流行的JavaScript库,用于创建交互式的、基于Web的地图应用。本实例将详细介绍如何利用OpenLayers加载离线地图,并通过mui将其打包成移动应用...

    openlayers5加载百度地图.zip

    这个压缩包“openlayers5加载百度地图.zip”显然包含了使用OpenLayers 5版本与百度地图API集成的示例代码。OpenLayers 5是这个库的一个重要升级,提供了更多的功能、性能优化以及对现代Web标准的支持。 首先,让...

    openlayers发布简易离线地图DEMO

    通过这个DEMO,开发者可以学习到如何使用OpenLayers来创建和展示离线地图,这对于在没有网络连接或者网络不稳定的情况下仍然需要地图服务的场景非常有用。同时,这也是对OpenLayers API的一个基础实践,为进一步开发...

    openlayers发布离线地图DEMO

    总结来说,这个"openlayers发布离线地图DEMO"展示了如何使用OpenLayers库加载本地存储的瓦片数据,创建一个无需网络连接就能显示的地图应用。这对于那些需要在无网络环境或带宽有限的场合使用地图的应用场景非常有用...

    openlayers加载瓦片地图并手动标记坐标点

    OpenLayers 是一个强大的开源JavaScript库,用于在Web浏览器中创建交互式地图应用。它支持多种数据源,包括瓦片地图,使得开发者可以轻松地将地理信息集成到网站中。本教程将详细介绍如何使用OpenLayers加载瓦片地图...

    Openlayers2多地图联动

    "OpenLayers2多地图联动"这个主题涉及到如何在同一个应用中同步显示和操作多个地图源,实现地图之间的交互。 在OpenLayers2中,多地图联动的核心是通过事件监听和处理来同步各个地图层的行为。例如,当用户在一张...

    二三维离线地图演示系统 V1.0(for OpenLayers3)

    在这个系统中,太乐地图的离线数据被整合到OpenLayers 3中,通过本地存储的地理信息数据来实现地图的离线显示。这需要对地图瓦片的组织结构有深入理解,通常地图瓦片会被按照特定的坐标系和分辨率划分,以便在需要时...

    openlayers3+ 地图右键

    在OpenLayers 3及以上版本中,地图右键功能的实现是一项关键操作,它允许用户与地图交互并执行特定任务,如获取地图上的坐标、测量距离、添加标记等。本篇文章将详细探讨如何在OpenLayers中自定义地图右键菜单,以...

    openlayers3添加各种地图资源

    在WebGIS开发中,OpenLayers 3 是一个强大的开源JavaScript库,用于在网页上创建交互式的地图应用。这个库提供了丰富的功能,使开发者能够轻松地整合多种地图服务,包括百度地图、天地图、高德地图以及Google地图。...

    openlayers5加载谷歌地图.zip

    学习和理解这个过程不仅有助于理解OpenLayers的工作原理,也有助于开发自定义的地图应用,比如叠加其他数据源,实现交互功能等。记得在实际使用时遵守谷歌地图的服务条款,尊重版权和隐私规定。

    java+openlayers实现MBTiles地图瓦片浏览

    1) 部署到tomcat6的webapps下面。 2) 将world.mbtiles放到D:/gisdata/mbtiles/目录下。 3) 在浏览器输入:(世界地图,图层0-7) http://localhost:8080/MbTileService/local_tiles.html

    openlayers3+geoserver地图交互

    《OpenLayers 3 + GeoServer 实现地图交互详解》 在现代GIS(地理信息系统)应用中,地图交互功能是至关重要的。本篇文章将详细介绍如何利用OpenLayers 3和GeoServer来构建一个具备地图框选、点击街道选中要素以及...

    openlayers 加载天地图示例

    在"Openlayers 加载天地图示例"中,`Openlayers-tianditu.html`很可能是主HTML文件,它会引入OpenLayers库以及我们自定义的`tiandituLayers.js`脚本来实现天地图的加载。在HTML文件中,我们可能会看到一个`&lt;div&gt;`...

    OpenLayers3加载谷歌地图

    OpenLayers3加载谷歌地图,加载谷歌地图显示,实现效果很好,放大比例尺也能看得清楚。文章链接:https://blog.csdn.net/Gary_888/article/details/89914290

    基于Openlayers的GIS组件设计

    如题,基于开源的gis框架(openlayers)设计的js组件,支持异步加载,可扩展。同时也提供了webgis操作的相关案例和代码,无论是学习还是工作需要均可满足。纯前端框架,下载后无需配置,可直接运行。

    基于openlayers实现图片地图,路径绘制,点是否在区域中判定,路径播放,回放控制

    1、实现图片地图,图片地图比例尺 2、绘制点的路径 3、绘制多边形,定位不规则多边形中心点,显示名称 4、多边形编辑 5、地图全屏,地图截图 6、点是否在区域中判定 7、暂停,播放,向前,向后20s,倍速播放控制路径...

    openlayers5加载天地图.zip

    在"openlayers5加载天地图.zip"这个压缩包中,我们可以期待找到一个示例项目,展示了如何利用OpenLayers 5来加载和展示天地图的数据。天地图是中国的一个官方基础地理信息服务平台,提供了丰富的地图服务,包括地形...

    openlayers5加载天地图影像.zip

    OpenLayers 是一个流行的开源JavaScript库,用于在网页上创建交互式的地图应用。版本5提供了许多增强功能和优化,使得开发者能够更加便捷地处理地图数据。本文将深入探讨如何使用OpenLayers 5加载天地图影像,这是一...

    解决openlayers加载百度地图,坐标偏移,热力图渲染闪烁问题

    项目需求是想在百度地图上面用openlayers渲染热力图,然后就去看了相关openlayers的文档,选择了6.15.1版本,然后仿照地震热力图例子写了代码,但是由于自带是OSM地图,不符合项目要求,所以研究了如何加载百度地图...

Global site tag (gtag.js) - Google Analytics