封装了一个类似全局动画控制器的类 用于播放所有动画
// 动画播放总控制器
class animationSupper {
funList = {}//所有的动画
//修改动画
setAnimationAct(animationAct) {
this.funList.map(item => {
item.animationAct()
})
this.setAnimationAct = animationAct
return this
}
//动画播放方法
animationFun() {
if (!Object.keys(this.funList).length) return
Object.values(this.funList).map(item => {
item()
})
requestAnimationFrame(() => this.animationFun())
}
// 修改动画
setFun(keyValue, fun) {
let key = keyValue ? keyValue : Math.random()
this.funList[key] = fun
this.animationFun()
return key
}
//添加动画
addFun(fun) {
let key = Math.random()
this.funList[key] = fun
this.animationFun()
return key
}
//删除动画
removeFun(key) {
delete this.funList[key]
}
}
单个动画控制类
//下面的控制器要用到这个实例化后的类
let ani = new animationSupper()
// 动画控制器
class animation {
geometry
animationAct
//掩饰时间
timer = 1
//动画携带数据
columnData
//播放状态控制
status = false
//每个动画专有的key
funKey
//入口需要传入图形 和动画方法
constructor(geometry, animationAct) {
this.geometry = geometry
this.animationAct = animationAct
return this
}
//修改某个动画携带的数据
setCoumnData(columnData) {
this.columnData = columnData
return this
}
//修改动画时间
setTimer(timer) {
this.timer = timer
return this
}
//更改动画
setAnimationAct(animationAct) {
this.animationAct = animationAct
ani.setFun(this.funKey, () => this.animationAct(this.columnData))
return this
}
//开始动画
start() {
this.status = true
setTimeout(() => {
this.funKey = ani.addFun(() => this.animationAct(this.columnData))
}, this.timer)
return this
}
//停止动画
stop() {
ani.removeFun(this.funKey)
this.status = false
}
}
基础地图
let map = new ol.Map({
target: "map",
view: new ol.View({
center: [112.549248, 37.857014],
zoom: 5,
projection: "EPSG:4326",
}),
layers: [],
})
文字图层相关内容
//新建空的文字图层 名字为了方便控制
let textLayer = new ol.layer.Vector({
name: "text",
zIndex: 3,//进行图层层次控制
source: new ol.source.Vector(),
})
/**
* 创建一个文字 返回文字要素 需要传入坐标点 及文字内容
* @param {[number,number]} xy 坐标
* @param {string} text 渲染的文字
* @returns {Feature} 要素
*/
function addText(xyz, text) {
//新建要素 点的位置为
let feature = new ol.Feature({
//几何为一个点 位置在xy
geometry: new ol.geom.Point(xyz)
});
//修改样式为文字
feature.setStyle(new ol.style.Style({
text: new ol.style.Text({
text: text,//文字内容为传入的text
font: '16px Calibri,sans-serif',//字体大小和字体样式
fill: new ol.style.Fill({color: '#fff'}),//填充样式
offsetY: -18//位置偏移 有y就有x
})
}));
return feature
}
map.addLayer(textLayer)
点图层的相关内容
//新建空的点图层 名字为了方便控制
let pointLayer = new ol.layer.Vector({
name: "point",
zIndex: 2, //进行图层层次控制
source: new ol.source.Vector()
})
/**
* 创建一个圆 返回圆的要素 需要传入坐标点
* @param {[number,number]} xy 坐标
* @returns {Feature} 要素
*/
function addCircle(xy) {
// 创建一个圆点要素
let a = new ol.Feature({
//几何对象为一个点 位置在xy
geometry: new ol.geom.Point(xy),
});
//修改创建的要素样式为圆
a.setStyle(new ol.style.Style({
image: new ol.style.Circle({
//半径为3
radius: 3,
//填充颜色
fill: new ol.style.Fill({
color: 'rgba(255,1,1,0.3)'
}),
})
}))
return a
}
map.addLayer(pointLayer)
行政区划 部分内容 geojson文件地址
//原本样式 这里提出来为了下面的移入样式做准备
let geoStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#eee',
width: 1
}),
fill: new ol.style.Fill({
color: '#d1d1d1'
})
})
//选中的样式 为下面的移入样式做准备
let selectStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#eee',
width: 1
}),
fill: new ol.style.Fill({
color: '#92959e'
}),
})
//新建 行政区划geojson name为了下面选中的时候不影响其他图层
let geoLayer = new ol.layer.Vector({
name: "geoLayer",
index: 1,//进行图层层次控制
source: new ol.source.Vector({
url: './province.geojson',//放你的地址
format: new ol.format.GeoJSON()
}),
style: geoStyle
})
map.addLayer(geoLayer)
添加点和文字的方法 不需要的可以在里面删除掉 某个方法的调用 不需要点的动画就直接将addCircle返回的内容添加到pointLayer
//添加点和文字的方法
let initTextAndPoint = (event) => {
//在所有的要素中遍历
event.target.getFeatures().map(item => {
//获取要素属性
let data = item.getProperties()
//获取到各省市的中心点
if (data.center || data.centroid) {
//在文字图层获取数据源 且在数据源中添加要素 添加的要素为addText的返回内容 传入的文字裁掉 省|特别行政区|自治区
textLayer.getSource().addFeature(addText(data.center || data.centroid, data.name.replace(/省|特别行政区|自治区/g, '')))
//获取Circle画的圆要素
let geometry = addCircle(data.center || data.centroid)
//将这个要素添加到点图层
pointLayer.getSource().addFeatures([geometry])
//使用刚才创建的动画类 创建一个动画
let an = new animation(geometry, ({radius, status}) => {
//如果我们添加进去的 radius 半径大于10 我们将数据还原为0
if (radius > 10)
an.setCoumnData({
radius: 0
})
else {
//否则将数据++ 这里加的值越大 速度越快
an.setCoumnData({
radius: radius + 0.005
})
}
//捕获错误
try {
//获取到圆的style中的自定义styleImage 就是创建出来的样式源更改半径
geometry.getStyle().getImage().setRadius(radius)
//再更改源的style 实现动画
geometry.setStyle(geometry.getStyle())
} catch (e) {
//如果出错则停止动画
an.stop()
}
}
)
//更改延迟执行时间
an.setTimer(Math.random() * 1000)
//修改自定义数据 且开始动画
an.setCoumnData({
radius: 0,
}).start()
}
}
)
// 停止监听数据源更改 否则此方法一直调用
geoLayer.getSource().un('change', initTextAndPoint)
}
//监听数据源修改 调用添加点和文字方法
geoLayer.getSource().on('change', initTextAndPoint)
鼠标移入 更改颜色 代码
//鼠标移入的选中项
let selectFeature = null
let selectId = null
//监听鼠标移动
map.on('pointermove', function (event) {
//从map中获取到像素位置下的要素
map.forEachFeatureAtPixel(event.pixel, (feature, layer) => {
//如果图层为geoLayer并且不是上一次选中的要素
if (selectId != feature.ol_uid && layer.get('name') == 'geoLayer' && feature) {
//如果选中的要素有则还原style 且将其他设置为空
if (selectFeature) {
selectFeature.setStyle(geoStyle)
selectFeature = null
selectId = null
}
// 将唯一id提出来 进行性能优化 避免下一次再更改样式
selectId = feature.ol_uid
//将给要素给到选中要素 为了下一次恢复使用
selectFeature = feature
//修改要素样式
feature.setStyle(selectStyle)
}
});
});