日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


 

1、什么是Canvas?

html5 提供Canvas API,其本質上是一個DOM元素,可以看成是瀏覽器提供一塊畫布供我們在上面渲染2D或者3D圖形。由于3D繪制上下文(webgl)目前在很多瀏覽器上兼容性較差,所以我們一般用于繪制2D圖形。

2、為什么使用Canvas?

canvas是HTML5引入的標簽,在此之前我們通常會使用SVG來繪制一些圖形,那么兩者之間有什么區別呢?SVG可縮放矢量圖形(Scalable Vector Graphics)是基于可擴展標記語言XML描述的2D圖形的語言,兩者部分區別:

 

  • SVG 圖像是使用各種元素創建的,這些元素分別應用于矢量圖像的結構、繪制與布局;而Canvas本身并不描述圖像,而是通過JAVAscript完成繪制;
  • 如上所述,SVG本身是DOM元素,每一個描述元素也是DOM元素,瀏覽器在進行渲染時需要進行大量計算以處理每一個元素;而在渲染Canvas的過程中,瀏覽器只需要渲染一張畫布,其余的是通過JavaScript引擎執行邏輯來繪制;
  • SVG(矢量圖)不依賴分辨率,放大不會失真;而Canvas(位圖)依賴分辨率,放大會失真;

 

由于Canvas是通過Javascript來完成繪制的,所以可控性很強,我們可以比較精確的控制圖形渲染的每一幀;從另一方面來說,如果在高頻率渲染中要處理過多的DOM元素就意味著性能一定不會太好,渲染速度會下降很多。Canvas的高性能能夠保障復雜場景中圖形的渲染效率,所以目前很多領域都會使用Canvas,例如動畫、游戲圖形、數據可視化、照片處理和實時視頻處理等。


3、Canvas的基本使用

要使用Canvas,我們需要先獲取Canvas元素的引用繼而通過getContext()方法獲取圖形的繪制上下文。

const canvas = document.getElementById('canvas')const ctx = canvas.getContext('2d')

獲取到圖形繪制上下文后,我們就能使用CanvasRenderingContext2D接口上的繪圖API了,接下來我們可以了解一些比較常規的使用。

3.1、畫布屬性:

 

  • width、height:畫布的寬度以及高度,默認大小為300x150;
  • fillStyle:填充圖形的樣式,值可以是color string、CanvasGradient對象;
  • strokeStyle:輪廓圖形的樣式,值可以是color string、CanvasGradient對象;
  • lineWidth:繪制線條的寬度;
  • globalAlpha:畫布的透明度,0-1的偏移值;
  • globalCompositeOperation:畫布中新老圖形重疊時的渲染方式,默認為source-over,新圖形覆蓋老圖形;
  •  
ctx.width = 300ctx.height = 300ctx.fillStyle = '#fff'ctx.strokeStyle = 'blue'ctx.lineWidth = 5ctx.globalAlpha = 0.3ctx.globalCompositeOperation = 'destination-out' // 新老圖形重疊部分變透明

 

3.2、繪制圖形:

 

  • .fillRect(x,y,width,height):繪制一個填充的矩形,矩形左上角的坐標為(x,y),高寬分別為width、height;
  • .strokeRect(x,y,width,height):繪制一個矩形邊框,矩形左上角的坐標為(x,y),高寬分別為width、height;
  • .clearRect(x,y,width,height):清除指定矩形區域,讓清除部分完全透明;
ctx.fillStyle = 'red'ctx.fillRect(100,100,100,100)ctx.strokeStyle = 'blue'ctx.strokeRect(200,200,100,100)ctx.clearRect(125,125,50,50)ctx.strokeRect(130,130,40,40)

 


 

3.3、繪制路徑:

 

  • .beginPath():開始一段路徑的繪制;
  • .closePath():從起始點到當前點,結束路徑的繪制,非必需;
  • .fill():根據路徑生成填充圖形;
  • .stroke():通過路徑生成輪廓圖形;
  • .moveTo(x,y):聲明一段路徑的起始點;
  • .l.NETo(x,y):繪制一條從當前坐標到(x,y)的線;
ctx.beginPath()ctx.moveTo(50,50)ctx.lineTo(100,100)ctx.lineTo(100,0)ctx.fill()ctx.beginPath()ctx.moveTo(110,100)ctx.lineTo(150,100)ctx.lineTo(150,200)ctx.lineTo(110,200)ctx.closePath() // 輪廓圖形不會根據從當前坐標到起始坐標生成輪廓,所以需要閉合路徑ctx.stroke()

 


 

