use-viewer.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { Viewer } from "../viewer.ts";
  2. import { computed, nextTick, ref, watch, watchEffect } from "vue";
  3. import { dragListener, scaleListener } from "../../utils/event.ts";
  4. import { globalWatch, installGlobalVar, useStage } from "./use-global-vars.ts";
  5. import { useCan } from "./use-status";
  6. import { mergeFuns } from "../../utils/shared.ts";
  7. import { Transform } from "konva/lib/Util";
  8. import { lineLen } from "@/utils/math.ts";
  9. import { useResize } from "./use-event.ts";
  10. import { FixScreen, getFixPosition } from "@/utils/bound.ts";
  11. import { useFormalLayer } from "./use-layer.ts";
  12. import { Group } from "konva/lib/Group";
  13. import { DataGroupId } from "@/constant/index.ts";
  14. import { IRect } from "konva/lib/types";
  15. import { MathUtils } from "three";
  16. export const useViewer = installGlobalVar(() => {
  17. const stage = useStage();
  18. const viewer = new Viewer();
  19. const can = useCan();
  20. const size = useResize();
  21. const transform = ref(new Transform());
  22. const disabled = ref(false);
  23. const sizeMat = ref<Transform | null>(null);
  24. const init = (dom: HTMLDivElement) => {
  25. let downEv: PointerEvent;
  26. const onDestroy = mergeFuns(
  27. dragListener(dom, {
  28. down(_, ev) {
  29. downEv = ev;
  30. },
  31. move: ({ end, prev, ev }) => {
  32. if (downEv.button === 2 || disabled.value) return;
  33. if (can.viewMode) {
  34. viewer.movePixel({ x: end.x - prev.x, y: end.y - prev.y });
  35. }
  36. },
  37. notPrevent: true,
  38. }),
  39. scaleListener(dom, (info) => {
  40. if (can.viewMode || disabled.value) {
  41. viewer.scalePixel(info.center, info.scale);
  42. }
  43. }),
  44. watchEffect(() => {
  45. size.value && viewer.setSize(size.value);
  46. })
  47. );
  48. viewer.bus.on("transformChange", (newTransform) => {
  49. transform.value = newTransform;
  50. });
  51. viewer.bus.on("viewSizeChange", () => {
  52. sizeMat.value = viewer.sizeMat;
  53. });
  54. transform.value = viewer.transform;
  55. sizeMat.value = viewer.sizeMat;
  56. return onDestroy;
  57. };
  58. return {
  59. var: {
  60. transform: transform,
  61. viewer,
  62. sizeMat,
  63. disabled,
  64. },
  65. onDestroy: globalWatch(
  66. () => can.viewMouseReact,
  67. (can, _, onCleanup) => {
  68. if (can) {
  69. const dom = stage.value!.getNode().container();
  70. onCleanup(init(dom));
  71. }
  72. },
  73. { immediate: true }
  74. ),
  75. };
  76. }, Symbol("viewer"));
  77. export const useViewerTransform = installGlobalVar(() => {
  78. const viewer = useViewer();
  79. return viewer.transform;
  80. }, Symbol("viewTransform"));
  81. export const useViewerTransformConfig = () => {
  82. const transform = useViewerTransform();
  83. return computed(() => transform.value.decompose());
  84. };
  85. export const useViewerInvertTransform = () => {
  86. const transform = useViewerTransform();
  87. return computed(() => transform.value.copy().invert());
  88. };
  89. export const useViewerInvertTransformConfig = () => {
  90. const transform = useViewerInvertTransform();
  91. return computed(() => transform.value.decompose());
  92. };
  93. export const useUnitTransform = installGlobalVar(() => {
  94. const transform = useViewerTransform();
  95. const invTransform = useViewerInvertTransform();
  96. return {
  97. getPixel(real: number) {
  98. return lineLen(
  99. invTransform.value.point({ x: real, y: 0 }),
  100. invTransform.value.point({ x: 0, y: 0 })
  101. );
  102. },
  103. getReal(pixel: number) {
  104. return lineLen(
  105. transform.value.point({ x: pixel, y: 0 }),
  106. transform.value.point({ x: 0, y: 0 })
  107. );
  108. },
  109. };
  110. }, Symbol("unitTransform"));
  111. export const useCacheUnitTransform = installGlobalVar(() => {
  112. const unitTransform = useUnitTransform();
  113. const transform = useViewerTransform();
  114. const invTransform = useViewerInvertTransform();
  115. let pixelCache: Record<string, number> = {};
  116. let realCache: Record<string, number> = {};
  117. watch(transform, () => {
  118. pixelCache = {};
  119. });
  120. watch(invTransform, () => {
  121. realCache = {};
  122. });
  123. return {
  124. getPixel(real: number) {
  125. if (real in pixelCache) {
  126. return pixelCache[real];
  127. } else {
  128. return (pixelCache[real] = unitTransform.getPixel(real));
  129. }
  130. },
  131. getReal(pixel: number) {
  132. if (pixel in realCache) {
  133. return realCache[pixel];
  134. } else {
  135. return (pixelCache[pixel] = unitTransform.getReal(pixel));
  136. }
  137. },
  138. };
  139. }, Symbol("cacheUnitTransform"));
  140. export const useViewSize = installGlobalVar(() => {
  141. const size = useResize();
  142. const { sizeMat, viewer } = useViewer();
  143. return computed(() => {
  144. if (sizeMat.value) {
  145. return viewer.viewSize!;
  146. } else {
  147. return size.value;
  148. }
  149. });
  150. });
  151. export const useViewBoxPixelRect = installGlobalVar(() => {
  152. const size = useResize();
  153. const { sizeMat, viewer, transform } = useViewer();
  154. return computed(() => {
  155. if (sizeMat.value) {
  156. const size = viewer.viewSize!;
  157. const p1 = transform.value.point({ x: 0, y: 0 });
  158. const p2 = transform.value.point({ x: size.width, y: size.height });
  159. return {
  160. ...p1,
  161. width: p2.x - p1.x,
  162. height: p2.y - p1.y,
  163. };
  164. } else {
  165. return {
  166. x: 0,
  167. y: 0,
  168. width: 100,
  169. height: 100,
  170. ...size.value,
  171. };
  172. }
  173. });
  174. });
  175. export const useGetViewBoxPositionPixel = () => {
  176. const size = useResize();
  177. const { sizeMat, viewer, transform } = useViewer();
  178. return (fixPosition: FixScreen, selfSize = { width: 1, height: 1 }) => {
  179. if (sizeMat.value) {
  180. const size = viewer.viewSize!;
  181. const pos = getFixPosition(fixPosition, selfSize, size);
  182. return transform.value.point(pos);
  183. } else {
  184. return getFixPosition(
  185. fixPosition,
  186. selfSize,
  187. size.value || { width: 100, height: 100 }
  188. );
  189. }
  190. };
  191. };
  192. export const useSetViewport = () => {
  193. const formalLayer = useFormalLayer();
  194. const { viewer } = useViewer();
  195. const config = useViewerTransformConfig();
  196. const initViewport = () => {
  197. const rect = formalLayer
  198. .value!.findOne<Group>("#" + DataGroupId)!
  199. .getClientRect();
  200. if (!(rect.width > 0 && rect.height > 0)) return;
  201. const center = {
  202. x: rect.x + rect.width / 2,
  203. y: rect.y + rect.height / 2,
  204. };
  205. const mat = new Transform()
  206. .translate(center.x, center.y)
  207. .rotate(MathUtils.degToRad(config.value.rotation))
  208. .translate(-center.x, -center.y);
  209. const start = mat.point({x: rect.x, y: rect.y});
  210. const end = mat.point({
  211. x: rect.x + rect.width,
  212. y: rect.y + rect.height,
  213. });
  214. let width = end.x - start.x;
  215. let height = end.y - start.y;
  216. setViewport({ ...start, width, height });
  217. };
  218. const setViewport = (rect: IRect, padding = 20, isPixel = true) => {
  219. const invMat = viewer.transform.invert();
  220. const lt = isPixel ? invMat.point(rect) : rect;
  221. const rb = isPixel
  222. ? invMat.point({
  223. x: rect.x + rect.width,
  224. y: rect.y + rect.height,
  225. })
  226. : {
  227. x: rect.x + rect.width,
  228. y: rect.y + rect.height,
  229. };
  230. viewer.setBound({
  231. targetBound: {
  232. ...lt,
  233. width: rb.x - lt.x,
  234. height: rb.y - lt.y,
  235. },
  236. padding,
  237. });
  238. };
  239. return {
  240. initViewport,
  241. setViewport,
  242. };
  243. };