整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Three.js开发秘籍:FlyControls的拖拽视角问题解决方案

求背景

工作中需要使用 threejs 制作一个第一人称的 viewer,在使用 threejsflyControls 时发现一些和需求不一样的情景。

主要的问题就是拖拽查看时相机在拖拽后会导致上方向的变化从而导致视角变化很奇怪,所以需要改造一下原本的 FlyControl

既然要改造那就肯定要先解析 FlyControls 的源码了

FlyControls的功能

FlyControls 实现了一个类似第一人称视角通过 WASD 来调整相机前进的基本控制器。

例子https://threejs.org/examples/#misc_controls_fly

文档https://threejs.org/docs/index.html?q=fly#examples/zh/controls/FlyControls

可以看到上图 WASD 控制移动,RF 控制上下移动,QE 旋转相机,方向键上下左右可以控制视角。

也可以用鼠标偏移位置自动旋转视角

源码分析属性声明

地址

https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/FlyControls.js

首先 FlyControls 继承自 EventDispatcherEventDispatcher 是事件调度器。

主要是用于 FlyControls 的事件信息传递用。

构造函数中一个是 object 也就是控制的摄像机对象从 TS 定位文件中可以看出是一个Camera或者继承自Camera的对象。

domElement 则是当前 threejs renderer 绘制的 dom 元素

接下来就是一系列变量的定义

其中 movmentSpeedrollSpeed 是控制相机移动和旋转的速度的

dragToLook 则是我们需求中需要的拖拽使相机视角发生变化,可以看到这里默认是 false

autoForward 是自动向前

EPS 应该是最小误差修正用的

可以看到这里还用 lastQuaternionlastPosition 记录了最后相机的四元组和位置信息

tmpQuaternion 就是临时保存用的一个四元组

剩下就是一些状态值

源码分析事件监听

在代码最底部可以看到 FlyControls 监听了7个事件分别对应一系列操作。

先从第一个keydown分析

1、一开始判断是否按下了 alt 键和是否启用了控制器

2、然后根据按键的键码分别设置 moveState 的状态,其中 shift 对移动速度进行了修改

3、然后就是最关键的 updateMovementVectorupdateRotationVector,这两个之后进行分析。

这里 keyupkeydown 类似就不过多做分析

然后是鼠标操作三兄弟

pointerdown 可以看出来是根据 dragToLook 来进行不同的操作。

如果是拖拽调整视角就修改 status 的值

如果不是则根据按下的鼠标左键还是又键修改 moveState 的状态。

紧接着pointermove事件中

依旧如果不是使用拖拽查看或者 status大于0 (这里的 status>0 是由向前的 pointerdown 修改的,也就是可以看做是否按下了鼠标)

然后就是这个 getContainerDimensions ,其实就是查看这个当前的 viewer 是不是在 docment 对象,返回相应的大小和偏移值

halfWidthhalfHeight 就是当前 viewer 可视区域一半的宽高。

