UNPKG

danmaku

Version:

Display danmaku (flying comments) on HTML5 video.

140 lines (127 loc) 3.84 kB
var dpr = typeof window !== 'undefined' && window.devicePixelRatio || 1; export var canvasHeightCache = Object.create(null); export function canvasHeight(font, fontSize) { if (canvasHeightCache[font]) { return canvasHeightCache[font]; } var height = 12; var regex = /(\d+(?:\.\d+)?)(px|%|em|rem)(?:\s*\/\s*(\d+(?:\.\d+)?)(px|%|em|rem)?)?/; var p = font.match(regex); if (p) { var fs = p[1] * 1 || 10; var fsu = p[2]; var lh = p[3] * 1 || 1.2; var lhu = p[4]; if (fsu === '%') fs *= fontSize.container / 100; if (fsu === 'em') fs *= fontSize.container; if (fsu === 'rem') fs *= fontSize.root; if (lhu === 'px') height = lh; if (lhu === '%') height = fs * lh / 100; if (lhu === 'em') height = fs * lh; if (lhu === 'rem') height = fontSize.root * lh; if (lhu === undefined) height = fs * lh; } canvasHeightCache[font] = height; return height; } export function createCommentCanvas(cmt, fontSize) { if (typeof cmt.render === 'function') { var cvs = cmt.render(); if (cvs instanceof HTMLCanvasElement) { cmt.width = cvs.width; cmt.height = cvs.height; return cvs; } } var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var style = cmt.style || {}; style.font = style.font || '10px sans-serif'; style.textBaseline = style.textBaseline || 'bottom'; var strokeWidth = style.lineWidth * 1; strokeWidth = (strokeWidth > 0 && strokeWidth !== Infinity) ? Math.ceil(strokeWidth) : !!style.strokeStyle * 1; ctx.font = style.font; cmt.width = cmt.width || Math.max(1, Math.ceil(ctx.measureText(cmt.text).width) + strokeWidth * 2); cmt.height = cmt.height || Math.ceil(canvasHeight(style.font, fontSize)) + strokeWidth * 2; canvas.width = cmt.width * dpr; canvas.height = cmt.height * dpr; ctx.scale(dpr, dpr); for (var key in style) { ctx[key] = style[key]; } var baseline = 0; switch (style.textBaseline) { case 'top': case 'hanging': baseline = strokeWidth; break; case 'middle': baseline = cmt.height >> 1; break; default: baseline = cmt.height - strokeWidth; } if (style.strokeStyle) { ctx.strokeText(cmt.text, strokeWidth, baseline); } ctx.fillText(cmt.text, strokeWidth, baseline); return canvas; } function computeFontSize(el) { return window .getComputedStyle(el, null) .getPropertyValue('font-size') .match(/(.+)px/)[1] * 1; } export function init(container) { var stage = document.createElement('canvas'); stage.context = stage.getContext('2d'); stage._fontSize = { root: computeFontSize(document.getElementsByTagName('html')[0]), container: computeFontSize(container) }; return stage; } export function clear(stage, comments) { stage.context.clearRect(0, 0, stage.width, stage.height); // avoid caching canvas to reduce memory usage for (var i = 0; i < comments.length; i++) { comments[i].canvas = null; } } export function resize(stage, width, height) { stage.width = width * dpr; stage.height = height * dpr; stage.style.width = width + 'px'; stage.style.height = height + 'px'; } export function framing(stage) { stage.context.clearRect(0, 0, stage.width, stage.height); } export function setup(stage, comments) { for (var i = 0; i < comments.length; i++) { var cmt = comments[i]; cmt.canvas = createCommentCanvas(cmt, stage._fontSize); } } export function render(stage, cmt) { stage.context.drawImage(cmt.canvas, cmt.x * dpr, cmt.y * dpr); } export function remove(stage, cmt) { // avoid caching canvas to reduce memory usage cmt.canvas = null; } export default { name: 'canvas', init: init, clear: clear, resize: resize, framing: framing, setup: setup, render: render, remove: remove, };