OpenLayers入门-第二篇、在vue3中使用elementplus制作图层控件,图层切换,显示隐藏,图层排序

简介: OpenLayers入门-第二篇、在vue3中使用elementplus制作图层控件,图层切换,显示隐藏,图层排序

本文将介绍openlayers中地图图层控制的组件制作方法,图层切换,显示隐藏,图层排序,在vue3中使用element,tree等组件。



(本专辑持续更新中)

1.基础知识准备

  1. 官方的图层组案例Layer Groups,首先看一下官方的图层控制是怎么回事。
  2. 官方的自定义控件的例子Custom Controls,了解自定义控件的用法。
  1. 核心组件基本知识

在 OpenLayers 中,地图图层控制是一个常见的需求,包括图层的切换、显示隐藏、图层排序等。在 Vue 3 中结合 Element UI 或其他 UI 库(如 Ant Design Vue、Vuetify 等)来实现这些功能可以为用户提供一个友好的交互界面。

下面将介绍如何使用 OpenLayers、Vue 3 和 Element UI 来制作一个地图图层控制的组件。

1. 安装必要的库

首先,你需要在项目中安装 OpenLayers、Vue 3 和 Element UI(或其他 UI 库)。

npm install ol vue@next element-plus

2. 创建地图容器和图层控制组件

在你的 Vue 组件中,你可以创建一个地图容器和一个用于控制图层的组件。

<template>
  <div ref="mapContainer" class="map-container"></div>
  <el-tree
    :data="layersData"
    node-key="id"
    ref="layersTree"
    @check-change="handleCheckChange"
    show-checkbox
  ></el-tree>
</template>

<script>
import { onMounted, ref } from 'vue';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

export default {
  name: 'MapComponent',
  setup() {
    const mapContainer = ref(null);
    const layersData = ref([
      { id: 1, label: 'OpenStreetMap', visible: true },
      // 其他图层数据
    ]);
    let map;

    onMounted(() => {
      const osmLayer = new TileLayer({
        source: new OSM(),
      });

      map = new Map({
        target: mapContainer.value,
        layers: [osmLayer],
        view: new View({
          center: [0, 0],
          zoom: 2,
        }),
      });
    });

    function handleCheckChange(data, checked, indeterminate) {
      const layerId = data.id;
      // 根据图层 ID 控制图层的显示和隐藏
    }

    return {
      mapContainer,
      layersData,
      handleCheckChange,
    };
  },
};
</script>

<style>
.map-container {
  width: 100%;
  height: 400px;
}
</style>

3. 控制图层的显示和隐藏

handleCheckChange 函数中,你可以根据图层的 ID 来控制图层的显示和隐藏。你需要维护一个图层和 OpenLayers 图层对象的映射关系,然后在该函数中切换图层的可见性。

let layersMap = {
  1: osmLayer,
  // 其他图层
};

function handleCheckChange(data, checked, indeterminate) {
  const layerId = data.id;
  const layer = layersMap[layerId];
  if (layer) {
    layer.setVisible(checked);
  }
}

4. 图层排序

图层排序可以通过调整 map.getLayers() 返回的图层数组的顺序来实现。你可以添加一个按钮来触发图层排序的操作。

<template>
  <!-- ... -->
  <el-button @click="sortLayers">排序图层</el-button>
</template>

<script>
// ...

export default {
  // ...
  methods: {
    sortLayers() {
      const layers = map.getLayers().getArray().slice();
      // 对 layers 数组进行排序
      layers.sort((a, b) => {
        // 根据你的排序规则进行比较
      });
      // 设置排序后的图层数组
      map.getLayers().setArray(layers);
    },
  },
};
</script>

5. 结合 Element UI 的 Tree 组件

在上面的例子中,已经使用了 Element UI 的 Tree 组件来展示图层,并通过 checkbox 来控制图层的显示和隐藏。你可以根据需要调整 Tree 组件的属性和事件来适应你的应用场景。

注意事项

  • 确保 OpenLayers、Vue 3 和 Element UI 的版本兼容。
  • 在实际项目中,可能需要处理更多的边界情况和性能优化。
  • 如果使用的是 Vue 3 的 Composition API,注意正确地使用 refreactive 来管理状态。
  • 图层控制和排序的逻辑可能会根据你的具体需求而有所不同,上面的例子只是一个基本的实现。

2.正式开发

1. 这里使用天地图,以XYZ的方式引入。

function getTDXYZUrl(type: string) {
    return (
        "http://t" +
        Math.round(Math.random() * 7) +
        ".tianditu.com/DataServer?T=" +
        type +
        "&x={x}&y={y}&l={z}&tk=" +
        myTDkey
    );
}

2. 图层的数据结构(模拟真实使用场景,方便图层的管理)。

const layersData = [
    {
        id: "1",
        label: "天地图",
        url: "",
        opacity: 100,
        visible:true,
        children: [
            {
                id: "4",
                label: "矢量注记",
                url: getTDXYZUrl("cva_w"),
                opacity: 100,
                visible:true,
                children: [],
            },
            {
                id: "3",
                label: "矢量底图",
                url: getTDXYZUrl("vec_w"),
                opacity: 80,
                visible:true,
                children: [],
            },

        ],
    },
    {
        id: "2",
        label: "影像底图",
        url: getTDXYZUrl("img_w"),
        opacity: 100,
        visible:true,
        children: [],
    },
];

3. 把图层数据转化成,openlayers的图层类。

