Canvas效果片段

栏目: Html5 · 发布时间: 6年前

内容简介:总结在使用canvas时遇到的一些通用效果实现与相关示例。使用

总结在使用canvas时遇到的一些通用效果实现与相关示例。

透底(剪裁)效果

使用 clip API

See the Pen Clip target area by yrq110 ( @yrq110 ) on CodePen .

示例中的蓝色小方块即为剪裁的区域,无透明效果的原始图案。

主要使用了如下三个元素:

  1. save() & restore()

    save()restore() 是为了保留裁剪前的上下文状态,不然在需要交互(如移动透底框体)场景下,透底区域的图像就不会随着外部canvas内容的变化而改变了。

  2. Path2D

    region为一个 Path2D 对象,用于声明路径,可以直接在canvas2d上下文中使用。

    首先在region上添加目标区域矩形,其次添加整体区域矩形,则两者相交叉的部分即为目标的透底(剪裁)区域。之后在上下文上使用clip API应用该region区域即可对目标区域进行透底(裁剪)。

  3. clip()

    clip有两种填充模式: nonzero 模式和 evenodd 模式,默认为 nonzero 。详情可以看张鑫旭的 这篇 文章了解。

    本例中使用的是 evenodd 模式(奇偶判断规则)。若想剪裁相关区域可以直接通过例子中 targetArea 所代表的目标区域来进行剪裁

相关QA: https://stackoverflow.com/questions/7821384/html-canvas-clip-area-context-restore

笔画效果

在canvas上想实现一个可以自由绘制的画笔效果,需要两个步骤

  1. 监听鼠标事件得到坐标数据
  2. 使用处理后的坐标进行绘制

在第2步中有两种方法进行绘制:一种是在监听到鼠标事件并处理坐标后立即绘制,第二种是通过一个标志位(开关)在requestAnimationFrame所执行的函数中进行绘制,区别在于体验时的流畅度、执行的频率以及性能。

鼠标事件

See the Pen bhiKl by Juriy Zaytsev ( @kangax ) on CodePen .

设置开始与结束绘制的标志位

el.onmousedown = function(e) {
  isDrawing = true;
  points.push({ x: e.clientX, y: e.clientY });
};
el.onmouseup = function() {
  isDrawing = false;
  points.length = 0;
};

在移动时通过标志点进行绘制,示例中为了使路径光滑使用了二次贝塞尔曲线函数

el.onmousemove = function(e) {
  if (!isDrawing) return;
  
  points.push({ x: e.clientX, y: e.clientY });

  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  
  var p1 = points[0];
  var p2 = points[1];
  
  ctx.beginPath();
  ctx.moveTo(p1.x, p1.y);
  for (var i = 1, len = points.length; i < len; i++) {
    var midPoint = midPointBtw(p1, p2);
    ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
    p1 = points[i];
    p2 = points[i+1];
  }
  ctx.lineTo(p1.x, p1.y);
  ctx.stroke();
};

鼠标事件 + requestAnimationFrame

同样根据判断鼠标事件中设置标志位绘制,不过是在requestAnimationFrame的动画关键帧函数中执行

See the Pen draw-stroke by yrq110 ( @yrq110 ) on CodePen .

路径坐标绘制

同样可以使用Path2D来绘制一个给定一系列坐标的轨迹线,需要先将这些坐标点转换成SVG路径,直接传入Path2D构造函数即可。笔者这里用了 svg-points 这个库来将坐标点转换成SVG路径。

let points = contour.map(p => {
    let [x, y] = p;
    return { x, y };
});
points[0].moveTo = true;
let svgPath = toPath(points);
ctx.beginPath();
var p = new Path2D(svgPath);
ctx.stroke(p);
ctx.closePath();

See the Pen draw-svg-path by yrq110 ( @yrq110 ) on CodePen .

图形或图像的透明效果

RGBA

在绘制时给填充或笔触颜色设置alpha值,就可以实现透明图形或图像的绘制。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(255,0,255,0.2)';
ctx.fillRect(0, 0, 75, 75);

See the Pen Overlaying transparent shapes-4 by yrq110 ( @yrq110 ) on CodePen .

globalAlpha

在canvas context上设定 globalAlpha 属性可以用来设置之后图形或图像绘制在canvas上的alpha值。

ctx.globalAlpha = 0.5;
ctx.fillStyle = '#FD0';
ctx.fillRect(0, 0, 75, 75); // 该矩形为半透明的

See the Pen Overlaying transparent shapes by yrq110 ( @yrq110 ) on CodePen .

层叠图形的加深效果

