flow-renderer-resize-observer.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import { injectable } from 'inversify';
  6. import { type FlowNodeTransformData } from '@flowgram.ai/document';
  7. import { Disposable } from '@flowgram.ai/utils';
  8. import { isHidden, isRectInit } from './utils/element';
  9. /**
  10. * 监听 dom 元素的 size 变化,用于画布节点的大小变化重新计算
  11. */
  12. @injectable()
  13. export class FlowRendererResizeObserver {
  14. /**
  15. * 监听元素 size,并同步到 transform
  16. * @param el
  17. * @param transform
  18. */
  19. observe(el: HTMLElement, transform: FlowNodeTransformData): Disposable {
  20. const observer = new ResizeObserver(entries => {
  21. /**
  22. * NOTICE: 不加 window.requestAnimationFrame
  23. * 会导致 "ResizeObserver loop completed with undelivered notifications." 报错
  24. * 这个报错在 chrome 和 firefox 是默认被忽略的,但本地调试会被编译工具弹窗打断
  25. */
  26. window.requestAnimationFrame(() => {
  27. if (!Array.isArray(entries) || !entries.length) {
  28. return;
  29. }
  30. const entry = entries[0];
  31. const { contentRect, target } = entry;
  32. // 元素宽高未计算时,不更新节点 size
  33. const isContentRectInit = isRectInit(contentRect);
  34. // 目标节点脱离 DOM 树,忽略本次变更
  35. const isLeaveDOMTree = !target.parentNode;
  36. // IDE 环境下画布元素可能 display none,这时候会监听到元素宽高 0 导致闪屏
  37. // 此情况下不作 resize 重渲染
  38. const isHiddenElement = isHidden(target.parentNode as HTMLElement);
  39. if (isContentRectInit && !isLeaveDOMTree && !isHiddenElement) {
  40. // 更新节点 size 数据
  41. transform.size = {
  42. width: Math.round(contentRect.width * 10) / 10,
  43. height: Math.round(contentRect.height * 10) / 10,
  44. };
  45. }
  46. });
  47. });
  48. observer.observe(el);
  49. return Disposable.create(() => {
  50. observer.unobserve(el);
  51. });
  52. }
  53. }