canvas圖形處理和進階用法

来源:http://www.cnblogs.com/xiaohuochai/archive/2017/08/23/7418664.html
-Advertisement-
Play Games

[1]圖形變換 [2]矩陣變換 [3]全局陰影 [4]全局透明 [5]圖形合成 [6]裁剪區域 [7]圖像繪製 [8]使用圖像數據 [9]模式 [10]非零環繞 [11]交互 ...


前面的話

  上一篇博客介紹了canvas基礎用法,本文將更進一步,介紹canvas的圖形處理和進階用法

 

圖形變換

  圖形變換是指用數學方法調整所繪形狀的物理屬性,其實質是坐標變形。所有的變換都依賴於後臺的數學矩陣運算。談到圖形變換,不得不得說的三個基本變換方法就是

平移變換:translate(x,y)
旋轉變換:rotate(deg)
縮放變換:scale(sx,sy)

【translate()】

  translate(x,y):將坐標原點移動到(x,y)。執行這個變換之後,坐標(0,0)會變成之前由(x,y)表示的點

  平移變換,顧名思義,就是一般的圖形位移。比如這裡想將位於(100,100)的矩形平移至(200,200)點。那麼只要在繪製矩形之前加上context.translate(100,100)即可

  下麵結合代碼來看看效果

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d'); 

    context.beginPath();
    context.fillStyle = "#00AAAA";
    context.fillRect(0,0,100,50);

    context.fillStyle = "red";
    context.translate(50,50);
    context.fillRect(0,0,100,50);
}
</script>

  青藍色矩形通過調用translate()方法後,將矩形向右移動了(50,50),並變成了紅色,尺寸不改變

  想把矩形再向右移動(50,50),應該使用translate(50,50),還是從最開始算起,使用traslate(100,100)呢?

<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.fillStyle = "#00AAAA";
    context.fillRect(0,0,100,50);

    context.fillStyle = "red";
    context.translate(50,50);
    context.fillRect(0,0,100,50);

    context.fillStyle = "lightblue";
    context.translate(50,50);
    context.fillRect(0,0,100,50);
}
</script>

  由結果可知,使用translate(50,50)即可實現,依照translate()的定義,第一次進行translate()變換時,已經變換了坐標系的原點,這次是基於新坐標系又一次地變換

【狀態保存】

  由於多次運行變換後,坐標系可能就亂套了,所以最好以最初狀態為參照物。這時就需要用到save()和resore()方法

  save()方法可以保存當前環境的狀態,並返回某組屬性與變換的組合。所有設置都會進入一個棧結構,得以妥善保管

  restore()方法可以在保存設置的棧結構中向前返回一級,恢復之前保存過的路徑狀態和屬性。連續調用save()方法可以把更多設置保存到棧結構中,之後再連續調用restore()方法可以一級一級返回

   如果使用狀態保存,則代碼如下所示

<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.fillStyle = "#00AAAA";
    context.fillRect(0,0,100,50);

    context.save();
    context.fillStyle = "red";
    context.translate(50,50);
    context.fillRect(0,0,100,50);
    context.restore();

    context.save();
    context.fillStyle = "lightblue";
    context.translate(100,100);
    context.fillRect(0,0,100,50);
    context.restore();
}
</script>

  這樣,每次圖形變換,都以(0,0)點為基準,不會造成坐標系的混亂

【rotate()】

  rotate(angle):圍繞原點旋轉圖像angle弧度

  同畫圓弧一樣,這裡的rotate(deg)傳入的參數是弧度,不是角度。同時需要註意的是,這個的旋轉是以坐標系的原點(0,0)為圓心進行的順時針旋轉。所以,在使用rotate()之前,通常需要配合使用translate()平移坐標系,確定旋轉的圓心。即,旋轉變換通常搭配平移變換使用的。

  最後一點需要註意的是,Canvas是基於狀態的繪製,所以每次旋轉都是接著上次旋轉的基礎上繼續旋轉,所以在使用圖形變換的時候必須搭配save()restore()方法,一方面重置旋轉角度,另一方面重置坐標系原點

  下麵是一個例子

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.fillStyle = "#00AAAA";
    context.fillRect(0,0,50,50);
context.save(); context.fillStyle
= "red"; context.rotate(30*Math.PI/180); context.fillRect(0,0,50,50); context.restore();
context.save(); context.fillStyle
= "green"; context.rotate(60*Math.PI/180); context.fillRect(0,0,50,50); context.restore(); } </script>

  由結果可知,元素是圍繞原點進行順時針旋轉rotate的

   下麵以元素左上角為圓心進行旋轉

