1、创建音频上下文。
2、创建音频乐谱分析仪
3、将分析出的数据画到canvas上。
1、创建音频上下文
this.audioContext = new AudioContext()
2、创建源及乐谱分析仪,并链接
// 创建音频源节点
this.source = this.audioContext.createMediaElementSource(this.audioElement)
// 创建乐谱分析器
this.analyser = this.audioContext.createAnalyser()
// 设置分析精度
this.analyser.fftSize = this.options.fftSize
// 将源链接到分析器
this.source.connect(this.analyser)
//将分析器链接到音频上下文目的地
this.analyser.connect(this.audioContext.destination)
3、绘制到canvas上
// 清除画布
const { width, height } = this.canvasElement
this.ctx.clearRect(0, 0, width, height)
// 让分析器节点将分析出的数据放到存储容器内
this.analyser.getByteFrequencyData(this.dataArray)
// 计算要绘制的区域
const l = this.dataArray.length * (this.options.range / 100)
// 计算每个块的宽度
const barWidth = width / l / 2
this.ctx.fillStyle = this.options.color
for (let i = 0; i < l; i++) {
// 获取每个的数据,此值小于256
const item = this.dataArray[i]
// 计算块高度
const h = (item / 255) * height
// 计算块开始的y
const y = height - h
// 计算块开始的x,对称
const x_r = i * barWidth + width / 2
const x_l = width - x_r
this.ctx.fillRect(x_r, y, barWidth, height)
this.ctx.fillRect(x_l, y, barWidth, height)
}
4、使用requestAnimationFrame重复绘制
this.animateId = requestAnimationFrame(this.draw.bind(this))
music-score.ts
interface IOptionsType {
// audio元素|audio元素选择器|网络音频地址
audio: string | htmlAudioElement
canvas: string | HTMLCanvasElement
fftSize?: number
color?: string
range?: number
}
export class MpMusicScore {
private options: Partial<IOptionsType> = {
fftSize: 512,
color: '#9adcff',
range: 70
}
private audioElement: HTMLAudioElement
private canvasElement: HTMLCanvasElement
private audioContext: AudioContext
private analyser: AnalyserNode
private source: MediaElementAudioSourceNode
private dataArray: Uint8Array
private animateId: number
private ctx: CanvasRenderingContext2D
private isInitAudio: boolean = false
constructor(options: IOptionsType) {
this.options = { ...this.options, ...options }
this.init()
}
// 初始化参数
private init() {
// 获取音频元素
if (typeof this.options.audio === 'string') {
if (
this.options.audio.includes('//') &&
this.options.audio.endsWith('.mp3')
) {
this.audioElement = new Audio(this.options.audio)
} else {
this.audioElement = document.querySelector(this.options.audio)
}
} else if (this.options.audio instanceof HTMLAudioElement) {
this.audioElement = this.options.audio
}
if (!(this.audioElement instanceof HTMLAudioElement)) {
throw '音频不存在!'
}
// 获取画布元素
if (typeof this.options.canvas === 'string') {
this.canvasElement = document.querySelector(this.options.canvas)
} else if (this.options.canvas instanceof HTMLCanvasElement) {
this.canvasElement = this.options.canvas
}
if (!(this.canvasElement instanceof HTMLCanvasElement)) {
throw '画布不存在!'
}
if (Math.log2(this.options.fftSize) % 1 !== 0) {
throw 'fftSize为2的n次幂!'
}
// 初始化画布及画布大小
this.ctx = this.canvasElement.getContext('2d')
const { clientWidth, clientHeight } = this.canvasElement
this.canvasElement.width = clientWidth
this.canvasElement.height = clientHeight
// 添加绘制事件
this.audioElement.addEventListener('play', this.draw.bind(this))
this.audioElement.addEventListener('pause', this.cancelDraw.bind(this))
}
// 初始化音频
private initAudio() {
if (this.isInitAudio) {
return
}
this.isInitAudio = true
// 创建audio上下文
this.audioContext = new AudioContext()
// 创建音频源节点
this.source = this.audioContext.createMediaElementSource(this.audioElement)
// 创建乐谱分析器
this.analyser = this.audioContext.createAnalyser()
// 设置分析精度
this.analyser.fftSize = this.options.fftSize
// 将源链接到分析器
this.source.connect(this.analyser)
//将分析器链接到音频上下文目的地
this.analyser.connect(this.audioContext.destination)
// 创建乐谱存储容器
this.dataArray = new Uint8Array(this.analyser.frequencyBinCount)
}
// 绘制乐谱
private draw() {
// 初始化Audio
this.initAudio()
this.animateId = requestAnimationFrame(this.draw.bind(this))
// 清除画布
const { width, height } = this.canvasElement
this.ctx.clearRect(0, 0, width, height)
// 让分析器节点将分析出的数据放到存储容器内
this.analyser.getByteFrequencyData(this.dataArray)
// 计算要绘制的区域
const l = this.dataArray.length * (this.options.range / 100)
// 计算每个块的宽度
const barWidth = width / l / 2
this.ctx.fillStyle = this.options.color
for (let i = 0; i < l; i++) {
// 获取每个的数据,此值小于256
const item = this.dataArray[i]
// 计算块高度
const h = (item / 255) * height
// 计算块开始的y
const y = height - h
// 计算块开始的x,对称
const x_r = i * barWidth + width / 2
const x_l = width - x_r
this.ctx.fillRect(x_r, y, barWidth, height)
this.ctx.fillRect(x_l, y, barWidth, height)
}
}
// 取消绘制
private cancelDraw() {
cancelAnimationFrame(this.animateId)
}
// 播放
public play() {
this.audioElement.play()
}
// 暂停
public pause() {
this.audioElement.pause()
}
// 获取audio元素
public getAudioElement() {
return this.audioElement
}
}
audio(audio元素 | audio元素选择器 | 网络音频地址)、
canvas(canvas元素或选择器)、
fftSize(精度,越大越精细,必须为2的n次幂)、
color(乐谱块颜色)、
range(乐谱的取值,因乐谱后面的频率一般为0,没有显示,可以通过此值,只取前面部分)。
new MpMusicScore({
audio: 'audio',
canvas: 'canvas',
color: '#58ee43',
range: 50,
fftSize: 1024
})
const score = new MpMusicScore({
audio: 'http://127.0.0.1:5173/1.mp3',
canvas: 'canvas',
color: 'red',
range: 75,
fftSize: 2048
})
setTimeout(() => {
score.play()
}, 1000)
文章参考:https://v.douyin.com/B7tMkcK/
来源:https://www.ljhmp.com/article-detail.html?id=29
今天这篇文章就来讲讲使用JavaScript来实现这种分屏的视觉UI效果。现在在网站上这种分屏视觉效果应用的也非常广泛,比如 Corsair website。
在css中使用伪类虽然实现了样式的改变,但由于没有过渡效果会显得很生硬。以前如果要实现过渡,就需要借助第三方的js框架来实现。现在只需要使用CSS3的过渡(transition)功能,就可以从一组样式平滑的切换到另一组样式。
js最近有个小伙伴问到了怎么实现新手引导的效果,然后便去网上找了下实现方案。可以通过css的border来实现。
设计图含有斜切角的效果时,我们一般想到的方法是切出四个角为背景,然后用border连起来,这样就能显示出该效果了,那么直接使用css呢?下面就整理css做斜边的效果。
这篇文章在不使用任何插件的情况,以最简洁的原生javascript来实现打字机效果和跑马灯效果。打字效果即把一段话一个字一个字的显示出来。
一般遮罩加上透明度opacity就是阴影效果。阴影效果和一般遮罩一样,唯一不同的是设置.mask遮罩的背景色用rgba()表示,当然hsla()也是可以的。模糊效果(毛玻璃效果) 通过 filter来实现
主要运用的是1.border 组成的直角三角形。2,before 和 after 伪元素 。3,z-index属性;将元素的长宽设置为0,并且将border的3条边设置为透明的,就会出现border颜色的直角三角形
文字选中效果,这个可能很少有人注意过。在默认状态先一般选中的文本颜色是白字蓝底的,不过可以通过CSS进行设置。::selection定义元素上的伪选择器,以便在选定元素时设置其中文本的样式。
发布iPhone XR的时候 各种心动 去官网看了一遍又一遍。闲着无聊发现 里面的介绍很用大篇幅的有背景文字来介绍。Like this:看着挺酷炫的还不错 就看了下实现方式。还挺简单的。
多元素之间如何实现过渡动画效果呢?这么写行不行呢?肯定是不行的,因为 Vue 在两个元素进行切换的时候,会尽量复用dom,就是因为这个原因,导致现在动画效果不会出现。如果不让 Vue 复用dom的话,应该怎么做呢?只需要给这两个div不同的key值就行了
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!