vue + canvas 简单绘图代码

pc的


canvas.png

移动的


canvas1.png

优化版本 使用 Promise 做了一个流程控制避免了之前快速更新造成的图画缺失,统一了pc和移动的绘图方法函数

<template>
  <div class="draw">
    <div class="drawTop" ref="drawTop" v-if="lineStep == lineNum">
      <div class="drawTopContrllor" @click="isUnfoldFun">
        <span>{{ isUnfoldText }}</span>
      </div>
      <div>
        <el-button type @click="resetAll">清空</el-button>
        <el-button type @click="repeal">撤销</el-button>
        <el-button type @click="canvasRedo">恢复</el-button>
        <el-button type @click="downLoad">下载</el-button>
        <el-button type @click="resetData">重置</el-button>
      </div>
      <div>
        <el-select v-model="type" placeholder="选择绘制类型">
          <el-option
            v-for="(item, index) in typeOption"
            :key="index"
            :label="item.label"
            :value="item.value"
          ></el-option>
        </el-select>
      </div>
      <div v-if="type == 'P'">
        边数:
        <el-input-number
          v-model="lineNum"
          :min="2"
          :step="1"
          label="描述文字"
          @change="lineStep = lineNum"
        ></el-input-number>
      </div>
      <div v-if="type == 'E'">
        扁的程度:
        <el-input-number
          v-model="ellipseR"
          :min="0.1"
          :max="0.9"
          :step="0.1"
          label="描述文字"
        ></el-input-number>
      </div>
      <div>
        边框粗细:
        <el-input-number
          v-model="lineWidth"
          :min="0"
          :step="0.1"
          label="描述文字"
        ></el-input-number>
      </div>
      <div>
        <el-radio-group v-model="isFill">
          <el-radio :label="true">填充</el-radio>
          <el-radio :label="false">不填充</el-radio>
        </el-radio-group>
      </div>
      <div v-if="isFill">
        填充颜色:
        <el-color-picker v-model="fillStyle"></el-color-picker>
      </div>
      <div>
        线条颜色:
        <el-color-picker v-model="strokeStyle"></el-color-picker>
      </div>
      <div>
        背景颜色:
        <el-color-picker
          v-model="canvasBack"
          @change="changeCanvasBack"
        ></el-color-picker>
      </div>
    </div>
    <div class="drawTop" v-else>
      <div>
        <el-button type @click="resetP('all')">取消</el-button>
      </div>
    </div>
    <section class="content"></section>
  </div>
</template>

