openlayers学习(2):地图常用控件

698 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第47天,点击查看活动详情

地图常用控件

1.导航条控件

ZoomSlider: 用于控制地图的缩放级别控件。 ZoomToExtent: 一个按钮,用于将视口显示到特点的投影区域

import { Map, View } from 'ol';
import ZoomSlider from 'ol/control/ZoomSlider';
import ZoomToExtent from 'ol/control/ZoomToExtent';

const map = new Map({
  target: 'map',
  layers: [....],
  view: new View({...}),
});

// 加载地图导航条
const zoomslider = new ZoomSlider();
map.addControl(zoomslider);
let zoomToExtent = new ZoomToExtent({
  extent: [13100022, 4290033, 1320000044, 5210055], // 视口区域设为北京
});
map.addControl(zoomToExtent);

2.缩放移动旋复位

View.setZoom(): 设置缩放层级。 View.setCenter(): 设置视图当前的位置。 View.setRotation(): 设置视图旋转角度。复位视图就使用上面三个 API 进行复位。

// 获取视图对象,初始缩放层级,初始显示位置,初始旋转角度
let view = map.getView();
let zoom = view.getZoom();
let center = view.getCenter();
let rotation = view.getRotation();

// 增大缩放层级
zoomOut.addEventListener('click', (e) => {
  view.setZoom(view.getZoom() + 1);
});

// 缩小缩放层级
zoomIn.addEventListener('click', (e) => {
  view.setZoom(view.getZoom() - 1);
});

// 移动到给定的经纬度处
moveDf.addEventListener('click', (e) => {
  let pos = fromLonLat([121, 40]);
  view.setCenter(pos); // 移动
  view.setZoom(18);
});

// 复原初始缩放,位置,旋转角度
moveRe.addEventListener('click', (e) => {
  view.setCenter(center); // 初始中心位置
  view.setZoom(zoom); // 初始缩放级别
  view.setRotation(rotation); // 初始旋转角度
});

// 获取鼠标点击的地点的经纬度
container.addEventListener('click', (e) => {
  console.log(transform(map.getEventCoordinate(e), 'EPSG:3857', 'EPSG:4326'));
});

3.图层显示隐藏

layer.setVisible(): 设置图层的可见层度。虽然 View 类没有提供控制图层显示隐藏的组件,但是提供了相关的 API,我们可以自定义组件,然后调用 API 实现。

<div id="map">
  <div class="layerControl">
    <div class="title">图层列表</div>
    <ul class="layerTree"></ul>
  </div>
</div>
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';

const publicKey = 'xxxxx'; // 自行去注册获取key:https://www.tianditu.gov.cn/
const url = `http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${publicKey}`;
const url2 = `http://t0.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${publicKey}`;
const url3 = `http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${publicKey}`;
const url4 = `http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=${publicKey}`;

let lay = new TileLayer({
  name: '天地图矢量图层',
  source: new XYZ({
    url: url,
  }),
});

let layTag = new TileLayer({
  name: '天地图标记层',
  source: new XYZ({
    url: url2,
  }),
});

let shape = new TileLayer({
  name: '天地图地形影像图图层',
  source: new XYZ({
    url: url3,
  }),
});

let shapeTag = new TileLayer({
  name: '天地图地形影像图标记层',
  source: new XYZ({
    url: url4,
  }),
});

let map = new Map({
  target: 'map',
  layers: [lay, layTag, shape, shapeTag],
  view: new View({
    zoom: 2,
    center: [0, 0],
  }),
});

initLayerVisible();

function initLayerVisible() {
  // 图层,图层名和图层是否可见的初始状态列表
  let layer = [];
  let layerName = [];
  let layerVisibity = [];

  // 获取被插入DOM的节点
  let treeContent = document.querySelector('.layerTree');

  // 获取地图中所有图层
  let layers = map.getAllLayers();

  // 循环插入DOM到自定义组件中
  layers.forEach(function (item, idx) {
    layer[idx] = item;
    layerName[idx] = item.get('name');
    layerVisibity[idx] = item.getVisible();

    let className = `ipt${idx}`;
    let li = `
      <li class="${className}">
        <input type="checkbox" id="${className}" ${
      layerVisibity[idx] && 'checked'
    }/>
        <label class="content" for="${className}">${layerName[idx]}</label>
      </li>
    `;

    treeContent.appendChild(
      new DOMParser()
        .parseFromString(li, 'text/html')
        .querySelector(`.${className}`)
    );
    let dom = document.querySelector(`#${className}`);
    dom.addEventListener('click', function (e) {
      console.log(item);
      if (this.checked) {
        item.setVisible(true);
      } else {
        item.setVisible(false);
      }
    });
  });
}

