Canvas實(shí)現(xiàn)連線題的方案設(shè)計(jì)

????????開(kāi)發(fā)“連線題”并沒(méi)什么難點(diǎn),這里主要分享的是:實(shí)現(xiàn)過(guò)程中的一點(diǎn)點(diǎn)布局設(shè)計(jì)上的小心思。想要的效果大體長(zhǎng)這樣(如下圖所示):

1

????????乍一看似乎需要獲取每個(gè)元素的位置信息、計(jì)算連線的端點(diǎn)坐標(biāo),似乎很繁瑣,而且每次頁(yè)面尺寸變化時(shí),都得重新計(jì)算。其實(shí),事情可以比想象中簡(jiǎn)單很多…

一、方案設(shè)計(jì)

????????1.1 將連線題分為上中下三個(gè)區(qū)塊,其中:

????????1)上下區(qū)塊均使用flex(justify-content: space-around)

????????2)中間區(qū)塊為canvas,在style屬性中將width和height設(shè)置為100%

.row-1 { justify-content: space-around; }

.row-2 {

????????height: 0; flex-grow: 1;

????????canvas { width: 100%; height: 100%; }

}

.row-3 { justify-content: space-around; }

2

? ??????1.2 這樣設(shè)置以后,有幾點(diǎn)好處

????????1)計(jì)算直線端點(diǎn)(元素中點(diǎn))坐標(biāo)就會(huì)變得很輕松,只需要排序百分比與canvas的內(nèi)容寬度相乘即可。

let x1 = (上方元素下標(biāo) * 2 + 1) / (上方元素總數(shù) * 2) * canvas.width

let x2 = (下方元素下標(biāo) * 2 + 1) / (下方元素總數(shù) * 2) * canvas.width

// 連線上方端點(diǎn)坐標(biāo): (x1, 0)

// 連線下方端點(diǎn)坐標(biāo): (x2, canvas.height)

????????2)頁(yè)面resize時(shí)無(wú)需重新計(jì)算,頁(yè)面也不會(huì)亂。當(dāng)然如果resize前后差異較大,可能連線粗細(xì)程度會(huì)不美觀。

????????經(jīng)測(cè),一般不重新繪制也問(wèn)題不大;如果要求高的話,可以在resize時(shí)重新繪制一下。(下圖是第一張圖在網(wǎng)頁(yè)resize后的效果,線條經(jīng)過(guò)拉伸變細(xì)了)

3

????????3)如果你連canvas的尺寸也懶得初始化,也是可以的,只不過(guò)效果會(huì)差些(線條有點(diǎn)模糊,粗細(xì)不美觀),Chrome中canvas默認(rèn)內(nèi)容尺寸是300*100,效果如下圖所示(截圖可能視覺(jué)效果不明顯):

4

二、代碼實(shí)現(xiàn)

????????線條繪制的相關(guān)代碼如下:

????????Html

<canvas ref="canvas" :width="cvsWidth" :height="cvsHeight"></canvas>

????????Js

// 動(dòng)態(tài)調(diào)整canvas的內(nèi)容尺寸(必要時(shí),可在每次resize時(shí)重復(fù)調(diào)用)

initCanvas() {

? if (!this.$refs.canvas) return

? let cvsInfo = this.$refs.canvas.getBoundingClientRect()

? this.cvsWidth = parseInt(cvsInfo.width)

? this.cvsHeight = parseInt(cvsInfo.height)

},

// 繪制連線

drawLine() {

? if (!this.$refs.canvas) return

? let count = this.dataList.length

? let ctx = this.$refs.canvas.getContext("2d");

? let cvsWidth = this.$refs.canvas.width

? let cvsHeight = this.$refs.canvas.height

? ctx.clearRect(0, 0, cvsWidth, cvsHeight);

? ctx.lineWidth = 4;

? ctx.lineCap = 'round';

? ctx.strokeStyle = '#FF9C0A'

? for (let k in this.answerDict) {

? ? let _i1 = parseInt(k)

? ? let _i2 = this.answerDict[k]

? ? let _i1_x = (_i1 * 2 + 1) / (count * 2) * cvsWidth

? ? let _i2_x = (_i2 * 2 + 1) / (count * 2) * cvsWidth

? ? ctx.beginPath()

? ? ctx.moveTo(_i1_x, 0);

? ? ctx.lineTo(_i2_x, cvsHeight);

? ? ctx.stroke()

? }

},

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容