背景
大概在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
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
View 常用配置:
center
:地图中心点zoom
:默认缩放级别minZoom
:最小缩放级别maxZoom
:最大缩放级别projection
:投影坐标系,默认EPSG:3857
,在这里我们使用高德地图服务,设置成EPSG:4326
,可以在 腾讯位置服务拾取坐标;extent
:地图边界值,超过边界值的内容将不会显示rotation
:地图旋转角度,Math.PI / 180 * 角度值
Controls
常用地图控件:全屏控件FullScreen
、比例尺控件ScaleLine
、缩放滑块刻度控件ZoomSlider
、鼠标位置控制MousePosition
、小地图控件OverviewMap
;
.ts
Defaults({ zoom: true }).extend([
new ScaleLine({
className: 'ol-scale-line custom-zoom-line'
}), //比例尺控件
new ZoomSlider(), //缩放滑块刻度控件
new FullScreen(), // 全屏控件
new MousePosition({
coordinateFormat: function (coordinate) {
return `东经${coordinate?.[0]} 北纬${coordinate?.[1]}`;
}
}), //鼠标位置控件
new OverviewMap({
layers
})
]);
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
很强大,这仅仅只是其中小小一部分,之后我也会持续更新相关功能实现,感兴趣的小伙伴可以添加收藏+关注,下一节我们聊聊绘画
;