<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.fillStyle = "#00AAAA";
    context.fillRect(30,30,50,50);

    context.save();
    context.fillStyle = "red";
    context.translate(30,30);
    context.rotate(30*Math.PI/180);
    context.fillRect(0,0,50,50);
    context.restore();  

    context.save();
    context.fillStyle = "lightgreen";
    context.translate(30,30);
    context.rotate(60*Math.PI/180);
    context.fillRect(0,0,50,50);
    context.restore(); 
}
</script>

  下麵以元素中心點為圓心進行旋轉,會出現如下所示神奇的效果

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.fillStyle = "rgba(255,0,0,0)";
    context.fillRect(45,45,50,50);
    for(var i = 1; i <=10; i++){
      context.save();
      context.fillStyle = "rgba(255,0,0,0.25)";
      context.translate(70,70);
      context.rotate(i*36*Math.PI/180);
      context.fillRect(0,0,50,50);
      context.restore();   
    }
}
</script>

【scale()】

  scale(scaleX,scaleY):縮放圖像,在x方向上乘以scaleX,在Y方向上乘以scaleY。scaleX和scaleY的預設值是1

  context.scale(2,2)就是對圖像放大兩倍。看上去簡單,實際用起來還是有一些問題的。先來看一段代碼

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
    context.beginPath();
    context.lineWidth = 3;
    context.strokeRect(10,10,50,50);
    for(var i = 1; i <= 2; i++){
      context.save();
      context.scale(i,i);
      context.strokeRect(20,20,50,50);
      context.restore();
    }
}
</script>

  結果如下,左上角頂點的坐標變了,而是線條的粗細也變了

  因此,對於縮放變換有兩點問題需要註意:

  1、縮放時,圖形左上角坐標的位置也會對應縮放

  2、縮放時,圖像線條的粗細也會對應縮放

 

矩陣變換

  上面所說的坐標變換的三種方式——平移translate(),縮放scale(),以及旋轉rotate()都可以通過transform()做到

  在介紹矩陣變換transform()前,先來介紹下什麼是變換矩陣

  [註意]關於transform的詳細介紹,移步CSS3的transform介紹

  以上是Canvas中transform()方法所對應的變換矩陣

【transform()】

  而此方法正是傳入圖中所示的六個參數,具體為context.transform(a,b,c,d,e,f)

  各參數意義對應如下表:

參數    意義
a    水平縮放(1)
b    水平傾斜(0)
c    垂直傾斜(0)
d    垂直縮放(1)
e    水平位移(0)
f    垂直位移(0)

  建議使用transform()的時候,可以在如下幾個情況下使用:

  1、使用context.transform (1,0,0,1,dx,dy)代替context.translate(dx,dy)

  2、使用context.transform(sx,0,0,sy,0,0)代替context.scale(sx, sy)

  3、使用context.transform(1,tany,tanx,1,0,0)來實現傾斜效果

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');

    context.beginPath();
    context.lineWidth = 3;
    context.strokeRect(10,10,50,50);

    context.save();
    context.transform (1,0,0,1,30,30);
    context.strokeStyle = 'pink';
    context.strokeRect(0,0,50,50);
    context.restore();

    context.save();
    context.transform(2,0,0,2,0,0)
    context.strokeStyle = 'lightblue';
    context.strokeRect(50,10,50,50);
    context.restore();

    context.save();
    context.transform(1,0,Math.tan(30*Math.PI/180),1,0,0);
    context.strokeStyle = 'lightgreen';
    context.strokeRect(200,10,50,50);
    context.restore();
} 
</script>

【setTransform()】

  setTransform():將變換矩陣重置為預設狀態,然後再調用transform()

  transform()方法的行為相對於由 rotate(),scale()translate(), or transform() 完成的其他變換。例如:如果已經將繪圖設置為放到兩倍,則 transform() 方法會把繪圖放大兩倍,那麼繪圖最終將放大四倍。這一點和之前的變換是一樣的。

  但是setTransform()不會相對於其他變換來發生行為。它的參數也是六個,context.setTransform(a,b,c,d,e,f),與transform()一樣

  當前面的代碼已經使用了多個transform()、translate()、rotate()、scale()等變換方法,無法輕易地從當前的矩陣變化到想要的矩陣時,就可以使用setTransform()方法將矩陣重置為預設狀態,然後再調用transform()

cxt.transform(1,0,0,1,50,100);
cxt.transform(2,0,0,1.5,0,0);
cxt.transform(1.-0.2,-0.2,1,0,0);
cxt.setTransform(1,0,0,1,100,100);

 

