OpenLayers 图文标注大全

前言

要素标注是一个常用功能,就是将要素信息如名称等显示在地图上,方便查找和使用。在OpenLayers中要素标注很灵活,使用起来也很方便,可以修改标注样式以及标注权限。

在本文中主要介绍图文标注详细信息,包括旋转缩放和偏移等。

1. 创建标注点及样式

在创建标注点之前需要先获取位置坐标数据,通过监听map对象单击事件可以得到点坐标数据。

arduino 复制代码
map.on('click', evt => {
    console.log("获取地图坐标:", evt.coordinate)
})

还需要提前准备好图片数据,然后根据坐标点创建几何对象,再由几何对象创建点要素,最后创建要素样式和点图层。对于要素类对象,可以通过setStyle方法重写图层样式,该方法参数可以是单个样式对象,也可以是样式数组对象或者接受分辨率并返回样式数组的函数。最后设置标注点为视图中心。

php 复制代码
const pointGeometry = new ol.geom.Point([100.9788433214299, 26.747704222514738])
const feature = new ol.Feature({
    geometry: pointGeometry
})
const vectotSource = new ol.source.Vector({
    features: [feature],
    wrapX: false
})
const iconStyle = new ol.style.Style({
    image: new ol.style.Icon({
        src: "../../image/label/simple_map.jpg",
        scale: [1 / 16, 1 / 16],
        // anchor: [0.5, 1.25]
    }),
    text: new ol.style.Text({
        font: "16px sans-serif",
        textAlign: "center",
        text: "Hello,World",
        fill: new ol.style.Fill({
            color: [255, 215, 0, 1],
        }),
        backgroundFill: new ol.style.Fill({
            color: [0, 191, 255, 0.25]
        }),
        offsetY: -30, // 向Y轴偏移
        padding: [10, 10, 10, 10]
    })
})
const featureStyle = new ol.style.Style({
    image: new ol.style.Circle({
        radius: 10,
        fill: new ol.style.Fill({
            color: "#fff"
        }),
        stroke: new ol.style.Stroke({
            color: "red"
        })
    })
})
feature.setStyle([iconStyle, featureStyle])
const vectorLayer = new ol.layer.Vector({
    source: vectotSource
})
map.addLayer(vectorLayer)
// 设置标注点为视图中心
map.getView().setCenter(pointGeometry.getCoordinates())

2. 视图旋转

监听滑块事件,设置视图旋转。setRotation参数接收弧度值,所以需要将度数转换为弧度。

php 复制代码
// 视图旋转事件
slider.render({
    // 顺时针旋转,弧度单位
    elem: '#view-rotate',
    value: 0,
    min: 0,
    max: 360,
    step: 5,
    change: function (value) {
        map.getView().setRotation(value * Math.PI / 180)
    }
});

监听图片文本跟随视图旋转事件: 监听开关事件,并在值改变时通过setRotateWithView方法设置是否开启跟随视图旋转。该方法接收参数为布尔值。

javascript 复制代码
// 图片跟随视图旋转事件
form.on('switch(image-box-filter)', function (data) {
    const elem = data.elem; // 获得 checkbox 原始 DOM 对象
    const checked = elem.checked; // 获得 checkbox 选中状态
    iconStyle.getImage().setRotateWithView(checked)
});
// 文本跟随视图旋转事件
form.on('switch(text-box-filter)', function (data) {
    const elem = data.elem; // 获得 checkbox 原始 DOM 对象
    const checked = elem.checked; // 获得 checkbox 选中状态
    iconStyle.getText().setRotateWithView(checked)
});

3. 监听图片文本事件

