canvas 根据点位web循环展示样式,并等比例适配h5

web效果图

web实现步骤

说明

首先这个设计的尺寸是w1200,h680,点位的配置也是针对这个尺寸的基础上去配置

点位的配置没有做灵活的,如果要做的话,正常来讲是在图片上点击选取点位,目前是用最简单输入框的方式配置

1、绘制带有圆角的矩形,也就是对话框

个人也是第一次用canvas,不是非常熟悉,觉得最难的部分在绘图,前端页面样式更多是用css的方式书写,但现在要用画布的方式去绘制,比如要绘制矩形,绘制圆角,绘制倒三角,文字填充等,不会写,各种百度

// 带有圆角、还有boxshadw效果的对话框
const drawRoundedRect = (ctx, x, y, width, height, radius,shadow) => {
  // 开始绘制路径
  ctx.beginPath()
  // 左上角圆角
  ctx.moveTo(x + radius, y)
  ctx.lineTo(x + width - radius, y)
  ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
  // 右上角圆角
  ctx.lineTo(x + width, y + height - radius)
  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
  // 右下角圆角
  ctx.lineTo(x + radius, y + height)
  ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
  // 左下角圆角
  ctx.lineTo(x, y + radius)
  ctx.quadraticCurveTo(x, y, x + radius, y)

  // 关闭路径
  ctx.closePath()
  if (shadow == 1) {
    ctx.shadowBlur = 30 // 阴影模糊度
    ctx.shadowColor = 'rgba(0,0,0,.2)' // 阴影颜色
  } else {
    ctx.shadowBlur = 0 // 阴影模糊度
    ctx.shadowColor = '' // 阴影颜色
  }
  // 填充矩形
  ctx.fill()
}

const copyPointFun = (arr) => {
  if (arr) {
    arr.forEach((item) => {
      item.x = item.pointX
      item.y = item.pointY
    })
    return arr
  }
}

// 根据宽高比比例计算实际点位位置
const pointsFun = (bw, bh, arr) => {
  let webWidth = 1200
  let webHeight = 680
  let screenWidth = bw //屏幕宽
  let screenHeight = bh // 屏幕高

  arr.forEach((item) => {
    let webx = webWidth / item.pointX
    let weby = webHeight / item.pointY
    let pintX = screenWidth / webx
    let pintY = screenHeight / weby
    item.x = pintX
    item.y = pintY
  })

  return arr
}

// 假数据
const points = ref([
  {
    id: 1260195,
    groupId: 1290194,
    x: 530,
    y: 470,
    name: '班会课班会陆班会课会课陆课会课',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 1,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-30 00:00:00',
    width: 128,
    height: 77,
  }, //班会课
  {
    id: 1290187,
    groupId: 1290194,
    x: 800,
    y: 460,
    name: '校门口',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 0,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-30 00:00:00',
    width: 128,
    height: 77,
  }, //校门口
  {
    id: 1260194,
    groupId: 1290194,
    x: 220,
    y: 440,
    name: '卫生角',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 0,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-30 00:00:00',
    width: 128,
    height: 77,
  }, //卫生角
  {
    id: 1290186,
    groupId: 1290194,
    x: 300,
    y: 230,
    name: '黑板报',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 0,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-30 00:00:00',
    width: 128,
    height: 77,
  }, //黑板报
  {
    id: 1260196,
    groupId: 1290194,
    x: 685,
    y: 165,
    name: '办公室',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 0,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-12 00:00:00',
    width: 128,
    height: 77,
  }, //办公室
  {
    id: 1290188,
    groupId: 1290194,
    x: 920,
    y: 370,
    name: '传达室',
    type: 0,
    state: 0,
    respondTimes: 2,
    reuploadFlag: 0,
    beginTime: '2024-05-30 00:00:00',
    endTime: '2024-06-06 00:00:00',
    width: 128,
    height: 77,
  }, //传达室
])
//判断是否超过9个字符,超过了就省略号
const stringLength = (val) => {
  let text
  if (val && val.length < 7) {
    // console.log('11111')
    return val
  } else if (val && val.length > 6 && val.length < 10) {
    // console.log('22222')
    //大于12个字符加换行符
    const charToInsert = '\n'
    const positionOth = 6
    const newResult = insertCharAt(val, charToInsert, positionOth)
    const text = newResult + '...'
    return text
  } else if (val && val.length > 6 && val.length > 10) {
    // console.log('33333')
    const originalString = val
    // 在第20个字符那拼接省略号
    const position = 10
    const result = getSubstringBefore(originalString, position)
    const newResult = result + '...'
    // 在第12个字符那插入换行符
    const charToInsert = '\n'
    const positionOth = 6
    text = insertCharAt(newResult, charToInsert, positionOth)
    return text
  }
}