<script>
const keys = {
  pc: {
    eventDown: 'onmousedown',
    eventUp: 'onmouseup',
    eventMove: 'onmousemove',
    xKey: 'layerX',
    yKey: 'layerY',
  },
  mobile: {
    eventDown: 'ontouchstart',
    eventUp: 'ontouchend',
    eventMove: 'ontouchmove',
    xKey: 'pageX',
    yKey: 'pageY',
  },
}
export default {
  name: 'draw',
  data() {
    return {
      canvas: '', // 画布对象
      ctx: '', // canvas Context('2d') 对象
      lineWidth: 1, // 线宽
      type: 'L', // 图形类型 默认线条
      typeOption: [
        { label: '线', value: 'L' },
        { label: '多边形', value: 'P' },
        { label: '圆', value: 'C' },
        { label: '矩形', value: 'R' },
        { label: '正方形', value: 'Rs' },
        { label: '椭圆', value: 'E' },
      ],
      isFill: false, // 是否填充
      canvasHistory: [], // 存放画布每一次操作之后的状态
      step: 0, // 历史数组长度记录 截断数组使用
      fillStyle: '#fff', // 填充色
      strokeStyle: '#fff', // 笔触色
      canvasBack: '#000', // 画布背景色
      lineNum: 2, // 多边形边数
      linePeak: [], // 多边形每一步的落点位置
      lineStep: 2, // 多边形剩余步数
      ellipseR: 0.5, // 椭圆两中心点的偏移距离
      isUnfold: false, // 操作区控制选项
      isUnfoldText: '展开操作区',
    }
  },
  computed: {
    // pc 移动 统一参数配置区
    terminal() {
      let terminal = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(
        navigator.userAgent
      )
      let obj = terminal ? keys.mobile : keys.pc
      return Object.assign({}, obj, { isMobile: terminal })
    },
  },
  mounted() {
    let _this = this
    let content = document.getElementsByClassName('content')[0]
    this.canvas = document.createElement('canvas')
    this.canvas.width = content.clientWidth
    this.canvas.height = content.clientHeight

    this.ctx = this.canvas.getContext('2d')

    this.ctx.fillStyle = this.canvasBack
    this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)

    this.canvasHistory.push(_this.canvas.toDataURL())

    this.ctx.globalCompositeOperation = this.type
    content.appendChild(this.canvas)
    this.bindEventLisner()
  },
  methods: {
    // 手机端是否展开操作区
    isUnfoldFun() {
      this.isUnfold = !this.isUnfold
      if (this.isUnfold) {
        this.$refs.drawTop.style.height = 'auto'
        this.isUnfoldText = '收起操作区'
      } else {
        this.$refs.drawTop.style.height = '30px'
        this.isUnfoldText = '展开操作区'
      }
    },
    // 重置数据
    resetData() {
      this.fillStyle = '#fff'
      this.strokeStyle = '#fff'
      this.canvasBack = '#000'
      this.lineNum = 2
      this.linePeak = []
      this.lineStep = 2
      this.ellipseR = 0.5
      this.lineWidth = 1
      this.type = 'L'
      this.changeCanvasBack()
    },
    // 下载画布
    downLoad() {
      let url = this.canvas.toDataURL('image/png')
      let fileName = 'canvas.png'
      if ('download' in document.createElement('a')) {
        // 非IE下载
        const elink = document.createElement('a')
        elink.download = fileName
        elink.style.display = 'none'
        elink.href = url
        document.body.appendChild(elink)
        elink.click()
        document.body.removeChild(elink)
      } else {
        // IE10+下载
        navigator.msSaveBlob(url, fileName)
      }
    },
    // 底色更改,更改后所有东西都不存在
    changeCanvasBack() {
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.fillStyle = this.canvasBack
      this.ctx.globalAlpha = 1
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
      this.canvasHistory = []
      this.canvasHistory.push(this.canvas.toDataURL())
      this.step = 0
    },
    // 清空画布及历史记录
    resetAll() {
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.fillStyle = this.canvasBack
      this.ctx.globalAlpha = 1
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
      this.canvasHistory = []
      this.canvasHistory.push(this.canvas.toDataURL())
      this.step = 0
    },
    // 清空当前画布
    reset(globalAlpha) {
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.ctx.fillStyle = this.canvasBack
      this.ctx.globalAlpha = globalAlpha ? globalAlpha : 1
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
    },
    // 绘制多边形时,取消按钮,及绘制完成之后的数据重置
    resetP(val) {
      this.linePeak = []
      this.lineStep = this.lineNum
      if (val) {
        this.reset()
        this.rebroadcast()
      }
    },
    // 创建线性渐变
    createLinearGradient(x, y, x1, y1) {
      let linearGradient = this.ctx.createLinearGradient(x, y, x1, y1)
      linearGradient.addColorStop(0, 'skyblue')
      linearGradient.addColorStop(1, 'darkturquoise')
      return linearGradient
    },
    // 创建环形渐变
    createRadialGradient(x, y, r, x1, y1, r1) {
      let radialGradient = this.ctx.createRadialGradient(x, y, r, x1, y1, r1)
      radialGradient.addColorStop(0, 'red')
      radialGradient.addColorStop(1, 'white')
      return radialGradient
    },
    // 撤销方法
    repeal() {
      if (this.step >= 1) {
        this.step = this.step - 1
        let canvasPic = new Image()
        console.log(this.step)
        canvasPic.src = this.canvasHistory[this.step]
        canvasPic.addEventListener('load', () => {
          this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
          this.ctx.globalAlpha = 1
          this.ctx.drawImage(canvasPic, 0, 0)
        })
      } else {
        this.$message.warning('不能再继续撤销了')
      }
    },
    // 恢复方法
    canvasRedo() {
      if (this.step < this.canvasHistory.length - 1) {
        if (this.step == 0) {
          this.step = 1
        } else {
          this.step++
        }
        let canvasPic = new Image()
        canvasPic.src = this.canvasHistory[this.step]
        canvasPic.addEventListener('load', () => {
          this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
          this.ctx.globalAlpha = 1
          this.ctx.drawImage(canvasPic, 0, 0)
        })
      } else {
        this.$message.warning('已经是最新的记录了')
      }
    },
    // 绘制历史数组中的最后一个
    rebroadcast() {
      let _this = this
      return new Promise((resolve, reject) => {
        let canvasPic = new Image()
        canvasPic.src = _this.canvasHistory[_this.step]
        canvasPic.addEventListener('load', () => {
          _this.ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height)
          _this.ctx.globalAlpha = 1
          _this.ctx.drawImage(canvasPic, 0, 0)
          resolve()
        })
      })
    },
    // 获取角度,绘制椭圆
    getAngle(px, py, mx, my) {
      let x = Math.abs(px - mx)
      let y = Math.abs(py - my)
      let z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
      let cos = x / z
      let radina = Math.acos(cos) //用反三角函数求弧度
      let angle = Math.floor(180 / (Math.PI / radina)) //将弧度转换成角度
      if (mx > px && my == py) {
        //鼠标在x轴正方向上
        angle = 0
      }
      if (mx > px && my < py) {
        //鼠标在第一象限
        angle = -angle
      }
      if (mx == px && my > py) {
        //鼠标在y轴负方向上
        angle = 90
      }
      if (mx < px && my < py) {
        //鼠标在第二象限
        angle = -90 - (90 - angle)
      }
      if (mx < px && my == py) {
        //鼠标在x轴负方向
        angle = -180
      }
      if (mx < px && my > py) {
        //鼠标在第三象限
        angle = -180 - angle
      }
      if (mx > px && my > py) {
        //鼠标在第四象限
        angle = angle
      }
      return (angle * Math.PI) / 180
    },
    // 绑定事件,判断分支
    bindEventLisner() {
      const { eventDown, eventUp, isMobile, xKey, yKey } = this.terminal
      let _this = this
      let r1, r2 // 绘制圆形,矩形需要
      this.canvas[eventDown] = function (target) {
        const e = isMobile ? target.changedTouches[0] : target
        r1 = e[xKey]
        r2 = e[yKey]
        _this.useChooseFun(e, 'begin', r1, r2)
      }
      this.canvas[eventUp] = function (target) {
        const e = isMobile ? target.changedTouches[0] : target
        _this.useChooseFun(e, 'end', r1, r2)
      }
    },
    useChooseFun(target, status, r1, r2) {
      let _this = this
      const { eventMove, xKey, yKey, isMobile } = this.terminal
      let fun = this[`draw${this.type}`]
      if (status == 'begin') {
        if (this.type == 'L') {
          this.ctx.beginPath()
          this.ctx.moveTo(target[xKey], target[yKey])
        }
        if (this.type == 'P') {
          return
        }
        _this.canvas[eventMove] = function (target) {
          let e = isMobile ? target.changedTouches[0] : target
          _this.type != 'L' && _this.reset()
          fun?.(e, r1, r2, status)
          _this.type != 'L' && _this.closeStoke(0.5)
        }
      } else if (status == 'end') {
        if (this.type == 'L') {
          this.ctx.closePath()
          _this.setStepAndHistory()
          return
        }
        if (this.type == 'P') {
          fun?.(target, r1, r2, status)
          return
        }
        _this.rebroadcast().then((res) => {
          fun?.(target, r1, r2, status)
          _this.closeStoke(1)
          _this.setStepAndHistory()
        })
      }
    },
    closeStoke(globalAlpha) {
      this.ctx.globalAlpha = globalAlpha
      this.ctx.strokeStyle = this.strokeStyle
      if (this.isFill) this.ctx.fillStyle = this.fillStyle
      this.ctx.lineWidth = this.lineWidth
      this.ctx.closePath()
      this.isFill ? this.ctx.fill() : this.ctx.stroke()
    },
    setStepAndHistory() {
      const { eventMove } = this.terminal
      this.step = this.step + 1
      if (this.step < this.canvasHistory.length - 1) {
        this.canvasHistory.length = this.step // 截断数组
      }
      this.canvasHistory.push(this.canvas.toDataURL())
      this.canvas[eventMove] = null
    },
    drawC(e, r1, r2, status) {
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      let r
      r = Math.sqrt(Math.pow(r1 - x, 2) + Math.pow(r2 - y, 2))
      this.ctx.beginPath()
      this.ctx.arc(r1, r2, r, 0, 2 * Math.PI)
    },
    drawL(e, r1, r2, status) {
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      this.ctx.lineTo(x, y)
      this.ctx.strokeStyle = this.strokeStyle
      this.ctx.lineWidth = this.lineWidth
      this.ctx.stroke()
    },
    drawRs(e, r1, r2, status) {
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      let r
      r = Math.abs(Math.min(x - r1, y - r2))
      let rx = x - r1 < 0 ? -r : r
      let ry = y - r2 < 0 ? -r : r
      this.ctx.beginPath()
      this.ctx.rect(r1, r2, rx, ry)
    },
    drawR(e, r1, r2, status) {
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      let rx = x - r1
      let ry = y - r2
      this.ctx.beginPath()
      this.ctx.rect(r1, r2, rx, ry)
    },
    // 绘制多边形
    drawP(e, r1, r2, status) {
      let _this = this
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      if (status == 'begin') {
      } else if (status == 'end') {
        _this.reset()
        _this.linePeak.push({ x: x, y: y })
        _this.lineStep = _this.lineStep - 1
        _this.ctx.beginPath()
        _this.ctx.strokeStyle = _this.strokeStyle
        _this.ctx.lineWidth = _this.lineWidth
        for (let i in _this.linePeak) {
          let peak = _this.linePeak[i]
          if (i == 0) {
            _this.ctx.moveTo(peak.x, peak.y)
          } else {
            _this.ctx.lineTo(peak.x, peak.y)
          }
          _this.ctx.stroke()
        }
        if (_this.lineStep == 0) {
          _this.reset()
          _this.rebroadcast().then((res) => {
            _this.ctx.beginPath()
            _this.ctx.strokeStyle = _this.strokeStyle
            _this.ctx.lineWidth = _this.lineWidth
            for (let i in _this.linePeak) {
              let peak = _this.linePeak[i]
              if (i == 0) {
                _this.ctx.moveTo(peak.x, peak.y)
              } else {
                _this.ctx.lineTo(peak.x, peak.y)
              }
            }
            _this.closeStoke(1)
            _this.resetP()
            _this.setStepAndHistory()
          })
        }
      }
    },
    drawE(e, r1, r2, status) {
      const { isMobile, xKey, yKey } = this.terminal
      let x = e[xKey],
        y = e[yKey]
      let r = Math.sqrt(Math.pow(r1 - x, 2) + Math.pow(r2 - y, 2)),
        deg = this.getAngle(r1, r2, x, y)
      this.ctx.beginPath()
      this.ctx.ellipse(r1, r2, r, r * this.ellipseR, deg, 0, 2 * Math.PI)
    },
  },
}
</script>

