CaveDraw源码02:canvas基础

canvas元素一些默认特性

  • 在默认状况下,canvas元素的背景色与其父元素的背景色一致。
  • 默认的canvas元素大小是300×150个屏幕像素 。
  • 在设置canvas的宽度与高度时,不能使用px后缀。

canvas是立即模式绘图系统

canvas元素是采用“立即模式”(immediate—mode)来绘制图形的,这意味着它会立刻将你所指定的内容绘制在canvas上。然后,它就会立刻忘记刚才绘制的内容,这表示canvas之中不会包含将要绘制的图形对象列表。某些绘图系统,比如SVG,则会维护一份所绘图形对象的列表。这些绘图系统被叫做“保留模式”(retained—mode)绘图系统。

由于立即模式并不维护所绘制对象的列表,所以相对于保留模式来说,它是一种更加底层的绘图模式。立即模式也更加灵活,因为它是直接向屏幕上绘制的,而不是像保留模式那样,需要调整由绘图系统传递过来的图形对象。

立即模式的绘制系统更适合制作“绘画应用程序”(paint application),这种程序不需要 跟踪记录用户所绘制的东西,而保留模式的绘制系统则更适合制作“画图应用程序”(drawing application),此种应用程序可以让用户操作其所创建的图形对象。

canvas元素的大小与绘图表面的大小,也就是css控制的大小和canvas实际大小

使用CSS来设置canvas元素的大小,与直接设置属性相比,其差别是基于这样一个事实 的:canvas元素实际上有两套尺寸。一个是元素本身的大小,还有一个是元素绘图表面(drawing surface)的大小。

当设置元素的width与height属性时,实际上是同时修改了该元素本身的大小与元素绘图表 面的大小。然而,如果是通过CSS来设定canvas元素的大小,那么只会改变元素本身的大小, 而不会影响到绘图表面。在默认情况下,canvas元素与其绘图表面,都是300像素宽、150像素 高。程序清单1—3的代码,使用CSS来将canvas元素的大小设置成600像素宽、300像素高,然而,绘图表面的大小依然没有改变,还是默认的300×150像素。

这时,有趣的事情就发生了。当canvas元素的大小不符合其绘图表面的大小时,浏览器就会 对绘图表面进行缩放,使其符合元素的大小。

board.js中,可以看到根据设备分辨率设置canvas 绘图表面大小和canvas 元素大小的代码。

// canvas 绘图表面大小
this.template.canvasEle.width = pageWidth * Utils.pixelRatio;
this.template.canvasEle.height = pageHeight * Utils.pixelRatio;

// canvas 元素大小
this.template.canvasEle.style.width = pageWidth + "px";
this.template.canvasEle.style.height = pageHeight + "px";

board.js中,可以看到根据设备分辨率获取鼠标在canvas 绘图表面位置的代码。

// 获取鼠标在【绘图表面】上的位置
_getPoint(e) {
  if (Utils.isMobile) {
    return {
      'x': (e.touches[0].clientX - this.template.canvasEle.getBoundingClientRect().left) * Utils.pixelRatio,
      'y': (e.touches[0].clientY - this.template.canvasEle.getBoundingClientRect().top) * Utils.pixelRatio
    };
  } else {
    return {
      'x': e.offsetX * Utils.pixelRatio,
      'y': e.offsetY * Utils.pixelRatio
    };
  }
}

canvas的两个属性和三个API

board.js中,获取了canvas的数据地址,也就是base64格式的字符串,更新到了评论框中。

_getImage() {
    return this.template.canvasEle.toDataURL("image/png");
}

_updateEditor = function (url) {
    return (url) => {
        let imgDom = `<img data-type="cdraw" src="${url}" />`;
        let reg = /\<img data-type="cdraw".*\>/g;
        if (reg.test(this.template.commentEle.value)) {
            this.template.commentEle.value = this.template.commentEle.value.replace(reg, imgDom);
        } else if (this.template.commentEle.value == "") {
            this.template.commentEle.value = imgDom;
        } else {
            if (/\n$/.test(this.template.commentEle.value)) {
                this.template.commentEle.value = this.template.commentEle.value + imgDom;
            } else {
                this.template.commentEle.value = this.template.commentEle.value + '\n' + imgDom;
            }
        }
        this.options.afterUpdateEditor();
    }
}

canvas的2d绘图环境(context)的所有属性

board.js中,设置了lineCap、lineJoin属性。

initCanvasStyle() {
    // 设置线条末端样式
    this.context.lineCap = "round";
    // 设定线条与线条间接合处的样式
    this.context.lineJoin = "round";
}

save()/restore()方法

Canvas的API提供了两个名叫save()和restore()的方法,用于保存及恢复当前canvas绘图 环境的所有属性。save()与restore()方法也许看上去没什么大不了的,不过一旦开始使用Canvas进行开发,就会发现它们其实是不可或缺的功能。

save()与restore()方法可以嵌套式调用。绘图环境的save()方法会将当前的绘图环境压入堆栈顶部。对应的restore()方法则会从堆栈顶部弹出一组状态信息,并据此恢复当前绘图环境的各个状态。这意味着可以嵌套式地调用save()/restore()方法。

shape/eraser.js中,绘制橡皮擦时候,临时更改了lineWidth、strokeStyle,但由于先调用了this.context.save()保存了先前的绘图属性,最后又调用了this.context.restore()恢复了先前的绘图属性,所以,其他形状的绘制不会收到影响,可以体会到上文的意思:“不过一旦开始使用Canvas进行开发,就会发现它们其实是不可或缺的功能”。

// 显示圆形橡皮擦
_drawEraser(x, y) {
    // 橡皮擦
    let eraserWidth = this.board.lineWidth;
    let eraserLineWidth = 5 * Utils.pixelRatio;
    let eraserStrokeStyle = 'rgb(252,150,148)';
    this.context.save();
    // 实际测试 lineWidth 绘制在了圆点内部
    this.context.lineWidth = eraserLineWidth;
    this.context.strokeStyle = eraserStrokeStyle;
    this.context.beginPath();
    this.context.arc(x, y, eraserWidth / 2, 0, Math.PI * 2);
    this.context.clip();
    this.context.stroke();
    this.context.restore();
}
Copyright © 2022,枫糖, 版权所有,禁止转载、演绎、商用。
离开前,建议您浏览一下 归档 页面,或许有更多相关的、有趣的内容!
如需博主帮助,请转到 小卖铺 页面,购买手工活服务!

添加评论

code

目录