HTML5 Canvas基本绘制线条教程

html-css016

HTML5 Canvas基本绘制线条教程,第1张

HTML5 Canvas基本绘制线条教程

怎么画线条?和现实中画画差不多:

1.移动画笔,使画笔移动至绘画的开始处

2.确定第一笔的停止点

3.规划好之后,选择画笔(包括画笔的粗细和颜色等)

4.确定绘制

因为Canvas是基于状态的绘制(很重要,后面会解释),所以前面几步都是在确定状态,最后一步才会具体绘制。

1.移动画笔(moveTo())

之前我们获得了画笔context,所以以此为例,给出改方法的使用实例——context.moveTo(100,100)。这句代码的意思是移动画笔至(100,100)这个点(单位是px)。记住,这里是以canvas画布的左上角为笛卡尔坐标系的原点,且y轴的正方向向下,x轴的正方向向右。

2.笔画停点(lineTo())

同理,context.lineTo(600,600)。这句的意思是从上一笔的停止点绘制到(600,600)这里。不过要清楚,这里的moveTo()``lineTo()都只是状态而已,是规划,是我准备要画,还没有开始画,只是一个计划而已!

3.选择画笔

这里我们暂且只设置一下画笔的颜色和粗细。

context.lineWidth = 5,这句话的意思是设置画笔(线条)的粗细为10px。

context.strokeStyle = "#AA394C",这句话的意思是设置画笔(线条)的颜色为玫红色。

因为Canvas是基于状态的绘制,所以我们在选择画笔粗细和颜色的同时,其实也是选择了线条的粗细和颜色。

4.确定绘制

确定绘制只有两种方法,fill()和stroke(),有点绘画基础的应该知道,前者是指填充,后者是指描边。因为我们只是绘制线条,所以只要描边就可以了。调用代码context.stroke()即可。

画一个线条

不就一条线段吗!废话了这么多!那我们就开始画吧。

JavaScript Code复制内容到剪贴板你的浏览器居然不支持Canvas?!赶快换一个吧!!

运行结果:

我还标注了一个页面解析图,供大家参考。

这里我将原本

标签中的width和height去掉了,但在JavaScript代码中设置了canvas对象的width和height的属性。

小结:要设置画布的大小,只有这两种方法

1.在标签中设置;

2.在JS代码中设置canvas的'属性.

怎么样,是不是非常的酷。接下来我们要加快脚步了,绘制一个多线条组成的图形。是不是感觉自己离艺术家又进了一步呢?别看这只是简简单单的一条线段,这一画只是我们的一小步,但却是人类的一大步!

绘制折线

上面我们已经成功绘制了一条线段。那么,如果我要绘制有两个笔画甚至是很多笔画的折线怎么办呢?

聪明的小伙伴肯定已经想到了,这还不简单,复用lineTo()就可以了。下面我就献丑随便画了一条优美的折线~

JavaScript Code复制内容到剪贴板你的浏览器居然不支持Canvas?!赶快换一个吧!!

运行结果:

绘制多条折线

那同理,我们要绘制多条样式各不相同的折线怎么办呢?比如我们在这里画三条折线,分别是红色、蓝色、黑色。聪明的小伙伴肯定想到了,这还不简单,只需要平移一下再改下画笔颜色就行了。代码格式都一样的,复制就可以了。代码如下。

JavaScript Code复制内容到剪贴板你的浏览器居然不支持Canvas?!赶快换一个吧!!

运行结果:

咦?是不是很奇怪?说好的先红色,再蓝色,再黑色呢?怎么全是黑色了?其实,这里的原因是我之前一直强调的一点——Canvas是基于状态的绘制。

什么意思呢?其实这段代码每次使用stroke()时,它都会把之前设置的状态再绘制一遍。第一次stroke()时,绘制一条红色的折线;第二次stroke()时,会再重新绘制之前的那条红色的折线,但是这个时候的画笔已经被更换成蓝色的了,所以画出的折线全是蓝色的。换言之,strokeStyle属性被覆盖了。同理,第三次绘制的时候,画笔颜色是最后的黑色,所以会重新绘制三条黑色的折线。所以,这里看到的三条折线,其实绘制了3次,一共绘制了6条折线。

