您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)怎么在html5中利用canvas繪制一個圓環(huán),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
實現(xiàn)過程:
首先:
html部分代碼如下:
<canvas style="margin-left: 50px;padding-top: 20px; display:block;" id="canvas" > 您的瀏覽器當(dāng)前版本不支持canvas</canvas>
具體實現(xiàn)步驟如下:
1、繪制大圓環(huán)。
使用canvas方法:context.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
x,y:圓心坐標(biāo),radius:圓心半徑,startAngle:繪制起始弧度,endAngle:繪制結(jié)束弧度, [, anticlockwise]:可選參數(shù),順時針還是逆時針繪制圓弧。
為了繪制方便,筆者將畫布的原點由之前的左上角,移動至畫布的中心。
筆者計算的圓環(huán)的半徑為 r-80
canvas.width = 500 canvas.height = 500 //計算畫布中心位置的半徑 let r = 500 / 2 // 界面初始化的時候?qū)嫴嫉脑c移動至畫布中心 ctx.translate(r,r) //將畫筆移動到圓形
具體代碼如下:
// 畫布初始化 let canvas = document.getElementById('canvas') let ctx= canvas.getContext('2d') let ratio = getPixelRato(ctx) canvas.width = 500 canvas.height = 500 //計算畫布中心位置的半徑 let r = 500 / 2 // 界面初始化的時候?qū)嫴嫉脑c移動至畫布中心 ctx.translate(r,r) //將畫筆移動到圓形 ctx.lineWidth = 3; //設(shè)置畫筆的線寬 ctx.beginPath(); //畫筆開始 // 繪制圓環(huán)邊緣漸變邊緣顏色 var arcColor = ctx.createLinearGradient(-170, -170, 0, 170) arcColor.addColorStop(0, '#8ec1ff') arcColor.addColorStop(0.2, '#83beff') arcColor.addColorStop(0.5, '#75b1ff') arcColor.addColorStop(0.7,'#5998ff') arcColor.addColorStop(1, '#2065ff') ctx.strokeStyle= arcColor;//設(shè)置畫筆的顏色 ctx.arc(0,0,r - 80,0,2*Math.PI,false) //繪制圓形,坐標(biāo)0,0,半徑250-80,整圓(0-360度),false表示順時針 ctx.closePath() ctx.stroke() //繪圖
繪制結(jié)果如下
2、繪制圓環(huán)中部背景圖片(當(dāng)前畫布原點為畫布中心)
drawImage(image, dx, dy, dWidth, dHeight)
image:Canvas圖片資源,如<img>圖片,SVG圖像,Canvas元素本身等。
dx、dy:在Canvas畫布上規(guī)劃一片區(qū)域用來放置圖片,dx就是這片區(qū)域的左上角橫、縱坐標(biāo)。
dWidth、dHeight:在Canvas畫布上規(guī)劃一片區(qū)域用來放置圖片,這片區(qū)域的寬度、高度。
以下坐標(biāo)都是筆者計算得出
let image = new Image() image.src = 'image/quan.png' image.onload = () => { // 原點移動至中心 ctx.drawImage(image,-140,-140,280,280) }
繪制結(jié)果如下:
3、繪制圓環(huán)上的文字,小圓點(當(dāng)前畫布原點為畫布中心)
文字和小圓點的繪制目標(biāo):
3.1 小圓點均勻的顯示在大圓環(huán)上
3.2 文字散落在小圓點外方一點點
解決思路:
1、筆者使用一個數(shù)組來存儲當(dāng)前的詞語
let textArr = ['海闊天空','技術(shù)能力','資金雄厚','維修控制','安居樂業(yè)','走馬觀花','畫龍點睛','去其糟粕','逆風(fēng)而行','職業(yè)發(fā)展']
2、因為小圓點的個數(shù)以及詞語的個數(shù)是一樣的,它們兩個的個數(shù)也就是上方數(shù)組textArr的length
3、一個整圓的弧度是2π,要讓小圓點們均分圓環(huán),筆者首先計算出每個小圓點所在點的弧度
for(let i = 0;i<lengths;i++){ // 計算弧度 let rad = 2*Math.PI/lengths*i }
4、根據(jù)三角函數(shù)可以計算出當(dāng)前小圓點在畫布上的坐標(biāo)(x,y)(當(dāng)前畫布原點為畫布中心)
其中弧度,小圓點,圓環(huán),圓環(huán)半徑,畫布原點關(guān)系,筆者畫了一個圖來描述它們。
計算文字的坐標(biāo):
// 計算小圓心坐標(biāo) let x = (r - 40)*Math.cos(rad) let y = (r - 40)*Math.sin(rad)
計算小圓點的坐標(biāo):因為小圓點的圓心都要落在圓環(huán)上,所以其計算橫縱坐標(biāo)是,
// 計算文字的坐標(biāo) let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad)
具體代碼如下:
// 繪制文字 ctx.font = '13px Arial' ctx.textAlign = 'center' ctx.textBaseline = 'middle' ctx.fillStyle="#000000" let lengths = textArr.length textArr.forEach(function(text,i){ //弧度 let rad = 2*Math.PI/lengths*i // 計算小圓心坐標(biāo) let x = (r - 40)*Math.cos(rad) let y = (r - 40)*Math.sin(rad) ctx.fillText(text,x+0.5,y+0.5) }); // 繪制小圓點 for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // // 繪制邊緣灰色半透明小圓點 ctx.beginPath() ctx.fillStyle = 'rgba(226,235,250,0.8)' ctx.arc(x,y,8,0,2*Math.PI,false) ctx.closePath() ctx.fill() // 繪制藍(lán)色小圓點 ctx.beginPath() ctx.fillStyle = '#208fe5' ctx.arc(x,y,4,0,2*Math.PI,false) ctx.closePath() ctx.fill() }
繪制結(jié)果如下:
4、繪制每個小圓點外面的三角形(當(dāng)前畫布原點為畫布中心)
4.1 因為要繪制出三角形的形狀,繪制三角形的思路就是,以當(dāng)前小圓點的圓心為起點向兩側(cè)畫條線,然后使用ctx.fill()封閉圖形,并使用漸變色填充內(nèi)部。
繪制三角形:坐標(biāo)自行計算。筆者是橫坐標(biāo)加減35.縱坐標(biāo)加上70(隨意隨意,看你喜歡,哈哈哈)
//畫筆開始 ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath()
繪制三角形下方的文字:(為了和之前的文字有區(qū)別,這里我文字我使用了紅色)
ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75)
具體代碼如下:
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // // 畫s三角形 // // ctx.rotate( -Math.PI / 4) ctx.beginPath() //畫筆開始 ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath() // // 設(shè)置 顏色 漸變--->從中心向兩邊添加顏色 var sColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75) }
繪制結(jié)果如下:
4.2 需求是每個三角形的方向是向外散發(fā),而現(xiàn)在三角形的方向都是朝下方,所以現(xiàn)在需要使用canvas的旋轉(zhuǎn)方法。
ctx.save() ctx.translate(x,y) // 旋轉(zhuǎn)角度以每個小圓點為中心 ctx.rotate( rad - Math.PI/2 ) // 因為一開始小圓點 ctx.translate(-x, -y) . 省略畫三角形和文字的代碼 . . ctx.restore()
由計算可得,以小圓點的圓心為旋轉(zhuǎn)起點,三角形的旋轉(zhuǎn)的弧度應(yīng)該是當(dāng)前小圓點的弧度減去π/2,因為旋轉(zhuǎn)的起始位置都是從x坐標(biāo)軸正方向開始,即弧度為0處開始,但是現(xiàn)在三角形的已經(jīng)都處于π/2弧度處,所以:
旋轉(zhuǎn)的弧度 = 小圓點的弧度 - π/2
記得旋轉(zhuǎn)的時候一定要使用Canvas狀態(tài)的存儲方法save()。
restore(),依次從堆棧的上方彈出存儲的Canvas狀態(tài),如果沒有任何存儲的Canvas狀態(tài),則執(zhí)行此方法沒有任何變化。
一定要記得最后要使用restore()方法,說到這里,筆者留下了悔恨的淚水。。。
具體代碼:
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // 畫s三角形 ctx.save() // 旋轉(zhuǎn)角度以每個小圓點為中心 因為一開始小圓點 ctx.translate(x,y) ctx.rotate( rad - Math.PI/2 ) ctx.translate(-x, -y) // 畫筆開始 ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath() //設(shè)置 顏色 漸變--->從中心向兩邊添加顏色 var sColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75) ctx.restore() }
繪制結(jié)果:
定睛一看,what???有些文字因為旋轉(zhuǎn)問題,顛倒了,通過觀察得出結(jié)果,當(dāng)弧度大于π的時候,文字才出現(xiàn)顛倒問題。
是時候?qū)懸徊╥f判斷了。。。。
旋轉(zhuǎn)文字的方法:
function rotateContext(ctx, x, y, degree) { // 旋轉(zhuǎn)文字 ctx.translate(x, y) // ctx.rotate(degree * Math.PI / 180) ctx.rotate(degree) ctx.translate(-x, -y) }
判斷弧度大于π的小圓點
if (rad > Math.PI) { // 因為文字需要顯示在三角形的邊緣,所以文字應(yīng)該隨著三角形旋轉(zhuǎn),才能一直維持在 // 三角形的邊緣,由于旋轉(zhuǎn)后當(dāng)弧度大于π的值都會出現(xiàn)文字倒轉(zhuǎn)問題,于是將文字進(jìn)行旋轉(zhuǎn)翻轉(zhuǎn) ctx.save() ctx.beginPath() // 旋轉(zhuǎn)文字 rotateContext(ctx, x, y+75, Math.PI) ctx.font = '13px Arial' ctx.textAlign = 'center' ctx.fillStyle = "#ff2238" ctx.fillText(textArr[i], x, y+ 75) ctx.restore() } else { ctx.fillStyle = '#ff2238' ctx.fillText(textArr[i], x, y + 75) }
繪制結(jié)果如下:
勝利再望,快要成功了,至少大概布局有了,革命尚未成功,同志仍需努力??!
5、下面就是實現(xiàn),鼠標(biāo)在小圓點上方,讓邊緣的三角形和三角形邊緣文字顯示,而圓環(huán)邊的文字不顯示
思路:
1、給畫布綁定鼠標(biāo)進(jìn)入事件
2、判斷當(dāng)前鼠標(biāo)所在畫布位置的坐標(biāo)是否等于某個小圓點的附近的坐標(biāo),如果等于就顯示對應(yīng)小圓點的三角形。
5.1給canvas畫布綁定mousemove事件:鼠標(biāo)在上方事件
canvas.addEventListener('mousemove',clickEvent)
5.2 計算鼠標(biāo)當(dāng)前在畫布上的坐標(biāo)
計算方法是:使用鼠標(biāo)當(dāng)前在dom上的坐標(biāo)減去,畫布距離左方或上方的距離,計算出畫布的距離
下圖的drawOne方法為繪制方法,文章后續(xù)會說到。
function clickEvent() { // 鼠標(biāo)所在位置坐標(biāo) let x = event.clientX - canvas.getBoundingClientRect().left let y = event.clientY - canvas.getBoundingClientRect().top drawOne(x,y) }
5.3,因為上方計算出來的鼠標(biāo)在畫布上的坐標(biāo)是以畫布的左上角為原點計算的坐標(biāo),但是當(dāng)前畫布的原點早已移動到畫布中心(250,250)處,所以當(dāng)用來判斷是否是點擊某個小圓點的時候需要橫縱坐標(biāo)都減去250,才能與當(dāng)前畫布的小圓點坐標(biāo)進(jìn)行比哦對,筆者在判斷的時候,發(fā)現(xiàn) 一個問題,不知道為啥筆者的y方向的差量是260而不是250,所以筆者y方向上都減去了260。
代碼如下:
其中Cx,Cy為鼠標(biāo)在畫布上的坐標(biāo)(以畫布左上角為原點),x,y為當(dāng)前小圓點的坐標(biāo),
筆者直接計算出小圓點圓心附近15px的位置,都顯示三角形,和小圓點變白色。
最主要的是每次重新繪制都需要清空之前的畫布:記住使用clearRect方法清空畫布
let XX = Cx - 250 let YY = Cy- 260 let leftX = x - 15 let rightX = x + 15 let topY = y - 15 let bottomY = y + 15 if (XX >= leftX && XX <= rightX && YY <= bottomY && YY >= topY ) { //就是它被點了。。。。。。 //這中間寫繪制的代碼 }
代碼后續(xù)附上鏈接:
6,界面上定義一個Input,給input綁定change事件。
實現(xiàn):每一次Input內(nèi)的值改變都重繪界面。
html代碼:
<input type="text" id="inpt" style="margin-left: 100px;margin-top: 50px" placeholder="請輸入...">
js代碼:
let inpt = document.getElementById('inpt') inpt.addEventListener('change', function () { if (inpt.value !== '') { textArr.push(inpt.value) drawAll(2) //此方法是繪制的方法,文章后續(xù)給源代碼 } })
7,出現(xiàn)了一個問題,當(dāng)每次點擊界面,重繪界面的時候都會出現(xiàn)一閃一閃的狀況
如下所示:
每次滑動,因為鼠標(biāo)的坐標(biāo)改變了,都需要清空圓環(huán)周圍的的內(nèi)容,重新繪制。所以就需要清空畫布達(dá)到動效的效果。
clearRect()在Canvas動畫繪制中非常常用,不斷清除畫布內(nèi)容再繪制,形成動畫效果。
clearRect()可以把Canvas元素畫布中的某一塊矩形區(qū)域變成透明的。
context.clearRect(x, y, width, height);
x、y:矩形左上角x、y坐標(biāo)。
width、heigh:被清除的矩形區(qū)域的寬度、高度。
由于clearRect()只能清除矩形區(qū)域的畫布,所以每次清除的時候,中間的背景圖片都會一塊兒被清除。
所以每次都要重新加載背景圖片,加載圖片又是有一定的時間的,所以出現(xiàn)沒次都會閃一下。
解決方案:
drawImage(image, dx, dy, dWidth, dHeight)
其中參數(shù)image:Canvas圖片資源,如<img>圖片,SVG圖像,Canvas元素本身等。
那可以使用其他canvas來緩存圖片方式。
使用額外的canvas來繪制出背景圖片,但是對于那個canvas不顯示在界面:display:none,然后使用當(dāng)清空畫布后,直接將緩存起來的canvals畫布對象,渲染到要顯示的畫布中間,就是不用再去加載一次圖片,加載圖片是比較耗時的。
html代碼:
<canvas width="280" height="280" style="margin-left: 50px;padding-top: 20px; display:none;" id="canvas2"> </canvas>
js代碼:
// 利用緩存來解決重繪圖片閃動問題 var tempCanvas = document.getElementById('canvas2') const tempCtx = tempCanvas.getContext('2d') tempCanvas.width = 280; tempCanvas.height = 280 let image = new Image() image.src = 'image/quan.png' image.onload = () => { // 原點移動至中心 tempCtx.drawImage(image,0,0,280,280) }
當(dāng)清除畫布后,重新繪制圖片的時候直接將緩存canvas:tempCanvas繪制出來
// 將緩存的canvas直接繪制到界面(緩存了中間輪胎界面) ctx.drawImage(tempCanvas,-140,-140)
看完上述內(nèi)容,你們對怎么在html5中利用canvas繪制一個圓環(huán)有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。