整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          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    
                      }
              }
            },
          };

          總結

          感謝閱讀,如果你覺得我今天分享的內容,不錯,請點一個贊,謝謝!!


          主站蜘蛛池模板: 亚洲高清一区二区三区| 久久精品人妻一区二区三区| 伊人久久精品一区二区三区| 国产一区二区免费| 国产成人久久精品一区二区三区 | 中文字幕av日韩精品一区二区 | 国产精品99精品一区二区三区| 成人免费一区二区无码视频| 一区二区视频在线播放| 综合久久一区二区三区| 一区二区三区四区在线播放| 精品人妻无码一区二区三区蜜桃一 | 久久伊人精品一区二区三区| 精品视频在线观看你懂的一区 | 精品久久一区二区三区| 香蕉免费看一区二区三区| 精品一区二区三区电影| 日韩精品一区二区三区中文版| 中文字幕无码不卡一区二区三区| 亚洲福利一区二区| 亚洲色无码一区二区三区| 国产一区二区三区久久| 亚洲AV综合色一区二区三区| 亲子乱AV视频一区二区| 成人影片一区免费观看| 久久国产精品一区| 久久精品一区二区三区日韩| 蜜桃传媒视频麻豆第一区| 国产精品va无码一区二区| 日韩精品无码一区二区三区| 色狠狠一区二区三区香蕉| 亚洲va乱码一区二区三区| 中文字幕人妻第一区| 午夜一区二区免费视频| 色一情一乱一伦一区二区三区日本| 精品乱人伦一区二区| 亚洲一区二区三区在线观看精品中文| 中文字幕AV一区中文字幕天堂| 精品三级AV无码一区| 国产精品久久无码一区二区三区网| 日韩一区二区三区在线|