123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- <template>
- <TempTable :data="tData" ref="tableRef" :id="data.id" />
- <PropertyUpdate
- :describes="describes"
- :data="data"
- :target="shape"
- @change="emit('updateShape', { ...data })"
- />
- <Operate
- :target="shape"
- :menus="operateMenus"
- @show="menuShowHandler"
- @hide="menuHideHandler"
- />
- <template v-for="(raw, rawNdx) in data.content">
- <template v-for="(_, colNdx) in raw">
- <TextDom
- v-if="tableRef?.texts[rawNdx] && tableRef?.texts[rawNdx][colNdx]?.getNode()"
- :shape="tableRef.texts[rawNdx][colNdx].getNode()!"
- @submit="(val) => submitInputHandler(val, rawNdx, colNdx)"
- @show="showInputHandler"
- @hide="quitInputHandler"
- />
- </template>
- </template>
- </template>
- <script lang="ts" setup>
- import TempTable from "./temp-table.vue";
- import TextDom from "../share/text-area.vue";
- import { TableData, getMouseStyle, defaultStyle, TableCollData } from "./index.ts";
- import { PropertyUpdate, Operate } from "../../propertys";
- import { useComponentStatus } from "@/core/hook/use-component.ts";
- import { Transform } from "konva/lib/Util";
- import { MathUtils } from "three";
- import {
- useCustomTransformer,
- useGetTransformerOperType,
- } from "@/core/hook/use-transformer.ts";
- import { copy, getResizeCorsur } from "@/utils/shared.ts";
- import { computed, ref, watch, watchEffect } from "vue";
- import { Group } from "konva/lib/Group";
- import { DC } from "@/deconstruction.js";
- import { Minus, Plus } from "@element-plus/icons-vue";
- import { Rect } from "konva/lib/shapes/Rect";
- import { setShapeTransform } from "@/utils/shape.ts";
- import { Text } from "konva/lib/shapes/Text";
- import {
- useMouseShapesStatus,
- useMouseShapeStatus,
- } from "@/core/hook/use-mouse-status.ts";
- import { useCursor, usePointerPos } from "@/core/hook/use-global-vars.ts";
- import { numEq, Pos } from "@/utils/math.ts";
- const props = defineProps<{ data: TableData }>();
- const emit = defineEmits<{
- (e: "updateShape", value: TableData): void;
- (e: "addShape", value: TableData): void;
- (e: "delShape"): void;
- }>();
- type TableRef = {
- shape: DC<Group>;
- texts: DC<Text>[][];
- getMouseIntersect: (
- pos?: Pos
- ) => {
- rawBorderNdx: number;
- colBorderNdx: number;
- rawNdx: number;
- colNdx: number;
- };
- };
- const tableRef = ref<TableRef>();
- const status = useMouseShapeStatus(computed(() => tableRef.value?.shape));
- let inter: Pick<
- ReturnType<TableRef["getMouseIntersect"]>,
- "rawBorderNdx" | "colBorderNdx"
- > | null = null;
- const pos = usePointerPos();
- const cursor = useCursor();
- const shapesStatus = useMouseShapesStatus();
- watch(
- () => status.value.hover && !status.value.press,
- (hover, _, onCleanup) => {
- if (!hover) return;
- onCleanup(
- watch(
- () => pos.value && tableRef.value?.getMouseIntersect(pos.value),
- (inter, _, onCleanup) => {
- const $shape = shape.value?.getNode();
- if ($shape && inter && (~inter.colBorderNdx || ~inter.rawBorderNdx)) {
- onCleanup(
- cursor.push(getResizeCorsur(!~inter.rawBorderNdx, $shape.rotation()))
- );
- }
- },
- { immediate: true, flush: "post" }
- )
- );
- },
- { flush: "post" }
- );
- watch(
- () => status.value.press,
- (press, _, onCleanup) => {
- if (!press) return;
- inter = tableRef.value?.getMouseIntersect() || null;
- const $shape = shape.value?.getNode();
- if ($shape && inter && (~inter.colBorderNdx || ~inter.rawBorderNdx)) {
- const pop = cursor.push(
- getResizeCorsur(!~inter.rawBorderNdx, shape.value?.getNode().rotation())
- );
- const isActive = shapesStatus.actives.includes($shape);
- if (isActive) {
- shapesStatus.actives = shapesStatus.actives.filter((s) => s !== $shape);
- }
- onCleanup(() => {
- inter = null;
- pop();
- // if (isActive) {
- // shapesStatus.actives = [...shapesStatus.actives, $shape];
- // }
- });
- }
- },
- { flush: "post" }
- );
- const getColMinSize = (col: TableCollData) => {
- const minw = (col.padding || 0) * 2 + (col.fontSize || 12) + 4;
- const minh = (col.padding || 0) * 2 + (col.fontSize || 12) + 4;
- return { w: minw, h: minh };
- };
- const getOperType = useGetTransformerOperType();
- const matToData = (data: TableData, mat: Transform, initData?: TableData) => {
- if (!initData) {
- initData = copy(data);
- }
- const dec = mat.decompose();
- if (!inter || (!~inter.colBorderNdx && !~inter.rawBorderNdx)) {
- const oldData = copy(data);
- data.height = dec.scaleY * initData.height;
- data.width = dec.scaleX * initData.width;
- let w = 0;
- let h = 0;
- data.content.forEach((raw, rndx) => {
- raw.forEach((col, cndx) => {
- const initCol = initData.content[rndx][cndx];
- const minSize = getColMinSize(initCol);
- col.width = Math.max(minSize.w, data.width * (initCol.width / initData.width));
- col.height = Math.max(
- minSize.h,
- data.height * (initCol.height / initData.height)
- );
- if (rndx === 0) {
- w += col.width;
- }
- if (cndx === 0) {
- h += col.height;
- }
- });
- });
- const eqW = numEq(w, data.width);
- const eqH = numEq(h, data.height);
- if (!eqW || !eqH) {
- const type = getOperType();
- if (type) {
- 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;
- }
- const initDec = new Transform(initData.mat).decompose();
- const move = new Transform().rotate(MathUtils.degToRad(-dec.rotation)).point({
- x: dec.x - initDec.x,
- y: dec.y - initDec.y,
- });
- if (~inter.rawBorderNdx) {
- const ndxRaw = inter.rawBorderNdx - 1;
- const ndx = ndxRaw === -1 ? 0 : ndxRaw;
- let offset = ndxRaw === -1 ? -move.y : move.y;
- const minSize = getColMinSize(data.content[ndx][0]);
- const h = Math.max(minSize.h, initData.content[ndx][0].height + offset);
- offset = h - initData.content[ndx][0].height;
- data.content[ndx].forEach(
- (col, colNdx) => (col.height = initData.content[ndx][colNdx].height + offset)
- );
- data.height = initData.height + offset;
- if (ndxRaw === -1) {
- const translate = new Transform()
- .rotate(MathUtils.degToRad(dec.rotation))
- .point({ x: 0, y: -offset });
- data.mat = new Transform()
- .translate(translate.x, translate.y)
- .multiply(new Transform(initData.mat)).m;
- }
- } else {
- const ndxRaw = inter.colBorderNdx - 1;
- const ndx = ndxRaw === -1 ? 0 : ndxRaw;
- let offset = ndxRaw === -1 ? -move.x : move.x;
- const minSize = getColMinSize(data.content[0][ndx]);
- const w = Math.max(minSize.w, initData.content[0][ndx].width + offset);
- offset = w - initData.content[0][ndx].width;
- data.content.forEach((row, rowNdx) => {
- row[ndx].width = initData.content[rowNdx][ndx].width + offset;
- });
- data.width = initData.width + offset;
- if (ndxRaw === -1) {
- const translate = new Transform()
- .rotate(MathUtils.degToRad(dec.rotation))
- .point({ x: -offset, y: 0 });
- data.mat = new Transform()
- .translate(translate.x, translate.y)
- .multiply(new Transform(initData.mat)).m;
- }
- }
- return data;
- };
- let repShape: Rect | null;
- const sync = (data: TableData) => {
- if (repShape) {
- repShape.width(data.width);
- repShape.height(data.height);
- const tf = new Transform(data.mat);
- setShapeTransform(repShape, tf);
- initData = copy(data);
- }
- };
- let initData: TableData;
- const { shape, tData, data, operateMenus, describes } = useComponentStatus<
- Group,
- TableData
- >({
- emit,
- props,
- getMouseStyle,
- defaultStyle,
- alignment: (data, mat) => {
- const tf = shape.value!.getNode().getTransform();
- mat.multiply(tf);
- matToData(data, mat);
- sync(data);
- },
- transformType: "custom",
- customTransform(callback, shape, data) {
- useCustomTransformer(shape, data, {
- openSnap: true,
- transformerConfig: { flipEnabled: false },
- getRepShape() {
- repShape = new Rect();
- sync(data.value);
- return {
- shape: repShape as any,
- };
- },
- beforeHandler(data, mat) {
- return matToData(copy(data), mat, initData);
- },
- handler(data, mat) {
- matToData(data, mat, initData);
- // sync(data);
- },
- callback(data) {
- callback();
- sync(data);
- },
- });
- },
- copyHandler(mat, data) {
- const tf = shape.value!.getNode().getTransform();
- mat.multiply(tf);
- return matToData({ ...data }, mat);
- },
- propertys: [
- "fill",
- "stroke",
- "fontColor",
- "strokeWidth",
- "fontSize",
- // "ref",
- "opacity",
- // "zIndex"
- "align",
- "fontStyle",
- ],
- });
- watchEffect((onCleanup) => {
- shape.value = tableRef.value?.shape;
- onCleanup(() => (shape.value = undefined));
- });
- watch(
- () => data.value.fontSize,
- () => {
- data.value.content.forEach((raw) => {
- raw.forEach((col) => {
- col.fontSize = data.value.fontSize;
- });
- });
- const $shape = shape.value!.getNode();
- data.value = matToData(data.value, $shape.getTransform());
- sync(data.value);
- $shape.fire("bound-change");
- },
- { flush: "sync" }
- );
- watchEffect(
- () => {
- data.value.content.forEach((raw) => {
- raw.forEach((col) => {
- col.fontColor = data.value.fontColor;
- col.fontStyle = data.value.fontStyle;
- col.align = data.value.align;
- });
- });
- },
- { flush: "sync" }
- );
- let addMenu: any;
- const menuShowHandler = () => {
- const config = tableRef.value!.getMouseIntersect();
- addMenu = [
- {
- icon: Plus,
- label: "插入行",
- handler: () => {
- const tempRaw = data.value.content[config.rawNdx];
- data.value.content.splice(
- config.rawNdx,
- 0,
- tempRaw.map((item) => ({ ...item, content: "" }))
- );
- data.value.height += tempRaw[0].height;
- sync(data.value);
- emit("updateShape", { ...data.value });
- },
- },
- {
- icon: Minus,
- label: "删除行",
- handler: () => {
- const tempRaw = data.value.content[config.rawNdx];
- data.value.content.splice(config.rawNdx, 1);
- data.value.height -= tempRaw[0].height;
- if (data.value.content.length === 0) {
- emit("delShape");
- } else {
- sync(data.value);
- emit("updateShape", data.value);
- }
- },
- },
- {
- icon: Plus,
- label: "插入列",
- handler: () => {
- const tempCol = data.value.content[0][config.colNdx];
- for (let i = 0; i < data.value.content.length; i++) {
- const raw = data.value.content[i];
- raw.splice(config.colNdx, 0, { ...tempCol, content: "" });
- }
- data.value.width += tempCol.width;
- sync(data.value);
- emit("updateShape", data.value);
- },
- },
- {
- icon: Minus,
- label: "删除列",
- handler: () => {
- const tempCol = data.value.content[0][config.colNdx];
- for (let i = 0; i < data.value.content.length; i++) {
- const raw = data.value.content[i];
- raw.splice(config.colNdx, 1);
- }
- data.value.width -= tempCol.width;
- if (data.value.content[0].length === 0) {
- emit("delShape");
- } else {
- sync(data.value);
- emit("updateShape", data.value);
- }
- },
- },
- ];
- operateMenus.unshift(...addMenu);
- };
- const menuHideHandler = () => {
- for (let i = 0; i < addMenu.length; i++) {
- const ndx = operateMenus.indexOf(addMenu[i]);
- if (ndx !== -1) {
- operateMenus.splice(ndx, 1);
- }
- }
- addMenu = [];
- };
- const showText = ref(false);
- const showInputHandler = () => {
- showText.value = true;
- const ndx = shapesStatus.actives.indexOf(shape.value!.getNode());
- if (~ndx) {
- shapesStatus.actives = shapesStatus.actives.filter(
- (v) => v !== shape.value!.getNode()
- );
- }
- };
- const quitInputHandler = () => {
- showText.value = false;
- };
- const submitInputHandler = (val: string, rawNdx: number, colNdx: number) => {
- quitInputHandler();
- data.value.content[rawNdx][colNdx].content = val;
- emit("updateShape", data.value);
- };
- </script>
|