index.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { Transform } from "konva/lib/Util";
  2. import { Text } from "konva/lib/shapes/Text";
  3. import { themeMouseColors } from "@/constant/help-style.ts";
  4. import {
  5. BaseItem,
  6. generateSnapInfos,
  7. getBaseItem,
  8. getRectSnapPoints,
  9. } from "../util.ts";
  10. import { getMouseColors } from "@/utils/colors.ts";
  11. import { shallowReactive } from "vue";
  12. import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
  13. import { zeroEq } from "@/utils/math.ts";
  14. import { MathUtils } from "three";
  15. export { default as Component } from "./text.vue";
  16. export { default as TempComponent } from "./temp-text.vue";
  17. export const shapeName = "文字";
  18. export const defaultStyle = {
  19. // stroke: themeMouseColors.theme,
  20. fill: themeMouseColors.theme,
  21. // strokeWidth: 0,
  22. fontFamily: "Calibri",
  23. fontSize: 16,
  24. align: "center",
  25. fontStyle: "normal",
  26. };
  27. export const addMode = "dot";
  28. export type TextData = Partial<typeof defaultStyle> &
  29. BaseItem & {
  30. mat: number[];
  31. content: string;
  32. width?: number;
  33. heihgt?: number;
  34. };
  35. export const getMouseStyle = (data: TextData) => {
  36. const fillStatus = getMouseColors(data.fill || defaultStyle.fill);
  37. // const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke);
  38. // const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth;
  39. return {
  40. default: { fill: fillStatus.pub },
  41. hover: { fill: fillStatus.hover },
  42. press: { fill: fillStatus.press },
  43. select: { fill: fillStatus.select },
  44. };
  45. };
  46. export const textNodeMap: Record<BaseItem["id"], Text> = shallowReactive({});
  47. export const getSnapPoints = (data: TextData) => {
  48. if (!textNodeMap[data.id]) return [];
  49. const node = textNodeMap[data.id];
  50. const tf = new Transform(data.mat);
  51. return getRectSnapPoints(data.width || node.width(), node.height(), 0, 0).map(
  52. (v) => tf.point(v)
  53. );
  54. };
  55. export const getSnapInfos = (data: TextData) => {
  56. return generateSnapInfos(getSnapPoints(data), true, false);
  57. };
  58. export const interactiveToData: InteractiveTo<"text"> = ({
  59. info,
  60. preset = {},
  61. ...args
  62. }) => {
  63. if (info.cur) {
  64. const item = {
  65. ...defaultStyle,
  66. ...getBaseItem(),
  67. ...preset,
  68. content: preset.content || "文字",
  69. } as unknown as TextData;
  70. return interactiveFixData({ ...args, info, data: item });
  71. }
  72. };
  73. export const interactiveFixData: InteractiveFix<"text"> = ({ data, info }) => {
  74. const mat = new Transform().translate(info.cur!.x, info.cur!.y);
  75. data.mat = mat.m;
  76. return data;
  77. };
  78. export const getMinWidth = (data: TextData) => (data.fontSize || 12) * 2
  79. export const getWidth = (data: TextData, scaleX: number) => {
  80. const minWidth = getMinWidth(data)
  81. let width: number;
  82. if ("width" in data) {
  83. width = Math.max(data.width! * scaleX, minWidth);
  84. } else {
  85. width = Math.max(minWidth * scaleX, minWidth);
  86. }
  87. return width;
  88. };
  89. export const matResponse = ({ data, mat, increment }: MatResponseProps<"text">) => {
  90. if (increment) {
  91. mat = mat.copy().multiply(new Transform(data.mat))
  92. }
  93. const { scaleX, x, y, rotation } = mat.decompose();
  94. if (!zeroEq(scaleX - 1)) {
  95. data.width = getWidth(data, scaleX)
  96. data.mat = new Transform()
  97. .translate(x, y)
  98. .rotate(MathUtils.degToRad(rotation))
  99. .scale(1, 1).m
  100. } else {
  101. data.mat = mat.m
  102. }
  103. return data
  104. };