zh

# 结合OpenLayers实现地图背景的拓扑图

2014-04-21

### 创建地图

``````<link rel="stylesheet" href="OpenLayers/theme/default/style.css" type="text/css">
<script src="OpenLayers/OpenLayers.js"></script>
``````

#### 初始化地图

``````function initMap(canvas, lon, lat){
map = new OpenLayers.Map(canvas, {
projection: 'EPSG:3857',
layers: [
{numZoomLevels: 20}
),
),
),
)
],
center: new OpenLayers.LonLat(lon, lat).transform('EPSG:4326', 'EPSG:3857'),
zoom: 5
});
return map;
}
``````

### 地图与拓扑图的结合

OpenLayers与Qunee是两套不同的组件库，有着各自的交互系统和坐标系，需要实现组件叠加，以及坐标和交互的同步

#### 组件叠加

OpenLayers结构复杂，具有多个HTML图层，而Qunee相对简单，所以最终决定将Qunee插入到OpenLayers的viewportDiv中

``````var canvas = document.createElement('div');
canvas.style.width = '100%';
canvas.style.height = '100%';
canvas.style.position = 'absolute';
canvas.style.top = '0px';
canvas.style.left = '0px';
canvas.style.zIndex = 999;
map.viewPortDiv.insertBefore(canvas, map.viewPortDiv.firstChild);
Q.doSuperConstructor(this, MapGraph, [canvas]);
``````

#### 坐标转换

Qunee使用的是屏幕坐标，与地图坐标系完全不同，需要做转换

##### 经纬度转换成屏幕坐标

``````toLonLat: function(lon, lat){
var l = new OpenLayers.LonLat(lon, lat);
l.transform('EPSG:4326', graph.map.getProjectionObject());
return l;
}
``````

``````getPixelFromLonLat: function(lonLat){
return this.map.getPixelFromLonLat(lonLat);
}
``````

``````createNodeByLonLat: function(name, lon, lat){
var l = this.toLonLat(lon, lat);
var p = this.getPixelFromLonLat(l);
var node = graph.createNode(name, p.x, p.y);
node.lonLat = l;
return node;
}
``````
##### 屏幕坐标转换成地理坐标

``````var pixel = this.toCanvas(data.location.x, data.location.y);
data.lonLat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(pixel.x, pixel.y));
``````

``````this.interactionDispatcher.addListener(function(evt){
if(evt.kind == Q.InteractionEvent.ELEMENT_MOVE_END){
var datas = evt.datas;
Q.forEach(datas, function(data){
var pixel = this.toCanvas(data.location.x, data.location.y);
data.lonLat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(pixel.x, pixel.y));
}, this);
}
}, this)
``````

#### 交互同步

OpenLayers和Qunee的交互是冲突的，比如拖拽操作，qunee响应了，OpenLayers就没法响应，这里我们在Qunee交互的基础之上实现地图的漫游缩放操作

##### 平移操作

``````translate: function (tx, ty) {
Q.doSuper(this, MapGraph, "translate", arguments);
this.map.moveByPx(-tx, -ty);
}
``````
##### 缩放操作

OpenLayers默认的通过双击、鼠标滚轮实现缩放，这些事件默认会被Qunee所拦截，所以需要自己添加和派发

``````this.html.ondblclick = createEventFunction(this, function(evt){
if(this.getElementByMouseEvent(evt)){
Q.stopEvent(evt);
}
});
this.onmousewheel = function(evt){
if (this._scaling) {
return;
}
this._scaling = true;
Q.callLater(function() {
delete this._scaling;
}, this, 200);
this.map.zoomTo(this.map.zoom + (evt.delta > 0 ? 1 : -1), this.globalToLocal(evt));
}
``````

``````this.enableWheelZoom = false;
this.enableDoubleClickToOverview = false;
``````

``````this.map.events.register('zoomend', this, function(){this.updateNodes(true)});
``````

``````updateNodes: function(updateLocation){
if(updateLocation === true){
this.forEach(function(d){
if(d instanceof Q.Node){
var l = d.lonLat;
var p = this.getPixelFromLonLat(l);
d.location = p;
}
}, this);
this.translateTo(0, 0);
return;
}
this.translateTo(this.map.layerContainerOriginPx.x, this.map.layerContainerOriginPx.y);
}
``````