#写在前面#
最近看了点openlayers的内容。官方api都是英文的,例子也难找。所以把openlayers的基本组件封装了一下方便以后使用。分别封装了 <点标注>,<折线>,<多边形>,<圆形>,<自定义覆盖物>,<弹出窗体>,<海量点> 这几个组件。
GitHub地址:https://github.com/zmannnnn/openlayers | 点击跟踪项目地址
开始
1, 安装
npm install ol
2,建立一个公共的地图配置文件,mapconfig.js(随便丢在哪里都可以,放在main.js一起也行,后面调用)
import TileLayer from 'ol/layer/Tile'
import { OSM, XYZ, TileArcGISRest } from 'ol/source'
const maptype = 2
// 0 表示部署的离线瓦片地图,1表示OSM, 2表示使用Arcgis在线午夜蓝地图服务
const streetmap = function() {
let maplayer = null
switch(maptype) {
case 0:
maplayer = new TileLayer({
source: new XYZ({
url:'http://127.0.0.1:7080/streetmap/shenzhen/{z}/{x}/{y}.jpg'
})
})
break
case 1:
maplayer = new TileLayer({
source: new OSM()
})
break
case 2:
maplayer = new TileLayer({
source:new TileArcGISRest({
url:'https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer'
})
})
break
}
return [ maplayer ]
}
const mapconfig = {
streetmap: streetmap
}
export default mapconfig
建立openlayers的vue页面
3,建立地图页面(注意开启了esline的要屏蔽掉esline的 no-unused-var 报错)
vue,openlayers地图页面代码:
<template>
<div class="openlayer">
<div id="map" ref="rootmap">
<!-- 弹出窗体 -->
<MapPopup :position="mapPopupData.position" :title="mapPopupData.title" :offset="mapPopupData.offset" :mapShow="mapPopupData.show" @close="mapPopupClose" :className="'map-popup'">{{ popupText }}</MapPopup>
<!-- 点标注,如果只想用文字标注label,可以把图片设置成一个像素的透明图片,如果只想用图标就label设置为null,单独的懒得封装了,-->
<MapIconMark :position="mapIconData.position" :label="mapIconData.label" :icon='mapIconData.icon' :elementName="mapIconData.elementName" :className="mapIconData.className"></MapIconMark>
<!-- 折线 -->
<MapLineString :pointList="mapLineStringData.pointlist" :lineColor="mapLineStringData.lineColor" :lineWidth="mapLineStringData.lineWidth" :lineDash="mapLineStringData.lineDash" :elementName="mapLineStringData.elementName" :className="mapLineStringData.className"></MapLineString>
<!-- 多边形 -->
<MapPolygon :pointList="mapPolygonData.pointlist" :fillColor="mapPolygonData.fillColor" :lineColor="mapPolygonData.lineColor" :lineWidth="mapPolygonData.lineWidth" :lineDash="mapPolygonData.lineDash" :elementName="mapPolygonData.elementName" :className="mapPolygonData.className"></MapPolygon>
<!-- 自定义覆盖物 -->
<MapOverlay :position="mapOverlayData.position" :className="mapOverlayData.className"><div><img :src="mapOverlayData.img" alt=""></div></MapOverlay>
<!-- 圆形 -->
<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>
<!-- 海量点 -->
<MapPointCollection :pointList="mapPointCollectionData.pointlist" :distance="mapPointCollectionData.distance" :fillColor="mapPointCollectionData.fillColor" :fontColor="mapPointCollectionData.fontColor" :zIndex='mapPointCollectionData.zIndex' :offset="mapPointCollectionData.offset"></MapPointCollection>
<!-- pointlist -->
<!-- 循环使用的方法 -->
<template v-for="(item,index) of pointlist">
<MapIconMark :position="item" :icon='iconImg' :key="index" :label="'标记点' + String(index)"></MapIconMark>
</template>
<!-- 路径示例 -->
<MapLineString :pointList="pointlist" :lineColor="'red'" :lineWidth="5" :lineDash="null" :elementName="'轨迹'" :className="'map-road'"></MapLineString>
</div>
<!-- <MapPolyLine :center="pointlist"></MapPolyLine> -->
<div class="click-center">{{clickCenter}}</div>
</div>
</template>
<script>
// @ is an alias to /src
import 'ol/ol.css'
import { Map, View } from 'ol'
import * as olControl from 'ol/control'
import MapPopup from '@/components/MapPopup'
import MapIconMark from '@/components/MapIconMark'
import MapLineString from '@/components/MapLineString'
import MapPolygon from '@/components/MapPolygon'
import MapCircle from '@/components/MapCircle'
import MapOverlay from '@/components/MapOverlay'
import MapPointCollection from '@/components/MapPointCollection'
import mapconfig from '@/mapconfig'
export default {
name:'openlayer',
components: {
MapPopup,
MapIconMark,
MapLineString,
MapPolygon,
MapCircle,
MapOverlay,
MapPointCollection
},
data() {
return {
// 弹出窗体图层数据
mapPopupData:{
position: [ 114.06919853061095, 22.52312915135971 ], // 弹窗中心点 Array[array], 必须
title: '弹窗标题', // 弹窗标题 String,非必须,默认为 ' '
show: false, // 弹窗显隐 Boolean,必须,默认为 true
offset:[0, 0], // 弹窗偏移 Array[number],必须,默认为 [0, 0]
className: 'map-popup' // 图层的class String,非必须,默认为 'map-popup'
},
// 点标注图层数据
mapIconData:{
position: [ 114.0744662014354, 22.52087080791021 ], // 标注中心点 Array, 必须
icon: require('@/assets/logo.png'), // 文件地址 String[url] ,必须 ,默认为 null,
label: '这个是中心位置', // 标注点名称 String, 非必须, 默认为 null
elementName: '点标识ID', // 标注点识别名称 String, 可以通过 feature.get('name') 获取到, 非必须, 默认为 'el-mapIconMark'
className: 'map-icon-mark' // 图层的class String, 非必须,默认为 'map-icon-mark'
},
// 折线图层数据
mapLineStringData:{
pointlist:[
[ 114.07167206985183, 22.5232403088372 ],
[ 114.07770027654792, 22.523326106333492 ],
[ 114.07195557462218, 22.518950434022546 ],
[ 114.07445489299245, 22.52480331540012 ],
[ 114.07624544943681, 22.519340980469103 ],
[ 114.07167206985183, 22.5232403088372 ]
], // 线条所有的点数组 Array[array], 必须
elementName: '地图线条', //弹窗标识别名 String, 非必须,默认为 'el-mapLineString'
lineColor: 'rgba(0,77,168,0.9)', // 线条颜色 String,非必须,默认为 '#409eff'
lineWidth: 2, // 线条宽度 Number,非必须,默认为 2
lineDash: [10], // 虚线 Array[number], 是否使用虚线,默认为 null
className: 'map-line-string', // 图层的class String, 非必须, 默认 "map-line-string"
zIndex: 300 // 图层z轴高度, 非必须, 默认 300
},
// 多边形图层数据
mapPolygonData:{
pointlist:[
[ 114.06763153723739, 22.523766343504477 ],
[ 114.07099169050478, 22.523803784736963 ],
[ 114.06770308108405, 22.521172327154904 ],
[ 114.0693165842837, 22.524608688036995 ],
[ 114.07017607779578, 22.521397632712155 ]
],
fillColor: 'rgba(255,0,0,0.8)', // 多边形填充颜色,非必须,默认为 'rgba(0,0,0,0.8)'
elementName: '地图多边形', // 多边形识别名称 String, 非必须,默认为 'el-mapPolygon'
lineColor: 'rgba(0,0,0,0.5)', // 多边形线条颜色 String,非必须,默认为 '#409eff'
lineWidth: 2,// 多边形线条宽度 Number,非必须,默认为 2
lineDash: null, // 多边形虚线 Array[number], 是否使用虚线 ,默认为 null
className: 'map-polygon' // 图层的class String, 非必须,默认为 'map-polygon'
},
// 圆形图层数据
mapCircleData:{
position: [ 114.07272943851653, 22.52535977514209 ], // 圆中心点 Array, 必须
radius: 100, // 圆半径 number ,默认为 100
fillColor: 'rgba(255,255,255,0.5)', // 圆形填充颜色,非必须,默认为 'rgba(255,255,255,0.5)'
elementName: '圆形叠加', // 圆形识别名称 String, 非必须,默认为 'el-mapCircle'
lineColor: '#409eff', // 圆形线条颜色 String,非必须,默认为 '#409eff'
lineWidth: 2,// 圆形线条宽度 Number,非必须,默认为 2
lineDash: [20, 5], // 圆形虚线 Array[number], 是否使用虚线 ,默认为 null
className: 'map-circle' // 图层的class String, 非必须,默认为 'map-circle'
},
// 自定义图层数据
mapOverlayData:{
position: [ 114.07253789792126, 22.524477970304865 ], // 标注中心点 Array, 必须
className: 'map-overlay', // 设置自定义图层的class String ,非必须, 默认 'map-overlay'
offset:[200,200], // 设置自定义图层的偏移量 Array[number] ,非必须,默认[0, 0]
img: require('@/assets/hot.gif') // slot
},
// 海量点图层数据
mapPointCollectionData:{
pointlist:[
[ 114.06923493949402, 22.5240832382725 ],
[ 114.0682861161323, 22.523565093192584 ],
[ 114.06995237746318, 22.523445526204714 ],
[ 114.0685676099809, 22.522193726398406 ],
[ 114.06969098007714, 22.522269498868212 ]
],
distance: 100, // 收起点的间距 number,必须,默认为 40
zIndex: 500, // 图层z轴高度, 非必须, 默认 400
offset:[0, 2], // 文字偏移距离 [x,y], 非必须, 默认 [0,0]
fontColor: '#ffeb00', // 文字的颜色 string (色彩标识,支持rgba),默认'#fff'(如果去掉文字那么直接rgba透明度设置为0)
fillColor: '#06d073', // 文字的背景颜色 string(色彩标识,支持rgba),默认'#f00'(如果去不要背景颜色那么直接rgba透明度设置为0)
bgImg: require('@/assets/mark.png') // 设置背景图,如果设置了此那么文字背景可以不设置
},
mapData: null,
mapCenter: [ 114.07228950670621, 22.524837614865916 ],
mapZoom: 18,
clickCenter: [0,0],
popupText: '弹窗初始化文字',
iconImg: require('@/assets/mark.png'), // 文件地址 String[url]
pointlist:[
[ 114.07871607950588, 22.52222782549443 ],
[ 114.07844961562236, 22.52315316542209 ],
[ 114.07696995439895, 22.524754342150676 ],
[ 114.08107178741518, 22.524136654355292 ]
]
}
},
mounted(){
this.initMap()
},
methods:{
initMap(){
const mapContainer = this.$refs.rootmap
const FullScreen = new olControl.FullScreen() // 全屏控件
const map = new Map({
layers: mapconfig.streetmap(),
controls: [FullScreen],
target: mapContainer,
view: new View({
projection: "EPSG:4326",
center: this.mapCenter,
zoom: this.mapZoom
})
})
// 添加鼠标点击事件
map.on('click', this.mapClick)
// 添加鼠标经过事件
map.on('pointermove',this.mapPointerMove)
// 保存地图
this.mapData = map
},
// 鼠标点击地图事件
mapClick(evt){
// 获取点击中心点
this.clickCenter = evt.coordinate
// 移动地图
this.mapData.getView().animate({
center:evt.coordinate,
})
// 这个做了一个点击改变中心点的操作
setTimeout(()=>{
this.mapIconData.position = [ 114.07438338675577, 22.522278765283236 ]
this.mapData.getView().animate({
center:[ 114.07438338675577, 22.522278765283236 ],
})
},5000)
},
// 鼠标划过地图事件
mapPointerMove(evt){
if (evt.dragging) {
return
}
// 获取地图上的重叠像素(用来获得叠加图层)
const pixel = this.mapData.getEventPixel(evt.originalEvent)
const hit = this.mapData.hasFeatureAtPixel(pixel)
// 获取地图上的feature
const feature = this.mapData.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
return feature
})
// 获取叠加图层对像素叠加图层(hit)设置鼠标样式(给标注点添加鼠标经过样式)
this.mapData.getTarget().style.cursor = hit ? 'pointer' : ''
// 鼠标移动到点标注的时候显示弹出窗体,feature.get('name') 可以获取标注标题,如果设置了的话
if(feature && feature.get('name') === this.mapIconData.elementName){
// 显示弹出窗体
this.mapPopupData.show = true
// 弹出窗体的内容
this.popupText = `当前坐标${this.mapIconData.position}`
// 弹出窗体的位置
this.mapPopupData.position = this.mapIconData.position
}
},
// 关闭弹出窗体事件
mapPopupClose(e){
this.mapPopupData.show = false
this.popupText = ''
}
}
}
</script>
<style lang="scss" scoped>
.openlayer{
height: 100vh;
width: 100vw;
}
#map{
height: 100%;
width: 100vw;
background: #f2f2f2;
}
.click-center{
position: absolute;
top: 10px;
right: 60px;
padding: 10px;
z-index: 2;
background: rgba($color: #000000, $alpha: .5);
color: #fff;
border-radius: 4px;
}
</style>
组件
4.1,组件<点标注>(MapIconMark.vue)
<script>
// 点标注组件
import { Vector as SourceVec, Cluster} from 'ol/source'
import { Feature } from 'ol'
import { Point } from 'ol/geom'
import { Style, Icon, Stroke, Fill, Text } from 'ol/style'
import { Vector as LayerVec } from 'ol/layer'
export default {
name: 'MapIcon',
render () {
return this.$parent.preventChildrenRender
},
props: {
position: { type: Array },
elementName: { type: String },
className: { type: String },
label: { type: String },
icon: { type: String },
zIndex: { type: Number }
},
data(){
return {
iconLayer: null
}
},
watch:{
position:{
handler (newVal, oldVal) {
this.MapIconMark()
},
deep: true
},
elementName:{
handler (newVal, oldVal) {
this.MapIconMark()
},
deep: true
},
className:{
handler (newVal, oldVal) {
this.MapIconMark()
},
deep: true
},
label:{
handler (newVal, oldVal) {
this.MapIconMark()
},
deep: true
},
icon:{
handler (newVal, oldVal) {
this.MapIconMark()
},
deep: true
},
zIndex:{
handler () {
this.MapIconMark()
},
deep: true
}
},
mounted(){
this.$nextTick(()=>{
this.MapIconMark()
})
},
methods:{
// 单个标注
MapIconMark() {
const _that = this
if(_that.iconLayer){
_that.iconLayer.getSource().clear()
}
// 创建矢量容器
const vectorSource = new SourceVec({})
//创建图标特性
const iconFeature = new Feature({
type: 'icon',
name: _that.elementName || 'el-mapIconMark',
geometry: new Point(this.position),
})
// 图标特性添加到矢量容器
vectorSource.addFeature(iconFeature)
//创建矢量层
_that.iconLayer = new LayerVec({
className: _that.className || 'map-icon-mark',
source: vectorSource,
zIndex: _that.zIndex || 800,
//创建图标样式
style: new Style({
image: new Icon({
src: _that.icon || null
}),
// 文本样式
text:new Text({
text: _that.label || null,
fill: new Fill({
color: '#fff',
}),
font:'14px Microsoft YaHei',
offsetX: 0,
offsetY: 30,
padding:[ 2, 10, 0, 10],
// 文本边框
/*
backgroundStroke: new Stroke({
color: '#f00',
width: 1,
}),
*/
// 文本填充
backgroundFill: new Fill({
color:'rgba(0,0,0,0.5)'
})
})
})
})
_that.$parent.$data.mapData.addLayer(_that.iconLayer)
}
}
}
</script>
4.2,组件<折线>(MapLineString.vue)
<script>
// 折线组件
import { Vector as SourceVec, Cluster } from "ol/source"
import { Feature } from "ol";
import { Style, Stroke, Fill } from "ol/style"
import { Vector as LayerVec } from "ol/layer"
import { LineString } from 'ol/geom'
export default {
name: "MapLineString",
render() {
return this.$parent.preventChildrenRender;
},
props: {
pointList: { type: Array },
elementName: { type: String },
className: { type: String },
lineColor: { type: String },
lineWidth: { type: Number },
lineDash: {tyep: Array },
zIndex: { type: Number }
},
data() {
return{
lineStringLayer: null
}
},
watch:{
pointList:{
handler () {
this.MapLineString()
},
deep: true
},
elementName:{
handler () {
this.MapLineString()
},
deep: true
},
className:{
handler () {
this.MapLineString()
},
deep: true
},
lineColor:{
handler () {
this.MapLineString()
},
deep: true
},
lineDash:{
handler () {
this.MapLineString()
},
deep: true
},
lineWidth:{
handler () {
this.MapLineString()
},
deep: true
},
zIndex:{
handler(){
this.MapLineString()
}
}
},
mounted() {
this.$nextTick(() => {
this.MapLineString()
});
},
methods: {
MapLineString() {
const _that = this
// 清除原来的
if(_that.lineStringLayer){
_that.lineStringLayer.getSource().clear()
}
// 创建一个 source图层
const source = new SourceVec();
// 所有点共同构成一个 feature
const feature = new Feature({
name: _that.elementName || null,
geometry: new LineString(this.pointList),
});
// 然后把feature添加到source里
source.addFeature(feature);
_that.lineStringLayer = new LayerVec({
className: _that.className || "map-line-string",
source: source,
zIndex: _that.zIndex || 300,
style: function (feature, resolution) {
// console.log(feature)
const style = [
new Style({
stroke: new Stroke({
color: _that.lineColor || '#409eff',
width: _that.lineWidth || 2,
lineDash: _that.lineDash || null,
lineDashOffset: 0
})
}),
];
return style;
},
});
_that.$parent.$data.mapData.addLayer(_that.lineStringLayer)
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
4.3,组件<多边形>(MapPolygon.vue)
<script>
// 多边形组件
import { Vector as SourceVec, Cluster } from "ol/source"
import { Feature } from "ol"
import { Style, Stroke, Fill } from "ol/style"
import { Vector as LayerVec } from "ol/layer"
import { Polygon } from 'ol/geom'
export default {
name: "MapPolygon",
render() {
return this.$parent.preventChildrenRender;
},
props: {
pointList: { type: Array },
elementName: { type: String },
className: { type: String },
lineColor: { type: String },
lineWidth: { type: Number },
lineDash: { tyep: Array },
fillColor: { type :String },
zIndex: { type: Number }
},
data() {
return{
polygonLayer: null
}
},
watch: {
pointList:{
handler () {
this.MapPolygon()
},
deep: true
},
elementName:{
handler () {
this.MapPolygon()
},
deep: true
},
className:{
handler () {
this.MapPolygon()
},
deep: true
},
lineColor:{
handler () {
this.MapPolygon()
},
deep: true
},
lineWidth:{
handler () {
this.MapPolygon()
},
deep: true
},
lineDash:{
handler () {
this.MapPolygon()
},
deep: true
},
fillColor:{
handler () {
this.MapPolygon()
},
deep: true
},
zIndex:{
handler(){
this.MapPolygon()
}
}
},
mounted() {
this.$nextTick(() => {
this.MapPolygon()
});
},
methods: {
MapPolygon() {
const _that = this
// 清除原来的
if(_that.polygonLayer){
_that.polygonLayer.getSource().clear()
}
// 创建一个 source图层
const source = new SourceVec()
// 所有点共同构成一个 feature
const feature = new Feature({
name: _that.elementName || 'el-mapPolygon',
geometry: new Polygon([this.pointList]),
})
// 然后把feature添加到source里
source.addFeature(feature)
this.polygonLayer = new LayerVec({
className: _that.className || "map-polygon",
source: source,
zIndex: _that.zIndex || 200,
style: function (feature, resolution) {
const style = [
new Style({
stroke: new Stroke({
color: _that.lineColor || '#409eff',
width: _that.lineWidth || 2,
lineDash: _that.lineDash || null,
lineDashOffset: 0
}),
//填充样式
fill: new Fill({
color: _that.fillColor || 'rgba(0,0,0,0.8)' //颜色、渐变或图案
}),
}),
];
return style;
},
})
this.$parent.$data.mapData.addLayer(this.polygonLayer)
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
4.4,组件<圆形>(MapCircle.vue)
<script>
// 点标注组件
import { Vector as SourceVec, Cluster} from 'ol/source'
import { Feature } from 'ol'
import { Circle } from 'ol/geom'
import { Style, Icon, Stroke, Fill, Text } from 'ol/style'
import { Vector as LayerVec } from 'ol/layer'
export default {
name: 'MapIcon',
render () {
return this.$parent.preventChildrenRender
},
props: {
position: { type: Array },
radius: {type: Number },
elementName: { type: String },
className: { type: String },
lineColor: { type: String },
lineWidth: { type: Number },
lineDash: { tyep: Array },
fillColor: { type :String },
zIndex: { type: Number }
},
data(){
return {
circleLayer: null
}
},
watch:{
position:{
handler () {
this.MapCircle()
},
deep: true
},
radius:{
handler () {
this.MapCircle()
},
deep: true
},
elementName:{
handler () {
this.MapCircle()
},
deep: true
},
className:{
handler () {
this.MapCircle()
},
deep: true
},
lineColor:{
handler () {
this.MapCircle()
},
deep: true
},
lineWidth:{
handler () {
this.MapCircle()
},
deep: true
},
lineDash:{
handler () {
this.MapCircle()
},
deep: true
},
fillColor:{
handler () {
this.MapCircle()
},
deep: true
},
zIndex:{
handler(){
this.MapCircle()
}
}
},
mounted(){
this.$nextTick(()=>{
this.MapCircle()
})
},
methods:{
// 圆形叠加图层
MapCircle() {
const _that = this
if(_that.circleLayer){
_that.circleLayer.getSource().clear()
}
// 圆的半径换算
let metersPerUnit = _that.$parent.$data.mapData.getView().getProjection().getMetersPerUnit()
let circleRadius = ( _that.radius || 100) / metersPerUnit
// 创建矢量容器
const centerRadius = new Circle(_that.position, circleRadius)
const vectorSource = new SourceVec({})
//创建图标特性
const circleFeature = new Feature({
type: 'mapCircle',
name: _that.elementName || 'el-mapCircle',
geometry: centerRadius,
})
// 图标特性添加到矢量容器
vectorSource.addFeature(circleFeature)
//创建矢量层
_that.circleLayer = new LayerVec({
className: _that.className || 'map-circle',
source: vectorSource,
zIndex: _that.zIndex || 200,
//创建圆的样式
style: new Style({
stroke: new Stroke({
color: _that.lineColor || '#409eff',
width: _that.lineWidth || 2,
lineDash: _that.lineDash || null,
lineDashOffset: 0
}),
//填充样式
fill: new Fill({
color: _that.fillColor || 'rgba(255,255,255,0.5)' // 颜色、渐变或图案
})
})
})
_that.$parent.$data.mapData.addLayer(_that.circleLayer)
}
}
}
</script>
4.5,组件<自定义覆盖物>(MapOverlay.vue)
<template>
<!-- Overlay start -->
<div ref="overlayMain" class="overlay-main">
<slot />
</div>
<!-- Overlay end -->
</template>
<script>
// 自定义覆盖物组件
import Overlay from 'ol/Overlay'
export default {
name: 'MapOverlay',
props: {
position: { type: Array },
className: { type: String },
offset:{ type: Array }
},
data() {
return {
dialogOverlay: null
}
},
watch:{
position: {
handler (val) {
this.reload()
},
deep: true
},
className: {
handler (val) {
this.reload()
},
deep: true
},
offset: {
handler (val) {
this.reload()
},
deep: true
}
},
mounted(){
this.$nextTick(()=>{
this.reload()
})
},
methods:{
reload(){
if(this.dialogOverlay) {
this.$parent.$data.mapData.removeOverlay(this.dialogOverlay)
}
this.dialogOverlay = new Overlay({
element: this.$refs.overlayMain,
stopEvent: false,
offset: this.offset || [0, 0],
className: this.className || 'map-overlay',
})
this.dialogOverlay.setPosition(this.position)
this.$parent.$data.mapData.addOverlay(this.dialogOverlay)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
4.6,组件<弹出窗体>(MapPopup.vue)
<template>
<!-- 弹窗 start -->
<div ref="mapPopup" class="map-popup-all" v-show="popupShow">
<div class="map-popup-closer" @click="closePopup">+</div>
<h3>{{ title || ' ' }}</h3>
<div id="popup-content"><slot /></div>
</div>
<!-- 弹窗 end -->
</template>
<script>
// 弹窗组件
import Overlay from 'ol/Overlay'
export default {
name: 'MapOverlay',
props: {
position: { type: Array },
className: { type: String },
mapShow: { type: Boolean },
title: {type: String },
offset: { type: Array },
},
data() {
return {
popupShow: true,
dialogOverlay: null
}
},
watch:{
position: {
handler () {
this.reload()
},
deep: true
},
className: {
handler () {
this.reload()
},
deep: true
},
title: {
handler () {
this.reload()
},
deep: true
},
offset: {
handler () {
this.reload()
},
deep: true
},
mapShow:{
handler(val){
this.popupShow = val
},
deep: true,
immediate: true
}
},
mounted(){
this.$nextTick(()=>{
this.reload()
})
},
methods:{
reload(){
if(this.dialogOverlay) {
this.$parent.$data.mapData.removeOverlay(this.dialogOverlay)
}
this.dialogOverlay = new Overlay({
element: this.$refs.mapPopup,
stopEvent: false,
offset: this.offset || [0, 0],
className: this.className || 'map-popup',
autoPanAnimation: {
duration: 250,
},
})
this.dialogOverlay.setPosition(this.position)
this.$parent.$data.mapData.addOverlay(this.dialogOverlay)
},
closePopup(){
this.$emit('close', false)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.map-popup-all {
position: absolute;
z-index: 400;
bottom: 20px;
left: 50%;
min-width: 150px;
transform: translateX(-50%);
background: #fff;
border-radius: 4px;
border: 1px solid #ebeef5;
padding: 12px;
color: #606266;
line-height: 1.4;
text-align: justify;
font-size: 14px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
word-break: break-all;
h3{
font-size: 14px;
margin-top: -4px;
padding-right: 20px;
}
.map-popup-closer{
position: absolute;
right: 0;
top: 0;
width: 20px;
text-align: center;
height: 20px;
font-size: 26px;
transform: rotate(45deg);
color: #c5c5c5;
cursor: pointer;
}
.map-popup-closer:hover{
color: #888;
}
}
.map-popup-all::before{
content: ' ';
width: 0;
height: 0;
border: solid 10px transparent;
border-top-color: #fff;
position: absolute;
bottom: -20px;
left: 50%;
transform: translateX(-50%);
}
</style>
4.7,组件<海量点>(MapPointCollection.vue)
<script>
import { Vector as SourceVec, Cluster } from "ol/source";
import { Feature } from "ol";
import { Point } from "ol/geom";
import { Style, Icon, Stroke, Fill, Text, Circle } from "ol/style";
import { Vector as LayerVec } from "ol/layer";
export default {
name: "MapPointCollection",
render() {
return this.$parent.preventChildrenRender;
},
props: {
pointList: { type: Array },
distance: { type: Number },
offset: { type: Array },
fontColor: { type: String },
fillColor: { type: String },
zIndex: { type: Number },
bgImg: { type: String },
className: { type: String }
},
data() {
return {
clustersLayer: null,
};
},
watch: {
pointList: {
handler() {
this.MapPointCollection();
},
deep: true,
},
zIndex: {
handler() {
this.MapPointCollection();
},
deep: true,
},
distance: {
handler() {
this.MapPointCollection();
},
deep: true,
},
fontColor: {
handler() {
this.MapPointCollection();
},
deep: true,
},
fillColor: {
handler() {
this.MapPointCollection();
},
deep: true,
},
bgImg: {
handler() {
this.MapPointCollection();
},
deep: true,
},
offset: {
handler() {
this.MapPointCollection();
},
deep: true,
},
className: {
handler() {
this.MapPointCollection();
},
deep: true,
},
},
mounted() {
this.$nextTick(() => {
this.MapPointCollection();
});
},
methods: {
// 海量点
MapPointCollection() {
const _that = this;
// 清除原来的
if (_that.clustersLayer) {
_that.clustersLayer.getSource().clear();
}
// 创建Feature对象集合
const features = [];
for (let i = 0; i < _that.pointList.length; i++) {
features.push(new Feature({ geometry: new Point(_that.pointList[i]) }));
}
// 加载聚合标注的矢量图层
const styleCache = {}; //用于保存特定数量的聚合群的要素样式
_that.clustersLayer = new LayerVec({
className: _that.className || "map-point-collection", // 设置容器的class
zIndex: _that.zIndex || 400,
// 聚合标注数据源
source: new Cluster({
distance: _that.distance || 40,
// 矢量要素数据源
source: new SourceVec({
features: features,
}),
}),
style: function (feature, resolution) {
const size = feature.get("features").length; // 获取该要素所在聚合群的要素数量
let style = styleCache[size];
if (!style) {
if (_that.bgImg) {
style = [
new Style({
image: new Icon({
src: _that.bgImg,
}),
// 文本设置
text: new Text({
text: size.toString(),
fill: new Fill({
color: _that.fontColor || "#fff",
}),
font: "14px Microsoft YaHei",
offsetX: _that.offset ? _that.offset[0] : 0,
offsetY: _that.offset ? _that.offset[1] : 0
}),
}),
];
styleCache[size] = style;
} else {
style = [
new Style({
image: new Circle({
radius: 10,
// 边线
stroke: new Stroke({
color: "#fff",
}),
fill: new Fill({
color: _that.fillColor || "#f00",
}),
}),
// 文本设置
text: new Text({
text: size.toString(),
fill: new Fill({
color: _that.fontColor || "#fff",
}),
font: "14px Microsoft YaHei",
offsetX: _that.offset ? _that.offset[0] : 0,
offsetY: _that.offset ? _that.offset[1] : 0
}),
}),
];
styleCache[size] = style;
}
}
return style;
},
});
_that.$parent.$data.mapData.addLayer(_that.clustersLayer);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
用法说明
点标注(MapIconMark)
<MapIconMark :position="mapIconData.position" :label="mapIconData.label" :icon='mapIconData.icon' :elementName="mapIconData.elementName" :className="mapIconData.className"></MapIconMark>
/**
* position // 标注点的位置 array [lng, lat]
* label // 标注点的标签 string | null , 非必须 ,默认 null,
* icon // 标注点的图标 string(url) | 如果只要标签名称就设置成一个像素的透明图标, 必须
* elmentName // 通过feature.get('name') 方法可以获得该叠加图层,非必须, 默认 'el-mapIconMark'
* className // 设置class名称, 非必须, 默认 'map-icon-mark'
* zIndex // 图层z轴高度, 非必须, 默认 800
*/
折线(MapLineString)
<MapLineString :pointList="mapLineStringData.pointlist" :lineColor="mapLineStringData.lineColor" :lineWidth="mapLineStringData.lineWidth" :lineDash="mapLineStringData.lineDash" :elementName="mapLineStringData.elementName" :className="mapLineStringData.className"></MapLineString>
/**
* pointList // 组成线的点列表数组 array [[lng, lat],...]
* lineColor // 线条颜色 String,非必须,默认为 '#409eff'
* lineWidth // 线条宽度 Number,非必须,默认为 2
* lineDash // 虚线 Array[number], 是否使用虚线,默认为 null
* className // 图层的class String, 非必须, 默认 "map-line-string"
* zIndex // 图层z轴高度, 非必须, 默认 300
* elmentName // 通过feature.get('name') 方法可以获得该叠加图层
*/
多边形(MapPolygon)
<MapPolygon :pointList="mapPolygonData.pointlist" :fillColor="mapPolygonData.fillColor" :lineColor="mapPolygonData.lineColor" :lineWidth="mapPolygonData.lineWidth" :lineDash="mapPolygonData.lineDash" :elementName="mapPolygonData.elementName" :className="mapPolygonData.className"></MapPolygon>
/**
* pointList // 组成多边形的点列表数组 array [[lng, lat],...]
* fillColor // 多边形填充颜色,非必须,默认为 'rgba(0,0,0,0.8)'
* elementName // 多边形识别名称 String, 非必须,默认为 'el-mapPolygon'
* lineColor // 多边形线条颜色 String,非必须,默认为 '#409eff'
* lineWidth // 多边形线条宽度 Number,非必须,默认为 2
* lineDash // 多边形虚线 Array[number], 是否使用虚线 ,默认为 null
* className // 图层的class String, 非必须,默认为 'map-polygon'
*/
圆形(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>
/**
* position // 圆中心点 Array, 必须
* radius // 圆半径 number ,默认为 100
* fillColor // 圆形填充颜色,非必须,默认为 'rgba(255,255,255,0.5)'
* elementName // 圆形识别名称 String, 非必须,默认为 'el-mapCircle'
* lineColor // 圆形线条颜色 String,非必须,默认为 '#409eff'
* lineWidth // 圆形线条宽度 Number,非必须,默认为 2
* lineDash // 圆形虚线 Array[number], 是否使用虚线 ,默认为 null
* className // 图层的class String, 非必须,默认为 'map-circle'
*/
自定义覆盖物(MapOverlay)
<MapOverlay :position="mapOverlayData.position" :className="mapOverlayData.className"><div><img :src="mapOverlayData.img" alt=""></div></MapOverlay>
/**
* position // 标注中心点 Array, 必须
* className // 设置自定义图层的class String ,非必须, 默认 'map-overlay'
* offset // 设置自定义图层的偏移量 Array[number] ,非必须,默认[0, 0]
*/
弹出窗体(MapPopup)
<MapPopup :position="mapPopupData.position" :title="mapPopupData.title" :offset="mapPopupData.offset" :mapShow="mapPopupData.show" @close="mapPopupClose" :className="'map-popup'">{{ popupText }}</MapPopup>
/**
* position // 弹窗中心点 Array[array], 必须
* title // 弹窗标题 String,非必须,默认为 ' '
* mapShow // 弹窗显隐 Boolean,必须,默认为 true
* offset // 弹窗偏移 Array[number],必须,默认为 [0, 0]
* className // 图层的class String,非必须,默认为 'map-popup'
* close() // 弹窗关闭事件
*/
海量点(MapPointCollection)
<MapPointCollection :pointList="mapPointCollectionData.pointlist" :distance="mapPointCollectionData.distance" :fillColor="mapPointCollectionData.fillColor" :fontColor="mapPointCollectionData.fontColor" :zIndex='mapPointCollectionData.zIndex' :offset="mapPointCollectionData.offset"></MapPointCollection>
/**
* pointlist // 组成多边形的点列表数组 array [[lng, lat],...]
* distance // 收起点的间距 number,必须,默认为 40
* zIndex // 图层z轴高度, 非必须, 默认 400
* offset // 文字偏移距离 [x,y], 非必须, 默认 [0,0]
* fontColor // 文字的颜色 string (色彩标识,支持rgba),默认'#fff'(如果去掉文字那么直接rgba透明度设置为0)
* fillColor // 文字的背景颜色 string(色彩标识,支持rgba),默认'#f00'(如果去不要背景颜色那么直接rgba透明度设置为0)
* bgImg // 设置背景图,如果设置了此那么文字背景可以不设置
*/