canvas实现画板功能

<!DOCTYPE html>
<html>

<head>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      width: 100vw;
      height: 100vh;
      position: relative;
    }
    .caidan {
      width: 100%;
      height: 80px;
      display: flex;
      justify-content: space-around;
      align-items: center;
    }
    .caidan .btn {
      height: 50px;
      line-height: 50px;
      border: 1px solid pink;
      padding: 0 20px;
      cursor: pointer;
      border-radius: 20px;
    }
    .caidan #clear {
      height: 50px;
      line-height: 50px;
      border: 1px solid pink;
      padding: 0 20px;
      cursor: pointer;
      border-radius: 20px;
    }
    .btn.active {
      box-shadow: 0 0 20px deepskyblue;
    }
    #canvas {
      width: 100%;
      flex: 1;
      border: 1px solid #ccc;
      position: relative;
    }
    .line {
      height: 50px;
      line-height: 50px;
      border: 1px solid pink;
      padding: 0 20px;
      cursor: pointer;
      border-radius: 20px;
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
    }
    .line.active {
      box-shadow: 0 0 20px deepskyblue;
    }
    .xi:before {
      content: '';
      width: 4px;
      height: 4px;
      display: block;
      border-radius: 50%;
      background: #000;
    }
    .normal:before {
      content: '';
      width: 8px;
      height: 8px;
      display: block;
      border-radius: 50%;
      background: #000;
    }
    .cu::before {
      content: '';
      width: 16px;
      height: 16px;
      display: block;
      border-radius: 50%;
      background: #000;
    }
    .color {
      height: 50px;
      line-height: 50px;
      border: 1px solid pink;
      padding: 0 20px;
      cursor: pointer;
      border-radius: 20px;
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
    }
    #download {
      height: 50px;
      line-height: 50px;
      border: 1px solid pink;
      padding: 0 20px;
      cursor: pointer;
      border-radius: 20px;
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
    }
  </style>
</head>

<body>
  <div class="caidan">
    <div class="btn active">画笔</div>
    <div class="btn">矩形</div>
    <div class="btn">圆形</div>
    <div class="line xi active"></div>
    <div class="line normal"></div>
    <div class="line cu"></div>
    <div class="color">
      <input type="color" id="color">
    </div>
    <div id="clear">清空</div>
    <div id="download">下载为图片</div>
    <a href="" id="downloads" download></a>
  </div>
  <canvas id="canvas"></canvas>
  <script>
    /** @type {HTMLCanvasElement} */
    let canvas = document.getElementById('canvas')
    let ctx = canvas.getContext('2d')
    let huabiBtn = document.getElementsByClassName('btn') // 形状
    let lines = document.getElementsByClassName('line') // 粗细
    let color = document.getElementById('color') // 颜色
    let clear = document.getElementById('clear')
    let download = document.getElementById('download')
    canvas.setAttribute("width", canvas.offsetWidth)
    canvas.setAttribute("height", canvas.offsetHeight)
    // 清空画布
    clear.onclick = () => {
      clearhuaban()
    }
    function clearhuaban() {
      let newimg = ctx.createImageData(canvas.offsetWidth, canvas.offsetHeight)
      huaban.imgData = newimg
      ctx.putImageData(huaban.imgData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight)
    }
    ctx.lineWidth = 4
    // 定义画板类型
    let huaban = {
      type: 'huabi',
      isDraw: false, // 是否开始绘画
      beginX: 0, // 开始x轴路径
      beginY: 0, // 开始的y轴路径
      imgData: ctx.getImageData(0, 0, canvas.offsetWidth, canvas.offsetHeight), // 画板存档
    }
    // 粗细按钮
    for (let i = 0; i < lines.length; i++) {
      lines[i].onclick = () => {
        switch (i) {
          case 0:
            ctx.lineWidth = 4
            break
          case 1:
            ctx.lineWidth = 6
            break
          case 2: 
            ctx.lineWidth = 12
            break
        }
        for (let index = 0; index < huabiBtn.length; index++) {
          lines[index].classList.remove("active")
          lines[i].classList.add("active")
        }
      }
    }
    // 颜色切换
    color.onchange = () => {
      ctx.strokeStyle = color.value
    }
    // 切换画板类型
    for (let i = 0; i < huabiBtn.length; i++) {
      huabiBtn[i].onclick = () => {
        changeHuabanType(i) // 切换画笔
        for (let index = 0; index < huabiBtn.length; index++) {
          huabiBtn[index].classList.remove("active")
          huabiBtn[i].classList.add("active")
        }
      }
    }
    // 画板各类型功能
    function changeHuabanType(i) {
      switch (i) {
        case 0:
          huaban.type = "huabi" // 画笔
          huaban.fn = e => {
            let x = e.pageX - canvas.offsetLeft
            let y = e.pageY - canvas.offsetTop
            ctx.lineCap = "round";
            ctx.lineTo(x, y);
            ctx.stroke();
          }
          break;
        case 1:
          huaban.type = 'rect' // 矩形
          huaban.fn = e => {
            let x = e.pageX - canvas.offsetLeft
            let y = e.pageY - canvas.offsetTop
            ctx.putImageData(huaban.imgData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight)
            ctx.beginPath()
            ctx.rect(huaban.beginX, huaban.beginY, x-huaban.beginX, y-huaban.beginY)
            ctx.stroke()
            ctx.closePath()
          }
          break;
        case 2:
          huaban.type = 'round' // 圆形
          huaban.fn = e => {
            let x = e.pageX - canvas.offsetLeft
            let y = e.pageY - canvas.offsetTop
            ctx.putImageData(huaban.imgData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight)
            ctx.beginPath()
            ctx.arc(huaban.beginX, huaban.beginY, Math.sqrt(Math.pow(x-huaban.beginX, 2) + Math.pow(y-huaban.beginY,2)), 0, 2*Math.PI);
            ctx.stroke();
            ctx.stroke()
            ctx.closePath()
          }
          break;
      }
    }
    changeHuabanType(0)
    // 绘画过程
    canvas.onmousedown = e => {
      huaban.isDraw = true
      huaban.beginX = e.pageX - canvas.offsetLeft
      huaban.beginY = e.pageY - canvas.offsetTop
      // 画笔
      if (huaban.type == 'huabi') {
        ctx.beginPath()
        ctx.moveTo(huaban.beginX, huaban.beginY);
      }
    }
    canvas.onmousemove = e => {
      if (huaban.isDraw) {
        huaban.fn && huaban.fn(e)
      }
    }
    // 鼠标抬起
    canvas.onmouseup = () => {
      huaban.isDraw = false
      // 存档,矩形使用
      huaban.imgData = ctx.getImageData(0, 0, canvas.offsetWidth, canvas.offsetHeight)
    }
    download.onclick = () => {
      let imgUrl = canvas.toDataURL()
      let downloads = document.getElementById('downloads')
      downloads.setAttribute('href', imgUrl)
      downloads.click()
    }
  </script>
</body>

</html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值