在《HT for Web整合OpenLayers实现GIS地图应用》篇中介绍了HT for Web与OpenLayers的整合,很多朋友反应国内用得比较多的仍是百度地图,虽然HT整合百度地图原理与OpenLayers一致,但不一样GIS引擎客户端结合代码细节仍是有很多差别,自定义地图风格更是彻底不同,为此我再开篇介绍下HT与百度地图整合的方案,此次咱们将改进之前的例子,除了表明城市的拓扑节点外,再增长连线链接省会和城市,实现网络拓扑链路的流动效果。php
百度地图有多种客户端SDK,咱们这里用的天然是JavaScript版的API,百度地图的2.0版增长了很多新功能,例如能够自定义地图样式模板,本例中咱们特地设置成style:’midnight’的深色背景风格。插入map的位置与OpenLayers也不同,经过mapDiv.firstChild.firstChild.appendChild(view);插入,zIndex这些属性都还好不须要设置。html
坐标转换方面从经纬度转换成平面坐标是map.pointToPixel函数,经过node.setPosition(map.pointToPixel(new BMap.Point(lon, lat)));可设置ht.Node对应的平面逻辑坐标,经过map.pixelToPoint(new BMap.Pixel(x,y))可将平面坐标转换成经纬度坐标,咱们在监听节点图元被拖拽结束的endMove须要从新计算当前位置的经纬度时用到。node
地图数据方面每一个省的省会城市都是第一个出现,所以咱们构建了size大一点的带渐进色的图元表明省会城市,其余城市构建时同时构建ht.Edge的连线与省会节点链接,同时引入HT的ht-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扩展的功能也能够经过在HT的GraphView实现,这样地图仅仅是做为背景,业务逻辑代码彻底在更灵活强大的HT模型中进行,例如图元的隐藏和显示也都在HT的GraphView中重载了graphView.isVisible函数实现的,经过HT设置能够定义到更细节的isNoteVisible这样的图元部件是否可见,这里代码和OpenLayers有的区别的仅仅是从map.zoom改成map.getZoom()。app
另外由于城市节点较多,每次移动界面时咱们都须要调用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交给地图控制。dom
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的整合容易不少,没有太多须要特殊设置的地方。ui
构建城市节点依然采用了http://llllll.li/randomColor/随机生成颜色的框架,仅对省会节点增长了渐进色的效果,省会节点和城市节点间构建了ht.Edge连线,经过'flow': true的style启动连线流动,flow.*还有不少控制参数,例如控制流动的方向,流动的效果等,这里就再也不展开介绍了。
如下为操做视频、抓图和源代码供你们参考,这样的结合可完美的将百度地图丰富的地图数据信息,与HT强大的逻辑拓扑功能相结合,不然光靠百度地图SDK的API的扩展方式,用户只能作些简单的效果,例如连线流动等效果都远不如HT这样一行代码就搞定来的容易。http://v.youku.com/v_show/id_XODQxMDcwNjQ0.html
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); } }); }