全局陰影

  2D上下文會根據以下4個屬性的值自動為形狀或路徑繪製出陰影

  [註意]關於CSS陰影box-shadow的詳細情況移步至此

shadowColor:      用CSS顏色格式表示的陰影顏色(預設為黑色)    
shadowOffsetX:    形狀或路徑x軸方向的陰影偏移量(預設為0)
shadowOffsetY:    形狀或路徑y軸方向的陰影偏移量(預設為0)
shadowBlur:       模糊的像素數(預設為0,即不模糊)

  這四個屬性只要設置了第一個和剩下三個中的任意一個就有陰影效果。不過通常情況下,四個屬性都要設置

  [註意]要先設置陰影,再繪製圖形

  下麵代碼創建一個向右下方位移各5px的紅色陰影,模糊2px

<canvas id="drawing" style="border:1px solid black">
    <p>The canvas element is not supported!</p>
</canvas>
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');

    context.shadowColor = "red";
    context.shadowOffsetX = 5;
    context.shadowOffsetY = 5;
    context.shadowBlur= 2;

    context.fillStyle = 'lightblue';
    context.fillRect(10,10,100,100);
} 
</script>

  下麵是一個文字陰影的效果

  [註意]關於CSS3屬性文本陰影text-shadow的詳細情況移步至此

<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');

    context.shadowColor = "rgba(0,0,0,0.5)";
    context.shadowOffsetX = 5;
    context.shadowOffsetY = 5;
    context.shadowBlur= 2;
    context.font= '30px 微軟雅黑';
    context.fillText("小火柴的藍色理想",40,60); 
} 
</script>

 

全局透明

  全局透明globalAlpha是一個介於0和1之間的屬性值(包括0和1),用於指定所有繪製的透明度(預設值為1)。如果後續所有操作都基於相同透明度,可以先把globalAlpha設置為適當值,然後繪製,最後再設置回預設值1

  [註意]全局透明globalAlpha也是一個基於狀態的屬性,所以需要先設置該屬性,再繪製圖形

<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
    var context = drawing.getContext('2d');
 
    context.fillStyle = 'lightblue';
    context.fillRect(10,10,100,100);

    context.globalAlpha = 0.5;
    context.fillStyle = 'lightb

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 實例搜索應用 實現效果: 實現代碼與註釋: ...
  • 一、<meta>標簽的定義和用法 <meta> 元素可提供有關頁面的元信息(meta-information),位於文檔的頭部<head>和</head>之間,不包含任何內容。<meta> 標簽的屬性定義了與文檔相關聯的名稱/值對。 二、<meta>標簽的屬性 1.必要屬性 2.可選屬性 conte ...
  • JSON創建鍵值對(key是中文或者數字)方式詳解 先準備好一個空的json對象 1. 最原始的方法 2. 使用json[key]的方式(這邊key即使是中文也沒事) 3.使用json['key']的方式 "JSON取值方式(key為數字或者字元串)詳解" ...
  • node的非同步io雖然好用,但是控制非同步流程確實一個比較麻煩的事情,比如在爬蟲中控制併發數量,避免併發過大導致網站宕機或被加入黑名單。因此需要一個工具來控制併發,這個工具可以自己寫或者使用async(官方文檔點擊這裡)。代碼基於node 8.x,如版本過低可能會出現錯誤。 說明 async本身有七十 ...
  • 接觸 npm 也有一個多月的時間了,一直只是將他作為當著 webstorm + node.js 環境中的一個插件來用(甚至說把她當著命令來用)。畢竟大部分的時間,他是輸入的命令行中的一部分(別笑,小新人真的會存在這個問題)。這幾天決定好好整理一下關於 npm ,收藏在這了。 1、安裝 現在 npm ...
  • 前端(轉換): var param = XXXXXXXXXXXXXXXXXX; param = decodeURIComponent(param,true); param = encodeURI(param, "UTF-8"); $.post('<%=request.getContextPath() ...
  • 這篇博文有關css的權重問題,我個人認為這是css知識中很重要的一個知識點。因為在開發的過程能中我們會經常遇到這種問題,特別是如果你使用框架的時候,有些框架的某些標簽有一些預設的樣式。所以我們可以通過增加權重的方式來使我們所寫的樣式有效。既然說到權重那就必然要說起權重的等級以及權重值。 css的權重 ...
  • 1、jQuery基礎 Jquery它是一個庫(框架),要想使用它,必須先引入! jquery-1.8.3.js:一般用於學習階段。 jquery-1.8.3.min.js:用於項目使用階段 官網下載後,複製到當前WEB項目的js文件夾下,如下: 引入代碼:<script type="text/jav ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...