【openlayer实现动态效果的点渲染】

使用openlayers实现动态扩散点

需求

需要在地图上显示物联设备的状态,需要比较显眼的方式,通过一定的动态效果展示。通过矢量图层的样式其实是比较难实现一些好一点的动态效果的,查询API发现了有一个ImageCanvas的Source,通过canvas那就可以做很多事了。

实现方案

继承openlayers 的ImageCanvas,根据添加的Point和属性信息操作canvas画出效果,通过 window.requestAnimationFrame 实现动画效果。

openlayers6 中也可以通过layer的 prerender和postrender去更改样式中的参数实现动态效果,如修改样式的颜色,透明度,圆半径等

代码实现

//定义一个新的source
ol.source.AnimaSource = function (opt_options) {
  let options = opt_options || {};
  let map = this.map = options.map;
  this.zIndex = options.zIndex;
  this.offset = [0,0];
  this.features = new Array();
  this.idCahce = {}
  this.isAnimation = false;
  this.init = false;
  let _this = this;
  let canvas = this.canvas = document.createElement("canvas");
  let context = this.context = this.canvas.getContext('2d');
  ol.source.ImageCanvas.call(this,{
    canvasFunction:_this.canvasFunc
  });
  this.map.on('change:size', this.resize.bind(this));
  let scale = function (pixelP, center, scaleRatio) {
    var x = (pixelP[0] - center[0]) * scaleRatio + center[0];
    var y = (pixelP[1] - center[1]) * scaleRatio + center[1];
    return [x, y];
  }

	//坐标转屏幕坐标
  let transformCoordinate =function(coordinate) {
    let x = (coordinate[0] - _this._mapCenter[0]) / _this._reselutions, y = (_this._mapCenter[1] - coordinate[1]) / _this._reselutions;
    var scaledP = [x + _this._mapCenterPx[0], y + _this._mapCenterPx[1]];
    scaledP = scale(scaledP, _this._mapCenterPx, 1);
    return [scaledP[0] + _this.offset[0], scaledP[1] + _this.offset[1]];
  };

// 动画render方法
  let render = this.renderFunc = function () {
    if(_this.aid!=null){
      window.cancelAnimationFrame(_this.aid);
    }
    context.save();
    context.clearRect(0,0,_this.canvas.width,_this.canvas.height);

    for (let i=0;i<_this.features.length;i++){
      let f= _this.features[i];
      //调用实体的draw方法
      f.draw(context,transformCoordinate);
    }
    context.restore();
    map.render();
    if(_this.isAnimation){
      _this.aid = window.requestAnimationFrame(render);
    }
  }
};
// 指定source的画布方法
ol.source.AnimaSource.prototype.canvasFunc= function (extent, resolution, pixelRatio, size, projection) {
  if(!this.init){
    this.init = true;
    this.startAnimation(this.renderFunc);
  }
  var mapWidth = size[0] / pixelRatio;
  var mapHeight = size[1] / pixelRatio;
  var width = this.map.getSize()[0];
  var height = this.map.getSize()[1];
  this.pixelRatio = pixelRatio;
  let offset = [(mapWidth - width) / 2, (mapHeight - height) / 2];
  this.offset[0] = offset[0];
  this.offset[1] = offset[1];
  this.canvas.style.cssText = "position:absolute;" + "left:"+offset[0]+";" + "top:"+offset[1]+";" + "z-index:" + this.zIndex + ";";
  this.canvas.className = "myAnimClass";

  this.canvas.width = size[0];
  this.canvas.height = size[1];

  this._mapCenter = this.map.getView().getCenter();
  this._mapCenterPx = this.map.getPixelFromCoordinate(this._mapCenter);
  this._reselutions = this.map.getView().getResolution();
  this._rotation = this.map.getView().getRotation();
  this.context.scale(pixelRatio,pixelRatio);
  return this.canvas;
}

ol.source.AnimaSource.prototype.startAnimation = function () {
  if(this.isAnimation==false){
    this.isAnimation = true;
    this.aid = window.requestAnimationFrame(this.renderFunc);
  }
}

ol.source.AnimaSource.prototype.stopAnimation = function () {
  if(this.aid!=null){
    window.cancelAnimationFrame(this.aid);
    this.aid = null;
  }
  this.isAnimation = false;
}

// 地图大小变化时,重新计算画布大小,坐标偏移
ol.source.AnimaSource.prototype.resize = function (evt) {
  let mapSize = evt.target.getSize();
  let mapWidth = mapSize[0];
  let mapHeight = mapSize[1];
  this._mapCenter = this.map.getView().getCenter();
  this._mapCenterPx = this.map.getPixelFromCoordinate(this._mapCenter);
  let global$2 = typeof window === 'undefined' ? {} : window;
  let devicePixelRatio = this.devicePixelRatio = global$2.devicePixelRatio;
  let offset = [(this.canvas.width/devicePixelRatio - mapWidth) / 2, (this.canvas.height/devicePixelRatio -mapHeight) / 2];
  this.offset[0] = offset[0];
  this.offset[1] = offset[1];
  this.context.scale(devicePixelRatio, devicePixelRatio);
  this.canvas.style.width = mapWidth + "px";
  this.canvas.style.height = mapHeight + "px";
}

