手写输入法

来到新公司三个月了,碰到的新奇的功能有写一个手写输入法组件,具体实现思想为:

  1. 创建一个画布供用户写字
  2. 画布中如果有字且已经一秒钟都没有变,就把画布中笔画的坐标作为接口入参,获取到响应后清除画布中的笔画,并把响应中的文字显示在画布右侧,用户点击选择右侧的字
    效果如图:

1
2

3、实现核心代码:


// 触摸
    initCanvas () {
      if (!this.canvas) {
        return;
      }
      let canvasWidth = document.documentElement.clientWidth / 2;
      let canvasHeight = document.documentElement.offsetHeight * 0.3;
      this.canvas.width = canvasWidth;
      this.canvas.height = canvasHeight;
      this.$refs.wordBtn.style.width = this.$refs.result.offsetWidth + "px";
      this.drawBackground();
      this.canvas.addEventListener(
        "touchstart",
        (event) => {
          document.addEventListener("touchstart", this.preHandler, {
            passive: false,
          });
          this.drawBegin(event);
        },
        { passive: false }
      );
      this.canvas.addEventListener(
        "touchend",
        (event) => {
          document.addEventListener("touchend", this.preHandler, {
            passive: false,
          });
          this.drawEnd();
        },
        { passive: false }
      );
    },
    drawBegin (e) {
      this.stageInfo = this.canvas.getBoundingClientRect();
      // 双击禁止选择文字
      // window.getSelection()
      //   ? window.getSelection().removeAllRanges()
      //   : document.selection.empty();
      this.cxt = this.canvas.getContext("2d");
      this.cxt.strokeStyle = "#000";
      this.cxt.beginPath();
      let x = e.changedTouches[0].clientX - this.stageInfo.left;
      let y = e.changedTouches[0].clientY - this.stageInfo.top;
      this.cxt.moveTo(x, y);
      this.writingPos.push({ x: Math.round(x), y: Math.round(y) });
      this.canvas.addEventListener(
        "touchmove",
        (e) => {
          this.drawing(e);
        },
        { passive: false }
      );
    },
    drawing (e) {
      let x = e.changedTouches[0].clientX - this.stageInfo.left;
      let y = e.changedTouches[0].clientY - this.stageInfo.top;
      this.cxt.lineTo(x, y);
      this.writingPos.push({ x: Math.round(x), y: Math.round(y) });
      this.cxt.lineWidth = 4;
      this.cxt.stroke();
    },
    drawEnd () {
      let beforeCanvas = this.canvas.toDataURL();
      this.writingPos.push({ x: 0, y: 0 });
      setTimeout(() => {
        if (
          beforeCanvas === this.canvas.toDataURL() &&
          this.writingPos.length > 0
        ) {
          // 调用输入法接口
          this.getWordOptions();
        }
      }, 1000);
      this.cxt.closePath();
      document.removeEventListener("touchstart", this.preHandler, false);
      document.removeEventListener("touchend", this.preHandler, false);
      document.removeEventListener("touchmove", this.preHandler, false);
    },
    preHandler (e) {
      if (e.preventDefault) {
        e.preventDefault();
      } else {
        e.returnValue = false;
      }
    },
    //鼠标
    mouseInitCanvas () {
      if (!this.canvas) {
        return;
      }
      let canvasWidth = document.documentElement.clientWidth / 2;
      let canvasHeight = document.documentElement.offsetHeight * 0.3;
      this.canvas.width = canvasWidth;
      this.canvas.height = canvasHeight;
      this.drawBackground();
      this.canvas.addEventListener(
        "mousedown",
        (event) => {
          document.addEventListener("mousedown", this.preHandler, {
            passive: false,
          });
          this.mouseDrawBegin(event);
        },
        { passive: false }
      );
      this.canvas.addEventListener(
        "mousemove",
        (e) => {
          this.mouseDrawing(event);
        },
        { passive: false }
      );
      this.canvas.addEventListener(
        "mouseup",
        (event) => {
          document.addEventListener("mouseup", this.preHandler, {
            passive: false,
          });
          this.mouseDrawEnd(event);
        },
        { passive: false }
      );
    },
    mouseDrawBegin (e) {
      this.stageInfo = this.canvas.getBoundingClientRect();
      window.getSelection()
        ? window.getSelection().removeAllRanges()
        : document.selection.empty();
      this.cxt.strokeStyle = "#000";
      this.cxt.beginPath();
      this.cxt.moveTo(e.offsetX, e.offsetY);
      this.writingPos.push({ x: e.offsetX, y: e.offsetY });
      this.drawingshow = 1;
    },
    mouseDrawing (e) {
      if (this.drawingshow === 1) {
        this.writingPos.push({ x: e.offsetX, y: e.offsetY });
        this.cxt.lineTo(e.offsetX, e.offsetY);
        this.cxt.lineWidth = 4;
        this.cxt.stroke();
      } else if (this.drawingshow === 0) {
        this.cxt.moveTo(e.offsetX, e.offsetY);
      } else {
        this.cxt.closePath();
      }
    },
    mouseDrawEnd (e) {
      let beforeCanvas = this.canvas.toDataURL();
      this.writingPos.push({ x: 0, y: 0 });
      setTimeout(() => {
        if (
          beforeCanvas === this.canvas.toDataURL() &&
          this.writingPos.length > 0
        ) {
          // 调用输入法接口
          this.getWordOptions();
        }
      }, 1000);
      this.cxt.closePath();
      this.drawingshow = 2;
      document.removeEventListener("mousedown", this.preHandler, {
        passive: false,
      });
      document.removeEventListener("mouseup", this.preHandler, {
        passive: false,
      });
      document.removeEventListener("mousemove", this.preHandler, {
        passive: false,
      });
    },
    clear () {
      if (this.cxt) {
        this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.drawBackground();
      }
    },
    //绘制虚线
    drawDashed (x, y, x1, y1, color, width) {
      this.cxt.lineWidth = width;
      this.cxt.strokeStyle = color;
      this.cxt.beginPath();
      this.cxt.setLineDash([5, 5]);
      this.cxt.moveTo(x, y);
      this.cxt.lineTo(x1, y1);
      this.cxt.stroke();
      this.cxt.closePath();
      // 将线条转为实现
      this.cxt.setLineDash([]);
    },
    drawBackground () {
      //绘制水平线
      this.drawDashed(
        0,
        0.5 * this.canvas.height,
        this.canvas.width,
        0.5 * this.canvas.height,
        "#e7e7e7",
        1
      );
      //绘制垂直线
      this.drawDashed(
        this.canvas.width / 2,
        0,
        this.canvas.width / 2,
        this.canvas.height,
        "#e7e7e7",
        1
      );
    },
    getWordOptions() {
      // 将画布中写的字的坐标传给C#,获取到响应res
          (res) => {
            const resData = JSON.parse(res);
            const value = JSON.parse(resData.stateValue);
            // console.log("=======输入法响应=======", resData);
            if (resData.stateType === 0) {
              this.wordOptions = value;
              this.writingPos = [];
              this.words += value[0];
              this.clear();
            } else {
              api.openAlert(this, resData.stateMsg, "提示");
            }
          }
    }
posted @ 2023-05-22 16:17  straightforward  阅读(8)  评论(0)    收藏  举报