百度Map与HT for Web结合的GIS网络拓扑应用

简介: 在《HT for Web整合OpenLayers实现GIS地图应用》篇中介绍了HT for Web与OpenLayers的整合,不少朋友反应国内用得比较多的还是百度地图,虽然HT整合百度地图原理与OpenLayers一致,但不同GIS引擎客户端结合代码细节还是有不少差异,自定义地图风格更是完全不一样,为此我再开篇介绍下HT与百度地图整合的方案,这次我们将改进以前的例子,除了代表城市的拓扑节点外,再增加连线连接省会和城市,实现网络拓扑链路的流动效果。

在《HT for Web整合OpenLayers实现GIS地图应用》篇中介绍了HT for Web与OpenLayers的整合,不少朋友反应国内用得比较多的还是百度地图,虽然HT整合百度地图原理与OpenLayers一致,但不同GIS引擎客户端结合代码细节还是有不少差异,自定义地图风格更是完全不一样,为此我再开篇介绍下HT与百度地图整合的方案,这次我们将改进以前的例子,除了代表城市的拓扑节点外,再增加连线连接省会和城市,实现网络拓扑链路的流动效果。

Screen Shot 2014-12-03 at 11.18.02 PM

百度地图有多种客户端SDK,我们这里用的自然是JavaScript版的API,百度地图的2.0版增加了不少新功能,例如可以自定义地图样式模板,本例中我们特意设置成style:’midnight’的深色背景风格。插入map的位置与OpenLayers也不一样,通过mapDiv.firstChild.firstChild.appendChild(view);插入,zIndex这些属性都还好不需要设置。

坐标转换方面从经纬度转换成平面坐标是map.pointToPixel函数,通过node.setPosition(map.pointToPixel(new BMap.Point(lon, lat)));可设置ht.Node对应的平面逻辑坐标,通过map.pixelToPoint(new BMap.Pixel(x,y))可将平面坐标转换成经纬度坐标,我们在监听节点图元被拖拽结束的endMove需要重新计算当前位置的经纬度时用到。

地图数据方面每个省的省会城市都是第一个出现,因此我们构建了size大一点的带渐进色的图元代表省会城市,其他城市构建时同时构建ht.Edge的连线与省会节点连接,同时引入HTht-flow.js插件,只需要graphView.enableFlow(60);一句话就可以启动流动连线功能,每条edge连线还可以有很多flow.*相关的流动参考可控制流动效果,这里的简单例子我们不需要做定制,保持HT默认的流动参数就足够酷了。

另外通过graphView.setLayers(['edgeLayer', 'nodeLayer']);我们为拓扑设置了两个层,node.setLayer(‘nodeLayer’);和edge.setLayer(‘edgeLayer’)使得图元节点全部呈现于连线之上,这个仅是简单例子如果需要可以随意定义更多的layers,layers的数组顺序决定了最终图元显示的先后顺序。

传统使用GIS应用来说图层都需要操作GIS客户端API来进行,但从这个例子大家可以发现,以前需要在GIS的SDK扩展的功能也可以通过在HTGraphView实现,这样地图仅仅是作为背景,业务逻辑代码完全在更灵活强大的HT模型中进行,例如图元的隐藏和显示也都在HTGraphView中重载了graphView.isVisible函数实现的,通过HT设置可以定义到更细节的isNoteVisible这样的图元部件是否可见,这里代码和OpenLayers有的区别的仅仅是从map.zoom改为map.getZoom()。

另外因为城市节点较多,每次移动界面时我们都需要调用node.setPosition(map.pointToPixel(new BMap.Point(lon, lat)));重新定位图元平面坐标,毕竟对于js来说密集型的大量计算不是其强项,因此我们监听了map的movestart、moveend、zoomstart、zoomend、dragstart和dragend等事件,做的都是同样的事情在开始变化前通过view.style.opacity = 0;因此GraphView拓扑图,当事件结束后通过view.style.opacity = 1;再次显示拓扑图,同时调用resetPosition();重新定位图元节点,这样保证用户能够流畅的操作地图,而密集型的运算仅在最后才进行一次。

拓扑图方面还有些细节,例如graphView.setAutoScrollZone(-1)关闭默认拖拽图元到边缘时的自动滚动功能,graphView.handleScroll = function(){};关闭拓扑的滚轮缩放功能,graphView.handlePinch = function(){};关闭拓扑在touch触屏的缩放功能,因为这些功能都要传递给Map交给地图控制。

