方案一的可优化点最明显的就是循环,其两大缺陷都是基于此的。因此方案二的主要思路放弃了clip方法。而是利用了canvas上下文的strokeStyle属性,该属性是指在canvas中绘制矢量图形的时候矢量线的绘制样式,其值可以为color(颜色值)、gradient(渐变对象)、pattern(pattern对象)。这个方案就是将方案一中的drawImg方式改为将canvas上下文的strokeStyle设置为图片,然后在绘制的时候直接画线就可以了,因为矢量线的背景就是需要展示的图片,这样就实现了擦除的效果。HTML结构不变,JS代码如下:
function CanvasDoodle(canvas){
this.canvas=canvas;
this.ctx=canvas.getContext("2d");
this.imgSrc=canvas.getAttribute("imgsrc");
this.width=canvas.width;
this.height=canvas.height;
this.left=parseInt(canvas.style.left);
this.top=parseInt(canvas.style.top);
this.touchX=0;
this.touchY=0;
this.needDraw=false;
this.init();
}
CanvasDoodle.prototype={
init:function(){
var _self=this;
var img=new Image();
img.onload=function(){
var pat=_self.ctx.createPattern(img,"no-repeat");
_self.ctx.strokeStyle=pat;
_self.ctx.lineCap="round";
_self.ctx.lineJoin="round";
_self.ctx.lineWidth="25";
}
img.src=this.imgSrc;
this.canvas.addEventListener('mousedown',function(e){
e.preventDefault();
_self.needDraw=true;
_self.ctx.beginPath();
_self.ctx.moveTo(e.clientX-_self.left,e.clientY-_self.top);
},false);
this.canvas.addEventListener('mousemove',function(e){
e.preventDefault();
if(_self.needDraw){
_self.ctx.lineTo(e.clientX-_self.left,e.clientY-_self.top);
_self.ctx.stroke();
}
},false);
this.canvas.addEventListener('mouseup',function(e){
e.preventDefault();
_self.needDraw=false;
});
}
};
new CanvasDoodle(document.getElementById('CanvasDoodle'));
可以看到,已经没有循环调用了,只是在初始化的时候就设置strokeStyle为图片,在鼠标移动的时候直接lineTo然后stroke就可以了,即简单,又高效,并且即使快速移动鼠标也不会出现锯齿边缘了,因此这个改进的方案完全替代了方案一。效果如下:
新需求,新方案
相信今年年初的雾霾应该是妇孺皆知的了,因为一位前央视记者自费做了一个长期调查然后做了一次演讲,掀起了轩然大波。这个需求正是在这个时期提出的。希望在地图上动态显示雾霾的驱散效果。
先来点简单的
这里我们先分析另外一个略微简单一些的需求,循序渐进。
稍微变一下,是需要展示雾霾扩散效果,这将会是相对来说比较容易实现的,因为雾霾可以理解为均匀的灰色,即使不是均匀,也可以表示为自圆心向边缘不同程度的灰色渐变,上文说到过canvas的strokeStyle可以设置为渐变的,因此正好利用渐变就可以实现边缘的模糊。(并且还可以给canvas设置一些css3的动画,比如从小变大,或者由暗变明)。
HTML结构基本不变,主体JS代码如下: