开启掘金成长之旅!这是我参与「掘金日新计划 · 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.鼠标位置
- 通 过MousePosition控 件获取鼠标位置。
- 根据投影坐标 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.比例尺控件
- 通 过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]), // 投影坐标控件
});