canvas教程

使用CANVAS实现交互性圆形马赛克效果

字号+ 作者:H5之家 来源:H5之家 2017-01-06 16:00 我要评论( )

在看D3.js的时候,无意间看到了一个 例子 ,觉得很有趣,像是会分裂的圆形的马赛克。看了下代码,发现是使用svg完成的,但是具体实现方式使得在手机端无法把玩,

> 脚本语言 > >

使用CANVAS实现交互性圆形马赛克效果 2017-01-03 16:34 出处:清屏网 人气: 

在看D3.js的时候,无意间看到了一个 例子 ,觉得很有趣,像是会分裂的圆形的马赛克。看了下代码,发现是使用svg完成的,但是具体实现方式使得在手机端无法把玩,于是就自己实现了一个canvas版本的。代码很简单,canvas初学者可以自己试试当做练笔,还是挺有趣的一个效果。

Online Demo

online demo

在demo中任意从本地选择一张图片,然后通过鼠标移动或者移动端touchmove就能实现圆形分裂的效果。

难点

说是难点,其实根本不难。一开始看到的时候会好奇大大小小的圆形的颜色是怎么计算的,计算该面积下的平均值?其实很简单,就是从绘制了图片的canvas上获取圆心坐在图片对应位置上的颜色值。这样的算法在圆形半径较大的时候,对被遮盖的图片区域的颜色代表性其实不好,但是从整个分裂过程来看,这个取色的方案效果还不错。

关键技术点
  • canvas绘图: CanvasRenderingContext2D.drawImage()

  • canvas绘制圆形: CanvasRenderingContext2D.arc()

  • canvas上取指定坐标上的颜色值: CanvasRenderingContext2D.getImageData()

  • 思路
  • 将图片绘制在一个offline(即不用挂在DOM树上)的canvas上,为了在指定位置获取颜色用

  • 创建另一个canvas,用来绘制圆。两个canvas尺寸保持一致(而且都是方形),方便通过坐标获取颜色

  • 绘制第一个圆形,以canvas中心为原点,使用对应offline canvas坐标上的颜色填充

  • 维持一个 circles 数组,代表所有的圆,每个元素有坐标(x, y),半径(r)和是否标记分裂(readyToSplit)

  • 需要一个渲染循环(rendering loop),不断的找出被标记出来需要分裂(readyToSplit)的圆,拿去做分裂绘制

  • 事件处理:当mousemove或者touchmove发生在圆上时,该圆被标记 readyToSplit = true ,后面的则有渲染循环去处理

  • 测试驱动

    在我自己做这样的编程时,会以测试驱动的方式开始代码。因此会脑子里先写下自己写的类将被如何使用,怎么样能够简单易用。

    我打算把这个效果封装成一个类,它将在使用时被实例化。最终的效果肯定是要在DOM树上显示的,所以这里在实例化时肯定需要指定一个mount节点,所有的事情在其内部进行。而且,按照通常的习惯,开放一些配置,使得使用者可以做一些简单的定制化。但是目前还没有想好哪些内部的配置拿出来比较合适,所以第二个参数 options 可以后面再考虑。

    var cs = new CircleSplit('#mountNode', options);

    我希望能够动态的切换显示的图片内容,所以想提供一个 setImage 的方法,它应该能接受图片路径,或者 Image 元素对象。

    cs.setImage(image);

    OK,这就是目前我希望的实例化方式,和想要提供的接口。后面再具体实现过程中,可以再继续添加或者修改。

    试想内部

    结合前面谈到的实现思路,考虑 CircleSplit 类里面该如果定义属性和私有共有方法。

    从构造函数入手。个人习惯在构造函数最后加上init方法,init方法里做一些准备工作,完成 setImage 前的一些必要的事情。

    function CircleSplit (el, options) { ... this._init(); } CircleSplit.prototype._init = function () { this._createSourceCanvas(); // 创建源canvas,用来绘制图片,作为offline canvas,提供坐标颜色使用 this._createTargetCanvas(); // 创建目标canvas,用来绘制看到的大大小小的圆 this._render(); // 开启渲染循环 this.bindEvent(); // 绑定事件,touchmove mousemove这些 }

    这样我们一下子多了好几个函数,而且目的都很明确,因此可以很容易的判断需要那些实例属性和该如何实现各自函数体。这里可能需要多注意一下 _render() ,思路中谈到在这里应该去绘制需要分裂的圆,那么大致应该像下面这样:

    CircleSplit.prototype._render = function () { // 循环体 this.circles.forEach(function (circle) { if (circle.readyToSplit) { this._splitCircle(circle); circle.readyToSplit = false; } }, this); // 下一个循环 requestAnimationFrame(this._render.bind(this)); }

    而什么时候设置 circle.readyToSplit 呢?就是在 bindEvent() 的事件处理函数里面。这里会通过 _tagCircle() 遍历circles,找到能hitd到事件坐标的一个圆,将其标记(tag)上readToSplit。

    从共有方法入手。 setImage 之后,相当于将整个CircleSplit中的状态都重置了下, circles 数组得重置,两个canvas得重置等。

    CircleSplit.prototype.setImage = function (image) { this._resetCanvas(this.sourceCanvas); // clear source canvas this._drawSourceImage(image); // draw source canvas this._resetCanvas(this.targetCanvas); // clear target canvas this._drawCircle(x, y, r) // draw target canvas。绘制第一个,也是最大的一个圆形。圆心为canvas中心,半径为canvas的一半 }

    _drawSourceImage() 里面就是调用了 CanvasRenderingContext2D.drawImage() 进行图片绘制。这个API函数有3中传参形式,我这里选择了5参数的形式,使用了自己写的简易的居中库 CenterIt ,来解决图片居中绘制问题:无论图片尺寸,都可以轻易的居中覆盖填充(cover)或者居中包含(contain)填充。

    这里的 _drawCircle(x, y, r) 应该能重用,后面每次圆形分裂的时候都能调用。初步给它3个参数,圆心坐标和半径。在其内部应该能够自己去获取坐标对应的颜色值。所以简单想象一下它的内部:

    CircleSplit.prototype._drawCircle = function (x, y, r) { ... context.fillStyle = this._getColor(x, y); // 获取坐标颜色 context.beginPath(); context.arc(x, y, r, 0, 2 * Math.PI); context.closePath(); context.fill(); ... }

    绘制圆时使用 CanvasRenderingContext2D.arc() API,使用起来不算简单明了,每次还需要begin和close Path。相比而下,一些canvas的游戏库或者图形库,则简单直观的多:

    // create.js var circle = new createjs.Shape(); circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50); // two.js var circle = two.makeCircle(72, 100, 50); circle.fill = '#FF8000'; circle.stroke = 'orangered'; circle.linewidth = 5;

    因此,如果要做比较复杂的绘制操作,推荐找一个适合自己的canvas库,会使得工作变得容易的多。

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • Android开发面试题:Drawable、Bitmap、Canvas和Paint的关系

      Android开发面试题:Drawable、Bitmap、Canvas和Paint的关系

      2017-01-06 16:02

    • 3样章.pdf.pdf 全文免费在线阅读

      3样章.pdf.pdf 全文免费在线阅读

      2017-01-06 15:01

    • canvas如何转存为图片!

      canvas如何转存为图片!

      2017-01-06 14:06

    • 【网盘资源】HTML5 Canvas核心技术 图形、动画与游戏开发.pdf

      【网盘资源】HTML5 Canvas核心技术 图形、动画与游戏开发.pdf

      2017-01-06 14:06

    网友点评