摘要:對(duì)于平行線來(lái)說(shuō),仿射變換也會(huì)保持平行。仿射變換用個(gè)參數(shù)描述成為如下表述通過(guò)傳入?yún)?shù)實(shí)現(xiàn)仿射變換對(duì)于坐標(biāo)變換來(lái)說(shuō),除非進(jìn)行刷新,否則,已經(jīng)繪制的圖形,不會(huì)進(jìn)行消失,所有的變換,都不能對(duì)已經(jīng)繪制的圖形進(jìn)行更改。
介紹
SVG是構(gòu)建XML樹的方式來(lái)達(dá)到繪制圖形的,canvas是通過(guò)調(diào)用相關(guān)的方法來(lái)繪制圖形的。
區(qū)別:SVG繪制圖形,通過(guò)移除或者更改DOM方式來(lái)而使用canvas需要把圖片從新擦除。
繪制的API在繪制上下文中定義。而不在畫布中定義。
需要獲得上下文對(duì)象的時(shí)候,需要調(diào)用畫布的getContext方法,獲得繪畫的上下文。
畫布元素和上下文,屬于兩個(gè)不同的對(duì)象,其中畫布元素為canvas畫布,而上下文對(duì)象為繪制需要的上下文。繪制圓關(guān)于3D圖形,即,webGL 為封裝了基本的OPENGL,當(dāng)調(diào)用webGL的時(shí)候,其瀏覽器會(huì)調(diào)用OpenGL相關(guān)的API
Title 第一個(gè)園第二個(gè)園
// 獲取畫布元素 let canvas = document.getElementById("square"); // 獲取繪制2D元素上下文 let context = canvas.getContext("2d"); // 設(shè)置填充顏色為紅色 context.fillStyle = "#f00"; // 填充一個(gè)正方形 context.fillRect(10,0,10,10);繪制線段,填充多邊形
// 獲取畫布元素 let canvas = document.getElementById("square"); // 獲取繪制2D元素上下文 let context = canvas.getContext("2d"); // 開始一條路徑 context.beginPath(); // 從100,100 開始定義一條新的子路徑 context.moveTo(100,100); // 從100 100 到 200 200 繪制一條線段 context.lineTo(200,200); // 從200 200 到 100 200 繪制一條線段 context.lineTo(100,200); // 從100 200 到 100 100 繪制一條路徑 context.lineTo(100,100); // 繪制邊 context.stroke(); // 進(jìn)行填充 context.fill();繪制多邊形
以五邊形為例子,
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 繪制一個(gè)以100,100為中心,半徑為20的柜子N變形,每個(gè)定點(diǎn)均勻分布在圓角上,第一個(gè)定點(diǎn)放置在最上下 // 偏轉(zhuǎn)角度為0 // 開始定義一條子路徑 context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0)); // 計(jì)算兩個(gè)頂點(diǎn)之間夾角 // 其中2π為一個(gè)園,除以邊數(shù),得到需要旋轉(zhuǎn)的角度 var delta = 2 * Math.PI/5; console.log(delta); // 循環(huán)剩余每個(gè)頂點(diǎn) var angle = 0; for(var i = 1; i < 5; i++){ // 角度累加 angle += delta; // 通過(guò)旋轉(zhuǎn)繪制下一個(gè)頂點(diǎn),不斷的旋轉(zhuǎn)繪制 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle)); } // 最后一個(gè)頂點(diǎn)和起點(diǎn)進(jìn)行連接 context.closePath(); // 從新開始一條新路徑 context.stroke(); context.fill();同理,畫圓
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 繪制一個(gè)以100,100為中心,半徑為20的柜子N變形,每個(gè)定點(diǎn)均勻分布在圓角上,第一個(gè)定點(diǎn)放置在最上下 // 偏轉(zhuǎn)角度為0 // 開始定義一條子路徑 context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0)); // 計(jì)算兩個(gè)頂點(diǎn)之間夾角 // 其中2π為一個(gè)園,除以邊數(shù),得到需要旋轉(zhuǎn)的角度 var delta = 2 * Math.PI/500000; console.log(delta); // 循環(huán)剩余每個(gè)頂點(diǎn) var angle = 0; for(var i = 1; i < 500000; i++){ // 角度累加 angle += delta; // 通過(guò)旋轉(zhuǎn)繪制下一個(gè)頂點(diǎn),不斷的旋轉(zhuǎn)繪制 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle)); } // 最后一個(gè)頂點(diǎn)和起點(diǎn)進(jìn)行連接 context.closePath(); // 從新開始一條新路徑 context.stroke(); context.fill();非零繞數(shù)原則
要檢測(cè)一個(gè)點(diǎn)p是否在路徑內(nèi)部,使用非零繞數(shù)原則,即,一條從點(diǎn)p出發(fā)沿著任意方向無(wú)限延伸,或者一直延伸到路徑所在的區(qū)域外某點(diǎn)的射線,現(xiàn)在從0開始初始化一個(gè)計(jì)數(shù)器,對(duì)穿過(guò)這條射線的路徑進(jìn)行枚舉,每當(dāng)一條路徑順時(shí)針?lè)较虼┻^(guò)射線的時(shí)候,計(jì)數(shù)器加1,逆時(shí)針減1,最后,枚舉完所有路徑以后,如果計(jì)時(shí)器的值不是0,那么就認(rèn)為p在路徑內(nèi),反過(guò)來(lái),計(jì)數(shù)器的值為0,p在路徑外。
js根據(jù)非零繞數(shù)原則確定那個(gè)在路徑內(nèi),那個(gè)在路徑外,用于進(jìn)行填充。
圖形屬性可以通過(guò)設(shè)置畫布上下文的fillStyle等屬性,設(shè)置圖形的屬性,例如對(duì)畫布上下文的fillStyle的屬性進(jìn)行設(shè)置,即,可以設(shè)置出填充時(shí)的顏色,漸變,圖案等樣式。
對(duì)于canvas來(lái)說(shuō),每次獲取上下文對(duì)象的時(shí)候,都會(huì)返回同一個(gè)上下文對(duì)象,即,上下文對(duì)象為單例的。
還可以使用save方法,把當(dāng)前的狀態(tài),壓入已經(jīng)保存的棧中,調(diào)用restore方法,把狀態(tài)進(jìn)行恢復(fù),即彈棧。
畫布尺寸坐標(biāo)畫布的默認(rèn)的坐標(biāo)系為左上角的坐標(biāo)原點(diǎn)(0,0),右邊數(shù)值大,下數(shù)值大,使用浮點(diǎn)數(shù)指定坐標(biāo),但不會(huì)自動(dòng)轉(zhuǎn)換為整數(shù),會(huì)用反鋸齒的方式,模擬填充部分元素。
畫布尺寸不能隨意改變,對(duì)任意屬性進(jìn)行操作,都會(huì)清空整個(gè)畫布。
坐標(biāo)系變換每一個(gè)點(diǎn)的坐標(biāo)都會(huì)映射到css像素上,css像素會(huì)映射到一個(gè)或多個(gè)設(shè)備像素。
畫布中的特定操作,屬性使用默認(rèn)坐標(biāo)系。
畫布還有當(dāng)前變換矩陣。
畫布還有當(dāng)前變換矩陣,當(dāng)前變換矩陣作為圖形狀態(tài)的一部分。矩陣定義了當(dāng)前畫布的坐標(biāo)系。
畫布的操作會(huì)把該點(diǎn)映射到當(dāng)前的坐標(biāo)系中。
當(dāng)調(diào)用c.translate(dx,dy)方法的時(shí)候,會(huì)進(jìn)行如下變換
translate會(huì)進(jìn)行坐標(biāo)的上下移動(dòng)
x" = x + dy; y" = y + dy;
縮放
如要進(jìn)行縮放,進(jìn)行的是如下的變換
x" = sx * x; y" = sy * y;
進(jìn)行旋轉(zhuǎn)操作,進(jìn)行的是如下變換
x" = x * cos(a) - y * sin(a); y" = y * cos(a) - x * sin(a);
如果要先變換再伸縮,進(jìn)行如下變換
需要先把現(xiàn)有坐標(biāo)系映射成為坐標(biāo)系中的點(diǎn)x’, y" 然后再變換到x‘’ , y‘’
x"" = sx*x + dx; y"" = sy*y + dy;
如果變換順序相反進(jìn)行如下變換
x"" = sx*(x + dx); y"" = sy*(y + dy);
這種變換稱為仿射變換,并且仿射變換會(huì)修改點(diǎn)的距離和線段間的夾角。對(duì)于平行線來(lái)說(shuō),仿射變換也會(huì)保持平行。仿射變換用6個(gè)參數(shù)描述成為如下表述
x" = ax + cy + e; y" = bx + dy + f;
通過(guò)傳入?yún)?shù)實(shí)現(xiàn)仿射變換
對(duì)于坐標(biāo)變換來(lái)說(shuō),除非進(jìn)行刷新,否則,已經(jīng)繪制的圖形,不會(huì)進(jìn)行消失,所有的變換,都不能對(duì)已經(jīng)繪制的圖形進(jìn)行更改。栗子如下
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 通過(guò)坐標(biāo)變換實(shí)現(xiàn)科赫雪花 // 開始一條路徑 context.beginPath(); // 開始繪制子路徑 context.moveTo(100,100); // 繼續(xù)繪制 context.lineTo(200,200); // 繼續(xù)繪制 context.lineTo(200,200); // 進(jìn)行繪制邊 context.stroke(); context.translate(200,200); // 開始一條路徑 context.beginPath(); // 開始繪制子路徑 context.moveTo(100,100); // 繼續(xù)繪制 context.lineTo(200,200); // 繼續(xù)繪制 context.lineTo(200,200); // 進(jìn)行繪制邊 context.stroke();
已經(jīng)繪制的圖形不會(huì)進(jìn)行改變,改變的是已經(jīng)繪制的圖形
科赫雪花var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 通過(guò)坐標(biāo)變換實(shí)現(xiàn)科赫雪花 // 當(dāng)前狀態(tài)入棧 function leg(n) { // 保存狀態(tài) context.save(); // 遞歸畫 if(n == 0){ context.lineTo(50, 0); }else{ // 定義為v字型 context.scale(1/2,1/2); // 遞歸第一條 context.rotate(60 * (Math.PI / 180)); leg(n - 1); context.rotate(-120 * (Math.PI / 180)); leg(n - 1); } // 坐標(biāo)恢復(fù)變換 context.restore(); // 恢復(fù)下一個(gè)坐標(biāo)為0,0 context.translate(50, 0); } context.save(); context.moveTo(50, 50); // 繪制第一條 leg(1); context.stroke();繪制填充曲線
繪制一些常見(jiàn)的圖形
var canvas = document.getElementById("square"); var context = canvas.getContext("2d"); // 工具函數(shù),角度轉(zhuǎn)弧度 function rads(x) { return Math.PI * x / 180; } // 繪制園 context.beginPath(); context.arc(100,100,40, 0, rads(360), false); context.stroke(); context.fill();
同理繪制貝塞爾曲線也是同理。
顏色,透明度,漸變,圖案繪制一個(gè)漸變
需要使用createLinearGradient獲取一個(gè)進(jìn)行漸變的上下文,對(duì)這個(gè)上下文進(jìn)行處理。然后其顏色設(shè)置為這個(gè)漸變的上下文,即,fillStyle屬性。
對(duì)于線段,有三種封頂方式,即,butt,square,round
在繪制圖形以后,會(huì)參數(shù)尖角,圓角,平角,三種。
lineCap屬性
和css類似,基線問(wèn)題。
裁剪直接調(diào)動(dòng)clip即可,當(dāng)前路徑也會(huì)被裁剪進(jìn)入,路徑外的統(tǒng)統(tǒng)不會(huì)顯示。
陰影設(shè)置shadow屬性即可
圖片畫布API支持位圖圖片,同時(shí)也支持canvas導(dǎo)出成為圖片。
// 創(chuàng)建一個(gè)img元素 let img = document.createElement("img"); // 設(shè)置src屬性 img.src = canvas.toDataURL(); // 追加到文檔后面 document.body.appendChild(img);合成
一些api不在闡述
像素操作調(diào)用getImageDate方法返回ImageDate對(duì)象
使用createImageDate()可以創(chuàng)建像素容器
進(jìn)行動(dòng)態(tài)模糊先獲取像素的ImageDate對(duì)象,然后再獲取該對(duì)象的data屬性,該data為一個(gè)數(shù)組。為一個(gè)維數(shù)組。每四個(gè)元素代表紅色分量,綠色分量,藍(lán)色分量,透明度分量。(Alpha分量)
其色素直為0-1,即,數(shù)組元素中保存的數(shù)組為色素值。
每四個(gè)每四個(gè)元素遍歷。然后把其色素值的1/ n + 上一個(gè)色塊的m/n 然后賦值給新的色塊,代碼如下
// row為行數(shù) for(var row = 0; row < height; row++){ // 獲得每行第二個(gè)元素的偏移量,其中width為行的色素塊。 var i = row * width * 4; // 每4個(gè)的色素值進(jìn)行處理 for(var col = 1; col < width; col++, i+=4){ // 對(duì)紅色分量處理 data[i] = (data[i] + data[i - 4] * m) / n; // 對(duì)綠色分量處理 data[i + 1] = (data[i + 1] + data[i + 1 - 4] * m) / n; // 對(duì)藍(lán)色分量處理 data[i + 2] = (data[i + 2] + data[i + 2 - 4] * m) / n; // 對(duì)透明度分量處理 data[i + 3] = (data[i + 3] + data[i + 3 - 4] * m) / n; } }
然后把其色素塊進(jìn)行復(fù)制回去即可。
其中每個(gè)像素占據(jù)一個(gè)字節(jié),一個(gè)四個(gè)字節(jié)。
isPointInPath方法用來(lái)確定一個(gè)點(diǎn)是否落在當(dāng)前路徑中。
即命中檢測(cè)。
命中檢測(cè)可以和鼠標(biāo)事件相互轉(zhuǎn)化
但是坐標(biāo)需要進(jìn)行轉(zhuǎn)換。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101601.html
摘要:已獲原作者授權(quán)原系列地址簡(jiǎn)介為提供了繪圖功能其提供的圖形組件包括線形圓形圖片甚至其他控件控件為繪制圖形圖表編輯圖形自定義控件提供了可能在第一個(gè)例子里我們將演示如何畫一條直線方法用來(lái)繪制一條直線為以整形表示的四個(gè)坐標(biāo)參數(shù)這表示所要繪制的直線連 已獲原作者授權(quán). 原系列地址: Python Tkinter 簡(jiǎn)介 Canvas 為 Tkinter 提供了繪圖功能. 其提供的圖形組件包括 線...
摘要:本次技術(shù)調(diào)研來(lái)源于項(xiàng)目中的一個(gè)重要功能需求實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。以下主要解決兩類跨域的圖片資源包括已配置過(guò)的中的圖片資源和微信用戶頭像圖片資源。 本次技術(shù)調(diào)研來(lái)源于H5項(xiàng)目中的一個(gè)重要功能需求:實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。 這里有個(gè)栗子(請(qǐng)用微信打開,長(zhǎng)按圖片即可保存):3分鐘探索你的知識(shí)邊界 將整個(gè)網(wǎng)頁(yè)保存為圖片是一個(gè)十分有趣的功能,常見(jiàn)于H5活動(dòng)頁(yè)的結(jié)尾頁(yè)分享。以下則是項(xiàng)目中...
摘要:本次技術(shù)調(diào)研來(lái)源于項(xiàng)目中的一個(gè)重要功能需求實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。以下主要解決兩類跨域的圖片資源包括已配置過(guò)的中的圖片資源和微信用戶頭像圖片資源。 本次技術(shù)調(diào)研來(lái)源于H5項(xiàng)目中的一個(gè)重要功能需求:實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。 這里有個(gè)栗子(請(qǐng)用微信打開,長(zhǎng)按圖片即可保存):3分鐘探索你的知識(shí)邊界 將整個(gè)網(wǎng)頁(yè)保存為圖片是一個(gè)十分有趣的功能,常見(jiàn)于H5活動(dòng)頁(yè)的結(jié)尾頁(yè)分享。以下則是項(xiàng)目中...
摘要:本次技術(shù)調(diào)研來(lái)源于項(xiàng)目中的一個(gè)重要功能需求實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。以下主要解決兩類跨域的圖片資源包括已配置過(guò)的中的圖片資源和微信用戶頭像圖片資源。 本次技術(shù)調(diào)研來(lái)源于H5項(xiàng)目中的一個(gè)重要功能需求:實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。 這里有個(gè)栗子(請(qǐng)用微信打開,長(zhǎng)按圖片即可保存):3分鐘探索你的知識(shí)邊界 將整個(gè)網(wǎng)頁(yè)保存為圖片是一個(gè)十分有趣的功能,常見(jiàn)于H5活動(dòng)頁(yè)的結(jié)尾頁(yè)分享。以下則是項(xiàng)目中...
摘要:今天講的內(nèi)容是和的區(qū)別,在沒(méi)有做項(xiàng)目之前,其實(shí)我是并沒(méi)有深入了解過(guò)這兩個(gè)屬性的,最近在研究項(xiàng)目的自適應(yīng)問(wèn)題,尤其是在中置入圖片,碰到了圖片模糊的問(wèn)題,這些雜癥都是和文章要講的有關(guān)系。最后,當(dāng)我們不指定的真實(shí)大小時(shí),默認(rèn)按照處理。 今天講的內(nèi)容是canvas.width和canvas.style.width的區(qū)別,在沒(méi)有做canvas項(xiàng)目之前,其實(shí)我是并沒(méi)有深入了解過(guò)這兩個(gè)屬性的,最近在...
摘要:本次技術(shù)調(diào)研來(lái)源于項(xiàng)目中的一個(gè)重要功能需求實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。小結(jié)是目前實(shí)現(xiàn)網(wǎng)頁(yè)保存為圖片功能的綜合最佳選擇。 本次技術(shù)調(diào)研來(lái)源于H5項(xiàng)目中的一個(gè)重要功能需求:實(shí)現(xiàn)微信長(zhǎng)按網(wǎng)頁(yè)保存為截圖。 這里有個(gè)栗子(請(qǐng)用微信打開,長(zhǎng)按圖片即可保存):3分鐘探索你的知識(shí)邊界 將整個(gè)網(wǎng)頁(yè)保存為圖片是一個(gè)十分有趣的功能,常見(jiàn)于H5活動(dòng)頁(yè)的結(jié)尾頁(yè)分享。以下則是項(xiàng)目中調(diào)研和踩坑的一些小結(jié)和匯總。 ...
閱讀 1599·2023-04-26 02:29
閱讀 3133·2021-10-11 10:58
閱讀 2925·2021-10-08 10:16
閱讀 3185·2021-09-24 09:47
閱讀 1593·2019-08-29 16:56
閱讀 2745·2019-08-29 11:03
閱讀 2030·2019-08-26 13:35
閱讀 3199·2019-08-26 13:34