181 lines
4.9 KiB
Vue
181 lines
4.9 KiB
Vue
<template>
|
|
<div :class="$style.content">
|
|
<canvas :class="$style.canvas" ref="dom_canvas"></canvas>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, onBeforeUnmount, onMounted, useRefGetter, watch } from '@renderer/utils/vueTools'
|
|
import { getAnalyser } from '@renderer/plugins/player'
|
|
import { isPlay } from '@renderer/core/share/player'
|
|
import { player as eventPlayerNames } from '@renderer/event/names'
|
|
|
|
const themes = {
|
|
green: 'rgba(77,175,124,.16)',
|
|
blue: 'rgba(52,152,219,.16)',
|
|
yellow: 'rgba(233,212,96,.22)',
|
|
orange: 'rgba(245,171,53,.16)',
|
|
red: 'rgba(214,69,65,.12)',
|
|
pink: 'rgba(241,130,141,.16)',
|
|
purple: 'rgba(155,89,182,.14)',
|
|
grey: 'rgba(108,122,137,.16)',
|
|
ming: 'rgba(51,110,123,.14)',
|
|
blue2: 'rgba(79,98,208,.14)',
|
|
black: 'rgba(39,39,39,.4)',
|
|
mid_autumn: 'rgba(74,55,82,.1)',
|
|
naruto: 'rgba(87,144,167,.14)',
|
|
happy_new_year: 'rgba(192,57,43,.1)',
|
|
}
|
|
|
|
const getBarWidth = canvasWidth => {
|
|
let barWidth = (canvasWidth / 128) * 2.5
|
|
const width = canvasWidth / 85
|
|
// console.log(barWidth - width)
|
|
// if (barWidth - width > 20) newBarWidth = 20
|
|
// barWidth = newBarWidth
|
|
return barWidth - width > 12 ? width : barWidth
|
|
}
|
|
export default {
|
|
setup() {
|
|
const dom_canvas = ref(null)
|
|
const analyser = getAnalyser()
|
|
|
|
let ctx
|
|
let bufferLength = 0
|
|
let dataArray
|
|
let WIDTH
|
|
let HEIGHT
|
|
let MAX_HEIGHT
|
|
let barWidth
|
|
let barHeight
|
|
let x = 0
|
|
let isPlaying = false
|
|
let animationFrameId
|
|
|
|
let num
|
|
let mult
|
|
const maxNum = 255
|
|
let frequencyAvg = 0
|
|
|
|
const theme = useRefGetter('theme')
|
|
// const setting = useRefGetter('setting')
|
|
let themeColor = themes[theme.value || 'green']
|
|
watch(theme, theme => {
|
|
themeColor = themes[theme || 'green']
|
|
})
|
|
|
|
// https://developer.mozilla.org/zh-CN/docs/Web/API/AnalyserNode/smoothingTimeConstant
|
|
const renderFrame = () => {
|
|
animationFrameId = null
|
|
if (isPlaying) animationFrameId = window.requestAnimationFrame(renderFrame)
|
|
|
|
x = 0
|
|
|
|
analyser.getByteFrequencyData(dataArray)
|
|
|
|
ctx.clearRect(0, 0, WIDTH, HEIGHT)
|
|
// ctx.fillRect(0, 0, WIDTH, HEIGHT)
|
|
ctx.fillStyle = themeColor
|
|
|
|
for (let i = 0; i < bufferLength; i++) {
|
|
mult = Math.floor(i / maxNum)
|
|
num = mult % 2 === 0 ? (i - maxNum * mult) : (maxNum - (i - maxNum * mult))
|
|
let spectrum = num > 90 ? 0 : dataArray[num + 20]
|
|
frequencyAvg += spectrum * 1.2
|
|
}
|
|
frequencyAvg /= bufferLength
|
|
frequencyAvg *= 1.4
|
|
|
|
frequencyAvg = frequencyAvg / maxNum
|
|
// ctx.scale(1, 1 + frequencyAvg)
|
|
|
|
for (let i = 0; i < bufferLength; i++) {
|
|
if (x > WIDTH) break
|
|
|
|
barHeight = dataArray[i]
|
|
|
|
// let r = barHeight + (25 * (i / bufferLength))
|
|
// let g = 250 * (i / bufferLength)
|
|
// let b = 50
|
|
|
|
// ctx.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')'
|
|
barHeight = (barHeight * frequencyAvg + barHeight * 0.42) * MAX_HEIGHT
|
|
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight)
|
|
|
|
x += barWidth
|
|
}
|
|
}
|
|
|
|
const handlePlay = () => {
|
|
isPlaying = true
|
|
analyser.fftSize = 256
|
|
bufferLength = analyser.frequencyBinCount
|
|
// console.log(bufferLength)
|
|
barWidth = getBarWidth(WIDTH)
|
|
dataArray = new Uint8Array(bufferLength)
|
|
renderFrame()
|
|
}
|
|
const handlePause = () => {
|
|
if (animationFrameId) window.cancelAnimationFrame(animationFrameId)
|
|
isPlaying = false
|
|
}
|
|
|
|
const handleResize = () => {
|
|
const canvas = dom_canvas.value
|
|
canvas.width = canvas.clientWidth
|
|
canvas.height = canvas.clientHeight
|
|
WIDTH = canvas.width
|
|
HEIGHT = canvas.height
|
|
MAX_HEIGHT = Math.round(HEIGHT * 0.4 / 255 * 10000) / 10000
|
|
// console.log(MAX_HEIGHT)
|
|
barWidth = getBarWidth(WIDTH)
|
|
}
|
|
|
|
window.eventHub.on(eventPlayerNames.play, handlePlay)
|
|
window.eventHub.on(eventPlayerNames.pause, handlePause)
|
|
window.eventHub.on(eventPlayerNames.error, handlePause)
|
|
window.addEventListener('resize', handleResize)
|
|
onBeforeUnmount(() => {
|
|
handlePause()
|
|
window.eventHub.off(eventPlayerNames.play, handlePlay)
|
|
window.eventHub.off(eventPlayerNames.pause, handlePause)
|
|
window.eventHub.off(eventPlayerNames.error, handlePause)
|
|
window.removeEventListener('resize', handleResize)
|
|
})
|
|
|
|
onMounted(() => {
|
|
const canvas = dom_canvas.value
|
|
ctx = canvas.getContext('2d')
|
|
canvas.width = canvas.clientWidth
|
|
canvas.height = canvas.clientHeight
|
|
WIDTH = canvas.width
|
|
HEIGHT = canvas.height
|
|
MAX_HEIGHT = Math.round(HEIGHT * 0.4 / 255 * 10000) / 10000
|
|
// console.log(MAX_HEIGHT)
|
|
if (isPlay.value) handlePlay()
|
|
})
|
|
|
|
return {
|
|
dom_canvas,
|
|
}
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" module>
|
|
.content {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none;
|
|
z-index: 100;
|
|
}
|
|
.canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
// opacity: 0.1;
|
|
}
|
|
</style>
|