Browse Source

修改为手动涂画版本

caner 1 year ago
parent
commit
c7dbc3045c
2 changed files with 150 additions and 88 deletions
  1. 110 48
      src/pages/views/draw/assets/js/draw.js
  2. 40 40
      src/pages/views/draw/index.vue

+ 110 - 48
src/pages/views/draw/assets/js/draw.js

@@ -1,14 +1,12 @@
-import { lineSplit, polygon, pointsWithinPolygon, lineString, nearestPointOnLine, point, getCoord } from "@turf/turf";
-
 class DrawCanvas {
 class DrawCanvas {
 
 
   constructor() {
   constructor() {
     this._ctx = null
     this._ctx = null
     this._canvas = null
     this._canvas = null
-    this._executionArr = { s: 0, e: 0, arr: [], type: 1, outPath: [], splitPath: null } //每移动一笔的数据
+    this._executionArr = { s: 0, e: 0, arr: [], type: 0, w: 0, h: 0, fillStyle: null } //没一笔的相关数据
     this._pathArr = [] //抬起落下为一笔
     this._pathArr = [] //抬起落下为一笔
-    this._fillStyle = null // 每笔的样式
     this._matrix = new DOMMatrix() //旋转矩阵
     this._matrix = new DOMMatrix() //旋转矩阵
+    this._outPath = null //外轮廓
   }
   }
 
 
   _init({ canvas, dicTypePath = '', callBack }) {
   _init({ canvas, dicTypePath = '', callBack }) {
@@ -29,7 +27,7 @@ class DrawCanvas {
     if (path) {
     if (path) {
       this._ctx.stroke(path)
       this._ctx.stroke(path)
       this._ctx.clip(path) //IOS真机裁切后,导致无法画图
       this._ctx.clip(path) //IOS真机裁切后,导致无法画图
-      this._executionArr.outPath = this.getPathPonit(dicTypePath) //获取所有外轮阔点
+      this._outPath = path
     }
     }
     // 事件监听
     // 事件监听
     canvas.addEventListener('touchstart', this.touchStart.bind(this))
     canvas.addEventListener('touchstart', this.touchStart.bind(this))
@@ -40,60 +38,124 @@ class DrawCanvas {
   }
   }
 
 
   touchStart(event) {
   touchStart(event) {
+    const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
+    const x = clientX - offsetLeft
+    const y = clientY - offsetTop
     if (!this._executionArr.type) {
     if (!this._executionArr.type) {
-      const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
-      this._executionArr.s = clientX - offsetLeft
-      this._executionArr.e = clientY - offsetTop
+      this._executionArr.s = x
+      this._executionArr.e = y
+      this._executionArr.arr = [[x, y]]
     }
     }
-    this._executionArr.arr = []
-    console.log('点击');
+    if (this._executionArr.type) {
+      this._executionArr.arr = []
+    }
+    console.log('点击', this._executionArr);
   }
   }
 
 
   touchMove(event) {
   touchMove(event) {
     const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
     const { clientX, clientY, target: { offsetLeft, offsetTop } } = event.targetTouches[0]
     const x = clientX - offsetLeft
     const x = clientX - offsetLeft
     const y = clientY - offsetTop
     const y = clientY - offsetTop
-    this._executionArr.arr.push([x, y])
-    this.drawLine(x, y)
+
+    // 画笔
+    if (this._executionArr.type) {
+      const { w, h, fillStyle } = this._executionArr
+      const X = x - (w / 2)
+      const Y = y - (h / 2)
+      this._executionArr.arr.push([X, Y])
+      this._ctx.fillStyle = fillStyle
+      this._ctx.fillRect(X, Y, w, h)
+    }
+
+    // 画线
+    if (!this._executionArr.type) {
+      this._executionArr.arr.push([x, y])
+      this.drawLine(x, y)
+    }
+
   }
   }
 
 
   touchEnd() {
   touchEnd() {
-    const { arr: line, outPath, type } = this._executionArr
-    if (line.length > 2) {
-      // 画线才记录数据
-      this._pathArr.push({
-        ...this._fillStyle,
-        path: this._executionArr
-      })
-      // 查找最近的点
-      // const st = point(line[0])
-      // const et = point(line[line.length - 1])
-      // const sp = getCoord(nearestPointOnLine(lineString(outPath), st))
-      // const ep = getCoord(nearestPointOnLine(lineString(outPath), et))
-
-      // // 补齐 方向有问题
-      // this._executionArr.s = line[0][0]
-      // this._executionArr.e = line[0][1]
-      // this.drawLine(sp[0], sp[1])
-      // this._executionArr.s = line[line.length - 1][0]
-      // this._executionArr.e = line[line.length - 1][1]
-      // this.drawLine(ep[0], ep[1])
-
-      // line.unshift(sp)
-      // line.push(ep)
-      // console.log(22222222, sp, ep, this._executionArr);
-
-
-      // 画线后切分
-      // if (!type && outPath) {
-      //   const splitPath = lineSplit(lineString(line), lineString(outPath))
-      //   if (!splitPath.features.length) console.log('数据无法切分,请重画');
-      //   this._executionArr.splitPath = splitPath
-      //   console.log('画线结束,切割区域', this._pathArr);
-      // }
+    this._pathArr.push({
+      ...this._executionArr
+    })
+    console.log('结束', this._pathArr);
+  }
+
+  // 撤销
+  pathBack() {
+    // 删除每个移动数据
+    if (!this._pathArr.length) return
+    // 清空画布
+    this._ctx.clearRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height)
+    this._ctx.fillStyle = "#FFFFFF";
+    this._ctx.fillRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height);
+    if (this._outPath) this._ctx.stroke(this._outPath)
+    this._pathArr.pop()
+    // 重画
+    for (let k = 0; k < this._pathArr.length; k++) {
+      const el = this._pathArr[k];
+      // 画笔
+      if (el.type && el.fillStyle) {
+        for (let z = 0; z < el.arr.length; z++) {
+          const es = el.arr[z];
+          this._ctx.fillStyle = el.fillStyle
+          this._ctx.fillRect(es[0], es[1], el.w, el.h)
+        }
+      }
+      // 画线
+      if (!el.type) {
+        this._ctx.beginPath();
+        this._ctx.strokeStyle = '#2080f0'
+        this._ctx.moveTo(el.arr[0], el.arr[1]);
+        for (let j = 0; j < el.arr.length; j++) {
+          const es = el.arr[j];
+          this._ctx.lineTo(es[0], es[1]);
+        }
+        this._ctx.stroke();
+      }
+    }
+    console.log('撤销', this._pathArr);
+  }
+
+  // 清空
+  pathClear() {
+    console.log('清空');
+    if (!this._pathArr.length) return
+    this._ctx.clearRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height)
+    this._ctx.fillStyle = "#FFFFFF";
+    this._ctx.fillRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height);
+    if (this._outPath) this._ctx.stroke(this._outPath)
+  }
+
+  // 保存
+  pathSave(callBack) {
+    if (!this._canvas) {
+      callBack(null);
+      return
     }
     }
-    console.log('结束', this._fillStyle, this._pathArr);
+    const imgData = this._canvas.toDataURL()
+    callBack(imgData)
+  }
 
 
+  // 切换画笔
+  changeBrush({ url = '', w = 10, h = 10, angle = 0, value = 0 }) {
+    this._executionArr.type = value
+    console.log('切换画笔1', this._matrix, value);
+    if (!url || !this._executionArr.type) return
+    const img = new Image()
+    img.src = url
+    img.onload = () => {
+      const fillStyle = this._ctx.createPattern(img, 'repeat')
+      if (angle && this._matrix) {
+        this._matrix.rotateSelf(angle)
+        fillStyle.setTransform(this._matrix)
+      }
+      this._executionArr.fillStyle = fillStyle
+      this._executionArr.w = w
+      this._executionArr.h = h
+      console.log('切换画笔2', fillStyle, this._matrix, value);
+    }
   }
   }
 
 
   // 画线
   // 画线
