一. 绘图API总览:

  • strokeStyle
  • fillStyle
  • lineWidth
  • save()
  • restore()
  • beginPath()
  • closePath()
  • stroke()
  • lineTo(x, y)
  • moveTo(x, y)
  • quadraticCurveTo(cpx, cpy, x, y)
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
  • arcTo(x1, y1, x2, y2, radius)
  • arc(x, y, radius, startAngle, endAngle [, anticlockwise])
  • createLinearGradient(x0, y0, x1, y1)
  • createRadialGradient(x0, y0, r0, x1, y1, r1)
  • clearRect(x, y, width, height)
  • fillReact(x, y, width, height)

二. canvas上下文

每个canvas元素都包含一个绘图上下文,可以通过它访问绘图API。

var canvas = document.getElementById("canvas"),
    context = canvas.getContext("2d");

getContext()传入字符串参数”2d”,用于指定将要使用的平面绘图API类型。

getContext()传入字符串参数”3d”,用于指定3D绘图 API,但是目前兼容性极差。

三. 消除图案

在大多数动画中,必须在绘制下一帧图案前清除canvas,通过这样来模拟出物体正在运动的效果。

context.clearRect(x, y, width, height)方法会通过将像素的颜色设置为全透明的黑色擦除指定区域内的每一个像素,从而清除指定的矩形区域。

四. 设置线条的外观

  • strokeStyle:指定线条颜色;
  • lineWidth:线条宽度;
  • lineCap:线条重点的绘制样式。可选值有:butt(默认,延长线)、round(圆的)、square(平的);
  • lineJoin:两条线段的接合方式。可选值有:round、bevel、miter(默认);
  • miterLimit:用于控制两条相交线外侧交点与内侧交点的距离。

五. 使用填充色创建图形

  • context.fillStyle:填充样式。可以填充纯色、渐变色、pattern和图片。
  • context.fill():开始填充。

六. 创建简便填充色

线性渐变context.createLinearGradient(x0, y0, x1, y1):将沿点(x0, y0)与点(x1, y1)之间的直线填充渐变色。

放射性渐变context.createRadialGradient(x0, y0, r0, x1, y1, r1):从指定的空间的中心开始向各个方向扩散,从而创建一个圆形渐变。

6.1 设置渐变点的颜色

可以使用Gradient.addColorStop(ratio, color)方法为渐变色添加渐变点颜色。其中ratio是填充比例,取值范围为[0, 1]。

例如:

var gradient = context.createLinearGradient(0, 0, 100, 100);
gradient.addColorStop(0, "#fff");
gradient.addColorStop(1, "#000");

七. 绘制的样式状态切换

context.save()context.restore()方法可以实现在不同的样式间切换。

context.save()方法将canvas的当前状态存入栈中,其中包含各种样式,例如,strokeStyle、fillStyle以及应用于canvas的变换效果。

context.restore()方法可以使得当前的canvas状态出栈,转而使用下一个状态,即使用之前的状态。

八. 绘制直线

  • context.beginPath():开始绘制新路径;
  • context.moveTo(x0, y0):移动到线条起点;
  • context.lineTo(x1, y1):连线到线条终点;
  • context.stroke():绘制线条。

基于上面的绘图指令,可以创建一个简单的绘图程序,如下:

<canvas id="canvas" width="400" height="400" style="background: #ccc;"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d");

    function onMouseMove(e) {
        var movePosition = {
            x: getMouse(e).x,
            y: getMouse(e).y
        };
        context.lineTo(movePosition.x, movePosition.y);
        context.stroke();
    }

    canvas.addEventListener("mousedown", function(e) {
        var curPosition = {
            x: getMouse(e).x,
            y: getMouse(e).y
        };
        context.beginPath();
        context.moveTo(curPosition.x, curPosition.y);
        console.log("curPosition: " + curPosition.x + "; " + curPosition.y);
        canvas.addEventListener("mousemove", onMouseMove, false);
    }, false);

    canvas.addEventListener("mouseup", function(e) {
        canvas.removeEventListener("mousemove", onMouseMove, false);
    }, false);

    // 获取鼠标的当前位置
    function getMouse(event) {
        var event = event || window.event;
        var mouse = {};
        var x, y;
        if(event.pageX || event.pageY) {
            x = event.pageX;
            y = event.pageY;
        } else if(event.clientX || event.clientY) {
            var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            x = event.clientX + scrollLeft;
            y = event.clientY + scrollTop;
        }
        mouse.x = x;
        mouse.y = y;
        return mouse;
    }
</script>

演示如下:http://codepen.io/dengzhirong/pen/PzgaRk

九. 使用quadraticCurveTo绘制曲线

二次贝塞尔曲线quadraticCurveTo(cpx, cpy, x, y)接收两个点作为参数:第一个点是控制点,用于影响曲线的形状,第二个点是曲线的终点。

quadraticCurveTo()的绘制方法与lineTo()类似,都是以上一次方法调用的重点或上一个context.moveTo()的位置作为起点。两者唯一的区别在于绘制出来线条的形状。

例子:

