Openlayers利用原生Canvas繪製閃爍樣式
背景
專案需要地圖上實現不斷報警的閃爍樣式,之前是通過Overlay來處理的,但Overlay遮擋要素,無法很好的觸發事件,所以就轉而使用Canvas原生實現。過程主要參考:openlayers4中閃爍點的實現、canvas-flashMarker-RunJS。
改造
原flashMarker的使用
原本的做法是通過構造新的物件new FlashMarker(map, citys),每次構造新增一個Canvas,沒有辦法清除,那麼我針對這些問題進行適應性的修改。
改造版本的使用
- 通過構造CanvasLayer進行使用,只需使用一個Canvas的可以只new一個物件。
- 得到圖層物件後呼叫addMarkers方法,一批批地將閃爍樣式加入到Canvas裡。
- 清除Canvas呼叫clear方法,直接對圖層進行清空。
不足
經測試,過多的樣式繪製會有卡頓,目前沒有太好的方法解決,不過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;
})));
相關文章
- Canvas繪製星光閃爍的生日祝福Canvas
- HTML5-canvas動畫閃爍分析HTMLCanvas動畫
- 協程實現canvas影像隨機閃爍Canvas隨機
- openlayers通過overlayhtml5css3設定圖示閃爍效果HTMLCSSS3
- canvas 繪製矩形Canvas
- canvas 繪製扇形Canvas
- canvas 繪製文字Canvas
- 小程式利用Canvas繪製圖片和豎排文字Canvas
- HTML5利用canvas繪製矩形程式碼例項HTMLCanvas
- 【Windows 10 IoT - 2】LED閃爍及動畫繪製(樹莓派 Pi2)Windows動畫樹莓派
- canvas 繪製線條Canvas
- canvas 繪製圓形Canvas
- canvas繪製流星效果Canvas
- canvas繪製直線Canvas
- canvas簡單動畫案例(圓圈閃爍漸變動畫)Canvas動畫
- 原生Canvas繪製餅圖,我是不是被騙程式碼了Canvas
- Canvas 繪製雷達圖Canvas
- canvas繪製動畫的技巧Canvas動畫
- canvas 繪製立體圓環Canvas
- canvas 繪製文字詳解Canvas
- canvas 繪製圓角矩形Canvas
- canvas 繪製矩形缺角Canvas
- canvas 繪製雙線技巧Canvas
- canvas繪製風車效果Canvas
- canvas繪製笑臉表情Canvas
- canvas繪製太陽系Canvas
- canvas繪製矩形框Canvas
- Canvas 繪製風向動畫Canvas動畫
- 基於canvas實現波浪式繪製圖片Canvas
- js閃爍效果JS
- canvas 繪製圖案是重疊繪製而不是重置Canvas
- canvas繪製圖案是重疊繪製而不是重置Canvas
- Canvas(3)---繪製餅狀圖Canvas
- canvas系列教程之繪製矩形Canvas
- 用canvas繪製流星夜空Canvas
- 使用canvas繪製圓弧動畫Canvas動畫
- canvas繪製不重合的圓Canvas
- canvas繪製sin正弦曲線Canvas