From c8d1e1ed1d5c8d20a9aad8554d51001afb3c6312 Mon Sep 17 00:00:00 2001
From: YM <479443481@qq.com>
Date: 星期三, 20 十一月 2024 15:28:27 +0800
Subject: [PATCH] Merge branch 'master' of http://182.92.203.7:2001/r/TextbookReader

---
 src/components/graffiti/index.vue |  243 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 insertions(+), 0 deletions(-)

diff --git a/src/components/graffiti/index.vue b/src/components/graffiti/index.vue
new file mode 100644
index 0000000..4c8034a
--- /dev/null
+++ b/src/components/graffiti/index.vue
@@ -0,0 +1,243 @@
+<!-- 娑傝壊杩炵嚎棰樻帶浠� -->
+<template>
+  <div class="page">
+    <div class="main">
+      <div id="canvas_panel">
+        <canvas id="canvas" :style="{
+            backgroundSize: 'cover',
+            backgroundPosition: 'center',
+          }">褰撳墠娴忚鍣ㄤ笉鏀寔canvas銆�</canvas>
+      </div>
+    </div>
+    <div class="footer">
+      <BrushSize :size="brushSize" @change-size="onChangeSize" @change-color="onChangeColor" />
+      <ToolBtns :tool="brushTool" @change-tool="onChangeTool" />
+    </div>
+  </div>
+</template>
+
+<script>
+  import BrushSize from "./components/brushSize.vue";
+  import ToolBtns from "./components/toolBtns.vue";
+  export default {
+    name: "graffiti",
+    components: { BrushSize, ToolBtns },
+    props: {
+      save: {
+        type: Function,
+      },
+    },
+    data() {
+      return {
+        canvas: null,
+        context: null,
+        painting: false, // 璁板綍鐘舵�侊紝榧犳爣鏄惁鍦ㄦ寜涓嬬姸鎬�
+        historyData: [], // 瀛樺偍鍘嗗彶鏁版嵁锛岀敤浜庢挙閿�
+        brushSize: 2, // 绗斿埛澶у皬
+        brushColor: "#000000", // 绗斿埛棰滆壊
+        brushTool: "brush",
+        canvasOffset: {
+          left: 0,
+          top: 0,
+        },
+      };
+    },
+    mounted() {
+      this.canvas = (this.container ? this.container : document).getElementById(
+        "canvas"
+      );
+      if (this.canvas.getContext) {
+        this.context = this.canvas.getContext("2d", { willReadFrequently: true });
+        // window.addEventListener('resize', updateCanvasPosition);
+        (this.container ? this.container : document).addEventListener(
+          "scroll",
+          this.updateCanvasOffset,
+          true
+        ); // 娣诲姞婊氬姩鏉℃粴鍔ㄤ簨浠剁洃鍚櫒
+        this.getCanvasOffset();
+        this.context.lineGap = "round";
+        this.context.lineJoin = "round";
+        this.canvas.addEventListener("mousedown", this.downCallback);
+        this.canvas.addEventListener("mousemove", this.moveCallback);
+        this.canvas.addEventListener("mouseup", this.closePaint);
+        this.canvas.addEventListener("mouseleave", this.closePaint);
+        setTimeout(() => {
+          this.initCanvas();
+        }, 300);
+      }
+      this.toolClear();
+    },
+    methods: {
+      // 鍒濆鍖� 鐢诲竷锛岃缃ぇ灏忚儗鏅壊
+      initCanvas() {
+        const that = this;
+        const resetCanvas = () => {
+          const elPanel = (
+            this.container ? this.container : document
+          ).getElementById("canvas_panel");
+          console.log("clientWidth"+elPanel.clientWidth);
+          console.log("clientWidth"+elPanel.clientHeight);
+          try {
+            that.canvas.width = elPanel.clientWidth;
+            that.canvas.height = elPanel.clientHeight;
+          } catch (error) { }
+
+          that.context = that.canvas.getContext("2d", {
+            willReadFrequently: true,
+          }); // 娣诲姞杩欎竴琛�
+          that.context.fillStyle = "white";
+          that.context.fillRect(0, 0, that.canvas.width, that.canvas.height);
+          that.context.fillStyle = "black";
+          that.getCanvasOffset(); // 鏇存柊鐢诲竷浣嶇疆
+        };
+        resetCanvas();
+        // 鐩戝惉绐楀彛澶у皬 锛岀獥鍙f敼鍙橀噸鏂版覆鏌撶敾甯�
+        window.addEventListener("resize", resetCanvas);
+      },
+
+      // 鑾峰彇canvas鐨勫亸绉诲��
+      getCanvasOffset() {
+        const rect = this.canvas.getBoundingClientRect();
+        this.canvasOffset.left = rect.left * (this.canvas.width / rect.width); // 鍏煎缂╂斁鍦烘櫙
+        this.canvasOffset.top = rect.top * (this.canvas.height / rect.height);
+      },
+
+      // 璁$畻褰撳墠榧犳爣鐩稿浜巆anvas鐨勫潗鏍�
+      calcRelativeCoordinate(x, y) {
+        return {
+          x: x - this.canvasOffset.left,
+          y: y - this.canvasOffset.top,
+        };
+      },
+      // 榧犳爣鎶捣鏂规硶
+      downCallback(event) {
+        // 鍏堜繚瀛樹箣鍓嶇殑鏁版嵁锛岀敤浜庢挙閿�鏃舵仮澶嶏紙缁樺埗鍓嶄繚瀛橈紝涓嶆槸缁樺埗鍚庡啀淇濆瓨锛�
+        const data = this.context.getImageData(
+          0,
+          0,
+          this.canvas.width,
+          this.canvas.height
+        );
+        this.saveData(data);
+        const { clientX, clientY } = event;
+        const { x, y } = this.calcRelativeCoordinate(clientX, clientY);
+        this.context.beginPath();
+        this.context.moveTo(x, y);
+        this.context.lineWidth = this.brushSize;
+        this.context.strokeStyle =
+          this.brushTool === "eraser" ? "#FFFFFF" : this.brushColor;
+        this.painting = true;
+      },
+      // 榧犳爣绉诲姩鏂规硶(璁$畻鍧愭爣骞舵覆鏌撹建杩�)
+      moveCallback(event) {
+        if (!this.painting) {
+          return;
+        }
+        const { clientX, clientY } = event;
+        const { x, y } = this.calcRelativeCoordinate(clientX, clientY);
+        this.context.lineTo(x, y);
+        this.context.stroke();
+      },
+      closePaint() {
+        this.painting = false;
+      },
+      // 閲嶆柊璁$畻鐢诲竷鐨勫亸绉诲��
+      updateCanvasOffset() {
+        this.getCanvasOffset();
+      },
+      // 鏀瑰彉绗斿埛澶у皬
+      onChangeSize(size) {
+        this.brushSize = size;
+      },
+      // 鏀瑰彉绗斿埛棰滆壊
+      onChangeColor(color) {
+        this.brushColor = color;
+      },
+      // 淇濆瓨锛屾竻绌虹瓑鎸夐挳
+      onChangeTool(tool) {
+        this.brushTool = tool;
+        switch (tool) {
+          case "clear":
+            this.toolClear();
+            break;
+          case "undo":
+            this.toolUndo();
+            break;
+          case "save":
+            this.toolSave();
+            break;
+        }
+      },
+      // 娓呯┖canvas鎵�鏈夊唴瀹�(鑳屾櫙鍥鹃櫎澶�)
+      toolClear() {
+        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+        this.resetToolActive();
+      },
+      // 淇濆瓨鐢诲竷鑳屾櫙鍜屽垝绾垮埌鏈湴鏂规硶
+      toolSave() {
+        var imgData = this.canvas.toDataURL('image/jpeg');
+        console.log(imgData);
+        if (this.save) {
+          this.save(imgData);
+        }
+      },
+      // 杩斿洖涓婁竴姝ユ柟娉�(鎾ら攢)
+      toolUndo() {
+        if (this.historyData.length <= 0) {
+          this.resetToolActive();
+          return;
+        }
+        // 灏嗙敾鐨勪笂涓�姝ユ暟鎹啓鍏anvas 閲嶆柊娓叉煋
+        const lastIndex = this.historyData.length - 1;
+        this.context.putImageData(this.historyData[lastIndex], 0, 0);
+        this.historyData.pop();
+        this.resetToolActive();
+      },
+      // 瀛樺偍鏁版嵁
+      saveData(data) {
+        this.historyData.length >= 50 && this.historyData.shift(); // 璁剧疆鍌ㄥ瓨涓婇檺涓�50姝�
+        this.historyData.push(data);
+      },
+      // 娓呴櫎銆佹挙閿�銆佷繚瀛樼姸鎬佷笉闇�瑕佷繚鎸侊紝鎿嶄綔瀹屽悗鎭㈠绗斿埛鐘舵��
+      resetToolActive() {
+        setTimeout(() => {
+          this.brushTool = "brush";
+        }, 1000);
+      },
+    },
+  };
+</script>
+
+<style scoped>
+  .page {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    height: 100%;
+  }
+
+  .main {
+    flex: 1;
+  }
+
+  .footer {
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    height: 88px;
+  }
+
+  #canvas_panel {
+    width: 100%;
+    height: 100%;
+    margin-bottom: 12px;
+    /* 娑堥櫎绌烘牸褰卞搷 */
+    font-size: 0;
+    background-color: #fff;
+    border-bottom: 1px solid #ccc;
+  }
+  
+  #canvas {
+    cursor: crosshair;
+  }
+</style>
\ No newline at end of file

--
Gitblit v1.9.1