Files
ArtPlayer/packages/artplayer-proxy-canvas/src/index.js
T
Harvey Zhao 1e60637b74 refactor: remove global window assignment for Artplayer and template export
- Removed the assignment of Artplayer to the global window object in index.js of the artplayer package.
- Eliminated the window export for the template plugin in index.js, streamlining the code and reducing global scope pollution.
2026-03-07 20:24:29 +08:00

140 lines
3.6 KiB
JavaScript

export default function artplayerProxyCanvas(callback) {
return (art) => {
const { constructor } = art
const { createElement } = constructor.utils
const canvas = createElement('canvas')
const video = createElement('video')
const ctx = canvas.getContext('2d')
let animationId = null
const originalCanvasMethods = {}
for (const prop in canvas) {
if (typeof canvas[prop] === 'function') {
originalCanvasMethods[prop] = canvas[prop].bind(canvas)
}
}
for (const prop in video) {
if (!(prop in canvas)) {
Object.defineProperty(canvas, prop, {
get() {
const value = video[prop]
return typeof value === 'function' ? value.bind(video) : value
},
set(value) {
video[prop] = value
},
configurable: true,
enumerable: true,
})
}
}
for (const prop in originalCanvasMethods) {
canvas[prop] = function (...args) {
if (prop in originalCanvasMethods) {
return originalCanvasMethods[prop](...args)
}
return video[prop](...args)
}
}
setupEventListeners()
setupArtPlayerEvents()
return canvas
function setupEventListeners() {
const { events } = constructor.config
setTimeout(() => {
events.forEach((event) => {
art.proxy(video, event, (event) => {
art.emit(`video:${event.type}`, event)
})
})
})
}
async function draw() {
try {
if (typeof createImageBitmap !== 'undefined') {
const bitmap = await createImageBitmap(video)
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height)
bitmap.close()
}
else {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
}
callback && callback(ctx, video)
art.emit('artplayerProxyCanvas:draw', ctx, video)
}
catch (error) {
art.emit('artplayerProxyCanvas:error', error)
}
}
async function animation() {
await draw()
animationId = requestAnimationFrame(animation)
}
function resize() {
const player = art.template?.$player
if (!player || art.option.autoSize)
return
const aspectRatio = video.videoWidth / video.videoHeight
const containerWidth = player.clientWidth
const containerHeight = player.clientHeight
const containerRatio = containerWidth / containerHeight
let canvasWidth, canvasHeight
if (containerRatio > aspectRatio) {
canvasHeight = containerHeight
canvasWidth = canvasHeight * aspectRatio
}
else {
canvasWidth = containerWidth
canvasHeight = canvasWidth / aspectRatio
}
canvas.width = canvasWidth
canvas.height = canvasHeight
const paddingLeft = (containerWidth - canvasWidth) / 2
const paddingTop = (containerHeight - canvasHeight) / 2
Object.assign(canvas.style, {
padding: `${paddingTop}px ${paddingLeft}px`,
})
}
function setupArtPlayerEvents() {
art.on('video:loadedmetadata', () => {
canvas.width = video.videoWidth
canvas.height = video.videoHeight
})
art.on('video:play', () => {
cancelAnimationFrame(animationId)
animation()
})
art.on('video:pause', () => {
cancelAnimationFrame(animationId)
})
art.on('resize', () => {
resize()
draw()
})
art.on('destroy', () => {
cancelAnimationFrame(animationId)
})
}
}
}