背景
大概在19年的时候,由于项目需要,当时只能内网开发,客户对地图有很多定制化功能,又要求免费,所以就选择了使用openlayers;这段时间近来无事,准备开设一专栏,专门回顾一下,也方便大家一起学习。
在此专栏里面,我们会一起学习到,瞄点,画圆,画方,画遮挡物等基本操作,也有热力图,区域搜索,测距,测面,定位,物体运动轨迹,历史轨迹回放等更复杂的操作;
由于实际项目中使用的Geoserver自定义地图服务,我们在实际学习时访问不了,以下我们都使用高德地图服务学习 :http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}
切勿在实际项目中使用,会有经纬度偏移问题。 学习不影响~ 仓库地址
Openlayers简介

OpenLayers使得在任何网页中放置动态地图变得很容易。它可以显示从任何来源加载的地图瓦片,矢量数据和标记。OpenLayers的开发是为了进一步利用各种地理信息。它是完全免费的,开源JavaScript,在2条款BSD许可证(也称为FreeBSD)下发布。 地址
上面这段话大家简单看下就行,就一句话,ol是免费的,可以自定义地图源,支持更多的定制化地图操作,支持内网开发,地图数据更安全,可以自己发布地图服务,坐标数据完全存储在本地。
Openlayers入门
本文我们开始介绍地图的加载,以及一些常用的属性,控件。
了解过PS的朋友知道,一张设计图是由很多图层构成,我们设计的图案,都需要在图层上进行操作;ol有些类似,不管你要画圆,画方,画任何物体都需要先创建图层。本文我们就不一个个写demo了,直接开始一步步封装。
安装
本文用到的
ol版本是9.0.0,基于Vue3进行开发
js
npm i ol
安装完成后,不要忘记引入ol的css文件;这里我遇到一个坑,我在包里面没有找到对应的css文件,就从官网examples中复制了一份。
main.js
import '@/public/css/ol.css';
使用
创建一个utils文件夹,在文件夹下创建map文件,目录如下:

其中config.ts地图相关配置;index.ts地图入口文件,也是实例化地图的入口;plugin地图相关工具包,如各种图形的绘制,各种工具的使用,热力图,运动轨迹这些,都会单独封装成ts放在文件夹中;
config.ts
// 地图相关配置
export const config = {
url: {
xyzUrls: [
'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
] // 天地图加载地址
},
center: [104.066939, 30.578673], // 默认中心点
zoom: 10, // 默认缩放等级
maxZoom: 20, // 最大缩放等级
minZoom: 5, // 最小缩放等级
projection: 'EPSG:4326', // 坐标系规则
extent: [], // 边界值
};
初始化Map Apis
js
<!-- 地图容器 -->
<div id="map-box"></div>
new Map({
layers,
controls,
target: 'map-box',
view: new View({
projection: config.projection,
center: config.center,
zoom: config.zoom,
maxZoom: config.maxZoom,
minZoom: config.minZoom
})
})
new Map() 是地图的容器,它返回一个 ol 地图对象。它可以配置各种图层、加载各种控件。
上面例子中,包含四个ol常用要素:
target:绑定地图容器的属性,传入容器的id即可。layers:地图图层。 支持配置多个图层,根据图层添加的先后顺序,决定叠加顺序。view:地图视图。配置地图相关信息,如:中心点、缩放等级、透明度、坐标系规则、旋转角度等controls: 地图使用控件,下文会提到有哪些常用的控件
接下来我们展开来说这几个要素:target这个就不用多说了,就是承载地图的容器。
Layers
它是多个图层的集合,所以是个数组,在ol中,主要定义了四种图层类型,热度图HeatMap Layer、图片图层Image Layer、切片图层Tile Layer、 矢量图层Vector Layer,它们都是继承 Layer 这个基类。
Layer的主要属性:
opacity: 不透明度(0-1),默认为 1 ,即完全不透明;zIndex: 图层的叠放顺序,默认为0,值最小的图层位于最下方;visible:是否可见,默认为 true;地图切换功能就是通过控制这个属性来完成extent:图层渲染的边界范围。图层将不会在这个范围之外被渲染;minResolution:最小分辨率,当图层的缩放级别小于这个分辨率时,图层就会隐藏;maxResolution:最大分辨率,当图层的缩放级别等于或超过这个分辨率时,图层就会隐藏;minZoom:最小视图缩放级别,在此级别之上,图层将可见;maxZoom:最大视图缩放级别,在此级别之上,图层将不可见;source:图层数据源
Tile Layer加载瓦片地图服务:
js
const layers = config.url.xyzUrls.map(url => {
return new TileLayer({
visible: true,
source: new XYZ({ url })
});
});
在此实战项目中,我们采用瓦片的形式加载地图
Vector Layer加载矢量地图数据,需要准备一份GeoJSON 的数据,GeoJSON 是一种使用JavaScript 对象表示法(JSON) 对地理数据结构进行编码的格式,可以理解为它就是一份"具有地图规范格式的 JSON"
HeatMap Layer热力图,另一种地图展示形式,之后我们实战热力图时再研究;
Image Layer单张图片的矢量图层,这里可以是网络图片的地址,或者是本地的文件地址;然后需要传入参考坐标系 projection和图片尺寸imageExtent
js
new ImageLayer({
visible: true,
source: new ImageStatic({
projection: 'EPSG:4326',
imageExtent: [100, 30, 102, 32],
url: 'https://picsum.photos/200'
})
})
View 常用配置
center:地图中心点zoom:默认缩放级别minZoom:最小缩放级别maxZoom:最大缩放级别projection:投影坐标系,默认EPSG:3857,在这里我们使用高德地图服务,设置成EPSG:4326,可以在 腾讯位置服务拾取坐标;extent:地图边界值,超过边界值的内容将不会显示rotation:地图旋转角度,Math.PI / 180 * 角度值
Controls
常用地图控件:全屏控件FullScreen、比例尺控件ScaleLine、缩放滑块刻度控件ZoomSlider、鼠标位置控制MousePosition、小地图控件OverviewMap;
FullScreen

