Skip to content

Commit

Permalink
add demos
Browse files Browse the repository at this point in the history
  • Loading branch information
dealfonso committed Mar 1, 2023
1 parent 6adcc6f commit 215f85a
Show file tree
Hide file tree
Showing 3 changed files with 463 additions and 0 deletions.
261 changes: 261 additions & 0 deletions lottietrimmer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Lottie Files Trimming application">
<meta name="author" content="Carlos A.">
<title>Lottie Files trimming application</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.10.2/lottie_svg.js" integrity="sha512-1Sf0VQyouGn2djsiUsLO2FXgMD9WIvyLGSH6kqgjDkgZt665gTVF1EVk5MpPK6UyCsoATfuI9einAmgPYTCbJg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/gh/jsutilslib/nojquery@1/nojquery.min.js"></script>
<script src="js/simplelottieplayer.js"></script>
<script src="js/lottieutils.js"></script>
<style>
html, body {
height: 100%;
}
#dropzone {
width: 500px;
border-style: dashed !important;
border-width: 5px !important;
position: relative;
}
#dropzone input[type=file] {
opacity: 0;
position: absolute; top:0; left:0; bottom: 0; right: 0; width: 100%; height: 100%
}
#original-player {
height: 200px;
width: 200px;
}
#resulting-player {
height: 200px;
width: 200px;
}
.control-buttons {
background-color: #222 !important;
border-radius: 0.375rem;
}
</style>
</head>
<body class="text-center text-bg-dark h-100 d-flex flex-column">
<div class="modal fade" id="progressDialog" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body text-dark">
<h4>analyzing frames</h4>
<div class="progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: 0%"></div>
</div>
<button type="button" class="btn btn-danger mt-3" onclick="cancel()">cancel</button>
</div>
</div>
</div>
</div>
<div class="header w-100">
<div class="mx-3 d-flex px-3 pt-3">
<h1 class="mt-auto">Simple LottieFile Trimmer</h1>
<div class="ms-auto my-auto">
<a class="btn btn-outline-light" href="https://github.com/dealfonso/simplelottieplayer" target="_blank"><i class="bi bi-github pe-2"></i>view in github</a>
</div>
</div>
</div>
<div class="m-auto w-100 d-flex flex-column p-5">
<div class="m-auto">
<div class="text-center w-100">
<p>this is an application to make that an animation downloaded from <a href="https://lottiefiles.com" target="_blank">LottieFiles</a> is trimmed (i.e.) the borders are removed <a href="#info"><sup class="bi bi-info-circle pe-2"></sup></a></p>
<div id="dropzone" class="rounded-5 border border-white m-auto d-flex">
<div class="m-auto p-3">
<h2>add your animation</h2>
<h4>you can drop a file, paste an url or file, or press here to browse for a file</h4>
</div>
<input type="file" >
</div>
<div id="trimming-zone" class="mt-3 d-flex w-100">
<simplelottie id="original-player" class="rounded-2 border border-white ms-auto"
control-buttons css-class-control-buttons="control-buttons" fullsize-button max-height="400" max-width="400"
></simplelottie>
<div id="controls" class="d-flex flex-column me-auto ms-3">
<a id="cropBtn" title="trim lottie animation" href="javascript:executeTrimAnimation();" class="btn btn-outline-light m-auto mx-auto">
<i class="bi bi-crop"></i>
</a>
</div>
<div id="resulting-animation" class="mx-auto my-auto">
<simplelottie id="resulting-player" class="rounded-2 border border-white"
control-buttons css-class-control-buttons="control-buttons" fullsize-button max-height="400" max-width="400"
></simplelottie>
<div class="mt-3">
<a id="download-button" href="#">download</a>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="text-white-50">
<p>&copy; Carlos A. - <a href="https://github.com/dealfonso" target="_blank">https://github.com/dealfonso</a></p>
<p id="info" class="border-top m-3 p-3 small"><i class="bi bi-info-circle pe-2"></i>how this works: the animation's frames are rendered, and the bounding box is calculated for each of them.
Once the bounding box is calculated for the whole animation, the lottie animation is updated by using a <a href="https://lottiefiles.github.io/lottie-docs/layers/#precomposition-layer" target="_blank">precomposition layer</a>
which is adjusted to make that the part shown in the animation is the window that corresponds to the bounding box. Using this method, the shapes are not modified at all and the
animation can be edited in other softwares such as <a href="https://www.adobe.com/es/products/aftereffects.html" target="_blank">Adobe AfterEffects</a></p>
</footer>
</body>
<script>
let animation = null;
let lottiePlayer = null;
let lottiePlayerResult = null;
let filename = null;
let modalDialog = new bootstrap.Modal("#progressDialog");
let progressBar = _$("#progressDialog .progress .progress-bar")[0];
let cancelled = false;