3.4、繪制圓?。?/p>

 

  • .arc(x,y,radius,startAngle,endAngle,anticlockwise):畫一個以(x,y)為圓心的以 radius 為半徑的圓弧(圓),從 startAngle 開始到 endAngle 結束,按照 anticlockwise 給定的方向(默認為順時針,false)來生成;
  • arcTo(x1,y1,x2,y2,radius):根據給定的兩條切線中的一組切點坐標生成半徑為radius的圓弧;

 


 

注意:arc函數中的角度的單位是弧度而不是度,弧度=(Math.PI/180)*度

// 圓左上部分ctx.beginPath()ctx.arc(100,100,50,Math.PI,Math.PI*3/2,false)ctx.strokeStyle = '#ff6700'ctx.stroke()// 圓右上部分ctx.beginPath()ctx.arc(100,100,50,Math.PI*3/2,0,false)ctx.strokeStyle = '#6700ff'ctx.stroke()// 圓右下部分ctx.beginPath()ctx.arc(100,100,50,0,Math.PI/2,false)ctx.strokeStyle = '#00FFFF'ctx.stroke()// 圓左下部分ctx.beginPath()ctx.arc(100,100,50,Math.PI/2,Math.PI,false)ctx.strokeStyle = '#8B008B'ctx.stroke()// 兩條切線的交點坐標為(0,0)ctx.beginPath()ctx.moveTo(100,0)ctx.arcTo(0,0,0,100,100)ctx.fillStyle = 'blue'ctx.fill()

3.5、漸變對象:

 

  • .createLinearGradient(x1, y1, x2, y2):創建一個沿參數坐標指定的直線的漸變,開始坐標為(x1,y1),結束坐標為(x2,y2);
  • .createRadialGradient(x1, y1, r1, x2, y2, r2):創建根據參數確定兩個圓的坐標的放射性漸變,開始圓形圓心為(x1,y1),半徑為r1;結束圓形圓心為(x2,y2),半徑為r2;

 

創建好漸變對象之后,可以通過漸變對象上的.addColorStop(offset,color)為每一個漸變階段填充顏色,offset為0-1的偏移值。

const gradient = ctx.createLinearGradient(50, 50, 250, 50)gradient.addColorStop(0, 'blue')gradient.addColorStop(0.5, 'green')gradient.addColorStop(1, 'red')ctx.fillStyle = gradientctx.fillRect(0, 0, 300, 90)const radialGradient = ctx.createRadialGradient(200,200,100,200,200,50);radialGradient.addColorStop(0,"yellow");radialGradient.addColorStop(1,"green");ctx.fillStyle = radialGradient;ctx.fillRect(100,100,200,200);

3.6、像素操作:

 

  • .drawImage(image,x,y,width,height):image可以是image對象、canvas元素、video元素;
  • .getImageData(x,y,width,height):獲取坐標為(x,y)一定區域內圖像的像素數據;
