canvas

Posted Ling201509

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了canvas相关的知识,希望对你有一定的参考价值。

canvas

canvas只能在标签中定义宽高

canvas跟其它标签一样,也可以定义样式,但需要注意的是:canvas的默认宽高为300px* 150px,在css中为canvas定义宽高,实际上定义的是canvas的显示的大小,但针对canvas来说还包括里面的绘制的图像的分辨率的大小。所以在css中定义高宽canvas中绘制的图形可能会变形。因此,我们可以使用以下方式指定大小:

// 在标签中指定
<canvas class="mycanvas" width="500" height="500">土鳖!你的浏览器out啦!</canvas> 
// -->标签中的内容是当浏览器不支持canvas时的后备信息。

// 在js中通过画布对象属性的方式指定
var drawing = document.querySelector(‘.mycanvas‘);
drawing.width = 500;
drawing.height = 500;

canvas对象的属性和方法:

  • width;
  • height;
  • getContext(); 获取canvas对象

canvas中的绘图是一种基于状态的绘图,也就是说我们需要先设置绘图的状态,在调用函数做一个具体的绘制。

一、基本用法

要在画布上绘图,首先要先获取绘图上下文,取得绘图上下文对象的引用。调用getContext()方法,传入上下文的名字。如下:

    var drawing = document.querySelector(‘.mycanvas‘);

    // 检测浏览器是否支持<canvas>
    if(drawing.getContext) {        
        var context = drawing.getContext(‘2d‘); //获取绘图上下文
    }


    if(drawing.getContext(‘2d‘)) {} // 不能这样写,这样写不支持canvas的浏览器会报错!!!

检测getContext()方法是否存在这一步很有必要。因为有些浏览器会为HTML规范之外的元素创建默认的HTML元素对象,并且可以引用它,但这个对象并没有getContext()方法

使用toDataURL()方法,可以导出在< canvas >元素上绘制的图像。这个参数接受一个参数,即图像的MIME类型格式,而且适合用于创建图像的任何上下文。默认情况下,浏览器会将图像编码为 PNG 格式(除非另行指定)。Firefox 和 Opera 也支持基于”image/jpeg” 参数的 JPEG 编码格式。

var drawing = document.querySelector(‘.mycanvas‘);

if(drawing.getContext) {
    // 获取图像的数据URL
    var imgURL = drawing.toDataURL(‘image/png‘);

    // 显示图像
    var image = document.createElement(‘img‘);
    image.src = imgURL;
    document.body.appendChild(image);
}

如果绘制到画布上的图像源自不同的域, toDataURL() 方法会抛出错误。

二、2D上下文

1、填充和描边

  • fillStyle属性;填充
  • strokeStyle属性;描边 属性值可以使字符串、渐变对象或模式对象。

2、绘制矩形

矩形是唯一一种可以直接在2D上下文中绘制的形状。

  • fillRect(x, y, width, height); 绘制填充指定颜色的矩形,填充颜色通过fillStyle属性指定。
  • strokeRect(x, y, width, height); 绘制指定颜色的描边矩形,描边颜色通过strokeStyle属性指定。

    • lineWidth属性; 线条宽度,值可以是任何整数。
    • lineCap属性; 控制线条末端的形状,值可以是:平头(’butt’)、圆头(’round’)、方头(’square’)。
    • lineJoin属性; 控制线条相交的方式,值可以是:圆交(’round’)、斜交(’bevel’)、斜接(’miter’)。
  • clearRect(x, y, width, height); 清除画布上的指定区域。

参数单位都是像素。

