jukebox/src/renderer/layouts/PlayerBar.vue

194 lines
5.6 KiB
Vue

<template>
<section class="player">
<img @load="onArtworkLoad" class="artwork" src="/static/demo/artwork.jpg" />
<div>
<p class="title">Don't Let Me Down</p>
<p class="artist">The Chainsmokers</p>
</div>
<div class="visualizer">
<div id="visualizer"></div>
<div id="minimap" class="shade"></div>
</div>
<div class="duration">
<p class="progress active">00:00</p>
<p>{{duration}}</p>
</div>
<div class="control-buttons">
<div class="play-pause-button" @click="togglePlay">
<svg v-show="!playingStatus" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm-4 29V15l12 9-12 9z"/></svg>
<svg v-show="playingStatus" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm-2 28h-4V16h4v16zm8 0h-4V16h4v16z"/></svg>
</div>
</div>
</section>
</template>
<script>
import WaveSurfer from 'wavesurfer.js'
import minimap from 'wavesurfer.js/dist/plugin/wavesurfer.minimap'
import color from 'dominant-color'
import { formatSeconds } from '../utility/DateTime'
export default {
name: 'PlayerBar',
mounted () {
let progress = this.$el.getElementsByClassName('progress')[0]
this.wavesurfer = WaveSurfer.create({
container: '#visualizer',
waveColor: '#c3c3c3',
progressColor: '#336cfb',
cursorColor: 'rgba(0,0,0,0)',
barWidth: 2,
barHeight: 1,
barGap: null,
autoCenter: true,
responsive: true,
height: 64,
plugins: [
minimap.create({
container: '#minimap',
waveColor: '#c3c3c3',
progressColor: '#336cfb',
cursorColor: 'rgba(0,0,0,0)',
barWidth: 2,
barHeight: 1,
barGap: null,
autoCenter: true,
responsive: true,
height: 64
})
]
})
this.wavesurfer.load('/static/demo/music.mp3')
this.wavesurfer.on('ready', () => {
this.duration = formatSeconds(this.getDuration())
this.wavesurfer.container.style['height'] = '100%'
let map = this.wavesurfer.minimap.drawer.container
map.style['height'] = '100%'
})
let currentWidth = 0
let hoverStatus = false
let hoverWidth = '0px'
let isSeek = false
let progressWave = this.wavesurfer.minimap.drawer.container.getElementsByTagName('wave')[1]
progressWave.style['zIndex'] = 4
let mainWave = this.wavesurfer.container.getElementsByTagName('wave')[0]
this.wavesurfer.on('audioprocess', (amount) => {
currentWidth = progressWave.style.width
if (hoverStatus && !isSeek) {
progressWave.style.width = hoverWidth
}
isSeek = false
progress.innerHTML = formatSeconds(amount)
})
mainWave.addEventListener('mouseenter', (e) => {
isSeek = false
hoverStatus = true
})
mainWave.addEventListener('mousemove', (e) => {
hoverWidth = e.offsetX + 'px'
progressWave.style.width = hoverWidth
})
mainWave.addEventListener('mouseout', (e) => {
hoverStatus = false
progressWave.style.width = currentWidth
})
this.wavesurfer.on('seek', (amount) => {
if (!this.playingStatus) {
this.wavesurfer.drawer.progress(amount)
}
isSeek = true
currentWidth = progressWave.style.width
})
},
data () {
return {
playingStatus: false,
duration: '00:00'
}
},
methods: {
onArtworkLoad () {
let img = this.$el.getElementsByTagName('img')[0]
color(img.src, (_, color) => {
this.wavesurfer.setProgressColor(`#${color}`)
this.wavesurfer.minimap.params.progressColor = `#${color}`
this.wavesurfer.minimap.drawer.updateSize()
})
},
play () {
this.wavesurfer.play()
},
pause () {
this.wavesurfer.pause()
},
stop () {
this.wavesurfer.stop()
},
toggleMute () {
this.wavesurfer.toggleMute()
},
setPlaybackRate (rate) {
this.wavesurfer.setPlaybackRate(rate)
},
isPlaying () {
return typeof this.wavesurfer === 'undefined' ? false : this.wavesurfer.isPlaying()
},
skip (offset) {
this.wavesurfer.skip(offset)
},
getVolume () {
return this.wavesurfer.getVolume()
},
setVolume (volume) {
this.wavesurfer.setVolume(volume)
},
getDuration () {
return this.wavesurfer.getDuration()
},
togglePlay () {
this.wavesurfer.playPause()
this.playingStatus = this.isPlaying()
}
}
}
</script>
<style lang="sass">
section.player
display: flex
align-items: center
border-top: 1px solid rgba(0,0,0,0.1)
height: 4.5rem
min-height: 4.5rem
img.artwork
height: 4.5rem
width: 4.5rem
p.title,p.artist
font-size: .8rem
margin: 8px 10px
p.artist
color: lighten(black,45)
.visualizer
flex-grow: 1
height: 64px
position: relative
div
position: absolute
left: 0
top: 0
bottom: 0
margin: auto
transition: height 500ms ease
height: 0px
width: 100%
z-index:
&.shade
pointer-events: none
z-index: 2
opacity: .6
wave
overflow-x: hidden !important
cursor: pointer
transition: width 200ms ease
height: 100% !important
</style>