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很强大,这仅仅只是其中小小一部分,之后我也会持续更新相关功能实现,感兴趣的小伙伴可以添加收藏+关注,下一节我们聊聊绘画;

相关推荐
谢道韫66626 分钟前
今日总结 2024-12-24
javascript·vue.js·elementui
racerun1 小时前
vue VueResource & axios
前端·javascript·vue.js
Calm5502 小时前
Vue3:uv-upload图片上传
前端·vue.js
新中地GIS开发老师2 小时前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
漫天转悠2 小时前
Vue3中404页面捕获(图文详情)
vue.js
Cachel wood3 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
天天进步20154 小时前
Vue项目重构实践:如何构建可维护的企业级应用
前端·vue.js·重构
2402_857583494 小时前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
小华同学ai4 小时前
vue-office:Star 4.2k,款支持多种Office文件预览的Vue组件库,一站式Office文件预览方案,真心不错
前端·javascript·vue.js·开源·github·office
k09334 小时前
vue中proxy代理配置(测试一)
前端·javascript·vue.js