Appearance
OpenLayers 用于在网页上显示地图
1.介绍
OpenLayers 是一个开源的 JavaScript 库,用于在网页上显示地图。它支持多种地图源,包括 OSM、Bing、MapQuest 等。
学习网站
2.基础使用
2.1.安装
npm install ol2.2.基础使用
vue
<template>
<div id="openLayers-container"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import 'ol/ol.css';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
onMounted(() => {
const map = new Map({
target: 'openLayers-container', // 地图容器的ID
layers: [
new TileLayer({
source: new OSM(), // 使用OpenStreetMap作为底图
}),
],
view: new View({
center: [0, 0], // 地图中心坐标
zoom: 2, // 初始缩放级别
}),
});
});
</script>
<style scoped>
#openLayers-container {
width: 100%;
height: 500px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>3.地图、图层、要素
3.1.地图(Map)
- 地图是 OpenLayers 的核心对象,用于管理图层、视图和用户交互。
- 一个地图可以包含多个图层,并控制它们的显示和交互。
3.2.图层(Layer)
- 图层是地图的组成部分,用于显示地理数据。
- 常见的图层类型包括:
- TileLayer:用于显示瓦片地图(如 OpenStreetMap)。
- VectorLayer:用于显示矢量数据(如点、线、面等要素)。
3.3.要素(Feature)
- 要素是地理空间数据的基本单位,可以是点、线、面等几何对象。
- 要素可以附加属性数据,并显示在矢量图层上
vue
<template>
<div id="openLayers-container1"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import 'ol/ol.css'; // 引入 OpenLayers 的样式
import { Map, View } from 'ol'; // 引入 Map 和 View
import TileLayer from 'ol/layer/Tile'; // 引入瓦片图层
import OSM from 'ol/source/OSM'; // 引入 OpenStreetMap 数据源
import VectorLayer from 'ol/layer/Vector'; // 引入矢量图层
import VectorSource from 'ol/source/Vector'; // 引入矢量数据源
import { Feature } from 'ol'; // 引入要素
import { Point, LineString, Polygon } from 'ol/geom'; // 引入几何类型
import { Style, Fill, Stroke, Circle } from 'ol/style'; // 引入样式
onMounted(() => {
// 1. 创建地图
const map = new Map({
target: 'openLayers-container1', // 地图容器的 ID
layers: [], // 先不添加任何图层
view: new View({
center: [0, 0], // 地图中心坐标
zoom: 2, // 初始缩放级别
}),
});
// 2. 添加瓦片图层(OpenStreetMap)
const tileLayer = new TileLayer({
source: new OSM(), // 使用 OpenStreetMap 作为底图
});
map.addLayer(tileLayer);
// 3. 创建矢量数据源
const vectorSource = new VectorSource();
// 4. 创建要素并添加到矢量数据源
// 点要素
const pointFeature = new Feature({
geometry: new Point([0, 0]), // 点的坐标
});
pointFeature.setStyle(
new Style({
image: new Circle({
radius: 10, // 点的大小
fill: new Fill({ color: 'red' }), // 填充颜色
stroke: new Stroke({ color: 'black', width: 2 }), // 描边
}),
})
);
// 线要素
const lineFeature = new Feature({
geometry: new LineString([
[-1e6, 1e6], // 起点
[1e6, 1e6], // 终点
]),
});
lineFeature.setStyle(
new Style({
stroke: new Stroke({
color: 'blue', // 线的颜色
width: 3, // 线的宽度
}),
})
);
// 面要素
const polygonFeature = new Feature({
geometry: new Polygon([
[
[-1e6, -1e6], // 第一个点
[1e6, -1e6], // 第二个点
[1e6, 1e6], // 第三个点
[-1e6, 1e6], // 第四个点
[-1e6, -1e6], // 闭合多边形
],
]),
});
polygonFeature.setStyle(
new Style({
fill: new Fill({ color: 'rgba(0, 255, 0, 0.5)' }), // 填充颜色
stroke: new Stroke({ color: 'green', width: 2 }), // 描边
})
);
// 将要素添加到矢量数据源
vectorSource.addFeatures([pointFeature, lineFeature, polygonFeature]);
// 5. 创建矢量图层并添加到地图
const vectorLayer = new VectorLayer({
source: vectorSource, // 设置矢量数据源
});
map.addLayer(vectorLayer);
})
</script>
<style scoped>
#openLayers-container1 {
width: 100%;
height: 500px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>4.投影和坐标系
4.1.投影(Web Mercator)
- 投影是将地球表面的三维地理坐标(经度、纬度)转换为二维平面坐标的数学方法。
- 不同的投影适用于不同的场景,例如:
- EPSG:4326:WGS84 地理坐标系,使用经度和纬度表示位置。
- EPSG:3857:Web Mercator 投影,广泛用于在线地图(如 Google Maps、OpenStreetMap)。
4.2.坐标系(Coordinate System)
- 坐标系定义了如何在地图上表示地理数据。
- OpenLayers 支持多种坐标系,常见的包括:
- EPSG:4326:WGS84 地理坐标系,单位为度。
- EPSG:3857:Web Mercator 投影坐标系,单位为米。
4.3.OpenLayers 中的投影使用
- OpenLayers 默认使用 EPSG:3857(Web Mercator)作为地图的投影。
- 如果需要使用其他投影(如 EPSG:4326),需要显式设置投影并转换坐标。
4.4.代码示例
vue
<template>
<div id="openLayers-container2"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import 'ol/ol.css'; // 引入 OpenLayers 的样式
import { Map, View } from 'ol'; // 引入 Map 和 View
import TileLayer from 'ol/layer/Tile'; // 引入瓦片图层
import OSM from 'ol/source/OSM'; // 引入 OpenStreetMap 数据源
import VectorLayer from 'ol/layer/Vector'; // 引入矢量图层
import VectorSource from 'ol/source/Vector'; // 引入矢量数据源
import { Feature } from 'ol'; // 引入要素
import { Point } from 'ol/geom'; // 引入几何类型
import { Style, Circle, Fill, Stroke } from 'ol/style'; // 引入样式
import { fromLonLat, transform } from 'ol/proj'; // 引入投影工具
onMounted(() => {
// 1. 创建地图
const map = new Map({
target: 'openLayers-container2', // 地图容器的 ID
layers: [], // 先不添加任何图层
view: new View({
center: fromLonLat([0, 0]), // 将经纬度坐标转换为 EPSG:3857
zoom: 2, // 初始缩放级别
}),
});
// 2. 添加瓦片图层(OpenStreetMap)
const tileLayer = new TileLayer({
source: new OSM(), // 使用 OpenStreetMap 作为底图
});
map.addLayer(tileLayer);
// 3. 创建矢量数据源
const vectorSource = new VectorSource();
// 4. 创建要素并添加到矢量数据源
// 使用 EPSG:4326 坐标创建点要素
const pointFeature = new Feature({
geometry: new Point(fromLonLat([0, 0])), // 将经纬度坐标转换为 EPSG:3857
});
pointFeature.setStyle(
new Style({
image: new Circle({
radius: 10, // 点的大小
fill: new Fill({ color: 'red' }), // 填充颜色
stroke: new Stroke({ color: 'black', width: 2 }), // 描边
}),
})
);
// 使用 EPSG:3857 坐标创建点要素
const pointFeature3857 = new Feature({
geometry: new Point([0, 0]), // 直接使用 EPSG:3857 坐标
});
pointFeature3857.setStyle(
new Style({
image: new Circle({
radius: 10, // 点的大小
fill: new Fill({ color: 'blue' }), // 填充颜色
stroke: new Stroke({ color: 'black', width: 2 }), // 描边
}),
})
);
// 将要素添加到矢量数据源
vectorSource.addFeatures([pointFeature, pointFeature3857]);
// 5. 创建矢量图层并添加到地图
const vectorLayer = new VectorLayer({
source: vectorSource, // 设置矢量数据源
});
map.addLayer(vectorLayer);
// 6. 动态转换坐标
// 将 EPSG:4326 坐标转换为 EPSG:3857
const lonLat = [30, 45]; // 经度 30,纬度 45
const projectedCoords = fromLonLat(lonLat);
console.log('EPSG:4326 坐标:', lonLat);
console.log('转换为 EPSG:3857 坐标:', projectedCoords);
// 将 EPSG:3857 坐标转换为 EPSG:4326
const originalCoords = transform(projectedCoords, 'EPSG:3857', 'EPSG:4326');
console.log('转换回 EPSG:4326 坐标:', originalCoords);
})
</script>
<style scoped>
#openLayers-container2 {
width: 100%;
height: 500px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>代码说明
1投影转换:
- 使用 fromLonLat 将 EPSG:4326 坐标(经度、纬度)转换为 EPSG:3857 坐标。
- 使用 transform 将 EPSG:3857 坐标转换回 EPSG:4326 坐标。
2要素创建:
- 创建了两个点要素,一个使用 EPSG:4326 坐标,另一个使用 EPSG:3857 坐标。
- 通过 Style 设置要素的样式。
3地图视图:
- 地图的初始中心坐标通过 fromLonLat 转换为 EPSG:3857 坐标。
4控制台输出:
- 在控制台中打印坐标转换的结果,方便调试。
5.视图(View)和控制器(Controls)
5.1. 视图(View)
视图定义了地图的显示范围、中心点、缩放级别和旋转角度等属性。
通过视图,可以控制地图的初始状态以及动态调整地图的显示。
主要属性:
center:地图的中心坐标。
zoom:地图的缩放级别。
rotation:地图的旋转角度(以弧度为单位)。
projection:地图的投影(默认为 EPSG:3857)。
5.2. 控制器(Controls)
控制器是地图上的交互工具,用于增强用户体验。
OpenLayers 提供了多种内置控制器,例如:
缩放控件(Zoom Control):用于放大和缩小地图。
旋转控件(Rotate Control):用于旋转地图。
全屏控件(FullScreen Control):用于全屏显示地图。
比例尺控件(ScaleLine Control):显示地图比例尺。
控制器可以自定义或禁用。
5.3.示例代码:使用视图和控制器
以下代码展示了如何在 OpenLayers 中配置视图和添加控制器。
vue
<template>
<div id="openLayers-container3"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import 'ol/ol.css'; // 引入 OpenLayers 的样式
import { Map, View } from 'ol'; // 引入 Map 和 View
import TileLayer from 'ol/layer/Tile'; // 引入瓦片图层
import OSM from 'ol/source/OSM'; // 引入 OpenStreetMap 数据源
import { defaults as defaultControls, Zoom, Rotate, FullScreen, ScaleLine } from 'ol/control'; // 引入控制器
onMounted(() => {
// 1. 创建地图
const map = new Map({
target: 'openLayers-container3', // 地图容器的 ID
layers: [
new TileLayer({
source: new OSM(), // 使用 OpenStreetMap 作为底图
}),
],
view: new View({
center: [0, 0], // 地图中心坐标(EPSG:3857)
zoom: 2, // 初始缩放级别
rotation: Math.PI / 6, // 旋转 30 度(以弧度为单位)
}),
controls: defaultControls().extend([
new Zoom(), // 添加缩放控件
new Rotate(), // 添加旋转控件
new FullScreen(), // 添加全屏控件
new ScaleLine(), // 添加比例尺控件
]),
});
// 2. 动态调整视图
const view = map.getView();
view.on('change:resolution', () => {
console.log('当前缩放级别:', view.getZoom());
});
view.on('change:rotation', () => {
console.log('当前旋转角度:', view.getRotation());
});
// 3. 添加自定义控件
const customControl = document.createElement('div');
customControl.className = 'ol-control custom-control';
customControl.innerHTML = '<button>自定义控件</button>';
customControl.addEventListener('click', () => {
alert('你点击了自定义控件!');
});
map.addControl(
new ol.control.Control({
element: customControl,
})
);
})
</script>
<style scoped>
#openLayers-container3 {
width: 100%;
height: 500px;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>