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

百度地图有多种客户端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

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

百度Map与HT for Web结合的GIS网络拓扑应用的更多相关文章

  1. 百度地图与HT for Web结合的GIS网络拓扑应用

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

  2. 百度地图、ECharts整合HT for Web网络拓扑图应用

    前一篇谈及到了ECharts整合HT for Web的网络拓扑图应用,后来在ECharts的Demo中看到了有关空气质量的相关报表应用,就想将百度地图.ECharts和HT for Web三者结合起来 ...

  3. ECharts+BaiduMap+HT for Web网络拓扑图应用

    前一篇谈及到了ECharts整合HT for Web的网络拓扑图应用,后来在ECharts的Demo中看到了有关空气质量的相关报表应用,就想将百度地图.ECharts和HT for Web三者结合起来 ...

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

    HT for Web作为逻辑拓扑图形组件自身没有GIS功能,但可以与各种GIS引擎即其客户端组件进行融合,各取所长实现逻辑拓扑和物理拓扑的无缝融合,本章将具体介绍HT for Web与开发免费的Ope ...

  5. HT for Web基于HTML5的图像操作(一)

    HT for Web独创的矢量图片设计架构,使其具有强大丰富的动态图形呈现能力,但从最近知乎热议的“Adobe Photoshop 是否已经过时?”的话题,大家能体会到很多情况下实际项目不可能完全采用 ...

  6. 透过HT for Web 3D看动画Easing函数本质

    http://www.hightopo.com/guide/guide/plugin/form/examples/example_easing.html 50年前的这个月诞生了BASIC这门计算机语言 ...

  7. 基于HT for Web 快速搭建3D机房设备面板

    以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟 ...

  8. 基于HT for Web的3D拓扑树的实现

    在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在 ...

  9. 基于HT for Web的3D树的实现

    在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在 ...

随机推荐

  1. EF6(CodeFirst)+MySql开发脱坑指南

    废话 话说当年,在一个春光明媚的晌午,邂逅了迷人的丁香姑娘,从此拜倒在了她的石榴裙下,至今不能自拔,这位丁香姑娘就是ORM思想. 所谓ORM思想,我的理解就是根据一定的规则,把程序中的对象和数据库中的 ...

  2. 如何捕获和分析 JavaScript Error

    前端工程师都知道 JavaScript 有基本的异常处理能力.我们可以 throw new Error(),浏览器也会在我们调用 API 出错时抛出异常.但估计绝大多数前端工程师都没考虑过收集这些异常 ...

  3. FusionCharts简单教程(六)-----如何自定义图表上的工具提示

          所谓图表上的工具提示就是当鼠标放在某个特定的数据块上时所显示的提示信息.如下: 禁用显示工具提示       在默认情况下工具提示功能是显示的,但是有时候我们并不是很想需要这个功能提示功能 ...

  4. Ubuntu下安装 jdk6

    Ubuntu下安装 jdk6 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议   1,下载最新的 jdk6 版本,目前最 ...

  5. sublime 3 快捷键

    来自(http://dengo.org/archives/970) Sublime text 3是我最喜欢的代码编辑器,每天和代码打交道,必先利其器,掌握基本的代码编辑器的快捷键,能让你打码更有效率. ...

  6. AWS系列之二 使用EC2

    在本文中我们有三个任务. 第一:使用Amazon management console创建一个EC2实例. 第二:使用本地的命令行工具远程登陆到该EC2实例. 第三:在该EC2实例上创建一个web服务 ...

  7. 移动APP的自动化测试

    开发移动应用,最耗时耗力的就是手动测试APP的每个功能点或修复bug.有人就会提议App的业务逻辑可以使用nUnit或xUnit测试单元来辅助完成.那用户界面要如何测试?众所周知,移动设备多种多样,数 ...

  8. Java框架介绍-13个不容错过的框架项目

    本文转自互联网,个人收藏所用. 下面,我们将一同分享各有趣且颇为实用的Java库,大家请任取所需.不用客气~ 1.极致精简的Java Bootique是一项用于构建无容器可运行Java应用的极简技术. ...

  9. Javascript隐式转换

    乱想 javascript为什么需要隐式转换?如果没有会出现什么情况? 找了一圈没有看到关于这个的讨论,只好自己研究了,可能不一定正确,自行辨知. 郁闷就是郁闷在好好的,为什么要搞个隐式转换,一般来讲 ...

  10. JavaScript练习之for循环语句

    for循环四要素:初始条件.循环条件.循环体.状态改变. 1.for(var a=i;i<=aa;i++) { 循环体(例sum=sum+i  sum是输出的) } 例题 1-20关没关一分 2 ...