layui组件中调用slider.render方法创建滑块,然后配置最大最小值等参数,在change事件中,监听滑块值变化并更改要素标注样式。注意:在改变要素样式后,要素对象需立即调用changed方法通知Feature,说明样式已经被改变了。**layui**滑块配置[https://layui.dev/docs/2/slider/](https://layui.dev/docs/2/slider/)

php 复制代码
// 图片旋转事件
slider.render({
    // 顺时针旋转,弧度单位
    elem: '#imageRotation',
    value: 0,
    min: 0,
    max: 360,
    step: 5,
    change: function (value) {
        iconStyle.getImage().setRotation(value * Math.PI / 180)
        feature.changed()
    }
});
// 文本旋转事件
slider.render({
    // 顺时针旋转,弧度单位
    elem: '#textRotation',
    value: 0,
    min: 0,
    max: 360,
    step: 5,
    change: function (value) {
        iconStyle.getText().setRotation(value * Math.PI / 180)
        feature.changed()
    }
});

4. 属性介绍

4.1. Icon

Icon类用于设置要素类图标样式。其属性信息如下表。

| 属性名 | 类型 | 描述 |
|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------|-----------|--------|
| anchor | Array. (defaults to [0.5, 0.5]) | 锚点,默认值图标中心 |
| anchorOrigin | IconOrigin (defaults to 'top-left') | 锚点原点: bottom-left, bottom-right, top-left or top-right |
| anchorXUnits | IconAnchorUnits (defaults to 'fraction') | X轴锚点单位,可以是分数或者像素 |
| anchorYUnits | IconAnchorUnits (defaults to 'fraction') | Y轴锚点单位,可以是分数或者像素 |
| color | Color | string | undefined | 设置图片颜色 |
| img | HTMLImageElement | HTMLCanvasElement | ImageBitmap | undefined | 图标图片对象 |
| displacement | Array. (defaults to [0, 0]) | 图标位移像素。正值将使图标向右和向上移动。 |
| opacity | number (defaults to 1) | 图标透明度 |
| width | number | undefined | 图标宽度(像素),不能与scale一起使用 |
| height | number | undefined | 图标高度(像素),不能与scale一起使用 |
| scale | number | Size (defaults to 1) | 缩放比例 |
| rotateWithView | boolean (defaults to false) | 是否跟随视图旋转 |
| rotation | number (defaults to 0) | 旋转(弧度) |
| offset | Array. (defaults to [0, 0]) | 偏移 |
| offsetOrigin | IconOrigin(defaults to 'top-left') | 偏移原点: bottom-left, bottom-right, top-left or top-right. |
| size | Size | undefined | 图标大小(像素) |
| src | string | undefined | 图片url |
| declutterMode | DeclutterMode | undefined | 分离模式(压盖处理) |

4.2. Text

Text类为矢量要素设置文本样式。其属性信息如下表。

| 属性名 | 类型 | 描述 |
|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|--------|
| font | string | undefined | css 字体样式值 |
| maxAngle | number (defaults to Math.PI/4) | 当放置设置为"行"时,允许相邻字符之间的最大角度。预期值以弧度为单位,默认值为45° |
| offsetX | number (defaults to 0) | 水平偏移量(像素),正值向右 |
| offsetY | number (defaults to 0) | 竖直偏移量(像素),正值向下 |
| overflow | boolean (defaults to false) | 对于多边形标签或当放置设置为"线"时,允许文本超过标签位置处多边形的宽度或其遵循的路径的长度。 |
| placement | TextPlacement (defaults to 'point') | 文本方式模式 |
| repeat | number | undefined | 重复间隔。设置后,文本将以该间隔重复,该间隔指定了两个文本锚点之间的像素距离。仅当放置设置为"行"时可用。覆盖"textAlign"。 |
| scale | number | Size | undefined | 缩放比例 |
| rotateWithView | boolean (defaults to false) | 是否跟随视图旋转 |
| rotation | number (defaults to 0) | 旋转(弧度),正值顺时针方向 |
| text | string | Array. | undefined | 文本内容 |
| textAlign | CanvasTextAlign | undefined | 文本框对齐方式 |
| justify | TextJustify | undefined | 文本框内文本对齐方式 |
| textBaseline | CanvasTextBaseline (defaults to 'middle') | 文本基线 |
| fill | Fill | null | undefined | 文本填充样式 |
| stroke | Stroke | undefined | 文本描边样式 |
| backgroundFill | Fill | undefined | 文本框背景颜色 |
| backgroundStroke | Stroke | undefined | 文本框背景描边颜色 |
| padding | Array. (defaults to [0, 0, 0, 0]) | 文本框内边距 |
| declutterMode | DeclutterMode | undefined | 文本压盖模式 |

5. 完整代码

其中libs文件夹下的包需要更换为自己下载的本地包或者引用在线资源。本示例引用了layui组件,请自行替换。

xml 复制代码
<!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="../../libs/js/proj4.js"></script>
    <script src="../../libs/js/ol9.2.4.js"></script>
    <script src="../../libs/layui/layui.js"></script>
    <script src="../../libs/js/geotiff.min.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
            font-size: 14px;
            font-family: '微软雅黑';
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        #map {
            position: absolute;
            top: 50px;
            bottom: 0;
            width: 100%;
        }

        #top-content {
            position: absolute;
            width: 100%;
            height: 50px;
            line-height: 50px;
            background: linear-gradient(135deg, #ff00cc, #ffcc00, #00ffcc, #ff0066);
            color: #fff;
            text-align: center;
            font-size: 32px;
        }

        #top-content span {
            font-size: 32px;
        }

        #layer-container {
            position: absolute;
            top: 10%;
            left: 20px;
            width: 30%;
            bottom: 5%;
            background: #fff;
            border-radius: 2.5px;
            border: 1px solid #ddd;
            overflow-y: scroll;
            max-height: 80%;
        }

        .layer-head {
            background: #16baaa;
            padding: 10px;
            margin-bottom: 15px;
        }

        .label-style {}

        .image-style-content {
            margin: 5px 25px;
        }

        .text-title {
            padding: 10px;
            margin-bottom: 15px;
            background: #16baaa;
            color: #fff;
        }

        .image-title {
            padding: 10px;
            margin-bottom: 15px;
            background: #16baaa;
            color: #fff;
        }

        .layer-prop-item {
            display: flex;
            justify-content: space-between;
            flex-direction: row;
            margin: 10px 0;
        }

        .layer-slider-item {
            width: 45%;
            margin-top: 16px;
        }

        .layui-form-label {
            width: 50%;
            padding: 8px 15px;
            height: 38px;
            line-height: 20px;
            border-width: 1px;
            border-style: solid;
            border-radius: 2px 0 0 2px;
            text-align: center;
            background-color: #fafafa;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            box-sizing: border-box;
            border-color: #eee;
            font-weight: 400;
        }

        .map-rotate {
            position: absolute;
            right: 20px;
            top: 100px;
            padding: 10px 20px;
            width: 250px;
            background: #fff;
            border-radius: 5px;
            box-shadow: 5px 6px 6px 2px #29292975;
        }

        .view-slider-item {
            margin-top: 8px;
            width: 70%;
        }
    </style>
