首页 > 其他分享 >#yyds干货盘点#用canvas实现一个简单的画板

#yyds干货盘点#用canvas实现一个简单的画板

时间:2023-09-01 16:36:50浏览次数:34  
标签:yyds canvas const 画板 window context addEventListener rect

画板的功能

  • 修改画笔颜色;
  • 修改画笔粗细;
  • 橡皮擦;
  • 重置画板;
  • 撤销上一步;
  • 保存成图片;

一步步实现

<canvas id="myCanvas" width="400" height="400"></canvas>

class Board {
  constructor(id) {
    this.canvas = document.getElementById(id);
    this.context = this.canvas.getContext('2d');
    this.isDrawing = false;
    this.posX = 0;
    this.posY = 0;
    this.init();
  }
  init() {
    const bindDown = this.handleMouseDown.bind(this);
    const bindMove = this.handleMouseMove.bind(this);
    this.canvas.addEventListener('mousedown', bindDown);
    this.canvas.addEventListener('mousemove', bindMove);
    window.addEventListener('mouseup', () => {
      this.isDrawing = false;
    });
  }
  handleMouseDown(e) {
    const rect = this.canvas.getBoundingClientRect();
    this.posX = e.clientX - rect.left;
    this.posY = e.clientY - rect.top;
    this.isDrawing = true;
  }
  handleMouseMove(e) {
    if (this.isDrawing === true) {
      const rect = this.canvas.getBoundingClientRect();
      this.drawLine(this.context, this.posX, this.posY,
         e.clientX - rect.left, e.clientY - rect.top);
      this.posX = e.clientX - rect.left;
      this.posY = e.clientY - rect.top;
    }
  }
  drawLine(context, x1, y1, x2, y2) {
    context.beginPath();
    context.strokeStyle = 'black';
    context.lineWidth = 1;
    context.moveTo(x1, y1);
    context.lineTo(x2, y2);
    context.stroke();
    context.closePath();
  }
}
new Board('myCanvas');

第二步,可以修改画笔颜色;

<input id="colorPicker" type="color" />

document.getElementById('colorPicker').addEventListener('change', e => {
      b.changeColor(e.target.value);
    })
    
    class Board {
        constructor(id, color = '#000') {
              this.penColor = color; 
        }  
        drawLine(context, x1, y1, x2, y2) {
          context.strokeStyle = this.penColor;          
        }
        changeColor(color) {
        this.penColor = color;
      }              
    }

第三步,修改画笔粗细;

ctx.lineWidth = number;

第四步,橡皮擦;

context.globalCompositeOperation = 'destination-out';参照刮刮乐功能。

第五步,重置画板;

context.clearRect(0, 0, width, height);

第六步,撤销上一步;

this.canvas.toDataURL()将当前canvas保存为base64的图片,存放在数组中。再设置一个索引,撤销/恢复修改索引的值,从数组中取出对应的图片。

第七步,保存为图片;

创建一个a标签,href为toDataURL()生成的图片,模拟点击事件,点击a链接。

完整代码

<div class="opera">
    <input id="colorPicker" type="color" />
    <select id="fontsizeSelect">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
    </select>
    <button id="eraser">橡皮擦</button>
    <button id="reset">重置</button>
    <button id="revoke">撤销</button>
    <button id="recover">恢复</button>
    <button id="saveAsPic">保存为图片</button>
  </div>
  <canvas id="myCanvas" width="400" height="400"></canvas>
