import { Transform } from "konva/lib/Util"; import { Text } from "konva/lib/shapes/Text"; import { BaseItem, generateSnapInfos, getBaseItem, getRectSnapPoints, } from "../util.ts"; import { getMouseColors } from "@/utils/colors.ts"; import { shallowReactive } from "vue"; import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts"; import { zeroEq } from "@/utils/math.ts"; import { MathUtils } from "three"; export { default as Component } from "./text.vue"; export { default as TempComponent } from "./temp-text.vue"; export const shapeName = "文字"; export const defaultStyle = { // stroke: themeMouseColors.theme, fill: '#000000', // strokeWidth: 0, fontFamily: "Calibri", fontSize: 16, align: "center", fontStyle: "normal", }; export const addMode = "dot"; export type TextData = Partial & BaseItem & { stroke?: string mat: number[]; content: string; width?: number; heihgt?: number; }; export const getMouseStyle = (data: TextData) => { const fillStatus = getMouseColors(data.fill || defaultStyle.fill); // const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke); // const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth; return { default: { fill: data.fill || defaultStyle.fill }, hover: { fill: fillStatus.hover }, press: { fill: fillStatus.press }, focus: { fill: fillStatus.hover }, select: { fill: fillStatus.select }, }; }; export const textNodeMap: Record = shallowReactive({}); export const getSnapPoints = (data: TextData) => { if (!textNodeMap[data.id]) return []; const node = textNodeMap[data.id]; const tf = new Transform(data.mat); return getRectSnapPoints(data.width || node.width(), node.height(), 0, 0).map( (v) => tf.point(v) ); }; export const getSnapInfos = (data: TextData) => { return generateSnapInfos(getSnapPoints(data), true, false); }; export const interactiveToData: InteractiveTo<"text"> = ({ info, preset = {}, ...args }) => { if (info.cur) { const item = { ...defaultStyle, ...getBaseItem(), ...preset, content: preset.content || "文字", } as unknown as TextData; return interactiveFixData({ ...args, info, data: item }); } }; export const interactiveFixData: InteractiveFix<"text"> = ({ data, info }) => { const mat = new Transform().translate(info.cur!.x, info.cur!.y); data.mat = mat.m; return data; }; export const getMinWidth = (data: TextData) => (data.fontSize || 12) * 2 export const getWidth = (data: TextData, scaleX: number) => { const minWidth = getMinWidth(data) let width: number; if ("width" in data) { width = Math.max(data.width! * scaleX, minWidth); } else { width = Math.max(minWidth * scaleX, minWidth); } return width; }; export const matResponse = ({ data, mat, increment }: MatResponseProps<"text">) => { if (increment) { mat = mat.copy().multiply(new Transform(data.mat)) } const { scaleX, x, y, rotation } = mat.decompose(); if (!zeroEq(scaleX - 1)) { data.width = getWidth(data, scaleX) data.mat = new Transform() .translate(x, y) .rotate(MathUtils.degToRad(rotation)) .scale(1, 1).m } else { data.mat = mat.m } return data }; export const getPredefine = (key: keyof TextData) => { if (key === 'stroke') { return { canun: true } } }