@@ -147,10 +209,10 @@ class DrawCanvas {
   destory() {
   destory() {
     this._ctx = null
     this._ctx = null
     this._canvas = null
     this._canvas = null
-    this._executionArr = []
+    this._executionArr = {}
     this._pathArr = []
     this._pathArr = []
-    this._style = null
     this._matrix = null
     this._matrix = null
+    this._outPath = null
   }
   }
 }
 }
 
 

+ 40 - 40
src/pages/views/draw/index.vue

@@ -10,36 +10,34 @@
       :render-label="renderLabel"
       :render-label="renderLabel"
       @update:value="changeOption"
       @update:value="changeOption"
     />
     />
-    <label>
-      旋转角度º:
-      <input
-        v-model="angle"
+    <n-input-group>
+      <n-input-group-label>旋转角度º</n-input-group-label>
+      <n-input-number
+        v-model:value="angle"
         type="number"
         type="number"
-      >
-    </label>
-    <n-button
-      type="tertiary"
-      block
-    >
-      撤销
-    </n-button>
-    <n-button
-      type="tertiary"
-      block
-    >
-      清空
-    </n-button>
-    <n-button
-      type="info"
-      block
+        style="width: 100%;"
+        :min="0"
+        :max="360"
+        @update:value="changeOption(null, options[check])"
+      />
+    </n-input-group>
+    <template
+      v-for="(item, index) in btns"
+      :key="index"
     >
     >
