Skip to content

Commit

Permalink
fix(useDevicePixelRatio): more efficient mechanism (#2044)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
Waleed-KH and antfu committed Sep 5, 2022
1 parent c463ab7 commit eb05403
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 33 deletions.
1 change: 1 addition & 0 deletions packages/core/useDevicePixelRatio/demo.vue
Expand Up @@ -10,4 +10,5 @@ const code = stringify(pixelRatio)
<template>
<div>Device Pixel Ratio:</div>
<pre>{{ code }}</pre>
<span class="opacity-50">Zoom in and out (or move the window to a screen with a different scaling factor) to see the value changes</span>
</template>
2 changes: 1 addition & 1 deletion packages/core/useDevicePixelRatio/index.md
Expand Up @@ -6,7 +6,7 @@ category: Sensors

Reactively track [`window.devicePixelRatio`](https://developer.mozilla.org/ru/docs/Web/API/Window/devicePixelRatio)
>
> NOTE: there is no event listener for `window.devicePixelRatio` change. So this function uses [`Testing media queries programmatically (window.matchMedia)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) as described in [this example](https://stackoverflow.com/questions/28905420/window-devicepixelratio-change-listener/29653772#29653772), but unlike the example this function subscribes to **several** pixelRatio scales (taken from [mydevice.io](https://www.mydevice.io/)) to detect any `window.devicePixelRatio` change.
> NOTE: there is no event listener for `window.devicePixelRatio` change. So this function uses [`Testing media queries programmatically (window.matchMedia)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries) applying the same mechanism as described in [this example](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes).
## Usage

Expand Down
53 changes: 21 additions & 32 deletions packages/core/useDevicePixelRatio/index.ts
@@ -1,24 +1,7 @@
import { ref, watch } from 'vue-demi'
import { useEventListener } from '../useEventListener'
import { useMediaQuery } from '../useMediaQuery'
import type { ConfigurableWindow } from '../_configurable'
import { defaultWindow } from '../_configurable'

// device pixel ratio statistics from https://www.mydevice.io/
const DEVICE_PIXEL_RATIO_SCALES = [
1,
1.325,
1.4,
1.5,
1.8,
2,
2.4,
2.5,
2.75,
3,
3.5,
4,
]
import { ref } from 'vue-demi'
import { type Fn, tryOnScopeDispose } from '@vueuse/shared'
import { type ConfigurableWindow, defaultWindow } from '../_configurable'

/**
* Reactively track `window.devicePixelRatio`.
*
Expand All @@ -34,21 +17,27 @@ export function useDevicePixelRatio({
}
}

const pixelRatio = ref(window.devicePixelRatio)
const pixelRatio = ref(1)

const handleDevicePixelRatio = () => {
pixelRatio.value = window.devicePixelRatio
}
const cleanups: Fn[] = []

useEventListener(window, 'resize', handleDevicePixelRatio, { passive: true })
const cleanup = () => {
cleanups.map(i => i())
cleanups.length = 0
}

DEVICE_PIXEL_RATIO_SCALES.forEach((dppx) => {
// listen mql events in both sides
const mqlMin = useMediaQuery(`screen and (min-resolution: ${dppx}dppx)`)
const mqlMax = useMediaQuery(`screen and (max-resolution: ${dppx}dppx)`)
const observe = () => {
pixelRatio.value = window.devicePixelRatio
cleanup()
const media = window.matchMedia(`(resolution: ${pixelRatio.value}dppx)`)
media.addEventListener('change', observe, { once: true })
cleanups.push(() => {
media.removeEventListener('change', observe)
})
}

watch([mqlMin, mqlMax], handleDevicePixelRatio)
})
observe()
tryOnScopeDispose(cleanup)

return { pixelRatio }
}
Expand Down

0 comments on commit eb05403

Please sign in to comment.