今天在做一個(gè)功能應(yīng)用的時(shí)候惹盼,需要?jiǎng)討B(tài)地畫(huà)線(示例圖如下)庸汗,因?yàn)楦鱾€(gè)節(jié)點(diǎn)是動(dòng)態(tài)從服務(wù)端請(qǐng)求過(guò)來(lái)的,所以線的數(shù)量也是動(dòng)態(tài)的手报,這個(gè)時(shí)候?qū)τ诋?huà)布的高度就要能自適應(yīng)蚯舱,但是對(duì)于canvas本身要預(yù)先設(shè)置好高度,但是一開(kāi)始的高度又不知道(因?yàn)閿?shù)據(jù)還沒(méi)請(qǐng)求過(guò)來(lái))掩蛤,那怎么處理呢枉昏,想了一個(gè)辦法,就是等數(shù)據(jù)請(qǐng)求過(guò)來(lái)之后揍鸟,然后計(jì)算出畫(huà)布應(yīng)該設(shè)置的高度兄裂,最后再把canvas開(kāi)放出顯示。
一、模板代碼
<!-- 線路區(qū)域 -->
<view class="footmark-line-wrap" id="footmarkLineWrap">
<!-- 線路畫(huà)布 -->
<canvas
v-if="isShowCanvas"
canvas-id="lineBg"
class="canvas-wrap"
:style="{ height: lineBgHeight + 'rpx' }"
></canvas>
<!-- 線路畫(huà)布 -->
<!-- 節(jié)點(diǎn) -->
<line-node
class="line-node"
:style="{
left: item.left + 'px',
top: item.top + 'px'
}"
:id="getNodeIndex(index)"
v-for="(item, index) in nodeList"
:key="item.id"
:node-info="item"
:node-index="index"
:current-pos="currentPos"
:button-color="buttonColor"
@detail="showNodeDetailModal"
></line-node>
<!-- 節(jié)點(diǎn) -->
</view>
<!-- 線路區(qū)域 -->
二晰奖、數(shù)據(jù)變量
data() {
return {
//畫(huà)布對(duì)象
canvasContext: null,
//節(jié)點(diǎn)高度
nodeSize: {
width: 0,
height: 0
},
//畫(huà)布高度
lineBgHeight: 0,
//線路區(qū)域的寬度
lineAreaWidth: 0,
//路線節(jié)點(diǎn)列表
nodeList: [],
//是否顯示畫(huà)布
isShowCanvas: false
}
},
三谈撒、方法
//畫(huà)布背景高度
setLineBgHeight() {
//通過(guò)獲取到的節(jié)點(diǎn)數(shù)據(jù)來(lái)估算出畫(huà)布的高度
let nodeNum = this.nodeList.length
if (nodeNum <= 3) {
this.lineBgHeight = 800
} else {
this.lineBgHeight = 260 * nodeNum
}
},
//獲取節(jié)點(diǎn)的寬
async getLineAreaWidth() {
return new Promise((resolve) => {
let query = uni.createSelectorQuery().in(this)
query.select('#footmarkLineWrap').boundingClientRect()
query.exec((res) => {
if (res && res[0]) {
resolve(res[0].width)
}
})
})
},
//獲取節(jié)點(diǎn)索引
getNodeIndex(index) {
return 'lineNode' + index
},
//獲取節(jié)點(diǎn)的寬高
async getLineNodeSize(index) {
return new Promise((resolve) => {
let domid = '#' + this.getNodeIndex(index)
let query = uni.createSelectorQuery().in(this)
query.select(domid).boundingClientRect()
query.exec((res) => {
if (res && res[0]) {
resolve({
width: res[0].width,
height: res[0].height
})
} else {
resolve(false)
}
})
})
},
//處理節(jié)點(diǎn)列表(每個(gè)節(jié)點(diǎn)動(dòng)態(tài)計(jì)算出坐標(biāo))
handleNodeList() {
//初始節(jié)點(diǎn)坐標(biāo)
let xLeftPos = 0
let xRightPos = this.lineAreaWidth - 103
let yPos = 0
let findPos = false
this.nodeList = this.nodeList.map((item, index) => {
if (item.user_done == 0 && !findPos) {
this.currentPos = index
findPos = true
}
//判斷當(dāng)前索引處于偶數(shù)還是基數(shù)
let isEven = index % 2 == 0
//節(jié)點(diǎn)信息
let itemInfo = {
...item,
left: isEven
? xLeftPos + this.$u.random(0, this.lineAreaWidth / 6)
: xRightPos - this.$u.random(0, this.lineAreaWidth / 5),
top: yPos
}
yPos += 130
return itemInfo
})
},
//繪制線路
async drawLine() {
if (this.nodeList.length) {
//獲取節(jié)點(diǎn)的大小
let nodeSize = await this.getLineNodeSize(0)
if (!nodeSize) {
nodeSize = {
width: 99,
height: 105
}
}
this.canvasContext = uni.createCanvasContext('lineBg')
//開(kāi)始繪制
this.canvasContext.beginPath()
this.canvasContext.setShadow(10, 10, 50, '#EF808B')
this.canvasContext.setLineCap('round')
this.canvasContext.setLineJoin('round')
this.canvasContext.setStrokeStyle('#EF9D73')
this.canvasContext.setLineWidth(12)
//節(jié)點(diǎn)列表
this.nodeList.map((item, index) => {
let xPos = item.left + nodeSize.width / 2
let yPos = item.top + nodeSize.height / 2
if (index == 0) {
this.canvasContext.moveTo(xPos, yPos)
} else {
//前一個(gè)節(jié)點(diǎn)
let prePoint = this.nodeList[index - 1]
//控制點(diǎn)
let cxPos = (item.left + prePoint.left + nodeSize.width) / 2
let cyPos = (item.top + prePoint.top + nodeSize.height) / 2
//隨機(jī)出曲線控制點(diǎn)方向
let controldirection = this.$u.random(0, 1)
if (controldirection) {
cyPos -= this.$u.random(30, 80)
} else {
cyPos += this.$u.random(30, 80)
}
this.canvasContext.quadraticCurveTo(cxPos, cyPos, xPos, yPos)
}
})
this.canvasContext.stroke()
this.canvasContext.draw()
}
},
四、業(yè)務(wù)處理
async onLoad(args) {
//獲取節(jié)點(diǎn)數(shù)據(jù)列表
await this.getNodeList()
//設(shè)置畫(huà)布高度
this.setLineBgHeight()
//高度設(shè)置完成之后開(kāi)啟顯示canvas
this.isShowCanvas = true
//設(shè)置線路區(qū)域的寬度
this.lineAreaWidth = await this.getLineAreaWidth()
//處理節(jié)點(diǎn)
this.handleNodeList()
//繪制線路
this.drawLine()
},
五匾南、CSS樣式
.footmark-line-wrap {
position: relative;
.canvas-wrap {
width: 100%;
}
.line-node {
position: absolute;
}
}