function makeTree(layersData: Array<IlayersData>) {
    let rootLayers: (LayerGroup | TileLayer<XYZ>)[] = [];
    layersData.forEach((e) => {
        if (e.children.length > 0) {
            let group = new LayerGroup({
                properties: {
                    label: e.label,
                },
                opacity: e.opacity!/100,
                layers: makeTree(e.children),
                visible:e.visible,
            });
            rootLayers.unshift(group);

        } else {
            let layer = new TileLayer({
                source: new XYZ({
                    url: e.url,
                    projection: e.projection ?? "EPSG:3857",
                }),
                opacity: e.opacity!/100,
                properties: {
                    label: e.label,
                },
            });
            rootLayers.unshift(layer)
        }
    });
    return rootLayers
}

let layers = makeTree(layersData)
function initMap(optons: { target: HTMLElement }) {
    return new Map({
        layers: layers,
        target: optons.target as HTMLElement,
        view: new View({
            center: [0, 0],
            zoom: 2,
        }),
    });
}
export {
    initMap,layersData
}

4. 控件的html

  <div class="whr-vertical-control  " ref="my-vertical-control">
    <el-popover placement="left" :width="300" trigger="hover">
      <template #reference>
        <!-- <el-tooltip class="box-item" effect="dark" content="图层控制" placement="top-start"> -->
        <el-button type="primary" icon="CopyDocument"/>
        <!-- </el-tooltip> -->
      </template>
      <template #default>
        <div>
          <div class="whr-popover-title">
            <div class="yigeshu"></div>
            <div class="" style="margin-left: 5px;">图层控制</div>

          </div>
          <el-divider/>
          <div class="whr-popover-body">
            <el-tree node-key="label" :data="layerTreeData" :props="defaultProps" @check-change="layerVisibleControl"
                     :default-checked-keys="defaultCheckedLayers"
                     show-checkbox>
              <template #default="{ node, data }">
                <span class="custom-tree-node">
                  <span>{{ node.label }}</span>
                  <span style="width: 100px;" v-if="data.children.length == 0">
                     <el-slider v-model="data.opacity" size="small" @change="layerOpacityChange($event,data)"  />
                  </span>
                </span>


              </template>
            </el-tree>
          </div>
        </div>
      </template>

    </el-popover>
  </div>

5. 初始化控件,加载地图。

  class MyVerticalControl extends Control {
      constructor(opt_options: any) {
        const options = opt_options || {};
        super({
          element: self.$refs["my-vertical-control"] as HTMLElement,
          target: options.target,
        });
      }
    }

    this.vercontrol = new MyVerticalControl({})
    this.map = initMap({target: this.$refs.map as HTMLElement})
    (this.map as Map).addControl(this.vercontrol as Control)

如果需要地图组件保活,可以把添加控件写在activated钩子里。

  activated() {
    (this.map as Map).addControl(this.vercontrol as Control);
  },

6. 控制图层显示隐藏和透明度,顺序也可以。

  layerVisibleControl(data: Tree,
                 checked: boolean,
                 indeterminate: boolean) {
      console.log(data, checked, indeterminate)
      let currentLayer = this.map!.getAllLayers().filter(e => {
        return e.getProperties().label == data.label
      })
      if (currentLayer.length > 0) {
        currentLayer[0].setVisible(checked)
      }
    },
    layerOpacityChange($event,data){
      console.log($event,data)
      let currentLayer = this.map!.getAllLayers().filter(e => {
        return e.getProperties().label == data.label
      })
      if (currentLayer.length > 0) {
        currentLayer[0].setOpacity($event/100)
      }
    }

相关文章
|
7天前
|
JavaScript 容器
乾坤qiankun框架搭建 主应用为vue3的项目。
乾坤qiankun框架搭建 主应用为vue3的项目。
64 2
|
1天前
Vue3 中使用 Event Bus
【10月更文挑战第16天】Event Bus 是 Vue3 中一种简单而实用的通信方式,在一些简单的场景中可以发挥重要作用。但在实际应用中,要根据项目的具体需求和复杂度,选择合适的通信方式,以实现最佳的性能和可维护性。同时,要遵循最佳实践,合理使用 Event Bus,避免出现问题。
10 5
|
1天前
|
前端开发 UED
vue3知识点:Suspense组件
vue3知识点:Suspense组件
11 4
|
1天前
|
JavaScript 前端开发 Java
《vue3第五章》新的组件,包含:Fragment、Teleport、Suspense
《vue3第五章》新的组件,包含:Fragment、Teleport、Suspense
10 2
|
1天前
|
Java
vue3知识点:Teleport组件
vue3知识点:Teleport组件
10 1
|
7天前
|
JavaScript
vue3 生命周期
【10月更文挑战第14天】vue3 生命周期
|
7天前
|
JavaScript 前端开发 API
深入探索挖掘vue3 生命周期
【10月更文挑战第10天】
20 0
|
3天前
|
JavaScript
在 Vue 中处理组件选项与 Mixin 选项冲突的详细解决方案
【10月更文挑战第18天】通过以上的分析和探讨,相信你对在 Vue 中使用 Mixin 时遇到组件选项与 Mixin 选项冲突的解决方法有了更深入的理解。在实际开发中,要根据具体情况灵活选择合适的解决方案,以确保代码的质量和可维护性。
27 7
|
3天前
|
存储 JavaScript
vue——store全局存储
【10月更文挑战第18天】Vuex 是 Vue.js 应用中非常重要的一个工具,它为我们提供了一种有效的状态管理方式。通过合理地使用 Vuex,我们可以更好地组织和管理应用的状态,提高应用的开发效率和质量。
15 1
|
2天前
|
缓存 JavaScript UED
Vue 的动态组件与 keep-alive
【10月更文挑战第19天】总的来说,动态组件和 `keep-alive` 是 Vue.js 中非常实用的特性,它们为我们提供了更灵活和高效的组件管理方式,使我们能够更好地构建复杂的应用界面。深入理解和掌握它们,以便在实际开发中能够充分发挥它们的优势,提升我们的开发效率和应用性能。
29 18