canvas學習總結三:繪製路徑-線段

来源:http://www.cnblogs.com/beevesnoodles/archive/2017/06/18/7045018.html
-Advertisement-
Play Games

Canvas繪圖環境中有些屬於立即繪製圖形方法,有些繪圖方法是基於路徑的。 立即繪製圖形方法僅有兩個strokeRect(),fillRect(),雖然strokezText(),fillText()方法也是立即繪製的,但是文本不算是圖形。 基於路徑的繪製系統 大多數繪製系統,如:SVG(Scala ...


Canvas繪圖環境中有些屬於立即繪製圖形方法,有些繪圖方法是基於路徑的。

立即繪製圖形方法僅有兩個strokeRect(),fillRect(),雖然strokezText(),fillText()方法也是立即繪製的,但是文本不算是圖形。

基於路徑的繪製系統
大多數繪製系統,如:SVG(Scalable Verctor Graphics, 可縮放的矢量圖形),Adobe Illustrator等,都是基於路徑的,

使用這些繪製系統時,你需要先定義一個路徑,然後再對其進行描邊或填充,也可以描邊加填充這樣圖形才能顯示出來。

Canvas中的三種繪製方式:

 

繪製一條線段

 

Canvas繪圖環境中,線段也是基於路徑繪製的,稱為線性路徑,創建線性路徑的方法:moveTO()與lineTo(),在創建路徑之後調用stroke()方法,才能在Canvas中畫出線段出來。

這就是前面我們所說的基於路徑的繪製方法,必須對其進行描邊或者填充;

通常兩點連一線因此繪製線段非常簡單,通過moveTO()指定線的起點,通過lineTo()移動到另一個點。

function drawLine(){
    cxt.moveTo(50, 50);
    cxt.lineTo(100, 100);
}

然而這樣我們在畫布中是看不見線段的,前面我們說到基於路徑的繪製方法,必須要描邊或者填充。所以要想看到結果,我們必須還要使用stroke()方法。

因此我們把方法修改成下麵這樣就會繪製出一條線段

function drawLine(){
    cxt.moveTo(50, 50);
    cxt.lineTo(200, 200);
    cxt.stroke();
}

我們只使用lineTo()也是能在畫布中繪製出線段的,我們把上面的代碼改成如下麵所示,效果也是一樣的

function drawLine(){
    cxt.lineTo(50, 50);
    cxt.lineTo(200, 200);
    cxt.stroke();
}

總結下moveTo()與lineTo()的用法

  • moveTo(x,y): 將筆觸移動到指定的坐標x以及y上,向當前路徑中增加一條子路徑,該方法不會清除當前路徑中的任何子路徑。
  • lineTo(x,y): 繪製一條從當前位置到指定x以及y位置的直線,如果當前路徑中沒有子路徑,那麼這個方法的行為與moveTo()一樣。如果當前路徑中存在子路徑,此方法會將你所指定的這個點加入子路徑中。

改變線段的樣式

改變線段的寬度

 

function= 14;
    cxt.lineTo(50, 50);
    cxt.lineTo(200, 200);
    cxt.stroke();
}

 

改變線段的顏色

function drawLine(){
    cxt.lineWidth = 14;
    cxt.strokeStyle = 'green';
    cxt.lineTo(50, 50);
    cxt.lineTo(200, 200);
    cxt.stroke();
}

 

我們還可以利用CanvasGradient對象或者CanvasPattern對象給線段添加漸變色或圖案

function drawLine(){
    cxt.lineWidth = 14;
    var gradient = cxt.createLinearGradient(0, 0, canvas.width/2, canvas.height/2);
    gradient.addColorStop(0, 'blue');
    gradient.addColorStop(0.5, 'purple');
    gradient.addColorStop(1, 'yellow');
    cxt.strokeStyle = gradient;
    cxt.lineTo(50, 50);
    cxt.lineTo(200, 200);
    cxt.stroke();
}

 

beginPath()與closePath()

從上面canvas中的三種繪製方式中我們可以看出,第二行的弧形路徑是開放路徑,最後一行的弧形是封閉路徑。那麼封閉的路徑是怎麼實現的呢?

