使用canvas手绘一只冰墩墩

冬奥会刚刚结束,可爱的冰墩墩可是火了一把。昨天闲着没事刷掘金,看到一片文章,叫产品经理:你能不能用div给我画条龙?,既然可以画龙,那么画冰墩墩当然也可以。后来我又看到有人用 three.js 实现了3D版冰墩墩,彻底实现了冰墩墩自由?。
为所欲为.gif

今天我们主要还是学习canvas,之后再学习three.js,一步一步来,毕竟步子迈大了,容易…

canvas

canvas 是 ES6 发布的一个新的标签,是通过HTML和JS结合的方式来绘制图形,可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

其实画出一只冰墩墩就和把大象放进冰箱里一样简单,只需要以下三步:

  1. 创建一个画布(容器)
  2. 获得图片宽高和图像信息(轮廓,每个像素点的色值)
  3. 使用上一步获取的数据在画布上面绘制自己的冰墩墩
<canvas id="canvas"></canvas>
复制代码
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 定义一个图片标签
var image = new Image();
image.src = "dun.jpeg";
image.onload = function () {
 // 获取图片的宽高
 // 通常我们会动态的设置画布的宽高,防止画布拉伸导致图像失真的情况
    canvas.width = image.width;
    canvas.height = image.height;
    // 根据获取的数据绘制图像
    ctx.drawImage(image, 0, 0);
}
       
复制代码

后面我还借用别人的代码绘制了像素点矩阵,代码太长我就不一一列举了,代码链接我会放到文章最下方。

canvas有这几个特点:

  • canvas主要是用笔刷来绘制 2D 图形的
  • canvas绘制出的图形是位图,具有很好的渲染性能,但在放大缩小的时候,可能会出现失真的情况
  • canvas绘制的图形不会出现在DOM结构中,在DOM结构中只有一个canvas标签
  • canvas类似于动画,每次图形的改变都是先清除原来的图形,然后把新的图形画上去
  • canvas适用于大量图形高频率交互的场景,适合图像密集型的游戏开发
  • canvas可以导出jpg/png图片

canvas主要用于绘制2D图形,那么如果我们想要绘制3D图形就需要用到WebGL了,之前提到的Three.js就是基于WebGL的框架,这里先留个坑,我们之后再去实现3D版的冰墩墩。

canvas绘制的图形放大缩小的时候可能会失真,如果需要图片随意放大缩小还不失真,就要用到svg了。

svg

svg是用标签来绘制不规则矢量图形,主要有以下特点:

  • svg 使用 XML 格式定义图像。

  • svg 图像在放大或改变尺寸的情况下其图形不会出现失真的情况。

  • svg 内部通过标签来绘制图像,会显示到页面dom结构中,同时也可以对内部标签进行绑定事件等操作

掘金有一篇文章是说svg的,讲得很详细,SVG入门—如何手写SVG – 掘金 (juejin.cn),对svg感兴趣的朋友,可以看一下。我也照着文章中的操作做了几个相同的icon,这里我举个简单的例子,做一个平时很常见的播放图标。

播放图标通常由两部分构成,外面的圆形和里面的三角形,svg有可以创建圆形和多边形的标签。

  • <ellipse> 标签用来创建圆和椭圆,通过设置圆心位置和竖直半径来绘制一个圆。
    属性:

    • cx:中心位置在 x 轴上的坐标
    • cy:中心位置在 y 轴上的坐标
    • rx:沿 x 轴向的半径,也就是它会把图形分割成上下两部分
    • ry:沿 y 轴向的半径,也就是它会把图形分割成左右两部分
  • <polygon> 标签用来创建多边形。设置几个点的位置来绘制一个多边形。
    只有一个属性:

    • points :多边形顶点的坐标
    • 这里我们要绘制一个三角形,那就需要三个顶点的坐标,这里我们三个顶点坐标分别为(35,23)(60,43) 和 (35,63)
    • 然后把三个点的坐标当作points的属性值,注意:中间要用逗号分隔,如:35 23, 60 43, 35 63
    • 顶点坐标的第一个参数为x轴上的坐标,也就是横坐标,上面的35 60 35都是横坐标;第二个参数为y轴上的坐标,也就是纵坐标,上面的23 43 63都是纵坐标。

用 ellipse 标签绘制一个圆形,再用 polygon 绘制一个三角形,把两个图形拼在一起就组成了我们的播放器图标。
不过在这儿我犯了一个小错误,我开始把 polygo(多边形)标签放到了 ellipse (圆形)标签里面,结果只有圆形,三角形消失了。

错误代码示范❌

  <ellipse cx="43" cy="43" rx="40" ry="40">
    <polygon points="35 23, 60 43, 35 63" />
  </ellipse>
复制代码

image.png

正确代码示范?

 <svg width="120" height="120">
    <defs>
        <symbol id="play" viewBox="0 0 86 86">
            // ellipse 和 polygo 这两个标签不能互相嵌套使用
            <ellipse cx="43" cy="43" rx="40" ry="40"></ellipse>
            <polygon points="35 23, 60 43, 35 63" />
        </symbol>
    </defs>
    <use href="#play" x="13" y="13" width="100" height="100"></use>
</svg>
复制代码

svg也是通过内部添加标签来构造图标的结构,再通过给内部标签添加属性(位置,宽高,颜色)来实现我们想要的图标。其实和构建网页是一样,添加dom结构,给标签添加属性样式
下面是我学习后做的几个图标,代码链接放到了文章最后。
image.png

学习完 canvas 和 svg后,又有朋友要问了:既然 canvas 和 svg 都可以绘制图形,那么他们有什么区别呢?
那我们就来对比一下canvas 和 svg,顺便对今天的学习做一下总结:

  • canvas 和 svg 都可以用来绘制2D图形
  • canvas 绘制的图形不会出现在dom结构中,性能更好一些;svg 绘制的图形会展示到 dom 结构中,节点过多的时候,会影响渲染速度
  • canvas 绘制的图形通常是位图,在放大缩小时会出现失真的情况;而svg 绘制的是矢量图,svg 的出现恰恰就是为了解决图片放大缩小会失真的问题
  • canvas 不能直接操作内部的元素;svg可以直接对内部元素进行事件操作
  • canvas 绘制图形时会清除原来的图形,把新的图形画上去,适合图形频繁重绘的场景;svg 不适合游戏应用

canvas冰墩墩代码链接:MambaNeverOut/canvas-demo (github.com)
svg图标代码链接:MambaNeverOut/svg-demo (github.com)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享