4.鼠标位置

  1. 通 过MousePosition控 件获取鼠标位置。
  2. 根据投影坐标 API getEventCoordinate 获 取。
import './style.css';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import MousePosition from 'ol/control/MousePosition';
import { createStringXY } from 'ol/coordinate';
import { defaults as defaultControls } from 'ol/control';
import { transform } from 'ol/proj';

const publicKey = 'xxxxx'; // 自行去注册获取key:https://www.tianditu.gov.cn/
const url = `http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${publicKey}`;
const url2 = `http://t0.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${publicKey}`;

const mousePositionControl = new MousePosition({
  coordinateFormat: createStringXY(4),
  projection: 'EPSG:4326',
  className: 'custom-mouse-position',
  target: document.querySelector('.mouse-position'),
  placeholder: '找不到坐标',
});

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new XYZ({
        url: url,
        wrapX: false,
      }),
    }),
    new TileLayer({
      source: new XYZ({
        url: url2,
        wrapX: false,
      }),
    }),
  ],
  view: new View({
    zoom: 2, // 地图初始显示层级
    center: [0, 0],
  }),
  controls: defaultControls().extend([mousePositionControl]), // 投影坐标控件
});

// 修改投影坐标
const projection = document.querySelector('#projection');
projection.addEventListener('change', function (e) {
  mousePositionControl.setProjection(e.target.value);
});

// 修改投影坐标精度
const number = document.querySelector('#Precision');
number.addEventListener('change', function (e) {
  const format = createStringXY(e.target.valueAsNumber);
  mousePositionControl.setCoordinateFormat(format);
});

// 通过API获取坐标
document.querySelector('#map').addEventListener('click', (e) => {
  // 转换坐标从源投影转换成目标投影  EPSG:3857是源,EPSG:4326是目标
  console.log(transform(map.getEventCoordinate(e), 'EPSG:3857', 'EPSG:4326'));
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      .content {
        position: absolute;
        right: 20px;
        top: 20px;
        padding: 20px;
        background-color: #fff;
        border-radius: 5px;
        z-index: 6;
      }

      input,
      select {
        padding: 5px;
        outline: none;
        border: 2px solid red;
      }

      .box {
        margin-bottom: 5px;
      }
    </style>
  </head>
  <body>
    <div id="map">
      <div class="content">
        <div class="box">
          <label for="projection">请选择投影坐标:</label>
          <select id="projection">
            <option value="EPSG:4326">EPSG:4326</option>
            <option value="EPSG:3857">EPSG:3857</option>
          </select>
        </div>
        <div class="box">
          <label for="Precision" class="number">请选择精度:</label>
          <input type="number" id="Precision" value="4" />
        </div>
        <div class="mouse-position"></div>
      </div>
    </div>
    <script type="module" src="./main.js"></script>
  </body>
</html>

5.比例尺控件

  1. 通 过ScaleLine插 入控件到页面中
import './style.css';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import ScaleLine from 'ol/control/ScaleLine';
import { defaults as defaultControls } from 'ol/control';

const publicKey = 'xxxxx'; // 自行去注册获取key:https://www.tianditu.gov.cn/
const url = `http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${publicKey}`;
const url2 = `http://t0.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${publicKey}`;

const scaleLineControl = new ScaleLine({
  units: 'metric',
});

const map = new Map({
  target: 'map',
  layers: [
    new TileLayer({
      source: new XYZ({
        url: url,
        wrapX: false,
      }),
    }),
    new TileLayer({
      source: new XYZ({
        url: url2,
        wrapX: false,
      }),
    }),
  ],
  view: new View({
    zoom: 2, // 地图初始显示层级
    center: [0, 0],
  }),
  controls: defaultControls().extend([scaleLineControl]), // 投影坐标控件
});