若设置globalAlpha后绘制层叠图形,那么层叠的部分会出现透明度加深的效果

See the Pen Overlaying transparent shapes by yrq110 ( @yrq110 ) on CodePen .

全局统一透明度

若想保持图形的透明度统一,可以采用加一层offscreen canvas(通过 document.createElement('canvas') 创建,非不在屏幕上绘制canvas)的方式。

offscreen层为不透明的,将其绘制到onscreen层,设置onscreen层的globalAlpha属性即可。

通过如下方式创建,不显示在屏幕上的canvas元素

let canvas = ;
canvas.ctx = canvas.getContext('2d');

采用off-screen绘制方式,一方面降低重绘另一方面可以使用全局透明度进行上层canvas的透底效果

See the Pen Overlaying transparent shapes-3 by yrq110 ( @yrq110 ) on CodePen .

相关QA: https://stackoverflow.com/questions/33723384/how-to-reset-transparency-when-drawing-overlapping-content-on-html-canvas

擦除操作

设置 globalCompositeOperation 属性进行绘制即可,会将绘制图形的形状未覆盖的部分保留。

ctx.globalCompositeOperation = "destination-out";

在下面这个例子中,绘制的路径形状会被去除,显示为背景的白色。

See the Pen erase-effect by yrq110 ( @yrq110 ) on CodePen .

图片绘制与导出

图片绘制

使用 drawImage API 进行绘制。

需要注意的是,表示图像源的第一个参数可以是多种类型:CSSImageValue, HTMLImageElement, SVGImageElement, HTMLVideoElement, HTMLCanvasElement, ImageBitmap, OffscreenCanvas。

即在常见的场景中,可以将图像绘制到画布,也可以将另一个画布的内容绘制到该画布上。

通过调整表示尺寸的source与destination参数可以在绘制时进行一定比例的缩放。

跨域问题

若跨域使用图片资源,并在画布上进行如下三种操作时:

  1. 在canvas上下文中调用getImageData()
  2. 在<canvas>元素上调用toBlob()
  3. 在canvas对象上调用toDataURL()

会提示 Tainted canvases may not be exported 的错误,此时需要给Image对象设置一个 crossOrigin 属性来解决。

如下是个简单封装的加载image方法:

export const loadImage = imgPath => {
  return new Promise((resolve, reject) => {
    let img = new Image();
    img.setAttribute("crossOrigin", "anonymous"); // to solve "Tainted canvases may not be exported" error
    img.onload = () => {
      resolve(img);
    };
    img.onerror = e => {
      reject(new Error(e));
    };
    img.src = imgPath;
  });
};

图片导出成base64

使用 toDataURL API

let img = await loadImage(imagePath)
let { width, height } = img;
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
let imageData = canvas.toDataURL("image/png");
console.log('imageData: ', imageData)
// imageData:  data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAg4AAAIOCAYAAADQu4U5AAAgAElEQVR4Xu3dd5zdVZ3/8de5M5M6k4QmLqKsIhYgE4orsjbcddcVewklE5pYsLA2VBQRfooFFxXsNEWSCWBYy+qK7loQFREJGxKwF1BBBYEkM5M6c8/v8Z077EYI8J3J/Z45c+/r+6ee7/mc8zwn4Z3v/ZaAhwIKKKCAAgooUFIglGxnMwUUUEABBRRQAIO...

原始图像与mask遮罩合成

将mask层的alpha通道值赋予原始图像的alpha通道进行结果图的合成

// resultMaskData: { width, height, values }
...
let resultMaskLayer = document.createElement("canvas");
let resultMaskCtx = resultMaskLayer.getContext("2d");
resultMaskLayer.width = img.width;
resultMaskLayer.height = img.height;
resultMaskCtx.drawImage(img, 0, 0);
if (resultMaskData) {
  let { width: maskWidth, height: maskHeight, values } = resultMaskData;
  let maskData = resultMaskCtx.getImageData(0, 0, maskWidth, maskHeight);
  let size = maskWidth * maskHeight;
  for (let i = 0; i < size; i++) {
    if (values[i] !== 255) {
      maskData.data[(i + 1) * 4 - 1] = values[i];
    }
  }
  resultMaskCtx.putImageData(maskData, 0, 0);
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro JavaScript Techniques

Pro JavaScript Techniques

John Resig / Apress / 2006-12-13 / USD 44.99

Pro JavaScript Techniques is the ultimate JavaScript book for the modern web developer. It provides everything you need to know about modern JavaScript, and shows what JavaScript can do for your web s......一起来看看 《Pro JavaScript Techniques》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具