APP & program

uniapp中使用canvas的时候如何动态修改画布的高度

2022-06-14  本文已影响0人  周星星的学习笔记

今天在做一个功能应用的时候,需要动态地画线(示例图如下),因为各个节点是动态从服务端请求过来的,所以线的数量也是动态的,这个时候对于画布的高度就要能自适应,但是对于canvas本身要预先设置好高度,但是一开始的高度又不知道(因为数据还没请求过来),那怎么处理呢,想了一个办法,就是等数据请求过来之后,然后计算出画布应该设置的高度,最后再把canvas开放出显示。

示例

一、模板代码

<!-- 线路区域 -->
    <view class="footmark-line-wrap" id="footmarkLineWrap">
      <!-- 线路画布 -->
      <canvas
        v-if="isShowCanvas"
        canvas-id="lineBg"
        class="canvas-wrap"
        :style="{ height: lineBgHeight + 'rpx' }"
      ></canvas>
      <!-- 线路画布 -->

      <!-- 节点 -->
      <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>
      <!-- 节点 -->
    </view>
    <!-- 线路区域 -->

二、数据变量

data() {
    return {
      //画布对象
      canvasContext: null,
      //节点高度
      nodeSize: {
        width: 0,
        height: 0
      },
      //画布高度
      lineBgHeight: 0,
      //线路区域的宽度
      lineAreaWidth: 0,
      //路线节点列表
      nodeList: [],
      //是否显示画布
      isShowCanvas: false
    }
  },

三、方法

//画布背景高度
setLineBgHeight() {
      //通过获取到的节点数据来估算出画布的高度
      let nodeNum = this.nodeList.length
      if (nodeNum <= 3) {
        this.lineBgHeight = 800
      } else {
        this.lineBgHeight = 260 * nodeNum
      }
},
//获取节点的宽
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)
          }
        })
      })
},
//获取节点索引
getNodeIndex(index) {
      return 'lineNode' + index
 },
//获取节点的宽高
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)
          }
        })
      })
},
//处理节点列表(每个节点动态计算出坐标)
handleNodeList() {
      //初始节点坐标
      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
        }
        //判断当前索引处于偶数还是基数
        let isEven = index % 2 == 0
        //节点信息
        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) {
        //获取节点的大小
        let nodeSize = await this.getLineNodeSize(0)
        if (!nodeSize) {
          nodeSize = {
            width: 99,
            height: 105
          }
        }
        this.canvasContext = uni.createCanvasContext('lineBg')
        //开始绘制
        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)
        //节点列表
        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 {
            //前一个节点
            let prePoint = this.nodeList[index - 1]
            //控制点
            let cxPos = (item.left + prePoint.left + nodeSize.width) / 2
            let cyPos = (item.top + prePoint.top + nodeSize.height) / 2
            //随机出曲线控制点方向
            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()
      }
},

四、业务处理

async onLoad(args) {
    //获取节点数据列表
    await this.getNodeList()
    //设置画布高度
    this.setLineBgHeight()
    //高度设置完成之后开启显示canvas
    this.isShowCanvas = true
    //设置线路区域的宽度
    this.lineAreaWidth = await this.getLineAreaWidth()
    //处理节点
    this.handleNodeList()
    //绘制线路
    this.drawLine()
},

五、CSS样式

.footmark-line-wrap {
    position: relative;
    .canvas-wrap {
      width: 100%;
    }
    .line-node {
      position: absolute;
    }
}
上一篇下一篇

猜你喜欢

热点阅读