class Board {
      constructor(id, color = '#000', fontsize = 1) {
        this.canvas = document.getElementById(id);
        this.context = this.canvas.getContext('2d');
        this.isDrawing = false;
        this.posX = 0;
        this.posY = 0;
        this.penColor = color;
        this.fontsize = fontsize;
        this.isErasing = false;
        this.step = 0;
        this.histroyList = [];
        this.init();
      }
      init() {
        const bindDown = this.handleMouseDown.bind(this);
        const bindMove = this.handleMouseMove.bind(this);
        this.canvas.addEventListener('mousedown', bindDown);
        this.canvas.addEventListener('mousemove', bindMove);
        window.addEventListener('mouseup', () => {
          this.isDrawing = false;
        });
        this.canvas.addEventListener('mouseup', () => {
          this.step++;
          if (this.step < this.histroyList.length) {
            this.histroyList.length = this.step;
          }
          this.histroyList.push(this.canvas.toDataURL());
        });
        this.histroyList.push(this.canvas.toDataURL());
      }
      handleMouseDown(e) {
        const rect = this.canvas.getBoundingClientRect();
        this.posX = e.clientX - rect.left;
        this.posY = e.clientY - rect.top;
        this.isDrawing = true;
      }
      handleMouseMove(e) {
        const rect = this.canvas.getBoundingClientRect();
        if (this.isErasing) {
          this.context.globalCompositeOperation = 'destination-out';
          this.context.beginPath();
          this.context.arc(e.clientX - rect.left, e.clientY - rect.top,
             10, 0, Math.PI * 2);
          this.context.fill();
        } else if (this.isDrawing === true) {
          this.drawLine(this.context, this.posX, this.posY,
         e.clientX - rect.left, e.clientY - rect.top);
          this.posX = e.clientX - rect.left;
          this.posY = e.clientY - rect.top;
        }
      }
      drawLine(context, x1, y1, x2, y2) {
        context.beginPath();
        context.strokeStyle = this.penColor;
        context.lineWidth = this.fontsize;
        context.moveTo(x1, y1);
        context.lineTo(x2, y2);
        context.stroke();
        context.closePath();
      }
      changeColor(color) {
        this.penColor = color;
      }
      changeFontSize(size) {
        this.fontsize = size;
      }
      switchEraseStatus() {
        this.isErasing = !this.isErasing;
      }
      clearBoard() {
        this.context.clearRect(0, 0, window.myCanvas.width,
     window.myCanvas.height);
        this.step = 0;
        this.histroyList = [];
      }
      revoke() {
        if (this.step > 0) {
          this.step--;
          this.context.clearRect(0, 0, window.myCanvas.width, 
        window.myCanvas.height);
          let pic = new Image();
          pic.src = this.histroyList[this.step];
          pic.addEventListener('load', () => {
            this.context.drawImage(pic, 0, 0);
          })
        } else {
          console.log('不能继续撤销了')
        }
      }
      recover() {
        if (this.step < this.histroyList.length - 1) {
          this.step++;
          this.context.clearRect(0, 0, window.myCanvas.width,
       window.myCanvas.height);
          let pic = new Image();
          pic.src = this.histroyList[this.step];
          pic.addEventListener('load', () => {
            this.context.drawImage(pic, 0, 0);
          })
        } else {
          console.log('不能继续恢复了')
        }
      }
      saveAsPic() {
        const el = document.createElement('a');
        el.href = this.canvas.toDataURL();
        el.download = 'canvas';
        const event = new MouseEvent('click');
        el.dispatchEvent(event);
      }
    }
    const b = new Board('myCanvas');


    window.colorPicker.addEventListener('change', e => {
      b.changeColor(e.target.value);
    })


    window.fontsizeSelect.addEventListener('change', e => {
      b.changeFontSize(window.fontsizeSelect.value);
    })


    window.eraser.addEventListener('click', () => {
      b.switchEraseStatus();
    })


    window.reset.addEventListener('click', () => {
      b.clearBoard();
    })


    window.revoke.addEventListener('click', () => {
      b.revoke();
    })


    window.recover.addEventListener('click', () => {
      b.recover();
    })


    window.saveAsPic.addEventListener('click', () => {
      b.saveAsPic();
    })

标签:yyds,canvas,const,画板,window,context,addEventListener,rect
From: https://blog.51cto.com/u_11365839/7324133

