index.ts 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import { Transform } from "konva/lib/Util";
  2. import { themeColor } from "@/constant";
  3. import {
  4. BaseItem,
  5. generateSnapInfos,
  6. getBaseItem,
  7. getRectSnapPoints,
  8. } from "../util.ts";
  9. import { getMouseColors } from "@/utils/colors.ts";
  10. import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
  11. import { numEq, Size } from "@/utils/math.ts";
  12. import { copy } from "@/utils/shared.ts";
  13. import { MathUtils } from "three";
  14. export { default as Component } from "./table.vue";
  15. export { default as TempComponent } from "./temp-table.vue";
  16. export const shapeName = "表格";
  17. export const defaultStyle = {
  18. stroke: '#000000',
  19. strokeWidth: 1,
  20. fontSize: 16,
  21. align: "center",
  22. fontStyle: "normal",
  23. fontColor: '#000000',
  24. };
  25. export const defaultCollData = {
  26. fontFamily: "Calibri",
  27. fontSize: 16,
  28. align: "center",
  29. fontStyle: "normal",
  30. fontColor: themeColor
  31. };
  32. export const addMode = "area";
  33. export type TableCollData = Partial<typeof defaultCollData> &
  34. Size & {
  35. content: string;
  36. padding: number;
  37. readonly?: boolean;
  38. notdel?: boolean;
  39. key?: string
  40. };
  41. export type TableData = Partial<typeof defaultStyle> &
  42. BaseItem &
  43. Size & {
  44. fill?: string | null
  45. notaddRow?: boolean;
  46. notaddCol?: boolean;
  47. mat: number[];
  48. content: TableCollData[][];
  49. tempSize?: {
  50. colWidth: number[]
  51. rowHeight: number[]
  52. }
  53. };
  54. export const getMouseStyle = (data: TableData) => {
  55. const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke);
  56. return {
  57. default: { stroke: data.stroke || defaultStyle.stroke },
  58. hover: { stroke: strokeStatus.hover },
  59. press: { stroke: strokeStatus.press },
  60. select: { select: strokeStatus.select },
  61. };
  62. };
  63. export const getSnapPoints = (data: TableData) => {
  64. const tf = new Transform(data.mat);
  65. const points = getRectSnapPoints(data.width, data.height, 0, 0).map((v) =>
  66. tf.point(v)
  67. );
  68. return points;
  69. };
  70. export const getSnapInfos = (data: TableData) => {
  71. return generateSnapInfos(getSnapPoints(data), true, false);
  72. };
  73. export const interactiveToData: InteractiveTo<"table"> = ({
  74. info,
  75. preset = {},
  76. ...args
  77. }) => {
  78. if (info.cur) {
  79. const item = {
  80. fill: null,
  81. ...defaultStyle,
  82. ...getBaseItem(),
  83. ...preset,
  84. } as unknown as TableData;
  85. return interactiveFixData({ ...args, info, data: item });
  86. }
  87. };
  88. export const autoCollWidth = 100;
  89. export const autoCollHeight = 50;
  90. export const interactiveFixData: InteractiveFix<"table"> = ({
  91. data,
  92. info,
  93. notdraw,
  94. }) => {
  95. if (info.cur) {
  96. const area = info.cur!;
  97. const origin = {
  98. x: Math.min(area[0].x, area[1].x),
  99. y: Math.min(area[0].y, area[1].y),
  100. };
  101. data.width = Math.abs(area[0].x - area[1].x);
  102. data.height = Math.abs(area[0].y - area[1].y);
  103. if (!notdraw || !(data.content?.length && data.content[0].length)) {
  104. const colNum = Math.floor(data.width / autoCollWidth) || 1;
  105. const rawNum = Math.floor(data.height / autoCollHeight) || 1;
  106. const temp = data.content?.[0]?.[0] || {
  107. content: "",
  108. };
  109. data.content = Array.from({ length: rawNum }, () =>
  110. Array.from({ length: colNum }, () => ({
  111. ...temp,
  112. width: data.width / colNum,
  113. height: data.height / rawNum,
  114. padding: 8,
  115. }))
  116. );
  117. } else {
  118. const colHeight = data.height / data.content.length;
  119. const colWidth = data.width / data.content[0].length;
  120. data.content.forEach((row) => {
  121. row.forEach((col) => {
  122. col.width = col.width || colWidth;
  123. col.height = col.height || colHeight;
  124. col.padding = col.padding || 8;
  125. });
  126. });
  127. }
  128. data.mat = new Transform().translate(origin.x, origin.y).m;
  129. }
  130. return data;
  131. };
  132. export const getColMinSize = (col: TableCollData) => {
  133. const minw = (col.padding || 0) * 2 + (col.fontSize || 12) + 4;
  134. const minh = (col.padding || 0) * 2 + (col.fontSize || 12) ;
  135. return { w: minw, h: minh };
  136. };
  137. export const matResponse = (
  138. { data, mat, operType, increment }: MatResponseProps<"table">,
  139. initData?: TableData
  140. ) => {
  141. if (!initData) {
  142. initData = copy(data);
  143. }
  144. if (increment) {
  145. mat = mat.copy().multiply(new Transform(data.mat))
  146. }
  147. const dec = mat.decompose();
  148. const oldData = copy(data);
  149. data.height = dec.scaleY * initData.height;
  150. data.width = dec.scaleX * initData.width;
  151. let minwNdxs: number[] = []
  152. let minhNdxs: number[] = []
  153. let w = 0;
  154. let h = 0;
  155. const updateColSize = () => {
  156. // 调整最小值
  157. let curMinwNdxs = [...minwNdxs]
  158. let curMinhNdxs = [...minhNdxs]
  159. const getNewWidth = (ndx: number) => {
  160. // data.width * (initCol.width / initData.width)
  161. const initCol = initData.content[0][ndx]
  162. let initWidth = initData.width
  163. const index = minwNdxs.indexOf(ndx)
  164. const spMinwNdxs = ~index ? minwNdxs.slice(0, index) : minwNdxs
  165. spMinwNdxs.forEach(ndx => initWidth -= initData.content[0][ndx].width)
  166. const width = (data.width - w) * (initCol.width / initWidth);
  167. return width
  168. }
  169. const getNewHeight = (ndx: number) => {
  170. const initCol = initData.content[ndx][0]
  171. let initHeight = initData.height
  172. const index = minhNdxs.indexOf(ndx)
  173. const spMinhNdxs = ~index ? minhNdxs.slice(0, index) : minhNdxs
  174. spMinhNdxs.forEach(ndx => initHeight -= initData.content[ndx][0].height)
  175. const height = (data.height - h) * (initCol.height / initHeight)
  176. return height
  177. }
  178. data.content.forEach((row, rndx) => {
  179. row.forEach((col, cndx) => {
  180. const initCol = initData.content[rndx][cndx];
  181. const minSize = getColMinSize(initCol);
  182. if (!curMinwNdxs.includes(cndx)) {
  183. const neww = getNewWidth(cndx)
  184. if (neww < minSize.w) {
  185. col.width = minSize.w
  186. if (rndx === 0) {
  187. minwNdxs.push(cndx)
  188. w += col.width
  189. }
  190. }
  191. }
  192. if (!curMinhNdxs.includes(rndx)) {
  193. const newh = getNewHeight(rndx)
  194. if (newh < minSize.h) {
  195. col.height = minSize.h
  196. if (cndx === 0) {
  197. minhNdxs.push(rndx)
  198. h += col.height
  199. }
  200. }
  201. }
  202. });
  203. });
  204. if (curMinwNdxs.length !== minwNdxs.length || curMinhNdxs.length !== minhNdxs.length) {
  205. return updateColSize()
  206. }
  207. const needUpdateH = curMinhNdxs.length !== data.content.length
  208. const needUpdateW = curMinwNdxs.length !== data.content[0].length
  209. if (!needUpdateH && !needUpdateW) return;
  210. data.content.forEach((row, rndx) => {
  211. row.forEach((col, cndx) => {
  212. if (needUpdateW && !minwNdxs.includes(cndx)) {
  213. col.width = getNewWidth(cndx)
  214. }
  215. if (needUpdateH && !minhNdxs.includes(rndx)) {
  216. col.height = getNewHeight(rndx)
  217. }
  218. })
  219. })
  220. data.content.forEach((row, rndx) => {
  221. row.forEach((col, cndx) => {
  222. if (needUpdateW && !minwNdxs.includes(cndx) && rndx === 0) {
  223. w += col.width
  224. }
  225. if (needUpdateH &&!minhNdxs.includes(rndx) && cndx === 0) {
  226. h += col.height
  227. }
  228. })
  229. })
  230. }
  231. updateColSize()
  232. const eqW = numEq(w, data.width);
  233. const eqH = numEq(h, data.height);
  234. if (!eqW || !eqH) {
  235. if (operType) {
  236. Object.assign(data, oldData);
  237. } else {
  238. data.width = w;
  239. data.height = h;
  240. const initDec = new Transform(initData.mat).decompose();
  241. data.mat = new Transform()
  242. .translate(eqW ? dec.x : initDec.x, eqH ? dec.y : initDec.y)
  243. .rotate(MathUtils.degToRad(dec.rotation)).m;
  244. }
  245. } else {
  246. data.mat = new Transform()
  247. .translate(dec.x, dec.y)
  248. .rotate(MathUtils.degToRad(dec.rotation)).m;
  249. }
  250. return data;
  251. };
  252. export const getPredefine = (key: keyof TableData) => {
  253. if (key === 'fill') {
  254. return { canun: true }
  255. }
  256. }