</head>

<body>
    <div id="top-content">
        <span>OpenLayers 图文标注大全</span>
    </div>
    <div id="map" title="地图显示"></div>

    <div class="map-rotate">
        <div class='layer-prop-item'>
            <label class="layui-label">旋转地图:</label>
            <div class="view-slider-item" id="view-rotate"></div>
        </div>
    </div>
    <div id="layer-container">
        <!-- <h2 class="layer-head">样式属性</h2> -->
        <div class="label-style">
            <div class="image-style">
                <h3 for="" class="image-title">Image Style</h3>
                <div class="image-style-content">
                    <div class='layer-prop-item layui-form'>
                        <label class="layui-form-label">跟随视图旋转</label>
                        <input type="checkbox" name="image-rotation" lay-filter="image-box-filter" title="开启|关闭"
                            lay-skin="switch">
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">图片旋转(度)</label>
                        <div class="layer-slider-item" id="imageRotation"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">水平缩放</label>
                        <div class="layer-slider-item" id="imageScaleX"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">竖直缩放</label>
                        <div class="layer-slider-item" id="imageScaleY"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">水平位置</label>
                        <div class="layer-slider-item" id="imageAnchorX"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">竖直位置</label>
                        <div class="layer-slider-item" id="imageAnchorY"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">水平偏移</label>
                        <div class="layer-slider-item" id="imageDisplacementX"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">竖直偏移</label>
                        <div class="layer-slider-item" id="imageDisplacementY"></div>
                    </div>
                </div>
            </div>
            <div class="text-style">
                <h3 for="" class="text-title">Text Style</h3>
                <div class="image-style-content">
                    <div class='layer-prop-item layui-form'>
                        <label class="layui-form-label">跟随视图旋转</label>
                        <input type="checkbox" name="text-rotation" lay-filter="text-box-filter" title="开启|关闭"
                            lay-skin="switch">
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">文本旋转(度)</label>
                        <div class="layer-slider-item" id="textRotation"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">水平缩放</label>
                        <div class="layer-slider-item" id="textScaleX"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">竖直缩放</label>
                        <div class="layer-slider-item" id="textScaleY"></div>
                    </div>
                    <div class='layer-prop-item '>
                        <label class="layui-form-label">文本对齐方式</label>
                        <div class="layui-col-md6 layui-form layui-row layui-col-space16">
                            <select lay-filter="align-select-filter">
                                <option value="left">居左</option>
                                <option value="center">居中</option>
                                <option value="right">居右</option>
                                <option value="start">开始</option>
                                <option value="end">结束</option>
                            </select>
                        </div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">文本基线</label>
                        <div class="layui-col-md6 layui-form layui-row layui-col-space16">
                            <select lay-filter="baseline-select-filter">
                                <option value="top">top</option>
                                <option value="bottom">bottom</option>
                                <option value="middle">middle</option>
                                <option value="alphabetic">alphabetic</option>
                                <option value="hanging">hanging</option>
                                <option value="ideographic">ideographic</option>
                            </select>
                        </div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">水平偏移</label>
                        <div class="layer-slider-item" id="textOffsetX"></div>
                    </div>
                    <div class='layer-prop-item'>
                        <label class="layui-form-label">竖直偏移</label>
                        <div class="layer-slider-item" id="textOffsetY"></div>
                    </div>
                </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: "天地图影像图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions: "天地图影像描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })
    const TDTImgCvaLayer = new ol.layer.Tile({
        title: "天地图影像注记图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions: "天地图注记描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })
    const map = new ol.Map({
        target: "map",
        loadTilesWhileInteracting: true,
        view: new ol.View({
            center: [102.845864, 25.421639],
            zoom: 6.5,
            worldsWrap: false,
            minZoom: 1,
            maxZoom: 20,
            projection: 'EPSG:4326',
        }),
        layers: [TDTImgLayer],
        // 地图默认控件
        controls: ol.control.defaults.defaults({
            zoom: false,
            attribution: true,
            rotate: true
        })
    })
    map.on('click', evt => {
        console.log("获取地图坐标:", evt.coordinate)
    })

    const pointGeometry = new ol.geom.Point([100.9788433214299, 26.747704222514738])
    const feature = new ol.Feature({
        geometry: pointGeometry
    })
    const vectotSource = new ol.source.Vector({
        features: [feature],
        wrapX: false
    })
    const iconStyle = new ol.style.Style({
        image: new ol.style.Icon({
            src: "../../image/label/simple_map.jpg",
            scale: [1 / 16, 1 / 16],
            // color: "red"
            // anchor: [0.5, 1.25]
        }),
        text: new ol.style.Text({
            font: "16px sans-serif",
            textAlign: "center",
            text: "Hello,World",
            fill: new ol.style.Fill({
                color: [255, 215, 0, 1],
            }),
            backgroundFill: new ol.style.Fill({
                color: [0, 191, 255, 0.25]
            }),
            offsetY: -30, // 向Y轴偏移
            padding: [10, 10, 10, 10]
        })
    })
    const featureStyle = new ol.style.Style({
        image: new ol.style.Circle({
            radius: 10,
            fill: new ol.style.Fill({
                color: "#fff"
            }),
            stroke: new ol.style.Stroke({
                color: "red"
            })
        })
    })
    feature.setStyle([iconStyle, featureStyle])
    const vectorLayer = new ol.layer.Vector({
        source: vectotSource
    })
    map.addLayer(vectorLayer)
    map.getView().setCenter(pointGeometry.getCoordinates())

    layui.use(function () {
        const form = layui.form;
        const layer = layui.layer

        const imageDisplacement = iconStyle.getImage().getDisplacement()
        console.log("imageDisplacement:", imageDisplacement)
        // 图片跟随视图旋转事件
        form.on('switch(image-box-filter)', function (data) {
            const elem = data.elem; // 获得 checkbox 原始 DOM 对象
            const checked = elem.checked; // 获得 checkbox 选中状态
            const value = elem.value; // 获得 checkbox 值
            iconStyle.getImage().setRotateWithView(checked)

        });
        // 文本跟随视图旋转事件
        form.on('switch(text-box-filter)', function (data) {
            const elem = data.elem; // 获得 checkbox 原始 DOM 对象
            const checked = elem.checked; // 获得 checkbox 选中状态
            const value = elem.value; // 获得 checkbox 值

            iconStyle.getText().setRotateWithView(checked)
        });

        // select 文本事件
        form.on('select(align-select-filter)', function (data) {
            const elem = data.elem; // 获得 select 原始 DOM 对象
            const value = data.value; // 获得被选中的值
            const othis = data.othis; // 获得 select 元素被替换后的 jQuery 对象
            iconStyle.getText().setTextAlign(value)
            feature.changed()
        });
        // select 文本基线事件
        form.on('select(baseline-select-filter)', function (data) {
            const elem = data.elem; // 获得 select 原始 DOM 对象
            const value = data.value; // 获得被选中的值
            const othis = data.othis; // 获得 select 元素被替换后的 jQuery 对象
            iconStyle.getText().setTextBaseline(value)
            feature.changed()
        });

        const slider = layui.slider;

        // 视图旋转事件
        slider.render({
            // 顺时针旋转,弧度单位
            elem: '#view-rotate',
            value: 0,
            min: 0,
            max: 360,
            step: 5,
            change: function (value) {
                // console.log(value) // 滑块当前值
                map.getView().setRotation(value * Math.PI / 180)
            }
        });

        // 图片渲染事件
        slider.render({
            // 顺时针旋转,弧度单位
            elem: '#imageRotation',
            value: 0,
            min: 0,
            max: 360,
            step: 5,
            change: function (value) {
                console.log(value) // 滑块当前值
                iconStyle.getImage().setRotation(value * Math.PI / 180)
                feature.changed()
            }
        });
        slider.render({
            elem: '#imageScaleX',
            value: 1,
            min: -2,
            max: 2,
            step: 0.25,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setScale([value * 1 / 16, 1 / 16])
                feature.changed()
            }
        });
        slider.render({
            elem: '#imageScaleY',
            value: 1,
            min: -2,
            max: 2,
            step: 0.25,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setScale([1 / 16, value * 1 / 16])
                feature.changed()
            }
        });
        slider.render({
            elem: '#imageAnchorX',
            value: 0,
            min: -2,
            max: 2,
            step: 0.125,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setAnchor([0.5 + value, 1.25])
                feature.changed()
            }
        });
        slider.render({
            elem: '#imageAnchorY',
            value: 0,
            min: -2,
            max: 2,
            step: 0.125,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setAnchor([0.5, 1.25 + value])
                feature.changed()
            }
        });

        slider.render({
            elem: '#imageDisplacementX',
            value: 0,
            min: -50,
            max: 50,
            step: 1,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setDisplacement([value, 0])
                feature.changed()
            }
        });
        slider.render({
            elem: '#imageDisplacementY',
            value: 0,
            min: -50,
            max: 50,
            step: 1,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getImage().setDisplacement([0, value])
                feature.changed()
            }
        });

        slider.render({
            // 顺时针旋转,弧度单位
            elem: '#textRotation',
            value: 0,
            min: 0,
            max: 360,
            step: 5,
            change: function (value) {
                console.log(value) // 滑块当前值
                iconStyle.getText().setRotation(value * Math.PI / 180)
                feature.changed()
            }
        });
        slider.render({
            elem: '#textScaleX',
            value: 1,
            min: -2,
            max: 2,
            step: 0.25,
            change: function (value) {
                // console.log(value) // 滑块当前值
                const scaleY = iconStyle.getText().getScale()
                const curScaleY = scaleY ? +scaleY[1] : 1
                iconStyle.getText().setScale([value, curScaleY])
                feature.changed()
            }
        });
        slider.render({
            elem: '#textScaleY',
            value: 1,
            min: -2,
            max: 2,
            step: 0.25,
            change: function (value) {
                // console.log(value) // 滑块当前值
                const scaleX = iconStyle.getText().getScale()
                const curScaleX = scaleX ? +scaleX[0] : 1
                iconStyle.getText().setScale([curScaleX, value])
                feature.changed()
            }
        });

        slider.render({
            elem: '#textOffsetX',
            value: 0,
            min: -200,
            max: 200,
            step: 5,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getText().setOffsetX(value)
                feature.changed()
            }
        });
        slider.render({
            elem: '#textOffsetY',
            value: 0,
            min: -200,
            max: 200,
            step: 5,
            change: function (value) {
                // console.log(value) // 滑块当前值
                iconStyle.getText().setOffsetY(value)
                feature.changed()
            }
        });

    });

</script>

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

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

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

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

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

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

相关推荐
GIS之路12 分钟前
GeoTools 结合 OpenLayers 实现属性查询(二)
前端·信息可视化
烛阴20 分钟前
一文搞懂 Python 闭包:让你的代码瞬间“高级”起来!
前端·python
AA-代码批发V哥23 分钟前
HTML之表单结构全解析
前端·html
聪聪的学习笔记34 分钟前
【1】确认安装 Node.js 和 npm版本号
前端·npm·node.js
小磊哥er1 小时前
【前端工程化】你知道前端编码规范包含哪些内容吗
前端
菌菇汤1 小时前
uni-app实现单选,多选也能搜索,勾选,选择,回显
前端·javascript·vue.js·微信小程序·uni-app·app
Ramos丶1 小时前
【ABAP】 从无到有 新建一个Webdynpro程序
java·前端·javascript
qq_411671981 小时前
vue3 的模板引用ref和$parent
前端·javascript·vue.js
清幽竹客3 小时前
vue-37(模拟依赖项进行隔离测试)
前端·vue.js
vvilkim3 小时前
Nuxt.js 页面与布局系统深度解析:构建高效 Vue 应用的关键
前端·javascript·vue.js