项目需要地图上实现不断报警的闪烁样式,之前是通过Overlay来处理的,但Overlay遮挡要素,无法很好的触发事件,所以就转而使用Canvas原生实现。过程主要参考:openlayers4中闪烁点的实现、canvas-flashMarker-RunJS。
原本的做法是通过构造新的对象new FlashMarker(map, citys),每次构造新增一个Canvas,没有办法清除,那么我针对这些问题进行适应性的修改。
经测试,过多的样式绘制会有卡顿,目前没有太好的方法解决,不过Canvas绘制仍然效果比Openlayers好。
这里效果就不展示了,效果可以在背景贴的原文那里看,我只是改动调用和优化实现。
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.CanvasLayer = factory());
}(this, (function () { 'use strict';
//封装一个兼容性良好的方法
window.requestAnimFrame= (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
}
})();
window.cancelAnimFrame = (function(){
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
function(id){
window.clearTimeout(id);
}
})();
function CanvasLayer(options) {
this.options = options || {};
this.paneName = this.options.paneName || 'labelPane';
this.zIndex = this.options.zIndex || 0;
this._map = options.map;
this._lastDrawTime = null;
this.show();
}
CanvasLayer.prototype.initialize = function () {
var map = this._map;
var canvas = this.canvas = document.createElement('canvas');
var ctx = this.ctx = this.canvas.getContext('2d');
canvas.style.cssText = 'position:absolute;' + 'left:0;' + 'top:0;' + 'z-index:' + this.zIndex + ';';
this.animationIds = [];
this.adjustSize();
this.adjustRatio(ctx);
map.getViewport().appendChild(canvas);
var that = this;
map.getView().on('propertychange',function(){
$(canvas).hide();
});
map.on("moveend",function(){
$(canvas).show();
that.adjustSize();
//that._draw();
});
};
// Wilson
CanvasLayer.prototype.clear = function () {
var animationCtx = this.ctx;
var width = this._map.getSize()[0];
var height = this._map.getSize()[1];
var animationIds = this.animationIds;
for (var i = 0; i < animationIds.length; i++) {
window.cancelAnimationFrame(animationIds[i]);
}
this.animationIds = [];
animationCtx.clearRect(0, 0, width, height);
};
// Wilson
CanvasLayer.prototype.addMarkers = function (dataSet) {
var animationCtx = this.ctx;
var width = this._map.getSize()[0];
var height = this._map.getSize()[1];
var markers = [];
var length = this.animationIds.length;
var that = this;
for (var i = 0; i < dataSet.length; i++) {
markers.push(new Marker(dataSet[i]));
}
//开始动画
var startAnim = function() {
var animationId = window.requestAnimFrame(render);
that.animationIds[length] = animationId;
}
function render() {
startAnim();
animationCtx.fillStyle = 'rgba(0,0,0,.95)';
var prev = animationCtx.globalCompositeOperation;
animationCtx.globalCompositeOperation = 'destination-in';
animationCtx.fillRect(0, 0, width, height);
animationCtx.globalCompositeOperation = prev;
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
marker.draw(animationCtx);
}
};
startAnim();
};
CanvasLayer.prototype.adjustSize = function () {
var size = this._map.getSize();
var canvas = this.canvas;
canvas.width = size[0];
canvas.height = size[1];
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
};
CanvasLayer.prototype.adjustRatio = function (ctx) {
var backingStore = ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
var pixelRatio = (window.devicePixelRatio || 1) / backingStore;
var canvasWidth = ctx.canvas.width;
var canvasHeight = ctx.canvas.height;
ctx.canvas.width = canvasWidth * pixelRatio;
ctx.canvas.height = canvasHeight * pixelRatio;
ctx.canvas.style.width = canvasWidth + 'px';
ctx.canvas.style.height = canvasHeight + 'px';
ctx.scale(pixelRatio, pixelRatio);
};
/*CanvasLayer.prototype._draw = function () {
var map = this._map;
var size = map.getSize();
var center = map.getView().getCenter();
if (center) {
var pixel = map.getPixelFromCoordinate(center);
this.canvas.style.left = pixel[0] - size[0] / 2 + 'px';
this.canvas.style.top = pixel[1] - size[1] / 2 + 'px';
//this.options.update && this.options.update.call(this);
}
};*/
CanvasLayer.prototype.getContainer = function () {
return this.canvas;
};
CanvasLayer.prototype.show = function () {
this.initialize();
this.canvas.style.display = 'block';
};
CanvasLayer.prototype.hide = function () {
this.canvas.style.display = 'none';
};
CanvasLayer.prototype.setZIndex = function (zIndex) {
this.canvas.style.zIndex = zIndex;
};
CanvasLayer.prototype.getZIndex = function () {
return this.zIndex;
};
CanvasLayer.prototype.getZIndex = function () {
return this.zIndex;
};
function Marker(opts) {
this.city = opts.name;
this.location = [opts.lnglat[0], opts.lnglat[1]];
this.color = opts.color;
this.type = opts.type || 'circle';
this.speed = opts.speed || 0.15;
this.size = 0;
this.max = opts.max || 20;
}
Marker.prototype.draw = function (context) {
context.save();
context.beginPath();
switch (this.type) {
case 'circle':
this._drawCircle(context);
break;
case 'ellipse':
this._drawEllipse(context);
break;
default:
break;
}
context.closePath();
context.restore();
this.size += this.speed;
if (this.size > this.max) {
this.size = 0;
}
};
Marker.prototype._drawCircle = function (context) {
var pixel = this.pixel||map.getPixelFromCoordinate(this.location);
if(pixel) {
context.strokeStyle = this.color;
context.moveTo(pixel[0] + pixel.size, pixel[1]);
context.arc(pixel[0], pixel[1], this.size, 0, Math.PI * 2);
context.stroke();
}
};
Marker.prototype._drawEllipse = function (context) {
var pixel = this.pixel || map.getPixelFromCoordinate(this.location);
if(pixel) {
var x = pixel[0],
y = pixel[1],
w = this.size,
h = this.size / 2,
kappa = 0.5522848,
// control point offset horizontal
ox = w / 2 * kappa,
// control point offset vertical
oy = h / 2 * kappa,
// x-start
xs = x - w / 2,
// y-start
ys = y - h / 2,
// x-end
xe = x + w / 2,
// y-end
ye = y + h / 2;
context.strokeStyle = this.color;
context.moveTo(xs, y);
context.bezierCurveTo(xs, y - oy, x - ox, ys, x, ys);
context.bezierCurveTo(x + ox, ys, xe, y - oy, xe, y);
context.bezierCurveTo(xe, y + oy, x + ox, ye, x, ye);
context.bezierCurveTo(x - ox, ye, xs, y + oy, xs, y);
context.stroke();
}
};
return CanvasLayer;
})));