添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • (1) 捕捉overlay的dom的鼠标事件“mousedown”事件,以及地图map的“pointermove”、“pointerup”事件;
  • (2) 当触发“mousedown”时,记录下当前鼠标在元素中的相对于基点也就是overlay定位点的位置,_x,_y;
  • (3) 紧接着处理“pointermove”事件,通过改变overlay的停靠点的位置,来移动元素;
  • (4) 当触发“pointerup”事件时,终止拖动。
  • 1.创建一个overlay

    1
    
    
    
    
        
    
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import OSM from 'ol/source/OSM';
    import {fromLonLat} from 'ol/proj';
    import TileLayer from 'ol/layer/Tile';
    import View from 'ol/View';
    import Map from 'ol/Map';
    import Overlay from 'ol/Overlay';
    import DragPan from 'ol/interaction/DragPan';

    var pos = fromLonLat([16.3725, 48.208889]);
    var layer = new TileLayer({
    source: new OSM()
    });
    var map = new Map({
    layers: [layer],
    target: 'map',
    view: new View({
    center: pos,
    zoom: 2
    })
    });
    var overlayDom = document.getElementById('marker');
    var overlay = new Overlay({
    position: pos,
    positioning: 'center-center',
    element: overlayDom,
    stopEvent: false,
    dragging: false
    });
    map.addOverlay(marker);

    2.实现可拖动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // overlayDom是overlay的dom
    // overlay是overlay
    // 绑定属性框移动事件
    var dragPan;
    let map=this.mainmap;
    // 获取拖动对象
    map.getInteractions().forEach(function(interaction){
    if (interaction instanceof DragPan) {
    dragPan = interaction;
    }
    });
    // 监听鼠标点击事件
    let offsetXY=[0,0];
    overlayDom.addEventListener('mousedown', function(evt) {
    dragPan.setActive(false);
    overlay.set('dragging', true);
    // 获取事件点击的坐标值
    let evtCoord=map.getEventCoordinate(evt);
    let domCoord=overlay.get("coordinate");
    // 计算鼠标点击位置和基点坐标(可能是div的左上角)之间的偏移量
    offsetXY=[evtCoord[0]-domCoord[0],evtCoord[1]-domCoord[1]];
    });
    // 监听地图鼠标移动事件
    map.on('pointermove', function(evt) {
    if (overlay.get('dragging') === true) {
    // 将当前的鼠标位置减去偏移量,得到基点应该所处的位置
    let coor=[evt.coordinate[0]-offsetXY[0],evt.coordinate[1]-offsetXY[1]];
    overlay.setPosition(coor);
    // 保存最新坐标,因为使用getPostion()方法无法获取overlay的坐标
    overlay.set("coordinate",coor);

    // 绘制虚线
    }
    });
    // 监听鼠标释放事件
    map.on('pointerup', function() {
    if (overlay.get('dragging') === true) {
    dragPan.setActive(true);
    overlay.set('dragging', false);
    }
    });

    参考文章:
    1.
    openlayers 地图上绘制区域悬浮弹窗实现跟随鼠标移动 (这个代码也挺简单的,没有拖动一个div,而是实现了一个可以随着鼠标移动的overlay)
    2. javascript - 我们可以在OpenLayers 3上使ol.Overlay可拖动吗? (这里有一点就是说,ol.Feature可以实现任何事情,所有不要用Overlay)
    3. 关于Openlayers Overlay事件监听的一个坑 (这里其实是一个进行标会的案例,说了自己在开发这么一个功能的时候,遇到的手机端和PC端的问题,对于简单的一个地图PC端拖动来说,其实还是不需要的。因为里面涉及到了一些源码的东西)
    4. 一个可以拖动的Overlay的实例 (这是实现了拖动Overlay的实例,强烈推荐,就是源码,除了没有属性框以及连线,其他的都包括了)
    5. 原生JavaScript实现div拖拽效果 (涉及到一个偏移量的问题,文章中还写道了进行原生拖动的原理)
    6. 用Javascript获取页面元素的位置 (阮一峰的讲解)
    7. js实现可拖拽的div (代码虽小,但是功能都全了)
    8. 使用js拖拽div (大同小异)

    3.绘制链接线

    这个其实有些麻烦的,我感觉。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import VectorLayer from 'ol/layer/Vector';
    import VectorSource from 'ol/source/Vector';

    // 添加连线图层
    let vectorSource = new VectorSource({
    name:"overlayLineLayer_source",
    });
    let vector = new VectorLayer({
    source: vectorSource,
    name:"overlayLineLayer_layer",
    zIndex:15
    });
    map.addLayer(vector);

    其中的feature其实就是对应了Overlayer对应的那个地图图标,就是一个箭头的地方。使用监听的方式,其实是因为地图缩放的时候,会出现的起始点连线不正确的问题,监听地图的rendercomplete,是因为不知道为什么,在第一绘制线段的时候,使用map.getPixelFromCoordinate(stationCoordinate);无法获取到正确的屏幕Pixel。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    let stationGeom=feature.getGeometry();
    let stationCoordinate=stationGeom.getCoordinates(); // 站点坐标
    overlay.set("stationCoordinate",stationCoordinate); // 保存站点坐标
    // 监听地图分辨率改变事件,重新计算指向线的起点位置
    let mapview=map.getView();
    mapview.on("change:resolution",function(){
    // 计算图标顶点的坐标,也就是绘制的连线,应该指向图标的顶点
    // 计算方法,也就是获取图标的旋转角度,获取站点原始坐标,图标的宽高为30x46
    // 根据三角函数,已知斜边,求两个直角标的宽高,就可以使用sin和cos三角函数关系
    // 其中36是图标的不含外边框的高度
    let label=feature.get("label");
    let radian = 0; // 角度转弧度
    let picOffsetX=parseInt(36*Math.sin(radian));
    let picOffsetY=parseInt(36*Math.cos(radian));
    switch(label){
    case 0:
    picOffsetX=0;
    picOffsetY=36;
    break;
    case 90:
    picOffsetX=36;
    picOffsetY=0;
    break;
    case 180:
    picOffsetX=0;
    picOffsetY=-36;
    break;
    case 270:
    picOffsetX=-36;
    picOffsetY=0;
    break;
    default:
    radian = label * (Math.PI/180); // 角度转弧度
    picOffsetX=parseInt(36*Math.sin(radian));
    picOffsetY=parseInt(36*Math.cos(radian));
    break;
    }
    // 获取站点坐标的屏幕像素值,
    // 这里有一个问题,就是当地图第一次加载的时候,会出现stationPixel计算不正确的问题,通过设置地图渲染完成监听事件进行解决
    let stationPixel=map.getPixelFromCoordinate(stationCoordinate);
    // 计算屏幕像素偏移量
    stationPixel=[stationPixel[0]+picOffsetX,stationPixel[1]-picOffsetY];
    // if(feature.get("id")==26){
    // console.log(stationPixel);
    // }
    let offsetCoordinate=map.getCoordinateFromPixel(stationPixel);
    overlay.set("offsetCoordinate",offsetCoordinate); // 也就是偏移点坐标

    // 删除已有的连线
    let lineFeature=overlay.get("line");
    let source=that.overlayLineLayer.getSource();
    if(lineFeature){
    source.removeFeature(lineFeature);
    }
    // 获取最新坐标
    let coor=overlay.get("coordinate");
    if(coor){
    let tempOffset=map.getPixelFromCoordinate(coor);
    tempOffset=[tempOffset[0]+offset[0],tempOffset[1]+offset[1]]
    coor=map.getCoordinateFromPixel(tempOffset);
    // 绘制虚线,从overlay的基点位置,到图标的末点位置
    lineFeature = new Feature({
    geometry: new LineString([coor,offsetCoordinate])
    });
    overlay.set("line",lineFeature);
    source.addFeature(lineFeature);
    }
    });
    // 地图渲染完成之后,绘制第一条连线
    map.once("rendercomplete",function(){
    // 计算图标顶点的坐标,也就是绘制的连线,应该指向图标的顶点
    // 计算方法,也就是获取图标的旋转角度,获取站点原始坐标,图标的宽高为30x46
    // 根据三角函数,已知斜边,求两个直角标的宽高,就可以使用sin和cos三角函数关系
    let label=feature.get("label");
    let radian = 0; // 角度转弧度
    let picOffsetX=parseInt(36*Math.sin(radian));
    let picOffsetY=parseInt(36*Math.cos(radian));
    switch(label){
    case 0:
    picOffsetX=0;
    picOffsetY=36;
    break;
    case 90:
    picOffsetX=36;
    picOffsetY=0;
    break;
    case 180:
    picOffsetX=0;
    picOffsetY=-36;
    break;
    case 270:
    picOffsetX=-36;
    picOffsetY=0;
    break;
    default:
    radian = label * (Math.PI/180); // 角度转弧度
    picOffsetX=parseInt(36*Math.sin(radian));
    picOffsetY=parseInt(36*Math.cos(radian));
    break;
    }
    // 获取站点坐标的屏幕像素值,
    // 这里有一个问题,就是当地图第一次加载的时候,会出现stationPixel计算不正确的问题
    let stationPixel=map.getPixelFromCoordinate(stationCoordinate);
    // 计算屏幕像素偏移量
    stationPixel=[stationPixel[0]+picOffsetX,stationPixel[1]-picOffsetY];
    let offsetCoordinate=map.getCoordinateFromPixel(stationPixel);
    overlay.set("offsetCoordinate",offsetCoordinate); // 也就是偏移点坐标

    // 删除已有的连线
    let lineFeature=overlay.get("line");
    let source=that.overlayLineLayer.getSource();
    if(lineFeature){
    source.removeFeature(lineFeature);
    }
    // 获取最新坐标
    let coor=overlay.get("coordinate");
    if(coor){
    let tempOffset=map.getPixelFromCoordinate(coor);
    tempOffset=[tempOffset[0]+offset[0],tempOffset[1]+offset[1]]
    coor=map.getCoordinateFromPixel(tempOffset);
    // 绘制虚线,从overlay的基点位置,到图标的末点位置
    lineFeature = new Feature({
    geometry: new LineString([coor,offsetCoordinate])
    });
    overlay.set("line",lineFeature);
    source.addFeature(lineFeature);
    }
    });

    拖动绘制虚线的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    // 监听地图鼠标移动事件
    map.on('pointermove', function(evt) {
    if (overlay.get('dragging') === true) {
    // 将当前的鼠标位置减去偏移量,得到基点应该所处的位置
    // 基点位置,即overlay停靠到图标的位置
    let coor=[evt.coordinate[0]-offsetXY[0],evt.coordinate[1]-offsetXY[1]];
    overlay.setPosition(coor);
    // 保存最新坐标,因为使用getPostion()方法无法获取overlay的坐标
    overlay.set("coordinate",coor);


    // 删除已有的连线
    let lineFeature=overlay.get("line");
    let source=that.overlayLineLayer.getSource();
    if(lineFeature){
    source.removeFeature(lineFeature);
    }
    // 计算偏移量,从基点位置,反求停靠点位置
    let tempOffset=map.getPixelFromCoordinate(coor);
    tempOffset=[tempOffset[0]+offset[0],tempOffset[1]+offset[1]]
    coor=map.getCoordinateFromPixel(tempOffset);
    // 绘制虚线,从overlay的基点位置,到图标的末点位置
    let offsetCoordinate=overlay.get("offsetCoordinate");

    if(offsetCoordinate){
    lineFeature = new Feature({
    geometry: new LineString([coor,offsetCoordinate])
    });
    overlay.set("line",lineFeature);
    source.addFeature(lineFeature);
    }

    }
    });

    这样就完成了整个拖动ovlayer并且添加指向线的功能。

    参考文章:
    1.
    Openlayers 3 linedash画虚线 (绘制虚线)