# 可拖拽弹窗

🥡

有时间在整理

<template>
    <div id="mapcontainer" class="mapcontainer"></div>
    <div id="popup" ref="popupRef">
        <div class="popupStyle">该弹窗可拖拽</div>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { Map, View, Overlay, Feature } from "ol"; // 地图实例方法、视图方法
import { Style, Stroke, Icon } from "ol/style";
import { LineString, Point } from "ol/geom";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import DragPan from 'ol/interaction/DragPan'; // 拖拽交互

import marker from '@/assets/markers/marker.png'

import {
    overlay,
    mousePosition
} from './mapconfig.js'

import "ol/ol.css"; // 地图样式

const map = ref(null); // 存放地图实例
const popupRef = ref(null) // 弹窗ref
const popupOverlay = ref(null) // 弹窗实例

// 添加marker Point
let iconFeature = null;
let lineFeature = null;
const addPointMarker = (coordinate = [104.03228, 30.72147]) => {
    // marker
    iconFeature = new Feature({
        geometry: new Point(coordinate),
        featureType: 'marker'
    });
    const iconStyle = new Style({
        image: new Icon({
            anchor: [0.5, 46],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: marker,
            scale: 0.3
        })
    });
    iconFeature.setStyle(iconStyle);

    // line 
    lineFeature = new Feature({
        geometry: new LineString([])
    });
    var lineStyle = new Style({
        stroke: new Stroke({
            color: '#ffcc33',
            width: 3,
            lineDash: [10, 10]
        })
    });

    var vectorSource = new VectorSource({
        features: [iconFeature, lineFeature]  // 组合要素 也可以使用addFeature方法
    });

    var vectorLayer = new VectorLayer({
        source: vectorSource,
        style: [lineStyle],
        updateWhileInteracting: true, // 自动更新位置
    });

    map.value.addLayer(vectorLayer);
}

const addPopup = (coordinate = [104.03228, 30.72147]) => {
    popupOverlay.value = new Overlay({
        element: popupRef.value,
        positioning: 'bottom-center',
        stopEvent: false,
        dragging: false,
        offset: [90, -90]
    });

    popupOverlay.value.setPosition(coordinate);
    map.value.addOverlay(popupOverlay.value);
}

var dragPan;
const inintMap = () => {
    map.value = new Map({
        target: "mapcontainer", // 对应页面里 id 为 map 的元素
        layers: [overlay],
        view: new View({
            projection: "EPSG:4326",
            center: [104.03228760, 30.72147313], // 地图中心点
            minZoom: 12, // 地图缩放最小级别
            maxZoom: 18, // 地图缩放最大级别
            zoom: 14, // 地图缩放级别(打开页面时默认级别)
        }),
        overlays: [],
        controls: [mousePosition]
    })

    map.value.getInteractions().forEach(function (interaction) {
        if (interaction instanceof DragPan) {
            dragPan = interaction;
        }
    });

    popupRef.value.addEventListener('mousedown', function (evt) {
        dragPan.setActive(false);
        popupOverlay.value.set('dragging', true);
        console.info('start dragging');
    });

    map.value.on('pointermove', function (evt) {
        var startPoint = iconFeature.getGeometry().getCoordinates();
        if (popupOverlay.value && popupOverlay.value.get('dragging')) {
            var dd2 = map.value.getPixelFromCoordinate(evt.coordinate);
            var newX = dd2[0] - 90; // 减去偏移量
            var newY = dd2[1] - (-90);
            var newPoint = map.value.getCoordinateFromPixel([newX, newY]);
            popupOverlay.value.setPosition(newPoint);
            lineFeature.getGeometry().setCoordinates([startPoint, evt.coordinate]);
        }
    });
    map.value.on('pointerup', function (evt) {
        if (popupOverlay.value && popupOverlay.value.get('dragging') === true) {
            console.info('stop dragging');
            dragPan.setActive(true);
            popupOverlay.value.set('dragging', false);
        }
    });
    mapClick()
}

// 地图点击事件
const mapClick = () => {
    map.value.on("singleclick", (evt) => {
        const feature = map.value.forEachFeatureAtPixel(
            evt.pixel,
            function (feature) {
                return feature;
            }
        );
        // 点击图标才出现信息框
        if (feature && feature.values_.featureType === "marker") {
            let featureCoordinate = iconFeature.getGeometry().getCoordinates();
            addPopup(featureCoordinate)  // 添加信息框
            var dd2 = map.value.getPixelFromCoordinate(featureCoordinate);
            var newX = dd2[0] + 90; // 加上偏移量
            var newY = dd2[1] - 90;
            let endLineCoordinate = map.value.getCoordinateFromPixel([newX, newY]);
            lineFeature.getGeometry().setCoordinates([featureCoordinate, endLineCoordinate]);
        } else {
            popupOverlay.value.setPosition(null);
            lineFeature.getGeometry().setCoordinates([]);
        }
    });
};

onMounted(() => {
    inintMap()
    addPointMarker() // 添加点标记
})
</script>


<style lang="scss" scoped>
#mapcontainer {
    position: relative;
    width: 100%;
    height: 100vh
}

#popup {
    cursor: pointer;
}

.popupStyle {
    position: relative;
    width: 100px;
    height: 100px;
    text-align: center;
    line-height: 100px;
    color: white;
    background-color: rgba(0, 0, 0, 0.4);
}
</style> 
Last Updated: 8/6/2022, 5:22:46 PM