var drawing = document.querySelector(‘#mycanvas‘);
if(drawing.getContext) {
    var context = drawing.getContext(‘2d‘);

    context.fillStyle = ‘red‘;
    context.fillRect(10, 10, 100,100);

    context.strokeStyle = ‘green‘;
    context.strokeRect(60, 60, 100, 100);

    context.clearRect(70, 70, 30, 30);
}

3、绘制路径

创建路径:
- beginPath(); 开辟新的路径
- closePath(); 闭合路径

  • moveTo(x, y);
  • lineTo(x, y); 从上一点开始绘制一条直线,直到(x, y)为止。

  • rect(x, y, width, height); 绘制矩形路径

  • arc(x, y, radius, startAngle, endAngle, counterclockwise); 绘制弧线。 (圆心x, 圆心y, 半径, 开始角度, 结束角度, 是否按逆时针方向计算)

  • arcTo(x1, y1, x2, y2, radius); 绘制弧线
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y); 贝塞尔曲线。从上一点开始绘制一条曲线,到(x, y)为止,并且以(c1x, c1y)和(c2x, c2y)为控制点。
  • quadraticCurveTo(cx, cy, x, y); 从上一点开始绘制一条二次曲线,到(x, y)为止,并且以(cx, cy)作为控制点。

绘制图形:

  • fill(); 填充路径
  • stroke(); 描边路径
  • clip(); 创建一个剪切区域

  • isPointInPath(x, y);用于在路径被关闭之前确定画布上的某一点是否位于路径上

4、绘制文本

  • fillText(str, x, y, maxWidth); 绘制填充文本
  • strokeText(str, x, y, maxWidth); 绘制描边文本

  • font; 文本样式、大小及字体

  • textAlign; 文本对齐方式:
    • start 默认。文本在指定的位置开始。
    • end 文本在指定的位置结束。
    • center 文本的中心被放置在指定的位置。
    • left 文本左对齐。
    • right 文本右对齐。
  • textBaseline; 文本的基线:
    • alphabetic 默认。文本基线是普通的字母基线。
    • top 文本基线是 em 方框的顶端。
    • hanging 文本基线是悬挂基线。
    • middle 文本基线是 em 方框的正中。
    • ideographic 文本基线是表意基线。
    • bottom 文本基线是 em 方框的底端。

计算文本大小:

由于绘制文本比较复杂,特别是需要把文本控制在某一区域中的时候,2D上下文提供了辅助确定文本大小的方法measureText(str); 返回TextMetrice对象。返回的对象目前只有一个width属性,但将来还会增加更多度量属性。

var fontSize = 100;
context.font = fontSize + ‘px Arial‘;

while(context.measureText(‘Hello world!‘).width > 140) {
    fontSize--;
    context.font = fontSize + ‘px Arial‘;
} 
context.fillText(‘Hello world!‘, 100, 100);
context.fillText(‘Font size is ‘ + fontSize + ‘px‘, 100, 120);

fillText()和strokeText()方法都可以接受第四个参数(maxWidth),也就是文本的最大像素宽度。提供的这个参数后,如果传入的字符串大于最大宽度,则绘制的文本字符的高度正确,但宽度会收缩以适应最大宽度。不过,这个可选的参数尚未得到所有浏览器支持。

5、变换

为绘制上下文应用变换,会导致使用不同的变换矩阵应用处理,从而产生不同的结果。

  • rotate(angle); 围绕原点旋转。
  • scale(scaleX, scaleY); 缩放图像,在x方向乘以scaleX,在y方向乘以scaleY。scaleX和scaleY的默认值都是1.0。
  • translate(x, y); 重置原点。
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy); 修改变换矩阵。
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy); 将变换矩阵重置为默认状态,然后在调用transform()。

  • save(); 保存当前上下文状态。 注意:save()方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

  • restore(); 返回上一级保存的上下文状态。

6、绘制图像

  • drawImage();

根据期望的最终结果不同,调用这个方法时,可以使用三种不同的参数组合。

1、传入一个html< img >元素,以及绘制该图像的起点(x,y坐标)。如下:

// 取得图像
var img = document.images[0];
// 将图像绘制到上下文中
context.drawImage(img, 100, 100);

绘制到画布上的图像与原始大小一样。

2、绘制指定大小的图像。如果想要改变绘制后的图像的大小,可以再多穿如两个参数,分别表示目标宽度和目标高度。通过这种方式来缩放图像并不影响上下文的变换矩阵。如下:

var img = document.images[0];
context.drawImage(img, 100, 100, 30, 30); // 绘制大小为30*30的图像