const div = document.querySelector('div')let mousedown = false;function getRandom() {return Math.round(255 * Math.random());function getColor() {return `rgb(${getRandom()},${getRandom()},${getRandom()})`;const gradient = ctx.createLinearGradient(0, 0, 300, 300);gradient.addColorStop(0, getColor());gradient.addColorStop(0.6, getColor());gradient.addColorStop(1, getColor());function clear() {ctx.fillStyle = gradient;ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.beginPath();ctx.fillStyle = gradient;ctx.fillRect(0, 0, 300, 300);function selector(x = 150, y = 150) {clear();ctx.beginPath();ctx.arc(x, y, 5, 0, Math.PI * 2);ctx.strokeStyle = "#fff";ctx.stroke();const { data } = ctx.getImageData(x, y, 1, 1); // 獲取(x,y)點對應的imageDataconst color = `rgba(${data[0]},${data[1]},${data[2]},${data[3] / 255})`div.innerText = `color: ${color}`;div.style.backgroundColor = colorfunction handleSelector(e) {const x = e.offsetX;const y = e.offsetY;selector(x, y);canvas.addEventListener("mousedown", (e) => {mousedown = true;handleSelector(e)canvas.addEventListener("mouseup", () => {mousedown = false;canvas.addEventListener("mousemove", (e) => {if (mousedown) {handleSelector(e)selector();

 

3.7、畫布狀態:

 

  • .save():將當前畫布的狀態推入到棧中,例如fillStyle、2D轉換等;
  • .restore():將棧頂元素彈出,恢復上一次推入棧中畫布的狀態;

 

當我們需要通過空間轉換來繪制圖形時,保存與恢復畫布的狀態是很關鍵的,因為我們是在同一塊畫布上繪制圖形,而變換都是基于畫布的,這與我們平時使用到的css 2D轉換截然不同,所以我們在下一步繪制時要確認此時畫布的狀態是否是我們的理想狀態。

ctx.save() // 保存畫布初始狀態ctx.translate(100,100) // 將畫布原點轉移至(100,100)ctx.fillStyle = 'red'ctx.fillRect(0,0,50,50)ctx.restore() // 恢復畫布狀態,此時畫布原點為(0,0)ctx.fillStyle = 'blue'ctx.fillRect(0,0,50,50)

3.8、幾何變化:

 

  • .translate(x,y):畫布默認的原點是(0,0),此方法可以切換原點到(x,y)而不需要手動更改繪制圖形的坐標;
  • .rotate(angle):將畫布旋轉一定的角度,angle單位為弧度;
  • .scale(sx,sy):sx為水平方向的縮放比例,sy為豎直方向的縮放比例;
  • .transform(a,b,c,d,e,f):依次為水平縮放、垂直傾斜、水平傾斜、垂直縮放、水平移動、垂直移動;

 

const colors = ['red','orange','yellow','green','blue','purple'];ctx.translate(150,150)for(let i = 0; i < 6; i++) {ctx.beginPath()ctx.fillStyle = colors[i]ctx.moveTo(0,0)ctx.lineTo(100,0)ctx.lineTo(100,50)ctx.rotate(Math.PI/3)ctx.fill()


 

4、綜合實戰

const p = Math.PI;function clock() {const date = new Date();const hour = date.getHours()const s = date.getSeconds();const m = date.getMinutes();const h = !!(hour % 12) ? hour % 12 : 12;ctx.clearRect(0, 0, canvas.width, canvas.height);ctx.save(); // 保存畫布初始狀態ctx.translate(150, 150);ctx.rotate(-p / 2);// 輪廓ctx.beginPath();ctx.lineWidth = 5;ctx.strokeStyle = "#76b2ff";ctx.arc(0, 0, 80, 0, p * 2);ctx.stroke();// 圓心ctx.beginPath();ctx.arc(0, 0, 2, 0, p * 2);ctx.fill();// 分針、秒針刻度for (let i = 0; i < 60; i++) {ctx.beginPath();ctx.rotate(p / 30);ctx.moveTo(75, 0);ctx.lineWidth = 4;ctx.strokeStyle = "#89f086";ctx.lineTo(80, 0);ctx.stroke();// 時針刻度for (let i = 0; i < 12; i++) {ctx.beginPath()ctx.rotate(p / 6)ctx.moveTo(70, 0)ctx.lineTo(80, 0)ctx.stroke()ctx.save(); // 保存畫布變換之后的狀態// 秒針ctx.beginPath();ctx.rotate(s * (p / 30));ctx.lineWidth = 2ctx.strokeStyle = '#ff6700'ctx.moveTo(0, 0);ctx.lineTo(80, 0);ctx.stroke();// 恢復之前的狀態再保存,時針、分針、秒針都是基于原點以及畫布方向變換后繪制ctx.restore();ctx.save();// 分針ctx.beginPath();ctx.rotate(m * (p / 30));ctx.lineWidth = 3;ctx.strokeStyle = '#6700ff'ctx.moveTo(0, 0);ctx.lineTo(70, 0);ctx.stroke();ctx.restore();// 時針ctx.beginPath();ctx.rotate(h * (p / 6));ctx.lineWidth = 4;ctx.moveTo(0, 0);ctx.lineTo(60, 0);ctx.stroke();ctx.restore(); // 恢復畫布最初狀態document.querySelector('div').innerText = `Now:${h} : ${m} : ${s} ${hour > 12 ? 'pm' : 'am'}`window.requestAnimationFrame(clock);clock();


 

5、小結

隨著互聯網的高速發展,用戶對頁面的視覺和交互有著越來越高的要求,傳統的web開發無法得到滿足,利用Canvas強大的繪圖能力,可以讓網頁顯示的內容更加的豐富多彩,也能給用戶帶來更好的視覺體驗。

作者:LLS-FE團隊

出處:https://mp.weixin.qq.com/s/bvkx3wOeMvIUU64cktX6iA

分享到:
標簽:Canvas
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定