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

相关文章
|
3月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
181 64
|
30天前
|
资源调度 JavaScript 前端开发
创建vue3项目步骤以及安装第三方插件步骤【保姆级教程】
这是一篇关于创建Vue项目的详细指南,涵盖从环境搭建到项目部署的全过程。
163 1
|
3月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
149 58
|
2月前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
146 3
|
3月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
74 8
|
3月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
64 1
|
3月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
151 1
|
8天前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
12天前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
66 12

热门文章

最新文章