3、将图像中的某个区域绘制到上下文中。
drawImage()方法的这种调用方式总共需要出入9个参数:
(img, 源图像x, 源图像y, 源图像width, 源图像height, 目标图像x, 目标图像y, 目标图像width, 目标图像height)。

context.drawImage(img, 500, 0, 500, 500, 0, 0, 500, 500);

原始图像的起点为(500, 0),宽和高都是500px。最终绘制到上下文中的图像的起点是(0, 0),而大小变成了500*500px

除了给drawImage()方法传入HTML< img >元素外,还可以传入另一个< canvas >元素作为其第一个参数。这样就可以把另一个画布内容会知道当前画布上。

结合使用drawImage()和其他方法,可以对图像进行各种基本操作。操作结果可以通过toDataURL()方法获得。不过,图像不能来自其他域。如果图像来自其他域,调用toDataURL()会抛出一个错误。例如,位于www.aaa.com上的页面绘制的图像来自于www,bbb,com,当前上下文就会被认为’不干净’,因而会抛出错误。[注意:toDataURL()是< canvas >对象的方法,而不是上下文对象的方法。]

7、阴影

  • shadowColor; 阴影颜色
  • shadowOffsetX; 形状或路径x轴偏移量
  • shadowOffsetY; y轴偏移量
  • shadowBlur; 模糊像素。默认0,即不模糊。

这些属性都可以通过context对象修改。只要在绘制之前为它们设置适当的值,就能自动产生阴影。

不同浏览器对阴影的支持有一些差异。

8、渐变

  • createLinearGradient(起点x, 起点y, 终点x, 终点y);创建线性渐变。【基于起点的x, y坐标以及宽度和高度值创建渐变对象。】
  • createRadialGradient(x1, y1, radius1, x2, y2, radius2);6个参数,分别对应着两个圆的圆心和半径。
  • addColorStop(色标位置, CSS颜色值);

渐变有CanvasGradient实例演示,创建一个新的线性渐变,可以调用createLinearGradient()方法。 调用这个方法后,它就会创建一个指定大小的渐变,并返回CanvasGradient对象的实例。创建渐变对象后,下一步就是使用addColorStop()方法来指定色标【色标位置是一个0(开始的颜色)到1(结束的颜色)之间的位数字】。然后把fillStyle或strokeStyle设置为这个对象,从而使用渐变来绘制或描边。

// 1、创建渐变对象
var gradient = context.createLinearGradient(110, 110, 310, 310);

// 2、指定色标
gradient.addColorStop(0, ‘red‘);
gradient.addColorStop(0.5, ‘yellow‘);
gradient.addColorStop(1, ‘blue‘);

// 3、将渐变对象赋给fillStyle或strokeStyle
context.fillStyle = gradient;
context.fillRect(110, 110, 200, 200);

createLinearGradient()基于起点的x, y坐标以及宽度和高度值创建渐变对象,因此我们可以在fillRect()中使用相同的坐标(起点x, 起点y)。如下:

function createLinearGradient(context, x, y, width, height) {
    return context.createLinearGradient(x, y, x + width, y + height);
}

var gradient = createLinearGradient(context, 110, 110, 200, 200);
gradient.addColorStop(0, ‘red‘);
gradient.addColorStop(0.5, ‘yellow‘);
gradient.addColorStop(1, ‘blue‘);


context.fillStyle = gradient;
context.fillRect(110, 110, 200, 200);

径向渐变: 可以把径向渐变想象成一个长圆桶,而createRadialGradient()方法的这6个参数定义的就是这个桶的原型开口的位置。

9、模式

模式其实就是重复的图像,可以用来填充或描边图形。
- createPattern(img, str)方法。接收2个参数:一个HTML< img >元素和一个表示如何重复图像的字符串(与CSS的background-repeat属性值相同)。

var img = document.images[0];
pattern = context.createPattern(img, ‘repeat‘);

// context.fillStyle = pattern;
// context.fillRect(100, 100, 300, 300);

