This article introduces you to the use of openLayers offline map from zero to one, including:
- Get offline map tiles
- Openlayers loads offline map tiles
- Display geographic coordinates
- Displays the geographic coordinate range.
- This is a must see. The OpenLayers API is really not very friendly compared to commercial maps like Autonavi and Baidu.
Get offline map tiles
- Autonavi provides an API that you are interested in. This article does not take that approach.
- Download offline map tiles, there are many methods online, most of the charges to find a suitable tool really difficult, find a free contribution out of the omnipotent map downloader
- Link: pan.baidu.com/s/18LiUAh1-… Extraction code: YD88
- Offline tile download is completed to such a piece of data
Publishing offline Data
- The map offline tile must be on the server, it’s too big for the project.
- Local test, local up a service used to access the map offline tile, this article uses HTTP -server to view the installation of a line of command.
- The http://192.168.3.6:8081 local service and IP port will be used below
This paper takes the VUE project as an example
Install the openlayers
- The document
npm install ol
- Of course, it can also be imported directly through JS
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.8.1/build/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.8.1/css/ol.css">
Copy the code
Create the map and load the points
<template>
<div style="width: 100%; height: 100%">
<div class="map" id="map"></div>
<el-card id="popup" class="popup">
<div class="popupContainer"></div>
</el-card>
</div>
</template>
<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import Feature from 'ol/Feature';
import VectorSource from 'ol/source/Vector';
import Overlay from 'ol/Overlay';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import View from 'ol/View';
import {transform} from 'ol/proj';
import XYZ from 'ol/source/XYZ'
import Point from 'ol/geom/Point';
import GeoJSON from 'ol/format/GeoJSON';
import {Fill, Stroke, Icon, Style} from 'ol/style'
import markerImg from '@/assets/img/markerIcon.png'
export default {
name: "openlayersMap",
data () {
return {
mapObj: null.mapDom: null.mapPointList: [].pointLayerSource:null.pointLayer: null.markerIcon: markerImg
}
},
mounted() {
this.initMap()
},
methods: {
In some cases there will be two maps in the container and the map will not display properly.
// There is no corresponding API provided by the official.
mapClear (){
if (this.mapDom) {
this.mapDom.innerHTML = ' '
this.mapDom = null}},// Initialize the map
initMap () {
// Try clearing first
this.mapClear()
// Get the map container
this.mapDom = document.getElementById('map')
// Initialize the map configuration
this.mapObj = new Map({
target: this.mapDom, // Map container
view: new View({
center: [117.990969.36.635013].// Map center point
zoom: 10./ / zoom
projection: 'EPSG:4326' / / coordinate system})})// Add a layer that uses an offline tile map
const offlineMapLayer = new TileLayer({
source: new XYZ({
url: 'http://192.168.3.6:8081' + '/{z}/{x}/{y}.png' // Set the path for storing the local offline tile})})// Add layers to the map
this.mapObj.addLayer(offlineMapLayer)
// Load the geographic coordinates
this.addPoint()
},
// Add the geographic coordinates
addPoint () {
this.delPointAll()
// Array of geographic coordinates
const pointData = [
{longitude: 117.990969.latitude: 36.635013}
]
pointData.map(item= > {
/ / create
const point = new Feature({
geometry: new Point([item.longitude, item.latitude]),
data: item
})
// Point style
const iconStyle = new Style({
image: new Icon({
color: '#ffffff'.crossOrigin: 'anonymous'.src: this.markerIcon,
}),
})
// Set the style
point.setStyle(iconStyle)
// Save to data for easy deletion
this.mapPointList.push(point)
})
// Create geoJSON data source
this.pointLayerSource = new VectorSource({features: this.mapPointList})
// Create layers and load data
this.pointLayer = new VectorLayer({source: this.pointLayerSource})
// Add layers to the map
this.mapObj.addLayer(this.pointLayer)
},
// Delete the geographic point
delPointAll(){
// Check whether the deleted data source exists
if (this.pointLayerSource) {
// Iterate over the delete
this.mapPointList.map(item= > {
this.pointLayerSource.removeFeature(item)
})
// Delete the layer and reset the data
this.mapObj.removeLayer(this.pointLayer)
this.pointLayerSource = null
this.pointLayer = null
this.mapPointList = []
}
}
},
beforeDestroy() {
this.mapClear()
}
}
</script>
<style scoped>
.map {
width: 100%;
height: 100%;
}
</style>
Copy the code
Geographic point appending
- Layer data source
VectorSource
Provide one after creationaddFeature
methodspointLayerSource.addFeature(item)
item
Is to createpoint
Point data is as follows:
/ / create
const point = new Feature({
geometry: new Point([item.longitude, item.latitude]),
data: item
})
// Point style
const iconStyle = new Style({
image: new Icon({
color: '#ffffff'.crossOrigin: 'anonymous'.src: this.markerIcon,
}),
})
// Set the style
point.setStyle(iconStyle)
Copy the code
Not surprisingly, the page will display a map and an anchor point if you haven’t checked first
- The first request for the above service will be stuck in CMD and a few press enter.
- Check whether the offline map tile request path is correct
- Are the coordinates correct and within the displayed map area?
Point response events display popup window
<template>
<div style="width: 100%; height: 100%">
<div class="map" id="map"></div>
<el-card id="popup" class="popup">
<div class="popupContainer"></div>
</el-card>
</div>
</template>
<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import Feature from 'ol/Feature';
import VectorSource from 'ol/source/Vector';
import Overlay from 'ol/Overlay';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import View from 'ol/View';
import {transform} from 'ol/proj';
import XYZ from 'ol/source/XYZ'
import Point from 'ol/geom/Point';
import GeoJSON from 'ol/format/GeoJSON';
import {Fill, Stroke, Icon, Style} from 'ol/style'
import markerImg from '@/assets/img/markerIcon.png'
export default {
name: "openlayersMap",
data () {
return {
mapObj: null.mapDom: null.mapPointList: [].pointLayerSource:null.pointLayer: null.markerIcon: markerImg
}
},
mounted() {
this.initMap()
},
methods: {
In some cases there will be two maps in the container and the map will not display properly.
// There is no corresponding API provided by the official.
mapClear (){
if (this.mapDom) {
this.mapDom.innerHTML = ' '
this.mapDom = null}},// Initialize the map
initMap () {
// Try clearing first
this.mapClear()
// Get the map container
this.mapDom = document.getElementById('map')
// Initialize the map configuration
this.mapObj = new Map({
target: this.mapDom, // Map container
view: new View({
center: [117.990969.36.635013].// Map center point
zoom: 10./ / zoom
projection: 'EPSG:4326' / / coordinate system})})// Add a layer that uses an offline tile map
const offlineMapLayer = new TileLayer({
source: new XYZ({
url: 'http://192.168.3.6:8081' + '/{z}/{x}/{y}.png' // Set the path for storing the local offline tile})})// Add layers to the map
this.mapObj.addLayer(offlineMapLayer)
// Map click event
this.mapOnClick()
// Load the geographic coordinates
this.addPoint()
},
// Map click event
mapOnClick (){
const self = this
// popupDom
const popupDom = document.getElementById('popup')
/ / create the popup
const popup = new Overlay({
element: popupDom,
positioning: 'bottom-center'.stopEvent: false
})
// Load to map
this.mapObj.addOverlay(popup)
// Map click event
this.mapObj.on('click'.function (evt) {
// Get the click location data
const feature = self.mapObj.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature;
})
// Determine if a custom popup is clicked based on the click element className
const isClickPopUp = evt.originalEvent.path.map(item= > item.className).includes('el-card__body')
if(! isClickPopUp) { popupDom.style.display ='none'
}
// The official example uses the JQ + Bootstrap popup, but I don't think it's necessary if you use the Bootstrap component a lot.
const popupContainer = document.getElementsByClassName('popupContainer') [0]
// Determine the data
if (feature) {
// feature.values_.data, the data field is added when the addPoint function creates the point
if (feature.values_.data) {
const pointData = feature.values_.data
popup.setPosition(evt.coordinate)
popupContainer.innerHTML = `<div>${pointData.name}</div>`
popupDom.style.display = 'block'}}})},// Add the geographic coordinates
addPoint () {
this.delPointAll()
// Array of geographic coordinates
const pointData = [
{longitude: 117.990969.latitude: 36.635013.name: 'Li Dazhuang'}
]
pointData.map(item= > {
/ / create
const point = new Feature({
geometry: new Point([item.longitude, item.latitude]),
data: item
})
// Point style
const iconStyle = new Style({
image: new Icon({
color: '#ffffff'.crossOrigin: 'anonymous'.src: this.markerIcon,
}),
})
// Set the style
point.setStyle(iconStyle)
// Save to data for easy deletion
this.mapPointList.push(point)
})
// Create geoJSON data source
this.pointLayerSource = new VectorSource({features: this.mapPointList})
// Create layers and load data
this.pointLayer = new VectorLayer({source: this.pointLayerSource})
// Add layers to the map
this.mapObj.addLayer(this.pointLayer)
},
// Delete the geographic point
delPointAll(){
// Check whether the deleted data source exists
if (this.pointLayerSource) {
// Iterate over the delete
this.mapPointList.map(item= > {
this.pointLayerSource.removeFeature(item)
})
// Delete the layer and reset the data
this.mapObj.removeLayer(this.pointLayer)
this.pointLayerSource = null
this.pointLayer = null
this.mapPointList = []
}
}
},
beforeDestroy() {
this.mapClear()
}
}
</script>
<style scoped>
.map {
width: 100%;
height: 100%;
}
</style>
Copy the code
Add administrative area scope
- Administrative region refers to the scope of a province, city or region. Generally, a city has a geoJSON data, from which datAV Geo can be obtained
- Notice the order of the layers and if the point layer is not on top it may cause the click event to not respond properly and the layer added first is below
<template>
<div style="width: 100%; height: 100%">
<div class="map" id="map"></div>
<el-card id="popup" class="popup">
<div class="popupContainer"></div>
</el-card>
</div>
</template>
<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import Feature from 'ol/Feature';
import VectorSource from 'ol/source/Vector';
import Overlay from 'ol/Overlay';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import View from 'ol/View';
import {transform} from 'ol/proj';
import XYZ from 'ol/source/XYZ'
import Point from 'ol/geom/Point';
import GeoJSON from 'ol/format/GeoJSON';
import {Fill, Stroke, Icon, Style} from 'ol/style'
import {inject, onMounted, watch, onUnmounted} from 'vue'
import home from "@model/home";
export default {
name: "MapBox".props: {
pointData: {
type: Array.default: []}},emits: ['mapClickPoint'].setup(props, {emit}) {
const {APP_MAP_ZOOM, APP_MAP_TILES_URL} = window.appConfig
let mapObj = null
let mapDom = null
const mapClear = () = > {
if (mapObj) {
mapDom.innerHTML = ' '
}
}
onUnmounted(() = > {
mapClear()
})
const initMap = () = > {
mapClear()
mapDom = document.getElementById('map')
// set the map center to chengdu, and the local offlineMapTiles just have a chengdu tile with zoom 4
const center = transform([117.990969.36.635013].'EPSG:4326'.'EPSG:3857');
mapObj = new Map({
target: mapDom,
view: new View({
center: center,
zoom: APP_MAP_ZOOM,
projection: 'EPSG:3857'})})// Add a layer that uses an offline tile map
const offlineMapLayer = new TileLayer({
source: new XYZ({
url: APP_MAP_TILES_URL + '/{z}/{x}/{y}.png' // Set the path for storing the local offline tile})}); mapObj.addLayer(offlineMapLayer) mapOnClick() addAreaPolygon() getGpsList() watch(() = > props.pointData, () = > {
addPoint()
}, {immediate: true.deep: true})}// Map click event
const mapOnClick = () = > {
const popupDom = document.getElementById('popup')
const popup = new Overlay({
element: popupDom,
positioning: 'bottom-center'.stopEvent: false
})
mapObj.addOverlay(popup)
mapObj.on('click'.function (evt) {
const feature = mapObj.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature;
})
// Determine if a custom popup is clicked based on the click element className
const isClickPopUp = evt.originalEvent.path.map(item= > item.className).includes('el-card__body')
if(! isClickPopUp) { popupDom.style.display ='none'
}
// The official example uses the JQ + Bootstrap popup, but I don't think it's necessary if you use the Bootstrap component a lot.
const popupContainer = document.getElementsByClassName('popupContainer') [0]
if (feature) {
if ( feature.values_.gpsPointData) {
const pointData = feature.values_.gpsPointData
popup.setPosition(evt.coordinate)
popupContainer.innerHTML = `<div>${pointData.name}</div>`
popupDom.style.display = 'block'
}
emit('mapClickPoint', pointData)
} else {
emit('mapClickPoint', {})}})}let mapPointList = []
let pointLayerSource = null
let pointLayer = null
const addPoint = () = > {
delPointAll()
props.pointData.map(item= > {
if (item.checked) {
item.poi_list.map(pointItem= > {
pointItem.panelType = item.value
const point = new Feature({
geometry: new Point(transform([pointItem.longitude, pointItem.latitude], 'EPSG:4326'.'EPSG:3857')),
data: pointItem
})
const imgSrc = require(`@/assets/img/map/icon_${item.value}.png`)
const iconStyle = new Style({
image: new Icon({
color: '#ffffff'.crossOrigin: 'anonymous'.src: imgSrc,
}),
})
point.setStyle(iconStyle)
mapPointList.push(point)
})
}
})
// Data layer
pointLayerSource = new VectorSource({features: mapPointList})
pointLayer = new VectorLayer({source: pointLayerSource})
mapObj.addLayer(pointLayer)
}
const delPointAll = () = > {
if (pointLayerSource) {
mapPointList.map(item= > {
pointLayerSource.removeFeature(item)
})
mapObj.removeLayer(pointLayer)
pointLayerSource = null
pointLayer = null
mapPointList = []
}
}
// Add a range of counties
const addAreaPolygon = () = > {
let geoJson = require('@/mock/zb.json')
const vectorSource = new VectorSource({
features: new GeoJSON({featureProjection: 'EPSG:3857'}).readFeatures(geoJson),
})
const layer = new VectorLayer({
source: vectorSource,
style: new Style({
stroke: new Stroke({
color: 'blue'.lineDash: [4].width: 3,}).fill: new Fill({
color: 'rgba (0, 0, 0, 0.1)',})})}); mapObj.addLayer(layer) }// Todo gets the WS push data injected by providing the home file
const wsDataInfo = inject('wsDataInfo')
watch(wsDataInfo, () = > {
if (wsDataInfo.value) {
let data = JSON.parse(wsDataInfo.value.data)
const type = data.pushType + ' '
console.log(data, 'p[p[[')
if (type === '2') {
addGpsPoint([data], false}}}, {immediate: true.deep: true})
// Get the list of GPS points
const getGpsList = () = > {
home.getGpsList().then(res= > {
if (res.state === 0) {
// addGpsPoint(res.resultInfo)}})}let gpsPointList = []
let gpsPointLayerSource = null
let gpsPointLayer = null
const addGpsPoint = (data, del = true) = > {
// Initially loading multiple points...
let pointList = []
data.map(item= > {
const point = new Feature({
geometry: new Point(transform([item.longitude, item.latitude], 'EPSG:4326'.'EPSG:3857')),
gpsPointData: item
})
const imgSrc = require(`@/assets/img/map/gpsIcon.png`)
const iconStyle = new Style({
image: new Icon({
color: '#ffffff'.crossOrigin: 'anonymous'.src: imgSrc,
}),
})
point.setStyle(iconStyle)
pointList.push(point)
})
// Data layergpsPointList.push(... pointList)if(! gpsPointLayerSource) {// Data layer
gpsPointLayerSource = new VectorSource({features: gpsPointList})
gpsPointLayer = new VectorLayer({source: gpsPointLayerSource})
mapObj.addLayer(gpsPointLayer)
} else {
pointList.map(item= > {
gpsPointLayerSource.addFeature(item)
})
}
}
const delGpsPointAll = () = > {
if (gpsPointLayerSource) {
gpsPointList.map(item= > {
gpsPointLayer.removeFeature(item)
})
mapObj.removeLayer(gpsPointLayer)
gpsPointLayerSource = null
gpsPointLayer = null
gpsPointList = []
}
}
onMounted(() = > {
initMap()
})
}
}
</script>
<style lang="scss" scoped>
.map {
width: 100%;
height: 100%;
}
</style>
Copy the code