123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- <template>
- <TempTable
- :data="tData"
- ref="tableRef"
- :id="data.id"
- @update-content="submitInputHandler"
- editer
- />
- <PropertyUpdate
- :describes="describes"
- :data="data"
- :target="shape"
- @change="emit('updateShape', { ...data })"
- @delete="emit('delShape')"
- />
- <Operate
- :target="shape"
- :menus="operateMenus"
- @show="menuShowHandler"
- @hide="menuHideHandler"
- />
- </template>
- <script lang="ts" setup>
- import TempTable from "./temp-table.vue";
- import {
- TableData,
- getMouseStyle,
- defaultStyle,
- matResponse,
- getColMinSize,
- } from "./index.ts";
- import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
- import { useComponentStatus } from "@/core/hook/use-component.ts";
- import { Transform } from "konva/lib/Util";
- import { MathUtils } from "three";
- import {
- useCustomTransformer,
- useGetTransformerOperType,
- useTransformer,
- } from "@/core/hook/use-transformer.ts";
- import { copy, getResizeCorsur } from "@/utils/shared.ts";
- import { computed, nextTick, ref, watch, watchEffect } from "vue";
- import { Group } from "konva/lib/Group";
- import { DC } from "@/deconstruction.js";
- 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 { 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
- ) => {
- rowBorderNdx: number;
- colBorderNdx: number;
- rowNdx: number;
- colNdx: number;
- };
- };
- const tableRef = ref<TableRef>();
- const status = useMouseShapeStatus(computed(() => tableRef.value?.shape));
- let inter: Pick<
- ReturnType<TableRef["getMouseIntersect"]>,
- "rowBorderNdx" | "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.rowBorderNdx)) {
- onCleanup(
- cursor.push(getResizeCorsur(!~inter.rowBorderNdx, $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.rowBorderNdx)) {
- const pop = cursor.push(
- getResizeCorsur(!~inter.rowBorderNdx, shape.value?.getNode().rotation())
- );
- const isActive = shapesStatus.actives.includes($shape);
- if (isActive) {
- shapesStatus.actives = shapesStatus.actives.filter((s) => s !== $shape);
- }
- onCleanup(() => {
- inter = null;
- pop();
- });
- }
- },
- { flush: "post" }
- );
- 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.rowBorderNdx)) {
- return matResponse({ data, mat, operType: getOperType()! }, initData);
- }
- 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.rowBorderNdx) {
- const ndxrow = inter.rowBorderNdx - 1;
- const ndx = ndxrow === -1 ? 0 : ndxrow;
- let offset = ndxrow === -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 (ndxrow === -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 ndxrow = inter.colBorderNdx - 1;
- const ndx = ndxrow === -1 ? 0 : ndxrow;
- let offset = ndxrow === -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 (ndxrow === -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 transformer = useTransformer();
- 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);
- transformer.forceUpdate();
- }
- };
- let initData: TableData;
- const { shape, tData, data, operateMenus, describes } = useComponentStatus<
- Group,
- TableData
- >({
- emit,
- props,
- getMouseStyle,
- defaultStyle,
- // alignment: (data, mat) => {
- // matResponse({ data, mat, increment: true });
- // sync(data);
- // return 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,
- update(data) {
- sync(data);
- },
- };
- },
- beforeHandler(data, mat) {
- return matToData(copy(data), mat, initData);
- },
- handler(data, mat) {
- matToData(data, mat, initData);
- },
- callback(data) {
- callback();
- nextTick(() => shape.value?.getNode().fire("bound-change"));
- },
- });
- },
- copyHandler(mat, data) {
- return matResponse({ data, mat, increment: true });
- },
- 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((row) => {
- row.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((row) => {
- row.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 = [];
- if (!data.value.notaddRow) {
- addMenu.push({
- label: "插入行",
- handler: () => {
- const temprow = data.value.content[config.rowNdx];
- data.value.content.splice(
- config.rowNdx,
- 0,
- temprow.map((item) => ({ ...item, content: "" }))
- );
- data.value.height += temprow[0].height;
- sync(data.value);
- nextTick(() => shape.value?.getNode().fire("bound-change"));
- emit("updateShape", { ...data.value });
- },
- });
- }
- const canDelRaw = data.value.content[config.rowNdx].every((item) => !item.notdel);
- if (canDelRaw) {
- addMenu.push({
- label: "删除行",
- handler: () => {
- const temprow = data.value.content[config.rowNdx];
- data.value.content.splice(config.rowNdx, 1);
- data.value.height -= temprow[0].height;
- nextTick(() => shape.value?.getNode().fire("bound-change"));
- if (data.value.content.length === 0) {
- emit("delShape");
- } else {
- sync(data.value);
- emit("updateShape", data.value);
- }
- },
- });
- }
- if (!data.value.notaddCol) {
- addMenu.push({
- label: "插入列",
- handler: () => {
- const tempCol = data.value.content[0][config.colNdx];
- for (let i = 0; i < data.value.content.length; i++) {
- const row = data.value.content[i];
- row.splice(config.colNdx, 0, { ...tempCol, content: "" });
- }
- data.value.width += tempCol.width;
- nextTick(() => shape.value?.getNode().fire("bound-change"));
- sync(data.value);
- emit("updateShape", data.value);
- },
- });
- }
- const canDelCol = data.value.content.every((items) => !items[config.colNdx].notdel);
- if (canDelCol) {
- addMenu.push({
- label: "删除列",
- handler: () => {
- const tempCol = data.value.content[0][config.colNdx];
- for (let i = 0; i < data.value.content.length; i++) {
- const row = data.value.content[i];
- row.splice(config.colNdx, 1);
- }
- data.value.width -= tempCol.width;
- nextTick(() => shape.value?.getNode().fire("bound-change"));
- 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 submitInputHandler = (playData: {
- val: string;
- rowNdx: number;
- colNdx: number;
- }) => {
- data.value.content[playData.rowNdx][playData.colNdx].content = playData.val;
- emit("updateShape", data.value);
- };
- </script>
|