context.strokeStyle = pattern;
context.lineWidth = 20;
context.strokeRect(100, 100, 300, 300);

模式与渐变一样,都是从画布的原点(0, 0)开始的。将填充样式(fillStyle)设置为模式对象,只表示在某个特性的区域显示重复的图像,而不是要从某个位置开始绘制重复的图像

10、使用图像数据

  • getImageData(x, y, width, height); 获取图像数据
  • putImageData(x, y, width, height); 回写图像数据并显示结果

2D上下文的一个明显的长处就是,可以通过getImageData()取得原始图像数据。这个方法接受4各参数:要取得其数据的画面区域的x和y坐标以及该区域的像素宽度和高度。

var imgData = context.getImageData(10, 5, 50, 50);

这里返回的对象是ImageData的实例。每个ImageData对象都有三个属性:width、height和data。其中data属性是一个数组,保存着图像总每一个像素的数据。在data数组中,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度值。因此,第一个像素的数据就保存在数组的第0到第3个元素中。

通过修改图像数据,可以像下面这样创建一个简单的灰阶过滤器。如下:

if(drawing.getContext) {
  var context = drawing.getContext(‘2d‘);
  var img = document.images[0];
  var imageData, data, i, len, average, red, green, blue, alpha;

  // 绘制原始图像
  context.drawImage(img, 0, 0);

  // 取得图像数据
  imageData = context.getImageData(0, 0, img.width, img.height);
  data = imageData.data;
  for(i = 0,len = data.length; i < len; i+=4) {
    red = data[i];
    green = data[i+1];
    blue = data[i+2];
    alpha = data[i+3];
    // 求得rgb平均值
    average = Math.floor((red + green + blue) /3 + 10);

    // 设置颜色值,透明度不变
    data[i] = average;
    data[i+1] = average;
    data[i+2] = average;
  }
  // 回写图像数据并显示结果
  imageData.data = data;
  context.putImageData(imageData, 0, 0);
}

通过操作原始像素值不仅能实现灰阶过滤,还能实现其他功能。

11、合成

  • globalAlpha; 指定所有绘制的透明度。(值介于0~1之间,包括0和1)
  • globalCompositionOperation; 表示后绘制的图形怎样与先绘制的图形结合。
    可能的字符串值:
  • source-over(默认值); 后绘制的图形位于先绘制的图形上方。
  • source-in; 后绘制的图形与之前的图形重叠的部分可见
  • source-out; 后绘制的图形与之前的图形不重叠的部分可见
  • source-atop; 后绘制的图形与之前的图形重叠的部分可见,但先绘制的图形不受影响
  • destination-over; 后绘制的图形位于先绘制的图形下方。
  • destination-in;
  • destination-out;
  • destination-atop; 后绘制的图形位于先绘制的图形的下方,在两者不重叠的地方,先绘制的图形变透明
  • lighter; 后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。
  • copy; 后绘制的图形完全替代与之重叠
  • 的先绘制图形。
  • xor; 后绘制的图形与先绘制的图形重叠的部分执行“异步”操作。

三、WebGL

WebGL是针对Canvas的3D上下文。与其他Web技术不同,WebGL并不是W3C制定的标准,而是有Khronos Group制定的。
Khtonos Group也设计了其他图形处理API,比如OpenGL ES 2.0。

…此处省略…

四、context绘图上下文对象的canvas属性

canvas属性; 返回当前绘图上下文对象所属的canvas对象

以上是关于canvas的主要内容,如果未能解决你的问题,请参考以下文章

Android UICanvas 画布 ⑨ ( Canvas 绘图坐标系平移实例 )

Canvas状态的保存与恢复

Android UICanvas 画布 ⑧ ( Canvas 绘图坐标系 2x2 矩阵 | Canvas 绘图坐标系 3x3 操作矩阵 )

Android UICanvas 画布 ⑤ ( Canvas 坐标系 | Canvas 绘图坐标系变换示例 )

canvas绘图基础及基于粒子系统的雪花飘落

Canvas绘图优化之使用位图--基于createjs库