openlayers
是一个用于开发WebGIS
客户端的JavaScript
包,它是一个开源的项目,其设计之意是为互联网客户端提供强大的地图展示功能,包括地图数据显示与相关操作,并具有灵活的扩展机制。
架构
Map
:整个地图的容器Layer
:地图图层Source
:对应图层的数据源Style
:矢量图层的样式View
:地图表现相关的视图
坐标系
库默认使用EPSG:4326
地理坐标系,EPSG:3857
投影坐标系展示地图。
在创建视图时,若使用EPSG:4326
坐标系覆盖默认的EPSG:3857
投影,用于展示地图,在这种情况下,openLayers
会将经纬度坐标直接映射到屏幕坐标系,而不会进行任何投影转换。
使用经纬度投影时,经度的范围为
-180
度至+180
度,纬度的范围为-90
度至+90
度。较小纬度的区域(如赤道附近)会在屏幕上呈现较大的比例因子,而较高纬度的区域(如极地附近)会呈现较小的比例因子。
需要注意的是,使用经纬度投影时,地图上的直线不一定是直的,因为经纬度本身是曲线坐标系。如果需要在地图上绘制直线,或者进行测量和几何计算等操作,可能需要先将经纬度坐标转换为其他投影坐标系(如投影坐标系,如
Web
墨卡托投影EPSG:3857
),然后再进行相应的操作。
安装和使用
bash
npm i ol --save
Map
和View
map
是ol
总的核心组件,初始化地图(map
)时,至少需要一个可视化区域(view
)、一个或多个图层(layer
)、一个地图加载的目标html
元素(target
)
js
import Map from 'ol/map';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import Tile from 'ol/layer/Tile';
const map = new Map({
target: document.getElementById('map'),
layers: [
new Tile({
source: new OSM(),
}),
],
view: new View({
zoom: 4,
center: [108.358224, 22.904248],
}),
});
坐标系注册和转换
若需要使用其他坐标系,可以进行注册,如下注册了一个GCJ02
地理坐标系并添加到了库中:
js
const GCJ02 = new ol.proj.Projection({
// 坐标系代码
code: 'GCJ:02',
// 坐标系范围
extent: [-180, -90, 180, 90],
// 坐标系分辨率使用的单位
units: 'degrees',
// 用于确定坐标系的坐标轴方向
axisOrientation: 'enu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(GCJ02);
若该坐标系也使用EPSG:3857
投影,则需要配置他们直接的转换关系:
js
// 定义GCJ02地理坐标系和web墨卡托投影坐标系之间的转换规则
ol.proj.addCoordinateTransforms(
'GCJ:02',
'EPSG:3857',
function (coordinate) {
// GCJ02火星坐标系转换为投影坐标系是使用经纬度直接转换,只有当前地理坐标系为WGS84时,经纬度可以被直接转换为EPSG:3857。
// 若当前坐标系使用 GCJ02,算法会将GCJ02先转为WGS84,再转为EPSG:3857,所以这里将GCJ02视为WGS84进行直接转换
return gcoord.transform(
coordinate, // 经纬度坐标
gcoord.WGS84, // 当前坐标系
gcoord.EPSG3857 // 目标坐标系
);
},
function (coordinate) {
return gcoord.transform(
coordinate, // 投影坐标
gcoord.EPSG3857, // 当前坐标系
gcoord.WGS84 // 目标坐标系
);
}
);
之后可以使用gcoord
工具转换,也可以使用openlayers
自带的方法转换:
js
// 将经纬度坐标从 EPSG:4326 转换为 EPSG:3857 投影坐标系坐标,也可以反向转换
ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857');
// 将经纬度视为 EPSG:4326 转换到指定坐标系
// 默认转换至 EPSG:3857
ol.proj.fromLonLat([lon, lat]);
// 指定转换至 EPSG:3857
ol.proj.fromLonLat([lon, lat], 'EPSG:3857');
// 将坐标信息转换为经纬度,固定转换至 EPSG:4326
// 默认坐标系 EPSG:3857
ol.proj.toLonLat([lon, lat]);
// 指定坐标系
ol.proj.toLonLat([lon, lat], 'EPSG:3857');
demo
以下demo
均为百度地图的demo
,初始化地图的代码init-bmap.js
如下:
Details
js
/*定义百度地图分辨率与瓦片网格*/
const resolutions = [];
for (var i = 0; i <= 19; i++) {
resolutions[i] = Math.pow(2, 18 - i);
}
// 创建百度地理坐标系,
const projBD09 = new ol.proj.Projection({
// 坐标系代码
code: 'BD:09',
// 坐标系范围
extent: [-180, -90, 180, 90],
// 坐标系分辨率使用的单位
units: 'degrees',
// 用于确定坐标系的坐标轴方向
axisOrientation: 'enu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(projBD09);
// 创建百度投影坐标系
const projBD09Meter = new ol.proj.Projection({
// 坐标系代码
code: 'BD:09-Meter',
// 坐标系范围
extent: [-20037726.37, -11708041.66, 20037726.37, 12474104.17],
// 坐标系分辨率使用的单位
units: 'm',
// 用于确定坐标系的坐标轴方向
axisOrientation: 'neu',
});
// 添加到openlayers支持的坐标系
ol.proj.addProjection(projBD09Meter);
// 定义百度投影坐标系和 BD:09 坐标系之间的转换规则
ol.proj.addCoordinateTransforms(
'BD:09',
'BD:09-Meter',
function (coordinate) {
return gcoord.transform(
coordinate, // 经纬度坐标
gcoord.BD09, // 当前坐标系
gcoord.BD09Meter // 目标坐标系
);
},
function (coordinate) {
return gcoord.transform(
coordinate, // 投影坐标
gcoord.BD09Meter, // 当前坐标系
gcoord.BD09 // 目标坐标系
);
}
);
/*加载百度地图离线瓦片不能用ol.source.XYZ,ol.source.XYZ针对谷歌地图(注意:是谷歌地图)而设计,而百度地图与谷歌地图使用了不同的投影、分辨率和瓦片网格。因此这里使用ol.source.TileImage来自行指定投影、分辨率、瓦片网格。*/
const tileGrid = new ol.tilegrid.TileGrid({
origin: [0, 0],
resolutions: resolutions,
});
// 创建百度坐标系切片资源
const bMapSources = new ol.source.TileImage({
projection: 'BD:09-Meter',
tileGrid: tileGrid,
tileUrlFunction: function (tileCoord, pixelRatio, proj) {
let z = tileCoord[0];
let x = tileCoord[1];
let y = -tileCoord[2] - 1;
if (x < 0) x = 'M' + -x;
if (y < 0) y = 'M' + -y;
// return `http://111.12.91.15:28802/map/bmap/${z}/${x}/${y}.png`;
return `https://maponline3.bdimg.com/tile/?qt=vtile&z=${z}&x=${x}&y=${y}&styles=pl&scaler=1&udt=20230616&from=jsapi3_0`;
},
});
// 创建切片图层
const bdMapLayers = new ol.layer.Tile({
source: bMapSources,
});
export default () => {
const view = new ol.View({
// 在百度地图jsapi中为了方便开发者,在底层将经纬度自动转换为墨卡托投影坐标,所以可以直接使用经纬度进行定位
// 在使用openlayers的时候,需要手动对经纬度坐标进行转换,转换为百度的墨卡托投影坐标才能正确显示
center: ol.proj.transform(
[108.34171638707808, 22.818581259540537],
'BD:09',
'BD:09-Meter'
),
zoom: 10, // 缩放
maxZoom: 19,
projection: 'BD:09-Meter',
// 使用和百度切片资源设置的分辨率
resolutions: bMapSources.getTileGrid().getResolutions(),
// 设置缩放级别为整数
constrainResolution: true,
// 关闭无极缩放地图
smoothResolutionConstraint: false,
});
return new ol.Map({
target: 'map',
layers: [bdMapLayers],
view: view,
controls: ol.control.defaults.defaults({
zoom: true,
rotate: true,
attribution: true,
}),
});
};
demo
-点
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
canvas {
backface-visibility: hidden;
transform: translate3d(0, 0, 0);
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const { Draw, Select, Modify } = ol.interaction
const map = initMap()
// 创建一个矢量资源组
const makerSource = new VectorSource()
// 创建一个矢量图层存放点
const makerLayer = new Vector({
source: makerSource,
})
map.addLayer(makerLayer)
// 创建点图形特征
const pointFeature = new Feature({
geometry: new Point(ol.proj.transform(
[108.34171638707808, 22.818581259540537],
"BD:09",
"BD:09-Meter"
))
});
// 设置样式
const fill = new Fill({
color: 'blue',
});
const stroke = new Stroke({
color: 'skyblue',
width: 3,
});
pointFeature.setStyle(new Style({
image: new Circle({
fill: fill,
stroke: stroke,
radius: 10,
}),
zIndex: 2
}));
// 添加到矢量要素资源组
makerSource.addFeature(pointFeature)
// 创建可选交互,图形可以被选中
const selectInteraction = new Select({
// 禁用多选
multi: false,
// 选中样式
style: new Style({
image: new Circle({
fill: new Fill({
color: 'red',
}),
stroke: new Stroke({
color: 'yellow',
width: 3,
}),
radius: 10,
}),
zIndex: 2
})
})
// 选中或取消选中事件
selectInteraction.on('select', (event) => {
const selectedFeature = event.selected[0]
if (selectedFeature) {
// 选中图像坐标点:
const coordinate = ol.proj.transform(
selectedFeature.getGeometry().getCoordinates(),
"BD:09-Meter",
"BD:09"
)
console.log(coordinate)
} else {
// 取消选中
}
})
// 将交互添加至地图
map.addInteraction(selectInteraction)
</script>
</body>
</html>
demo
-多边形样式绘制和编辑删除
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多边形</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
.actions {
position: absolute;
top: 20px;
right: 20px;
}
.actions button {
padding: 5px 10px;
margin-left: 10px;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="actions">
<button class="btn-delete" type="button" style="display: none;">删除选中多边形</button>
<button class="btn-create" type="button">绘制多边形</button>
<button class="btn-add" type="button">直接添加一个多边形</button>
</div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const { Draw, Select, Modify } = ol.interaction
const Polygon = ol.geom.Polygon
const map = initMap()
// 创建一个矢量资源组
const vectoSource = new VectorSource()
// 创建一个矢量图层存放点
const vectorLayer = new Vector({
source: vectoSource,
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new Stroke({
color: 'skyblue',
width: 2
})
})
})
map.addLayer(vectorLayer)
// 操作按钮
const btnDel = document.querySelector('.btn-delete')
const btnCreate = document.querySelector('.btn-create')
const btnAdd = document.querySelector('.btn-add')
// 创建可选交互,图形可以被选中
let selectedFeature
const selectInteraction = new Select({
// 禁用多选
multi: false
})
// 选中时更新当前选中图形
selectInteraction.on('select', (event) => {
selectedFeature = event.selected[0]
if (selectedFeature) {
btnDel.style.display = 'inline-block'
} else {
btnDel.style.display = 'none'
}
})
// 将交互添加至地图
map.addInteraction(selectInteraction)
// 创建可编辑交互,
const modifyInteraction = new Modify({
// 选中的图形可编辑
features: selectInteraction.getFeatures()
})
// 监听 modifyend 事件,当结束编辑时获取多边形的坐标集合
modifyInteraction.on('modifyend', function (event) {
// 获取多边形的边界和内部边界集合
const feature = event.features.getArray()[0];
const polygon = feature.getGeometry();
const coordinates = polygon.getCoordinates()[0].map(item => ol.proj.transform(
item,
"BD:09-Meter",
"BD:09"
));
console.log(coordinates);
});
// 将交互添加至地图
map.addInteraction(modifyInteraction)
// 开始多边形绘制
const startDrawPolygon = (polyCoords) => {
// 选择交互先禁用
selectInteraction.setActive(false)
// 定义绘制样式
const style = new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2
}),
image: new Circle({
radius: 7,
fill: new Fill({
color: '#ffcc33'
})
})
})
// 创建多边形绘制交互
const drawInteraction = new Draw({
source: vectorLayer.getSource(),
type: 'Polygon',
// 设置绘制完成后的样式
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2
}),
image: new Circle({
radius: 7,
fill: new Fill({
color: '#ffcc33'
})
})
})
})
// 添加交互至地图
map.addInteraction(drawInteraction)
// 绘制完成后事件
drawInteraction.on('drawend', (event) => {
// 关闭绘制交互
drawInteraction.setActive(false)
map.removeInteraction(drawInteraction)
// 启用选择交互
selectInteraction.setActive(true)
// 获取多边形的坐标集合
const feature = event.feature;
const polygon = feature.getGeometry();
const coordinates = polygon.getCoordinates()[0].map(item => ol.proj.transform(
item,
"BD:09-Meter",
"BD:09"
));
console.log(coordinates);
})
if (polyCoords) {
const polyFeature = new Feature({
geometry: new Polygon(polyCoords),
})
vectoSource.addFeature(polyFeature);
// 关闭绘制交互
drawInteraction.setActive(false)
map.removeInteraction(drawInteraction)
// 启用选择交互
selectInteraction.setActive(true)
}
}
// 删除选中的图形
const delPolygon = () => {
vectorLayer.getSource().removeFeature(selectedFeature)
selectedFeature = null
btnDel.style.display = 'none'
}
btnDel.addEventListener('click', delPolygon)
btnCreate.addEventListener('click', () => {
startDrawPolygon()
})
btnAdd.addEventListener('click', () => {
const cordStr = '108.37928810485103,22.814679938509663|108.38124641086213,22.812781095654344|108.38289929299995,22.814346810120874|108.3841748868237,22.816262287101505|108.38455217513777,22.816822540109328|108.38449827680718,22.817611432792752|108.38368980184848,22.818494199816865|108.3827465810633,22.818971164222994|108.38153386862524,22.81899387669899|108.38025827480149,22.818960564964552|108.38006064758936,22.81679755590632|108.37928810485103,22.814679938509663'
const polyCoords = [
cordStr.split('|').map(item => item.split(',')).map(item => ol.proj.transform(
item,
"BD:09",
"BD:09-Meter"
))
]
startDrawPolygon(polyCoords)
})
</script>
</body>
</html>
demo
-圆形样式绘制和编辑删除
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>圆形</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
.actions {
position: absolute;
top: 20px;
right: 20px;
}
.actions button {
padding: 5px 10px;
margin-left: 10px;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="actions">
<button class="btn-delete" type="button" style="display: none;">删除选中圆形</button>
<button class="btn-create" type="button">绘制圆形</button>
<button class="btn-add" type="button">直接添加一个圆形</button>
</div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const { Draw, Select, Modify } = ol.interaction
const CircleShape = ol.geom.Circle
const map = initMap()
// 创建一个矢量资源组
const vectoSource = new VectorSource()
// 创建一个矢量图层存放点
const vectorLayer = new Vector({
source: vectoSource,
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new Stroke({
color: 'skyblue',
width: 2
})
})
})
map.addLayer(vectorLayer)
// 操作按钮
const btnDel = document.querySelector('.btn-delete')
const btnCreate = document.querySelector('.btn-create')
const btnAdd = document.querySelector('.btn-add')
// 创建可选交互,图形可以被选中
let selectedFeature
const selectInteraction = new Select({
// 禁用多选
multi: false
})
// 选中时更新当前选中图形
selectInteraction.on('select', (event) => {
selectedFeature = event.selected[0]
if (selectedFeature) {
btnDel.style.display = 'inline-block'
} else {
btnDel.style.display = 'none'
}
})
// 将交互添加至地图
map.addInteraction(selectInteraction)
// 创建可编辑交互,
const modifyInteraction = new Modify({
// 选中的图形可编辑
features: selectInteraction.getFeatures()
})
// 监听 modifyend 事件,当结束编辑时获取多边形的坐标集合
modifyInteraction.on('modifyend', function (event) {
const feature = event.features.getArray()[0];
const circle = feature.getGeometry();
// 获取圆形的圆心坐标和半径
const center = ol.proj.transform(
circle.getCenter(),
"BD:09-Meter",
"BD:09"
);
const radius = circle.getRadius();
// 输出圆形的圆心坐标和半径
console.log(center, radius);
});
// 将交互添加至地图
map.addInteraction(modifyInteraction)
// 开始多边形绘制
const startDrawPolygon = (coords) => {
// 选择交互先禁用
selectInteraction.setActive(false)
// 创建多边形绘制交互
const drawInteraction = new Draw({
source: vectorLayer.getSource(),
type: 'Circle',
// 设置绘制完成后的样式
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.4)'
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2
}),
image: new Circle({
radius: 7,
fill: new Fill({
color: '#ffcc33'
})
})
})
})
// 添加交互至地图
map.addInteraction(drawInteraction)
// 绘制完成后事件
drawInteraction.on('drawend', (event) => {
// 关闭绘制交互
drawInteraction.setActive(false)
map.removeInteraction(drawInteraction)
// 启用选择交互
selectInteraction.setActive(true)
const feature = event.feature;
const circle = feature.getGeometry();
// 获取圆形的圆心坐标和半径
const center = ol.proj.transform(
circle.getCenter(),
"BD:09-Meter",
"BD:09"
);
const radius = circle.getRadius();
// 输出圆形的圆心坐标和半径
console.log(center, radius);
})
if (coords) {
const circleFeature = new Feature({
geometry: new CircleShape(coords.center, coords.radius),
})
vectoSource.addFeature(circleFeature);
// 关闭绘制交互
drawInteraction.setActive(false)
map.removeInteraction(drawInteraction)
// 启用选择交互
selectInteraction.setActive(true)
}
}
// 删除选中的图形
const delPolygon = () => {
vectorLayer.getSource().removeFeature(selectedFeature)
selectedFeature = null
btnDel.style.display = 'none'
}
btnDel.addEventListener('click', delPolygon)
btnCreate.addEventListener('click', () => {
startDrawPolygon()
})
btnAdd.addEventListener('click', () => {
const circle = {
center: ol.proj.transform(
[
108.457123841618,
23.167687666375514
],
"BD:09",
"BD:09-Meter"
),
radius: 5000
}
startDrawPolygon(circle)
})
</script>
</body>
</html>
demo
-geojson
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制行政区域</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
.actions {
position: absolute;
top: 20px;
right: 20px;
}
.actions button {
padding: 5px 10px;
margin-left: 10px;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="actions">
<select class="select-address">
<option value="" selected>请选择区域</option>
<option value="450000000000" data-center="[108.358224, 23.404248]" data-level="2">广西</option>
<option value="450100000000" data-center="[108.320004, 22.82402]" data-level="3">南宁</option>
<option value="450200000000" data-center="[109.411703, 24.314617]" data-level="3">柳州</option>
</select>
<button class="btn-remove" type="button">清除</button>
</div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const GeoJSON = ol.format.GeoJSON
const map = initMap()
// 创建一个矢量资源组
const vectorSource = new VectorSource()
// 创建一个矢量图层存放点
const vectorLayer = new Vector({
source: vectorSource,
})
map.addLayer(vectorLayer)
let areaFeatures
const levelMap = {
1: 5,
2: 8,
3: 9
}
const clearArea = () => {
if (areaFeatures) {
areaFeatures.forEach((feature) => {
vectorSource.removeFeature(feature)
})
areaFeatures.length = 0
}
}
const drawArea = (code, center, level) => {
fetch(`http://111.12.91.15:28802/map/geojson/${code}.json`, {
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
method: 'GET'
}).then(res => {
res.json().then(data => {
// 清除原边界
clearArea()
// 生成要素
const geojsonFormat = new GeoJSON();
data.features.forEach(function (feature) {
const coordinates = feature.geometry.coordinates;
const transformedCoordinates = coordinates.map(coordinateList => {
return coordinateList.map((coordinate) => {
return coordinate.map(item => {
return ol.proj.transform(
item,
"BD:09",
"BD:09-Meter"
)
})
})
});
feature.geometry.coordinates = transformedCoordinates;
});
areaFeatures = geojsonFormat.readFeatures(data);
// 添加到资源组
vectorSource.addFeatures(areaFeatures);
// 设置中心点
const mapView = map.getView()
mapView.animate({ zoom: levelMap[level] }, { center });
})
})
}
document.querySelector('.btn-remove').addEventListener('click', clearArea)
document.querySelector('.select-address').addEventListener('change', event => {
const areaCode = event.target.value
if (areaCode) {
const options = Array.from(event.target.querySelectorAll('option'))
const current = options.find(option => option.value === areaCode)
drawArea(areaCode, ol.proj.transform(
JSON.parse(current.dataset.center),
"BD:09",
"BD:09-Meter"
), current.dataset.level)
}
})
</script>
</body>
</html>
demo
-窗口内地图范围坐标
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>获取窗口内地图范围坐标</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
.actions {
position: absolute;
top: 20px;
right: 20px;
}
.actions button {
padding: 5px 10px;
margin-left: 10px;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="actions">
<button class="btn-compute" type="button">查询当前视口坐标</button>
</div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const map = initMap()
document.querySelector('.btn-compute').addEventListener('click', () => {
const extent = map.getView().calculateExtent(map.getSize());
const formatExtent = [
...ol.proj.transform(
[extent[0], extent[1]],
"BD:09-Meter",
"BD:09"
),
...ol.proj.transform(
[extent[2], extent[3]],
"BD:09-Meter",
"BD:09"
)
]
alert(`[minx, miny, maxx, maxy]:${formatExtent}`)
})
</script>
</body>
</html>
demo
-比例尺功能、平移缩放控件
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>比例尺功能、平移缩放控件</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const ScaleLine = ol.control.ScaleLine
const map = initMap()
// 创建一个 ScaleLine 控件实例
const scaleLineControl = new ScaleLine({
// 设置比例尺单位为度量制(metric)
units: 'metric'
});
// 添加 ScaleLine 控件到地图中
map.addControl(scaleLineControl);
</script>
</body>
</html>
demo
-图标和动画
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图标和动画</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const map = initMap()
// 创建一个矢量资源组
const makerSource = new VectorSource()
// 创建一个矢量图层存放点
const makerLayer = new Vector({
source: makerSource,
})
map.addLayer(makerLayer)
// 创建点图形特征
const pointFeature = new Feature({
geometry: new Point(ol.proj.transform(
[108.34171638707808, 22.818581259540537],
"BD:09",
"BD:09-Meter"
))
});
// 创建图标
const icon = new Icon({
anchor: [0.5, 1],
src: '../../images/location.png',
width: 40,
height: 40,
})
// 把图标添加到图形特征样式
pointFeature.setStyle(new Style({
image: icon,
zIndex: 2,
}));
// 添加到矢量要素资源组
makerSource.addFeature(pointFeature)
// 添加动画
const current = {
value: 0
}
anime({
targets: current,
value: 1,
direction: 'alternate',
loop: true,
duration: 500,
easing: function (el, i, total) {
return function (t) {
return Math.pow(Math.sin(t * (i + 1)), total);
}
},
update: function () {
const next = [0, 20 * current.value]
// 更新图标的偏移量
icon.setDisplacement(next)
// 触发更新
pointFeature.changed()
}
});
</script>
</body>
</html>
demo
-自定义覆盖物,显示html
结构
Details
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点</title>
<link rel="stylesheet" href="./style/ol.css">
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh
}
.info-window {
background-color: #fff;
padding: 20px;
border-radius: 20px;
box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.2);
color: plum;
font-size: 20px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/gcoord/dist/gcoord.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="./lib/ol.js"></script>
<script type="module">
import initMap from './lib/init-bmap.js';
const { getVectorContext } = ol.render
const Feature = ol.Feature
const Point = ol.geom.Point
const VectorSource = ol.source.Vector
const { Tile, Vector } = ol.layer
const { Style, Circle, Fill, Stroke, Icon } = ol.style
const Overlayer = ol.Overlay
const map = initMap()
const element = document.createElement('div')
element.innerHTML = `<h1>hello world</h1><button type="button" class="btn-close" >点击关闭</button>`
const infoWindow = new Overlayer({
id: 'infoWindow',
element,
position: ol.proj.transform(
[108.358224, 22.904248],
"BD:09",
"BD:09-Meter"
),
// 坐标为该窗口的左下角
positioning: 'bottom-left',
autoPan: true,
className: 'info-window'
})
map.addOverlay(infoWindow)
document.querySelector('.btn-close').addEventListener('click', () => {
map.removeOverlay(infoWindow)
})
</script>
</body>
</html>