天地图提供了网络地图开发接口,同时有部分web开发的插件,但是本文遇到的场景并不考虑使用天地图本身的插件,而是使用openlayer6.x完成需求。
需求
- 加载天地图影像图层
- 加载天地图矢量图层
- 在图层上叠加静态图片,以增强展示效果
- 希望图片能动起来-旋转以实现雷达图的效果
技术选型
- html5+css3
- vuejs
- elementui
- openlayer6.x
- 天地图服务
天地图服务注册
这里使用的是天地图的地图服务数据api,api提供了较多开源接口,大家可以按需使用。
注:开发者需要注册webkey,并受到日访问次数限制,生产环境使用,可以升级企业级或*部门级别,以减少限制。
依赖引入
这里只是openlayer的依赖,vue相关的暂不赘述
//这里只是openlayer的依赖,vue相关的暂不赘述
//openlayer官网的示例的依赖比这里要多,其他的用不到,不需要引入
"ol": "6.9.0"
模块导入
import 'ol/ol.css';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
//WMTS的图层模块
import WMTS from 'ol/source/WMTS';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
//坐标模块
import {get as getProjection} from 'ol/proj';
import {getTopLeft, getWidth} from 'ol/extent';
import View from 'ol/View';
//图片图层
import ImageLayer from 'ol/layer/Image';
import Static from 'ol/source/ImageStatic';
//静态图片的路径
import mapXWImg from '@/assets/test3.png';
构造影像图层
引入天地图的影响图层
//影像图层
let wmtsLayer = new TileLayer({
opacity: 1,
source: new WMTS({
attributions:
'Tiles © <a href="#"' +
' target="_blank">skyocar</a>',
url: 'http://t{0-7}.tianditu.gov.cn/img_c/wmts?tk=' + this.webKey,
layer: 'img',
matrixSet: 'c',
format: 'image/png',
projection: this.projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
style: 'default',
wrapX: true,
}),
});
构造矢量图层
矢量图层的加载是为了地图上展示出地理位置标识等。
//这个是矢量标绘图层,标注底图中的各文字信息
let cvaLayer = new TileLayer({
opacity: 0.7,
source: new WMTS({
url: 'http://t{0-7}.tianditu.gov.cn/cva_c/wmts?tk=' + this.webKey,
layer: 'cva',
matrixSet: 'c',
format: 'tiles',
projection: this.projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
style: 'default',
wrapX: true,
}),
});
加载静态图片层
静态图片的加入可以应对局部地图增强。主要的难点在于中心点定位,这里采用中心定位法,让图片的中心定位到当前屏幕地图中心位置,并设置特定比例的缩放。利用中心点控制、缩放控制,把图片完美的覆盖到地图特定的点位(这也是此次的核心诉求)。
图片图层定位的方法是尝试出来的,并没有找到准确的定位策略,如下。
这里的 -- this.mapCenter = [118.6504, 32.0143]
/** 叠加图片图层 */
getImageLayer: function () {
let p = 0.0001; //图片的缩放尺寸,通过调整图片的加载尺寸和中心点位置,可以调整图片到合适的位置加载
let w = 1210, h = 1210; //图片的宽、高
const imageExtent = [
this.mapCenter[0] - w * p / 2, this.mapCenter[1] - h * p / 2,
this.mapCenter[0] + w * p / 2, this.mapCenter[1] + h * p / 2
];
return new ImageLayer({
className: "image_css",
extent: imageExtent,
source: new Static({
url: mapXWImg,
projection: this.projection,
imageExtent: imageExtent,
dragPan: false
}),
})
},
加载地图主类
<template>
<div class="app-container">
<div id="map" class="map" ref="rootmap">
</div>
</div>
</template>
<style lang='scss'>
.map {
width: 100%;
height: 800px;
}
#mouse-position {
float: right;
position: absolute;
right: 3px;
width: 200px;
height: 20px;
/* 将z-index设置为显示在地图上层 */
z-index: 2000;
}
</style>
this.pageMap = new Map({
layers: [
wmtsLayer,
cvaLayer,
imageLayer,
],
target: 'map',
view: new View({
center: this.mapCenter,
projection: this.projection,
zoom: 13,
}),
});
效果如下:
让静态图片层动起来
这里是为了应对雷达图的效果,请UI同学切了个雷达图片,然后我控制旋转,就完成了雷达图了。这里是使用css3让地图动起来的,代码如下:
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.image_css {
-webkit-transform: rotate(360deg);
animation: rotation 3s linear infinite;
-moz-animation: rotation 3s linear infinite;
-webkit-animation: rotation 3s linear infinite;
-o-animation: rotation 3s linear infinite;
}
效果如下:
完整的代码
<template>
<div class="app-container">
<div id="map" class="map" ref="rootmap">
</div>
</div>
</template>
<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import WMTS from 'ol/source/WMTS';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import {get as getProjection} from 'ol/proj';
import {getTopLeft, getWidth} from 'ol/extent';
import View from 'ol/View';
import ImageLayer from 'ol/layer/Image';
import Static from 'ol/source/ImageStatic';
//静态图片的路径
import mapXWImg from '@/assets/test3.png';
export default {
name: 'OlMap',
props: ['tableData', 'targetPoint'],
data() {
return {
map1: null,
view: null,
vectorSource: null,
mousePositionControl: null,
/** webKey 来源于天地图的开发者密钥,个人开发者有访问限制(每天1万次),
* 上线项目应该使用客户的信息申请企业或*,以解除访问限制 https://console.tianditu.gov.cn/api/traffic */
webKey: '369e7d3985dee029f58564a7747e0dd0',
// webKey: '2a7fadcac8665927c912c4de29ada090',
mapCenter: [118.6504, 32.0143], //底图初始中心点
projection: getProjection('EPSG:4326'),
pageMap: null
}
},
created() {
},
activated() {
},
mounted() {
const projectionExtent = this.projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = new Array(19);
const matrixIds = new Array(19);
for (let z = 0; z < 19; ++z) {
// generate resolutions and matrixIds arrays for this WMTS
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = z;
}
let imageLayer = this.getImageLayer();
imageLayer.on("change", function (event) {
});
//影像图层
let wmtsLayer = new TileLayer({
opacity: 1,
source: new WMTS({
attributions:
'Tiles © <a href="#"' +
' target="_blank">skyocar</a>',
url: 'http://t{0-7}.tianditu.gov.cn/img_c/wmts?tk=' + this.webKey,
layer: 'img',
matrixSet: 'c',
format: 'image/png',
projection: this.projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
style: 'default',
wrapX: true,
}),
});
//这个是矢量标绘图层,标注底图中的各文字信息
let cvaLayer = new TileLayer({
opacity: 0.7,
source: new WMTS({
url: 'http://t{0-7}.tianditu.gov.cn/cva_c/wmts?tk=' + this.webKey,
layer: 'cva',
matrixSet: 'c',
format: 'tiles',
projection: this.projection,
tileGrid: new WMTSTileGrid({
origin: getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds,
}),
style: 'default',
wrapX: true,
}),
});
this.pageMap = new Map({
layers: [
wmtsLayer,
cvaLayer,
imageLayer,
],
target: 'map',
view: new View({
center: this.mapCenter,
projection: this.projection,
zoom: 13,
}),
});
},
methods: {
/** 叠加图片图层 */
getImageLayer: function () {
let p = 0.0001; //图片的缩放尺寸,通过调整图片的加载尺寸和中心点位置,可以调整图片到合适的位置加载
let w = 1210, h = 1210; //图片的宽、高
const imageExtent = [
this.mapCenter[0] - w * p / 2, this.mapCenter[1] - h * p / 2,
this.mapCenter[0] + w * p / 2, this.mapCenter[1] + h * p / 2
];
return new ImageLayer({
className: "image_css",
extent: imageExtent,
source: new Static({
url: mapXWImg,
projection: this.projection,
imageExtent: imageExtent,
dragPan: false
}),
})
},
}
};
</script>
<style lang='scss'>
.map {
width: 100%;
height: 800px;
}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
.image_css {
-webkit-transform: rotate(360deg);
animation: rotation 3s linear infinite;
-moz-animation: rotation 3s linear infinite;
-webkit-animation: rotation 3s linear infinite;
-o-animation: rotation 3s linear infinite;
}
</style>
未解决的问题
虽然实现了效果,但依然有瑕疵未完全解决,对于球面坐标系和桌面坐标系的理解依然不足,希望有心人可以指导一二。
- 因地图坐标系和桌面坐标系的不同,暂时未找到保持一致的算法,一旦地图拖动,会导致雷达图旋转点错位;
- 静态图片叠加的定位算法有待优化,需要找到更适合的算法,以便于快速定位。