ScaleLine

ZoomSlider

MousePosition

OverviewMap

完整封装代码
index.ts
import { config } from './config';
import Map, { MapOptions } from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import XYZ from 'ol/source/XYZ.js';
import {
defaults as Defaults,
MousePosition,
ScaleLine,
ZoomSlider,
FullScreen
} from 'ol/control';
export type IMap = Map | null;
class SMap {
map: IMap = null;
constructor(opts: MapOptions) {
this.init(opts);
}
private init(opts: MapOptions) {
this.map = new Map(opts);
}
getMap() {
return this.map;
}
}
export const smap = (opts: MapOptions) => {
const layers =
opts.layers ||
config.url.xyzUrls.map(url => {
return new TileLayer({
visible: true,
source: new XYZ({ url })
});
});
const controls =
opts.controls ||
Defaults({ zoom: true }).extend([
new ScaleLine(), //比例尺控件
new ZoomSlider(), //缩放滑块刻度控件
new FullScreen(), // 全屏控件
new MousePosition({
coordinateFormat: function (coordinate) {
return `东经${coordinate?.[0]} 北纬${coordinate?.[1]}`;
}
}) //鼠标位置控件
]);
return new SMap(
Object.assign(
{
layers,
controls,
target: opts.target,
view:
opts.view ||
new View({
projection: config.projection,
center: config.center,
zoom: config.zoom,
maxZoom: config.maxZoom,
minZoom: config.minZoom
})
},
opts
)
);
};
smap.prototype = SMap.prototype;
map.vue
<template>
<div class="map-area">
<div id="map-box" class="map-container"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, Ref, ref } from 'vue';
import { smap } from '@/utils/map';
import { defaults } from 'ol/interaction';
const map: Ref<IMap> = ref(null);
onMounted(() => {
const mapInstance = smap({
target: 'map-box',
interactions: defaults({ doubleClickZoom: false }) // 禁止双击放大行为
});
map['value'] = mapInstance.getMap();
});
</script>
<style scoped lang="less">
.map-area {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
.map-container {
width: 100%;
height: 100%;
}
}
</style>
最后
以上就是ol基础入门,ol很强大,这仅仅只是其中小小一部分,之后我也会持续更新相关功能实现,感兴趣的小伙伴可以添加收藏+关注,下一节我们聊聊绘画;
