OpenLayers 自定义地图组件

关注我,带你一起学GIS ^

注:当前使用的是 ol [9.2.4] 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

前言

使用Vue、React等框架的过程中,经常会听到一个词“组件化”,在构建项目过程中,很多时候都是在写组件,不管是官方提供的还是自己写的,都可以算作是自定义组件。像vue-leaflet即是使用Vue集成的地图组件库,这种组件小巧,使用简单,只需要按约定传递一些属性即可。在框架中已经被封装好了,但如果要自己写的话该怎么实现呢?

1. customElements元素

customElements属于全局属性,是window对象上的只读属性,用于创建自定义HTML元素。该元素继承自HTMLElement ,可以通过customElements.define() 方法注册自定义元素。define(customElementName,customElement)方法接收两个参数:

  • customElementName:字符串类型,表示自定义元素名称
  • customElementHTMLElement 类型,表示自定义元素

以下是来自于mdn的示例代码:通过this.attachShadow({ mode: "open" })可以创建一个影子结构,使得自定义组件具有独立性和安全性,将mode属性设置为open之后,能够通过css选择器查询到Shadow内部元素。

// 方式一
let customElementRegistry = window.customElements;
customElementRegistry.define("my-custom-element", MyCustomElement);

// 方式二
customElements.define(
  "element-details",
  class extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById(
        "element-details-template",
      ).content;
      const shadowRoot = this.attachShadow({ mode: "open" }).appendChild(
        template.cloneNode(true),
      );
    }
  },
);

2. 自定义地图组件

定义olMap类并继承自HTMLElement,在构造函数中创建link元素和style元素,并将ol-css引用传递给link元素href属性。创建div元素装载地图,并将Map属性target设置为div元素。最后使用customElements 方法define('ol-map', olMap)即可完成自定义地图组件。

const olCSSUrl = "../../libs/css/ol9.2.4.css"
class olMap extends HTMLElement {
    constructor() {
        super()
        this.shadow = this.attachShadow({ mode: "open" })
        const link = document.createElement("link")
        link.setAttribute("rel""stylesheet")
        link.setAttribute("href", olCSSUrl)
        this.shadow.appendChild(link)
        const style = document.createElement("style")
        style.innerText = `
            :host{
                display:block
            }
        `
        this.shadow.appendChild(style)
        const div = document.createElement("div")
        div.style.width = "100%"
        div.style.height = "100%"
        this.shadow.appendChild(div)

        this.map = new ol.Map({
            target: div,
            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: false,
                rotate: false
            })
        })
    }
}
customElements.define('ol-map', olMap);

还可以使用另一种方式创建自定义地图组件,就是将组件名称和自定义元素写在一起。而且,下面这种方式算是创建自定义组件的常见用法,这样可以避免别人修改组件代码造成不良影响。

const olCSSUrl = "../../libs/css/ol9.2.4.css"
customElements.define('ol-map',
    class olMap extends HTMLElement {
        constructor() {
            super()
            this.shadow = this.attachShadow({ mode: "open" })
            const link = document.createElement("link")
            link.setAttribute("rel""stylesheet")
            link.setAttribute("href", olCSSUrl)
            this.shadow.appendChild(link)
            const style = document.createElement("style")
            style.innerText = `
            :host{
                display:block
            }
        `
            this.shadow.appendChild(style)
            const div = document.createElement("div")
            div.style.width = "100%"
            div.style.height = "100%"
            this.shadow.appendChild(div)

            this.map = new ol.Map({
                target: div,
                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: false,
                    rotate: false
                })
            })
        }
    }
);

3. 使用自定义组件

html结构中写入以下结构并设置好map样式即可。

// 使用自定义地图组件
<body>
    <ol-map id="map" class="map"></ol-map>
</body>
// 自定义地图组件css
#map {
    position: absolute;
    top: 50px;
    bottom: 0;
    width: 100%;
}

4. 完整代码

其中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">

    <script src="../../js/config.js"></script>
    <script src="../../libs/js/ol9.2.4.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;
        }

    </style>
</head>

<body>
    <div id="top-content">
        <span>OpenLayers 自定义地图组件</span>
    </div>
    <ol-map id="map" class="map"></ol-map>
</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 olCSSUrl = "../../libs/css/ol9.2.4.css"
    customElements.define('ol-map',
        class olMap extends HTMLElement {
            constructor() {
                super()
                this.shadow = this.attachShadow({ mode: "open" })
                const link = document.createElement("link")
                link.setAttribute("rel""stylesheet")
                link.setAttribute("href", olCSSUrl)
                this.shadow.appendChild(link)
                const style = document.createElement("style")
                style.innerText = `
                :host{
                    display:block
                }
            `
                this.shadow.appendChild(style)
                const div = document.createElement("div")
                div.style.width = "100%"
                div.style.height = "100%"
                this.shadow.appendChild(div)

                this.map = new ol.Map({
                    target: div,
                    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: false,
                        rotate: false
                    })
                })
            }
        }
    );
</script>

OpenLayers示例数据下载,请在公众号后台回复:ol数据

全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试

GIS之路公众号已经接入了智能助手,欢迎大家前来提问。

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

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

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

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部