graphView.mi监听了moveEnd事件,这个用于某些情况下,用户需要手工移动节点,意味着要改变节点的经纬度信息,因此在监听到moveEnd之后,我们通过data.lonLat = map.pixelToPoint(new BMap.Pixel(x,y));根据屏幕坐标重新得到移动后的经纬度信息。

毕竟GraphView和Map的交互方式是完全不一样的,因此handleClick在用户点击界面时我们需要控制分流,也就是决定此次点击要交给GraphView处理,还是Map处理,我们通过var data = graphView.getDataAt(e);判断当前是否点击中了图元,如果选中了图元则GraphView拓扑图接管交互任务,因此通过e.stopPropagation();停止事件的继续传播,如果点击在背景上则无需特殊处理,Map自动会接管任务,毕竟我们是通过mapDiv.firstChild.firstChild.appendChild(view);的方式插入拓扑图,mapDiv作为底层父辈类组件依然会监听到事件,这点比OpenLayers的整合容易很多,没有太多需要特殊设置的地方。

构建城市节点依然采用了http://llllll.li/randomColor/随机生成颜色的框架,仅对省会节点增加了渐进色的效果,省会节点和城市节点间构建了ht.Edge连线,通过'flow': true的style启动连线流动,flow.*还有很多控制参数,例如控制流动的方向,流动的效果等,这里就不再展开介绍了。

以下为操作视频、抓图和源代码供大家参考,这样的结合可完美的将百度地图丰富的地图数据信息,与HT强大的逻辑拓扑功能相结合,否则光靠百度地图SDK的API的扩展方式,用户只能做些简单的效果,例如连线流动等效果都远不如HT这样一行代码就搞定来的容易。http://v.youku.com/v_show/id_XODQxMDcwNjQ0.html


Screen Shot 2014-12-04 at 12.31.13 AM

 

var dataModel = new ht.DataModel();
var graphView = new ht.graph.GraphView(dataModel);              
var map = null;   

function init() {
    map = new BMap.Map("map");   
    var point = new BMap.Point(116.404, 39.915);                          
    map.addTileLayer(new BMap.TrafficLayer());                    
    map.centerAndZoom(point, 4);                    
    map.enableScrollWheelZoom();                       
    map.addControl(new BMap.NavigationControl());                               

    map.setMapStyle({
        features: ["road", "building","water","land"],
        style:'midnight'
    });

    var view = graphView.getView();
    view.className = 'graphView'; 
    var mapDiv = document.getElementById('map');
    mapDiv.firstChild.firstChild.appendChild(view);

    map.addEventListener('movestart', function(e){                   
       view.style.opacity = 0;
    });
    map.addEventListener('moveend', function(e){
       view.style.opacity = 1; 
       resetPosition(); 
    });
    map.addEventListener('dragstart', function(e){
       view.style.opacity = 0;                
    });
    map.addEventListener('dragend', function(e){
       view.style.opacity = 1; 
       resetPosition(); 
    });                                
    map.addEventListener('zoomstart', function(e){
        view.style.opacity = 0;
    });                
    map.addEventListener('zoomend', function(e){
        view.style.opacity = 1;    
        resetPosition(); 
    });                

    graphView.setLayers(['edgeLayer', 'nodeLayer']);
    graphView.enableFlow(60);
    graphView.enableToolTip();
    graphView.getToolTip = function(event){
        var data = this.getDataAt(event);
        if(data instanceof ht.Node){
            return '城市:' + data.s('note') + '
经度:' + data.lonLat.lng + '
维度:' + data.lonLat.lat;
        }
        return null;
    };
    graphView.isVisible = function(data){
        return map.getZoom() > 1 || this.isSelected(data);
    };
    graphView.isNoteVisible = function(data){
        return map.getZoom() > 8 || this.isSelected(data);
    }; 
    graphView.getLabel = function(data){
        if(data instanceof ht.Node){
            return '经度:' + data.lonLat.lng + '\n维度:' + data.lonLat.lat;
        }                    
    };
    graphView.isLabelVisible = function(data){
        return map.getZoom() > 9 || this.isSelected(data);
    }; 

    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.pixelToPoint(new BMap.Pixel(x,y)); 
                }                            
            });
        }
    });

    graphView.setAutoScrollZone(-1);
    graphView.handleScroll = function(){};
    graphView.handlePinch = function(){};

    var handleClick = function(e){
        var data = graphView.getDataAt(e);
        if(data){
            e.stopPropagation();
        }
        else if(e.metaKey || e.ctrlKey){
            e.stopPropagation();
        }
    };
    graphView.getView().addEventListener('click', handleClick, false);                
    graphView.getView().addEventListener('dblclick', handleClick, false);
    graphView.getView().addEventListener(ht.Default.isTouchable ? 'touchstart' : 'mousedown', handleClick, false);

    window.addEventListener("resize", function(e) {
        graphView.invalidate();
    }, false);                 

    var color = randomColor(),
        province = null;
    lines = china.split('\n');
    for(var i=0; i<lines.length; i++) {
        line = lines[i].trim();
        if(line.indexOf('【') === 0){               
            color = randomColor();
            province = null;
        }else{
            var ss = line.split(' ');
            if(ss.length === 3){
                var node = createNode(parseFloat(ss[1].substr(3)), parseFloat(ss[2].substr(3)), ss[0].substr(3), color); 
                if(province){
                    var edge = new ht.Edge(province, node);
                    edge.s({
                        'edge.center': true,
                        'edge.width': 1,                                    
                        'flow': true
                    });
                    edge.setLayer('edgeLayer');
                    dataModel.add(edge);
                }else{
                    province = node;
                    node.s({                                   
                        'shape.gradient': 'radial.center',                                    
                        'border.type': 'circle',
                        'border.width': 1,
                        'border.color': 'rgba(200, 200, 200, 0.5)'                                    
                    });
                    node.setSize(15, 15);
                }
            }
        }
    }                

}

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.setLayer('nodeLayer');
    node.setSize(10, 10);
    var lonLat = new BMap.Point(lon, lat); 
    node.setPosition(map.pointToPixel(lonLat));
    node.lonLat = lonLat;
    graphView.dm().add(node);
    return node;
}            

