iT邦幫忙

0

【Day08】Openlayers從入門到微精通 - 動動你的手來量測地球1

  • 分享至 

  • xImage
  •  

參考文章
https://openlayers.org/en/latest/examples/measure.html

跟官網的範例比較,我有把一些我認為比較會會的地方給抽調,因為範例中是增加了下拉選單可以選擇多邊形或是線段的繪製

我認為主要的概念是

  • 建立繪圖專用的的layer
  • Interaction是要與繪圖專用layer共用source (這點很重要)
  • openlayers中可以建立監聽事件,API中可以查詢參考
    • 此範例中就用上Geometry的change與Draw的drawstart、drawend
  • Overlay是一個可以在地圖上放置HTML標記的功能
    • 我自己是這樣理解,如果大家有其他想法歡迎分享
    • 這可能有點太早說了,但就......剛好想講這個主題

JS

const map = new ol.Map({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        })
    ],
    target: 'map',
    view: new ol.View({
        projection: "EPSG:3857",
        center: ol.proj.fromLonLat([120.846642, 23.488793]),
        zoom: 7.5,
        maxZoom: 20,
        minZoom: 5,
        enableRotation: false,
    }),
    controls: []
});

// 1.source共用
const source = new ol.source.Vector();
const vector = new ol.layer.Vector({
    source: source,
    style: {
        'fill-color': 'rgba(255, 255, 255, 0.2)',
        'stroke-color': '#ffcc33',
        'stroke-width': 2,
        'circle-radius': 7,
        'circle-fill-color': '#ffcc33',
    },
});
map.addLayer(vector)

// Currently drawn feature.
let sketch;
// The measure tooltip element.
let measureTooltipElement;
// Overlay to show the measurement.
let measureTooltip;

// 計算距離
const formatLength = function (line) {
    const length = ol.sphere.getLength(line);
    let output;
    if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km';
    } else {
        output = Math.round(length * 100) / 100 + ' ' + 'm';
    }
    return output;
};

// 增加互動
function addInteraction() {
    let draw = new ol.interaction.Draw({
        // 1.source共用
        source: source,
        type: 'LineString',
        style: new ol.style.Style({
            fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 0.2)',
            }),
            stroke: new ol.style.Stroke({
                color: 'rgba(0, 0, 0, 0.5)',
                lineDash: [10, 10],
                width: 2,
            }),
            image: new ol.style.Circle({
                radius: 5,
                stroke: new ol.style.Stroke({
                    color: 'rgba(0, 0, 0, 0.7)',
                }),
                fill: new ol.style.Fill({
                    color: 'rgba(255, 255, 255, 0.2)',
                }),
            }),
        }),
    });
    map.addInteraction(draw);

    createMeasureTooltip();

    let listener;
    draw.on('drawstart', function (evt) {
        // set sketch
        sketch = evt.feature;
        let tooltipCoord = evt.coordinate;

        listener = sketch.getGeometry().on('change', function (evt) {
            const geom = evt.target;
            let output = formatLength(geom);
            tooltipCoord = geom.getLastCoordinate();
            measureTooltipElement.innerHTML = output; // 顯示計算完的長度
            measureTooltip.setPosition(tooltipCoord); // 更新提示框的位置
        });
    });

    draw.on('drawend', function () {
        measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
        measureTooltip.setOffset([0, -7]);
        // unset sketch
        sketch = null;
        // unset tooltip so that a new one can be created
        measureTooltipElement = null;
        createMeasureTooltip();
        ol.Observable.unByKey(listener);
    });
}

// 顯示測量距離
function createMeasureTooltip() {
    if (measureTooltipElement) {
        measureTooltipElement.parentNode.removeChild(measureTooltipElement);
    }
    measureTooltipElement = document.createElement('div');
    measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
    measureTooltip = new ol.Overlay({
        element: measureTooltipElement,
        offset: [0, -15],
        positioning: 'bottom-center',
        stopEvent: false,
        insertFirst: false,
    });
    map.addOverlay(measureTooltip);
}

addInteraction();

CSS

這段css是參考官網的,主要也要回應我提到的Overlay,因為是HTML元素放到地圖上,所以可以透過css來控制
createMeasureTooltip的function中特別指定自己想要客製化的class名稱,如此一來可以更多元的操控Overlay的樣子

html,
body {
    margin: 0;
    padding: 0;
}

#map {
    width: 100vw;
    height: 100vh;
}

.ol-tooltip {
    position: relative;
    background: rgba(0, 0, 0, 0.5);
    border-radius: 4px;
    color: white;
    padding: 4px 8px;
    opacity: 0.7;
    white-space: nowrap;
    font-size: 12px;
    cursor: default;
    user-select: none;
}

.ol-tooltip-measure {
    opacity: 1;
    font-weight: bold;
}

.ol-tooltip-static {
    background-color: #ffcc33;
    color: black;
    border: 1px solid white;
}

.ol-tooltip-measure:before,
.ol-tooltip-static:before {
    border-top: 6px solid rgba(0, 0, 0, 0.5);
    border-right: 6px solid transparent;
    border-left: 6px solid transparent;
    content: "";
    position: absolute;
    bottom: -6px;
    margin-left: -7px;
    left: 50%;
}

.ol-tooltip-static:before {
    border-top-color: #ffcc33;
}

參考網址

https://github.com/weijung0923/learning-openlayers-micromastery/tree/day08


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言