需求
地图上增加旋转、缩放、比例尺、鼠标经纬度等控件。
实现过程
通过ol.Map({controls})实现各种控件的添加和样式自定义。
知识点
ol.control.defaults.defaults()包含3个控件的配置:版权所属信息attribution、缩放zoom、旋转rotate。- 可通过
ol.control.defaults.defaults().extend([])扩展各种控件,也可以通过map.addControl()方法添加控件。 ol.control.FullScreen()全屏控件。ol.control.ScaleLine()比例尺控件。ol.control.ZoomSlider()缩放滑块控件。ol.control.OverviewMap()小地图鹰眼控件。ol.control.ZoomToExtent()一键恢复到默认视图控件。ol.control.MousePosition()鼠标经纬度实时显示控件。- 每个控件默认都有一定的样式和摆放位置,比如缩放按钮和缩放滑块在左上角、鼠标位置在右上角、比例尺和小地图在左下角、版权信息在右下角等。可以通过设置自定义类名
className、父元素容器target、文本信息label、title信息tipLabel等配置自定义控件的样式和位置。 target配置的值可以是元素的id,也可以直接是DOM元素。map.getView().setRotation()将视图旋转到指定角度。- 鼠标经纬度实时显示控件的
coordinateFormat参数可以格式化显示的经纬度值。placeholder参数可以配置鼠标不在地图范围内时显示的文本。
代码HTML+CSS+JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>各种工具</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body,
#app,
.app-map {
height: 100%;
height: 100%;
}
.app-btns {
position: fixed;
right: 10px;
top: 50%;
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
width: 210px;
padding: 25px;
text-align: center;
border-radius: 5px;
z-index: 2;
transform: translateY(-50%);
}
#app .app-btns .ctrl {
position: relative;
width: 100%;
height: 100%;
background-color: transparent;
}
.app-btns .contorl button {
font-size: 16px;
border: none;
padding: 0px 15px;
border-radius: 0px;
color: #fff;
background-color: #409eff;
border-color: #409eff;
cursor: pointer;
border: none;
margin-bottom: 5px;
line-height: 40px;
height: 40px;
width: 100%;
}
#app .app-btns button:focus,
#app .app-btns button:hover {
background: #66b1ff;
border-color: #66b1ff;
color: #fff;
outline: none;
}
.app-btns .contorl {
height: 40px;
width: 100%;
margin-bottom: 10px;
}
#zoom-to-extent button {
width: 100%;
}
#zoom .ctrl {
display: flex;
}
#mouse-position {
position: relative;
text-align: center;
}
#mouse-position .ol-mouse-position {
top: 0;
right: 0;
position: relative;
height: 40px;
line-height: 40px;
background-color: #409eff;
border-color: #409eff;
color: #fff;
font-size: 16px;
}
#rotate {
position: relative;
display: flex;
}
#rotate .ol-rotate {
position: relative;
top: 0;
right: 0;
bottom: 0;
width: 50%;
}
#rotate .ol-rotate button {
margin: 0;
}
#rotate .manual-rorate {
width: 50%;
}
#scale-line {
position: relative;
height: 60px;
}
#scale-line .ol-scale-bar {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
#zoom-slider {
position: relative;
height: auto;
}
#zoom-slider .ol-zoomslider {
top: 0;
left: 0;
height: 200px;
position: relative;
width: 36px;
margin: 0 auto;
}
#zoom-slider .ol-zoomslider button {
margin-bottom: 0;
margin: 0;
}
#overview-map {
position: relative;
height: 150px;
}
#overview-map .ol-overviewmap {
left: 5px;
bottom: 0;
}
.ol-attribution,
#attribution {
height: 40px;
line-height: 40px;
}
#rotate .ol-control,
#attribution .ol-control {
background-color: transparent;
}
</style>
</head>
<body>
<div id="app">
<div class="app-map" id="app-map">
<div class="app-btns">
<div class="contorl" id="zoom-to-extent"></div>
<div class="contorl" id="zoom"></div>
<div class="contorl" id="full-screen"></div>
<div class="contorl" id="mouse-position"></div>
<div class="contorl" id="rotate">
<button @click='handleClickRotateMap' type="button" class="manual-rorate">旋转</button>
</div>
<div class="contorl" id="scale-line"></div>
<div class="contorl" id="zoom-slider"></div>
<div id="overview-map"></div>
<div id="attribution"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/dist/ol.min.js" integrity="sha512-xXS2hdEzrUC2BFO0fIJ+d/bwScOLgN+W7psE4XXq6xULXjKFCskUNe8QOVVUsB7vtYRI5ZS0Ie4EgS4VzJQBkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js" integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const { createApp } = Vue;
const vm = createApp({
data() {
return {
map: {}
}
},
methods: {
// 初始化地图
initMap() {
const attributions = '<a href="https://ditu.amap.com/" target="_blank">© 地图版权归高德地图所有</a>';
// 图层资源
const source = new ol.source.XYZ({
attributions: attributions,
url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
});
// 高德地图瓦片地址
const mainLayer = new ol.layer.Tile({
source
});
// 初始化地图
this.map = new ol.Map({
target: 'app-map',
layers: [mainLayer],
controls: ol.control.defaults.defaults({
zoom: true, // 放大缩小工具
zoomOptions: {
zoomInLabel: '放大 +', // 放大按钮文本
zoomInTipLabel: '点击放大', // 放大按钮title
zoomOutLabel: '缩小 -', // 缩小按钮文本
zoomOutTipLabel: '点击缩小', // 缩小按钮title
target: 'zoom', // 父元素ID
className: 'ctrl', // 自定义类名
duration: 500, // 动画效果的持续时间
delta: 0.1 // 每次点击放大缩小的层级,默认为1
},
rotate: true, // 旋转工具
rotateOptions: {
tipLabel: '摆正', // title文本
autoHide: false, // 角度为0的时候是否自动隐藏
target: 'rotate', // 父元素ID
compassClassName: 'icon', // 旋转图标的自定义类名
duration: 250, // 旋转动画的持续时间
resetNorth: (a) => { // 默认是点击后旋转到0度,可自定义点击后的操作,可以覆盖原有的
this.map.getView().setRotation(0);
}
},
attribution: true, // 地图版权信息工具
attributionOptions: {
target: 'attribution', // 父元素ID
collapsed: false, // 默认折叠
collapsible: true // 是否可折叠,显示折叠按钮 106.577545 29.565593
}
}).extend([
// 全屏退出全屏工具
new ol.control.FullScreen({
label: '全屏', // 全屏按钮文本
labelActive: '退出全屏', // 退出全屏按钮文本
tipLabel: '全屏/退出全屏', // 按钮title
className: 'ctrl', // 自定义类名
target: 'full-screen', // 父元素ID
activeClassName: 'is-full', // 全屏状态下按钮自定义类名
inactiveClassName: 'not-full' // 不是全屏状态下按钮自定义类名
}),
// 比例尺工具
new ol.control.ScaleLine({
bar: true, // 展示为柱状,默认是直线
text: true, // 显示比例尺数字 1:421,111,348,当bar为true是生效
units: 'metric', // 单位,默认米制 {'degrees'} {'imperial'} {'nautical'} {'metric'} {'us'}
// className: 'sccale-line', // 自定义类名
steps: 4, // 柱状的比例尺时,将柱状分为几段,默认4
target: 'scale-line'// 父元素ID
}),
// 缩放滑块工具
// https://openlayers.org/en/v8.1.0/examples/zoomslider.html
new ol.control.ZoomSlider({
// className: 'ol-zoomslider ol-zoomslider-custom', // 自定义类名
duration: 500, // 缩放动画执行时间
target: 'zoom-slider' // 父元素ID
}),
// 小地图工具
new ol.control.OverviewMap({
target: 'overview-map', // 父元素ID
className: 'ol-overviewmap ol-overviewmap-custom', // 自定义类名
collapsed: false, // 默认折叠
collapsible: true, // 是否可折叠,显示折叠按钮
label: 'op', // 展开的文本
collapseLabel: 'cl', // 折叠的文本
rotateWithView: false, // 是否跟着地图旋转
tipLabel: '小地图', // 文本的title
layers: [ // 小地图内部的图层
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
})
})
]
}),
// 恢复到置顶视图工具
new ol.control.ZoomToExtent({
extent: [7108532.525146691, 2150882.129043405, 16501114.56082915, 6646602.384664332], // 恢复视图的经纬度范围
label: '恢复默认视图', // 展示的文本
tipLabel: '点击恢复默认视图', // title文本
target: 'zoom-to-extent', // id 或者DOM document.getElementById('zoomToExtent')
className: 'zoomToExtent ctrl' // 自定义类名
}),
// 展示鼠标经纬度工具
new ol.control.MousePosition({
projection: 'EPSG:4326', // 经纬度的坐标系
coordinateFormat: function (coordinate) { // 格式化经纬度
return '(' + coordinate.map(e => {
return e.toFixed(3)
}).join(',') + ')';
},
target: 'mouse-position', // 父元素ID
placeholder: '鼠标不在地图范围内'
})
]),
view: new ol.View({
projection: 'EPSG:3857',
center: ol.proj.transform([106.04453415000009, 36.70986324334069], 'EPSG:4326', 'EPSG:3857'),
zoom: 10
})
});
window.aa = this.map;
},
// 点击旋转地图
handleClickRotateMap () {
this.map.getView().setRotation(Math.floor(Math.random() * (2 * Math.PI)));
}
},
mounted() {
this.initMap();
}
}).mount('#app')
</script>
</body>
</html>