Last active
September 4, 2019 07:40
-
-
Save smolinari/37367d96e800c940c289e86f752c2562 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template lang="pug"> | |
div.component(ref="el" :style="{ filter: `saturate(${saturation}) brightness(${brightness})` }") | |
div | |
div Brightness: {{brightness}} | |
div Saturation: {{saturation}} | |
div Width: {{width}} | |
div Height: {{height}} | |
div X: {{x}} | |
div Y: {{y}} | |
</template> | |
<script> | |
import { onBeforeUnmount, onMounted, reactive, ref, toRefs, watch } from '@vue/composition-api' | |
export default { | |
setup () { | |
let el = ref(null) | |
const { x, y } = useRelativeMousePosition(el) | |
const { width, height } = useSizeObserver(el) | |
const { brightness } = useBrightness(x, width) | |
const { saturation } = useSaturation(y, height) | |
return { | |
el, | |
width, | |
height, | |
x, | |
y, | |
brightness, | |
saturation | |
} | |
} | |
} | |
function useRelativeMousePosition (el) { | |
let mousePosition = reactive({ | |
x: 0, | |
y: 0 | |
}) | |
function update (event) { | |
const rect = el.getBoundingClientRect() | |
mousePosition.x = event.clientX - rect.left | |
mousePosition.y = event.clientY - rect.top | |
} | |
onMounted(() => window.addEventListener('mousemove', update)) | |
onBeforeUnmount(() => window.removeEventListener('mousemove', update)) | |
return toRefs(mousePosition) | |
function useSizeObserver (el) { | |
let attrs = reactive({ | |
width: 0, | |
height: 0 | |
}) | |
const resizeObserver = new ResizeObserver(entries => { | |
for (let entry of entries) { | |
attrs.width = entry.contentRect.width | |
attrs.height = entry.contentRect.height | |
} | |
}) | |
onMounted(() => resizeObserver.observe(el)) | |
onBeforeUnmount(() => resizeObserver.unobserve(el)) | |
return toRefs(attrs) | |
} | |
function useBrightness (value, maxValue) { | |
let brightnessRef = ref(0) | |
watch([value, maxValue], ([value, max]) => { | |
brightnessRef = cappedValue(value, { max, min: 0 }) | |
}, { lazy: true }) | |
return { brightnessRef } | |
} | |
function useSaturation (value, maxValue) { | |
let saturationRef = ref(0) | |
watch([value, maxValue], ([value, max]) => { | |
saturationRef = cappedValue(value, { max, min: 0 }) | |
}, { lazy: true }) | |
return { saturationRef } | |
} | |
function cappedValue (value, { max, min }) { | |
return Math.max(min, Math.min(value, max)) / max | |
} | |
</script> | |
<style | |
lang="scss" | |
scoped | |
> | |
.component { | |
max-width: 700px; | |
min-height: 300px; | |
background: royalblue; | |
color: white; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
flex-direction: column; | |
} | |
</style> |
@smolinari
Will check your solution soon.
I realised that in my use cases i never had to deal with actual mutable lists or other complex data. Took me long to realise, but seems like I can't really do those with refs only without much pain 😅
@smolinari
Besides couple of typos there are still problems with lines #20 and #21 because primitive values are passed into functions instead of refs/reactive data.
@trafium - And if just the variable is passed in without value? Using value in the function?
Scott
@smolinari
Yes, in fact we don't need to use .value
at all since we would pass ref into watch
and receive plain values in callback function ([value, max]
part)
@trafium - edited. Will that work?
Scott
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use it to group properties that really do belong together. A mouse position always has an x and y. A date range that has start, end. In the rare occasion you really only need/can pass the y axis along, i'd destructure it into refs.
I actually use it rather often. It might seem that reactive is superfluous, but at this point I would not want to miss it.