Vue2+OpenLayers实现折线绘制、起始点标记和轨迹打点的完整功能(提供Gitee源码)
目录
一、案例截图
二、安装OpenLayers库
三、代码实现
3.1、HTML页面
3.2、初始化变量
3.3、创建起始点位
3.4、遍历轨迹点
3.5、画折线
3.6、初始化弹窗信息
3.7、初始化地图上标点的点击事件
3.8、完整代码
四、Gitee源码
一、案例截图
二、安装OpenLayers库
npm install ol
三、代码实现
整体的实现思路:
1、创建开始、结束点位。
2、遍历轨迹点信息
3、画出轨迹折线
4、初始化弹窗样式
5、初始化地图上标点的点击事件。
3.1、HTML页面
关键代码:
<template>
<div>
<div id="map-container"></div>
<div id="popup-box" class="popup-box">
<button id="close-button" class="close-button">×</button>
<div id="popup-content" class="popup-content"></div>
</div>
</div>
</template>
3.2、初始化变量
关键代码:
data() {
return {
map:null,
overLay:null,
// 定义路径坐标
pointList: [
[120.430070,31.938140],
[120.428570,31.939100],
[120.429530,31.941680],
[120.431240,31.943580],
[120.432410,31.944820],
[120.433600,31.943970],
],
pointLayer: new VectorLayer({
source: new VectorSource(),
zIndex: 5
}),
}
},
3.3、创建起始点位
关键代码:
/**
* 创建开始点位
*/
createStartPoint(){
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(this.pointList[0]),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 设置图片效果
image: new Icon({
src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
// anchor: [0.5, 0.5],
scale: 1,
}),
zIndex: 10,
}),
);
this.pointLayer.getSource().addFeature(feature);
},
//创建结束点位
createEndPoint(){
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(this.pointList[this.pointList.length-1]),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 设置图片效果
image: new Icon({
src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
// anchor: [0.5, 0.5],
scale: 1,
}),
zIndex: 10
}),
);
this.pointLayer.getSource().addFeature(feature);
},
3.4、遍历轨迹点
先封装一个创建轨迹点的方法:
关键代码:
//创建轨迹点位
addPoint(coordinate) {
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(coordinate),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 使用 Circle 图形
image: new Circle({
radius: 10, // 圆的半径
fill: new Fill({
color: 'white', // 内部颜色
}),
stroke: new Stroke({
color: 'blue', // 外部颜色
width: 3, // 外圈线宽
}),
}),
zIndex: 5
}),
);
return feature;
},
遍历轨迹点:
关键代码:
/**
* 遍历点位
*/
drawPoints(){
this.createStartPoint();
for(let i = 0 ; i < this.pointList.length ; i++){
let feature = this.addPoint(this.pointList[i]);
this.pointLayer.getSource().addFeature(feature);
}
this.createEndPoint();
this.map.addLayer(this.pointLayer);
},
3.5、画折线
关键代码:
//画线
drawLine(){
// 创建线特征
const lineFeature = new Feature({
geometry: new LineString(this.pointList),
});
// 设置线样式
const lineStyle = new Style({
stroke: new Stroke({
color: '#25C2F2',
width: 4,
lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
}),
});
lineFeature.setStyle(lineStyle);
// 创建矢量层并添加特征
const vectorSource = new VectorSource({
features: [lineFeature],
});
const vectorLayer = new VectorLayer({
source: vectorSource,
zIndex: 1
});
// 将矢量层添加到地图
this.map.addLayer(vectorLayer);
// 设置地图视图以适应路径
this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
padding: [20, 20, 20, 20],
maxZoom: 18,
});
},
3.6、初始化弹窗信息
关键代码:
/**
* 初始化弹窗信息
*/
initPointWindow() {
let popupBox = document.getElementById('popup-box');
let closeButton = document.getElementById('close-button');
//用于显示详情页面的窗口(根据经纬度来的,位置不固定)
this.overlay = new Overlay({
element: popupBox,
autoPan: {
animation: {
duration: 250,
},
},
offset:[0,-20],
});
this.map.addOverlay(this.overlay);
// 关闭弹出框的事件处理
let _that = this;
closeButton.addEventListener('click', () => {
_that.overlay.setPosition(undefined); // 关闭弹出框
});
},
3.7、初始化地图上标点的点击事件
关键代码:
/**
* 初始化地图上标点的点击事件
*/
initPointEvent(){
let _that = this;
//给点初始化点击事件
this.map.on("singleclick", (e) => {
let pixel = this.map.getEventPixel(e.originalEvent);
let feature = this.map.forEachFeatureAtPixel(pixel, function(feature) { return feature; });
let coordinates = e.coordinate;
if(feature){
_that.overlay.setPosition(coordinates);
let popupContent = document.getElementById('popup-content');
popupContent.innerHTML = `<div>经度:${coordinates[0]}</div><div>纬度:${coordinates[1]}</div>`;
}
});
},
3.8、完整代码
<template>
<div>
<div id="map-container"></div>
<div id="popup-box" class="popup-box">
<button id="close-button" class="close-button">×</button>
<div id="popup-content" class="popup-content"></div>
</div>
</div>
</template>
<script>
import { Map, View } from 'ol'
import {Tile as TileLayer} from 'ol/layer'
import Overlay from 'ol/Overlay';
import { get } from 'ol/proj';
import { getWidth, getTopLeft } from 'ol/extent'
import { WMTS } from 'ol/source'
import WMTSTileGrid from 'ol/tilegrid/WMTS'
import { defaults as defaultControls} from 'ol/control';
import 'ol/ol.css';
import OSM from 'ol/source/OSM';
import { Feature } from 'ol';
import LineString from 'ol/geom/LineString';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Style from 'ol/style/Style';
import Stroke from 'ol/style/Stroke';
import {Circle, Fill, Icon} from "ol/style";
import CircleStyle from "ol/style/Circle";
import {Point} from "ol/geom";
export const projection = get("EPSG:4326");
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = [];
for (let z = 0; z < 19; ++z) {
resolutions[z] = size / Math.pow(2, z);
}
export default {
data() {
return {
map:null,
overLay:null,
// 定义路径坐标
pointList: [
[120.430070,31.938140],
[120.428570,31.939100],
[120.429530,31.941680],
[120.431240,31.943580],
[120.432410,31.944820],
[120.433600,31.943970],
],
pointLayer: new VectorLayer({
source: new VectorSource(),
zIndex: 5
}),
}
},
mounted(){
this.initMap() // 加载矢量底图
},
methods:{
initMap() {
const KEY = '你申请的KEY'
this.map = new Map({
target: 'map-container',
layers: [
// 底图
new TileLayer({
source: new WMTS({
url: `http://t{0-6}.tianditu.com/vec_c/wmts?tk=${KEY}`,
layer: 'vec', // 矢量底图
matrixSet: 'c', // c: 经纬度投影 w: 球面墨卡托投影
style: "default",
crossOrigin: 'anonymous', // 解决跨域问题 如无该需求可不添加
format: "tiles", //请求的图层格式,这里指定为瓦片格式
wrapX: true, // 允许地图在 X 方向重复(环绕)
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
})
})
}),
// 标注
new TileLayer({
source: new WMTS({
url: `http://t{0-6}.tianditu.com/cva_c/wmts?tk=${KEY}`,
layer: 'cva', //矢量注记
matrixSet: 'c',
style: "default",
crossOrigin: 'anonymous',
format: "tiles",
wrapX: true,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
})
})
})
],
view: new View({
center: [119.975000,31.809701],
projection: projection,
zoom: 12,
maxZoom: 17,
minZoom: 1
}),
//加载控件到地图容器中
controls: defaultControls({
zoom: false,
rotate: false,
attribution: false
})
});
//画点
this.drawPoints();
//画线
this.drawLine();
//初始化窗体
this.initPointWindow();
//初始化标点点击事件
this.initPointEvent();
},
/**
* 创建开始点位
*/
createStartPoint(){
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(this.pointList[0]),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 设置图片效果
image: new Icon({
src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
// anchor: [0.5, 0.5],
scale: 1,
}),
zIndex: 10,
}),
);
this.pointLayer.getSource().addFeature(feature);
},
//创建结束点位
createEndPoint(){
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(this.pointList[this.pointList.length-1]),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 设置图片效果
image: new Icon({
src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
// anchor: [0.5, 0.5],
scale: 1,
}),
zIndex: 10
}),
);
this.pointLayer.getSource().addFeature(feature);
},
//创建轨迹点位
addPoint(coordinate) {
// 创建feature要素,一个feature就是一个点坐标信息
let feature = new Feature({
geometry: new Point(coordinate),
});
// 设置要素的图标
feature.setStyle(
new Style({
// 使用 Circle 图形
image: new Circle({
radius: 10, // 圆的半径
fill: new Fill({
color: 'white', // 内部颜色
}),
stroke: new Stroke({
color: 'blue', // 外部颜色
width: 3, // 外圈线宽
}),
}),
zIndex: 5
}),
);
return feature;
},
/**
* 遍历点位
*/
drawPoints(){
this.createStartPoint();
for(let i = 0 ; i < this.pointList.length ; i++){
let feature = this.addPoint(this.pointList[i]);
this.pointLayer.getSource().addFeature(feature);
}
this.createEndPoint();
this.map.addLayer(this.pointLayer);
},
//画线
drawLine(){
// 创建线特征
const lineFeature = new Feature({
geometry: new LineString(this.pointList),
});
// 设置线样式
const lineStyle = new Style({
stroke: new Stroke({
color: '#25C2F2',
width: 4,
lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
}),
});
lineFeature.setStyle(lineStyle);
// 创建矢量层并添加特征
const vectorSource = new VectorSource({
features: [lineFeature],
});
const vectorLayer = new VectorLayer({
source: vectorSource,
zIndex: 1
});
// 将矢量层添加到地图
this.map.addLayer(vectorLayer);
// 设置地图视图以适应路径
this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
padding: [20, 20, 20, 20],
maxZoom: 18,
});
},
/**
* 初始化地图上标点的点击事件
*/
initPointEvent(){
let _that = this;
//给点初始化点击事件
this.map.on("singleclick", (e) => {
let pixel = this.map.getEventPixel(e.originalEvent);
let feature = this.map.forEachFeatureAtPixel(pixel, function(feature) { return feature; });
let coordinates = e.coordinate;
if(feature){
_that.overlay.setPosition(coordinates);
let popupContent = document.getElementById('popup-content');
popupContent.innerHTML = `<div>经度:${coordinates[0]}</div><div>纬度:${coordinates[1]}</div>`;
}
});
},
/**
* 初始化弹窗信息
*/
initPointWindow() {
let popupBox = document.getElementById('popup-box');
let closeButton = document.getElementById('close-button');
//用于显示详情页面的窗口(根据经纬度来的,位置不固定)
this.overlay = new Overlay({
element: popupBox,
autoPan: {
animation: {
duration: 250,
},
},
offset:[0,-20],
});
this.map.addOverlay(this.overlay);
// 关闭弹出框的事件处理
let _that = this;
closeButton.addEventListener('click', () => {
_that.overlay.setPosition(undefined); // 关闭弹出框
});
},
}
}
</script>
<style scoped>
#map-container {
width: 100%;
height: 100vh;
}
.popup-box {
background: rgba(255, 255, 255, 0.95);
border: 1px solid #ccc;
border-radius: 8px;
padding: 20px;
z-index: 1000;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
max-width: 300px;
font-family: 'Arial', sans-serif;
position: absolute;
transform: translate(-50%, -100%); /* 使弹出框上移并居中 */
}
/* 添加箭头样式 */
.popup-box::after {
content: "";
position: absolute;
top: 100%; /* 箭头位于弹出框的底部 */
left: 50%; /* 箭头横向居中 */
margin-left: -6px; /* 调整箭头与弹出框的间距 */
border-width: 6px; /* 箭头的大小 */
border-style: solid;
border-color: rgba(255, 255, 255, 0.95) transparent transparent transparent; /* 箭头的颜色 */
}
.close-button {
background: none;
color: gray;
border: none;
font-size: 20px;
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
.popup-content {
width: 240px;
margin-top: 10px;
font-size: 16px;
line-height: 1.5;
}
</style>
四、Gitee源码
地址:Vue2+OpenLayers实现折线绘制起始点标记和轨迹打点的完整功能