阅读 10
^ 关注我,带你一起学GIS ^
❝
注:当前使用的是 ol 9.2.4 版本,天地图使用的
key
请到天地图官网申请,并替换为自己的key
动画在WebGIS
开发中是很常见的操作,一般具有平移动画、旋转动画、弹性动画等。在OpenLayers
开发中,地图动画主要由View
类的animate
方法实现。animate
可以实现多段动画效果,其中参数包括zoom
、center
、resolution
等。
参考动画地址:https://easings.net/#
1. 普通平移动画
普通平移动画方便简单,获取当前视图缩放级别,设置平移中心点即可。
view.animate({
zoom: view.getZoom(),
center
});
2. 弹性平移动画
弹性平移在普通平移的基础上加上动画函数。
view.animate(
{
zoom: 10,
center,
duration: 2000,
easing: elastic
}
);
3. 弹跳平移动画
弹跳平移可以设置多段动画,可以使用OpenLayers
提供的动画函数upAndDown
,也可以自定义动画函数。
view.animate(
//第一段动画
{
zoom: zoom - 1,
center,
duration: 1000,
// easing: ol.easing.upAndDown
easing: easeInBounce
},
//第二段动画
{
zoom: zoom,
center,
duration: 1000,
// easing: ol.easing.upAndDown
easing: easeInBounce
}
);
4. 旋转平移动画
旋转动画主要设置rotation参数,其值为弧度大小,-Math.PI * 2<=rotation<=Math.PI * 2
view.animate(
{
zoom: 10,
center,
rotation: Math.PI
},
{
zoom: 10,
center,
rotation: Math.PI * 2
}
);
5. 飞行平移动画
在飞行动画中,可以设置多段动画效果,改变飞行过程中缩放级别参数,在动画结束时恢复动画开始之前的缩放级别。
view.animate(
{
zoom: zoom,
center,
duration: 2000
},
{
zoom: zoom - 1,
center,
duration: 1000
},
{
zoom: zoom,
center,
duration: 1000
}
)
6. 完整代码
其中libs
文件夹下的包需要更换为自己下载的本地包或者引用在线资源。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>地图动画</title>
<meta charset="utf-8" />
<script src="../../libs/js/jquery-2.1.1.min.js"></script>
<script src="../../js/ol9.2.4.js"></script>
<link rel="stylesheet" href="../../css/ol9.2.4.css">
<style>
* {
padding: 0;
margin: 0;
font-size: 14px;
font-family: '微软雅黑';
}
html,
body {
width: 100%;
height: 100%;
}
#map {
position: absolute;
top: 50px;
bottom: 0;
width: 100%;
}
#top-content {
position: absolute;
width: 100%;
height: 50px;
line-height: 50px;
background: linear-gradient(135deg, #ff00cc, #ffcc00, #00ffcc, #ff0066);
color: #fff;
text-align: center;
}
.animate {
border-radius: 5px;
border: 1px solid #50505040;
padding: 5px 20px;
color: #fff;
margin: 0 10px;
background: #377d466e;
transition: background-color 10s ease-in-out 10s;
text-align: center;
font-size: 16px;
font-weight: bold;
}
.animate:hover {
cursor: pointer;
filter: brightness(120%);
background: linear-gradient(135deg, #c850c0, #4158d0);
}
.active {
background: linear-gradient(135deg, #c850c0, #4158d0);
}
.ol-popup {
position: relative;
font-size: 16px;
color: #4c4c4c;
background-color: #FFF;
border-radius: 5px;
}
.ol-popup::before {
display: block;
content: "";
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-top: 10px solid #FFF;
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
}
.ol-popup-main {
padding: 20px;
}
.ol-popup-close {
position: absolute;
display: inline-block;
top: -6px;
right: 5px;
color: #878282b5;
font-size: 20px;
}
.ol-popup-text {
font-size: 14px;
font-weight: bold;
color: #434343;
}
.ol-popup-close:hover {
cursor: pointer;
color: #0e0e0eb5;
filter: brightness(120%);
}
</style>
</head>
<body>
<div id="map" title="地图显示"></div>
<div id="top-content">
<button class="animate simple-animate">普通平移</button>
<button class="animate flex-animate">弹性平移</button>
<button class="animate jump-animate">弹跳平移</button>
<button class="animate rotate-animate">旋转平移</button>
<button class="animate fly-animate">飞行平移</button>
<button class="animate reset">复位</button>
</div>
</body>
</html>
<script>
//地图投影坐标系
const projection = ol.proj.get('EPSG:3857');
//==============================================================================//
//============================天地图服务参数简单介绍==============================//
//================================vec:矢量图层==================================//
//================================img:影像图层==================================//
//================================cva:注记图层==================================//
//======================其中:_c表示经纬度投影,_w表示球面墨卡托投影================//
//==============================================================================//
const TDTImgLayer = new ol.layer.Tile({
title: "天地图影像图层",
source: new ol.source.XYZ({
url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
attibutions: "天地图注记描述",
crossOrigin: "anoymous",
wrapX: false
})
})
const TDTImgCvaLayer = new ol.layer.Tile({
title: "天地图影像注记图层",
source: new ol.source.XYZ({
url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=2a890fe711a79cafebca446a5447cfb2",
attibutions: "天地图注记描述",
crossOrigin: "anoymous",
wrapX: false
})
})
const map = new ol.Map({
target: "map",
loadTilesWhileInteracting: true,
view: new ol.View({
center: [104.0635986160487, 30.660919181071225],
// center: [11444274, 12707441],
zoom: 5,
worldsWrap: true,
minZoom: 1,
maxZoom: 20,
projection: "EPSG:4326"
}),
layers: [TDTImgLayer, TDTImgCvaLayer],
// 地图默认控件
controls: ol.control.defaults.defaults({
zoom: true,
attribution: true,
rotate: true
})
})
map.on('click', evt => {
console.log(evt.coordinate)
})
/**
* 添加图层
*/
function addPoint(center, popupEle) {
const point = new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(center)
})
]
})
const layer = new ol.layer.Vector({
source: point,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: "red"
})
})
})
})
layer.set("name", "pointLayer")
const marker = new ol.Overlay({
id: "maker",
position: center,
element: popupEle,
offset: [0, -20], // x、y轴偏移量,正值向右向下,负值相反
positioning: 'bottom-center', // 定位方式,顶部居中
// aotuPan: true,
// autoPanMargin: 1.25,
})
map.addOverlay(marker)
map.addLayer(layer)
}
/**
* 移除图层
*/
function clearPoint() {
const layers = map.getLayers().getArray()
layers.forEach(layer => {
if (layer.get("name") === "pointLayer") {
map.removeLayer(layer)
}
})
const overlays = map.getOverlays().getArray()
overlays.forEach(overlay => {
map.removeOverlay(overlay)
})
}
const view = map.getView()
/**
* 普通平移
*/
const simpleAnimateEle = document.querySelector(".simple-animate")
simpleAnimateEle.addEventListener("click", evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [24.22230887826462, 11.917610630971534]
view.animate({
zoom: view.getZoom(),
center
});
const popupEle = createPopupEle("这里是非洲!")
addPoint(center, popupEle)
})
// 获取弹性伸缩值
function elastic(t) {
return Math.pow(2, -10 * t) * Math.sin(t - 0.075) * (2 * Math.PI) + 1
}
/**
* 弹性平移
*/
const flexAnimateEle = document.querySelector(".flex-animate")
flexAnimateEle.addEventListener("click", evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [120.1585181123716, 30.252189829156805]
view.animate(
{
zoom: 10,
center,
duration: 2000,
easing: elastic
}
);
const popupEle = createPopupEle("这里是杭州!")
addPoint(center, popupEle)
})
function easeOutBounce(x) {
const n1 = 7.5625;
const d1 = 2.75;
if (x < 1 / d1) {
return n1 * x * x;
} else if (x < 2 / d1) {
return n1 * (x -= 1.5 / d1) * x + 0.75;
} else if (x < 2.5 / d1) {
return n1 * (x -= 2.25 / d1) * x + 0.9375;
} else {
return n1 * (x -= 2.625 / d1) * x + 0.984375;
}
}
function easeInBounce(number) {
return 1 - easeOutBounce(1 - number);
}
/**
* 弹跳平移
*/
const jumpAnimateEle = document.querySelector(".jump-animate")
jumpAnimateEle.addEventListener("click", evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [103.83814721904622, 36.05218284753544]
const zoom = view.getZoom()
view.animate(
{
zoom: zoom - 1,
center,
duration: 1000,
// easing: ol.easing.upAndDown
easing: easeInBounce
},
{
zoom: zoom,
center,
duration: 1000,
// easing: ol.easing.upAndDown
easing: easeInBounce
}
);
const popupEle = createPopupEle("这里是兰州!")
addPoint(center, popupEle)
})
/**
* 旋转平移
*/
const rotateAnimateEle = document.querySelector(".rotate-animate")
rotateAnimateEle.addEventListener("click", evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [104.0635986160487, 30.660919181071225]
view.animate(
{
zoom: 10,
center,
rotation: Math.PI
},
{
zoom: 10,
center,
rotation: Math.PI * 2
}
);
const popupEle = createPopupEle("这里是成都!")
addPoint(center, popupEle)
})
/**
* 飞行平移
*/
const flyAnimateEle = document.querySelector(".fly-animate")
flyAnimateEle.addEventListener("click", evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [113.2562927875718, 23.134318823592487]
const zoom = view.getZoom()
view.animate(
{
zoom: zoom,
center,
duration: 2000
},
{
zoom: zoom - 1,
center,
duration: 1000
},
{
zoom: zoom,
center,
duration: 1000
}
)
const popupEle = createPopupEle("这里是广州!")
addPoint(center, popupEle)
})
/**
* 复位
*/
document.querySelector(".reset").addEventListener('click', evt => {
clearPoint()
toogleAciveClass(evt.target)
const center = [112.21975149119689, 30.33501910629522]
view.animate({ zoom: view.getZoom() }, { center: center }, { rotation: 0 });
const popupEle = createPopupEle("这里是荆州!")
addPoint(center, popupEle)
})
/**
* 切换激活样式
*/
function toogleAciveClass(target) {
// 判断top-content子元素是否激活,并切换激活样式
const swipeBtnLike = document.querySelector('#top-content')
for (let element of swipeBtnLike.children) {
if (target === element) {
target.classList.add('active')
} else {
element.classList.remove('active')
}
}
}
/**
* 创建Popup 内容
* @mainContent:HTML 或者 文字
*/
function createPopupEle(mainContent) {
const htmlEle = document.createElement("div")
const closeEle = document.createElement('span')
const mainEle = document.createElement('div')
mainEle.className = 'ol-popup-main'
console.log(typeof mainContent)
const contentType = typeof mainContent
if (contentType === 'object') {
mainEle.appendChild(mainContent)
} else if (contentType === 'string') {
mainEle.innerHTML = mainContent
}
closeEle.textContent = "×"
closeEle.className = "ol-popup-close"
htmlEle.className = "ol-popup"
htmlEle.appendChild(mainEle)
htmlEle.appendChild(closeEle)
// 注册关闭popup事件
closeEle.addEventListener('click', evt => {
clearPoint()
})
return htmlEle
}
</script>
❝
OpenLayers示例数据下载,请在公众号后台回复:ol数据
全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试
❝
GIS之路公众号已经接入了智能助手,欢迎大家前来提问。
欢迎访问我的博客网站-长谈GIS:
http://shanhaitalk.com
都看到这了,不要忘记点赞、收藏+关注 哦!
本号不定时更新有关 GIS开发 相关内容,欢迎关注