-( event.pageX - container.offset[ 0 ] )( ( event.pageY - container.offset[ 1 ] ) 是鼠标在当前可视区域的相对坐标,

其值减去一半的宽度后,其实就可以视作鼠标相对于可视区域中心点的相对位置了。

x轴来举例可以看出来 ( event.pageX - container.offset[ 0 ] ) - halfWidth 则是红线部分则是鼠标到中心点的距离。

然后除以 halfWidth 则是一个归一化处理,相当于把鼠标距离中心点位置的值域控制在0到1之间了,最后在修改 moveState

最后pointerup事件则是将状态还原

在此之后 可以看到 updateMovementVectorupdateRotationVector 实质上是修改了 moveVectorrotationVector

最后

再根据之前设置的速度和旋转值以及 rotationVectormoveVector 来控制相机的位置以及旋转。

最后的判断则是看移动和旋转的值是否太小了。

太小就进行忽略。

分析

那么这个控制器为什么会造成拖拽后上方向发生变化呢,其实从上面代码的分析不难看出。

先将鼠标向上旋转一个角度

再将鼠标朝右旋转

最后再朝下拖动鼠标时

此时的相机左方向轴已经不在x轴与y轴构成的平面上了。

所以相机上方向发生了变化。

其根本原因是相机左右旋转时旋转轴是以自身上方向为旋转轴造成的。

如果要保持相机上方向一致的情况下旋转视角应该以z轴作为相机旋转的旋转轴。

这样相机怎么旋转都能保持上方向一致了。

– 欢迎点赞、关注、转发、收藏【我码玄黄】,gonghao 同名

TML 标题

HTML 标题(Heading)是通过 <h1> - <h6> 标签来定义的.

h是英文header标题的缩写,标题无处不在,它的应用范围十分广泛:网站结构、写作文、PPT 等。

这里有六个标题元素标签 —— <h1><h2><h3><h4><h5><h6>,每个元素代表文档中不同级别的内容:

<h1> 表示主标题( the main heading ),<h2> 表示二级子标题( subheadings ),<h3>表示三级子标题( sub-subheadings ),<h4><h5><h6>字体的大小依次递减。

<h1>这是标题1</h1>
<h2>这是标题2</h2>
<h3>这是标题3</h3>
<h4>这是标题4</h4>
<h5>这是标题5</h5>
<h6>这是标题6</h6>

HTML 段落

HTML 段落是通过标签<p>来定义的,P是英文paragraph段落的缩写,经常被用来创建一个段落,就和你写作文一样。

<p>这是一个段落。</p>
<p>这是另外一个段落。</p>

HTML 中的链接

HTML 链接是通过标签<a>来定义的。a标签,也叫anchor(锚点)元素,既可以用来链接到外部地址实现页面跳转功能,也可以链接到当前页面的某部分实现内部导航功能。

<a href="http://www.liyadong.cn">这是一个链接</a>
<a href="#">这是一个空链接</a> 

HTML 图像

HTML 图像是通过标签<img>来定义的。使用img元素来为你的网站添加图片,使用src 属性指向一个图片的具体地址。

<img src="logonew2.png" width="206" height="36">

请注意:img元素是自关闭元素,不需要结束标记。

HTML 强调

在 HTML 中我们可以使用em(emphasis)元素来标记这样的情况,浏览器默认风格为斜体:

在 HTML 中我们还可以使用<strong>(strong importance)元素来标记这样的请况,浏览器默认风格为粗体:

<p>我 <em>很高兴</em>你不 <em>讨厌我</em>.</p>
<p>这种液体是<strong>高毒性的</strong>.</p>
<p>我就指望你<strong>不会</strong> 迟到!</p>

HTML 水平线

<hr> 标签在 HTML 页面中创建水平线。

hr 元素可用于分隔内容,使用该元素产生的水平线可以在视觉上将文档分隔成各个部分。

<p>hr 标签定义水平线:</p>
<hr />
<p>这是段落。</p>
<hr />
<p>这是段落。</p>
<hr />
<p>这是段落。</p>

HTML 注释

可以将注释插入 HTML 代码中,这样可以提高其可读性,使代码更易被人理解。浏览器会忽略注释,也不会显示它们。

HTML 注释可以方便地用来帮助网页设计人员,提醒他们与程序相关的信息。

注释写法如下:

<!-- 这是一个注释 -->

HTML 折行

如果您希望在不产生一个新起点的情况下进行换行(新行),请使用 <br /> 标签。

在 HTML 语言中,<br /> 标签定义为一个换行符,它可以理解为简单的输入一个空行,而不是用来对内容进行拆分:

<p>这个<br>段落<br>演示了分行的效果</p>

HTML 文本格式化标签

标签

描述

<b>

定义粗体文本

<em>

定义着重文字

<i>

定义斜体字

<small>

定义小号字

<strong>

定义加重语气

<sub>

定义下标字

<sup>

定义上标字

<ins>

定义插入字

<del>

定义删除字

HTML "计算机输出" 标签

标签

描述

<code>

定义计算机代码

<kbd>

定义键盘码

<samp>

定义计算机代码样本

<var>

定义变量

<pre>

定义预格式文本

HTML 引文, 引用, 及标签定义

标签

描述

<abbr>

定义缩写

<address>

定义地址

<bdo>

定义文字方向

<blockquote>

定义长的引用

<q>

定义短的引用语

<cite>

定义引用、引证

<dfn>

定义一个定义项目。

HTML <q> 用于短的引用

HTML <q> 元素定义短的引用。

浏览器通常会为 <q> 元素包围引号。

<p>WWF 的目标是:<q>构建人与自然和谐共存的世界。</q></p>

用于长引用的 HTML <blockquote>

HTML <blockquote> 元素定义被引用的节。

浏览器通常会对 <blockquote> 元素进行缩进处理。

<p>以下内容引用自 WWF 的网站:</p>
<blockquote cite="http://www.worldwildlife.org/who/index.html">
五十年来,WWF 一直致力于保护自然界的未来。
世界领先的环保组织,WWF 工作于 100 个国家,
并得到美国一百二十万会员及全球近五百万会员的支持。
</blockquote>

用于缩略词的 HTML <abbr>

HTML <abbr> 元素定义缩写或首字母缩略语。

对缩写进行标记能够为浏览器、翻译系统以及搜索引擎提供有用的信息。

<p><abbr title="World Health Organization">WHO</abbr> 成立于 1948 年。</p>

用于定义的 HTML <dfn>

HTML <dfn> 元素定义项目或缩写的定义。

<dfn> 的用法,按照 HTML5 标准中的描述,有点复杂:

1. 如果设置了 <dfn> 元素的 title 属性,则定义项目:

<p><dfn title="World Health Organization">WHO</dfn> 成立于 1948 年。</p>

2. 如果 <dfn> 元素包含具有标题的 <abbr> 元素,则 title 定义项目:

<p><dfn><abbr title="World Health Organization">WHO</abbr></dfn> 成立于 1948 年。</p>

3. 否则,<dfn> 文本内容即是项目,并且父元素包含定义。

<p><dfn>WHO</dfn> World Health Organization 成立于 1948 年。</p>

注释:如果您希望简而化之,请使用第一条,或使用 <abbr> 代替。

用于联系信息的 HTML <address>

HTML <address> 元素定义文档或文章的联系信息(作者/拥有者)。此元素通常以斜体显示。大多数浏览器会在此元素前后添加折行。

<address>
Written by Donald Duck.<br> 
Visit us at:<br>
Example.com<br>
Box 564, Disneyland<br>
USA
</address>

用于著作标题的 HTML <cite>

HTML <cite> 元素定义著作的标题。

浏览器通常会以斜体显示 <cite> 元素。

<p><cite>The Scream</cite> by Edward Munch. Painted in 1893.</p>

用于双向重写的 HTML <bdo>

HTML <bdo> 元素定义双流向覆盖(bi-directional override)。

<bdo> 元素用于覆盖当前文本方向:

<bdo dir="rtl">This text will be written from right to left</bdo>

HTML 引文、引用和定义元素

标签

描述

<abbr>

定义缩写或首字母缩略语。

<address>

定义文档作者或拥有者的联系信息。

<bdo>

定义文本方向。

<blockquote>

定义从其他来源引用的节。

<dfn>

定义项目或缩略词的定义。

<q>

定义短的行内引用。

<cite>

定义著作的标题。

HTML 区块

HTML 可以通过 <div> 和 <span> 将元素组合起来。

HTML 区块元素

大多数 HTML 元素被定义为块级元素内联元素

块级元素在浏览器显示时,通常会以新行来开始(和结束)。

实例: <h1>, <p>, <ul>, <table>

HTML 内联元素

内联元素在显示时通常不会以新行开始。

实例: <b>, <td>, <a>, <img>

HTML <div> 元素

<div> 标签可以把文档分割为独立的、不同的部分。

HTML <div> 元素是块级元素,它是可用于组合其他 HTML 元素的容器。

<div> 元素没有特定的含义。除此之外,由于它属于块级元素,浏览器会在其前后显示折行。

如果与 CSS 一同使用,<div> 元素可用于对大的内容块设置样式属性。

<div> 元素的另一个常见的用途是文档布局。它取代了使用表格定义布局的老式方法。使用 <table> 元素进行文档布局不是表格的正确用法。<table> 元素的作用是显示表格化的数据。

<p>这是一些文本。</p>
<div style="color:#00FFFF">
<h3>这是一个在 div 元素中的标题。</h3>
<p>这是一个在 div 元素中的文本。</p>
</div>
<p>这是一些文本。</p>

HTML <span> 与元素

HTML <span> 元素是内联元素,可用作文本的容器

<span> 元素也没有特定的含义。

当与 CSS 一同使用时,<span> 元素可用于为部分文本设置样式属性。

<p>我有一双
<span style="color:gold">金色</span> 的
<span style="font-size:50px">大眼睛</span>和 
<span style="color:blue">蓝色的头发</span>。
</p> 

HTML 分组标签

标签

描述

<div>

定义了文档的区域,块级 (block-level)

<span>

用来组合文档中的行内元素, 内联元素(inline)


HTML无序列表

无序列表是一个项目的列表,此列项目使用粗体圆点(典型的小黑圆圈)进行标记。

无序列表适合成员之间无级别顺序关系的情况。

无序列表使用 <ul> 标签:

<ul>
<li>Coffee</li>
<li>Milk</li>
</ul>

HTML 有序列表

同样,有序列表也是一列项目,列表项目使用数字进行标记。 有序列表始于 <ol> 标签。每个列表项始于 <li> 标签。

有序列表适合各项目之间存在顺序关系的情况。

<ol>       
<li>Coffee</li>      
<li>Milk</li>       
</ol>

HTML 自定义列表

自定义列表不仅仅是一列项目,而是项目及其注释的组合。

自定义列表以 <dl> 标签开始。每个自定义列表项以 <dt> 开始。每个自定义列表项的定义以 <dd> 开始。

自定义列表中的一个术语名可以对应多重定义或者多个术语名对应同一个定义,如果只有术语名或者只有定义也是可行的,也就是说 <dt> 与 <dd> 在其中数量不限、对应关系不限。

<dl>
<dt>Coffee</dt>
<dd>- black hot drink</dd>
<dt>Milk</dt>
<dd>- white cold drink</dd>
</dl>

HTML 表格

表格由<table>标签来定义。每个表格均有若干行(由<tr>标签定义),每行被分割为若干单元格(由<td>标签定义)。字母 td 指表格数据(table data),即数据单元格的内容。数据单元格可以包含文本、图片、列表、段落、表单、水平线、表格等等。

 HTML 表格的基本结构:

<table>…</table>:定义表格

<th>…</th>:定义表格的标题栏(文字加粗)

<tr>…</tr>:定义表格的行

<td>…</td>:定义表格的列

<table border="1">
<tr>
<td>row 1, cell 1</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
</tr>
</table>

HTML 表格标签


标签

描述

<table>

定义表格

<th>

定义表格的表头

<tr>

定义表格的行

<td>

定义表格单元

<caption>

定义表格标题

<colgroup>

定义表格列的组

<col>

定义用于表格列的属性

<thead>

定义表格的页眉

<tbody>

定义表格的主体

<tfoot>

定义表格的页脚

HTML框架

<iframe>标签规定一个内联框架。

一个内联框架被用来在当前 HTML 文档中嵌入另一个文档。

通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。

iframe 语法:

<iframe src="URL"></iframe>

URL指向不同的网页,将窗口内容显示为URL地址指向页面。


heightwidth属性用来定义iframe标签的高度与宽度。属性默认以像素为单位, 但是你可以指定其按比例显示 (如:"80%").

<iframe src="demo_iframe.htm" width="80%" height="80%"></iframe>

iframe可以显示一个目标链接的页面,目标链接的属性必须使用iframe的属性,如下实例:

<iframe src="demo_iframe.htm" name="iframe_a"></iframe>
<p><a href="http://www.w3cschool.cn" target="iframe_a">W3CSCHOOL.CN</a></p>

HTML 表单

表单是一个包含表单元素的区域。

表单元素是允许用户在表单中输入内容,比如:文本域 (textarea)、下拉列表、单选框 (radio-buttons)、复选框 (checkboxes)等等。

表单使用表单标签 <form> 来设置:

<form>
.   
input elements        
.
</form>

文本域通过 <input type="text"> 标签来设定,当用户要在表单中键入字母、数字等内容时,就会用到文本域。您可以在编程测试中创建文本输入框!

<form>
姓名: <input type="text" name="firstname"><br>       
电话号码: <input type="text" name="lastname">      
</form>

密码字段通过标签 <input type="password"> 来定义:

单选按钮(Radio Buttons)

<input type="radio"> 标签定义了表单单选框选项。

<form>        
<input type="radio" name="sex" value="male">男<br>      
<input type="radio" name="sex" value="female">女       
</form>

复选框(Checkboxes)

<input type="checkbox"> 定义了复选框. 用户需要从若干给定的选择中选取一个或若干选项。

<form>      
<input type="checkbox" name="vehicle" value="Bike">我有自行车<br>      
<input type="checkbox" name="vehicle" value="Car">我有小车
</form>

提交按钮 (Submit Button)

<input type="submit"> 定义了提交按钮.

当用户单击确认按钮时,表单的内容会被传送到另一个文件。表单的动作属性定义了目的文件的文件名。由动作属性定义的这个文件通常会对接收到的输入数据进行相关的处理。:

<form name="input" action="html_form_action.php" method="get">
Username: <input type="text" name="user">
<input type="submit" value="Submit">
</form>


以上内容整理于网络,如有侵权请联系删除。

者:前端Q

转发链接:https://mp.weixin.qq.com/s/ewFfXptccFs5KvjUINLGbQ

前端

小试牛刀,实现了六款简单常见HTML5 Canvas特效滤镜,并且封装成一个纯JavaScript可调用的API文件gloomyfishfilter.js。支持的特效滤镜分别为:

1.反色

2.灰色调

3.模糊

4.浮雕

5.雕刻

6.合理

滤镜原理解释:

2.灰色调:获取一个预期点RGB值r,g,b则新的RGB值

newr =(r * 0.272)+(g * 0.534)+(b * 0.131);

newg =(r * 0.349)+(g * 0.686)+(b * 0.168);

newb =(r * 0.393)+(g * 0.769)+(b * 0.189);

3.模糊:基于一个5 * 5的卷积核

4.浮雕与雕刻:

根据当前预期的前一个预期RGB值与它的后一个重新的RGB值之差再加上128

5.总体:模拟了物体在镜子中与之对应的效果。

杂项准备

1、如何获取Canvas 2d context对象

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

canvas.width = source.clientWidth;

canvas.height = source.clientHeight;

**if**(!canvas.getContext) {

   console.log("Canvas not supported. Please install a HTML5compatible browser.");

   **return**;

}

// get 2D context of canvas and draw image

tempContext = canvas.getContext("2d");

2、如何添加一个DOM img对象到Canvas对象中

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

tempContext.drawImage(source, 0, 0, canvas.width,canvas.height);

3、如何从Canvas对象中获取预定数据

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

var len = canvas.width * canvas.height * 4;

var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);

