本篇文章作为初学者角度编写
连接:码云开源地址:http://exeup.gitee.io/watercolor-online/
相信画板这类应用大家都不陌生,
感觉接触计算机不多久就接触到了画板,带给我们很多方便,也用于在教学,办公中提升效率.
前段时间自己做了这样的一个画板,主体部分由两层绝对定位100%宽高的canvas组成;然后由一个绝对定位z轴更加靠上的DIV作为工具栏;
首先介绍一下两层canvas,之所以使用两层,就是因为有一层是在鼠标移动但并不是拖动的时候,将落笔点呈现在用户面前,这一层是在不断的擦除的;而底层则是在出现绘画动作的时候,将 绘画内容记录在底层画板上的.
首先,canvas本身就是一个画板,所以这些实现起来难点只在于拖动;(于初学者而言);
浏览器准备了一个拖动事件(ondragover)但并不好用(我是这么觉得);那么我们尝试将多个事件组合在一起,拼凑成拖动事件;
(初学者容易产生困惑的地方)一张图片在浏览器中被拖动应该是会出现拖拽复制的情况,(大多数浏览器确实如此),导致这种情况出现的原因是IMG对象默认可以触发的拖动事件;所以只需要重写这些事件就可以,并且拖动事件的触发是按下鼠标左键,那么我们重写鼠标左键onclick事件就会导致这张图片不会被拖动.
那么我们需要一个拖动事件,事实上我们处理的是左键按下,鼠标滑动,左键抬起,三个事件,说起来也简单,原本在较上层canvas中就有一个鼠标拖动时擦除并绘制一个笔触的事件,只需要在按下左键时绑定新的事件即可,
同样的我们需要调色板可以被拖动以及调色板上的调色条也是可以使用同样的道理实现的;此处以拖动调色板的源代码作为示例(原因是短小精悍通俗易懂)
function pango(e){//移动调色板
var x = e.clientX;
var y = e.clientY;
panel.style.top = (y-5)+"px";
panel.style.left = (x-50)+"px";
}
function panto(){//按下鼠标左键时,触发这个函数为事件绑定一个方法
window.οnmοusemοve=function(){
pango(event);
}
}
function panup(){
//抬起鼠标解绑
window.οnmοusemοve=function(){
}
}
在这里绑定事件的时候并不是绑定到调色板这个DIV对象上的,特别是调色板内的调色滑动条,更是不要绑定在自己身上,因为滑动条过小,很容易就出了范围了,而window这个对象在这里就扮演了一个很重要的可以全屏捕获鼠标位置的好方法,(注:在canvas上时应绑定在上层画板上,尽管绘制的是底层画板,)
再添加一段关于滑动条的代码,也就是如何处理在一个可变的DIV中对一个子元素应该处于那个位置的定位;(我的语文好差)
function blueto(){
window.οnmοusemοve=function(){
bluego();
}
}
function bluego(){//蓝色块位移
var x = event.clientX;
var ox = x-sa.offsetLeft-panel.offsetLeft;
if(ox>=0&&ox<=127.5){
bluebut.style.marginLeft = ox+"px";
intblue = ox*2;
ToUpdate();
}
}
同样的,这里的事件依然会被绑定到window上 ,这里的难点在于ox 即滑块左边大小的控制,这里使用的(sa)对象是滑块的背景(即那个灰色的滑槽),使用这个对象的offsetLeft值减去面板的offsetLeft之后在被当前鼠标位置减去就是滑块本身对应于滑槽的坐标了.
在此时改变定义于全局参数的蓝色值(我使用的是RGBA算法所以滑槽是127.5PX,*2以后直接作为蓝色值使用,其他颜色值/size/透明度等原理都相同);
然后展现一下核心代码(哈哈 其实真正绘制的只有几句话而已)
function myonclick(){//这个是鼠标按下时触发的函数 ifclick = true ; canvalu.strokeStyle = "rgba("+intred+","+intgreen+","+intblue+","+transparent+")";//设置线的颜色 canvalu.lineWidth=osize;//设置线的粗细 var x = event.clientX/$(window).width()*cantotest.width; var y = event.clientY/$(window).height()*cantotest.height; canvalu.moveTo(x,y);//这句话是鼠标按下时的点作为起点. cantotest.οnmοusemοve=function(){//为鼠标在上层canvas上拖动创建的绑定事件 otesto(event);//这个当然就是绘制了,这个函数将在后面列出,功能是计算x,y的值并传给canvasto otest(event);//这个函数是在上层canvas中预览操作; } }
unction canvasto(x,y){//绘制 if(isover==false){//鼠标移动的时候触发的事件算出鼠标的位置x,y, canvalu.lineTo(x,y);//其实在移动的时候 只需要创建线段的点就可以了 }else{//这一句是我的橡皮擦. canvalu.clearRect((x-(oversize/2)),(y-(oversize/2)),oversize,oversize); } }
function otesto(e){//这里是绘制事直接调用的方法,用来计算x.yfunction up(){//这个自然就是绘制过程结束/抬笔的动作了; ifclick = false; if(ifGrap){ canvalu.closePath(); canvalu.fill(); } canvalu.stroke(); canvalu.beginPath();//至此就把这条线画出来了; canvalu.lineWidth=0; cantotest.οnmοusemοve=function(){//绑定事件更新/此时就不再绘制了而是只触发预览的方法 otest(event); } }
var x = e.clientX/$(window).width()*cantotest.width;//由于canvas的像素值改变时内容会被清空;因此为了保持绘画过程足够流畅,采用这种算法计算出落笔点;
var y = e.clientY/$(window).height()*cantotest.height;
canvasto(x,y);
}这样画的线条不是很规整,咱们让canvas使用圆滑处理:canvalu.lineCap="round"当然也可以使用方形,这只需要将值设定为"square"就可以了;这样大体上一个canvas画板就出来了;忍不住要画两笔了 哈哈,尽管手残,还是将"大作"展示给大家!
哈哈 忍不住画两笔!