亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > HTML > 正文

使用html5 canvas繪制圓環動效

2024-08-26 00:21:30
字體:
來源:轉載
供稿:網友

最近筆者有個需求,需求內容為:一組文字顯示在圓環的周圍,用戶可添加文字,文字圍繞著圓環,每個詞對應圓環周圍的的藍色小圓點,當用戶鼠標放在圓環上方小藍點時時,實現放射出三角形,再顯示出文字,先看看動圖效果吧!

html5,canvas,圓環動效 ? ??

如上圖所示,當鼠標放在對應藍色小圓點上時,需要放射出射類似三角形的射線,并在三角形外側顯示對應文字,且小藍點變小白點。

html5,canvas,圓環動效?

當用戶在上方輸入內容后,將內容添加至下方的圓環周圍。如上圖所示。

筆者本來一開始的想法是使用css來實現,就像下圖的動態二級菜單一樣。

html5,canvas,圓環動效? ??

但是考慮到圓環邊緣的內容可變,又要定位到圓環周圍,css可能會比較難實現。所以哇,筆者決定使用canvas來實現。(筆者最近才學的canvas,有什么不對的,接受大家的指正)。

實現過程:

首先:

html部分代碼如下:

<canvas style="margin-left: 50px;padding-top: 20px; display:block;" id="canvas" > 您的瀏覽器當前版本不支持canvas</canvas>

具體實現步驟如下:

1、繪制大圓環。

使用canvas方法:context.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);

x,y:圓心坐標,radius:圓心半徑,startAngle:繪制起始弧度,endAngle:繪制結束弧度, [, anticlockwise]:可選參數,順時針還是逆時針繪制圓弧。

為了繪制方便,筆者將畫布的原點由之前的左上角,移動至畫布的中心。

筆者計算的圓環的半徑為 r-80

canvas.width = 500canvas.height = 500//計算畫布中心位置的半徑let r = 500 / 2// 界面初始化的時候將畫布的原點移動至畫布中心ctx.translate(r,r) //將畫筆移動到圓形

具體代碼如下:

// 畫布初始化let canvas = document.getElementById('canvas')let  ctx= canvas.getContext('2d')let ratio = getPixelRato(ctx)canvas.width = 500canvas.height = 500//計算畫布中心位置的半徑let r = 500 / 2// 界面初始化的時候將畫布的原點移動至畫布中心ctx.translate(r,r) //將畫筆移動到圓形ctx.lineWidth = 3; //設置畫筆的線寬ctx.beginPath(); //畫筆開始// 繪制圓環邊緣漸變邊緣顏色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;//設置畫筆的顏色ctx.arc(0,0,r - 80,0,2*Math.PI,false)  //繪制圓形,坐標0,0,半徑250-80,整圓(0-360度),false表示順時針ctx.closePath()ctx.stroke() //繪圖

?繪制結果如下

html5,canvas,圓環動效 ?

2、繪制圓環中部背景圖片(當前畫布原點為畫布中心)

drawImage(image, dx, dy, dWidth, dHeight)

image:Canvas圖片資源,如<img>圖片,SVG圖像,Canvas元素本身等。

dx、dy:在Canvas畫布上規劃一片區域用來放置圖片,dx就是這片區域的左上角橫、縱坐標。

dWidth、dHeight:在Canvas畫布上規劃一片區域用來放置圖片,這片區域的寬度、高度。

以下坐標都是筆者計算得出

