import { Transform } from "konva/lib/Util"; import { themeColor } from "@/constant"; import { BaseItem, generateSnapInfos, getBaseItem, getRectSnapPoints, } from "../util.ts"; import { getMouseColors } from "@/utils/colors.ts"; import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts"; import { numEq, Size } from "@/utils/math.ts"; import { copy } from "@/utils/shared.ts"; import { MathUtils } from "three"; export { default as Component } from "./table.vue"; export { default as TempComponent } from "./temp-table.vue"; export const shapeName = "表格"; export const defaultStyle = { stroke: '#000000', strokeWidth: 1, fontSize: 16, align: "center", fontStyle: "normal", fontColor: '#000000', }; export const defaultCollData = { fontFamily: "Calibri", fontSize: 16, align: "center", fontStyle: "normal", fontColor: themeColor }; export const addMode = "area"; export type TableCollData = Partial & Size & { content: string; padding: number; readonly?: boolean; notdel?: boolean; key?: string }; export type TableData = Partial & BaseItem & Size & { fill?: string | null notaddRow?: boolean; notaddCol?: boolean; mat: number[]; content: TableCollData[][]; tempSize?: { colWidth: number[] rowHeight: number[] } }; export const getMouseStyle = (data: TableData) => { const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke); return { default: { stroke: data.stroke || defaultStyle.stroke }, hover: { stroke: strokeStatus.hover }, press: { stroke: strokeStatus.press }, select: { select: strokeStatus.select }, }; }; export const getSnapPoints = (data: TableData) => { const tf = new Transform(data.mat); const points = getRectSnapPoints(data.width, data.height, 0, 0).map((v) => tf.point(v) ); return points; }; export const getSnapInfos = (data: TableData) => { return generateSnapInfos(getSnapPoints(data), true, false); }; export const interactiveToData: InteractiveTo<"table"> = ({ info, preset = {}, ...args }) => { if (info.cur) { const item = { fill: null, ...defaultStyle, ...getBaseItem(), ...preset, } as unknown as TableData; return interactiveFixData({ ...args, info, data: item }); } }; export const autoCollWidth = 100; export const autoCollHeight = 50; export const interactiveFixData: InteractiveFix<"table"> = ({ data, info, notdraw, }) => { if (info.cur) { const area = info.cur!; const origin = { x: Math.min(area[0].x, area[1].x), y: Math.min(area[0].y, area[1].y), }; data.width = Math.abs(area[0].x - area[1].x); data.height = Math.abs(area[0].y - area[1].y); if (!notdraw || !(data.content?.length && data.content[0].length)) { const colNum = Math.floor(data.width / autoCollWidth) || 1; const rawNum = Math.floor(data.height / autoCollHeight) || 1; const temp = data.content?.[0]?.[0] || { content: "", }; data.content = Array.from({ length: rawNum }, () => Array.from({ length: colNum }, () => ({ ...temp, width: data.width / colNum, height: data.height / rawNum, padding: 8, })) ); } else { const colHeight = data.height / data.content.length; const colWidth = data.width / data.content[0].length; data.content.forEach((row) => { row.forEach((col) => { col.width = col.width || colWidth; col.height = col.height || colHeight; col.padding = col.padding || 8; }); }); } data.mat = new Transform().translate(origin.x, origin.y).m; } return data; }; export const getColMinSize = (col: TableCollData) => { const minw = (col.padding || 0) * 2 + (col.fontSize || 12) + 4; const minh = (col.padding || 0) * 2 + (col.fontSize || 12) ; return { w: minw, h: minh }; }; export const matResponse = ( { data, mat, operType, increment }: MatResponseProps<"table">, initData?: TableData ) => { if (!initData) { initData = copy(data); } if (increment) { mat = mat.copy().multiply(new Transform(data.mat)) } const dec = mat.decompose(); const oldData = copy(data); data.height = dec.scaleY * initData.height; data.width = dec.scaleX * initData.width; let minwNdxs: number[] = [] let minhNdxs: number[] = [] let w = 0; let h = 0; const updateColSize = () => { // 调整最小值 let curMinwNdxs = [...minwNdxs] let curMinhNdxs = [...minhNdxs] const getNewWidth = (ndx: number) => { // data.width * (initCol.width / initData.width) const initCol = initData.content[0][ndx] let initWidth = initData.width const index = minwNdxs.indexOf(ndx) const spMinwNdxs = ~index ? minwNdxs.slice(0, index) : minwNdxs spMinwNdxs.forEach(ndx => initWidth -= initData.content[0][ndx].width) const width = (data.width - w) * (initCol.width / initWidth); return width } const getNewHeight = (ndx: number) => { const initCol = initData.content[ndx][0] let initHeight = initData.height const index = minhNdxs.indexOf(ndx) const spMinhNdxs = ~index ? minhNdxs.slice(0, index) : minhNdxs spMinhNdxs.forEach(ndx => initHeight -= initData.content[ndx][0].height) const height = (data.height - h) * (initCol.height / initHeight) return height } data.content.forEach((row, rndx) => { row.forEach((col, cndx) => { const initCol = initData.content[rndx][cndx]; const minSize = getColMinSize(initCol); if (!curMinwNdxs.includes(cndx)) { const neww = getNewWidth(cndx) if (neww < minSize.w) { col.width = minSize.w if (rndx === 0) { minwNdxs.push(cndx) w += col.width } } } if (!curMinhNdxs.includes(rndx)) { const newh = getNewHeight(rndx) if (newh < minSize.h) { col.height = minSize.h if (cndx === 0) { minhNdxs.push(rndx) h += col.height } } } }); }); if (curMinwNdxs.length !== minwNdxs.length || curMinhNdxs.length !== minhNdxs.length) { return updateColSize() } const needUpdateH = curMinhNdxs.length !== data.content.length const needUpdateW = curMinwNdxs.length !== data.content[0].length if (!needUpdateH && !needUpdateW) return; data.content.forEach((row, rndx) => { row.forEach((col, cndx) => { if (needUpdateW && !minwNdxs.includes(cndx)) { col.width = getNewWidth(cndx) } if (needUpdateH && !minhNdxs.includes(rndx)) { col.height = getNewHeight(rndx) } }) }) data.content.forEach((row, rndx) => { row.forEach((col, cndx) => { if (needUpdateW && !minwNdxs.includes(cndx) && rndx === 0) { w += col.width } if (needUpdateH &&!minhNdxs.includes(rndx) && cndx === 0) { h += col.height } }) }) } updateColSize() const eqW = numEq(w, data.width); const eqH = numEq(h, data.height); if (!eqW || !eqH) { if (operType) { Object.assign(data, oldData); } else { data.width = w; data.height = h; const initDec = new Transform(initData.mat).decompose(); data.mat = new Transform() .translate(eqW ? dec.x : initDec.x, eqH ? dec.y : initDec.y) .rotate(MathUtils.degToRad(dec.rotation)).m; } } else { data.mat = new Transform() .translate(dec.x, dec.y) .rotate(MathUtils.degToRad(dec.rotation)).m; } return data; }; export const getPredefine = (key: keyof TableData) => { if (key === 'fill') { return { canun: true } } }