VTable icon indicating copy to clipboard operation
VTable copied to clipboard

[Bug] 放大页面后,图片变模糊

Open feEden opened this issue 1 year ago • 3 comments

Version

1.5.3

Link to Minimal Reproduction

https://codesandbox.io/p/sandbox/vtable-export-umd-forked-c33q9r?file=%2Fsrc%2Findex.ts%3A78%2C1

Steps to Reproduce

mac触摸板放大,图片模糊

Current Behavior

image

图片模糊

Expected Behavior

图片高清适配

Environment

- OS:
- Browser:
- Framework:

Any additional comments?

No response

feEden avatar Jul 22 '24 09:07 feEden

这个是canvas的 已经生成的情况下 用浏览器的发个功能确实会这样哦

fangsmile avatar Jul 23 '24 02:07 fangsmile

不过可以监听浏览器缩放事件 处理重绘。有兴趣的可以提pr

fangsmile avatar Jul 23 '24 02:07 fangsmile

不过可以监听浏览器缩放事件 处理重绘。有兴趣的可以提pr

改了下 解决了 懒得PR了

import { type ListTable } from '@visactor/vtable';
import { debounce } from 'lodash';

const MIN_DEVICE_PIXEL_RATIO = 1;
function isMobile(device?: string) {
  if (device === 'mobile') {
    return true;
  }
  return /(iPhone|iPad|SymbianOS|Windows Phone|iPod|iOS|Android)/i.test(navigator.userAgent);
}
export class HdAdapter {
  private viewport = window as typeof window & { visualViewport: Element };

  private devicePixelRatioMedia: MediaQueryList;

  private listTableInstance: ListTable;

  private isDevicePixelRatioChange = false;

  constructor(instance: ListTable) {
    this.listTableInstance = instance;
  }

  public init = () => {
    this.initDevicePixelRatioListener();
    this.initDeviceZoomListener();
  };

  public destroy = () => {
    this.removeDevicePixelRatioListener();
    this.removeDeviceZoomListener();
  };

  private initDevicePixelRatioListener() {
    this.devicePixelRatioMedia = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
    if (this.devicePixelRatioMedia?.addEventListener) {
      this.devicePixelRatioMedia.addEventListener('change', this.renderByDevicePixelRatioChanged);
    } else {
      this.devicePixelRatioMedia.addListener(this.renderByDevicePixelRatioChanged);
    }
  }

  private removeDevicePixelRatioListener = () => {
    if (this.devicePixelRatioMedia?.removeEventListener) {
      this.devicePixelRatioMedia.removeEventListener('change', this.renderByDevicePixelRatioChanged);
    } else {
      this.devicePixelRatioMedia.removeListener(this.renderByDevicePixelRatioChanged);
    }
  };

  private initDeviceZoomListener = () => {
    if (isMobile()) {
      return;
    }
    // VisualViewport support browser zoom & mac touch tablet
    this.viewport?.visualViewport?.addEventListener('resize', this.renderByZoomScaleWithoutResizeEffect);
  };

  private removeDeviceZoomListener = () => {
    if (isMobile()) {
      return;
    }
    this.viewport?.visualViewport?.removeEventListener('resize', this.renderByZoomScaleWithoutResizeEffect);
  };

  /**
   * DPR 改变也会触发 visualViewport 的 resize 事件, 预期是只监听双指缩放, 所以这里规避掉
   */
  private renderByZoomScaleWithoutResizeEffect = (event: Event & { target: VisualViewport }) => {
    this.isDevicePixelRatioChange = false;
    this.renderByZoomScale(event);
  };

  private renderByDevicePixelRatioChanged = () => {
    this.isDevicePixelRatioChange = true;
    this.renderByDevicePixelRatio();
  };

  private renderByDevicePixelRatio = (ratio = window.devicePixelRatio) => {
    const {
      options: { pixelRatio },
    } = this.listTableInstance;
    const canvas = this.listTableInstance.canvas;

    if (pixelRatio === ratio || !canvas) {
      return;
    }

    // 缩放时, 以向上取整后的缩放比为准
    // 设备像素比改变时, 取当前和用户配置中最大的, 保证显示效果
    const _pixelRatio = Math.max(ratio, devicePixelRatio, MIN_DEVICE_PIXEL_RATIO);
    this.listTableInstance.setPixelRatio(_pixelRatio);
  };

  private renderByZoomScale = debounce((event: Event & { target: VisualViewport }) => {
    const ratio = Math.ceil(event.target.scale);

    if (ratio >= 1 && !this.isDevicePixelRatioChange) {
      this.renderByDevicePixelRatio(ratio);
    }
  }, 350);
}

feEden avatar Jul 23 '24 07:07 feEden