下麵我們來看看canvas中路徑繪製中兩個比較重要的方法

  • beginPath(): 清除當前所有子路徑,以此來重置當前路徑,重新規劃一條路徑。
  • closePath(): 用於封閉某段開放路徑。不是必需的,如果圖形是已經閉合了的,即當前點為開始點,該函數什麼也不做。

先繪製出一條折線

function drawLine(){
    cxt.strokeStyle = 'green';
    cxt.lineWidth = 2;
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.lineTo(150, 150);
    cxt.stroke();
}

修改上面例子中的代碼在代碼中添加beginPath()與closePath()方法

function drawLine(){
    //描邊三角形
    cxt.strokeStyle = 'green';
    cxt.lineWidth = 2;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.stroke();
    cxt.beginPath();
    cxt.lineTo(150, 150);
    cxt.lineTo(150, 250);
    cxt.stroke();
  cxt.closePath();
}

可以看出我們在畫布中繪製了兩條路徑

註意:調用beginPath()之後,或者canvas剛建的時候,第一條路徑構造命令通常被視為是moveTo()。所以我們在繪製圖形的時候一定要先使用beginPath()。

 

我們繼續修改我們的代碼

function drawLine(){
    //描邊三角形
    cxt.strokeStyle = 'green';
    cxt.lineWidth = 2;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.lineTo(150, 150);
    cxt.closePath();
    cxt.stroke();
    //折線
    cxt.translate(150, 0);
    cxt.strokeStyle = 'red';
    cxt.lineWidth = 2;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.lineTo(150, 150);
    cxt.stroke();
    cxt.closePath();
    //綠色填充三角形
    cxt.translate(150, 0);
    cxt.fillStyle = 'green';
    cxt.lineWidth = 2;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.lineTo(150, 150);
    cxt.fill();
    cxt.closePath();
    //紅色填充三角形
    cxt.translate(150, 0);
    cxt.fillStyle = 'red';
    cxt.lineWidth = 2;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(50, 150);
    cxt.lineTo(150, 150);
    cxt.closePath();
    cxt.fill();
}

從上面的例子我們可以看出closePath()的位置不同,也會影響我們的圖形

註意:當你調用fill()函數時,所有沒有閉合的形狀都會自動閉合,所以此時closePath()函數不是必須的。

但是調用stroke():如果你在stroke()方法之前只用closePath()會形成閉合路徑,如果在stroke()方法之後調用closePath()方法,此時圖形已經繪製完成,當前的繪製路徑已經關閉,所以closePath()方法不起作用。

 

線段與像素邊界

先來看一個例子

function drawLine(){
    //描邊三角形
    cxt.lineWidth = 1;
    cxt.beginPath();
    cxt.moveTo(50, 50);
    cxt.lineTo(450, 50);
    cxt.stroke();
    cxt.beginPath();
    cxt.moveTo(50.5, 150.5);
    cxt.lineTo(450.5, 150.5);
    cxt.stroke();
}

 

從圖中我們可以看出,我們將兩條線段的lineWidth都是設置為1像素,但是上面的線段畫出的卻是兩像素。

 

如果你在某2個像素的邊界處繪製一條1像素寬的線段,那麼該線段實際會占據2個像素的寬度;

因為當你在像素邊界處繪製一條1像素寬度的垂直線段時,canvas的繪圖環境對象會試著將半個像素畫在邊界中線的右邊,將另外半個像素畫在邊界中線的左邊。

然而,在一個整像素的範圍內繪製半個像素寬的線段是不可能的,所以在左右兩個方向上的半個像素都被擴展為1個像素。

 

另外一方面,繪製在兩個像素之間,這樣的話,中線左右兩端的那半個像素就不會延伸,它們結合起來恰好占據1個像素的寬度。所以說,如果要繪製一條真正1像素寬度的線段,你必須將該線段繪製在某兩個像素之間

 

網格的繪製

既然我們已經明白瞭如何繪製真正的1像素的線段,那我們就開始繪製網格

function drawLine(stepx, stepy){
    cxt.lineWidth = 0.5;
    cxt.strokeStyle = 'green';
    //繪製豎線
    for(var i= stepx + 0.5; i< cxt.canvas.width; i+= stepx){
        cxt.beginPath();
        cxt.moveTo(i, 0);
        cxt.lineTo(i, cxt.canvas.height);
        cxt.stroke();
    }
    //繪製橫線
    for(var i= stepy + 0.5; i< cxt.canvas.height; i+= stepy){
        cxt.beginPath();
        cxt.moveTo(0, i);
        cxt.lineTo(cxt.canvas.width, i);
        cxt.stroke();
    }
}
drawLine(10, 10);

