百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

在vue项目中如何使用canvas制作画板

toyiye 2024-07-06 23:32 24 浏览 0 评论


用canvas做画板,效果如下


直线


矩形


其他更多效果可以复制下面的demo尝试


demo

<template>
  <div>
    <div class="container">
      <div class="row">
        <ul class="type">
          <li :class="{'active': chooseType === 'line'}" @click="chooseTypeFn('line')">直线</li>
          <li :class="{'active': chooseType === 'rect'}" @click="chooseTypeFn('rect')">矩形</li>
          <li :class="{'active': chooseType === 'circle'}" @click="chooseTypeFn('circle')">圆圈</li>
          <li :class="{'active': chooseType === 'pen'}" @click="chooseTypeFn('pen')">铅笔</li>
          <li :class="{'active': chooseType === 'curve'}" @click="chooseTypeFn('curve')">曲线</li>
          <li :class="['poly',{'active': chooseType === 'poly'}]" @click="chooseTypeFn('poly')">多边形
            <div :class="['bian',{'hide': chooseType !== 'poly'}]">
              <span>边数</span><a-input-number type="number" :min="3" :max="15" v-model="sides" @change="changePoly"/>
            </div>
          </li>
          <li :class="{'active': chooseType === 'eraser'}" @click="chooseTypeFn('eraser')">橡皮</li>
        </ul>
        <ul class="type">
          <li :class="{'active': borderType === 'stroke'}" @click="chooseBorderTypeFn('stroke')">描边</li>
          <li v-if="chooseType !== 'line' && chooseType !== 'pen'" :class="{'active': borderType === 'fill'}" @click="chooseBorderTypeFn('fill')">填充</li>
        </ul>
        <div class="space"></div>
        <div class="box"><label><span>颜色</span></label><input type="color" name="color" v-model="color" @change="changeColor"></div>
        <div class="box linewidth"><span>线宽</span><a-input-number type="number" :max="150" :min="1" v-model="lineWidth" @change="changeLineWidth"/></div>
        <div class="space"></div>
        <div class="clear shezhi" @click="plotFn('clear')">清空</div>
        <div class="back shezhi" @click="plotFn('back')">撤销</div>
        <div class="save shezhi" @click="plotFn('save')">保存</div>
      </div>
    </div>
    <canvas ref="canvasPlot" :width="canvasWidth" :height="canvasHeight"></canvas>
  </div>
</template>

