Vue3 + Openlayers9 项目实战训练:初识地图控件

背景

大概在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

安装完成后,不要忘记引入olcss文件;这里我遇到一个坑,我在包里面没有找到对应的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很强大,这仅仅只是其中小小一部分,之后我也会持续更新相关功能实现,感兴趣的小伙伴可以添加收藏+关注,下一节我们聊聊绘画;

相关推荐
你挚爱的强哥2 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
susu10830189113 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
Jacky(易小天)5 小时前
MongoDB比较查询操作符中英对照表及实例详解
数据库·mongodb·typescript·比较操作符
天天进步20155 小时前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
疯狂的沙粒5 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员6 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
疯狂的沙粒6 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
想自律的露西西★7 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5
白墨阳7 小时前
vue3:瀑布流
前端·javascript·vue.js
程序媛-徐师姐8 小时前
Java 基于SpringBoot+vue框架的老年医疗保健网站
java·vue.js·spring boot·老年医疗保健·老年 医疗保健