前面封装了方法,还有假数据,接下来就是写代码,在方法里调用了


const canvasFun = () => {
  // 获取当前屏幕宽度
  const screenWidth = window.screen.width
  const screenHeight = window.screen.height
    
  // 这里是针对pad尺寸的适配
  // 小于1281 是pad尺寸
  if (screenWidth < 1281) {
    // console.log('我不是pc')
    const boxs = document.querySelector('.second')
    var offsetLeft = boxs.offsetLeft
    var boxWidth = screenWidth - offsetLeft - 32 // 剪掉当前盒子距离左侧菜单及2边padding尺寸
    var boxHeight = screenHeight - 272 // 剪掉canvas距离顶部、底部的距离

    isPc.value = false
  } else {
    // console.log('我是pc')
    isPc.value = true
  }
    

  const canvas = document.querySelector('#canvas')
  const ctx = canvas.getContext('2d')

  const image = new Image()

  if (basicInfo.value.backgroundImage) {
    // console.log('有图片了')
    const url = `${publicUrl.getFile}?fileName=${
      basicInfo.value.backgroundImage
    }&dispositionType=2&satoken=${Cookies.get('satoken')}`

    image.src = url // 图片链接

    // 监听图片加载完成
    image.onload = function () {

      if (isPc.value == true) {
        canvas.width = 1200
        canvas.height = 680
        newArr.value = copyPointFun(basicInfo.value.chooseSubjectList)
      } else {
        canvas.width = boxWidth
        canvas.height = boxHeight
        // 去计算比例
        newArr.value = pointsFun(
          boxWidth,
          boxHeight,
          basicInfo.value.chooseSubjectList
        )
      }
    
      ctx.drawImage(image, 0, 0, canvas.width, canvas.height)

         // 添加点位交互
      newArr.value.forEach((point) => {
        //--------------设置高度
        let diaheight = setCanvasDiaHeight(point.name)
        //   // 设置填充颜色为黄色
        ctx.fillStyle = '#ffffff'
        //   // -------------绘制矩形
        let pointX = point.x - 50 //实际点位再偏移
        let pointY = point.y - diaheight
        console.log(pointX,pointY,'盒子的位置')
        //创建一个填充矩形(弹框)
        drawRoundedRect(ctx, pointX, pointY, 128, diaheight, 14,1)
        ctx.font = '16px AlibabaPuHuiTi' // 设置字体大小和颜色
        ctx.fontWeight = 'bold' // 再设置字重
        ctx.fillStyle = '#181A1C' // 设置字体大小和颜色
        ctx.textAlign = 'center' // 设置文本水平居中
        ctx.textBaseline = 'middle' // 设置文本基线

        // 处理标题名称,插入换行符
        let pointName = stringLength(point.name)
        // 在换行处拆分文本并多次调用 fillText() 来模拟换行
        var lineheight = 18
        var lines = pointName.split('\n')
        // console.log(lines,'lines')
        // 在弹框中间写入文本
        for (var i = 0; i < lines.length; i++) {
          if (i == 0) {
            ctx.fillText(lines[i], pointX + 64, pointY + 30 + i * lineheight)
          } else {
            ctx.fillText(lines[i], pointX + 54, pointY + 30 + i * lineheight)
          }
        }
     })
    }
   }
}

onMounted(() => {
  canvasFun()
})

setCanvasDiaHeight()方法是动态设置高度,因为盒子的高度会存在2种尺寸

 drawRoundedRect(ctx, pointX, pointY, 128, diaheight, 14,1)

pointX, pointY 是实际点位,这里128是对话框的宽度,diaheight 是动态设置高,14是圆角,1是是否要盒子阴影

到目前位置只是绘制的一部分,只是一个矩形,和填充了标题,因为标题可能过长,这里stringLength()方法也处理了过长加换行和省略号

 

2、绘制下三角

