写一个字
demo 地址
根据速度设置线条粗细
代码
1 | var lastLineWidth = -1; |
刚开始画图宽度取值
参见上面代码的lastLineWidth == -1
情况。
2/3与1/3的平滑过渡技巧
参考上面代码,其实也不一定要设置成1/3 2/3,也可以是其他值,可以自己试验,只要壁画看起来平滑过渡即可。
笔画的主体方法
从onmousedown开始
1 | function beginStroke(point){ |
只在isMouseDown true时才画图
onmousedown时设置isMouseDown为true,在鼠标松开(onmouseup)、鼠标离开dom时(onmouseout)设置isMouseDown为false,
onmousemove时不设置 值,此事件只负责画图。
在onmousemove事件中画图
所以的绘制方法都在此事件中写:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33canvas.onmousemove = function(e){
e.preventDefault()
if( isMouseDown ){
moveStroke({x: e.clientX , y: e.clientY})
}
};
function moveStroke(point){
//获取当前坐标
var curLoc = windowToCanvas( point.x , point.y );
var curTimestamp = new Date().getTime();
var s = calcDistance( curLoc , lastLoc )
var t = curTimestamp - lastTimestamp
var lineWidth = calcLineWidth( t , s );
//draw
context.beginPath();
context.moveTo( lastLoc.x , lastLoc.y );
context.lineTo( curLoc.x , curLoc.y );
context.strokeStyle = strokeColor
context.lineWidth = lineWidth
// lineCap lineJoin 让线条更加平滑
context.lineCap = "round"
context.lineJoin = "round"
context.stroke()
//重置上一次的状态
lastLoc = curLoc
lastTimestamp = curTimestamp
lastLineWidth = lineWidth
}
onmousedown、onmousemove之间计算距离
如上面《画图方法》代码,笔画的移动就是通过计算二者之间的位置算出来的距离。
onmousemove、onmousemove 之间计算距离
如上面《画图方法》代码中的下面内容说明了这一点:1
2
3
4//重置上一次的状态
lastLoc = curLoc
lastTimestamp = curTimestamp
lastLineWidth = lineWidth
lineCap lineJoin 让线条更加平滑
在没有加下面时,效果图如下:1
2context.lineCap = "round"
context.lineJoin = "round"

为什么会这样?我们画的线其实是有很多段矩形拼接而成,如此啊,在拼接处就会有缝隙,此时可以使用线段的帽子lineCap,再加一个lineJoin,双保险,平滑过渡:
图像处理-缩放图片
放大或缩小的显示
放大的时候,我们希望图像显示的中心点与原来图片中心点是重合的,为了保证中心点不动,就必须找准截取图片的坐标点,计算方法如下:
思路一(常规思路:误区)
常规的思想是从原来图片选择一个点,然后截取一个区域,放到画布上,进行显示,如下,下面的计算方式无法达到自动缩放要求。
这种思路也可以达到缩放,但是需要大量的计算,非常麻烦。1
2
3
4
5
6var imageWidth = 1152 * scale
var imageHeight = 768 * scale
var sx = imageWidth / 2 - canvas.width / 2
var sy = imageHeight / 2 - canvas.height / 2
context.drawImage( image , sx , sy , canvas.width , canvas.height
, 0 , 0 , canvas.width , canvas.height )
思路二(推荐)
参考《经典的缩放处理方案》
经典的缩放处理算法
概述
缩放时必须保证 中心点不动。
放大的时候,x为负数,达到放大效果,缩小时,x为正值,达到缩小效果,完美兼容放大和缩小两种情况。1
2
3
4
5
6
7
8var imageWidth = 1152 * scale
var imageHeight = 768 * scale
x = canvas.width /2 - imageWidth / 2
y = canvas.height / 2 - imageHeight / 2
context.clearRect( 0 , 0 , canvas.width , canvas.height )
context.drawImage( image , x , y , imageWidth , imageHeight )
保证中心点不动
参考上面
选取坐标点技巧
参考上面
放大或缩放处理图片
参考上面,为了缩放显示图片,在drawImage的最后两个参数时,都进行放大或缩放处理。
onmousemove 代替 onchange
为了达到鼠标移动时就触发绘图,需要使用onmousemove,因为onchange只有在停止滑动时才触发事件。1
2
3
4
5
6
7
8
9// slider.onchange = function(){
// scale = slider.value
// drawImage( image , scale )
// }
slider.onmousemove = function(){
scale = slider.value
drawImageByScale( scale )
}
离屏canvas技术
水印demo
介绍
定义一个水印的canvas,display 设置为不可见,让后将此canvas作为 drawImage 的第一个参数,绘制到画布当中。
因为水印的canvas本身不被显示,而只将其投影显示到画布当中,因此称之为离屏canvas。
1 | <!-- 原来的canvas将会被cody到上一个图片画布中作为水印展示,不需要展示原来的canvas,因此隐藏原有的canvas --> |
1 | //setup watermark canvas |
将canvas作为drawImage参数
利用了drawImage 可以将图片和canvas作为参数进行处理。
放大镜
原理
只使用一张高清图片。
离屏canvas绘制原尺寸图片,并且display none。
原屏canvas绘制缩放后图片,
计算离屏与缩放后图片的 倍率,以此作为缩放参数。
原屏绘制好后就不动它了,
每次放大镜时,都使用clip剪切区显示离屏投射。
可以参考上面代码。
代码 和 demo地址
demo地址1
2
3
4
5<canvas id="canvas" style="display:block;margin:0 auto;border:1px solid #aaa;">
您的浏览器尚不支持canvas
</canvas>
<canvas id="offCanvas" style="display: none">
1 | var canvas = document.getElementById("canvas") |
计算离屏信息
这里需要计算离屏canvas的这些信息(sx , sy , 2mr , 2mr),原理见下图:1
context.drawImage( offCanvas , sx , sy , 2*mr , 2*mr , dx , dy , 2*mr , 2*mr )

计算原屏信息
这里需要计算离屏canvas的这些信息(dx , dy , 2mr , 2mr),原理见下图:1
context.drawImage( offCanvas , sx , sy , 2*mr , 2*mr , dx , dy , 2*mr , 2*mr )

使用剪切 clip 来做放大镜
见上面代码。
为什么clip不隐藏原屏图片
刚开始以为clip可能会隐藏原屏图片,结果没有,究其原因,估计是原屏图片是在clip之前就绘制好了,所以不受影响,后期绘制的离屏投射就受影响了