From 82df2a3df5cf7276d91d52787437f43bf2b84037 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Tue, 14 Jul 2020 14:53:06 +0200 Subject: [PATCH] add news title --- examples/README.md | 10 ++++++++ examples/newsTitle.json5 | 15 ++++++++++++ index.js | 2 +- sources/fabricFrameSource.js | 44 ++++++++++++++++++++++++++++++++++++ sources/frameSource.js | 3 ++- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 examples/newsTitle.json5 diff --git a/examples/README.md b/examples/README.md index 064bdb2..fc59fd3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,6 +10,16 @@ editly kenBurns.json5 ``` +## News title + +![](https://github.com/mifi/gifs/raw/master/newsTitle.gif) + +[kenBurns.json5](https://github.com/mifi/editly/blob/master/examples/newsTitle.json5) + +```bash +editly newsTitle.json5 +``` + ## Resize modes ![](https://github.com/mifi/gifs/raw/master/resizeHorizontal.gif) diff --git a/examples/newsTitle.json5 b/examples/newsTitle.json5 new file mode 100644 index 0000000..36af020 --- /dev/null +++ b/examples/newsTitle.json5 @@ -0,0 +1,15 @@ +{ + width: 900, + height: 1600, + outPath: './newsTitle.mp4', + defaults: { + layer: { fontPath: './assets/Patua_One/PatuaOne-Regular.ttf' }, + }, + clips: [ + { duration: 10, layers: [ + { type: 'image', path: './assets/91083241_573589476840991_4224678072281051330_n.jpg' }, + { type: 'news-title', text: 'BREAKING NEWS' }, + { type: 'subtitle', text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', backgroundColor: 'rgba(0,0,0,0.5)' } + ] }, + ], +} \ No newline at end of file diff --git a/index.js b/index.js index 8a65e47..075dfe4 100644 --- a/index.js +++ b/index.js @@ -108,7 +108,7 @@ module.exports = async (config = {}) => { return outLayers; } - if (type === 'title' || type === 'subtitle') { + if (['title', 'subtitle', 'news-title'].includes(type)) { assert(layer.text, 'Please specify a text'); let { fontFamily } = layer; diff --git a/sources/fabricFrameSource.js b/sources/fabricFrameSource.js index d8452f2..7466ed1 100644 --- a/sources/fabricFrameSource.js +++ b/sources/fabricFrameSource.js @@ -278,6 +278,49 @@ async function titleFrameSource({ width, height, params }) { return { onRender }; } +async function newsTitleFrameSource({ width, height, params }) { + const { text, textColor = '#ffffff', backgroundColor = '#d02a42', fontFamily = 'sans-serif', delay = 0, speed = 1 } = params; + + async function onRender(progress, canvas) { + const min = Math.min(width, height); + + const fontSize = Math.round(min * 0.05); + + const easedBgProgress = easeOutExpo(Math.max(0, Math.min((progress - delay) * speed * 3, 1))); + const easedTextProgress = easeOutExpo(Math.max(0, Math.min((progress - delay - 0.02) * speed * 4, 1))); + const easedTextOpacityProgress = easeOutExpo(Math.max(0, Math.min((progress - delay - 0.07) * speed * 4, 1))); + + const top = height * 0.08; + + const paddingV = 0.07 * min; + const paddingH = 0.03 * min; + + const textBox = new fabric.Text(text, { + top, + left: paddingV + (easedTextProgress - 1) * width, + fill: textColor, + opacity: easedTextOpacityProgress, + fontFamily, + fontSize, + charSpacing: width * 0.1, + }); + + const bgWidth = textBox.width + (paddingV * 2); + const rect = new fabric.Rect({ + top: top - paddingH, + left: (easedBgProgress - 1) * bgWidth, + width: bgWidth, + height: textBox.height + (paddingH * 2), + fill: backgroundColor, + }); + + canvas.add(rect); + canvas.add(textBox); + } + + return { onRender }; +} + async function createCustomCanvasFrameSource({ width, height, params }) { const canvas = createCanvas(width, height); const context = canvas.getContext('2d'); @@ -315,6 +358,7 @@ module.exports = { customFabricFrameSource, subtitleFrameSource, titleFrameSource, + newsTitleFrameSource, fillColorFrameSource, radialGradientFrameSource, linearGradientFrameSource, diff --git a/sources/frameSource.js b/sources/frameSource.js index aff727f..1050659 100644 --- a/sources/frameSource.js +++ b/sources/frameSource.js @@ -1,7 +1,7 @@ const assert = require('assert'); const pMap = require('p-map'); -const { rgbaToFabricImage, customFabricFrameSource, createCustomCanvasFrameSource, titleFrameSource, subtitleFrameSource, imageFrameSource, linearGradientFrameSource, radialGradientFrameSource, fillColorFrameSource, createFabricFrameSource, createFabricCanvas, renderFabricCanvas } = require('./fabricFrameSource'); +const { rgbaToFabricImage, customFabricFrameSource, createCustomCanvasFrameSource, titleFrameSource, subtitleFrameSource, imageFrameSource, linearGradientFrameSource, radialGradientFrameSource, fillColorFrameSource, createFabricFrameSource, newsTitleFrameSource, createFabricCanvas, renderFabricCanvas } = require('./fabricFrameSource'); const createVideoFrameSource = require('./videoFrameSource'); const { createGlFrameSource } = require('./glFrameSource'); @@ -24,6 +24,7 @@ async function createFrameSource({ clip, clipIndex, width, height, channels, ver 'linear-gradient': async (opts) => createFabricFrameSource(linearGradientFrameSource, opts), 'radial-gradient': async (opts) => createFabricFrameSource(radialGradientFrameSource, opts), 'fill-color': async (opts) => createFabricFrameSource(fillColorFrameSource, opts), + 'news-title': async (opts) => createFabricFrameSource(newsTitleFrameSource, opts), }; const createFrameSourceFunc = frameSourceFuncs[type]; assert(createFrameSourceFunc, `Invalid type ${type}`);