那么,我想绘制三条折线,难道就没有办法了吗?艺术家之魂到此为止了么?没救了么?不,还有办法。

使用beginPath()开始绘制

为了让绘制方法不重复绘制,我们可以在每次绘制之前加上beginPath(),代表下次绘制的起始之处为beginPath()之后的代码。我们在三次绘制之前分别加上context.beginPath()。

JavaScript Code复制内容到剪贴板你的浏览器居然不支持Canvas?!赶快换一个吧!!

可以看到,这里得到了我们预想的结果。因为使用了beginPath(),所以这里的绘制过程如我们所想的那样,只绘制了三次,而且每次只绘制一条折线。beginPath()是绘制设置状态的起始点,它之后代码设置的绘制状态的作用域结束于绘制方法stroke()、fill()或者closePath(),至于closePath()之后会讲到。

所以我们每次开始绘制前都务必要使用beginPath(),为了代码的完整性,建议大家在每次绘制结束后使用closePath()。

代码:

var clock=document.getElementById("clock")

var cxt=clock.getContext("2d")

function drawNow(){

var now=new Date()

var hour=now.getHours()

var min=now.getMinutes()

var sec=now.getSeconds()

hour=hour>12?hour-12:hour

hour=hour+min/60

//表盘(蓝色)

cxt.lineWidth=10

cxt.strokeStyle="blue"

cxt.beginPath()

cxt.arc(250,250,200,0,360,false)

cxt.closePath()

cxt.stroke()

//刻度

//时刻度

for(var i=0i<12i++){

cxt.save()

cxt.lineWidth=7

cxt.strokeStyle="black"

cxt.translate(250,250)

cxt.rotate(i*30*Math.PI/180)//旋转角度 角度*Math.PI/180=弧度

cxt.beginPath()

cxt.moveTo(0,-170)

cxt.lineTo(0,-190)

cxt.closePath()

cxt.stroke()

cxt.restore()

}

//分刻度

for(var i=0i<60i++){

cxt.save()

//设置分刻度的粗细

cxt.lineWidth=5

//重置画布原点

cxt.translate(250,250)

//设置旋转角度

cxt.rotate(i*6*Math.PI/180)

//画分针刻度

cxt.strokeStyle="black"

cxt.beginPath()

cxt.moveTo(0,-180)

cxt.lineTo(0,-190)

cxt.closePath()

cxt.stroke()

cxt.restore()

}

//时针

cxt.save()

// 设置时针风格

cxt.lineWidth=7

cxt.strokeStyle="black"

cxt.translate(250,250)

cxt.rotate(hour*30*Math.PI/180)

cxt.beginPath()

cxt.moveTo(0,-140)

cxt.lineTo(0,10)

cxt.closePath()

cxt.stroke()

cxt.restore()

//分针

cxt.save()

cxt.lineWidth=5

cxt.strokeStyle="black"

//设置异次元空间分针画布的中心

cxt.translate(250,250)

cxt.rotate(min*6*Math.PI/180)

cxt.beginPath()

cxt.moveTo(0,-160)

cxt.lineTo(0,15)

cxt.closePath()

cxt.stroke()

cxt.restore()

//秒针

cxt.save()

//设置秒针的风格

//颜色:红色

cxt.strokeStyle="red"

cxt.lineWidth=3

//重置原点

cxt.translate(250,250)

//设置角度

//cxt.rotate(330*Math.PI/180)

cxt.rotate(sec*6*Math.PI/180)

cxt.beginPath()

cxt.moveTo(0,-170)

cxt.lineTo(0,20)

cxt.closePath()

cxt.stroke()

//画出时针,分针,秒针的交叉点

cxt.beginPath()

cxt.arc(0,0,5,0,360,false)

cxt.closePath()

//设置填充

cxt.fillStyle="gray"

cxt.fill()

//cxt.strokeStyle="red"

cxt.stroke()

//画出秒针的小圆点

cxt.beginPath()

cxt.arc(0,-140,5,0,360,false)

cxt.closePath()

//设置填充

cxt.fillStyle="gray"

cxt.fill()

//cxt.strokeStyle="red"

cxt.stroke()</p>

<p> cxt.restore()</p>

<p>}