const canvasFun = () => {
  // 获取当前屏幕宽度
  const screenWidth = window.screen.width
  const screenHeight = window.screen.height
    
  // 这里是针对pad尺寸的适配
  // 小于1281 是pad尺寸
  if (screenWidth < 1281) {
    // console.log('我不是pc')
    const boxs = document.querySelector('.second')
    var offsetLeft = boxs.offsetLeft
    var boxWidth = screenWidth - offsetLeft - 32 // 剪掉当前盒子距离左侧菜单及2边padding尺寸
    var boxHeight = screenHeight - 272 // 剪掉canvas距离顶部、底部的距离

    isPc.value = false
  } else {
    // console.log('我是pc')
    isPc.value = true
  }
    

  const canvas = document.querySelector('#canvas')
  const ctx = canvas.getContext('2d')

  const image = new Image()

  if (basicInfo.value.backgroundImage) {
    // console.log('有图片了')
    const url = `${publicUrl.getFile}?fileName=${
      basicInfo.value.backgroundImage
    }&dispositionType=2&satoken=${Cookies.get('satoken')}`

    image.src = url // 图片链接

    // 监听图片加载完成
    image.onload = function () {

      if (isPc.value == true) {
        canvas.width = 1200
        canvas.height = 680
        newArr.value = copyPointFun(basicInfo.value.chooseSubjectList)
      } else {
        canvas.width = boxWidth
        canvas.height = boxHeight
        // 去计算比例
        newArr.value = pointsFun(
          boxWidth,
          boxHeight,
          basicInfo.value.chooseSubjectList
        )
      }
    
      ctx.drawImage(image, 0, 0, canvas.width, canvas.height)

         // 添加点位交互
      newArr.value.forEach((point) => {
        //--------------设置高度
        let diaheight = setCanvasDiaHeight(point.name)
        //   // 设置填充颜色为黄色
        ctx.fillStyle = '#ffffff'
        //   // -------------绘制矩形
        let pointX = point.x - 50 //实际点位再偏移
        let pointY = point.y - diaheight
        console.log(pointX,pointY,'盒子的位置')
        //创建一个填充矩形(弹框)
        drawRoundedRect(ctx, pointX, pointY, 128, diaheight, 14,1)
        ctx.font = '16px AlibabaPuHuiTi' // 设置字体大小和颜色
        ctx.fontWeight = 'bold' // 再设置字重
        ctx.fillStyle = '#181A1C' // 设置字体大小和颜色
        ctx.textAlign = 'center' // 设置文本水平居中
        ctx.textBaseline = 'middle' // 设置文本基线

        // 处理标题名称,插入换行符
        let pointName = stringLength(point.name)
        // 在换行处拆分文本并多次调用 fillText() 来模拟换行
        var lineheight = 18
        var lines = pointName.split('\n')
        // console.log(lines,'lines')
        // 在弹框中间写入文本
        for (var i = 0; i < lines.length; i++) {
          if (i == 0) {
            ctx.fillText(lines[i], pointX + 64, pointY + 30 + i * lineheight)
          } else {
            ctx.fillText(lines[i], pointX + 54, pointY + 30 + i * lineheight)
          }
        }


        // -------------绘制倒三角
        // 气泡框的起点坐标 (x, y)
        var x = point.x // 40是弹框宽度的一半
        var y = point.y // 55是弹框的高度
        // 倒三角的大小
        var width = 24
        var height = 17

        // 开始绘制
        ctx.beginPath()
        // 绘制倒三角形
        ctx.moveTo(x, y) // 气泡框左上角
        ctx.lineTo(x + width, y) // 气泡框右上角
        ctx.lineTo(x + width / 2, y + height) // 气泡框中间底部
        ctx.lineTo(x, y) // 闭合路径
        // 设置三角形颜色并填充
        ctx.fillStyle = '#FFFFFF'
        ctx.fill()

        
     })
    }
   }
}

onMounted(() => {
  canvasFun()
})
3、绘制参与按钮


