1
0
Fork 0
moritzruth.de/components/BlurredBlobCanvas.vue

130 lines
3.1 KiB
Vue

<template>
<canvas ref="canvasElement" :style="{ filter: `blur(${blur}px)`, height: size + 'px', width: size + 'px' }"/>
</template>
<script>
import { canvasPath as createBlobAnimation } from "blobs/v2/animate/index.module.js"
import { ref, watchEffect } from "vue"
import { useRafFn } from "@vueuse/core"
function getComponentsOfHexColor(hexColorString) {
return [
Number.parseInt(hexColorString.slice(1, 3), 16),
Number.parseInt(hexColorString.slice(3, 5), 16),
Number.parseInt(hexColorString.slice(5, 7), 16)
]
}
export default {
name: "BlurredBlobCanvas",
props: {
colors: {
type: Array,
required: true
},
size: {
type: Number,
required: true
},
blur: {
type: Number,
default: 30
},
minimumDuration: {
type: Number,
required: true
},
durationVariation: {
type: Number,
default: 0
},
minimumOpacity: {
type: Number,
required: true
},
opacityVariation: {
type: Number,
default: 0
},
points: {
type: Number,
default: 4
},
randomness: {
type: Number,
default: 40
}
},
setup(props) {
const canvasElement = ref(null)
// { blob, targetOpacity, opacityTransitionStart }
let blobs = []
const getRandomBlobOptions = () => ({
extraPoints: props.points - 3,
randomness: props.randomness,
seed: Math.random(),
size: props.size
})
const getRandomOpacity = () => props.minimumOpacity + (Math.random() * props.opacityVariation)
watchEffect(onInvalidate => {
props.colors.forEach(color => {
const animation = createBlobAnimation()
const loop = () => {
animation.transition({
duration: props.minimumDuration + (Math.random() * props.durationVariation),
timingFunction: "ease",
blobOptions: getRandomBlobOptions(),
callback: loop
})
}
animation.transition({
duration: 0,
blobOptions: getRandomBlobOptions(),
callback: loop
})
blobs.push({
animation,
color: getComponentsOfHexColor(color),
opacity: getRandomOpacity()
})
})
onInvalidate(() => {
blobs.forEach(blob => {
blob.animation.pause()
})
blobs = []
})
})
useRafFn(() => {
const canvas = canvasElement.value
if (canvas === null) return
canvas.width = props.size
canvas.height = props.size
const context = canvas.getContext("2d")
context.clearRect(0, 0, canvas.width, canvas.height)
blobs.forEach(blob => {
const [red, green, blue] = blob.color
context.fillStyle = `rgba(${red}, ${green}, ${blue}, ${blob.opacity})`
context.fill(blob.animation.renderFrame())
})
})
return {
canvasElement
}
}
}
</script>