动画

过去想要实现动画都是使用定时器,但是定时器的精度不高,可能导致动画播放不平滑。为了使计时精确,便是用requestAnimationFrame(func).并且这个函数还可以有一个参数,它的类型是DOMHighResTimeStamp,表示开始执行回调函数的时刻。

没执行一次requestAnimationFrame(func),他就会执行一次回调函数。但是这并不是一定的,如果调用太快他会自动进行合并。可以认为有一个任务队列,调用这个函数将它插入这个队列中,但是如果队列中有这个函数就不会插入。

function updateProgress(time)
{
var div = document.getElementById("status");
div.style.width = (parseInt(div.style.width, 10) + 5) + "%";
if(div.style.left != "100%")
{
requestAnimationFrame(updateProgress);
}
}
requestAnimationFrame(updateProgress);
  • window.cancelAnimationFrame(ID): 前面一个函数的返回值是一个ID,

canvas

<canvas>元素创建一个画布。创建它时至少要提供width和height属性,否则不会显示。开始标签和结束标签中的内容是不支持<canvas>时提示的内容。

<canvas id="drawing" width="200" height="200">A drawing of something</canvas>

想要在canvas上进行绘图,首先要获得绘图上下文,使用getContext("2d")可以获得2D图形绘图对象。

let drawing = document.getElementById("drawing");
if(drawing.getContext)//测试是否存在getContext函数
{
let context = drawing.getContext("2d");
}

可以使用toDateURL(type)获得<canvas>上的图像,参数为图片的类型。

let drawing = document.getElementById("image/png");
if(drawing.getContext)
{
let imgURI = drawing.toDataURL("image/png");
let image = document.createElement("img");
imge.src = imgURI;
document.body.appendChild(image);
}

2D绘图

属性:

  • width:
  • height: 画布的长宽,默认是在画布的左上角,其他的坐标值都根据该点计算
  • fillStyle: 填充样式,gradient是渐变
  • strokeStyle: 边框样式
  • context.font: 以css语法决定的字体样式,例如10px Arial
  • textAlign: 对齐方式,可以为start、end、left、right、center。推荐使用start和end,不使用left和right
  • textBaseLine: 指定文本的基线,可以为top、bottom、hanging、middle、alphabetic、ideographic。top表示y坐标在文本顶部,bottom表示y坐标在文本底部
  • shadowColor: css颜色值
  • shadowOffsetX: 阴影相对于路径的x坐标偏移量,默认是0
  • shodowOffsetY:
  • showdowBlur: 阴影的模糊量
  • globalAlpha: 透明度
  • globalCompositionOperation: 图像合成模式

绘制矩形

  • fillRect(x, y, w, h): 填充矩形,填充的样式由fillStyle决定
  • strokeRect(x, y, w, h):
  • clearRect(x, y, w, h):

例如:

let drawing = document.getElementById("drawing");
if(drawing.getContext)
{
let context = drawing.getContext("2d");
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);

context.fillStyle = "rgba(0, 0, 255, 0.5)";
context.fillRect(30, 30, 50, 50);
}

绘制路径

路径由多个点组成,可以闭合也可以不闭合,可以利用它绘制各种复杂的图形。

首先调用context.beginPath()表示开始绘制,然后再调用下列方法进行绘制(只是描点,并没有真正开始绘制,还需要运行绘制完成操作才可以进行绘制)

  • arc(x, y, radius, startAngle, endAngle, counterclockwise): 以(x, y)为中心,radius为半径绘制一条弧形。counterclockwise表示是否逆时针开始(默认是顺时针)
  • arcTo(x1, y1, x2, y2, radius): 从(x1, y1)到(x2, y2)绘制一条半径为raidus的弧
  • bezierCurveTo(c1x, c1y, c2x,c2y, x, y): 绘制一条以(c1x, c1y)和(c2x, c2y)为控制点,从上一点到(x, y)的弧线(三次贝塞尔曲线)
    let drawing = document.getElementById("drawing_canvas");
    if (drawing.getContext)
    {
    let ctx = drawing.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(20, 20);
    ctx.bezierCurveTo(20, 100, 200, 100, 200, 20);
    ctx.stroke();
    }
    结果为
  • lineTo(x, y): 从上一点到(x, y)绘制直线
  • moveTo(x, y): 画笔移动到(x, y)
  • quadraticCurveTo(cx, cy, x, y): 以(cx, cy)为控制点,绘制一条虫上一点到(x, y)的弧线(二次贝塞尔曲线)
  • rect(x, y, width, height):
  • isPointInPath(x, y): 检测点是否在路径中