const canvasFun = () => {
  // 获取当前屏幕宽度
  const screenWidth = window.screen.width
  const screenHeight = window.screen.height
    
  // 这里是针对pad尺寸的适配
  // 小于1281 是pad尺寸
  if (screenWidth < 1281) {
    // console.log('我不是pc')
    const boxs = document.querySelector('.second')
    var offsetLeft = boxs.offsetLeft
    var boxWidth = screenWidth - offsetLeft - 32 // 剪掉当前盒子距离左侧菜单及2边padding尺寸
    var boxHeight = screenHeight - 272 // 剪掉canvas距离顶部、底部的距离

    isPc.value = false
  } else {
    // console.log('我是pc')
    isPc.value = true
  }
    

  const canvas = document.querySelector('#canvas')
  const ctx = canvas.getContext('2d')

  const image = new Image()

  if (basicInfo.value.backgroundImage) {
    // console.log('有图片了')
    const url = `${publicUrl.getFile}?fileName=${
      basicInfo.value.backgroundImage
    }&dispositionType=2&satoken=${Cookies.get('satoken')}`

    image.src = url // 图片链接

    // 监听图片加载完成
    image.onload = function () {

      if (isPc.value == true) {
        canvas.width = 1200
        canvas.height = 680
        newArr.value = copyPointFun(basicInfo.value.chooseSubjectList)
      } else {
        canvas.width = boxWidth
        canvas.height = boxHeight
        // 去计算比例
        newArr.value = pointsFun(
          boxWidth,
          boxHeight,
          basicInfo.value.chooseSubjectList
        )
      }
    
      ctx.drawImage(image, 0, 0, canvas.width, canvas.height)

         // 添加点位交互
      newArr.value.forEach((point) => {
        //--------------设置高度
        let diaheight = setCanvasDiaHeight(point.name)
        //   // 设置填充颜色为黄色
        ctx.fillStyle = '#ffffff'
        //   // -------------绘制矩形
        let pointX = point.x - 50 //实际点位再偏移
        let pointY = point.y - diaheight
        console.log(pointX,pointY,'盒子的位置')
        //创建一个填充矩形(弹框)
        drawRoundedRect(ctx, pointX, pointY, 128, diaheight, 14,1)
        ctx.font = '16px AlibabaPuHuiTi' // 设置字体大小和颜色
        ctx.fontWeight = 'bold' // 再设置字重
        ctx.fillStyle = '#181A1C' // 设置字体大小和颜色
        ctx.textAlign = 'center' // 设置文本水平居中
        ctx.textBaseline = 'middle' // 设置文本基线

        // 处理标题名称,插入换行符
        let pointName = stringLength(point.name)
        // 在换行处拆分文本并多次调用 fillText() 来模拟换行
        var lineheight = 18
        var lines = pointName.split('\n')
        // console.log(lines,'lines')
        // 在弹框中间写入文本
        for (var i = 0; i < lines.length; i++) {
          if (i == 0) {
            ctx.fillText(lines[i], pointX + 64, pointY + 30 + i * lineheight)
          } else {
            ctx.fillText(lines[i], pointX + 54, pointY + 30 + i * lineheight)
          }
        }


        // -------------绘制倒三角
        // 气泡框的起点坐标 (x, y)
        var x = point.x // 40是弹框宽度的一半
        var y = point.y // 55是弹框的高度
        // 倒三角的大小
        var width = 24
        var height = 17

        // 开始绘制
        ctx.beginPath()
        // 绘制倒三角形
        ctx.moveTo(x, y) // 气泡框左上角
        ctx.lineTo(x + width, y) // 气泡框右上角
        ctx.lineTo(x + width / 2, y + height) // 气泡框中间底部
        ctx.lineTo(x, y) // 闭合路径
        // 设置三角形颜色并填充
        ctx.fillStyle = '#FFFFFF'
        ctx.fill()
            

         //--------------------设置按钮
        var btnheight = 20

        // 设置圆角的半径
        var radius = 10
 
        ctx.beginPath()
        let obj = showBtnName.value(point)
        //-------------------是否有带重传标志,再来设置,矩形的宽度和高度
        if (point.reuploadFlag == 1) {
          drawRoundedRect(ctx, point.x - 35, point.y - 30, 43, btnheight, radius,0)
        } else {
          // 填充矩形
          drawRoundedRect(ctx, point.x - 30, point.y - 30, 96, btnheight, radius,0)
        }

        let color = showBtnBgc(obj.label)
        ctx.fillStyle = color
        ctx.fill()
    
      })
        
     })
    }
   }
}

onMounted(() => {
  canvasFun()
})

这里的showBtnName是动态判断名称,因为按钮文本状态很多,showBtnBgc是根据状态去动态写入不同的颜色