ol.source.AnimaSource.prototype.addPoint = function (f) {
  let fp = new FlashPoint(f);
  this.features.push(fp);
  if (f.id!=null && f.id!==''){
    if(this.idCahce.hasOwnProperty(f.id)){
      throw new Error("id已经存在")
    }
    this.idCahce[f.id] = this.features.length-1
  }
  return fp
}

//继承 ImageCanvas
ol.inherits(ol.source.AnimaSource,ol.source.ImageCanvas);

/**
 *	定义一个实体
 *  @param fp_options 配置信息 {}
 *  inSize:内圈大小-半径 ;默认 6
 *  outSize:外圈大小;默认 16
 *  color:颜色;默认 #FF0000
 *  opacity:透明度 [0-1] ;默认 0.3
 *  coord:坐标 [x,y] 地图坐标
 *  maxInSize:最大内圈大小;默认 10
 *  maxOutSize:最大外圈大小 ;默认 32
 *  duration:动画时长.毫秒;默认 1000
 *
 * */
function FlashPoint(fp_options) {
  this.options = fp_options || {};
  this.id = this.options.id
  this.inSize = this.options.inSize || 2.5;
  this.outSize = this.options.outSize || 8;
  this.color = this.options.color || '#FF0000';
  this.opacity = this.options.opacity || 0.3;
  this.coord = this.options.coord;
  this.maxInSize = this.options.maxInSize || 5;
  this.maxOutSize = this.options.maxOutSize || 16;
  this.duration = this.options.duration || 1000;
  this.ocolor = Utils.hexToRgbOpacity(this.color,this.opacity);
  this.cInSize = this.inSize;
  this.cOutSize = this.outSize;
  //1秒60帧
  this.inStep = this.options.inStep == undefined ? (this.maxInSize - this.inSize)/this.duration*1000/60 : this.options.inStep;
  this.outStep = this.options.outStep == undefined ? (this.maxOutSize - this.outSize)/this.duration*1000/60 : this.options.outStep;
  this.ti = 1;
  return this;
}

FlashPoint.prototype.draw = function(context,transformCoordinate){

  if (this.cOutSize<=this.outSize){
    this.ti = 1;
  }else if(this.cOutSize>=this.maxOutSize){
    this.ti = -1;
  }

  this.cInSize = this.cInSize+this.ti*this.inStep;

  this.cOutSize = this.cOutSize+this.ti*this.outStep;

  let pixel = transformCoordinate(this.coord);
  context.fillStyle=this.color;
  context.beginPath();
  context.arc(pixel[0],pixel[1],this.cInSize,0,2*Math.PI);
  context.closePath();
  context.fill();
  context.fillStyle=this.ocolor;
  context.beginPath();
  context.arc(pixel[0],pixel[1],this.cOutSize,0,2*Math.PI);
  context.closePath();
  context.fill();
}

使用

const animaSource = new ol.source.AnimaSource({
		//配置options
})
const layer = ol.Vector.Layer({
	source:animaSource 
})
const flashPoint = new FlashPoint({
	//options
})
animaSource.addPoint(flashPoint)
map.addLayer(layer)

也可以定义一些其它实体,实现自己的draw方法,就可以在同一个source中添加数据后渲染不同的内容。

效果图:
在这里插入图片描述

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OpenLayers 是一个开源的 JavaScript 库,用于在 Web 地图上展示地理数据。它提供了丰富的功能和工具,可以轻松地在浏览器中创建交互式地图应用。 要实现展示信息,首先需要创建一个地图实例,并添加一个图层。然后,通过给图层添加要显示的矢量要素,来表示的位置。接下来,可以为地图添加一个交互功能,例如击事件监听器,以便在用户击地图上的时触发一些操作。 具体实现步骤如下: 1. 创建一个地图实例,并设置地图容器的 DOM 元素,指定地图的初始中心和缩放级别。 ```javascript var map = new ol.Map({ target: 'map-container', view: new ol.View({ center: ol.proj.fromLonLat([lon, lat]), // 初始中心的经纬度坐标 zoom: 10 // 初始缩放级别 }) }); ``` 2. 创建一个矢量图层,并将其添加到地图中。 ```javascript var vectorLayer = new ol.layer.Vector({ source: new ol.source.Vector() }); map.addLayer(vectorLayer); ``` 3. 创建一个击事件监听器,当用户击地图上的时触发。在该事件监听器中,首先需要判断击的是否是一个有效的矢量要素,如果是,则获取该要素的属性信息,并展示在页面上。 ```javascript map.on('singleclick', function(event) { map.forEachFeatureAtPixel(event.pixel, function(feature, layer) { var properties = feature.getProperties(); // 获取要素的属性信息 // 在这里展示属性信息,可以通过弹窗、Toast 等方式展示 }); }); ``` 通过以上步骤,我们可以实现展示信息的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkLess404

有问题可以私信交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值