function cancel() {
cancelled = true;
}

const State = {
empty: 0,
animation: 1,
trimmed: 2
}

let state = State.empty;

function updateState(newState) {
state = newState;
_$("#dropzone", "#trimming-zone", "#resulting-animation", "#controls").addClass("d-none");
switch (state) {
case State.animation:
_$("#trimming-zone", "#controls").removeClass("d-none");
break;
case State.trimmed:
_$("#trimming-zone", "#resulting-animation").removeClass("d-none");
break;
default:
_$("#dropzone").removeClass("d-none");
break;
}
}

function loadAnimationFromText(txt, name = "animation") {
let loadedAnimation = null;
try {
loadedAnimation = JSON.parse(txt);
} catch (e) {
throw ("invalid json file")
}
lottiePlayer.load(JSON.parse(JSON.stringify(loadedAnimation))).then(() => {
animation = loadedAnimation;
filename = name;
updateState(State.animation)
})
}

function processFile(file) {
if (file.type != "application/json") {
throw("invalid content-type");
}
let fileReader = new FileReader();
fileReader.onload = (event) => {
loadAnimationFromText(event.target.result, file.name);
}
fileReader.readAsText(file);
}

async function executeTrimAnimation() {
function setProgress(pct) {
progressBar.style.width = `${pct}%`;
}

cancelled = false;
modalDialog.show();
setProgress(0);

function onFrame(frameIndex, _, _, minFrame, maxFrame) {
let pct = 100 * frameIndex / (maxFrame - minFrame);
setProgress(pct);
return !cancelled;
}

lottiePlayer.stop();
let lottiePlayerRender = new MemLottiePlayer();
await lottiePlayerRender.load(JSON.parse(JSON.stringify(animation)));

try {
let boundingBoxes = await LottieUtils.calculateBoundingBox(lottiePlayerRender, animation["ip"], animation["op"], onFrame);
let boundingBox = boundingBoxes["animationBoundingBox"];
let resultingAnimation = LottieUtils.trimAnimation(animation, boundingBox[0], boundingBox[1], boundingBox[2], boundingBox[3]);
lottiePlayerResult.load(JSON.parse(JSON.stringify(resultingAnimation)));
updateState(State.trimmed);


let downloadButton = _$("#download-button")[0];
downloadButton.href = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(resultingAnimation));
downloadButton.setAttribute("download", `trimmed-${filename}`);

modalDialog.hide();
} catch (e) {
console.log("error", e)
modalDialog.hide();
}
}

_$(function() {
lottiePlayer = _$('#original-player')[0].getLottiePlayer();
lottiePlayer.updateOptions({
onPlayBtn: () => {
if (state === State.trimmed) {
lottiePlayerResult.play(lottiePlayer.currentFrame())
}
}
})
lottiePlayerResult = _$('#resulting-player')[0].getLottiePlayer();
lottiePlayerResult.updateOptions({
onPlayBtn: () => {
lottiePlayer.play(lottiePlayerResult.currentFrame());
},
onAnimationLoaded: () => {
lottiePlayer.play(0);
lottiePlayerResult.play(0);
}
});
// Add the mechanisms to load a file
_$("html").droppable( (files) => {
processFile(files[0])
}
).on('paste', (event) => {
let pasteContent = (event.clipboardData || window.clipboardData);

if ((pasteContent.files) && (pasteContent.files.length > 0)) {
processFile(pasteContent.files[0]);
} else {
let pasteText = pasteContent.getData("text");
if (pasteText != "") {
let url = null;
try {
url = new URL(pasteText);
fetch(url).then((content) => {
content.json().then((json) => loadAnimationFromText(JSON.stringify(json)));
})
} catch (e) {
console.log(e);
return;
}
}
}
})
_$('#dropzone input[type=file]').on("change", (event) => {
const fileList = event.target.files;
processFile(fileList[0]);
});

updateState(State.empty);
})
</script>
</html>
Loading

0 comments on commit 215f85a

Please sign in to comment.