<style scope>
* {
  box-sizing: border-box;
}
body,
html,
#app {
  overflow: hidden;
}
.draw {
  height: 100%;
  width: 100%;
  min-width: 420px;
  display: flex;
  flex-direction: column;
}
.content {
  flex-grow: 1;
  height: 100%;
  width: 100%;
}
.drawTop {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 5px;
  height: 52px;
}
.drawTop > div {
  display: flex;
  align-items: center;
  padding: 5px 5px;
}
div.drawTopContrllor {
  display: none;
}
@media screen and (max-width: 1200px) {
  .drawTop {
    position: absolute;
    background-color: white;
    width: 100%;
    flex-direction: column;
    align-items: flex-start;
    height: 30px;
    overflow: hidden;
  }
  .drawTopContrllor {
    display: flex !important;
    height: 30px;
    width: 100%;
    justify-content: center;
    align-items: center;
    padding: 0 !important;
  }
}
</style>

第一个版本 只保留了有删除和更改的函数

// 绘制历史数组中的最后一个
rebroadcast() {
  let canvasPic = new Image();
  canvasPic.src = this.canvasHistory[this.step];
  canvasPic.addEventListener("load", () => {
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    this.ctx.globalAlpha = 1;
    this.ctx.drawImage(canvasPic, 0, 0);
    this.loading = true;
  });
}
// 绑定事件,判断分支
bindEventLisner() {
  let terminal = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(
    navigator.userAgent
  );
  let _this = this;
  let r1, r2; // 绘制圆形,矩形需要
  if (terminal) {
    this.canvas.ontouchstart = function(e) {
      console.log("ontouchstart");
      let touch = e.changedTouches[0];
      if (_this.type == "C") {
        r1 = touch.pageX;
        r2 = touch.pageY;
        _this.createCM(touch, "begin", r1, r2);
      } else if (_this.type == "L") {
        _this.createLM(touch, "begin");
      } else if (_this.type == "Rs") {
        r1 = touch.pageX;
        r2 = touch.pageY;
        _this.createRsM(touch, "begin", r1, r2);
      } else if (_this.type == "R") {
        r1 = touch.pageX;
        r2 = touch.pageY;
        _this.createRM(touch, "begin", r1, r2);
      } else if (_this.type == "P") {
        _this.createPM(touch, "begin");
      } else if (_this.type == "E") {
        r1 = touch.pageX;
        r2 = touch.pageY;
        _this.createEM(touch, "begin", r1, r2);
      }
    };
    this.canvas.ontouchend = function(e) {
      console.log("ontouchend");
      let touch = e.changedTouches[0];
      if (_this.type == "C") {
        _this.createCM(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "L") {
        _this.createLM(touch, "end");
      } else if (_this.type == "Rs") {
        _this.createRsM(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "R") {
        _this.createRM(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "P") {
        _this.createPM(touch, "end");
      } else if (_this.type == "E") {
        _this.createEM(touch, "end", r1, r2);
        r1 = null;
        r2 = null;
      }
    };
  } else {
    this.canvas.onmousedown = function(e) {
      console.log("onmousedown");
      if (_this.type == "C") {
        r1 = e.layerX;
        r2 = e.layerY;
        _this.createC(e, "begin", r1, r2);
      } else if (_this.type == "L") {
        _this.createL(e, "begin");
      } else if (_this.type == "Rs") {
        r1 = e.layerX;
        r2 = e.layerY;
        _this.createRs(e, "begin", r1, r2);
      } else if (_this.type == "R") {
        r1 = e.layerX;
        r2 = e.layerY;
        _this.createR(e, "begin", r1, r2);
      } else if (_this.type == "P") {
        _this.createP(e, "begin");
      } else if (_this.type == "E") {
        r1 = e.layerX;
        r2 = e.layerY;
        _this.createE(e, "begin", r1, r2);
      }
    };
    this.canvas.onmouseup = function(e) {
      console.log("onmouseup");
      if (_this.type == "C") {
        _this.createC(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "L") {
        _this.createL(e, "end");
      } else if (_this.type == "Rs") {
        _this.createRs(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "R") {
        _this.createR(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      } else if (_this.type == "P") {
        _this.createP(e, "end");
      } else if (_this.type == "E") {
        _this.createE(e, "end", r1, r2);
        r1 = null;
        r2 = null;
      }
    };
  }
}
// 绘制线条
createL(e, status) {
  let _this = this;
  if (status == "begin") {
    _this.ctx.beginPath();
    _this.ctx.moveTo(e.layerX, e.layerY);
    _this.canvas.onmousemove = function(e) {
      console.log("onmousemove");
      _this.ctx.lineTo(e.layerX, e.layerY);
      _this.ctx.strokeStyle = _this.strokeStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.ctx.closePath();
    _this.step = _this.step + 1;
    if (_this.step < _this.canvasHistory.length - 1) {
      _this.canvasHistory.length = _this.step; // 截断数组
    }
    _this.canvasHistory.push(_this.canvas.toDataURL());
    _this.canvas.onmousemove = null;
  }
}
// 绘制 圆
createC(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    console.log("onmousemove");
    // _this.ctx.moveTo(e.layerX, e.layerY);
    _this.canvas.onmousemove = function(e) {
      _this.reset();
      r = Math.sqrt(
        Math.pow(r1 - e.layerX, 2) + Math.pow(r2 - e.layerY, 2)
      );
      _this.ctx.beginPath();
      _this.ctx.arc(r1, r2, r, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      r = Math.sqrt(
        Math.pow(r1 - e.layerX, 2) + Math.pow(r2 - e.layerY, 2)
      );
      _this.ctx.beginPath();
      _this.ctx.arc(r1, r2, r, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
// 绘制正方形
createRs(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    console.log("onmousemove");
    _this.canvas.onmousemove = function(e) {
      _this.reset();
      r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let rx = e.layerX - r1 < 0 ? -r : r;
      let ry = e.layerY - r2 < 0 ? -r : r;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let rx = e.layerX - r1 < 0 ? -r : r;
      let ry = e.layerY - r2 < 0 ? -r : r;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
// 绘制矩形
createR(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    console.log("onmousemove");
    _this.canvas.onmousemove = function(e) {
      _this.reset();
      //   r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let rx = e.layerX - r1;
      let ry = e.layerY - r2;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      //   r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let rx = e.layerX - r1;
      let ry = e.layerY - r2;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
// 绘制多边形
createP(e, status, r1, r2) {
  let _this = this;
  if (status == "begin") {
    // _this.canvas.onmousemove = function(e) {
    //   _this.reset(0.5);
    //   _this.ctx.beginPath();
    //   _this.ctx.arc(e.layerX, e.layerY, 5, 0, 2 * Math.PI);
    //   _this.ctx.fillStyle = _this.canvasBack;
    //   _this.ctx.closePath();
    //   _this.ctx.fill();
    // };
  } else if (status == "end") {
    _this.reset();
    _this.linePeak.push({ x: e.layerX, y: e.layerY });
    _this.lineStep = _this.lineStep - 1;
    _this.ctx.beginPath();
    _this.ctx.strokeStyle = _this.strokeStyle;
    _this.ctx.lineWidth = _this.lineWidth;
    for (let i in _this.linePeak) {
      let peak = _this.linePeak[i];
      if (i == 0) {
        _this.ctx.moveTo(peak.x, peak.y);
      } else {
        _this.ctx.lineTo(peak.x, peak.y);
      }
      _this.ctx.stroke();
    }
    if (_this.lineStep == 0) {
      _this.reset();
      _this.rebroadcast();
      let interval = setInterval(() => {
        if (_this.loading) {
          clearInterval(interval);
          _this.loading = false;
        } else {
          return;
        }
        _this.ctx.beginPath();
        _this.ctx.strokeStyle = _this.strokeStyle;
        _this.ctx.lineWidth = _this.lineWidth;
        for (let i in _this.linePeak) {
          let peak = _this.linePeak[i];
          if (i == 0) {
            _this.ctx.moveTo(peak.x, peak.y);
          } else {
            _this.ctx.lineTo(peak.x, peak.y);
          }
        }
        _this.ctx.strokeStyle = _this.strokeStyle;
        if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
        _this.ctx.lineWidth = _this.lineWidth;
        _this.ctx.closePath();
        _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
        _this.resetP();
        _this.step = _this.step + 1;
        if (_this.step < _this.canvasHistory.length - 1) {
          _this.canvasHistory.length = _this.step; // 截断数组
        }
        _this.canvasHistory.push(_this.canvas.toDataURL());
      }, 1);
    }
    // _this.canvas.onmousemove = null;
  }
}
// 绘制椭圆
createE(e, status, r1, r2) {
  let _this = this;
  let r, deg;
  if (status == "begin") {
    console.log("onmousemove");
    // _this.ctx.moveTo(e.layerX, e.layerY);
    _this.canvas.onmousemove = function(e) {
      _this.reset();
      r = Math.sqrt(
        Math.pow(r1 - e.layerX, 2) + Math.pow(r2 - e.layerY, 2)
      );
      deg = _this.getAngle(r1, r2, e.layerX, e.layerY);
      _this.ctx.beginPath();
      _this.ctx.ellipse(r1, r2, r, r * _this.ellipseR, deg, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      r = Math.sqrt(
        Math.pow(r1 - e.layerX, 2) + Math.pow(r2 - e.layerY, 2)
      );
      deg = _this.getAngle(r1, r2, e.layerX, e.layerY);
      _this.ctx.beginPath();
      _this.ctx.ellipse(r1, r2, r, r * _this.ellipseR, deg, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
// 手机端
// 绘制线条
createLM(e, status) {
  let _this = this;
  if (status == "begin") {
    _this.ctx.beginPath();
    _this.ctx.moveTo(e.pageX, e.pageY);
    _this.canvas.ontouchmove = function(e) {
      console.log("ontouchmove");
      let touch = e.changedTouches[0];
      _this.ctx.lineTo(touch.pageX, touch.pageY);
      _this.ctx.strokeStyle = _this.strokeStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.ctx.closePath();
    _this.step = _this.step + 1;
    if (_this.step < _this.canvasHistory.length - 1) {
      _this.canvasHistory.length = _this.step; // 截断数组
    }
    _this.canvasHistory.push(_this.canvas.toDataURL());
    _this.canvas.ontouchmove = null;
  }
}
// 绘制 圆
createCM(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    console.log("ontouchmove");
    // _this.ctx.moveTo(e.layerX, e.layerY);
    _this.canvas.ontouchmove = function(e) {
      _this.reset();
      let touch = e.changedTouches[0];
      r = Math.sqrt(
        Math.pow(r1 - touch.pageX, 2) + Math.pow(r2 - touch.pageY, 2)
      );
      _this.ctx.beginPath();
      _this.ctx.arc(r1, r2, r, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      let touch = e.changedTouches[0];
      r = Math.sqrt(
        Math.pow(r1 - touch.pageX, 2) + Math.pow(r2 - touch.pageY, 2)
      );
      _this.ctx.beginPath();
      _this.ctx.arc(r1, r2, r, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.ontouchmove = null;
    }, 1);
  }
}
// 绘制正方形
createRsM(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    _this.canvas.ontouchmove = function(e) {
      console.log("ontouchmove");
      _this.reset();
      let touch = e.changedTouches[0];
      r = Math.abs(Math.min(touch.pageX - r1, touch.pageY - r2));
      let rx = touch.pageX - r1 < 0 ? -r : r;
      let ry = touch.pageY - r2 < 0 ? -r : r;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      let touch = e.changedTouches[0];
      r = Math.abs(Math.min(touch.pageX - r1, touch.pageY - r2));
      let rx = touch.pageX - r1 < 0 ? -r : r;
      let ry = touch.pageY - r2 < 0 ? -r : r;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.ontouchmove = null;
    }, 1);
  }
}
// 绘制矩形
createRM(e, status, r1, r2) {
  let _this = this;
  let r;
  if (status == "begin") {
    console.log("ontouchmove");
    _this.canvas.ontouchmove = function(e) {
      _this.reset();
      //   r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let touch = e.changedTouches[0];
      let rx = touch.pageX - r1;
      let ry = touch.pageY - r2;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      //   r = Math.abs(Math.min(e.layerX - r1, e.layerY - r2));
      let touch = e.changedTouches[0];
      let rx = touch.pageX - r1;
      let ry = touch.pageY - r2;
      _this.ctx.beginPath();
      _this.ctx.rect(r1, r2, rx, ry);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
// 绘制多边形
createPM(e, status, r1, r2) {
  let _this = this;
  if (status == "begin") {
    // _this.canvas.onmousemove = function(e) {
    //   _this.reset(0.5);
    //   _this.ctx.beginPath();
    //   _this.ctx.arc(e.layerX, e.layerY, 5, 0, 2 * Math.PI);
    //   _this.ctx.fillStyle = _this.canvasBack;
    //   _this.ctx.closePath();
    //   _this.ctx.fill();
    // };
  } else if (status == "end") {
    _this.reset();
    _this.linePeak.push({ x: e.pageX, y: e.pageY });
    _this.lineStep = _this.lineStep - 1;
    _this.ctx.beginPath();
    _this.ctx.strokeStyle = _this.strokeStyle;
    _this.ctx.lineWidth = _this.lineWidth;
    for (let i in _this.linePeak) {
      let peak = _this.linePeak[i];
      if (i == 0) {
        _this.ctx.moveTo(peak.x, peak.y);
      } else {
        _this.ctx.lineTo(peak.x, peak.y);
      }
      _this.ctx.stroke();
    }
    if (_this.lineStep == 0) {
      _this.reset();
      _this.rebroadcast();
      let interval = setInterval(() => {
        if (_this.loading) {
          clearInterval(interval);
          _this.loading = false;
        } else {
          return;
        }
        _this.ctx.beginPath();
        _this.ctx.strokeStyle = _this.strokeStyle;
        _this.ctx.lineWidth = _this.lineWidth;
        for (let i in _this.linePeak) {
          let peak = _this.linePeak[i];
          if (i == 0) {
            _this.ctx.moveTo(peak.x, peak.y);
          } else {
            _this.ctx.lineTo(peak.x, peak.y);
          }
        }
        _this.ctx.strokeStyle = _this.strokeStyle;
        if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
        _this.ctx.lineWidth = _this.lineWidth;
        _this.ctx.closePath();
        _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
        _this.resetP();
        _this.step = _this.step + 1;
        if (_this.step < _this.canvasHistory.length - 1) {
          _this.canvasHistory.length = _this.step; // 截断数组
        }
        _this.canvasHistory.push(_this.canvas.toDataURL());
      }, 1);
    }
    // _this.canvas.onmousemove = null;
  }
}
// 绘制椭圆
createEM(e, status, r1, r2) {
  let _this = this;
  let r, deg;
  if (status == "begin") {
    console.log("ontouchmove");
    // _this.ctx.moveTo(e.layerX, e.layerY);
    _this.canvas.ontouchmove = function(e) {
      _this.reset();
      let touch = e.changedTouches[0];
      r = Math.sqrt(
        Math.pow(r1 - touch.pageX, 2) + Math.pow(r2 - touch.pageY, 2)
      );
      deg = _this.getAngle(r1, r2, touch.pageX, touch.pageY);
      _this.ctx.beginPath();
      _this.ctx.ellipse(r1, r2, r, r * _this.ellipseR, deg, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 0.5;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
    };
  } else if (status == "end") {
    _this.rebroadcast();
    let interval = setInterval(() => {
      if (_this.loading) {
        clearInterval(interval);
        _this.loading = false;
      } else {
        return;
      }
      r = Math.sqrt(Math.pow(r1 - e.pageX, 2) + Math.pow(r2 - e.pageY, 2));
      deg = _this.getAngle(r1, r2, e.pageX, e.pageY);
      _this.ctx.beginPath();
      _this.ctx.ellipse(r1, r2, r, r * _this.ellipseR, deg, 0, 2 * Math.PI);
      _this.ctx.globalAlpha = 1;
      _this.ctx.strokeStyle = _this.strokeStyle;
      if (_this.isFill) _this.ctx.fillStyle = _this.fillStyle;
      _this.ctx.lineWidth = _this.lineWidth;
      _this.ctx.closePath();
      _this.isFill ? _this.ctx.fill() : _this.ctx.stroke();
      _this.step = _this.step + 1;
      if (_this.step < _this.canvasHistory.length - 1) {
        _this.canvasHistory.length = _this.step; // 截断数组
      }
      _this.canvasHistory.push(_this.canvas.toDataURL());
      _this.canvas.onmousemove = null;
    }, 1);
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容

  • 现在关于移动互联网取代PC的言论特别多,的确,移动互联网产品的用户量大都已经远超PC产品,但个人认为,就像电视不能...
    简述_kitty阅读 3,186评论 2 23
  • 怒马说 0、不想读长文的直接看这10条。 1、小程序最早1月9号上线。 2、张小龙说,二维码是未来移动互联网的入口...
    小怒马阅读 658评论 0 1
  • 今天,前同事来机构里一起喝茶聊天,他分享了另外一个教育机构运作模式,好的方面是他们很注重服务的细节,不好的是商业性...
    TA76广新阅读 132评论 0 0
  • 多次因各地的灾情流泪。有一年安徽太湖县水灾,老百姓没吃的,郊外撅得一种黑米充饥。乾隆让地方官呈上一些,尝了一口就哭...
    卜萝月读阅读 547评论 0 1
  • 壹 Some unseen fingers, like an idle breeze, are playing u...
    天月将白阅读 332评论 0 3