index.ts 3.3 KB

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