<script>
function Draw (obj, setting) {
  console.log(setting.type)
  this.obj = obj
  this.type = setting.type || 'stroke'
  this.color = setting.color || '#f00'
  this.width = setting.width || '2'
  this.font = setting.font || '18px bold 黑体'
  this.fillStyle = setting.fillStyle || '#f00'
  this.textAlign = setting.textAlign || 'center'
  this.textBaseline = setting.textBaseline || 'middle'
}
Draw.prototype = {
  init () {
    this.obj.strokeStyle = this.color
    this.obj.lineWidth = this.width
    this.obj.font = this.font
    this.obj.fillStyle = this.fillStyle
    this.obj.textAlign = this.textAlign
    this.obj.textBaseline = this.textBaseline
  },
  rect (x, y, x1, y1) {
    this.init()
    this.obj.beginPath()
    this.obj.rect(x, y, x1 - x, y1 - y)
    if (this.type === 'stroke') {
      this.obj.stroke()
    } else if (this.type === 'fill') {
      this.obj.fill()
    }
  },
  circle (x, y, x1, y1) {
    this.init()
    const r = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2))
    this.obj.beginPath()
    this.obj.arc(x, y, r, 0, 2 * Math.PI)
    if (this.type === 'stroke') {
      this.obj.stroke()
    } else if (this.type === 'fill') {
      this.obj.fill()
    }
  },
  line (x, y, x1, y1) {
    this.init()
    this.obj.beginPath()
    this.obj.moveTo(x, y)
    this.obj.lineTo(x1, y1)
    this.obj.stroke()
  },
  text (content, x, y) {
    this.init()
    this.obj.fillText(content, x, y)
    this.obj.stroke()
  },
  poly (x, y, x1, y1, n) {
    this.init()
    const obj = this.obj
    const r = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2))
    obj.save()
    obj.translate(x, y)
    obj.rotate(Math.PI / 2)
    const nx = r * Math.cos(Math.PI / n)
    const ny = r * Math.sin(Math.PI / n)
    obj.beginPath()
    obj.lineCap = 'round'
    obj.moveTo(nx, ny)
    for (let i = 0; i <= n; i++) {
      obj.rotate(Math.PI * 2 / n)
      obj.lineTo(nx, -ny)
    }
    if (this.type === 'stroke') {
      this.obj.stroke()
    } else if (this.type === 'fill') {
      this.obj.fill()
    }
    obj.restore()
  },
  pen (x, y, x1, y1) {
    this.init()
    this.obj.save()
    this.obj.lineCap = 'round'
    this.obj.lineTo(x1, y1)
    this.obj.stroke()
    this.obj.restore()
  },
  eraser (x, y, x1, y1) {
    this.obj.lineCap = 'round'
    this.obj.clearRect(x1 - 5, y1 - 5, 10, 10)
  },
  cut (x, y, x1, y1) {
    this.init()
    this.obj.save()
    this.obj.setLineDash([4, 2])
    this.obj.beginPath()
    this.obj.lineWidth = 1
    this.obj.rect(x, y, x1 - x, y1 - y)
    this.obj.stroke()
    this.obj.restore()
  },
  curve (cp1x, cp1y, x, y) {
    this.init()
    this.obj.save()
    this.obj.beginPath()
    this.obj.moveTo(cp1y, y)
    this.obj.quadraticCurveTo(cp1x, cp1y, x, y)
    this.obj.stroke()
  }
}
export default {
  data () {
    return {
      chooseType: 'line',
      sides: 3,
      lineWidth: 1,
      borderType: 'stroke',
      color: '#f00',
      plotContext: {}, // canvas对象
      plotData: [],
      plotCoord: {
        x: 0,
        y: 0,
        x2: 0,
        y2: 0
      },
      canvasWidth: 900,
      canvasHeight: 600
    }
  },
  watch: {
  },
  beforeCreate () {
  },
  beforeDestroy () {
  },
  mounted () {
    this.initPlot()
  },
  created () {},
  methods: {
    chooseTypeFn (data) {
      this.chooseType = data
    },
    changePoly (val) {
      this.sides = val
    },
    chooseBorderTypeFn (val) {
      this.borderType = val
    },
    changeColor (val) {
      this.color = val
    },
    changeLineWidth (val) {
      this.lineWidth = val
    },
    /**
     * 绘图操作
     * @param type clear:清空 back:撤回 save:保存
     */
    plotFn (type) {
      if (type === 'clear') {
        this.plotData = []
        this.plotContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      }
      if (type === 'back') {
        this.plotData.pop()
        this.plotContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
        if (this.plotData.length > 0) {
          this.plotContext.putImageData(this.plotData[this.plotData.length - 1], 0, 0, 0, 0, this.canvasWidth, this.canvasHeight)
        }
      }
      if (type === 'save') {
        const reg = this.$refs.canvasPlot.toDataURL('image/png')
        console.log(reg)
        location.href = reg
      }
    },
    initPlot () {
      const _this = this
      const canvas = this.$refs.canvasPlot
      _this.plotContext = canvas.getContext('2d')
      _this.$refs.canvasPlot.width = _this.canvasWidth
      _this.$refs.canvasPlot.height = _this.canvasHeight
      canvas.onmousedown = function (e) {
        _this.plotCoord.x = e.offsetX
        _this.plotCoord.y = e.offsetY
        if (this.chooseType === 'pen') {
          _this.plotContext.beginPath()
          _this.plotContext.moveTo(_this.plotCoord.x, _this.plotCoord.y)
        }
        if (this.chooseType === 'eraser') {
          _this.plotContext.clearRect(_this.plotCoord.x - 5, _this.plotCoord.y - 5, 10, 10)
        }
        // 实例化构造函数
        const draw = new Draw(_this.plotContext, { type: _this.borderType, color: _this.color, width: _this.lineWidth })
        canvas.onmousemove = function (e) {
          _this.plotCoord.x2 = e.offsetX
          _this.plotCoord.y2 = e.offsetY
          if (_this.chooseType !== 'eraser') {
            _this.plotContext.clearRect(0, 0, _this.canvasWidth, _this.canvasHeight)
            if (_this.plotData.length !== 0) {
              _this.plotContext.putImageData(_this.plotData[_this.plotData.length - 1], 0, 0, 0, 0, _this.canvasWidth, _this.canvasHeight)
            }
          }
          if (_this.chooseType === 'poly') {
            draw[_this.chooseType](_this.plotCoord.x, _this.plotCoord.y, _this.plotCoord.x2, _this.plotCoord.y2, _this.sides)
          } else {
            draw[_this.chooseType](_this.plotCoord.x, _this.plotCoord.y, _this.plotCoord.x2, _this.plotCoord.y2)
          }
        }
        document.onmouseup = function () {
          canvas.onmousemove = null
          document.onmouseup = null
          _this.plotData.push(_this.plotContext.getImageData(0, 0, _this.canvasWidth, _this.canvasHeight))
        }
      }
    },
    fnProcessHttpError (err) {
      if (err.response) {
        switch (err.response.code) {
          default:
            this.$error({
              title: '错误',
              content: err.response.message
            })
            break
        }
      } else {
        this.$error({
          title: '错误',
          content: err.toString()
        })
      }
    }
  }
}
</script>

