temp-icon.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <template>
  2. <v-group :config="groupConfig" v-if="groupConfig && svg" ref="shape">
  3. <v-group :config="initDecMat" name="rep-position">
  4. <v-rect :config="rectConfig" name="repShape" />
  5. <v-path v-for="config in pathConfigs" :config="config" name="icon-path" />
  6. </v-group>
  7. </v-group>
  8. </template>
  9. <script lang="ts" setup>
  10. import { defaultStyle, IconData } from "./icon.ts";
  11. import { computed, ref, watch } from "vue";
  12. import { getSvgContent, parseSvgContent, SVGParseResult } from "@/utils/resource.ts";
  13. import { Group } from "konva/lib/Group";
  14. import { DC } from "@/deconstruction.js";
  15. import { Transform } from "konva/lib/Util";
  16. import { useViewerInvertTransform, useViewSize } from "@/core/hook/use-viewer.ts";
  17. import { getFixPosition } from "@/utils/bound.ts";
  18. import { useStore } from "@/core/store/index.ts";
  19. import { useHistory } from "@/core/hook/use-history.ts";
  20. const props = defineProps<{ data: IconData; addMode?: boolean }>();
  21. const svg = ref<SVGParseResult | null>(null);
  22. const shape = ref<DC<Group>>();
  23. const data = computed(() => ({ ...defaultStyle, ...props.data }));
  24. defineExpose({
  25. get shape() {
  26. return shape.value;
  27. },
  28. });
  29. const store = useStore();
  30. const history = useHistory();
  31. watch(
  32. () => data.value.url,
  33. async (url) => {
  34. svg.value = null;
  35. const svgContent = await getSvgContent(url);
  36. const content = parseSvgContent(svgContent);
  37. if (content.paths.length === 0) {
  38. svg.value = null;
  39. console.error(props.data.url, content, "路径数据不正确不是svg");
  40. history.preventTrack(() => store.delItem("icon", props.data.id));
  41. } else {
  42. svg.value = content;
  43. }
  44. },
  45. { immediate: true }
  46. );
  47. const scale = computed(() => {
  48. if (!svg.value) return null;
  49. let w = data.value.width;
  50. let h = data.value.height;
  51. w = w || svg.value.width || 0;
  52. h = h || svg.value.height || 0;
  53. const scale = {
  54. x: w / svg.value.width,
  55. y: h / svg.value.height,
  56. };
  57. return scale;
  58. });
  59. const pathConfigs = computed(() => {
  60. if (!svg.value) return [];
  61. return svg.value.paths.map((path) => ({
  62. ...path,
  63. ...data.value,
  64. id: undefined,
  65. lineWidth: 1000,
  66. zIndex: undefined,
  67. offset: { x: svg.value!.x, y: svg.value!.y },
  68. }));
  69. });
  70. const initDecMat = computed(() => {
  71. if (!svg.value || !scale.value) return;
  72. return new Transform()
  73. .scale(scale.value.x, scale.value.y)
  74. .multiply(new Transform().translate(-svg.value.width / 2, -svg.value.height / 2))
  75. .decompose();
  76. });
  77. const viewInvTransform = useViewerInvertTransform();
  78. const size = useViewSize();
  79. const groupConfig = computed(() => {
  80. let mat = new Transform(data.value.mat);
  81. if (data.value.fixScreen) {
  82. if (!size.value) return {};
  83. const pos = getFixPosition(data.value.fixScreen, data.value, size.value);
  84. pos.x += data.value.width / 2;
  85. pos.y += data.value.height / 2;
  86. mat = viewInvTransform.value.copy().translate(pos.x, pos.y).multiply(mat);
  87. }
  88. return {
  89. ...mat.decompose(),
  90. zIndex: undefined,
  91. listening: data.value.listening,
  92. id: data.value.id,
  93. opacity: props.addMode ? 0.3 : 1,
  94. };
  95. });
  96. const rectConfig = computed(() => {
  97. if (!svg.value) return null;
  98. return {
  99. fill: data.value.coverFill,
  100. id: "rep",
  101. stroke: data.value.coverStroke,
  102. opacity: data.value.coverOpcatiy,
  103. strokeWidth: data.value.coverStrokeWidth,
  104. width: svg.value.width,
  105. height: svg.value.height,
  106. };
  107. });
  108. </script>