这篇讲的是如何在地图上加载gif动画,因为openlayers本身是不支持插入gif动画的,因此我们要下一个gifler插件。
npm i gifler
npm下下来之后发现直接import和require引入都不行,好嘛,直接引入算了
在node_moudles里面找到这个文件,复制出来
直接丢到项目public/gifler下面
在index.html下面引入gifler
<script src="gifler/gifler.min.js"></script>
顺便在网上找一张gif动画放到data目录下。
然初始化一个map,这次用到的是StadiaMaps底图,我试了下应该是可以直接加载出来的。
const rasterLayer = new TileLayer({
source: new StadiaMaps({
layer: "stamen_toner",
}),
});
const map = new Map({
layers: [rasterLayer],
target: document.getElementById("map"),
view: new View({
center: [116.389, 39.903],
zoom: 8,
projection: "EPSG:4326",
}),
});
然后是加一个矢量点上去
const iconFeature = new Feature({
geometry: new Point([116.389, 39.903]),
});
const vectorSource = new VectorSource({
features: [iconFeature],
});
const vectorLayer = new VectorLayer({
source: vectorSource,
});
feature放到source上,source放到layer上 layer放到地图上
feature ->source->layer->map
然后把我们下载的gif加载到地图上,注意gif文件的地址不要写错了。
gifler(gifUrl).frames是gitler的一个方法,在里面打印会发现控制台会一直输出,看了下它的源码,大胆猜测一下,我感觉它是把gif的每一帧返回过来,然后通过canvas绘制图片的方法ctx.drawImage绘制到地图上,再调了map.render()实时渲染地图。不知道对不对,感兴趣的可以看下源码
const gifUrl = "data/dog.gif";
const gif = gifler(gifUrl);
gif.frames(
document.createElement("canvas"),
function (ctx, frame) {
if (!iconFeature.getStyle()) {
iconFeature.setStyle(
new Style({
image: new Icon({
img: ctx.canvas,
opacity: 1,
}),
})
);
}
ctx.clearRect(0, 0, frame.width, frame.height);
ctx.drawImage(frame.buffer, frame.x, frame.y);
// 渲染地图
map.render();
},
true
);
然后再是鼠标移动事件,getFeaturesAtPixel
方法会返回一个当前鼠标移动的坐标数组,hasFeatureAtPixel检查指定像素位置下是否存在地图要素(features)返回一个布尔值,然后动态改变鼠标的css样式。
map.on("pointermove", function (e) {
const pixel = map.getEventPixel(e.originalEvent);
const hit = map.hasFeatureAtPixel(pixel);
map.getTarget().style.cursor = hit ? "pointer" : "";
});
个人感觉这种方式加载gif不是很好,比如我要同时加载多个点位的gif动画,每张gif图片的大小还不一样,就有些难办。改鼠标样式也很麻烦。如果项目中有需求要加载多个gif建议使用Overlay,不要用这种矢量点的方式。
完整代码:
<template>
<div class="box">
<h1>Animated GIF</h1>
<div id="map"></div>
</div>
</template>
<script>
import Feature from "ol/Feature.js";
import Map from "ol/Map.js";
import Point from "ol/geom/Point.js";
import View from "ol/View.js";
import { Icon, Style } from "ol/style.js";
import { StadiaMaps, Vector as VectorSource, ImageCanvas } from "ol/source.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
export default {
name: "",
components: {},
data() {
return {
map: null,
};
},
computed: {},
created() {},
methods: {},
mounted() {
const iconFeature = new Feature({
geometry: new Point([116.389, 39.903]),
});
const vectorSource = new VectorSource({
features: [iconFeature],
});
const vectorLayer = new VectorLayer({
source: vectorSource,
});
const rasterLayer = new TileLayer({
source: new StadiaMaps({
layer: "stamen_toner",
}),
});
const map = new Map({
layers: [rasterLayer, vectorLayer],
target: document.getElementById("map"),
view: new View({
center: [116.389, 39.903],
zoom: 8,
projection: "EPSG:4326",
}),
});
const gifUrl = "data/dog.gif";
const gif = gifler(gifUrl);
gif.frames(
document.createElement("canvas"),
function (ctx, frame) {
if (!iconFeature.getStyle()) {
iconFeature.setStyle(
new Style({
image: new Icon({
img: ctx.canvas,
opacity: 1,
}),
})
);
}
ctx.clearRect(0, 0, frame.width, frame.height);
ctx.drawImage(frame.buffer, frame.x, frame.y);
// 渲染地图
map.render();
},
true
);
map.on("pointermove", function (e) {
const pixel = map.getEventPixel(e.originalEvent);
const hit = map.hasFeatureAtPixel(pixel);
map.getTarget().style.cursor = hit ? "pointer" : "";
});
},
};
</script>
<style lang="scss" scoped>
#map {
width: 100%;
height: 500px;
}
.box {
height: 100%;
}
</style>