function drawClock(){

cxt.clearRect(0,0,500,500)

drawNow()

}

drawNow()

setInterval(drawClock,1000)

步骤 1: 在 HTML 中设置画布,创建一个引用,并获取上下文对象

画布在 HTML 中通过 <canvas>标签定义。与其他标签类似,<canvas>的属性(如宽度和高度)作为特性输入。假设你希望创建一个宽 500 像素、高 500 像素的画布,并将其命名为“can1”,稍后在 JavaScript 中引用它时将用到。

在 HTML 文档中输入 <canvas>标签。

<canvas id="can1" width="500" height="500"></canvas>

在 JavaScript 文档中,创建一个变量,在编写脚本时该变量将代替“can1”。这里,我们将该变量命名为“myCanvas”,并使用 getElementById 将其链接到“can1”。

var myCanvas = document.getElementById("can1")

画布的 CanvasRenderingContext2D 对象具有操作画布的所有命令。 这里,在上下文对象中检索“can1”。将此变量称为“myContext”。

var myContext = myCanvas.getContext("2d")

步骤 2: 绘制矩形、直线、贝塞尔曲线、圆和形状

在画布上绘制简单的线条非常容易。使用 JavaScript 的 moveTo 方法可设置线条开始位置的坐标。然后只需使用另一方法设置终点。 第二步可以使用若干方法,每种方法专用于帮助呈现一种不同的线型,无论是直线、贝塞尔曲线还是圆弧。若要将线条合并为形状,可以闭合对 beginPath 和 closePath 方法调用中的线条。在指定所需的外观之后,可以使用 fill 方法应用颜色,并使用 stroke 方法执行线条和形状的呈现。

