Skip to content

图层管理

上次更新 2025年8月20日星期三 3:16:20 字数 0 字 时长 0 分钟

图层管理是 GIS 应用中的一个重要功能,它允许用户控制地图上不同图层的显示和隐藏、调整图层的透明度等。本章将介绍如何在 OpenLayers 中实现图层管理功能。

示例

新标签页预览

代码实现

vue
<template>
  <div class="page-container">
    <div class="layer-container"></div>
    <div id="map"></div>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import { fromLonLat } from "ol/proj";

onMounted(() => {
  // 创建地图
  const map = new Map({
    target: "map",
    view: new View({
      center: fromLonLat([117.33083, 39.094899]), // 天津
      zoom: 13,
    }),
  });

  // 创建天地图图层
  const tdtLayer = new TileLayer({
    source: new XYZ({
      url: "http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
    }),
  });

  const tdtLayer2 = new TileLayer({
    source: new XYZ({
      url: "http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd",
    }),
    visible: false,
  });

  map.addLayer(tdtLayer);
  map.addLayer(tdtLayer2);

  const layerContainer = document.querySelector(".layer-container");

  const layers = [
    {
      name: "基础图层",
      children: [
        { name: "天地图矢量", id: "tdt1", checked: true },
        { name: "天地图影像", id: "tdt2", checked: false },
      ],
    },
  ];

  function createLayerTree(layers, parent) {
    const ul = document.createElement("ul");
    layers.forEach((layer) => {
      const li = document.createElement("li");
      li.className = "layer-container__item";
      if (layer.children) {
        const span = document.createElement("span");
        span.textContent = layer.name;
        li.appendChild(span);
        li.appendChild(createLayerTree(layer.children, li));
      } else {
        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.id = layer.id;
        checkbox.checked = layer.checked;
        checkbox.onchange = (event) => toggleLayerVisibility(event, layer.id);

        const label = document.createElement("label");
        label.htmlFor = layer.id;
        label.textContent = layer.name;

        const opacitySlider = document.createElement("input");
        opacitySlider.type = "range";
        opacitySlider.min = "0";
        opacitySlider.max = "100";
        opacitySlider.value = "100";
        opacitySlider.className = "opacity-slider";
        opacitySlider.id = `${layer.id}-opacity`;
        opacitySlider.disabled = !layer.checked;
        opacitySlider.onchange = (event) => adjustLayerOpacity(event, layer.id);

        li.appendChild(checkbox);
        li.appendChild(label);
        li.appendChild(opacitySlider);
      }
      ul.appendChild(li);
    });
    return ul;
  }

  const tree = createLayerTree(layers, layerContainer);
  layerContainer.appendChild(tree);

  function adjustLayerOpacity(event, layerId) {
    const opacity = event.target.value / 100;
    const layers = {
      tdt1: tdtLayer,
      tdt2: tdtLayer2,
    };

    if (layers[layerId]) {
      layers[layerId].setOpacity(opacity);
    }
  }

  function toggleLayerVisibility(event, layerType) {
    const layers = {
      tdt1: tdtLayer,
      tdt2: tdtLayer2,
    };

    // 获取对应的透明度滑块
    const opacitySlider = document.getElementById(`${layerType}-opacity`);
    // 根据图层可见性设置滑块状态
    opacitySlider.disabled = !event.target.checked;

    if (layers[layerType]) {
      layers[layerType].setVisible(event.target.checked);
    }
  }
});
</script>

<style scoped>
.page-container {
  display: flex;
  height: 24rem;
  width: 100%;
}

.layer-container {
  width: 320px;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  overflow-y: auto;
}

.layer-container__item {
  margin: 12px 0;
  padding: 15px;
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.layer-container__item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.layer-container__item span {
  font-weight: 600;
  color: #333;
  font-size: 16px;
}

.layer-container__item label {
  margin-left: 8px;
  color: #444;
  font-size: 14px;
}

.layer-container__item input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

.opacity-slider {
  width: 100%;
  margin-top: 12px;
  height: 4px;
  background: #e9ecef;
  border-radius: 2px;
  -webkit-appearance: none;
  appearance: none;
}

.opacity-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  background: #4a90e2;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s ease;
}

.opacity-slider::-webkit-slider-thumb:hover {
  transform: scale(1.1);
  background: #357abd;
}

.opacity-slider:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.opacity-slider:disabled::-webkit-slider-thumb {
  background: #999;
  cursor: not-allowed;
}

#map {
  width: 100%;
  height: 100%;
}
</style>
关注公众号