4、设置文字颜色
 newArr.value.forEach((point) => {
        ctx.beginPath()
        let obj = showBtnName.value(point)
        let color = showBtnColor(obj.label)
        ctx.fillStyle = color
        ctx.font = '12px AlibabaPuHuiTi' // 设置字体大小和颜色
        if (point.reuploadFlag == 1) {
          ctx.fillText(obj.label, point.x - 15, point.y - 18)
          // 绘制带重传按钮
          ctx.fillStyle = '#E0831F'
          ctx.fillText('待重传', point.x + 40, point.y - 18)
          ctx.closePath()
          ctx.fill()
        } else {
          let leftX = setleft(obj.label, point.x)
          ctx.fillText(obj.label, leftX, point.y - 18)
          ctx.textAlign = 'center' // 设置文本水平居中
          ctx.textBaseline = 'middle' // 设置文本基线
          ctx.closePath()
          ctx.fill()
        }
      })
5、 根据不同状态去展示不同图标,这个图标指得是矩形左上角得图片
const iconIndexFun = (val) => {
  if (val == '完成') {
    return 2
  } else if (val == '已放弃') {
    return 1
  } else if (val == '查看') {
    return 0
  } else if (val == '待解锁') {
    return 3
  } else if (val == '参与' || val == '再次作答') {
    return 4
  } else if (val == '过期') {
    return 5
  } else {
    return 6 //代表没有
  }
}
// 图标数据

 const pointImageURLs = [
    require('@/assets/image/second-image/icon/read.png'),
    require('@/assets/image/second-image/icon/giveUp.png'),
    require('@/assets/image/second-image/icon/finish.png'),
    require('@/assets/image/second-image/icon/lock.png'),
    require('@/assets/image/second-image/icon/exclamationMark.png'),
    require('@/assets/image/second-image/icon/overdue.png'),
  ]
newArr.value.forEach((point) => {
        let obj = showBtnName.value(point)
        iconIndex.value = iconIndexFun(obj.label)
        let diaheight = setCanvasDiaHeight(point.name)
        let pointX = point.x - 60 //实际点位再偏移
        let pointY = point.y - diaheight - 7
        if(iconIndex.value==6||iconIndex.value==4){
          let show = show7Days.value(point)
            if(show){
            //展示7天截至图标
            const img = new Image();
              img.src = pointImageURLs[4];
              img.onload = () => {
                ctx.drawImage(img, pointX, pointY,28,28);
                ctx.fill()
              }
            }else{ 
              // 不展示任何图标
              return
            }
          }else {
            const img = new Image();
            img.src = pointImageURLs[iconIndex.value];
            img.onload = () => {
              ctx.drawImage(img, pointX, pointY,28,28);
              ctx.fill()
            }
          }
      })
6、 绘制7天截至矩形盒子
    newArr.value.forEach((point) => {
        let show = show7Days.value(point)
        if (show == true) {
          let diaheight = setCanvasDiaHeight(point.name)
          ctx.beginPath()
          // 创建渐变对象
          const gradient = ctx.createLinearGradient(0, 0, 0, 18)
          gradient.addColorStop(0, 'rgba(255,255,255,1)') // 渐变起始颜色
          gradient.addColorStop(1, 'rgba(255,226,220,1)') // 渐变结束颜色

          // 设置渐变为填充样式
          ctx.fillStyle = gradient
          drawRoundedRect(
            ctx,
            point.x - 50,
            point.y - diaheight - 3,
            76,
            18,
            10,
            0
          )
          ctx.fill()
          ctx.strokeStyle = 'white'
          ctx.stroke()
        } else {
          return
        }
      })

7、点击对话框进入对应页面

最初需求是点按钮进入,后来改了点击矩形区域就能进入对应页面

onMounted(() => {
  canvasFun()
  const canvas = document.querySelector('#canvas')
  const ctx = canvas.getContext('2d')
  canvas.addEventListener('mousedown', function (e) {
      
    for (var i = 0; i < newArr.value.length; i++) {
      var point = newArr.value[i]
      // 鼠标在屏幕上的位置
      var mouseX = e.clientX;
      var mouseY = e.clientY;
  
      // 鼠标相对于canvas的位置
      var rect = canvas.getBoundingClientRect();
      var canvasX = mouseX - rect.left - canvas.clientLeft;
      var canvasY = mouseY - rect.top - canvas.clientTop;
  
      // 转换为实际的绘图坐标(考虑缩放和平移等情况)
      var actualX = canvasX / canvas.offsetWidth * ctx.canvas.width;
      var actualY = canvasY / canvas.offsetHeight * ctx.canvas.height;

      //-------------获取高度
      let diaheight = setCanvasDiaHeight(point.name)
      // 矩形的起始点位
      let pointX = point.x - 50 //实际点位再偏移
      let pointY = point.y - diaheight
      let rangeX = pointX + 128
      let rangeY = pointY + diaheight

      // 计算点击范围
      if(actualX > pointX &&actualX < rangeX && actualY > pointY && actualY < rangeY){
        console.log(newArr.value[i],'拿到对应点位信息')
        //----下面就是进入对应页面的逻辑了
       
      }
    }
  })
})

