????????開發(fā)“連線題”并沒什么難點(diǎn),這里主要分享的是:實現(xiàn)過程中的一點(diǎn)點(diǎn)布局設(shè)計上的小心思翁潘。想要的效果大體長這樣(如下圖所示):
????????乍一看似乎需要獲取每個元素的位置信息、計算連線的端點(diǎn)坐標(biāo)客冈,似乎很繁瑣美莫,而且每次頁面尺寸變化時谊路,都得重新計算赊锚。其實成箫,事情可以比想象中簡單很多…
一格郁、方案設(shè)計
????????1.1 將連線題分為上中下三個區(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; }
? ??????1.2 這樣設(shè)置以后例书,有幾點(diǎn)好處:
????????1)計算直線端點(diǎn)(元素中點(diǎn))坐標(biāo)就會變得很輕松锣尉,只需要排序百分比與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)頁面resize時無需重新計算决采,頁面也不會亂自沧。當(dāng)然如果resize前后差異較大,可能連線粗細(xì)程度會不美觀树瞭。
????????經(jīng)測拇厢,一般不重新繪制也問題不大;如果要求高的話晒喷,可以在resize時重新繪制一下孝偎。(下圖是第一張圖在網(wǎng)頁resize后的效果,線條經(jīng)過拉伸變細(xì)了)
????????3)如果你連canvas的尺寸也懶得初始化凉敲,也是可以的衣盾,只不過效果會差些(線條有點(diǎn)模糊,粗細(xì)不美觀)爷抓,Chrome中canvas默認(rèn)內(nèi)容尺寸是300*100势决,效果如下圖所示(截圖可能視覺效果不明顯):
二、代碼實現(xiàn)
????????線條繪制的相關(guān)代碼如下:
????????Html
<canvas ref="canvas" :width="cvsWidth" :height="cvsHeight"></canvas>
????????Js
// 動態(tài)調(diào)整canvas的內(nèi)容尺寸(必要時蓝撇,可在每次resize時重復(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()
? }
},