绘制完成之后的操作函数

  • closePath(): 绘制前面所有的线和一条道起点的线
  • fill(): 填充路径
  • stroke(): 绘制路径,使用这个函数才会真正在画面上有显示
  • clip(): 创建一个剪切区域

绘制文本

  • fillText(str, x, y, maxpexel): 以(x, y)为基准点开始绘制str,最大像素为maxpexel。他会使用fillstyle属性
  • strokeText(str, x, y, maxpexel): 参数含义和上面相同
  • measureText(): 获得一个文本属性对象,目前这个对象只有width一个属性

例如:

context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseLine = "middle";
context.fillText("12", 100, 20);

//使用measureText限制最大宽度
let fontSize = 100;
context.font = fontSize + "px Arial";
while(context.measureText("hello world").width > 140)
{
fontSize--;
context.font = fontSize + "px Arial";
}
context.fillText("hello world", 10, 10);

变换

可以对图像进行缩放,平移,旋转等操作

  • rotate(angle): 以原点为中心旋转angle角度
  • scale(scalex, scaley): 进行缩放,x乘以scalex,y乘以scaley
    let drawing = document.getElementById("drawing_canvas");
    if (drawing.getContext)
    {
    let ctx = drawing.getContext("2d");
    ctx.beginPath();
    ctx.scale(1, 0.5);
    ctx.strokeRect(0, 0, 100, 100);//一个正方形
    ctx.stroke();
    }
  • translate(x, y): 把坐标原点移动到(x, y)主要是为了配合rotate使用
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy): 综合缩放旋转和移动,具体可看

渐变

  • createLinearGradient(x1, y1, x2, y2): 创建从(x1, y1)到(x2, y2)的渐变对象
  • createRadialGradient(x, y, radius, dstx, dsty, dstr): 放射性渐变,六个参数控制两个圆,第一个是内部圆,第二个是外部圆。

获得渐变对象之后,可以使用addColorStop()方法创建色标.并且这个对象可以赋值给fillStyle和strokeStyle

  • gradient.addColorStop(loc, color): loc是0-1范围的值,color是颜色

例如:

let drawing = document.getElementById("drawing_canvas");
if (drawing.getContext)
{
let ctx = drawing.getContext("2d");
let gradient = ctx.createLinearGradient(30, 30, 70, 70);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
ctx.fillStyle = gradient;
ctx.fillRect(50, 50, 50, 50);
}


正常情况下应该一半黑一半白,但是这里几乎都是黑色,因为渐变的范围是(30, 30)到(70, 70),到了矩形部分已经快渐变完了,因此显示都是黑色。因此为了显示比较好的渐变要渐变范围和图形范围相适应。

图像处理

  • drawImage(image, x, y, w, h, dstx, dsty, dstw, dsth): x,y,w,h是原图像的截取区域,dstx…是绘图区域中的一部分。
  • createPattern(img, repeat): 第一个参数时一个<img>元素,第二个参数是重复方式,有repeat、repeat-x、repeat-y和no-repeat
let image = document.images[0];
pattern = context.createPattern(image, "repeat");
context.filstyle = pattern;
context.fillRect(10, 10, 150, 150);//会在这个范围内重复显示图像
  • getImageData(x, y, w, h): 获得区域内的图像数据,返回的对象中有width、height、data三个属性。
  • putImageData(data, x, y): 将imageData对象放到(x, y)起点处

data属性表示像素,它是一个一维数组,前四个表示第一个像素的r,g,b,a。

let data = imageData.data;
let red = data[0];
let green = datat[1];
let blue = data[2];
let alpha = data[3];
let red2 = data[4];

globalCompositionOperation是多个形状之间如何融合。各属性具体讲解