应用一些基本风格。这里,通过使用 fillStyle 属性绘制一个黑色矩形,将画布背景设置为黑色 (#000)。然后使用 strokeStyle 属性将线条颜色设置为白色 (#fff),使用 fillRect 方法应用黑色背景,并使用 lineWidth 属性将线条的粗细设置为 3 个像素。

// Specify a black background, and white lines that are 3 pixels thick.

myContext.fillStyle   = '#000'

myContext.strokeStyle = '#fff'

myContext.fillRect(0,0,500,500)

myContext.lineWidth  = 3myContext.fill()

在后续步骤中,将在这个 500×500 的黑色画布上继续构建。

现在,准备在画布的黑色表面绘制一个白色线条。先从直线开始。

使用 moveTo 方法设置直线的起点,使用 lineTo 方法设置终点。

这些方法采用两个数字作为参数。第一个数字表示 x 轴坐标,或者表示此坐标定义的自画布左侧算起的像素数。第二个数字是从顶部开始测量的 y 轴坐标。

// Draw a line that starts at the upper left corner of the canvas and ends at the lower right. 

myContext.moveTo(0,0)

myContext.lineTo(500,500)

myContext.stroke()

若要绘制二次贝塞尔曲线,请使用 quadraticCurveTo 方法,该方法采用两个坐标—曲线的一个控制点和一个端点。

// Draw a swooping curve that spans the width of the canvas.

myContext.moveTo(0,0)

myContext.quadraticCurveTo(0,500,500,250)

myContext.stroke()

若要绘制三次贝塞尔曲线,请使用 bezierCurveTo 方法,该方法采用三个坐标—曲线的两个控制点和一个端点。

// Draw a V-shaped Bezier curve that spans the entire canvas.

myContext.moveTo(0,0)

myContext.bezierCurveTo(500, 820, 0, 500, 500, 0)

myContext.stroke()

若要创建一个圆,请使用 arc 方法:在设置用于绘制圆形轮廓的原点时,请确保将 moveTo 方法设置在沿线条路径的位置上,否则圆上将有一条通向 moveTo坐标的“尾巴”。

// Draw a circle that spans the width of the canvas.

myContext.moveTo(500,250)

myContext.arc(250,250,250,0,Math.PI*2,true)

myContext.stroke()

通过闭合对 beginPath 和 closePath 调用中的多个线条,可以从上述线条的任意组合中绘制一个 2D 形状。然后,整个形状可以使用 fill 接收一种颜色。前面设置的笔划样式将创建白色线条,在与应用于主体的红色 (#f00) 合并时,该形状将继承双色调外观。

//  Draw a red diamond that spans the entire canvas.

myContext.fillStyle = '#f00'

myContext.beginPath()

myContext.moveTo(250,0)

myContext.lineTo(0,250)

myContext.lineTo(250,500)

myContext.lineTo(500,250)

myContext.closePath()

myContext.fill()

步骤 3: 显示位图图像

位图图像(如 .jpg、.png 和 .gif 文件)可以放置在画布上,甚至可以在代码中缩放和裁剪,不会触及原始文件。若要添加位图图像,请指定该图像的 URI,然后使用 drawImage 方法在画布上指定其位置。使用可选参数可将图像缩放到指定的大小,甚至仅显示图像的一个片段,这对于实现滚动背景或使用子画面表动态显示子画面等操作非常有用。

若要在屏幕上绘制位图图像而不进行任何修改,请指定要用于左上角的 x 坐标和 y 坐标。

// Draw an image at the upper left corner of the canvas (0, 0).

var myImg = new Image()

myImg.src = 'myImageFile.png'

myContext.drawImage(myImg, 0, 0)

若要缩放图像,可在末尾添加两个数字,分别代表宽度和高度。如果有帮助,不妨将后两个数字视为“右部”和“底部”,而不是“宽度”和“高度”。

// Scale the image to span the entire 500 x 500 canvas.

var myImg = new Image()

myImg.src = 'myImageFile.png'

myContext.drawImage(myImg, 0, 0, 500, 500)

若要仅使用图像的一个切片,则需要定义两个矩形区域,对 drawImage 的调用提高到 9 个参数(第一个参数是 JavaScript 图像对象)。要传入的前四个数字表示图像的切片。后四个数字表示要显示该切片的画布区域。

// Take a 20 x 20 slice from the upper left of the image and scale it to span the entire 500 x 500 canvas.

var myImg = new Image()

myImg.src = 'myImageFile.png'

myContext.drawImage(myImg, 0, 0, 20, 20, 0, 0, 500, 500)

步骤 4: 渐变

任何人只要熟悉在图形设计程序中定义渐变的常见方式,都会喜欢使用 JavaScript 代码定义渐变的简单性。在设计程序中是选择颜色,渐变中的颜色位置使用水平滑块设置。JavaScript 中的唯一区别是使用从 0 到 1 范围内的小数值代替滑块。

在设计程序中,线性渐变使用线条在图像上定位,线条的开始和结束位置确定方向和缩放级别。在 JavaScript 中,该线条使用两对 x、y 轴坐标绘制。然后将 4 个数字传递到 createLinearGradient 方法以创建 CanvasGradient 对象。在定义渐变对象的属性之后,就会得到所需的渐变,CanvasGradient 作为 fillStyle 传递到 fillRect 方法进行呈现。

// Render a white, red and black gradient diagonally across the canvas.

var myGradient = myContext.createLinearGradient(0,0, 500,500) // gradient starts at upper left and ends at lower right

myGradient.addColorStop(0,"#fff")   // white at the beginning of the gradient

myGradient.addColorStop(0.5,"#f00")// red in the middle of the gradient

myGradient.addColorStop(1,"#000")  // black at the end of the gradient

myContext.fillStyle = myGradient   // ensure the next call to fillRect will use the specified gradient

myContext.fillRect(0,0,500,500)   // rectangle that contains the gradient spans the entire canvas

径向渐变的定义方式稍有不同。为渐变的起点和终点绘制两对 x、y 轴坐标—,这与线性渐变中一样—,但每个坐标对都有第三个与其关联的 z 轴坐标,用于定义半径。可以想像为围绕一个坐标绘制一个圆,该坐标位于中心 (250, 250),绘制的圆的大小以像素为单位定义。这样定义两个圆之后,一个圆较小,一个圆跨整个画布,有 6 个数字传递到 createRadialGradient。在呈现时,径向渐变在两个圆之间的空间中绘制,颜色等级与圆的半径的大小成正比。

// Render a white, red and black radial gradient spanning the canvas.

var myGradient = myContext.createRadialGradient(250,250,0, 250,250,500) // gradient is centered and spans the entire canvas 

myGradient.addColorStop(0,"#fff")   // white at the beginning of the gradient

myGradient.addColorStop(0.5,"#f00")  // red in the middle of the gradient

myGradient.addColorStop(1,"#000")   // black at the end of the gradient

myContext.fillStyle = myGradient    // ensure the next call to fillRect will use the specified gradient

myContext.fillRect(0,0,500,500)    // rectangle that contains the gradient spans the entire canvas

步骤 5: 动画

可以使用多种方法绘制动画。

对于画布内的元素,JavaScript 提供了 setInterval 方法,该方法计划一个重复调用的函数,每经过定义的时间间隔便调用一次该函数。在该函数中,需要重绘画布来反映对其上呈现的对象的更改。下面是一个示例,其中一个函数初始化该动画,将呈现频率计划为大约每秒 60 帧(每 13.33 毫秒一帧),并且重复调用该函数将重绘画布。在本例中,径向渐变从一个小点逐渐增大,直到填充整个画布。

// Generate an animation of a growing gradient.

// These variables must exist globally so both functions can access them.

var myCanvas 

var myContext

var outerBoundary = 0, innerBoundary = 0

// Start the animation.

window.onload = initialize

function initialize() {

    myCanvas = document.getElementById("can1")

    myContext = myCanvas.getContext("2d")

    setInterval("redrawCanvas()",13)    // redraw @ approximately 60 frames per second

}                                        

                                         

// Run the animation.                   

function redrawCanvas() {              

    if (outerBoundary < 500) {            

        outerBoundary++             // grow the size of the gradient

    } else {                             

        innerBoundary++             // grow the size of the inner white circle if red is maxed

    }                                    

    var myGradient = myContext.createRadialGradient(250,250,innerBoundary, 250,250,outerBoundary)

    myGradient.addColorStop(0,"#fff")   // white at the beginning of the gradient

    myGradient.addColorStop(0.5,"#f00") // red in the middle of the gradient

    myGradient.addColorStop(1,"#000")   // black at the end of the gradient

    myContext.fillStyle = myGradient    // ensure the next call to fillRect will use the specified gradient

    myContext.fillRect(0,0,500,500)     // rectangle that contains the gradient spans the entire canvas

}

CSS3 转换和动画可用于转换画布本身和画布外部的对象。

此外,新的 WinJS 库有许多高度优化的动画,创建这些动画是为了模拟原有 Windows 动画的行为。 WinJS 动画有助于为你的应用 UI 提供一个高度集成的外观。有关详细信息,请参阅WinJS.UI.Animation 命名空间。

步骤 6: 更多 HTML5 画布提示

可以使用一系列属性(shadowColor、shadowBlur、shadowOffsetX 和 shadowOffsetY)应用阴影。

可以使用 createPattern 方法作为一种模式重复画布中的元素。

可以使用 save 方法保存画布状态,然后执行更改,再使用 restore 方法还原以前的状态。该方法很好用,函数甚至不需要采用参数。

可以使用 globalCompositeOperation 属性定义两个画布元素重叠时会发生什么情况。 使用此属性始终可以定义在源或新元素级别发生的情况。可以执行的操作有颜色混合、遮蔽和更改重叠优先级等。

注意  globalCompositeOperation 主题使用源表示新元素,使用目标表示以前存在的元素。

可以使用 strokeText 方法将文本添加到画布。