Ver código fonte

feat: 对接uiConctrol

bill 2 anos atrás
pai
commit
2ccd913781

+ 2 - 1
src/api/board.ts

@@ -44,10 +44,11 @@ export interface TextShapeData extends ShapeData {
   fontSize: number
 }
 
+export type TableShapeContentItem = { width: number, height: number, value: string, rowIndex: number, colIndex: number }
 export interface TableShapeData extends CurrencyShapeData {
   type: typeof table
   fontSize: number
-  content: string[][]
+  content: TableShapeContentItem[]
 }
 
 export interface RectShapeData extends CurrencyShapeData {

+ 2 - 1
src/views/draw-file/board/index.d.ts

@@ -15,7 +15,7 @@ export type BoardShape<T = BoardShapeData, K = keyof T> = IntersectionFromUnion<
   K extends 'type'
     ? { data: { [key in K]: T[K]} }
     : { data: { [key in K]: T[K] } } & { [key in `set${Capitalize<K>}`]: (val: T[K]) => void }
->
+> & { delete: () => void }
 
 export type ExtractShape<T extends string, D = BoardShapeData> = BoardShape<
   D extends object
@@ -29,6 +29,7 @@ export type Board = {
     storeChange: undefined
     selectShape: BoardShape | null
   }>
+  unSelectShape(): void,
   setImage(url: string): void
   readyAddShape(type: ShapeType, onFinish?: () => void): () => void
   getCurrentStore(): BoardData

+ 43 - 85
src/views/draw-file/board/index.js

@@ -5,52 +5,6 @@ import {
 } from './shape'
 import Layer from './editCAD/Layer'
 
-const createShape = (refs, shapeData) => {
-  console.log('创建', shapeData)
-  const shape = {
-    data: shapeData,
-    setColor(color) {
-      console.log('set color', color)
-    },
-    destory() {
-      console.log('删除此数据')
-      const currentIndex = refs.shapes.indexOf(shape)
-      if (currentIndex !== -1) {
-        refs.shapes.splice(currentIndex, 1)
-      }
-    }
-  }
-
-  switch (shapeData.type) {
-    case text:
-      shape.setText = (text) => {
-        console.log('设置文字', text)
-      }
-      break;
-    case table:
-      shape.setFontSize = (text) => {
-        console.log('设置文字大小', text)
-      }
-      break;
-    default:
-      console.log('完成')
-  }
-  refs.shapes.push(shape)
-
-  return shape
-}
-
-const createBasemap = (refs, url) => {
-  const baseMap = {
-    data: url,
-    changeImage(url) {
-      baseMap.data = url
-      console.log('更换底图')
-    }
-  }
-  return baseMap
-}
-
 const toStore = (refs) => {
   return {
     bgImage: refs.baseMap?.data || null,
@@ -65,37 +19,44 @@ export const create = (store, canvas) => {
     shapes: [],
     baseMap: null
   }
-  const generateRefs = (store) => {
-    store.shapes.forEach(shapeData => createShape(refs, shapeData))
-    createBasemap(store.bgImage)
-  }
-
-  generateRefs(store)
-
-  canvas.addEventListener('click', () => {
-    // refs.bus.emit('selectShape', null)
-  })
-
-  const onSelect = (type, data = {}) => {
-    console.log(type, data)
-    refs.bus.emit('selectShape', {
-      data: { type: 'Table', ...data },
-      setColor(color) {
-        layer.uiControl.setAttributes(type, 'color', color)
-      },
-      setFontSize(fontSize) {
-        layer.uiControl.setAttributes(type, 'fontSize', fontSize)
-      },
-      setText(text) {
-        layer.uiControl.setAttributes(type, 'text', text)
-      }
-    })
-  }
 
   const layer = new Layer()
   layer.start(canvas, store)
-  layer.uiControl.uiSelectCallback = onSelect
-  layer.uiControl.setAttributes()
+  layer.uiControl.bus.on('showAttribute', ({type, value: data}) => {
+    const shape = { 
+      data: { type }, 
+      delete: () => {
+        layer.uiControl.clearUI()
+        layer.uiControl.setAttributes(type, 'delete')
+      }
+    }
+    const update = (newData) => {
+      shape.data.content = newData
+      layer.uiControl.setAttributes(type, 'update', newData)
+    }
+    switch (type) {
+      case table: {
+        data = data || [
+          { width: 160, height: 60, value: '', colIndex: 0, rowIndex: 0 },
+          { width: 160, height: 60, value: '', colIndex: 1, rowIndex: 0 },
+        ]
+        shape.data.content = data
+        shape.setContent = update
+        break;
+      }
+      case text: {
+        data = data || ''
+        shape.data.text = data
+        shape.setText = update
+        break;
+      }
+    }
+    refs.bus.emit('selectShape', shape)
+  })
+  setTimeout(() => {
+    layer.uiControl.bus.emit('showAttribute', { type: 'Table' })
+  }, 100)
+  layer.uiControl.bus.on('hideAttribute', () => refs.bus.emit('selectShape', null))
 
   const board = {
     bus: refs.bus,
@@ -107,20 +68,17 @@ export const create = (store, canvas) => {
       refs.baseMap = null
       generateRefs(newStore)
     },
+    unSelectShape() {
+      layer.uiControl.clearUI()
+    },
     readyAddShape(shapeType, onFine) {
       layer.uiControl.selectUI = shapeType
       layer.uiControl.updateEventNameForSelectUI()
-
-      // const definePosition = ev => {
-      //   const shape = createShape(refs, { type: shapeType, pos: { x: ev.offsetX, y: ev.offsetY } })
-      //   cleaup()
-      //   onFine()
-      //   refs.bus.emit('storeChange')
-      //   refs.bus.emit('selectShape', shape)
-      // }
-      // canvas.addEventListener('click',definePosition)
-      // const cleaup = () => canvas.removeEventListener('click',definePosition)
-      // return cleaup
+      const finePack = () => {
+        layer.uiControl.bus.off('hideUI', finePack)
+        onFine()
+      }
+      layer.uiControl.bus.on('hideUI', finePack)
     },
     setImage(url) {
       refs.baseMap.changeImage(url)

+ 93 - 78
src/views/draw-file/eshape.tsx

@@ -1,7 +1,6 @@
 import { useEffect, useMemo, useState } from "react"
-import { Button, Form, Input, Modal, Select } from 'antd'
+import { Button, Form, Modal, Input } from 'antd'
 import { CloseOutlined, PlusOutlined } from '@ant-design/icons'
-import InputColor from 'react-input-color';
 import style from './style.module.scss'
 import ReactEditeTable, { InputEditor } from 'react-edit-table'
 
@@ -9,27 +8,29 @@ import type { Board, BoardShape, ShapeType, ExtractShape } from "./board"
 import type { RefObject, ComponentType } from 'react'
 
 
-const ColorInput = ({ shape }: { shape: BoardShape }) => (
-  <Form.Item label="颜色" className={style['def-color-item']}>
-    <InputColor 
-      initialValue={shape.data.color || '#000'} 
-      onChange={(color) => shape.setColor(color.rgba)}
-    />
-  </Form.Item>
-)
+// import { Select } from 'antd'
+// import InputColor from 'react-input-color';
+// const ColorInput = ({ shape }: { shape: BoardShape }) => (
+//   <Form.Item label="颜色" className={style['def-color-item']}>
+//     <InputColor 
+//       initialValue={shape.data.color || '#000'} 
+//       onChange={(color) => shape.setColor(color.rgba)}
+//     />
+//   </Form.Item>
+// )
 
-const sizeOptions = [6,7,8,9,10,11,12,13,14,16,18,20,28,36,48,72]
-  .map(size => ({ label: `${size}px`, value: size }))
-const FontSizeInput = ({ shape }: { shape: ExtractShape<'fontSize'> }) => (
-  <Form.Item label="字号">
-    <Select
-      defaultValue={shape.data.fontSize}
-      style={{ width: 80 }}
-      onChange={(size) => shape.setFontSize(size)}
-      options={sizeOptions}
-    />
-  </Form.Item>
-)
+// const sizeOptions = [6,7,8,9,10,11,12,13,14,16,18,20,28,36,48,72]
+//   .map(size => ({ label: `${size}px`, value: size }))
+// const FontSizeInput = ({ shape }: { shape: ExtractShape<'fontSize'> }) => (
+//   <Form.Item label="字号">
+//     <Select
+//       defaultValue={shape.data.fontSize}
+//       style={{ width: 80 }}
+//       onChange={(size) => shape.setFontSize(size)}
+//       options={sizeOptions}
+//     />
+//   </Form.Item>
+// )
 
 
 const TextInput = ({ shape }: { shape: ExtractShape<'text'> }) => (
@@ -44,54 +45,79 @@ const TextInput = ({ shape }: { shape: ExtractShape<'text'> }) => (
 
 const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
   const [edit, setEdit] = useState(false)
-  const [content, setContent] = useState(shape.data.content || [['', '']])
-  // eslint-disable-next-line react-hooks/exhaustive-deps
-  const refer = content[0] || ['', '']
-  const transformRow = (columns: any[], row?: string[]) => {
-    const source: { [key in number]: string } = {}
-      for (let i = 0; i < columns.length; i++) {
-        source[i] = (row && row[i]) || ''
+  const [content, setContent] = useState(shape.data.content)
+  const refer = content.filter(item => item.rowIndex === 0)
+  const tableAttrs = useMemo(() => {
+    const dataSource: string[][] = []
+    content.forEach(item => {
+      let columns = dataSource[item.rowIndex]
+      if (!columns) {
+        columns = dataSource[item.rowIndex] = []
       }
-      return source
-  }
-  const tableAttrs = useMemo(() => ({
-    columns: refer.map((item, i) => ({
-      title: `列${i + 1}`,
-      dataIndex: i,
-      key: i,
-      editor: {
-        type: 'input',
-        component: InputEditor
+      columns[item.colIndex] = item.value
+    })
+
+    return {
+      columns: refer.map((item, i) => ({
+        title: `列${i + 1}`,
+        dataIndex: i,
+        key: i,
+        editor: {
+          type: 'input',
+          component: InputEditor
+        }
+      })),
+      dataSource
+    }
+  }, [content, refer])
+  const sortContent = () => 
+    content.sort((a, b) => {
+      const rowDiff = a.rowIndex - b.rowIndex
+      if (rowDiff) {
+        return rowDiff
+      } else {
+        return a.colIndex - b.colIndex
       }
-    })),
-    dataSource: content.map(item => transformRow(refer, item))
-  }), [content, refer])
-  
+    })
+
   const onChange = (data: any) => {
     const newContent = [...content]
-    newContent[data.rowIndex] = [...newContent[data.rowIndex]] 
-    newContent[data.rowIndex][data.key] = data.newValue
+    const item = newContent.find(item => item.rowIndex === data.rowIndex && item.colIndex === data.key)
+    item!.value = data.newValue
     setContent(newContent)
   }
   const onDelete = (data: any) => {
-    const newContent = [...content]
-    newContent.splice(data.rowIndex, 1)
-    setContent(newContent)
+    const newContent = sortContent()
+    const startIndex = newContent.findIndex(item => item.rowIndex === data.rowIndex)
+    const endIndex = startIndex + refer.length
+    setContent([
+      ...newContent.slice(0, startIndex),
+      ...newContent.slice(endIndex).map(item => ({...item, rowIndex: --item.rowIndex}))
+    ])
   }
   const onInsert = () => {
-    setContent([...content, refer.map(() => '')])
+    const maxRow = Math.max(...content.map(item => item.rowIndex))
+    setContent([
+      ...content, 
+      ...refer.map(item => ({ ...item, value: '', rowIndex: maxRow + 1 }))
+    ])
   }
+
   const onSubmit = () => {
     const rowEls = Array.from(document.querySelectorAll('#edit-table .body-container .row-container')) as HTMLDivElement[]
-    const bound = rowEls.map(row => {
+    const bound = rowEls.map((row, rowIndex) => {
       const cells = Array.from(row.querySelectorAll('.cell')) as HTMLDivElement[]
-      return {
+      return cells.slice(0, -1).map((cell, colIndex) => ({
+        width: cell.offsetWidth,
         height: row.offsetHeight - 1,
-        cellWidths: cells.slice(0, -1).map(cell => cell.offsetWidth)
-      }
-    })
-
-    console.log(bound, content)
+        value:  content.find(item => item.rowIndex === rowIndex && item.colIndex === colIndex)!.value,
+        colIndex,
+        rowIndex
+      }))
+    }).flat()
+    setContent(bound)
+    shape.setContent(bound)
+    setEdit(false)
   }
 
   useEffect(() => {
@@ -121,23 +147,9 @@ const ContentInput = ({ shape }: { shape: ExtractShape<'content'> }) => {
   )
 }
 
-const shapeCompontes: { [key in ShapeType]: ComponentType<{ shape: any }> } = {
-  Wall: ColorInput,
-  Tag: (props) => <><ColorInput {...props} /><FontSizeInput {...props} /><TextInput {...props} /> </>,
-  Table: (props) => <><ColorInput {...props} /><FontSizeInput {...props} /><ContentInput {...props} /> </>,
-  Rectangle: ColorInput,
-  Circle: ColorInput,
-  Arrow: ColorInput,
-  Icon: ColorInput,
-  Cigaret: ColorInput,
-  FirePoint: ColorInput,
-  LeftFootPrint: ColorInput,
-  RightFootPrint: ColorInput,
-  LeftShoePrint: ColorInput,
-  RightShoePrint: ColorInput,
-  FingerPrint: ColorInput,
-  DeadBody: ColorInput,
-  BloodStain: ColorInput
+const shapeCompontes: { [key in ShapeType]?: ComponentType<{ shape: any }> } = {
+  Tag: (props) => <><TextInput {...props} /> </>,
+  Table: (props) => <><ContentInput {...props} /> </>,
 }
 
 export type EShapeProps = {
@@ -145,6 +157,7 @@ export type EShapeProps = {
 }
 export const EShape = ({ board }: EShapeProps) => {
   const [shape, setShape] = useState<BoardShape | null>(null)
+  const Edit = shape && shapeCompontes[shape.data.type]
 
   useEffect(() => {
     if (board.current) {
@@ -154,15 +167,17 @@ export const EShape = ({ board }: EShapeProps) => {
     }
   }, [board])
 
-  const Edit = shape && shapeCompontes[shape.data.type]
-  return Edit && (
+  return shape ? (
     <div className={style['def-shape-edit']}>
-      <Edit shape={shape} />
+      { Edit && <Edit shape={shape} /> }
+      <Form.Item label="形状">
+        <Button type="primary" onClick={() => shape.delete()}>删除</Button>
+      </Form.Item>
       <div className={`ant-form-item ${style['def-close-shape-edit']}`} onClick={() => setShape(null)}>
-        <CloseOutlined className={`${style['icon']}`} />
+        <CloseOutlined className={`${style['icon']}`} onClick={() => board.current?.unSelectShape()}  />
       </div>
     </div>
-  )
+  ) : <></>
 }
 
 export default EShape