guanchunjie 3 tahun lalu
induk
melakukan
a25d0eae21

TEMPAT SAMPAH
src/assets/NPC/xj-xz.png


TEMPAT SAMPAH
src/assets/NPC/xj.png


+ 267 - 0
src/components/Adult/preview/components/FreeWriteQP.vue

@@ -0,0 +1,267 @@
+<template>
+  <canvas ref="canvas" id="panel1"></canvas>
+</template>
+
+<script>
+export default {
+  props: {
+    width: {
+      type: Number,
+      default: 800,
+    },
+    height: {
+      type: Number,
+      default: 300,
+    },
+    lineWidth: {
+      type: Number,
+      default: 4,
+    },
+    lineColor: {
+      type: String,
+      default: "#000000",
+    },
+    bgColor: {
+      type: String,
+      default: "",
+    },
+    isCrop: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      hasDrew: false,
+      resultImg: "",
+      canvasTxt: null,
+      canvas: null,
+      redrawCanvas: null,
+      isMouseDown: false,
+      lastLoc: { x: 0, y: 0 },
+      history: [],
+      sratio: 1,
+    };
+  },
+  computed: {
+    ratio() {
+      return this.height / this.width;
+    },
+    stageInfo() {
+      return this.$refs.canvas.getBoundingClientRect();
+    },
+    myBg() {
+      return this.bgColor ? this.bgColor : "rgba(255, 255, 255, 0)";
+    },
+    context() {
+      return this.$refs.canvas.getContext("2d");
+    },
+    redrawCxt() {
+      return this.$refs.canvas.getContext("2d");
+    },
+  },
+  watch: {
+    myBg: function (newVal) {
+      this.$refs.canvas.style.background = newVal;
+    },
+  },
+  beforeMount() {
+    window.addEventListener("resize", this.$_resizeHandler);
+  },
+  beforeDestroy() {
+    window.removeEventListener("resize", this.$_resizeHandler);
+  },
+  mounted() {
+    const canvas = this.$refs.canvas;
+    canvas.height = this.height;
+    canvas.width = this.width;
+    canvas.style.background = this.myBg;
+    this.$_resizeHandler();
+    // 在画板以外松开鼠标后冻结画笔
+    document.onmouseup = () => {
+      this.isMouseDown = false;
+    };
+    this.canvas = canvas;
+    this.redrawCanvas = canvas;
+    this.init();
+  },
+  methods: {
+    reload() {
+      this.reset();
+      this.redraw(this.redrawCxt);
+    },
+    init() {
+      this.canvas.onmousedown = (e) => {
+        this.isMouseDown = true;
+        this.hasDrew = true;
+        this.lastLoc = this.window2Canvas(e.clientX, e.clientY);
+      };
+      this.canvas.onmouseout = (e) => {
+        this.isMouseDown = false;
+      };
+      this.canvas.onmousemove = (e) => {
+        if (this.isMouseDown) {
+          let curLoc = this.window2Canvas(e.clientX, e.clientY); // 获得当前坐标
+          this.draw(this.context, this.lastLoc, curLoc);
+          this.history.push([this.lastLoc, curLoc]);
+          this.lastLoc = Object.assign({}, curLoc); // U know what I mean.
+        }
+      };
+      this.canvas.onmouseup = (e) => {
+        this.isMouseDown = false;
+        if (history.length) {
+          localStorage.setItem("history", JSON.stringify(this.history));
+        }
+      };
+    },
+    window2Canvas(x, y) {
+      let bbox = this.canvas.getBoundingClientRect();
+      return { x: Math.round(x - bbox.left), y: Math.round(y - bbox.top) };
+    },
+    draw(context, lastLoc, curLoc) {
+      if (context) {
+        context.lineWidth = 5;
+        context.beginPath();
+        context.moveTo(lastLoc.x, lastLoc.y);
+        context.lineTo(curLoc.x, curLoc.y);
+        context.strokeStyle = "#000";
+        context.lineCap = "round";
+        context.lineJoin = "round";
+        context.stroke();
+      } else {
+        this.redrawCxt.lineWidth = 5;
+        this.redrawCxt.beginPath();
+        this.redrawCxt.moveTo(lastLoc.x, lastLoc.y);
+        this.redrawCxt.lineTo(curLoc.x, curLoc.y);
+        this.redrawCxt.strokeStyle = "#000";
+        this.redrawCxt.lineCap = "round";
+        this.redrawCxt.lineJoin = "round";
+        this.redrawCxt.stroke();
+      }
+    },
+    redraw(context) {
+      if (localStorage.getItem("history")) {
+        let history = JSON.parse(localStorage.getItem("history"));
+        const len = history.length;
+        let i = 0;
+        const runner = () => {
+          i++;
+          if (i < len) {
+            this.draw(context, history[i][0], history[i][1]);
+            requestAnimationFrame(runner);
+          }
+        };
+        requestAnimationFrame(runner);
+      }
+    },
+
+    $_resizeHandler() {
+      const canvas = this.$refs.canvas;
+      canvas.style.width = this.width + "px";
+      const realw = parseFloat(window.getComputedStyle(canvas).width);
+      canvas.style.height = this.ratio * realw + "px";
+      this.canvasTxt = canvas.getContext("2d");
+      this.canvasTxt.scale(1 * this.sratio, 1 * this.sratio);
+      this.sratio = realw / this.width;
+      this.canvasTxt.scale(1 / this.sratio, 1 / this.sratio);
+    },
+    // 操作
+    generate() {
+      const pm = new Promise((resolve, reject) => {
+        if (!this.hasDrew) {
+          reject(`Warning: Not Signned!`);
+          return;
+        }
+        var resImgData = this.canvasTxt.getImageData(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.canvasTxt.globalCompositeOperation = "destination-over";
+        this.canvasTxt.fillStyle = this.myBg;
+        this.canvasTxt.fillRect(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.resultImg = this.$refs.canvas.toDataURL();
+        var resultImg = this.resultImg;
+        this.canvasTxt.clearRect(
+          0,
+          0,
+          this.$refs.canvas.width,
+          this.$refs.canvas.height
+        );
+        this.canvasTxt.putImageData(resImgData, 0, 0);
+        this.canvasTxt.globalCompositeOperation = "source-over";
+        if (this.isCrop) {
+          const crop_area = this.getCropArea(resImgData.data);
+          var crop_canvas = document.createElement("canvas");
+          const crop_ctx = crop_canvas.getContext("2d");
+          crop_canvas.width = crop_area[2] - crop_area[0];
+          crop_canvas.height = crop_area[3] - crop_area[1];
+          const crop_imgData = this.canvasTxt.getImageData(...crop_area);
+          crop_ctx.globalCompositeOperation = "destination-over";
+          crop_ctx.putImageData(crop_imgData, 0, 0);
+          crop_ctx.fillStyle = this.myBg;
+          crop_ctx.fillRect(0, 0, crop_canvas.width, crop_canvas.height);
+          resultImg = crop_canvas.toDataURL();
+          crop_canvas = null;
+        }
+        resolve(resultImg);
+      });
+      return pm;
+    },
+    reset() {
+      this.canvasTxt.clearRect(
+        0,
+        0,
+        this.$refs.canvas.width,
+        this.$refs.canvas.height
+      );
+      this.$emit("update:bgColor", "");
+      this.$refs.canvas.style.background = "rgba(255, 255, 255, 0)";
+      this.history = [];
+      this.hasDrew = false;
+      this.resultImg = "";
+    },
+    getCropArea(imgData) {
+      var topX = this.$refs.canvas.width;
+      var btmX = 0;
+      var topY = this.$refs.canvas.height;
+      var btnY = 0;
+      for (var i = 0; i < this.$refs.canvas.width; i++) {
+        for (var j = 0; j < this.$refs.canvas.height; j++) {
+          var pos = (i + this.$refs.canvas.width * j) * 4;
+          if (
+            imgData[pos] > 0 ||
+            imgData[pos + 1] > 0 ||
+            imgData[pos + 2] ||
+            imgData[pos + 3] > 0
+          ) {
+            btnY = Math.max(j, btnY);
+            btmX = Math.max(i, btmX);
+            topY = Math.min(j, topY);
+            topX = Math.min(i, topX);
+          }
+        }
+      }
+      topX++;
+      btmX++;
+      topY++;
+      btnY++;
+      const data = [topX, topY, btmX, btnY];
+      return data;
+    },
+  },
+};
+</script>
+
+<style scoped>
+canvas {
+  max-width: 100%;
+  display: block;
+}
+</style>

+ 73 - 4
src/components/Adult/preview/components/Freewrite.vue

@@ -11,7 +11,7 @@
         "
         class="character-target-div"
       >
-        <vueEsign
+        <FreeWriteQP
           :bgColor.sync="bgColor"
           :height="height"
           :isCrop="isCrop"
@@ -20,6 +20,26 @@
           :width="width"
           class="vueEsign"
           ref="esign"
+          id="esign"
+        />
+      </div>
+    </div>
+
+    <div class="imgsave">
+      <div class="image">
+        <div
+          class="character-target-div"
+          v-for="(item, i) in imgarr"
+          :key="'img' + i"
+        >
+          <img class="img" :src="item" alt="" @click="play(i)" />
+        </div>
+      </div>
+      <div class="xj">
+        <img
+          @click="handleGenerate"
+          src="../../../../assets/NPC/xj.png"
+          alt=""
         />
       </div>
     </div>
@@ -27,10 +47,10 @@
 </template>
 
 <script>
-import vueEsign from "vue-esign";
+import FreeWriteQP from "./FreeWriteQP.vue";
 export default {
   components: {
-    vueEsign,
+    FreeWriteQP,
   },
   props: ["lineColor", "lineWidth", "cur", "wordNum"],
   data() {
@@ -39,6 +59,8 @@ export default {
       height: 256,
       bgColor: "",
       isCrop: false,
+      history: [],
+      imgarr: [],
     };
   },
   computed: {},
@@ -49,6 +71,22 @@ export default {
   },
   //方法集合
   methods: {
+    play(index) {
+      let c = document.getElementById("esign");
+      let cxt = document.getElementById("esign").getContext("2d");
+      cxt.clearRect(0, 0, c.width, c.height);
+      let history = this.history[index];
+      const len = history.length;
+      let i = 0;
+      const runner = () => {
+        i++;
+        if (i < len) {
+          this.$refs.esign.draw(null, history[i][0], history[i][1]);
+          requestAnimationFrame(runner);
+        }
+      };
+      requestAnimationFrame(runner);
+    },
     handelReset() {
       this.$refs.esign.reset();
     },
@@ -57,8 +95,10 @@ export default {
         .generate()
         .then((res) => {
           let Book_img = res.replace("data:image/png;base64,", "");
+          this.history.push(this.$refs.esign.history);
+          this.imgarr.push(Book_img);
           //console.log(Book_img);
-          //this.textOcr(res.replace("data:image/png;base64,", ""));
+          // this.textOcr(res.replace("data:image/png;base64,", ""));
         })
         .catch((err) => {
           console.log(err);
@@ -82,6 +122,35 @@ export default {
 //@import url(); 引入公共css类
 .freewrite {
   width: 100%;
+
+  .imgsave {
+    margin-top: 8px;
+    display: flex;
+    justify-content: space-between;
+    .image {
+      > div {
+        width: 28px;
+        height: 28px;
+        background: #fff url("../../../../assets/NPC/chinaTianRed.png") center
+          no-repeat;
+        background-size: 100% 100%;
+      }
+      .img {
+        width: 100%;
+        height: 100%;
+        cursor: pointer;
+      }
+    }
+
+    .xj {
+      border-radius: 4px;
+      cursor: pointer;
+      img {
+        width: 16px;
+        height: 16px;
+      }
+    }
+  }
   .strockred {
     position: relative;
     margin: 0 auto;

+ 3 - 3
src/components/Adult/preview/components/Practice.vue

@@ -338,7 +338,7 @@ export default {
   .right-content {
     position: relative;
     width: 288px;
-    height: 338px;
+    height: 364px;
     background: #f3f3f3;
     border-radius: 16px;
     box-sizing: border-box;
@@ -356,7 +356,7 @@ export default {
       align-items: center;
       padding: 0;
       list-style: none;
-      margin-top: 16px;
+      margin-top: 44px;
       > li {
         height: 34px;
         width: 124px;
@@ -381,7 +381,7 @@ export default {
     }
     .footer {
       position: absolute;
-      bottom: 80px;
+      bottom: 100px;
       width: 100%;
       padding-right: 40px;
       display: flex;