OpenLayers 设置线段样式

34 阅读6分钟

前言

图形绘制是指在地图上绘制点、线、面、圆、矩形等图形。可以通过鼠标单机绘制,也可以键盘按键配合进行绘制。对于绘制的几何图形可以调整线段和端点样式。

1. 图形绘制

本篇文章主要介绍如何设置几何对象线段样式,对于如何进行图形绘制请参考文章OpenLayers 绘制几何对象

2. 创建线段样式结构

在页面中创建线段样式结构并添加其CSS。线段样式可以调整线宽、端点样式、拐点样式、虚线样式以及间隔等。其中端点样式具有三个值:buttroundsquare;拐点样式具有三个值:bevelroundmiter

.stroke-style {
    position: absolute;
    padding: 10px;
    top: 120px;
    left: 100px;
    background-color: #c19b03ab;
    border-radius: 2.5px;
}

.stroke-line-style {
    display: flex;
}

.line-style {
    margin-top: 15px;
    width: 80%;
}

<div class="stroke-style">
    <div class="layui-form">
        <div class="layui-form-item">
            <label class="layui-form-label">端点样式</label>
            <div class="layui-input-block">
                <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="butt" title="butt">
                <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="round" title="round"
                    checked>
                <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="square" title="square">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">拐点样式</label>
            <div class="layui-input-block">
                <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="bevel" title="bevel">
                <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="round" title="round"
                    checked>
                <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="miter" title="miter">
            </div>
        </div>
        <div class="layui-form-item stroke-line-style">
            <label class="layui-form-label">线宽(pixel)</label>
            <div id="stroke-width-value" class="line-style"></div>
        </div>
        <div class="layui-form-item stroke-line-style">
            <label class="layui-form-label">虚线样式</label>
            <div id="line-dash-value" class="line-style"></div>
        </div>
        <div class="layui-form-item stroke-line-style">
            <label class="layui-form-label">虚线偏移</label>
            <div id="line-dash-offset" class="line-style"></div>
        </div>
    </div>
</div>

3. 重设样式

创建重设样式方法,在该方法中传递样式对象,然后同构解构该对象生成样式对象,在添加新的样式图层前将原来的图层移除。

function setStyle(styleObj{
    const { width, lineCap, lineJoin, lineDash, lineDashOffset } = styleObj
    map.removeLayer(vectorLayer)
    const style new ol.style.Style({
        fillnew ol.style.Fill({
            color"#9b65ff30"
        }),
        strokenew ol.style.Stroke({
            color"yellow",
            width: width || lineWidth,
            lineCap: lineCap || 'round',
            lineJoin: lineJoin || 'round',
            lineDash: lineDash || lineDash,
            lineDashOffset: lineDashOffset || 0
        })
    })
    vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style: style
    })
    map.addLayer(vectorLayer)
}

4. 监听滑块事件

监听滑块移动事件,在滑块值发生改变时调用重设样式方法。

