前言
通过结合 HTML5 和 OpenLayers 可以组合成非常棒的一个电信地图网络拓扑图的应用,形成的效果可以用来作为电信资源管理系统,美食定位分享软件,片区找房,绘制铁轨线路等等,各个领域都能够涉及的一款应用。虽然这个 Demo 是结合 OpenLayers3 的,其实还可推广到与 ArcGIS、百度地图以及 GoogleMap 等众多 GIS 地图引擎融合。
demo 地址:OpenLayers Test
代码生成
创建地图
OpenLayers 是一个用于开发 WebGIS 客户端的 JavaScript 包。OpenLayers 支持的地图来源包括 Google Maps、Yahoo、 Map、微软 Virtual Earth 等多种离线在线地图,这里用到的是比较大众化的谷歌地图 Google Map 的在线地图,使用 OpenLayers 前只需要引入相关的类库以及 css 文件:
<link rel="stylesheet" href="css/ol.css" type="text/css">
<script src="lib/ol.js"></script>
初始化地图的操作则是将 Map 放进一个 div 元素中,初始化一个 ol.Map 地图类,这在整个电信资源管理系统中必不可少,然后设置这个类中的各个参数:
var mapDiv = document.getElementById('mapDiv');
map = new ol.Map({
target: 'mapDiv', // 地图容器
controls: ol.control.defaults().extend([
graphViewControl, // 自定义拓扑控件
new ol.control.OverviewMap(), // 地图全局视图控件
new ol.control.ScaleLine(), // 比例尺控件
new ol.control.ZoomSlider(), // 缩放刻度控件
new ol.control.ZoomToExtent() // 缩放到全局控件
]),
layers: [ // 图层
new ol.layer.Tile({
source: new ol.source.XYZ({ // 谷歌地图
url:'http://www.google.cn/maps/vt/pb=!1m4!1m3!1i{z}!2i{x}!3i{y}!2m3!1e0!2sm!3i345013117!3m8!2szh-CN!3scn!5e1105!12m4!1e68!2m2!1sset!2sRoadmap!4e0'
})
})
],
view: new ol.View({ // 地图视图
projection: 'EPSG:3857', // 投影
center: ol.proj.fromLonLat([106, 35]), // 视图的初始中心 中心的坐标系由projection选项指定
zoom: 4 // 缩放级别 用于计算视图的初始分辨率
})
});
上面的代码根据每行的代码注释加上官方 API 解释应该没有什么难度。细心的朋友可能注意到了一个非官方的控件:graphViewControl 控件,这个控件是我自定义出来,用来在这个控件上绘制拓扑图形的,声明和定义部分在 GraphViewControl.js 文件中。
自定义控件
自定义 OpenLayers 的控件,无非就是将某个类继承于 ol.control.Control 类,然后针对不同的需求重写父类方法或者增加方法。
我在声明类的时候传了一个 options 参数,通过在定义类的时候设置控件的容器元素并且将控件渲染到 GIS 地图的 viewport 之外:
var view = graphView.getView(); // 获取拓扑组件的 div
ol.control.Control.call(this, {
element: view, // 控件的容器元素
target: options.target // 将控件渲染到地图的视口之外
});
上面的 graphView 是通过 GraphViewControl 在父类方法上新添加的一个方法并且初始化值为 ht.graph.GraphView(入门手册 - HT for Web),HT 的拓扑图形组件:
// 获取GraphView对象
GraphViewControl.prototype.getGraphView = function() { return this._graphView; };
var graphView = this._graphView = new ht.graph.GraphView(); // 拓扑图组件
我在控件中还给 graphView 拓扑组件添加了一些事件的监听,由于 OpenLayers 和 HT 是两款不同的 js 库,有着各自的交互系统和坐标系,首先我们将某些我们需要获取在 HT 上做的交互事件并停止事件传播到 OpenLayers 上:
// 拖拽 node 时不移动地图
var stopGraphPropagation = function(e) {
var data = graphView.getDataAt(e); // 获取 graphView 事件下的节点
var interaction = graphView.getEditInteractor(); // 获取编辑交互器
if (data || e.metaKey || e.ctrlKey || interaction && interaction.gvEditing) {
e.stopPropagation(); // 不再派发事件 该方法将停止事件的传播,阻止它被分派到其他 Document 节点
}
}
/** pointerdown 当指针变为活动事件
* 对于鼠标,当设备从按下的按钮转换到至少一个按钮被按下时,它会被触发。
* 对于触摸,当与数字化仪进行物理接触时会被触发。
* 对于笔,当触笔与数字化仪进行物理接触时会被触发。
**/
view.addEventListener('pointerdown', stopGraphPropagation, false);
view.addEventListener('touchstart', stopGraphPropagation, false); // 当触摸点被放置在触控面板上事件
view.addEventListener('mousedown', stopGraphPropagation, false); // 鼠标点下事件
GraphViewControl 类定义部分还添加了一些关于移动和编辑节点的交互事件,主要是将节点的像素坐标转为 OpenLayers 的 ol.Cordinate 地图视图投影中的坐标并存储到节点的业务属性(HT 的一个可以存储任意值的对象)中,这样我们只需要通过获取或设置节点的业务属性 coord 就可以自由获取和设置节点在 map 上的像素坐标。