function resetPosition(e){
    graphView.tx(0);
    graphView.ty(0);
    dataModel.each(function(data){
        if(data instanceof ht.Node){
            var lonLat = data.lonLat,
                position = map.pointToPixel(lonLat);   
            data.setPosition(position.x,position.y);                           
        }
    });            
}

 

目录
相关文章
|
12天前
|
人工智能 运维 物联网
AI在蜂窝网络中的应用前景
AI在蜂窝网络中的应用前景
24 3
|
3天前
|
前端开发 JavaScript UED
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势
在数字化时代,Web 应用性能优化尤为重要。本文探讨了CSS与HTML在提升Web性能中的关键作用及未来趋势,包括样式表优化、DOM操作减少、图像优化等技术,并分析了电商网站的具体案例,强调了技术演进对Web性能的深远影响。
11 5
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
本文旨在通过深入浅出的方式,为读者揭示卷积神经网络(CNN)的神秘面纱,并展示其在图像识别领域的实际应用。我们将从CNN的基本概念出发,逐步深入到网络结构、工作原理以及训练过程,最后通过一个实际的代码示例,带领读者体验CNN的强大功能。无论你是深度学习的初学者,还是希望进一步了解CNN的专业人士,这篇文章都将为你提供有价值的信息和启发。
|
12天前
|
缓存 安全 网络安全
HTTP/2与HTTPS在Web加速中的应用
HTTP/2与HTTPS在Web加速中的应用
|
15天前
|
SQL 安全 前端开发
PHP与现代Web开发:构建高效的网络应用
【10月更文挑战第37天】在数字化时代,PHP作为一门强大的服务器端脚本语言,持续影响着Web开发的面貌。本文将深入探讨PHP在现代Web开发中的角色,包括其核心优势、面临的挑战以及如何利用PHP构建高效、安全的网络应用。通过具体代码示例和最佳实践的分享,旨在为开发者提供实用指南,帮助他们在不断变化的技术环境中保持竞争力。
|
12天前
RS-485网络中的标准端接与交流电端接应用解析
RS-485,作为一种广泛应用的差分信号传输标准,因其传输距离远、抗干扰能力强、支持多点通讯等优点,在工业自动化、智能建筑、交通运输等领域得到了广泛应用。在构建RS-485网络时,端接技术扮演着至关重要的角色,它直接影响到网络的信号完整性、稳定性和通信质量。
|
12天前
|
监控 网络协议 安全
员工网络监控软件:PowerShell 在网络监控自动化中的应用
在数字化办公环境中,企业对员工网络活动的监控需求日益增长。PowerShell 作为一种强大的脚本语言,能够有效实现员工网络监控自动化。本文介绍了如何使用 PowerShell 获取网络连接信息、监控特定网址的访问情况,并生成自动化报告,帮助企业高效管理员工网络活动,确保网络安全和合规性。
24 0
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
113 3
|
24天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
126 45
|
6天前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
20 2
下一篇
无影云桌面