let lineWidth = 2.5
let lineDash = [30405060]
layui.use(function ({
    const slider = layui.slider;
    // 线条宽度
    slider.render({
        elem'#stroke-width-value',
        value5, //初始值
        change: function (value) {
            lineWidth = value
            const styleObj = {
                width: lineWidth
            }
            setStyle(styleObj)
        }
    });
    // 虚线间隔
    slider.render({
        elem'#line-dash-value',
        value0, //初始值
        change: function (value) {
            lineDash = [value, 405060]
            const styleObj = {
                lineDash: lineDash
            }
            setStyle(styleObj)
        }
    });
    // 偏移值
    slider.render({
        elem'#line-dash-offset',
        value0, //初始值
        change: function (value) {
            const styleObj = {
                lineDashOffset: value
            }
            setStyle(styleObj)
        }
    });
});

5. 监听单选框事件

监听单选框事件,获取单选框点击值然后调用重设样式函数。

layui.use(function () {
    const form = layui.form;
    const layer = layui.layer;
    // radio 事件
    form.on('radio(cap-radio-filter)', function (data) {
        const elem = data.elem; // 获得 radio 原始 DOM 对象
        const checked = elem.checked; // 获得 radio 选中状态
        const value = elem.value; // 获得 radio 值
        const styleObj = {
            lineCap: value
        }
        setStyle(styleObj)
    })

    form.on('radio(join-radio-filter)', function (data) {
        const elem = data.elem; // 获得 radio 原始 DOM 对象
        const checked = elem.checked; // 获得 radio 选中状态
        const value = elem.value; // 获得 radio 值
        const styleObj = {
            lineJoin: value
        }
        setStyle(styleObj)
    })
});

6. 完整代码

其中libs文件夹下的包需要更换为自己下载的本地包或者引用在线资源。

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>OpenLayers 线段样式</title>
    <meta charset="utf-8" />

    <link rel="stylesheet" href="../../libs/css/ol9.2.4.css">
    <link rel="stylesheet" href="../../libs/layui/css/layui.css">

    <script src="../../js/config.js"></script>
    <script src="../../js/util.js"></script>
    <script src="../../libs/js/ol9.2.4.js"></script>
    <script src="../../libs/layui/layui.js"></script>
    <style>
        * {
            padding0;
            margin0;
            font-size14px;
            font-family'微软雅黑';
        }

        html,
        body {
            width100%;
            height100%;
        }

        #map {
            position: absolute;
            top50px;
            bottom0;
            width100%;
        }

        #top-content {
            position: absolute;
            width100%;
            height50px;
            line-height50px;
            backgroundlinear-gradient(135deg#ff00cc#ffcc00#00ffcc#ff0066);
            color#fff;
            text-align: center;
            font-size32px;
        }

        #top-content span {
            font-size32px;
        }

        .draw-shape {
            position: absolute;
            padding5px;
            top60px;
            left100px;
            background-color#ffcc00ad;
            border-radius2.5px;
        }

        .draw-ul {
            list-style-type: none;
        }

        .draw-ul::after {
            display: block;
            clear: both;
            content"";
        }

        .draw-li {
            float: left;
            padding5px;
            margin0 5px;
            min-width50px;
            background-color: azure;
            background#cae4cf82;
            transition: background-color 10s ease-in-out 10s;
            text-align: center;
            border-radius2.5px;
            transition: color ease-in-out 0.25s;
        }

        .draw-li:hover {
            cursor: pointer;
            color#fff;
            filterbrightness(120%);
            backgroundlinear-gradient(135deg#c850c0#4158d0);
        }

        .active {
            color#fff;
            backgroundlinear-gradient(135deg#c850c0#4158d0);
        }

        .stroke-style {
            position: absolute;
            padding10px;
            top120px;
            left100px;
            background-color#c19b03ab;
            border-radius2.5px;
        }

        .stroke-line-style {
            display: flex;
        }

        .line-style {
            margin-top15px;
            width80%;
        }
    </style>
</head>

<body>
    <div id="top-content">
        <span>OpenLayers 线段样式</span>
    </div>
    <div id="map" title="地图显示"></div>
    <div class="draw-shape">
        <ul class="draw-ul">
            <li class="draw-li" data-type="LineString">线</li>
            <li class="draw-li" data-type="Polygon">多边形</li>
            <li class="draw-li" data-type="Square">正方形</li>
            <li class="draw-li" data-type="Box">矩形</li>
            <li class="draw-li" data-type="None">清除</li>
        </ul>
    </div>
    <div class="stroke-style">
        <div class="layui-form">
            <div class="layui-form-item">
                <label class="layui-form-label">端点样式</label>
                <div class="layui-input-block">
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="butt" title="butt">
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="round" title="round"
                        checked>
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="square" title="square">
                </div>
            </div>
            <div class="layui-form-item">
                <label class="layui-form-label">拐点样式</label>
                <div class="layui-input-block">
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="bevel" title="bevel">
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="round" title="round"
                        checked>
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="miter" title="miter">
                </div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">线宽(pixel)</label>
                <div id="stroke-width-value" class="line-style"></div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">虚线样式</label>
                <div id="line-dash-value" class="line-style"></div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">虚线偏移</label>
                <div id="line-dash-offset" class="line-style"></div>
            </div>
        </div>
    </div>
</body>

</html>

<script>
    //地图投影坐标系
    const projection = ol.proj.get('EPSG:3857');
    //==============================================================================//
    //============================天地图服务参数简单介绍==============================//
    //================================vec:矢量图层==================================//
    //================================img:影像图层==================================//
    //================================cva:注记图层==================================//
    //======================其中:_c表示经纬度投影,_w表示球面墨卡托投影================//
    //==============================================================================//
    const TDTImgLayer = new ol.layer.Tile({
        title"天地图影像图层",
        sourcenew ol.source.XYZ({
            url"http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions"天地图影像描述",
            crossOrigin"anoymous",
            wrapXfalse
        })
    })
    const TDTImgCvaLayer = new ol.layer.Tile({
        title"天地图影像注记图层",
        sourcenew ol.source.XYZ({
            url"http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions"天地图注记描述",
            crossOrigin"anoymous",
            wrapXfalse
        })
    })
    const map = new ol.Map({
        target"map",
        loadTilesWhileInteractingtrue,
        viewnew ol.View({
            center: [102.84586425.421639],
            zoom5,
            worldsWrapfalse,
            minZoom1,
            maxZoom20,
            projection'EPSG:4326',
        }),
        layers: [TDTImgLayer]
    })

    const style = new ol.style.Style({
        fillnew ol.style.Fill({
            color"#9b65ff30"
        }),
        strokenew ol.style.Stroke({
            color"yellow",
            width5,
            lineCap'round',
            lineJoin'round',
            lineDash: [20304050],
            lineDashOffset0
        }),
        imagenew ol.style.Circle({
            fillnew ol.style.Fill({
                color"#fff"
            }),
            radius5,
            strokenew ol.style.Stroke({
                color"blue",
                width1,
            })
        })
    })
    const vectorSource = new ol.source.Vector({ wrapXfalse })
    let vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style
    })
    map.addLayer(vectorLayer)
    let drawInteraction = null
    /**
     * 根据几何类型绘制几何对象
     */
    function drawShape(type) {
        if (type === "None") {
            removeInteraction()
            // 清除图形
            vectorSource.clear()
            removeAllActiveClass(".draw-ul""active")
            return
        }
        let geometryFunction = null
        switch (type) {
            case "Square":
                type = "Circle"
                geometryFunction = ol.interaction.Draw.createRegularPolygon(4)
                break
            case "Box":
                type = "Circle"
                geometryFunction = ol.interaction.Draw.createBox()
                break
        }
        drawInteraction = new ol.interaction.Draw({
            source: vectorSource,
            type,
            geometryFunction,
            style,
            // freehand: true // 是否开启自由绘制模式
        })
        map.addInteraction(drawInteraction)
    }

    // 事件委托
    const targetEle = document.querySelector(".draw-ul")
    targetEle.addEventListener('click'evt => {
        removeInteraction()
        const targetEle = evt.target
        const geomType = targetEle.dataset.type
        if (geomType !== "None") {
            toogleAciveClass(targetEle, ".draw-ul")
        }
        if (geomType) {
            drawShape(geomType)
        }
    })

    // 移除绘制控件
    function removeInteraction() {
        if (drawInteraction) {
            map.removeInteraction(drawInteraction)
        }
    }
    let lineWidth = 2.5
    let lineDash = [30405060]
    layui.use(function () {
        const slider = layui.slider;
        // 线条宽度
        slider.render({
            elem'#stroke-width-value',
            value5//初始值
            changefunction (value) {
                lineWidth = value
                const styleObj = {
                    width: lineWidth
                }
                setStyle(styleObj)
            }
        });
        // 虚线间隔
        slider.render({
            elem'#line-dash-value',
            value0//初始值
            changefunction (value) {
                lineDash = [value, 405060]
                const styleObj = {
                    lineDash: lineDash
                }
                setStyle(styleObj)
            }
        });
        // 偏移值
        slider.render({
            elem'#line-dash-offset',
            value0//初始值
            changefunction (value) {
                const styleObj = {
                    lineDashOffset: value
                }
                setStyle(styleObj)
            }
        });
    });

    layui.use(function () {
        const form = layui.form;
        const layer = layui.layer;
        // radio 事件
        form.on('radio(cap-radio-filter)'function (data) {
            const elem = data.elem// 获得 radio 原始 DOM 对象
            const checked = elem.checked// 获得 radio 选中状态
            const value = elem.value// 获得 radio 值
            const styleObj = {
                lineCap: value
            }
            setStyle(styleObj)
        })

        form.on('radio(join-radio-filter)'function (data) {
            const elem = data.elem// 获得 radio 原始 DOM 对象
            const checked = elem.checked// 获得 radio 选中状态
            const value = elem.value// 获得 radio 值
            const styleObj = {
                lineJoin: value
            }
            setStyle(styleObj)
        })
    });

    function setStyle(styleObj) {
        const { width, lineCap, lineJoin, lineDash, lineDashOffset } = styleObj
        map.removeLayer(vectorLayer)
        const style = new ol.style.Style({
            fillnew ol.style.Fill({
                color"#9b65ff30"
            }),
            strokenew ol.style.Stroke({
                color"yellow",
                width: width || lineWidth,
                lineCap: lineCap || 'round',
                lineJoin: lineJoin || 'round',
                lineDash: lineDash || lineDash,
                lineDashOffset: lineDashOffset || 0
            })
        })
        vectorLayer = new ol.layer.Vector({
            source: vectorSource,
            style: style
        })
        map.addLayer(vectorLayer)
    }
</script>

OpenLayers示例数据下载,请回复关键字:ol数据

全国信息化工程师-GIS 应用水平考试资料,请回复关键字:GIS考试

【GIS之路】 已经接入了智能助手,欢迎关注,欢迎提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注 !