上面例子中我們將線段繪製在兩個像素之間的像素上,而且繪製出來的線段僅有0.5像素寬,

雖說canvas規範沒有明文規定,不過所有瀏覽器的Canvas實現都使用了“抗鋸齒”技術,以便創建出“亞像素”線段的繪製效果來

 

總結

本節內容主要講解canvas中路徑中線性路徑的繪製方法,主要是利用 moveTo()定義起點,lineTo()定義終點,stroke()描繪當前路徑。這三個方法繪製線段

canvas中繪製路徑有兩個重要的方法,beginPath()與closePath()。繪製圖形之前先調用beginPath()是繪製多個圖形必要的步驟。

closePath()在使用fill()時是可以省略的,而且還要註意closePath()方法的調用位置。

繪製線段時我們可以使用 lineWidth改變線段的寬度,strokeStyle改變線段的顏色。

弄清楚線段的像素邊界,這樣我們才能繪製出真正的1像素線寬的線段。


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

-Advertisement-
Play Games
更多相關文章
  • 『設計模式』中有一個模式可以解釋特定的語法規則,它就是解釋器模式(Interpreter Pattern)。不同於常見的策略模式或者是工廠模式,解釋器模式在.NET或者JDK中並不常見,而且在業務上也很少會去解釋特定的語法,所以它並不被廣泛使用。一個解釋器可大可小,大可以是複雜的編譯器,小也可以是一 ...
  • 隊列 定義 :隊列是一種特殊的線性表,特殊之處在於它只允許在表的前端(head)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。 按照隊列的定義,結合記憶體地址的理解,初始化隊列的時候,準備 和`rear ...
  • A 調用攝像頭拍照,自定義裁剪編輯頭像,頭像圖片色度調節B 集成代碼生成器 [正反雙向](單表、主表、明細表、樹形表,快速開發利器)+快速表單構建器 freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表sql腳本,處理類,service等完整模塊C 集成阿裡巴巴資料庫連接池 ...
  • css選擇器一個可以選擇樣式的工具, 這裡適用於無論是內部代碼還是外部引用 abc.css 這類型的文件. 基本選擇器*{ }就是一個簡單的*, 代表應用於全部. 不適合於個性化細緻化處理的頁面, 副作用是它會覆蓋原有的style, 不管好壞 *和繼承無關, 無論是否一級標簽,是否子標簽, 一律收到... ...
  • ES 2015/6 新增內容還是比較多的,這裡僅大綱性的列舉一下(不一定全面)這些特性。其實,每個點挖進去都會有很多學問在裡頭,本文旨在彙總,所以不對這些特性進行深層次的討論及研究。隨後有時間的話,在單獨寫幾篇博客對常用的點進行深挖,與大家進行深度交流。 ...
  • ::before與::after兩個偽元素其實是CSS3中的內容,然而實際上在CSS2中就已經有了這兩者的身影,只不過CSS2中是前面加一個冒號來表示(:before和:after)。今天主要講講這兩個偽元素該如何使用。 一、與普通元素一樣可以給其添加樣式 比如說我想在文字前面添加一個圖標,如果我用 ...
  • 本文提到的網站性能指網站的響應速度,這也符合絕大部分人對於網站性能的理解:訪問快速的網站性能好,反之,訪問速度越慢,則網站性能越差。本文總結的優化方法是巨集觀的工程層面的方法,並不包含微觀的語言語法層面的方法,例如,JS、CSS的語法優化,這一部分同樣影響網站的性能,但語言語法層面的優化更多的是取決於 ...
  • 雖然時間軸早已不是什麼新鮮事物了,個人只是感興趣所以就研究一下,最近從網上搜索了一個個人感覺比較好的時間軸demo,下載下來研究了一下並做了下修改.具體的效果如下圖:(該demo實現的是滾動載入圖片) 代碼地址:http://files.cnblogs.com/files/cby-love/html ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...