欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

canvas 中的自定义图形

程序员文章站 2024-03-15 08:30:53
...

以下属于 canvas 开发中 JavaScript 面向对象继承方面的内容

前言

一直以来,我都不认为 janvas 是一个框架,我更倾向于它是一个封装库,它提供了两个方面的内容:

  1. 基础内容,一些常用的东西,用于解决重复代码问题,如 Utils/Canvas。
  2. 图形封装,janvas 的本质,用于解决 canvas 中无对象的问题

以下通过对比原始绘图方式与继承的区别,来说明为何要使用 janvas。

准备工作

通常,要开发 canvas,页面中应该有这样一个东西:

<canvas id="canvas"></canvas>

可以通过以下语句获取这个 canvas 对象的引用:

var canvas = document.getElementById("canvas");

因为 canvas 仅仅是个“画布”,要绘制内容,还需要“画笔”,也就是:

var ctx = canvas.getContext("2d");

这样子,我们的准备工作就完成了。

原始绘图方式

通常,我们拿到一个画笔,想在坐标 10, 30 的位置填充一个宽高分别为 80, 40 的矩形,我们会这么做:

ctx.beginPath();
ctx.rect(10, 30, 80, 40);
ctx.fill();

结果如下:

canvas 中的自定义图形

进一步抽象一下,我们想在坐标 x, y 的位置填充一个宽高分别为 w, h 的矩形,我们会这么做:

function fillRect(x, y, w, h) {
  ctx.beginPath();
  ctx.rect(x, y, w, h);
  ctx.fill();
}

接下来,只需要调用 fillRect(10, 30, 80, 40); 函数,即可复用这一段绘制矩形的代码。

以上就是面向过程的思维方式,封装一个函数,做到某一件事情。

可是接下来呢?点击了某个区域,如何判断坐标是否在这个矩形内部?我们想在鼠标移动到矩形的时候,改变它的颜色又如何做到?我们如何控制这个矩形的变形呢?

毫无疑问,以上这些内容都需要编写大量额外的代码,但接下来的操作,可能会让你对 janvas 刮目相看。

继承于 janvas.Shape

现在,我们抽象一个矩形类,代码如下:

function MyRect(ctx, sx, sy, w, h) {
  janvas.Shape.call(this, ctx, sx, sy);
  this.w = w;
  this.h = h;
}

MyRect 构造函数需要传入五个对应参数,通过调用 janvas.Shape.call 将前三个参数,ctx 画笔,sx, sy 起始绘制点 x, y,传给父类,将后两个参数保存给自身。

接下来,只需要写一行继承代码:

janvas.Utils.inheritPrototype(MyRect, janvas.Shape);

见证奇迹的时刻马上发生,我们重写原型链上的 process() 方法:

MyRect.prototype.process = function () {
  this.ctx.beginPath();
  this.ctx.rect(this.sx, this.sy, this.w, this.h);
};

可以看到,绘制代码是在 process() 方法中实现的,相比原始绘图方式,多了抽象矩形类以及继承的一行语句,接着我们实例化一个矩形对象,看看它有什么作用:

var rect = new MyRect(ctx, 10, 30, 80, 40);
rect.fill();

canvas 中的自定义图形

这两行代码,同样的完成了矩形的绘制!

同样的,还可以试试调用以下两行代码,得到坐标点是否在矩形内:

console.log(rect.isPointInPath(5, 5));   // output: false
console.log(rect.isPointInPath(15, 40)); // output: true

继承的作用发挥出来了,它具备了探测坐标点是否在图形内的方法!

可以改变矩形的位置,并改变矩形的填充颜色,再次绘制:

rect.setStart(20, 40).getStyle().setFillStyle("pink");
rect.fill();

效果图如下:

canvas 中的自定义图形

实现过继承的它,同样具有了能改变自身位置以及颜色的能力。

也就是说,面向过程封装的函数方法中的绘制部分,如果以继承 janvas.Shape 的方式移植,会使得毫无生气的绘制过程变得对象化,使得:

  1. 这个对象不仅具有了自己的属性,还继承了判断坐标点是否在此对象内的方法
  2. 能单独给此对象设置相关的样式
  3. 能给对象设置以上代码没展示出来的各种变形参数,如错切、缩放、旋转以及平移能力。

其实,这以上就是 janvas.Rect 类的简化版实现源码。