<style>
</style>
<style scoped>
body,html{ padding: 0;margin: 0;width: 100%; height: 100%; background-repeat: no-repeat; background-position: 0 0 no-repeat; background-size: cover; overflow: hidden; font-family: "Microsoft yahei"; background-color: #fff; }
.hide{display: none !important;}
.ant-input-number {width:45px;}
li{ list-style-type: none; }
ul{ padding-left: 10px }
canvas{ position: fixed; left: 280px; top: 5px; display: block; cursor: pointer; background-color: #FFFFFF; border: 1px solid #CCCCCC; }
.container{
  width:260px;
  height:60px;
  padding: 10px;
}
.container h2{
  width:100%;
  height:60px;
  font-size:22px;
  text-align:center;
  color: #ff377e;
  font-weight:normal;
  line-height:60px;
  border-bottom:1px solid #000;
}
.container h3{
  width:100%;
  height:30px;
  font-size:18px;
  text-align:center;
  color: #41b1ff;
  font-weight:normal;
  line-height:30px;
}
.row{ width: 100%; height: auto; background-color: rgba(192,192,192,0.50); overflow: hidden;        }
.type{
  width:100%;
  height:auto;
  margin:20px 0;
  padding-bottom:10px;
  border-bottom:1px solid #fff;
}
.type:after{
  content:"";
  display:block;
  clear:both;
}
.type li{
  float:left;
  width:90px;
  height:45px;
  margin:10px;
  background-color:#0078ff;
  color:#fff;
  font-size:18px;
  line-height:45px;
  text-align:center;
  border-radius:5px;
  cursor:pointer;
  transition:all 0.7s;
}
.type li:hover{
  background-color:#fff;
  color:#0078ff;
  box-shadow:0 0 10px rgba(0, 120, 255, 0.77);
}
.type .active{
  background-color:#fff;
  color:#0078ff;
  box-shadow:0 0 10px rgba(0, 120, 255, 0.77);
}
.style{
  width:100%;
  height:40px;
}
.style li{
  float:left;
  width:90px;
  height:45px;
  background-color:#FFBC00;
  color:#fff;
  font-size:18px;
  line-height:45px;
  text-align:center;
  border-radius:5px;
  cursor:pointer;
  transition:all 0.7s;
}
.style li:hover{
  color: #ffa800;
  background-color:#fff;
  box-shadow:0 0 10px rgba(255, 232, 95, 0.77);
}
.style .active{
  color: #ffa800;
  background-color:#fff;
  box-shadow:0 0 10px rgba(255, 232, 95, 0.77);
}
.style li:nth-child(1){
  margin-left:25px;
}
.style li:nth-child(2){
  margin-left:20px;
}
.poly{
  position:relative;
}
.bian{
  position:absolute;
  left:100px;top:0;
  width:90px;
  height:auto;
  border-radius:5px;
  background-color:#EC494E;
  overflow:hidden;
  transform:scale(1.2);
}
.bian span{
  display:block;
  float:left;
  width:40px;
  height:45px;
  font-size:16px;
  color:#fff;
  text-align:center;
  line-height:40px;
  color:#fff;
  transition:all 0.7s;
}
.bian input{
  float:left;
  width:45px;
  height:35px;
  margin-top:5px;
  border:1px solid #fff;
  box-sizing:border-box;
  text-align:center;
  line-height:40px;
  font-size:18px;
  color:#fff;
  background:#EC494E;
  border-radius:3px;
  box-shadow:0 0 0 4px #fff inset;
  transition:all 0.7s;
}
.cut,.create,.back{
  float:left;
  width:90px;
  height:45px;
  margin-left:25px;
  margin-bottom:15px;
  background-color: #5bd219;
  color:#fff;
  font-size:18px;
  line-height:45px;
  text-align:center;
  border-radius:5px;
  cursor:pointer;
}
.copy,.clear,.save{
  float:left;
  width:90px;
  height:45px;
  margin-left:20px;
  margin-bottom:15px;
  background-color: #5bd219;
  color:#fff;
  font-size:18px;
  line-height:45px;
  text-align:center;
  border-radius:5px;
  cursor:pointer;
}
.shezhi{
  transition:all 0.7s;
}
.shezhi.active, .shezhi:hover{
  background:#fff;
  color:#5bd219;
}
.create{
  position:relative;
}
.xinjian{
  position:absolute;
  left:0;top:0;
  width:200px;
  height:165px;
  border-radius:5px;
  background-color:#EC494E;
  box-shadow:0 0 15px rgba(236, 73, 78, 0.76);
  cursor:default;
  display:none;
}
.xinjian:hover{
  color:#fff;
}
.xinjian_before{
  position:absolute;
  right:0;
  top:0;
  width:20px;
  height:20px;
  color:#fff;
  line-height:16px;
  text-indent:-1px;
  font-size:30px;
  border:1px solid #fff;
  transform:rotate(45deg);
  border-radius:50%;
  cursor:pointer;
}
.xinjian h6{
  width:100%;
  height:50px;
  color:#fff;
  line-height:50px;
  text-align:center;
  font-size:20px;
  font-weight:normal;
}
#ding{
  width:60px;
  height:30px;
  font-size:14px;
  border-radius:3px;
  color:#fff;
  background-color:#0078ff;
  border:0;
  outline:none;
  cursor:pointer;
  box-shadow:0 0 10px rgba(0, 120, 255, 0.5);
}
.xinjian_width,.xinjian_height{
  float:left;
  width:85px;
  height:40px;
  margin-left:10px;
  border-radius:5px;
  margin-bottom:20px;
  background-color:#FFBC00;
}
.xinjian_width:hover,.xinjian_height:hover{
  background-color:#fff;
  color:#000;
}
.xinjian_width span,.xinjian_height span{
  float:left;
  width:30px;
  height:100%;
  font-size:16px;
  text-align:center;
  line-height:40px;
}
.xinjian_width input,.xinjian_height input{
  float:left;
  margin-top:5px;
  width:50px;
  height:30px;
  text-align:center;
  line-height:30px;
  font-size:14px;
  border:1px solid #FFBC00;
  box-sizing:border-box;
}
.box{
  float:left;
  width:90px;
  height:auto;
  background-color:#EC494E;
  overflow:hidden;
  border-radius:5px;
  transition:all 0.7s;
}
.box{
  margin-left:25px;
}
.linewidth{
  margin-left:20px;
}
.box:hover{
  color:#f00;
  background-color:#fff;
}
.box span{
  display:block;
  float:left;
  width:40px;
  height:45px;
  font-size:16px;
  color:#fff;
  text-align:center;
  line-height:40px;
  transition:all 0.3s;
}
.box:hover span{color:#f00;}
.box input{
  float:left;
  width:45px;
  height:35px;
  margin-top:5px;
  border:1px solid #fff;
  box-sizing:border-box;
  text-align:center;
  line-height:40px;
  font-size:18px;
  color:#fff;
  background:#EC494E;
  border-radius:3px;
  box-shadow:0 0 0 4px #fff inset;
  transition:all 0.3s;
}
.box2 span{
  width:55px;
}
.box2 input{
  width:140px;
}
.space{
  float:left;
  width:100%;
  height:0;
  border-bottom:1px solid #fff;
  margin:20px 0;
}
</style>


demo还有很多不足之处,欢迎小伙伴纠错,O(∩_∩)O~

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码