first commit
This commit is contained in:
1
node_modules/lottie-web/test/animations/adrock.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/adrock.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/bacon.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/bacon.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/banner.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/banner.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/bm_ronda.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/bm_ronda.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/bodymovin.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/bodymovin.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/dalek.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/dalek.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/footage/data.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/footage/data.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/footage/images/footage_0.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/footage/images/footage_0.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"lat":33.4418,"lon":-94.0377,"timezone":"America/Chicago","timezone_offset":-18000,"current":{"dt":1616783932,"sunrise":1616760679,"sunset":1616805115,"temp":294.73,"feels_like":291.14,"pressure":1017,"humidity":43,"dew_point":281.63,"uvi":7.02,"clouds":1,"visibility":10000,"wind_speed":4.63,"wind_deg":120,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}]},"minutely":[{"dt":1616783940,"precipitation":0},{"dt":1616784000,"precipitation":0},{"dt":1616784060,"precipitation":0},{"dt":1616784120,"precipitation":0},{"dt":1616784180,"precipitation":0},{"dt":1616784240,"precipitation":0},{"dt":1616784300,"precipitation":0},{"dt":1616784360,"precipitation":0},{"dt":1616784420,"precipitation":0},{"dt":1616784480,"precipitation":0},{"dt":1616784540,"precipitation":0},{"dt":1616784600,"precipitation":0},{"dt":1616784660,"precipitation":0},{"dt":1616784720,"precipitation":0},{"dt":1616784780,"precipitation":0},{"dt":1616784840,"precipitation":0},{"dt":1616784900,"precipitation":0},{"dt":1616784960,"precipitation":0},{"dt":1616785020,"precipitation":0},{"dt":1616785080,"precipitation":0},{"dt":1616785140,"precipitation":0},{"dt":1616785200,"precipitation":0},{"dt":1616785260,"precipitation":0},{"dt":1616785320,"precipitation":0},{"dt":1616785380,"precipitation":0},{"dt":1616785440,"precipitation":0},{"dt":1616785500,"precipitation":0},{"dt":1616785560,"precipitation":0},{"dt":1616785620,"precipitation":0},{"dt":1616785680,"precipitation":0},{"dt":1616785740,"precipitation":0},{"dt":1616785800,"precipitation":0},{"dt":1616785860,"precipitation":0},{"dt":1616785920,"precipitation":0},{"dt":1616785980,"precipitation":0},{"dt":1616786040,"precipitation":0},{"dt":1616786100,"precipitation":0},{"dt":1616786160,"precipitation":0},{"dt":1616786220,"precipitation":0},{"dt":1616786280,"precipitation":0},{"dt":1616786340,"precipitation":0},{"dt":1616786400,"precipitation":0},{"dt":1616786460,"precipitation":0},{"dt":1616786520,"precipitation":0},{"dt":1616786580,"precipitation":0},{"dt":1616786640,"precipitation":0},{"dt":1616786700,"precipitation":0},{"dt":1616786760,"precipitation":0},{"dt":1616786820,"precipitation":0},{"dt":1616786880,"precipitation":0},{"dt":1616786940,"precipitation":0},{"dt":1616787000,"precipitation":0},{"dt":1616787060,"precipitation":0},{"dt":1616787120,"precipitation":0},{"dt":1616787180,"precipitation":0},{"dt":1616787240,"precipitation":0},{"dt":1616787300,"precipitation":0},{"dt":1616787360,"precipitation":0},{"dt":1616787420,"precipitation":0},{"dt":1616787480,"precipitation":0},{"dt":1616787540,"precipitation":0}]}
|
BIN
node_modules/lottie-web/test/animations/footage/images/img_0.jpg
generated
vendored
Normal file
BIN
node_modules/lottie-web/test/animations/footage/images/img_0.jpg
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
node_modules/lottie-web/test/animations/footage/images/img_1.jpg
generated
vendored
Normal file
BIN
node_modules/lottie-web/test/animations/footage/images/img_1.jpg
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 154 KiB |
1
node_modules/lottie-web/test/animations/lights.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/lights.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/monster.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/monster.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/navidad.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/navidad.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/ripple.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/ripple.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/lottie-web/test/animations/starfish.json
generated
vendored
Normal file
1
node_modules/lottie-web/test/animations/starfish.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
100
node_modules/lottie-web/test/index.html
generated
vendored
Normal file
100
node_modules/lottie-web/test/index.html
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body, html{
|
||||
background-color:#fff;
|
||||
margin: 0px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#lottie{
|
||||
background-color:#fff;
|
||||
width:100%;
|
||||
height:100%;
|
||||
display:block;
|
||||
overflow: hidden;
|
||||
transform: translate3d(0,0,0);
|
||||
pointer-events: none;
|
||||
/*display:none;*/
|
||||
}
|
||||
|
||||
</style>
|
||||
<script src="/lottie.min.js" ></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="lottie"></div>
|
||||
<script>
|
||||
const buildRenderSettings = (searchParams) => {
|
||||
const defaultValues = {
|
||||
path: '/test/animations/adrock.json',
|
||||
renderer: 'svg',
|
||||
};
|
||||
searchParams.forEach((value, key) => {
|
||||
defaultValues[key] = value;
|
||||
});
|
||||
|
||||
return defaultValues;
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
const submitAndWaitForResponse = (currentFrame, isLast) => (
|
||||
new Promise((resolve) => {
|
||||
window.onMessageReceivedEvent({
|
||||
currentFrame,
|
||||
isLast,
|
||||
});
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
</script>
|
||||
<script>
|
||||
const waitContinueCommand = () => {
|
||||
return new Promise((resolve) => {
|
||||
window.continueExecution = resolve;
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
|
||||
window.startProcess = () => {
|
||||
const url = new URL(window.location);
|
||||
const settings = buildRenderSettings(url.searchParams)
|
||||
const animation = lottie.loadAnimation({
|
||||
container: document.getElementById('lottie'),
|
||||
path: settings.path,
|
||||
autoplay: false,
|
||||
loop: false,
|
||||
renderer: settings.renderer,
|
||||
})
|
||||
animation.addEventListener('DOMLoaded', async () => {
|
||||
window.onAnimationLoaded();
|
||||
try {
|
||||
let totalFrames = animation.totalFrames;
|
||||
let currentFrame = 0;
|
||||
while (currentFrame <= totalFrames) {
|
||||
await waitContinueCommand();
|
||||
animation.goToAndStop(currentFrame, true);
|
||||
await submitAndWaitForResponse(
|
||||
currentFrame,
|
||||
currentFrame === totalFrames,
|
||||
);
|
||||
currentFrame += 1;
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('ERROR', error.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
// window.startProcess();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
350
node_modules/lottie-web/test/index.js
generated
vendored
Normal file
350
node_modules/lottie-web/test/index.js
generated
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
/**
|
||||
* This traverses all json files located on the examples folder, then iterates
|
||||
* over each file and opens a puppeteer page to a screenshot of all frames
|
||||
* combined in a single page.
|
||||
*/
|
||||
|
||||
const puppeteer = require('puppeteer');
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const { promises: { readFile } } = require('fs');
|
||||
const commandLineArgs = require('command-line-args');
|
||||
const PNG = require('pngjs').PNG;
|
||||
const pixelmatch = require('pixelmatch');
|
||||
|
||||
const examplesDirectory = '/test/animations/';
|
||||
const createDirectory = 'screenshots/create';
|
||||
const compareDirectory = 'screenshots/compare';
|
||||
|
||||
function createDirectoryPath(path) {
|
||||
const directories = path.split('/');
|
||||
directories.reduce((acc, current) => {
|
||||
let dir = acc + '/' + current
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
return dir
|
||||
}, '.')
|
||||
}
|
||||
|
||||
const animations = [
|
||||
{
|
||||
fileName: 'pigeon.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'banner.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'adrock.json',
|
||||
renderer: 'canvas',
|
||||
},
|
||||
{
|
||||
fileName: 'bm_ronda.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'bodymovin.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'bodymovin.json',
|
||||
renderer: 'canvas',
|
||||
},
|
||||
{
|
||||
fileName: 'dalek.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'navidad.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'monster.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'bacon.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'lights.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'ripple.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
fileName: 'starfish.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
{
|
||||
directory: 'footage',
|
||||
fileName: 'data.json',
|
||||
renderer: 'svg',
|
||||
},
|
||||
]
|
||||
|
||||
const getSettings = async () => {
|
||||
const defaultValues = {
|
||||
step: 'create',
|
||||
}
|
||||
const opts = [
|
||||
{
|
||||
name: 'step',
|
||||
alias: 's',
|
||||
type: (val) => {
|
||||
|
||||
return val === 'compare' ? 'compare' : 'create';
|
||||
},
|
||||
description: 'Whether it is the create or the compare step',
|
||||
}
|
||||
];
|
||||
const settings = {
|
||||
...defaultValues,
|
||||
...commandLineArgs(opts),
|
||||
};
|
||||
return settings;
|
||||
};
|
||||
|
||||
const wait = (time) => new Promise((resolve) => setTimeout(resolve, time));
|
||||
|
||||
const filesData = [
|
||||
{
|
||||
path: '/test/index.html',
|
||||
filePath: './test/index.html',
|
||||
type: 'html',
|
||||
},
|
||||
{
|
||||
path: '/lottie.min.js',
|
||||
filePath: './build/player/lottie.min.js',
|
||||
type: 'js',
|
||||
},
|
||||
];
|
||||
|
||||
const getEncoding = (() => {
|
||||
const encodingMap = {
|
||||
js: 'utf8',
|
||||
json: 'utf8',
|
||||
html: 'utf8',
|
||||
};
|
||||
return (fileType) => encodingMap[fileType];
|
||||
})();
|
||||
|
||||
const getContentTypeHeader = (() => {
|
||||
const contentTypeMap = {
|
||||
js: { 'Content-Type': 'application/javascript' },
|
||||
json: { 'Content-Type': 'application/json' },
|
||||
html: { 'Content-Type': 'text/html; charset=utf-8' },
|
||||
wasm: { 'Content-Type': 'application/wasm' },
|
||||
};
|
||||
return (fileType) => contentTypeMap[fileType];
|
||||
})();
|
||||
|
||||
const startServer = async () => {
|
||||
const app = express();
|
||||
await Promise.all(filesData.map(async (file) => {
|
||||
const fileData = await readFile(file.filePath, getEncoding(file.type));
|
||||
app.get(file.path, async (req, res) => {
|
||||
res.writeHead(200, getContentTypeHeader(file.type));
|
||||
// TODO: comment line. Only for live updates.
|
||||
const fileData = await readFile(file.filePath, getEncoding(file.type));
|
||||
res.end(fileData);
|
||||
});
|
||||
return file;
|
||||
}));
|
||||
|
||||
app.get('/*', async (req, res) => {
|
||||
try {
|
||||
if (req.originalUrl.indexOf('.json') !== -1) {
|
||||
const file = await readFile(`.${req.originalUrl}`, 'utf8');
|
||||
res.send(file);
|
||||
} else {
|
||||
const data = await readFile(`.${req.originalUrl}`);
|
||||
res.writeHead(200, { 'Content-Type': 'image/jpeg' });
|
||||
res.end(data);
|
||||
}
|
||||
} catch (err) {
|
||||
res.send('');
|
||||
}
|
||||
});
|
||||
app.listen('9999');
|
||||
};
|
||||
|
||||
const getBrowser = async () => puppeteer.launch({ defaultViewport: null });
|
||||
|
||||
const startPage = async (browser, path, renderer) => {
|
||||
const targetURL = `http://localhost:9999/test/index.html\
|
||||
?path=${encodeURIComponent(path)}&renderer=${renderer}`;
|
||||
const page = await browser.newPage();
|
||||
page.on('console', (msg) => console.log('PAGE LOG:', msg.text())); // eslint-disable-line no-console
|
||||
await page.setViewport({
|
||||
width: 1024,
|
||||
height: 768,
|
||||
});
|
||||
await page.goto(targetURL);
|
||||
return page;
|
||||
};
|
||||
|
||||
const createBridgeHelper = async (page) => {
|
||||
let resolveScoped;
|
||||
let animationLoadedPromise;
|
||||
const messageHandler = (event) => {
|
||||
resolveScoped(event);
|
||||
};
|
||||
const onAnimationLoaded = () => {
|
||||
if (animationLoadedPromise) {
|
||||
animationLoadedPromise()
|
||||
}
|
||||
}
|
||||
await page.exposeFunction('onAnimationLoaded', onAnimationLoaded);
|
||||
await page.exposeFunction('onMessageReceivedEvent', messageHandler);
|
||||
const waitForMessage = () => new Promise((resolve) => {
|
||||
resolveScoped = resolve;
|
||||
});
|
||||
const waitForAnimationLoaded = () => new Promise((resolve) => {
|
||||
animationLoadedPromise = resolve;
|
||||
});
|
||||
const continueExecution = async () => {
|
||||
page.evaluate(() => {
|
||||
window.continueExecution();
|
||||
});
|
||||
};
|
||||
return {
|
||||
waitForAnimationLoaded,
|
||||
waitForMessage,
|
||||
continueExecution,
|
||||
};
|
||||
};
|
||||
|
||||
const compareFiles = (folderName, fileName) => {
|
||||
const createPath = `${createDirectory}/${folderName}/${fileName}`;
|
||||
const comparePath = `${compareDirectory}/${folderName}/${fileName}`;
|
||||
const img1 = PNG.sync.read(fs.readFileSync(createPath));
|
||||
const img2 = PNG.sync.read(fs.readFileSync(comparePath));
|
||||
const {width, height} = img1;
|
||||
const diff = new PNG({width, height});
|
||||
|
||||
const result = pixelmatch(img1.data, img2.data, diff.data, width, height, {threshold: 0.1});
|
||||
// Using 50 as threshold because it should be an acceptable difference
|
||||
// that doesn't raise false positives
|
||||
if (result > 200) {
|
||||
console.log('RESULT NOT ZERO: ', result);
|
||||
throw new Error(`Animation failed: ${folderName} at frame: ${fileName}`)
|
||||
}
|
||||
}
|
||||
|
||||
const createIndividualAssets = async (page, folderName, settings) => {
|
||||
const filePath = `${settings.step === 'create' ? createDirectory : compareDirectory}/${folderName}`;
|
||||
createDirectoryPath(filePath);
|
||||
let isLastFrame = false;
|
||||
const bridgeHelper = await (createBridgeHelper(page));
|
||||
page.evaluate(() => {
|
||||
window.startProcess();
|
||||
});
|
||||
await bridgeHelper.waitForAnimationLoaded();
|
||||
while (!isLastFrame) {
|
||||
// Disabling rule because execution can't be parallelized
|
||||
/* eslint-disable no-await-in-loop */
|
||||
await wait(1);
|
||||
page.evaluate(() => {
|
||||
window.continueExecution();
|
||||
});
|
||||
const message = await bridgeHelper.waitForMessage();
|
||||
const fileNumber = message.currentFrame.toString().padStart(5, '0');
|
||||
const fileName = `image_${fileNumber}.png`;
|
||||
const localDestinationPath = `${filePath}/${fileName}`;
|
||||
await page.screenshot({
|
||||
path: localDestinationPath,
|
||||
fullPage: false,
|
||||
});
|
||||
if (settings.step === 'compare') {
|
||||
try {
|
||||
compareFiles(folderName, fileName);
|
||||
} catch (err) {
|
||||
console.log('FAILED AT FRAME: ', message.currentFrame);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
isLastFrame = message.isLast;
|
||||
}
|
||||
};
|
||||
|
||||
const getDirFiles = async (directory) => (
|
||||
new Promise((resolve, reject) => {
|
||||
fs.readdir(directory, (err, files) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(files);
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
async function processPage(browser, settings, directory, animation) {
|
||||
let fullDirectory = `${directory}`;
|
||||
if (animation.directory) {
|
||||
fullDirectory += `${animation.directory}/`;
|
||||
}
|
||||
const fileName = animation.fileName;
|
||||
const page = await startPage(browser, fullDirectory + fileName, animation.renderer);
|
||||
const fileNameWithoutExtension = fileName.replace(/\.[^/.]+$/, '');
|
||||
let fullName = `${fileNameWithoutExtension}_${animation.renderer}`
|
||||
if (animation.directory) {
|
||||
fullName = `${animation.directory}_` + fullName;
|
||||
}
|
||||
await createIndividualAssets(page, fullName, settings);
|
||||
}
|
||||
|
||||
const iteratePages = async (browser, settings) => {
|
||||
const failedAnimations = [];
|
||||
for (let i = 0; i < animations.length; i += 1) {
|
||||
const animation = animations[i];
|
||||
let fileName = `${animation.renderer}_${animation.fileName}`;
|
||||
if (animation.directory) {
|
||||
fileName = `${animation.directory}_` + fileName;
|
||||
}
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await processPage(browser, settings, examplesDirectory, animation);
|
||||
if (settings.step === 'create') {
|
||||
console.log(`Creating animation: ${fileName}`);
|
||||
}
|
||||
if (settings.step === 'compare') {
|
||||
console.log(`Animation passed: ${fileName}`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (settings.step === 'compare') {
|
||||
failedAnimations.push({
|
||||
fileName: fileName
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failedAnimations.length) {
|
||||
failedAnimations.forEach(animation => {
|
||||
console.log(`Animation failed: ${animation.fileName}`);
|
||||
})
|
||||
throw new Error('Animations failed');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const takeImageStrip = async () => {
|
||||
try {
|
||||
await startServer();
|
||||
const settings = await getSettings();
|
||||
await wait(1);
|
||||
const browser = await getBrowser();
|
||||
await iteratePages(browser, settings);
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
takeImageStrip();
|
Reference in New Issue
Block a user