var binaryData = canvasData.data;

4、如何对DOM对象实现鼠标ClickEvent绑定

function bindButtonEvent(element, type, handler) 
{  

if(element.addEventListener){ 

      element.addEventListener(type, handler,**false**); 

   }else{ 

      element.attachEvent('on'+type, handler);// for IE6,7,8

   } 

}

5、如何调用实现的gfilter API完成滤镜功能

<scriptsrc=*"gloomyfishfilter.js"*></script> //导入API文件

gfilter.colorInvertProcess(binaryData, len); //调用 API

6、浏览器支持:IE,FF,Chrome上测试通过,其中IE上支持通过以下标签实现:

<meta http-equiv="X-UA-Compatible"*content=*"chrome=IE8"> 


效果演示:

应用程序源代码:

CSS部分:

#svgContainer {
  width:800px;
  height:600px;
  background-color:#EEEEEE;
}

#sourceDiv { float: left; border: 2px solid blue} 
#targetDiv { float: right;border: 2px solid red}

filter1.html中HTML源代码:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="chrome=IE8">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Canvas Filter Demo</title>
<link href="default.css" rel="stylesheet" />
<script src="gloomyfishfilter.js"></scrip>
</head>
<body>
  <h1>HTML Canvas Image Process - By Gloomy Fish</h1>
  <div id="svgContainer">
    <div id="sourceDiv">
      <img id="source" src="../test.png" />
    </div>
    <div id="targetDiv">
      <canvas id="target"></canvas>
    </div>
  </div>
  <div id="btn-group">
    <button type="button" id="invert-button">反色</button>
    <button type="button" id="adjust-button">灰色调</button>
    <button type="button" id="blur-button">模糊</button>
    <button type="button" id="relief-button">浮雕</button>
    <button type="button" id="diaoke-button">雕刻</button>
    <button type="button" id="mirror-button">镜像</button>
  </div>