这里需要说下,我们实际的点位是图片上倒三角指向的地方(也就是红色圈),所以是要算出实际矩形的点位的,

而矩形的起始点位,也就是先拿到矩形左边定点的位置 pointX,

比如这个点位是100,而宽高都是已知的,就能算出实际矩形所在的点位了

所以用顶点位置+宽=右上边的位置,

用顶点位置+高=得到左下方的位置,

再用左下方的点位+宽=得到右下方的位置,

再最后判断event实际点击的位置是否在这个范围了,这就可以了。

结束

web的基本就到这了,经过测试,这套算法是没问题的,屏幕缩放120%、150%也好,都不影响,并且也适配pad端,至于小屏适配,走h5的那套算法

简单的说,在标注的点位上用canvas实现了全部的样式和交互

虽然是麻烦了点,但确实是实现了,暂时目前没有想到是否还有其他的方法去实现,因为需求是希望配置的1套点位,适配所有端。

当然这套代码里也是有冗余部分,画笔绘制完,需要关闭路径,才能画下一个内容,否则会有冲突,会出现样式相互影响的情况,为避免干扰,我采用的是再次循环的方法去写入样式,当然这样肯定是耗费性能的,目前暂时没想到更好的处理办法。

h5效果图

h5实现步骤

说明

样式的绘制跟web一样

不同的是,移动端点位的等比例适配计算、点击触发范围的计算,别的不变

1、移动端点位的等比例适配计算

a、 1200/手机横屏后的高=x宽高比
       680/手机横屏后的宽=y宽高比
b、再用x轴点位/x宽高比 =实际展示x点位
       y轴就是用y轴点位/y宽高比=实际展示y点位

举例:

点位 x 590

        y370

屏幕设备 宽414高896 (h5效果是要横屏过来,实际计算的时候 896是宽,414是高)

1200/896=1.33
680/414=1.64
x  590/1.33= 443.6
y 370/1.64=225.6

而443.6是移动端要展示的x点位,225.6是y的点位

 // 根据宽高比比例计算实际点位位置
const pointsFun=(arr)=>{
  let webWidth= 1200
  let webHeight=680
  let screenWidth = window.innerHeight //屏幕宽
  let screenHeight = window.innerWidth // 屏幕高
  
  arr.forEach(item=>{
    let webx = webWidth / item.pointX
    let weby = webHeight / item.pointY
    let pintX= screenWidth / webx
    let pintY= screenHeight / weby
    item.pintX=pintX 
    item.pintY=pintY 
  })
  
  return arr
}
 // 监听图片加载完成
    image.onload = function () {

       // 这里要获取屏幕的可视宽高作为canvas的宽高
     canvas.width = window.innerHeight
     canvas.height = window.innerWidth 


      ctx.drawImage(image, 0, 0, canvas.width, canvas.height)

     // 这里是去处理点位的适配计算
      newArr.value=pointsFun(basicInfo.value.chooseSubjectList)

      // 根据点位写入样式
      newArr.value.forEach((point) => {
            ...
       })
    }

这里横屏效果css样式

// 装canvas的父盒子
.interactiveActivitySecond {
  position:relative;
  width: 100vh;
  height: 100vw;
  transform-origin: 0 0;//主要是这个
  transform: rotateZ(90deg) translateY(-100%);//主要是这个
}

2、点击触发范围

没有像web一样去计算他的矩形实际宽高点位计算

是直接设置一个值60,以这个值去判断他的半径

 canvas.addEventListener('mousedown', function (e) {

    const radius = 60
    // 遍历所有标注点
    for (var i = 0; i < newArr.value.length; i++) {
      var point = newArr.value[i]

      // 计算点击坐标与标注点坐标的距离
      var dx = e.offsetX - point.pintX 
      var dy = e.offsetY - point.pintY + 50
      var distance = Math.sqrt(dx * dx + dy * dy)

      // 如果距离小于半径,则认为点击在标注点上
      if (distance < radius) {
            console.log('代表点击到了,去对应页面')
       }
    }
})

结束。

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值