<canvas id="canvas" width="400" height="400" style="background: #ccc;"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d");

    var x0 = 100,
        y0 = 200,
        x2 = 300,
        y2 = 200;

    canvas.addEventListener("mousemove", function(e) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        var x1 = getMouse(e).x;
            y1 = getMouse(e).y;
        context.beginPath();
        context.moveTo(x0, y0);
        context.quadraticCurveTo(x1, y1, x2, y2);
        context.stroke();
    }, false);

    // 获取鼠标的当前位置
    function getMouse(event) {
        var event = event || window.event;
        var mouse = {};
        var x, y;
        if(event.pageX || event.pageY) {
            x = event.pageX;
            y = event.pageY;
        } else if(event.clientX || event.clientY) {
            var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            x = event.clientX + scrollLeft;
            y = event.clientY + scrollTop;
        }
        mouse.x = x;
        mouse.y = y;
        return mouse;
    }
</script>

演示如下:http://codepen.io/dengzhirong/pen/yJAEEP

9.1 鼠标穿过控制点

如果希望鼠标能穿过控制点,可以用下面的共识计算控制点:(假设:以(x0, y0)作为起点,(x2, y2)作为终点,(x1, y1)作为控制点,(xt, yt)为鼠标所在的点):

x1 = xt * 2 - (x0 + x2) / 2;
y1 = yt * 2 - (y0 + y2) / 2;

可以把上面的程序稍作修改后,使鼠标穿过控制点:

把以下代码:

var x1 = getMouse(e).x;
    y1 = getMouse(e).y;

改为:

var x1 = getMouse(e).x * 2 - (x0 + x2) / 2;
    y1 = getMouse(e).y * 2 - (y0 + y2) / 2;

演示如下:http://codepen.io/dengzhirong/pen/QEPxBg

十. 其他形式的曲线绘制

  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y):增加一个到当前路径的点,并由三次贝塞尔曲线连接两个控制点;
  • arcTo(x1, y1, x2, y2, radius):使用两个控制点和指定半径为连接到前一个点的直线路径添加一个弧度;
  • arc(x, y, radius, startAngle, endAngle [, anticlockwise]):为连接到前一个点的直线路径添加一个弧度,该弧度将以x、y作为圆心,以radius为半径的一个圆的一部分。该弧度的起始角度和终止角度分别由startAngle和endAngle指定。

这些曲线的绘制方法大抵类似。以绘制圆为例子:

context.beginPath();
context.arc(100, 100, 50, 0, (Math.PI * 2), true);
context.closePath();
context.stroke();

十一. 加载并绘制图片

如果希望在动画中绘制一张外部图片,有两种方式可以用于在动画中访问外部图片:

  • 在脚本运行过程中加载一个URL;
  • 使用DOM接口访问一个内嵌在HTML中的图片元素。

当图片加载完成后,再使用绘图API将其渲染到canvas。

11.1 加载图片

为了实现在运行时加载一张图片,可以创建一个Image对象,并将其src属性设置为图片文件的url路径。当图片加载完成后,它就会执行onload方法所关联的回调函数。

如下:

<canvas id="canvas" width="180" height="180" style="background: #ccc;"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d"),
        image = new Image();

    image.src = "http://www.dengzhr.com/wp-content/themes/dengzhr/images/logo.jpg";
    image.onload = function() {
        context.drawImage(image, 0, 0);
    };
</script>

使用context.drawImage()方法将图片绘制到canvas元素上,该方法接受一个图片元素与canvas上的一个x、y坐标。

context.drawImage()方法有以下三种调用方式,分别使用多个参数:

  • drawImage(image, dx, dy):在canvas的(dx, dy)坐标上绘制一张图片。(dx, dy)是图片左上角的位置。
  • drawImage(image, dx, dy, dw, dh):分别根据dw、dh的值设定图片的宽度与高度,并将其绘制在canvas的(dx, dy)坐标。
  • drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh):将图片裁剪到矩形区域(sx, sy, dw, dh)中,并缩放至(dw, dh),再将其绘制到(dy, dy)坐标上。

11.2 使用图片元素

<canvas id="canvas" width="180" height="180" style="background: #ccc;"></canvas>
<img id="img" src="http://www.dengzhr.com/wp-content/themes/dengzhr/images/logo.jpg">
<script type="text/javascript">
    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d"),
        image = document.getElementById("img");

    image.onload = function() {
        context.drawImage(image, 0, 0);
    };
</script>

11.3 使用视频元素

除了可以将一幅静止的图片绘制到canvas以外,canvas还支持逐帧的视频渲染。

由于视频本质上就是按顺序播放的一系列静止的图像,因此canvas元素会在一个动画循环中不断绘制视频中的当前帧。

如下:

<canvas id="canvas" width="300" height="300" style="background: #ccc;"></canvas>
<video id="video" style="display: none; width: 300px; height: 300px;" autoplay>
    <source src="video.mp4" type="video/mp4" />
    <source src="video.webm" type="video/webm" />
    <source src="video.ogv" type="video/ogg" />
</video>
<script type="text/javascript">
    var canvas = document.getElementById("canvas"),
        context = canvas.getContext("2d"),
        video = document.getElementById("video");

        (function drawFrame() {
            window.requestAnimationFrame(drawFrame. canvas);
            context.drawImage(video, 0, 0);
        })();
</script>
本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/js/940