let image = new Image()image.src = 'image/quan.png'image.onload = () => {    // 原點移動至中心    ctx.drawImage(image,-140,-140,280,280)}

繪制結果如下:

html5,canvas,圓環動效 ?

3、繪制圓環上的文字,小圓點(當前畫布原點為畫布中心)

文字和小圓點的繪制目標:

3.1 小圓點均勻的顯示在大圓環上

3.2 文字散落在小圓點外方一點點

解決思路:

1、筆者使用一個數組來存儲當前的詞語

let textArr = ['海闊天空','技術能力','資金雄厚','維修控制','安居樂業','走馬觀花','畫龍點睛','去其糟粕','逆風而行','職業發展']

2、因為小圓點的個數以及詞語的個數是一樣的,它們兩個的個數也就是上方數組textArr的length

3、一個整圓的弧度是2π,要讓小圓點們均分圓環,筆者首先計算出每個小圓點所在點的弧度

for(let i = 0;i<lengths;i++){ // 計算弧度 let rad = 2*Math.PI/lengths*i}

4、根據三角函數可以計算出當前小圓點在畫布上的坐標(x,y)(當前畫布原點為畫布中心)

html5,canvas,圓環動效 ?

其中弧度,小圓點,圓環,圓環半徑,畫布原點關系,筆者畫了一個圖來描述它們。

html5,canvas,圓環動效 ?

計算文字的坐標:

// 計算小圓心坐標let x = (r - 40)*Math.cos(rad)let y = (r - 40)*Math.sin(rad)

計算小圓點的坐標:因為小圓點的圓心都要落在圓環上,所以其計算橫縱坐標是,

// 計算文字的坐標    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.lengthtextArr.forEach(function(text,i){    //弧度    let rad = 2*Math.PI/lengths*i    // 計算小圓心坐標    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()    // 繪制藍色小圓點    ctx.beginPath()    ctx.fillStyle = '#208fe5'    ctx.arc(x,y,4,0,2*Math.PI,false)    ctx.closePath()    ctx.fill()        }

繪制結果如下:

html5,canvas,圓環動效 ?

4、繪制每個小圓點外面的三角形(當前畫布原點為畫布中心)

4.1 因為要繪制出三角形的形狀,繪制三角形的思路就是,以當前小圓點的圓心為起點向兩側畫條線,然后使用ctx.fill()封閉圖形,并使用漸變色填充內部。

繪制三角形:坐標自行計算。筆者是橫坐標加減35.縱坐標加上70(隨意隨意,看你喜歡,哈哈哈)

//畫筆開始        ctx.beginPath()     ctx.moveTo(x,y)    ctx.lineTo(x-35,y+70)    ctx.lineTo(x+35,y+70)    ctx.closePath()

繪制三角形下方的文字:(為了和之前的文字有區別,這里我文字我使用了紅色)

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()    // // 設置 顏色 漸變--->從中心向兩邊添加顏色    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)}

繪制結果如下:

html5,canvas,圓環動效 ?

4.2 需求是每個三角形的方向是向外散發,而現在三角形的方向都是朝下方,所以現在需要使用canvas的旋轉方法。

ctx.save()    ctx.translate(x,y) // 旋轉角度以每個小圓點為中心    ctx.rotate( rad - Math.PI/2 ) // 因為一開始小圓點    ctx.translate(-x, -y)    .    省略畫三角形和文字的代碼    .    .    ctx.restore()

由計算可得,以小圓點的圓心為旋轉起點,三角形的旋轉的弧度應該是當前小圓點的弧度減去π/2,因為旋轉的起始位置都是從x坐標軸正方向開始,即弧度為0處開始,但是現在三角形的已經都處于π/2弧度處,所以:

旋轉的弧度 = 小圓點的弧度 - π/2

記得旋轉的時候一定要使用Canvas狀態的存儲方法save()。

restore(),依次從堆棧的上方彈出存儲的Canvas狀態,如果沒有任何存儲的Canvas狀態,則執行此方法沒有任何變化。

一定要記得最后要使用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()    // 旋轉角度以每個小圓點為中心  因為一開始小圓點    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()    //設置 顏色 漸變--->從中心向兩邊添加顏色    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()}

繪制結果:

html5,canvas,圓環動效 ?

定睛一看,what???有些文字因為旋轉問題,顛倒了,通過觀察得出結果,當弧度大于π的時候,文字才出現顛倒問題。

是時候寫一波if判斷了。。。。

旋轉文字的方法:

function rotateContext(ctx, x, y, degree) {            // 旋轉文字            ctx.translate(x, y)            // ctx.rotate(degree * Math.PI / 180)            ctx.rotate(degree)            ctx.translate(-x, -y)        }

判斷弧度大于π的小圓點

if (rad > Math.PI) {    // 因為文字需要顯示在三角形的邊緣,所以文字應該隨著三角形旋轉,才能一直維持在    // 三角形的邊緣,由于旋轉后當弧度大于π的值都會出現文字倒轉問題,于是將文字進行旋轉翻轉    ctx.save()    ctx.beginPath()    // 旋轉文字    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)}

繪制結果如下:

html5,canvas,圓環動效 ?

勝利再望,快要成功了,至少大概布局有了,革命尚未成功,同志仍需努力?。?/p>

5、下面就是實現,鼠標在小圓點上方,讓邊緣的三角形和三角形邊緣文字顯示,而圓環邊的文字不顯示

思路:

1、給畫布綁定鼠標進入事件

2、判斷當前鼠標所在畫布位置的坐標是否等于某個小圓點的附近的坐標,如果等于就顯示對應小圓點的三角形。

5.1給canvas畫布綁定mousemove事件:鼠標在上方事件

canvas.addEventListener('mousemove',clickEvent)

5.2 計算鼠標當前在畫布上的坐標

計算方法是:使用鼠標當前在dom上的坐標減去,畫布距離左方或上方的距離,計算出畫布的距離

下圖的drawOne方法為繪制方法,文章后續會說到。

function clickEvent() {            // 鼠標所在位置坐標            let x = event.clientX - canvas.getBoundingClientRect().left            let y = event.clientY - canvas.getBoundingClientRect().top            drawOne(x,y)}

5.3,因為上方計算出來的鼠標在畫布上的坐標是以畫布的左上角為原點計算的坐標,但是當前畫布的原點早已移動到畫布中心(250,250)處,所以當用來判斷是否是點擊某個小圓點的時候需要橫縱坐標都減去250,才能與當前畫布的小圓點坐標進行比哦對,筆者在判斷的時候,發現 一個問題,不知道為啥筆者的y方向的差量是260而不是250,所以筆者y方向上都減去了260。

代碼如下:

其中Cx,Cy為鼠標在畫布上的坐標(以畫布左上角為原點),x,y為當前小圓點的坐標,

筆者直接計算出小圓點圓心附近15px的位置,都顯示三角形,和小圓點變白色。

最主要的是每次重新繪制都需要清空之前的畫布:記住使用clearRect方法清空畫布

let XX = Cx - 250let YY = Cy- 260let leftX = x - 15 let rightX = x + 15let topY = y - 15let bottomY = y + 15if (XX >= leftX && XX <= rightX && YY <= bottomY && YY >= topY ) {//就是它被點了。。。。。。//這中間寫繪制的代碼}

代碼后續附上鏈接:

6,界面上定義一個Input,給input綁定change事件。

實現:每一次Input內的值改變都重繪界面。

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)  //此方法是繪制的方法,文章后續給源代碼    }})

7,出現了一個問題,當每次點擊界面,重繪界面的時候都會出現一閃一閃的狀況

如下所示:

html5,canvas,圓環動效?

每次滑動,因為鼠標的坐標改變了,都需要清空圓環周圍的的內容,重新繪制。所以就需要清空畫布達到動效的效果。

clearRect()在Canvas動畫繪制中非常常用,不斷清除畫布內容再繪制,形成動畫效果。

clearRect()可以把Canvas元素畫布中的某一塊矩形區域變成透明的。

context.clearRect(x, y, width, height);

x、y:矩形左上角x、y坐標。

width、heigh:被清除的矩形區域的寬度、高度。

由于clearRect()只能清除矩形區域的畫布,所以每次清除的時候,中間的背景圖片都會一塊兒被清除。

所以每次都要重新加載背景圖片,加載圖片又是有一定的時間的,所以出現沒次都會閃一下。

解決方案:

drawImage(image, dx, dy, dWidth, dHeight)

其中參數image:Canvas圖片資源,如<img>圖片,SVG圖像,Canvas元素本身等。

那可以使用其他canvas來緩存圖片方式。

使用額外的canvas來繪制出背景圖片,但是對于那個canvas不顯示在界面:display:none,然后使用當清空畫布后,直接將緩存起來的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 = 280let image = new Image()image.src = 'image/quan.png'image.onload = () => {    // 原點移動至中心    tempCtx.drawImage(image,0,0,280,280)}

當清除畫布后,重新繪制圖片的時候直接將緩存canvas:tempCanvas繪制出來

// 將緩存的canvas直接繪制到界面(緩存了中間輪胎界面) ctx.drawImage(tempCanvas,-140,-140)

好啦,成功了,獻上成果圖:

html5,canvas,圓環動效?

源代碼地址如下:

https://github.com/Linefate/Dynamic-effect-of-canvas-ring.git

總結

以上所述是小編給大家介紹的使用html5 canvas繪制圓環動效,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!

 


注:相關教程知識閱讀請移步到HTML教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国语自产精品视频在线看一大j8| 亚洲国产欧美在线成人app| 最近免费中文字幕视频2019| 亚洲欧美激情视频| 视频直播国产精品| 久久久久日韩精品久久久男男| 91精品国产色综合久久不卡98| 日本乱人伦a精品| 在线日韩欧美视频| 国产精品人成电影在线观看| 成人在线视频福利| 日韩高清av在线| 亚洲aaa激情| 精品人伦一区二区三区蜜桃免费| 精品视频久久久久久久| 国产精品日日做人人爱| 精品久久久久久久久久久久久| 久青草国产97香蕉在线视频| 国内精品模特av私拍在线观看| 亚洲а∨天堂久久精品喷水| 富二代精品短视频| 日韩精品亚洲元码| 中文字幕一区电影| 最新国产成人av网站网址麻豆| 欧美片一区二区三区| 国产成一区二区| 欧美亚洲视频在线观看| 欧美亚洲国产另类| 日韩国产欧美区| 欧美日韩国产精品专区| 久久久久久久久综合| 亚洲第一色在线| 久久国内精品一国内精品| 国产精品久久久久av| 精品无人国产偷自产在线| 精品色蜜蜜精品视频在线观看| 久久成人精品一区二区三区| 亚洲欧洲在线视频| 精品久久久国产| 国产美女精彩久久| 欧美激情日韩图片| 欧美多人爱爱视频网站| 亚洲欧美日韩爽爽影院| 亚洲精品国产精品自产a区红杏吧| 欧美激情精品久久久久久免费印度| 久久久久亚洲精品成人网小说| 欧美成人性生活| 久久精品国产91精品亚洲| 欧美一区二区三区免费观看| 欧美午夜视频在线观看| 91久久国产综合久久91精品网站| 91黑丝高跟在线| 不卡在线观看电视剧完整版| 久久99青青精品免费观看| 九九久久精品一区| 亚洲精品电影久久久| 亚洲男人天堂2019| 高清亚洲成在人网站天堂| 中文字幕日韩在线播放| 亚洲热线99精品视频| 深夜福利亚洲导航| 日韩欧美在线第一页| 欧美激情视频播放| 国产精品wwwwww| 欧美激情精品在线| 国产精品美女久久久久久免费| 国产91精品在线播放| 国产精品69久久| 欧美大片在线看免费观看| 久久久91精品国产| 久久综合电影一区| 国产一区玩具在线观看| 国产精品视频26uuu| 久久偷看各类女兵18女厕嘘嘘| 国产精品永久免费在线| 欧美亚洲视频在线观看| 国产精品一区电影| 国产精品小说在线| 亚洲欧洲在线视频| 97精品一区二区视频在线观看| 日韩在线免费视频观看| 亚洲午夜激情免费视频| 日韩欧中文字幕| 国产精品99久久99久久久二8| 美日韩在线视频| 国产69精品99久久久久久宅男| 亚洲无限乱码一二三四麻| 欧美电影在线观看完整版| 亚洲男子天堂网| 国产精品久久久久久一区二区| 欧美俄罗斯性视频| 国产精品久久999| 国产精品久久久久久亚洲影视| 亚洲自拍偷拍福利| 91国产视频在线播放| 精品日韩视频在线观看| 欧美久久精品一级黑人c片| 亚洲香蕉成视频在线观看| 国产精品mp4| 精品无人区太爽高潮在线播放| 日韩中文字在线| 国产精品久久久久久久久男| 成人乱人伦精品视频在线观看| 91国内揄拍国内精品对白| 欧美国产日韩在线| 久久九九全国免费精品观看| 亚洲一区精品电影| 成人中文字幕+乱码+中文字幕| 日本精品va在线观看| 粉嫩av一区二区三区免费野| 色狠狠av一区二区三区香蕉蜜桃| 久久999免费视频| 亚洲va久久久噜噜噜久久天堂| 国产极品精品在线观看| 性色av一区二区三区| 欧美高清一级大片| 日韩一区二区福利| 97av在线影院| 午夜精品蜜臀一区二区三区免费| 国产精品一区二区久久精品| 亚洲国产精品字幕| 热re91久久精品国99热蜜臀| 亚洲免费影视第一页| 亚洲免费视频在线观看| 亚洲国产天堂久久综合| 色一情一乱一区二区| 亚洲qvod图片区电影| 欧美孕妇性xx| 亚洲成人黄色网址| 亚洲电影在线观看| 欧美日本精品在线| 久久精品青青大伊人av| 91精品视频专区| 久久精品电影一区二区| xxxxx成人.com| 91丝袜美腿美女视频网站| 欧美一区二区三区图| 一本大道亚洲视频| 日本一欧美一欧美一亚洲视频| 亚洲第一精品福利| 国产精品精品久久久| 国产剧情日韩欧美| 日韩在线免费av| 欧美高清不卡在线| 久久精品久久久久电影| 岛国av一区二区三区| 亚洲成人黄色网| 亚洲国产成人在线播放| 亚洲性生活视频在线观看| 91精品国产色综合久久不卡98| 91精品在线观| 91精品国产自产在线老师啪| 国产精品av在线| 69久久夜色精品国产7777| 日本午夜在线亚洲.国产| 国产一区二区三区在线看| 久久男人的天堂| 精品中文字幕久久久久久| 国产91精品久久久久| 成人h视频在线观看播放| 在线观看91久久久久久| 欧美视频裸体精品| 欧美日韩精品在线视频| 欧美成人网在线|