openlayer + vue 地图辅助包
一个开箱即用、功能齐全、可高度配置的 Vue2 + OpenLayers 地图容器组件。
支持 多种底图切换、聚合点位、绘制测量、闪烁动画、点位序号、坐标转换 等常用能力,全部封装成 一行调用 的 API。
✨ 特性一览
| 类别 |
能力 |
状态 |
| 地图控制 |
缩放/平移/旋转/范围限制/级别限制/比例尺/滑动缩放/缩略图/全屏 |
✅ |
| 图层管理 |
矢量图层增删改查、Z-index、显隐、按 ID 清理 |
✅ |
| 覆盖物 |
Overlay 添加/删除/按 ID 查询、闪烁动画、CSS 扩散 |
✅ |
| 点位渲染 |
批量单点、序号、自定义图标、文字偏移、聚合(高性能) |
✅ |
| 绘制测量 |
线/面绘制、实时长度面积、分段提示、一键清除 |
✅ |
| 坐标系 |
自动 4326 ↔ 3857 互转、地图投影自适应 |
✅ |
| 事件 |
单击/双击/右键/移动/缩放/聚合点击/鼠标悬停 |
✅ |
| 性能 |
聚合缓存、节流 60 fps、内存清理、生命周期销毁 |
✅ |
🛠 依赖
{
"@turf/along": "^6.5.0",
"@turf/area": "^6.5.0",
"@turf/bbox-polygon": "^6.0.1",
"@turf/boolean-contains": "^6.0.1",
"@turf/buffer": "^5.1.5",
"@turf/kinks": "^7.3.1",
"@turf/length": "^6.5.0",
"@turf/line-intersect": "^6.5.0",
"core-js": "^2.6.5",
"ol": "^6.15.1"
}
npm 下载
📦 安装
npm install vue-openlayers-d -S
main.js 配置
//main.js 加入引用
import openlayersD from 'vueOpenlayersD'
// import 'vue-openlayers-d/dist/vue-openlayers-d.css'
Vue.use(openlayersD)
🗺️ 地图对象
Props 参数
| 参数 |
类型 |
默认值 |
说明 |
center |
Array |
[] |
地图初始中心点 [x,y] |
layerMapDefault |
String |
- |
默认底图服务地址 |
zoom |
Number |
16 |
初始缩放级别 |
minZoom |
Number |
2 |
最小缩放级别 |
maxZoom |
Number |
28 |
最大缩放级别 |
projection |
String |
EPSG:3857 |
投影坐标系 |
extent |
Array |
[] |
初始范围 |
isOpenScaleLine |
Boolean |
true |
是否显示比例尺 |
isOpenZoomSlider |
Boolean |
true |
是否显示缩放条 |
isOpenOverview |
Boolean |
true |
是否显示鹰眼 |
isOpenFullScreen |
Boolean |
false |
是否显示全屏按钮 |
isOpenBottomZoom |
Boolean |
false |
是否显示右下角缩放值 |
mapType |
Number |
4 |
底图类型 (业务自定义) |
config |
Object |
{} |
额外配置 |
noLayer |
Boolean |
false |
是否禁用默认底图 |
Events 回调事件
| 事件名 |
参数 |
说明 |
ready |
{ map } |
地图初始化完成 |
click |
{ lon,lat,feature,attributes } |
点击地图要素/空白处 |
clickCluster |
Array, center |
点击聚合点时返回聚合内所有 attributes |
dblclick |
{ lon, lat } |
双击地图 |
rightClick |
{ lon, lat } |
右键地图 |
pointerMove |
Object |
鼠标移动经过要素 |
zoomMoveEnd |
{ zoom, center, extent } |
缩放或移动结束 |
zoomend |
{ zoom, center, extent } |
缩放级别变化 |
视角控制
| 方法 |
参数 |
返回值 |
说明 |
setCenter(point) |
[x, y] |
— |
设置中心点 |
getCenter() |
— |
[x, y] |
获取当前中心 |
setLevel(level) |
Number |
— |
设置缩放级别 |
getLevel() |
— |
Number |
获取当前级别 |
centerAt(x, y) |
x, y |
— |
移动中心到指定坐标 |
centerArray(point) |
[x, y] |
— |
同 setCenter |
centerAndZoom(x, y, level) |
x, y, level |
— |
一次性定位并缩放 |
zoomIn() |
— |
— |
放大一级 |
zoomOut() |
— |
— |
缩小一级 |
setExtent(extent) |
{minX,minY,maxX,maxY} |
— |
缩放到指定范围 |
getCurrentExtent() |
— |
{minX,minY,maxX,maxY} |
当前视口 |
getExtent() |
— |
[minX,minY,maxX,maxY] |
当前视口(数组形式) |
图层管理
| 方法 |
参数 |
返回值 |
说明 |
addLayer(config) |
Object |
ol/layer/Vector |
创建并添加矢量/聚合图层 |
removeLayer(id) |
String |
— |
根据 id 删除图层 |
removeLayerById(id) |
String |
— |
同上 |
removeBaseMapLayer() |
— |
— |
移除所有底图 |
switchBaseMap(config) |
Object |
— |
一键切换底图 |
getLayer(id) |
String |
ol/layer/Base / null |
按 id 取图层 |
getAllLayers() |
— |
Array<ol/layer/Base> |
所有图层 |
clearLayerFeatures(id) |
String |
— |
清空指定矢量图层要素 |
isLayerExist(id) |
String |
Boolean |
是否存在 |
setVisible(id) |
String |
— |
显/隐切换 |
addRootLayer(config) |
Object |
— |
向地图直接追加底图图层 |
addGeoJson |
geojson,styles = { color: '#62aad0', width: 2 } |
- |
添加 geojson 格式边界 |
覆盖物(Overlay)
| 方法 |
参数 |
返回值 |
说明 |
addOverlay(overlay) |
ol/Overlay |
— |
添加覆盖物 |
removeOverlay(overlay) |
ol/Overlay |
— |
删除覆盖物 |
getOverlayById(id) |
String |
ol/Overlay / null |
按 id 取覆盖物 |
deleteOverlayById(id) |
String |
— |
删除 |
getOverlays() |
— |
Array<ol/Overlay> |
全部覆盖物 |
坐标转换
| 方法 |
参数 |
返回值 |
说明 |
wGS84ToMercator(point) |
[lon,lat] |
[x,y] |
4326 → 3857 |
mercatorToWGS84(point) |
[x,y] |
[lon,lat] |
3857 → 4326 |
辅助工具
| 方法 |
参数 |
返回值 |
说明 |
getViewport() |
— |
HTMLElement |
地图视口 DOM |
getTargetElement() |
— |
HTMLElement |
地图容器 DOM |
getSize() |
— |
[width,height] |
容器像素尺寸 |
render() |
— |
— |
手动触发地图重绘 |
updateSize() |
— |
— |
容器尺寸变化后刷新地图 |
createMapPolygon() |
— |
— |
容器尺寸变化后刷新地图 |
例子
<OpenLayers
class="map"
ref="olmap"
:zoom="map.zoom"
:center="map.center"
:projection="map.projection"
:layerMapDefault="map.layerMapDefault"
@click="pointClick"
@zoomend="zoomend"
@ready="ready"
></OpenLayers>
let map= {
center: [79.92941, 37.123631], //中心点
zoom: 11, //地图缩放级别
projection: "EPSG:4326", //地图的投影坐标系,
mapType:4,
maxZoom: 19, ///最大缩放级别
minZoom: 6, //最小缩放级别
layerMapDefault:
"https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}"
//瓦片服务地址
}
pointClick(obj) {
console.log('地图点击')
},
zoomend() {},
ready(obj) {
console.log('地图加载完成')
this.mapObj = obj.map
let config={
layerName: 'layer-root',
id: 'ol-map-root',
...this.map
}
this.$refs.olmap.addRootLayer(config)
//点位转跳
this.$refs.olmap.centerAndZoom(87.60834, 43.829723, 16)
}
📍 点标注组件(MapIconMark)
| 参数名 |
必选 |
类型 |
说明 |
| position |
是 |
Array |
点位 [array] [lon, lat] |
| label |
否 |
String |
显示文本信息 |
| icon |
否 |
Object |
如果只要标签名称就设置成一个像素的透明图标, 必须 |
| elmentName |
否 |
Object |
默认 'el-mapIconMark' |
| className |
否 |
String |
默认 'map-icon-mark' |
| zIndex |
否 |
Number |
z 轴高度, 非必须, 默认 800 |
<MapIconMark
:position="mapIconData.position"
:label="mapIconData.label"
:icon='mapIconData.icon'
:elementName="mapIconData.elementName"
:className="mapIconData.className">
</MapIconMark>
🎯 JS 画标注点
| 参数名 |
必选 |
类型 |
说明 |
| position |
是 |
Array |
点位 [array] [lon, lat] |
| id |
是 |
String |
唯一 id |
| icon |
否 |
Object |
标注图片 |
| attributes |
否 |
Object |
附加属性 |
| label |
否 |
String |
显示文本信息 |
| style |
否 |
String |
文本信息样式 |
let defaultStle = {
font: '14px Microsoft YaHei',
color: '#fff',
offsetX: 0,
offsetY: 30,
padding: [2, 10, 0, 10],
bgColor: 'rgba(0,0,0,0.5)'
}
let config = {
position: [87.60081797338869, 43.83722919055176],
id: 'layerMark',
icon: require('./mark.png'),
attributes: { name: '标注点位' },
label: '测试点位',
style: { bgColor: 'rgba(255,1,1,0.5)' }
}
this.$refs.olmap.createIconMark(config)
📈 折线组件(MapLineString)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| pointList |
必须 |
array [[lon, lat],...] |
组成线的点列表数组 Array, 必须 |
|
| lineColor |
否 |
String |
线条颜色 |
'#409eff' |
| lineWidth |
否 |
number |
线条宽度 |
2 |
| lineDash |
否 |
Array[number] |
是否使用虚线 |
null |
| className |
否 |
number |
图层的 className |
map-line-string |
| zIndex |
否 |
number |
图层 z 轴高度 |
300 |
| elementName |
否 |
String |
feature.get('name')方法可以获得该叠加图层 |
el-mapLineString |
<MapLineString
:pointList="mapLineStringData.pointlist"
:lineColor="mapLineStringData.lineColor"
:lineWidth="mapLineStringData.lineWidth"
:lineDash="mapLineStringData.lineDash"
:elementName="mapLineStringData.elementName"
:className="mapLineStringData.className"
></MapLineString>
🟦 多边形组件(MapPolygon)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| pointList |
必须 |
array [[lon, lat],...] |
组成多边形的点列表数组 Array, 必须 |
|
| fillColor |
否 |
String |
线条填充颜色 |
'rgba(0,0,0,0.8)' |
| lineColor |
否 |
String |
多边形线条颜色 |
'#409eff' |
| lineWidth |
否 |
number |
线条宽度 |
2 |
| lineDash |
否 |
Array[number] |
是否使用虚线 识别名称 识别名称 |
null |
| className |
否 |
number |
图层的 className |
map-polygon |
| zIndex |
否 |
number |
图层 z 轴高度 |
300 |
| elementName |
否 |
String |
识别名称 |
el-mapPolygon |
<MapPolygon
:pointList="mapPolygonData.pointlist"
:fillColor="mapPolygonData.fillColor"
:lineColor="mapPolygonData.lineColor"
:lineWidth="mapPolygonData.lineWidth"
:lineDash="mapPolygonData.lineDash"
:elementName="mapPolygonData.elementName"
:className="mapPolygonData.className">
</MapPolygon>
🔴 圆形组件(MapCircle)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| position |
必须 |
array [lon, lat] |
圆中心点 |
|
| radius |
否 |
number |
圆半径 number |
100 |
| fillColor |
否 |
String |
圆形填充颜色 |
'rgba(255,255,255,0.5)' |
| lineColor |
否 |
String |
线条颜色 |
'#409eff' |
| lineWidth |
否 |
number |
线条宽度 |
2 |
| lineDash |
否 |
Array[number] |
是否使用虚线 |
null |
| className |
否 |
number |
图层的 className |
map-circle |
| zIndex |
否 |
number |
图层 z 轴高度 |
300 |
| elementName |
否 |
String |
圆形识别名称 |
el-mapCircle |
<MapCircle
:position="mapCircleData.position"
:radius="mapCircleData.radius"
:fillColor="mapCircleData.fillColor"
:lineColor="mapCircleData.lineColor"
:lineWidth="mapCircleData.lineWidth"
:lineDash="mapCircleData.lineDash"
:elementName="mapCircleData.elementName"
:className="mapCircleData.className">
</MapCircle>
📌 自定义覆盖物(MapOverlay)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| position |
必须 |
Array[array] |
标注中心点 Array, 必须 |
|
| className |
否 |
String |
设置自定义图层的 class String |
map-overlay |
| offset |
否 |
Array[number] |
弹窗偏移 |
默认为 [0, 0] |
<MapOverlay
:position="mapOverlayData.position"
:className="mapOverlayData.className">
<div>
</div>
</MapOverlay>
💬 弹出窗体(MapPopup)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| position |
必须 |
Array[array] |
弹窗中心点 |
|
| mapShow |
必须 |
Boolean |
弹窗显隐 |
|
| title |
否 |
String |
弹窗标题 |
|
| offset |
否 |
Array[number] |
弹窗偏移 |
默认为 [0, 0] |
| className |
否 |
String |
图层的 className |
默认为 'map-popup' |
| bodyStyle |
否 |
String |
内容样式 |
|
| showClose |
否 |
Boolean |
是否显示关闭按钮 |
|
Events
| 事件名称 |
说明 |
回调参数 |
| close |
关闭事件 |
- |
<MapPopup
:position="mapPopupData.position"
:title="mapPopupData.title"
:offset="mapPopupData.offset"
:mapShow="mapPopupData.show"
@close="mapPopupClose"
:className="'map-popup'">
{{ popupText }}
</MapPopup>
mapPopupData: {
position: [87.621589, 43.827187], // 弹窗中心点 Array[array], 必须
title: "点位标题详情", // 弹窗标题 String,非必须,默认为 ' '
show: false, // 弹窗显隐 Boolean,必须,默认为 true
offset: [0, 0], // 弹窗偏移 Array[number],必须,默认为 [0, 0]
className: "map-popup", // 图层的class String,非必须,默认为 'map-popup'
attributes: {}
}
🌟 海量点(MapPointCollection)
Attributes
| 参数名 |
必选 |
类型 |
说明 |
默认值 |
| pointlist |
必须 |
array [[lon, lat],...] |
点列表数组 |
|
| distance |
否 |
number |
收起点的间距 |
40 |
| zIndex |
否 |
String |
图层 z 轴高度 |
400 |
| offset |
否 |
Array[number] |
弹窗偏移 |
默认为 [0, 0] |
| fontColor |
否 |
String |
文字的颜色 |
'#fff' |
| fillColor |
否 |
String |
线条填充颜色 |
'#f00' |
| img |
否 |
String |
点位图片 |
蓝色点 |
| bgImg |
否 |
String |
设置背景图 |
|
| className |
否 |
String |
图层的 className |
默认为 'map-point-collection' |
| elementName |
否 |
String |
图层的 id 标识 |
默认为 'el-mapPointCollection' |
<MapPointCollection
:pointList="mapPointCollectionData.pointlist"
:distance="mapPointCollectionData.distance"
:fillColor="mapPointCollectionData.fillColor"
:fontColor="mapPointCollectionData.fontColor"
:zIndex='mapPointCollectionData.zIndex'
:offset="mapPointCollectionData.offset">
</MapPointCollection>
mapPointCollectionData: {
pointlist: [],
distance: 100, // 收起点的间距 number,必须,默认为 40
zIndex: 500, // 图层z轴高度, 非必须, 默认 400
offset: [0, 2], // 文字偏移距离 [x,y], 非必须, 默认 [0,0]
fontColor: "#000", // 文字的颜色 string (色彩标识,支持rgba),默认'#fff'(如果去掉文字那么直接rgba透明度设置为0)
fillColor: "#2290e799", // 文字的背景颜色 string(色彩标识,支持rgba),默认'#f00'(如果去不要背景颜色那么直接rgba透明度设置为0)
scale: 0.6 //图标缩放大小
}
🔗 聚合点位组件 (MapClusterLayer)
✨ 核心能力
| 能力 |
状态 |
| 万级点位 秒级聚合 |
✅ |
| 平滑清空 不卡界面 |
✅(图层替换 + 异步分批) |
| 点击聚合 散列动画 |
✅(带关闭按钮) |
| 单点 / 聚合 样式自定义 |
✅ |
| 自动 4326 ↔ 3857 坐标转换 |
✅ |
| 增量更新 无闪烁 |
✅ |
| 防抖 10w+ 数据 |
✅ |
| 内存泄漏保护 |
✅ |
🎯 Props 参数
| 属性 |
类型 |
默认值 |
说明 |
id |
String |
必填 |
图层唯一标识 |
name |
String |
必填 |
图层名称 |
features |
Array |
[] |
点位数据,见下方格式 |
visible |
Boolean |
true |
是否显示 |
zIndex |
Number |
6 |
图层层级 |
clusterDistance |
Number |
100 |
聚合距离(像素) |
img |
String |
蓝点图标 |
单点默认图标 URL |
scale |
Number |
0.9 |
图标缩放 |
fontColor |
String |
'#fff' |
聚合数字颜色 |
fillColor |
String |
渐变蓝 |
聚合圆填充色 |
offset |
Array |
[0, 2] |
文字偏移 [x, y] |
noClusterZoom |
Number |
18 |
该级别以上不聚合 |
clusterStyleFn |
Function |
- |
自定义聚合样式 `(size)=>{color,radius} |
📡 事件 Event
| 事件 |
回调参数 |
触发时机 |
@featureClick |
{feature,type,center,coods,attributes} |
点击单个点位 |
@clusterClick |
Array<同上> |
点击聚合群 |
@clearDone |
- |
清空完成 |
📋 features 数据格式
;[
{
geom: { lon: 116.3974, lat: 39.9092 },
attributes: { id: 1, name: '车辆-101', icon: '/img/car.png' }
}
// ...支持 10w+ 条
]
icon 留空则使用默认 bluePoint
🎨 自定义聚合样式
:clusterStyleFn="size => ({
color: size > 100 ? '#ff4d4f' : '#91c7ff',
radius: size > 100 ? 30 : 16
})"
📦 快速使用
<MapClusterLayer
id="deviceLayer"
name="deviceLayer"
ref="deviceLayer"
:features="deviceLayerConfig.features"
:fontColor="deviceLayerConfig.fontColor"
:fillColor="deviceLayerConfig.fillColor"
:img="deviceLayerConfig.img"
:scale="deviceLayerConfig.scale"
@featureClick="onPointClick"
@clusterClick="onClusterClick"
/>
let deviceLayerConfig= {
features: [{
geom: {
type: 'Point',
lon: 12.111,
lat: 6.111
},
attributes: {
type: 'device',
index: index,
info: {},
id: index,
icon: '/icon/red.png'
}
}
],
img: require("./1-06.png"), //点位图标 默认为蓝色小点
fontColor: "#fff", //字体颜色 默认#FFF
fillColor: "#2290e799", //背景颜色 默认 #2290e799
scale: 0.5 //默认为0.9
},
通过 js 生成聚合点位
| 参数名 |
必选 |
类型 |
说明 |
| id |
是 |
String |
唯一 ID |
| features |
是 |
Array |
点位集合 array [[lon, lat],...] |
| img |
否 |
Object |
点位图标 |
| scale |
否 |
Number |
图标缩放比例 |
| fontColor |
否 |
Number |
字体颜色 |
| fillColor |
否 |
Number |
背景颜色 |
| clusterDistance |
否 |
Number |
聚合间隔 |
| offset |
否 |
Number |
偏移量 |
const uqPoints = Array.from({ length: 100 }, (_, i) => ({
geom: {
lon: 87.3 + Math.random() * 0.4, // 87.3 ~ 87.7
lat: 43.7 + Math.random() * 0.2 // 43.7 ~ 43.9
},
attributes: { id: i + 1000, name: `点位${i + 1}` }
}));
// 使用
this.$refs.olmap.createClusterTemplate({
id: 'poi-cluster',
name: '乌鲁木齐设备聚合',
features: uqPoints,
clusterDistance: 60
})
后台服务聚合只返回数字
<MapServerClusterLayer
id="serverLayer"
name="serverLayer" ref="serverLayer"
:features="serverLayerConfig.features"
:fontColor="serverLayerConfig.fontColor"
:fillColor="serverLayerConfig.fillColor"
:img="serverLayerConfig.img"
:scale="serverLayerConfig.scale" />
serverLayerConfig: {
features: [{
geom: {
type: 'Point',
...points
},
attributes: {
type: 'device',
index: index,
pointType: 1, //针对后台聚合功能 0是普通点位 1是聚合点位
count: 100, //聚合点位数量
info: {},
id: index
}
}],
img: require("./1-06.png"), //点位图标 默认为蓝色小点
fontColor: "#fff", //字体颜色
fillColor: "#fea81a99", //背景颜色
scale: 0.5 //默认为0.9
},
📡 FlashPoint 雷达扩散点覆盖物
一个用于在 OpenLayers 地图上添加可自定义颜色 + 任意属性的实心雷达扩散动画点的便捷方法。该点使用 CSS 动画实现扩散效果,支持挂载自定义数据到 DOM 与 Overlay 实例。
📥 参数说明
| 参数名 |
类型 |
必填 |
默认值 |
说明 |
id |
string |
否 |
'point_animation' |
覆盖物唯一标识,用于后续删除或查找。若已存在同 ID 覆盖物,将先删除再创建。 |
point |
Array |
是 |
— |
点的经纬度坐标,格式为 [lng, lat](注意:OpenLayers 默认使用 [x, y],请确保坐标系匹配)。 |
color |
string |
否 |
'#e6a23c' |
雷达扩散点的颜色,支持任意 CSS 颜色值(如 red, #ff0000, rgba(...))。通过 CSS 变量 --radar-color 注入样式。 |
attributes |
Object |
否 |
{} |
任意自定义属性对象。键值对将被挂载: • 到 DOM 元素的 dataset(对象值会被 JSON.stringify) • 到 Overlay 实例的 .attributes 属性(原始对象,未序列化) |
🎯 返回值
Overlay 实例:OpenLayers 的 Overlay 对象,可用于后续操作(如移除、更新位置等)。
🧪 使用示例
// 添加一个红色雷达点
const overlay = this.$refs.olmap.setFlashPoint(
'warning_point',
[120.123456, 30.123456],
'red',
{
type: 'alert',
level: 'high',
timestamp: Date.now()
}
)
// 后续可通过 overlay.attributes 访问原始数据
console.log(overlay.attributes.level) // 'high'
// 或通过 DOM dataset 访问(字符串化)
console.log(overlay.getElement().dataset.level) // "high"
🚗 轨迹动画 并出现小车按照轨迹移动(MapTrailAnimate)
一个基于 OpenLayers 的轨迹动画 Vue 组件,支持小车沿轨迹移动、起点终点标记、播放控制等功能。
📋 功能特性
- 🚗 轨迹动画 - 小车沿预设轨迹平滑移动
- 🎯 起点终点标记 - 自定义图标标记起终点
- ⏯️ 播放控制 - 播放、暂停、重启、速度调节
- 🔁 循环播放 - 支持动画循环播放
- 🎯 跟随模式 - 地图自动跟随小车移动
- 🎨 样式定制 - 自定义图标、线条样式、箭头等
- 📊 事件系统 - 丰富的状态变化事件回调
- 🛡️ 健壮性 - 完善的错误处理和边界检查
⚙️ Props 配置
| 属性名 |
类型 |
默认值 |
说明 |
features |
Array |
[] |
轨迹点数组 [[lng, lat], ...] |
startPic |
String |
defaultImage.startPic |
起点图标 URL |
endPic |
String |
defaultImage.endPic |
终点图标 URL |
carPic |
String |
defaultImage.carPic |
小车图标 URL |
loop |
Boolean |
false |
是否循环播放 |
speed |
Number |
10 |
动画速度 (1-100,数字越小越快) |
lineStyle |
Object |
{} |
轨迹线条样式配置 |
attributes |
Object |
{} |
自定义属性 |
<template>
<OpenLayers ref="map" :center="[116.4, 39.9]" :zoom="12">
<MapTrailAnimate
ref="trail"
:features="trailPoints"
:speed="trailSpeed"
:loop="trailLoop"
@positionUpdate="onPositionUpdate"
@animationEnd="onAnimationEnd"
/>
<button @click="$refs.trail.pause()">暂停</button>
<button @click="$refs.trail.resume()">继续</button>
<button @click="$refs.trail.restart()">重播</button>
<button @click="$refs.trail.toggleFollow()">跟随</button>
</OpenLayers>
</template>
<script>
export default {
data() {
return {
trailPoints: [
[87.575309, 43.816728],
[87.60081797338869, 43.83722919055176]
],
trailSpeed: 50,
trailLoop: false,
lineStyle: {
strokeColor: '#ff6600',
strokeWeight: 5,
showDir: false,
dirStep: 50
}
}
}
}
</script>
线条样式配置
lineStyle:{
zIndex: 2, // 覆盖物的叠加顺序
showDir: true, // 是否显示白色方向箭头
dirStep:100 //白色方向箭头的间距默认100 showDir:true时生效
strokeOpacity: 0.9, // 线条透明度
strokeWeight: 5, // 线条宽度
strokeStyle: "solid", // 轮廓线样式,实线: solid 虚线:dashed
strokeDasharray: [], // 轮廓线间隙
lineCap: "butt", // 折线两端线帽的绘制样式,默认值为'butt'无头,其他可选值:'round'圆头、'square'方头
lineJoin: "round", // 折线拐点的绘制样式,默认值为'round'圆角,其他可选值:'round'圆角、'bevel'斜角
isOutline: false, // 线条是否带描边,默认false
borderWeight: 10, // 描边的宽度,默认为1
outlineColor: "#000000", // 线条描边颜色,此项仅在isOutline为true时有效,默认:#000000
extData: null, // 自定义信息
strokeColor: "#28F"// 默认填充颜色
}
🎯 事件回调
| 事件名 |
参数 |
说明 |
start |
- |
动画开始 |
end |
- |
动画结束 |
paused |
- |
动画暂停 |
resumed |
- |
动画继续 |
restarted |
- |
动画重新开始 |
loopStart |
- |
循环开始 |
turnPoint |
{index} |
到达转弯点 |
positionUpdate |
{index, coordinate, progress} |
位置更新 |
positionJump |
{index} |
位置跳转 |
followToggled |
follow |
跟随模式切换 |
animationStart |
- |
动画开始 |
animationEnd |
- |
动画结束 |
error |
error |
错误发生 |
🎛️ 方法 API
播放控制
// 播放控制
this.$refs.trail.pause() // 暂停
this.$refs.trail.resume() // 继续
this.$refs.trail.restart() // 重新开始
this.$refs.trail.stopAndContinue() // 暂停/继续切换
// 速度控制
this.$refs.trail.setSpeed(50) // 设置速度 (1-100)
// 跟随模式
this.$refs.trail.toggleFollow() // 切换跟随模式
// 状态查询
this.$refs.trail.getStatus() // 获取当前状态
this.$refs.trail.isPlaying() // 是否正在播放
this.$refs.trail.isPaused() // 是否暂停
this.$refs.trail.getProgress() // 获取进度百分比
this.$refs.trail.getCurrentPosition() // 获取当前位置
状态查询
// 获取状态
const status = this.$refs.trail.getStatus()
// {
// isPlaying: true,
// isPaused: false,
// currentIndex: 5,
// totalPoints: 20,
// progress: 0.25,
// isLoop: false,
// speed: 50,
// follow: true
// }
// 其他查询方法
this.$refs.trail.getProgress() // 进度百分比
this.$refs.trail.getCurrentPosition() // 当前坐标
this.$refs.trail.getTotalPoints() // 总点数
this.$refs.trail.isPlaying() // 是否播放中
this.$refs.trail.isPaused() // 是否暂停
JS 绘画 Line
| 参数名 |
必选 |
类型 |
说明 |
| features |
是 |
Array |
点位集合 array [[lon, lat],...] |
| id |
是 |
String |
唯一 ID |
| attributes |
否 |
String |
附加属性 非必填 |
| lineStyle |
否 |
JSON |
线条样式 |
let points = [
[87.575309, 43.816728],
[87.60081797338869, 43.83722919055176],
[87.61420756079103, 43.82950442858887],
[87.64012842871095, 43.847872195922854],
[87.618283, 43.892136]
]
let lineStyle = {
zIndex: 2, // 覆盖物的叠加顺序
showDir: true, // 是否显示白色方向箭头
dirStep:100 //白色方向箭头的间距默认100 showDir:true时生效
strokeOpacity: 0.9, // 线条透明度
strokeWeight: 5, // 线条宽度
strokeStyle: 'solid', // 轮廓线样式,实线: solid 虚线:dashed
strokeDasharray: [], // 轮廓线间隙
lineCap: 'butt', // 折线两端线帽的绘制样式,默认值为'butt'无头,其他可选值:'round'圆头、'square'方头
lineJoin: 'round', // 折线拐点的绘制样式,默认值为'round'圆角,其他可选值:'round'圆角、'bevel'斜角
isOutline: false, // 线条是否带描边,默认false
borderWeight: 10, // 描边的宽度,默认为1
outlineColor: '#000000', // 线条描边颜色,此项仅在isOutline为true时有效,默认:#000000
extData: null, // 自定义信息
strokeColor: '#28F' // 默认填充颜色
}
let config = {
features: points,
id: 'LineLayer',
attributes: { name: '测试' },
lineStyle: lineStyle
}
this.$refs.olmap.createLine(config)
JS 画圆 drawCircle
| 参数名 |
类型 |
必须 |
默认值 |
描述 |
| id |
String |
否 |
'el-map-circle' |
圆形图层的唯一标识符,用于后续查找和删除图层。 |
| position |
Array |
否 |
[0, 0] |
圆心的经纬度坐标,格式为 [经度, 纬度]。 |
| radius |
number |
否 |
100 |
圆的半径,单位为米。 |
| lineColor |
String |
否 |
'#409eff' |
圆边框的颜色,使用标准的 CSS 颜色格式(如十六进制、RGB 等)。 |
| lineWidth |
number |
否 |
2 |
圆边框的宽度,单位为像素。 |
| lineDash |
Array |
否 |
null |
圆边框的虚线模式,指定线段和间隔的长度,例如 [4, 2] 表示 4 像素的线段和 2 像素的间隔。 |
| fillColor |
String |
否 |
'rgba(255,255,255,0.5)' |
圆内部的填充颜色,使用标准的 CSS 颜色格式。 |
| zIndex |
number |
否 |
200 |
圆形图层的 Z 轴索引,用于控制图层的显示顺序。 |
| className |
String |
否 |
'map-circle' |
圆形图层的 CSS 类名,用于样式定制。 |
| attributes |
Object |
否 |
null |
附加在圆形要素上的自定义属性数据,可以用于存储与圆形相关的额外信息。 |
this.$refs.olmap.drawCircle({
position: [87.611935, 43.963691],
radius: 1000,
id: 'circle-beijing',
width: 3,
lineColor: '#ff0000',
fillColor: 'rgba(255, 0, 0, 0.3)',
attributes:{name:123}
})
this.$refs.olmap.centerAt(87.611935, 43.963691)
🔥 热力图(MapHeat)
| 参数名 |
必选 |
类型 |
说明 |
| name |
否 |
string |
图层名字 |
| data |
是 |
object / array |
热力图的数据[{lon: 87.620,lat: 43.837,weight: 0.2}] |
| gradient |
否 |
array |
热力图渲染色带颜色 |
| longitude |
否 |
string |
热力图数据中代表经度的字段(默认为 lon) |
| latitude |
否 |
string |
热力图数据中代表纬度的字段(默认为 lat) |
| radius |
否 |
number |
每个像素渲染点半径 |
| blur |
否 |
number |
模糊度 |
| zIndex |
否 |
string / number |
图层层级,默认为 1 |
| visible |
否 |
boolean |
图层是否可见,默认为 false |
<MapHeat :map="mapObj" :data="heatData"></MapHeat>
this.heatData.push({
log: 87.62081797338869, // 经度
lat: 43.83722919055176, // 纬度
weight: 0.2 // 该坐标点的权重值(0-1之间的小数)
})
📏 测量工具(MapMeasureTool) 测距 测面积
Attributes
| 参数名 |
必选 |
类型 |
说明 |
| name |
否 |
string |
图层名字 |
| actived |
是 |
Bool |
绘画状态 true 开始 |
| type |
否 |
string |
LineString 测距 Polygon 测面积 默认 Polygon |
Events
| 事件名称 |
说明 |
回调参数 |
| mesureEnd |
绘画完成事件 |
object |
<MapMeasureTool :name="'MapMeasureTool'" :id="'MapMeasureTool'" :actived="actived" :type="'LineString'" @mesureEnd="mesureEnd"></MapMeasureTool>
✏️ 绘制工具(MapDraw)绘制圆形矩形多边形
| 参数名 |
必选 |
类型 |
说明 |
| name |
否 |
string |
图层名字 |
| actived |
是 |
Bool |
绘画状态 true 开始 |
| type |
是 |
string |
Circle 圆形 Box 多边形 默认矩形 Polygon |
Events
| 事件名称 |
说明 |
回调参数 |
| mesureEnd |
绘画完成事件 |
object |
<MapDraw id="drawLayers" name="绘制图层" :actived="drawActive" @drawend="drawFinish" :type="drawType"></MapDraw>
🏷️ 海量文本标注(addTextLabels)
| 参数名 |
类型 |
默认值 |
说明 |
cfg |
Object |
{} |
配置对象 |
├─ layerId |
string |
text-layer |
图层唯一标识,重复调用自动复用 |
├─ id |
string |
text-layer |
同 layerId,二选一即可 |
├─ zIndex |
number |
100 |
图层层级 |
├─ data |
Array<Object> |
[] |
标注数据,每一项必须包含 text 和 coord |
├─ style |
Object | Function |
{} |
文字样式对象,或 (text)=>Style 函数 |
├─ onClick |
Function |
— |
点击回调 (feature, attrs, evt)=>{} |
├─ onHover |
Function |
— |
悬停回调 (feature, attrs, evt)=>{} |
├─ onMouseOut |
Function |
— |
鼠标移出回调 (feature, attrs, evt)=>{} |
├─ clearBefore |
boolean |
false |
首次渲染前是否清空旧数据 |
// 1. 一次性渲染
const labels = this.$refs.olmap.addTextLabels({
layerId: 'city-names', // 图层 id(重复调用会复用同一层)
data: [
{
text: '北京',
coord: fromLonLat([116.404, 39.915]),
attributes: { id: 1 }
},
{ text: '上海', coord: fromLonLat([121.4737, 31.2304]) }
],
style: {
// 文字样式
font: 'bold 14px Arial',
fillColor: '#ff0000',
strokeColor: '#fff',
strokeWidth: 2,
offsetX: 0,
offsetY: 0
},
onClick: (feature, attrs, evt) => console.log('点击 →', attrs.text),
onHover: (feature, attrs, evt) => console.log('悬停 →', attrs.text),
onMouseOut: (feature, attrs, evt) => console.log('移出 →', attrs.text),
clearBefore: false, // 首次渲染是否清空旧数据
zIndex: 100 // 图层层级
})
// 2. 动态追加 / 替换
labels.update([{ text: '广州', coord: fromLonLat([113.2644, 23.1291]) }], {
clear: true
}) // clear=true 先清空再添加
// 3. 仅移除图层
labels.remove()
// 4. 完全销毁(清理交互)
labels.dispose()
setMapIconMarks 添加标注物 图片+文字
list 数组字段
| 字段 |
类型 |
必填 |
默认值 |
说明 |
id |
string |
✔ |
— |
唯一标识,用于增量更新 |
position |
[number, number] |
✔ |
— |
坐标 [lng, lat] |
icon |
string |
✖ |
opts.defaultIcon |
图标 URL |
scale |
number |
✖ |
opts.defaultScale |
图标缩放比例 |
label |
string |
✖ |
— |
标注文本 |
attributes |
Object |
✖ |
{} |
任意附加属性,会透传到 feature 上 |
opts 配置字段
| 字段 |
类型 |
必填 |
默认值 |
说明 |
layerKey |
string |
✖ |
_map_icon_marks_layer |
图层唯一标识 |
className |
string |
✖ |
map-icon-marks |
图层 CSS class |
zIndex |
number |
✖ |
30 |
图层层级 |
defaultIcon |
string |
✖ |
/img/bluePoint.png |
默认图标 URL |
defaultScale |
number |
✖ |
1.5 |
默认缩放比例 |
// 模拟生成 5 个点
const points = [
{
id: 'p1',
position: [87.3, 43.7],
icon: '/img/hot.png',
label: '点位1',
attributes: { pop: 100 }
},
{
id: 'p2',
position: [87.35, 43.75],
icon: '/img/hot.png',
label: '点位2',
attributes: { pop: 200 }
},
{
id: 'p3',
position: [87.4, 43.78],
label: '点位3',
attributes: { pop: 150 }
}
]
// 添加/更新图标图层
const layer = setMapIconMarks(points, {
className: 'my-icon-layer',
zIndex: 50,
defaultIcon: '/img/default.png'
})
// 后续更新或删除某些点,只需再次调用 setMapIconMarks
const updatedPoints = [
{
id: 'p1',
position: [87.31, 43.71],
label: '点位1更新',
attributes: { pop: 120 }
},
{
id: 'p4',
position: [87.42, 43.79],
icon: '/img/new.png',
label: '新增点',
attributes: { pop: 300 }
}
]
this.$refs.olmap.setMapIconMarks(updatedPoints)
🟨 多边形绘制(createMapPolygon)
| 参数 |
类型 |
默认值 |
说明 |
id |
String |
el-mapPolygon |
图层唯一标识,重复调用会先删除旧层 |
className |
String |
map-polygon |
图层 CSS 类名 |
attributes |
Object |
— |
任意业务属性,挂载到 feature |
zIndex |
Number |
200 |
层级 |
lineColor |
String |
rgba(0,0,0,0.6) |
边框颜色 |
lineWidth |
Number |
2 |
边框宽度 |
lineDash |
Array |
null |
虚线样式,如 [5, 5] |
fillColor |
String |
rgba(0,0,0,0.1) |
填充色,支持透明 |
pointList |
Array |
— |
必填 坐标数组,见下 |
projection |
String |
EPSG:4326 |
传入坐标的坐标系 |
// 在组件 methods 中直接调用
this.$refs.olmap.createMapPolygon({
id: 'fence',
pointList: [
[120, 30],
[121, 30],
[121, 31],
[120, 31],
[120, 30] // 外环闭合
],
fillColor: 'rgba(255,0,0,0.2)',
lineColor: '#ff0000',
lineWidth: 3,
zIndex: 200
})
参数总览
| 参数 |
类型 |
默认值 |
说明 |
polygons |
Array<Object> |
[] |
必填 多边形配置数组 |
layerKey |
String |
_batch_polygon_layer |
图层唯一标识,重复调用自动替换 |
className |
String |
map-batch-polygon |
图层 CSS 类名 |
zIndex |
Number |
200 |
图层叠加层级 |
单条多边形配置(polygons[i])
| 字段 |
类型 |
说明 |
id |
String |
多边形唯一标识(可选,用于属性查询) |
pointList |
Array |
必填 坐标数组,见下方格式 |
lineColor |
String |
边框颜色,默认 #007bff |
lineWidth |
Number |
边框宽度,默认 2 |
lineDash |
Array |
虚线样式,如 [5, 5] |
fillColor |
String |
填充色,默认 rgba(0,0,0,0.1) |
attributes |
Object |
任意业务字段,挂载到 feature |
projection |
String |
传入坐标系,默认 EPSG:4326 |
返回值
| 字段 |
类型 |
说明 |
layer |
ol/layer/Vector |
图层实例,可进一步操作 |
remove |
Function |
调用立即删除整张图层 |
// 1) 导入方法
// 已在组件 methods 中提供 createMapPolygons
// 2) 准备数据
const polygons = [
{
id: 'area1',
pointList: [
[120, 30],
[121, 30],
[121, 31],
[120, 31],
[120, 30] // 外环
],
fillColor: 'rgba(255,0,0,0.3)',
lineColor: '#f00',
lineWidth: 2,
attributes: { name: 'A区域' } // 任意业务字段
},
{
id: 'area2',
pointList: [
[
[120.5, 30.5],
[120.8, 30.5],
[120.8, 30.8],
[120.5, 30.8],
[120.5, 30.5]
], // 外环
[
[120.6, 30.6],
[120.7, 30.6],
[120.7, 30.7],
[120.6, 30.7],
[120.6, 30.6]
] // 内环(孔)
],
fillColor: 'rgba(0,128,255,0.2)',
lineDash: [5, 5],
attributes: { name: 'B区域(带孔)' }
}
]
// 3) 调用
const { layer, remove } = this.createMapPolygons(polygons, {
layerKey: 'myPolygons',
zIndex: 300
})
// 4) 一键删除
// remove()
// 更新数据
this.createMapPolygons(newPolygons, { layerKey: 'myPolygons' })
addPointsWithNumbers 使用说明
一键在 OpenLayers 地图上批量绘制 带数字序号 的点位(图标 + 文字),支持 自定义图标、偏移、样式、坐标系自动转换 等。
1. 快速上手
// 最简单的调用
mapComp.addPointsWithNumbers({
points: [
{ lon: 116.3974, lat: 39.9092 },
{ lon: 121.4737, lat: 31.2304 }
]
})
2. 参数总览
| 字段 |
类型 |
默认值 |
说明 |
layerId |
string |
'custom-points-layer' |
图层 ID,重复调用会先删除旧图层 |
points |
Array |
[] |
必填 点位数组,支持三种写法,见下方 |
center |
number[] |
this.center |
地图中心备用坐标 |
iconUrl |
string |
'' |
图标完整 URL,留空则显示圆点 |
iconScale |
number |
0.5 |
图标缩放 |
showNumber |
boolean |
true |
是否显示数字 |
startIndex |
number |
1 |
序号起始值 |
font |
string |
'14px Calibri,sans-serif' |
文字字体 |
textColor |
string |
'#000' |
文字颜色 |
strokeColor |
string |
'#fff' |
文字描边颜色 |
strokeWidth |
number |
2 |
文字描边宽度 |
offsetX |
number |
0 |
文字水平偏移(像素) |
offsetY |
number |
-10 |
文字垂直偏移(像素) |
zIndex |
number |
0 |
图层层级 |
3. 点位数据格式
三种写法均可混用:
// ① 对象式(推荐)
{ lon: 116.3, lat: 39.9, text: 'A', attributes: { id: 1001 } }
// ② 数组式
[116.3, 39.9]
// ③ 备用中心(当 lon/lat 缺失时使用)
{ lon: null, lat: null } // 会退化成 center
4. 自定义单点样式
{
lon: 116.3,
lat: 39.9,
text: '起', // 显示文字
style: {
iconUrl: '/img/start.png',
iconScale: 0.8,
offsetX: 10, // 单独偏移
offsetY: -20,
textColor: '#ff0000',
font: 'bold 16px Arial'
}
}
单点 style 里的字段会 覆盖全局参数。
5. 完整示例
// 删除旧图层并重新绘制
mapComp.addPointsWithNumbers({
layerId: 'patrol-points',
points: [
{ lon: 116.3974, lat: 39.9092, text: '起' },
{ lon: 116.41, lat: 39.915 },
{ lon: 116.42, lat: 39.92, text: '终', style: { iconUrl: '/img/end.png' } }
],
iconUrl: '/img/dot.png',
iconScale: 0.6,
startIndex: 0,
offsetY: -15,
zIndex: 999
})
6. 返回值
| 类型 |
说明 |
VectorLayer |
OpenLayers 矢量图层实例,可后续手动移除或隐藏 |
null |
参数异常或点位为空,已自动输出错误日志 |
7. 错误排查速查表
| 现象 |
快速定位 |
| 一个点都不显示 |
① console.log(points) 看有没有数据 ② 看控制台是否报 坐标无效 |
| 只显示圆点无数字 |
① showNumber 被设成 false ② text 为空且 startIndex 不是数字 |
| 图标不显示 |
① 浏览器 网络面板 404 → 地址写错 ② 跨域 → 服务器加 Access-Control-Allow-Origin:* |
| 文字偏移不对 |
用 offsetX / offsetY 一次调 1-2 像素,实时刷新看效果 |
8. 与地图坐标系无关
函数内部已自动:
// 如果地图不是 EPSG:4326,会自动 fromLonLat
if (mapProjection !== 'EPSG:4326') {
pointCoords = fromLonLat([lon, lat], mapProjection)
}
无论地图是 3857 还是 4326,直接给经纬度即可。
9. 清理图层
// 按 ID 移除
mapComp.removeLayerById('patrol-points')
✈️MapFlyline飞线组件
让地图飞线像电影一样丝滑:粒子 + 流光尾巴 + 起点终点标记,一行组件即可拥有。
✨ 特性
| 功能 |
状态 |
| 粒子动画 |
✅ 连续插值,60 FPS |
| 流光拖尾 |
✅ 紧跟粒子,无黑色 |
| 起点/终点标记 |
✅ 可独立开关 |
| 性能优化 |
✅ 视野裁剪 + 帧率节流 |
| 颜色/速度/宽度 |
✅ 全 props 控制 |
| WebGL 就绪 |
✅ 分段 ≤ 20,GPU 友好 |
⚙️ Props
| 属性 |
类型 |
默认值 |
说明 |
id |
String |
- |
图层唯一标识 |
name |
String |
- |
图层名称 |
flights |
Array |
[] |
飞线数据,见下方格式 |
visible |
Boolean |
true |
显示/隐藏 |
zIndex |
Number |
10 |
图层叠放顺序 |
lineColor |
String |
'#00ffff' |
底线颜色 |
lineWidth |
Number |
2 |
底线宽度 |
lineOpacity |
Number |
0.8 |
底线透明度 |
particleColor |
String |
'#ffffff' |
粒子颜色 |
particleSize |
Number |
4 |
粒子半径 |
glow |
Boolean |
true |
是否开启流光拖尾 |
glowColor |
String |
'#52e884' |
流光主色 |
glowWidth |
Number |
6 |
流光宽度(像素) |
glowTrailLength |
Number |
0.3 |
拖尾占全长比例 |
glowSpeed |
Number |
0.02 |
流光流动速度(0-1) |
animationDuration |
Number |
3000 |
单趟动画时长(ms) |
loop |
Boolean |
true |
是否循环播放 |
density |
Number |
1 |
0-1 线路采样率,<1 时随机丢弃 |
showStartPoint |
Boolean |
true |
显示起点标记 |
showEndPoint |
Boolean |
true |
显示终点标记 |
startPointStyle |
Object |
{color:'#00ff00', size:6} |
起点样式 |
endPointStyle |
Object |
{color:'#ff0000', size:6} |
终点样式 |
📡 Events
| 事件 |
参数 |
说明 |
flightClick |
{feature, flightData, index, coordinate} |
点击飞线时触发 |
🔧 快速使用
<template>
<MapFlyline
id="fly-1"
name="北京→上海"
:flights="flights"
:visible="true"
:zIndex="10"
lineColor="#00ffff"
glowColor="#52e884"
:glowWidth="6"
:glowTrailLength="0.3"
:speed="5"
:animationDuration="3000"
:loop="true"
@flightClick="onFlightClick"
/>
</template>
<script>
import MapFlyline from '@/components/MapFlyline.vue'
export default {
components: { MapFlyline },
data() {
return {
flights: [
{
from: { lon: 116.4074, lat: 39.9042 }, // 北京
to: { lon: 121.4737, lat: 31.2304 }, // 上海
curve: 0.3, // 弯曲度
value: 80 // 热力值
}
]
}
},
methods: {
onFlightClick(e) {
console.log('点击飞线', e.flightData, e.index)
}
}
}
</script>