相关文章

  • # yyds干货盘点 # 分享一个Python字符串替换的基础题目(上篇)
    大家好,我是皮皮。一、前言前几天在Python最强王者群【莫生气】问了一个Python字符串基础处理的问题,一起来看看吧。二、实现过程这里大家对于strip()函数理解不深刻的话,很容易犯迷糊,这里答案就是输出一个字符c。因为strip会把参数ab分开来一个个的删除,如果是strs.strip('abc')会把整......
  • android短视频开发,js如何设置canvas绕图形中心旋转
    android短视频开发,js如何设置canvas绕图形中心旋转1.准备一个页面拟写一个页面,用于实验,代码如下 <!DOCTYPEhtml><html><head><metacharset="utf-8"><metaname="viewport"content="width=device-width,initcal-scale=1.0"/><title>......
  • canvas组件
    以下是使用Python的Tkinter库中的Canvas组件的一些常用方法的示例代码: ```pythonimporttkinterastk defcreate_canvas(root):  canvas=tk.Canvas(root)  returncanvas #在Canvas组件上绘制图形defdraw_shape(canvas,shape,**kwargs):  canva......
  • uniapp使用canvas电子签名
    <template><viewclass="draw-page"><viewclass="draw-content"><canvasstyle="width:100%;height:100%"ref="sign"canvas-id="sign"id=&qu......
  • # yyds干货盘点 # 有大佬知道Pandas这个上面的如何改别名吗?
    大家好,我是皮皮。一、前言前几天在Python青铜群【9527】问了一个pandas列名处理的问题,一起来看看吧。二、实现过程这里【袁学东】大佬给了一个答案,如下图所示:如此顺利地解决了粉丝的问题。三、总结大家好,我是皮皮。这篇文章主要盘点了一个Python递归的基础问题,文中针对该问题,给出了......
  • # yyds干货盘点 # 盘点一个dataframe读取csv文件失败的问题
    大家好,我是皮皮。一、前言前几天在Python钻石群【心田有垢生荒草】问了一个Pandas数据处理的问题,一起来看看吧。大佬们求教个方法 现在有个数据量很大的dataframe 要吐csv格式 但结果总是串行 加了encoding='utf-8'还是没解决 还有其他方法么?下图是他提供的图片:二、实现......
  • # yyds干货盘点 # 通过pandas读取excel的数据,但是读取的结果显示后面四位变了?
    大家好,我是皮皮。一、前言前几天在Python最强王者群【wen】问了一个Pandas数据处理的问题,一起来看看吧。请教:通过pandas读取exlce的数据,其中,A列的数据为账号数字,原数据为6226093585801315,但是读取的结果显示6226093585800672,后面四位变了。df=pd.read_excel('销售数据.xlsx').conb......
  • 详情讲解canvas实现电子签名
    签名的实现功能我们要实现签名:1.我们首先要鼠标按下,移动,抬起。经过这三个步骤。我们可以实现一笔或者连笔。按下的时候我们需要移动画笔,可以使用moveTo来移动画笔。e.pageX,e.pageY来获取坐标位置移动的时候我们进行绘制ctx.lineTo(e.pageX,e.pageY)ctx.stroke()......
  • # yyds干货盘点 # 盘点一个pandas读取excel数据并处理的小需求
    大家好,我是皮皮。一、前言前几天在Python最强王者群【wen】问了一个pandas数据处理的问题,一起来看看吧。通过pandas读取excel数据,其中两列是交易的备注信息,对A列数据筛选并把结果输出到C列。如果A列中有['吉利','奔驰','福特']三个字段,C列标记为‘汽车品牌’,如果A列有['NIKE','李宁......
  • canvas实现签名
    在开源项目中发现canvas实现签名功能以此记录:http://www.youlai.tech/pages/52d5c3/HTML:<divclass="canvas-dom"><el-buttonplaintype="text"style="margin-left:20px;margin-top:20px;font-size:18px;"@click="back">返回<......