iT邦幫忙

0

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

  • 分享至 

  • xImage
  •  

https://openlayers.org/en/latest/examples/measure-style.html

控制測量工具Day08是透過overlay來標記,所以可以用css控制
本篇是透過feature style來控制顯示的樣式

HTML

只有新增控制label的checkbox開關

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <script src="https://cdn.jsdelivr.net/npm/ol@v8.2.0/dist/ol.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v8.2.0/ol.css">

    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div id="map"></div>
    // 開關
    <label for="segments" id="segments-label">
        <input type="checkbox" id="segments" checked />
        隱藏或開啟label
    </label>
    <script type="module" src="./main.js"></script>
</body>

</html>

CSS

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

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

#segments-label {
    position: absolute;
    top: 10px;
    right: 10px;
}

JS

特別注意styleFunction中是如何控制點的顯示,通篇重點我認為應該是這個funciton的理解,其餘都只是針對樣式或顏色的配置

const 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)',
        }),
    }),
});

const labelStyle = new ol.style.Style({
    text: new ol.style.Text({
        font: '25px Calibri,sans-serif',
        fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 1)',
        }),
        backgroundFill: new ol.style.Fill({
            color: 'rgba(0, 0, 0, 0.7)',
        }),
        padding: [3, 3, 3, 3],
        textBaseline: 'bottom',
        offsetY: -15,
    }),
    image: new ol.style.RegularShape({
        radius: 8,
        points: 3,
        angle: Math.PI,
        displacement: [0, 10],
        fill: new ol.style.Fill({
            color: 'rgba(0, 0, 0, 0.7)',
        }),
    }),
});

const segmentStyle = new ol.style.Style({
    text: new ol.style.Text({
        font: '20px Calibri,sans-serif',
        fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 1)',
        }),
        backgroundFill: new ol.style.Fill({
            color: 'rgba(0, 0, 0, 0.4)',
        }),
        padding: [2, 2, 2, 2],
        textBaseline: 'bottom',
        offsetY: -12,
    }),
    image: new ol.style.RegularShape({
        radius: 6,
        points: 3,
        angle: Math.PI,
        displacement: [0, 8],
        fill: new ol.style.Fill({
            color: 'rgba(0, 0, 0, 0.4)',
        }),
    }),
});

const segmentStyles = [segmentStyle];

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;
};

const source = new ol.source.Vector();

function styleFunction(feature, segments, drawType) {
    const styles = [];
    const geometry = feature.getGeometry();
    const type = geometry.getType();
    let point, label, line;
    if (!drawType || drawType === type || type === 'Point') {
        styles.push(style);
        if (type === 'LineString') {
            point = new ol.geom.Point(geometry.getLastCoordinate());
            label = formatLength(geometry);
            line = geometry;
        }
    }

    // 線段中間
    if (segments && line) {
        let count = 0;
        //不斷計算線段長度
        line.forEachSegment(function (a, b) {
            const segment = new ol.geom.LineString([a, b]);
            const label = formatLength(segment);
            if (segmentStyles.length - 1 < count) {
                segmentStyles.push(segmentStyle.clone());
            }
            const segmentPoint = new ol.geom.Point(segment.getCoordinateAt(0.5)); // 指定線段中間的位置標記
            segmentStyles[count].setGeometry(segmentPoint);
            segmentStyles[count].getText().setText(label);
            styles.push(segmentStyles[count]);
            count++;
        });
    }

    // 最後一點的位置標記
    if (label) {
        labelStyle.setGeometry(point);
        labelStyle.getText().setText(label);
        styles.push(labelStyle);
    }
    return styles;
}

const vector = new ol.layer.Vector({
    source: source,
    style: function (feature) {
        return styleFunction(feature, showSegments.checked);
    },
});

const map = new ol.Map({
    layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM()
        }),
        vector
    ],
    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: []
});


let draw; // global so we can remove it later

function addInteraction() {
    const drawType = 'LineString';
    draw = new ol.interaction.Draw({
        source: source,
        type: drawType,
        style: function (feature) {
            return styleFunction(feature, showSegments.checked, drawType);
        },
    });
    draw.on('drawstart', function () {
        source.clear();
    });
    map.addInteraction(draw);
}

addInteraction();

const showSegments = document.getElementById('segments');
showSegments.onchange = function () {
    vector.changed();
    draw.getOverlay().changed();
};

如果成功右上可以看到控制開關,自己玩玩看吧,成果如下圖
https://ithelp.ithome.com.tw/upload/images/20240308/20165487fhGJ6C8swl.png

結論

依據這兩天的操作,我們可以學到兩種控制的方式

  • Overlay放置點
    • 這不只是可以應用在這種顯示,因為是HTML的格式,所以只要與HTML有關的我們都可以操作
  • style function
    • 可以深度控制樣式,不過缺點是需要去爬API到底提供哪種參數可以使用

我個人更喜歡第二種透過style function控制,因這樣可以讓我們的樣式更自由。

參考

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


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

尚未有邦友留言

立即登入留言