-      保存
-    </n-button>
+      <n-button
+        :type="item.type"
+        block
+        @click="item.fn"
+      >
+        {{ item.name }}
+      </n-button>
+    </template>
   </div>
   </div>
 </template>
 </template>
 <script setup lang='ts'>
 <script setup lang='ts'>
-import {
-  h, onMounted, onUnmounted, ref
+import {
+  h, onMounted, onUnmounted, ref
 } from 'vue'
 } from 'vue'
 import { DrawCanvas } from './assets/js/draw'
 import { DrawCanvas } from './assets/js/draw'
 
 
@@ -207,6 +205,17 @@ const dicTypePath = {
   0: 'M175.000036,0.5 C222.664535,0.5 265.865535,21.1909654 297.358963,54.7296453 C328.90593,88.3253418 348.705559,134.812441 349.476653,186.303442 L349.490723,188.280824 L349.5,247.5 L0.5,247.5 L0.5,188.283766 C0.787224943,136.359137 20.4197058,89.3998566 51.9881066,55.4283849 C83.5364037,21.4785471 127.005458,0.5 175.000036,0.5 Z'
   0: 'M175.000036,0.5 C222.664535,0.5 265.865535,21.1909654 297.358963,54.7296453 C328.90593,88.3253418 348.705559,134.812441 349.476653,186.303442 L349.490723,188.280824 L349.5,247.5 L0.5,247.5 L0.5,188.283766 C0.787224943,136.359137 20.4197058,89.3998566 51.9881066,55.4283849 C83.5364037,21.4785471 127.005458,0.5 175.000036,0.5 Z'
 }
 }
 const angle = ref(0)
 const angle = ref(0)
+const btns = [
+  { name: '撤销', fn: () => drawCanvas.pathBack(), type: 'tertiary' },
+  { name: '清空', fn: () => drawCanvas.pathClear(), type: 'tertiary' },
+  {
+    name: '保存',
+    fn: () => drawCanvas.pathSave((data) => {
+      console.log('数据', data)
+    }),
+    type: 'info'
+  }
+]
 
 
 function renderLabel(option: { icon: string | URL; label: string; }) {
 function renderLabel(option: { icon: string | URL; label: string; }) {
   return h('div', {
   return h('div', {
@@ -231,9 +240,8 @@ function renderLabel(option: { icon: string | URL; label: string; }) {
   ])
   ])
 }
 }
 
 
-function changeOption(v: null, option: { label: string; icon: string; value: number; w: number; h: number; }) {
-  console.log('切换', v, option)
-  drawCanvas._executionArr.type = v
+function changeOption(_: null, option: { label: string; icon: string; value: number; w: number; h: number; }) {
+  drawCanvas.changeBrush({ ...option, url: new URL(`./assets/img/${option.icon}`, import.meta.url).href, angle: angle.value })
 }
 }
 
 
 onMounted(() => {
 onMounted(() => {
@@ -247,6 +255,7 @@ onMounted(() => {
     }
     }
   })
   })
 })
 })
+
 onUnmounted(() => drawCanvas.destory())
 onUnmounted(() => drawCanvas.destory())
 </script>
 </script>
 <style lang="scss">
 <style lang="scss">
@@ -265,21 +274,12 @@ onUnmounted(() => drawCanvas.destory())
     height: 248px;
     height: 248px;
   }
   }
 
 
-  .n-button {
+  &>div {
     margin-bottom: 10px;
     margin-bottom: 10px;
   }
   }
 
 
-  label {
-    display: block;
-    font-size: 14px;
-    margin: 10px 0;
-    border: 1px solid rgba(196, 200, 206, 1);
-    padding: 6px 10px;
-  }
-
-  label>input {
-    border: none;
-    outline: none;
+  &>button:not(:last-child) {
+    margin-bottom: 10px;
   }
   }
 }
 }
 </style>
 </style>