</body>
</html>

filter1.html中JavaScript源代码:

var tempContext = null; // global variable 2d context
    window.onload = function() {
      var source = document.getElementById("source");
      var canvas = document.getElementById("target");
      canvas.width = source.clientWidth;
      canvas.height = source.clientHeight;

      if (!canvas.getContext) {
          console.log("Canvas not supported. Please install a HTML5 compatible browser.");
          return;
      }

      // get 2D context of canvas and draw image
      tempContext = canvas.getContext("2d");
      tempContext.drawImage(source, 0, 0, canvas.width, canvas.height);

          // initialization actions
          var inButton = document.getElementById("invert-button");
          var adButton = document.getElementById("adjust-button");
          var blurButton = document.getElementById("blur-button");
          var reButton = document.getElementById("relief-button");
          var dkButton = document.getElementById("diaoke-button");
          var mirrorButton = document.getElementById("mirror-button");

          // bind mouse click event
          bindButtonEvent(inButton, "click", invertColor);
          bindButtonEvent(adButton, "click", adjustColor);
          bindButtonEvent(blurButton, "click", blurImage);
          bindButtonEvent(reButton, "click", fudiaoImage);
          bindButtonEvent(dkButton, "click", kediaoImage);
          bindButtonEvent(mirrorButton, "click", mirrorImage);
    }

    function bindButtonEvent(element, type, handler)  
{  
      if(element.addEventListener) {  
         element.addEventListener(type, handler, false);  
      } else {  
         element.attachEvent('on'+type, handler); // for IE6,7,8
      }  
    }  

    function invertColor() {
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
      var binaryData = canvasData.data;

          // Processing all the pixels
          gfilter.colorInvertProcess(binaryData, len);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

    function adjustColor() {
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          var binaryData = canvasData.data;

          // Processing all the pixels
          gfilter.colorAdjustProcess(binaryData, len);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

    function blurImage() 
{
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);

          // Processing all the pixels
          gfilter.blurProcess(tempContext, canvasData);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

    function fudiaoImage() 
{
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);

          // Processing all the pixels
          gfilter.reliefProcess(tempContext, canvasData);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

    function kediaoImage() 
{
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);

          // Processing all the pixels
          gfilter.diaokeProcess(tempContext, canvasData);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

    function mirrorImage() 
{
      var canvas = document.getElementById("target");
      var len = canvas.width * canvas.height * 4;
      var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);

          // Processing all the pixels
          gfilter.mirrorProcess(tempContext, canvasData);

          // Copying back canvas data to canvas
          tempContext.putImageData(canvasData, 0, 0);
    }

滤镜源代码(gloomyfishfilter.js):

var gfilter = {
    type: "canvas",
    name: "filters",
    author: "zhigang",
    getInfo: function () {
        return this.author + ' ' + this.type + ' ' + this.name;
    },

    /**
     * invert color value of pixel, new pixel = RGB(255-r, 255-g, 255 - b)
     * 
     * @param binaryData - canvas's imagedata.data
     * @param l - length of data (width * height of image data)
     */
   colorInvertProcess: function(binaryData, l) {
    for (var i = 0; i < l; i += 4) {
          var r = binaryData[i];
          var g = binaryData[i + 1];
          var b = binaryData[i + 2];

          binaryData[i] = 255-r;
          binaryData[i + 1] = 255-g;
          binaryData[i + 2] = 255-b;
      }
   },

   /**
    * adjust color values and make it more darker and gray...
    * 
    * @param binaryData
    * @param l
    */
  colorAdjustProcess: function(binaryData, l) {
    for (var i = 0; i < l; i += 4) {
          var r = binaryData[i];
          var g = binaryData[i + 1];
          var b = binaryData[i + 2];

          binaryData[i] = (r * 0.272) + (g * 0.534) + (b * 0.131);
          binaryData[i + 1] = (r * 0.349) + (g * 0.686) + (b * 0.168);
          binaryData[i + 2] = (r * 0.393) + (g * 0.769) + (b * 0.189);
      }
  },

  /**
   * deep clone image data of canvas
   * 
   * @param context
   * @param src
   * @returns
   */
  copyImageData: function(context, src)
  {
      var dst = context.createImageData(src.width, src.height);
      dst.data.set(src.data);
      return dst;
  },

  /**
   * convolution - keneral size 5*5 - blur effect filter(模糊效果)
   * 
   * @param context
   * @param canvasData
   */
  blurProcess: function(context, canvasData) {
    console.log("Canvas Filter - blur process");
    var tempCanvasData = this.copyImageData(context, canvasData);
    var sumred = 0.0, sumgreen = 0.0, sumblue = 0.0;
    for ( var x = 0; x < tempCanvasData.width; x++) {    
            for ( var y = 0; y < tempCanvasData.height; y++) {    

                // Index of the pixel in the array    
                var idx = (x + y * tempCanvasData.width) * 4;       
                for(var subCol=-2; subCol<=2; subCol++) {
                  var colOff = subCol + x;
                  if(colOff <0 || colOff >= tempCanvasData.width) {
                    colOff = 0;
                  }
                  for(var subRow=-2; subRow<=2; subRow++) {
                    var rowOff = subRow + y;
                    if(rowOff < 0 || rowOff >= tempCanvasData.height) {
                      rowOff = 0;
                    }
                    var idx2 = (colOff + rowOff * tempCanvasData.width) * 4;    
                      var r = tempCanvasData.data[idx2 + 0];    
                      var g = tempCanvasData.data[idx2 + 1];    
                      var b = tempCanvasData.data[idx2 + 2];
                      sumred += r;
                      sumgreen += g;
                      sumblue += b;
                  }
                }

                // calculate new RGB value
                var nr = (sumred / 25.0);
                var ng = (sumgreen / 25.0);
                var nb = (sumblue / 25.0);

                // clear previous for next pixel point
                sumred = 0.0;
                sumgreen = 0.0;
                sumblue = 0.0;

                // assign new pixel value    
                canvasData.data[idx + 0] = nr; // Red channel    
                canvasData.data[idx + 1] = ng; // Green channel    
                canvasData.data[idx + 2] = nb; // Blue channel    
                canvasData.data[idx + 3] = 255; // Alpha channel    
            }
    }
  },

  /**
   * after pixel value - before pixel value + 128
   * 浮雕效果
   */
  reliefProcess: function(context, canvasData) {
    console.log("Canvas Filter - relief process");
    var tempCanvasData = this.copyImageData(context, canvasData);
    for ( var x = 1; x < tempCanvasData.width-1; x++) 
    {    
            for ( var y = 1; y < tempCanvasData.height-1; y++)
            {    

                // Index of the pixel in the array    
                var idx = (x + y * tempCanvasData.width) * 4;       
        var bidx = ((x-1) + y * tempCanvasData.width) * 4;
        var aidx = ((x+1) + y * tempCanvasData.width) * 4;

                // calculate new RGB value
                var nr = tempCanvasData.data[aidx + 0] - tempCanvasData.data[bidx + 0] + 128;
                var ng = tempCanvasData.data[aidx + 1] - tempCanvasData.data[bidx + 1] + 128;
                var nb = tempCanvasData.data[aidx + 2] - tempCanvasData.data[bidx + 2] + 128;
                nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr);
                ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng);
                nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb);

                // assign new pixel value    
                canvasData.data[idx + 0] = nr; // Red channel    
                canvasData.data[idx + 1] = ng; // Green channel    
                canvasData.data[idx + 2] = nb; // Blue channel    
                canvasData.data[idx + 3] = 255; // Alpha channel    
            }
    }
  },

  /**
   *   before pixel value - after pixel value + 128
   *  雕刻效果
   * 
   * @param canvasData
   */
  diaokeProcess: function(context, canvasData) {
    console.log("Canvas Filter - process");
    var tempCanvasData = this.copyImageData(context, canvasData);
    for ( var x = 1; x < tempCanvasData.width-1; x++) 
    {    
            for ( var y = 1; y < tempCanvasData.height-1; y++)
            {    

                // Index of the pixel in the array    
                var idx = (x + y * tempCanvasData.width) * 4;       
        var bidx = ((x-1) + y * tempCanvasData.width) * 4;
        var aidx = ((x+1) + y * tempCanvasData.width) * 4;

                // calculate new RGB value
                var nr = tempCanvasData.data[bidx + 0] - tempCanvasData.data[aidx + 0] + 128;
                var ng = tempCanvasData.data[bidx + 1] - tempCanvasData.data[aidx + 1] + 128;
                var nb = tempCanvasData.data[bidx + 2] - tempCanvasData.data[aidx + 2] + 128;
                nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr);
                ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng);
                nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb);

                // assign new pixel value    
                canvasData.data[idx + 0] = nr; // Red channel    
                canvasData.data[idx + 1] = ng; // Green channel    
                canvasData.data[idx + 2] = nb; // Blue channel    
                canvasData.data[idx + 3] = 255; // Alpha channel    
            }
    }
  },

  /**
   * mirror reflect
   * 
   * @param context
   * @param canvasData
   */
  mirrorProcess : function(context, canvasData) {
    console.log("Canvas Filter - process");
    var tempCanvasData = this.copyImageData(context, canvasData);
    for ( var x = 0; x < tempCanvasData.width; x++) // column
    {    
            for ( var y = 0; y < tempCanvasData.height; y++) // row
            {    

                // Index of the pixel in the array    
                var idx = (x + y * tempCanvasData.width) * 4;       
        var midx = (((tempCanvasData.width -1) - x) + y * tempCanvasData.width) * 4;

                // assign new pixel value    
                canvasData.data[midx + 0] = tempCanvasData.data[idx + 0]; // Red channel    
                canvasData.data[midx + 1] = tempCanvasData.data[idx + 1]; ; // Green channel    
                canvasData.data[midx + 2] = tempCanvasData.data[idx + 2]; ; // Blue channel    
                canvasData.data[midx + 3] = 255; // Alpha channel    
            }
    }
  },
};

总结

感谢阅读,如果你觉得我今天分享的内容,不错,请点一个赞,谢谢!!