Skip to content

Commit

Permalink
fix: 🐛 resume playing from the current_frame after pause (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
theashraf authored Jan 25, 2024
1 parent 31599a1 commit 668ee6c
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 18 deletions.
3 changes: 1 addition & 2 deletions dotlottie-ffi/emscripten_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,5 @@ EMSCRIPTEN_BINDINGS(DotLottiePlayer)
.function("setConfig", &DotLottiePlayer::set_config)
.function("setFrame", &DotLottiePlayer::set_frame)
.function("stop", &DotLottiePlayer::stop)
.function("totalFrames", &DotLottiePlayer::total_frames)
.function("setBackgroundColor", &DotLottiePlayer::set_background_color);
.function("totalFrames", &DotLottiePlayer::total_frames);
}
1 change: 0 additions & 1 deletion dotlottie-ffi/src/dotlottie_player.udl
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,4 @@ interface DotLottiePlayer {
boolean render();
boolean resize(u32 width, u32 height);
void clear();
boolean set_background_color(u32 hex_color);
};
30 changes: 27 additions & 3 deletions dotlottie-rs/src/dotlottie_player.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use instant::Instant;
use instant::{Duration, Instant};
use std::sync::RwLock;

use dotlottie_fms::{DotLottieError, DotLottieManager, Manifest, ManifestAnimation};
Expand Down Expand Up @@ -116,9 +116,33 @@ impl DotLottieRuntime {

pub fn play(&mut self) -> bool {
if self.is_loaded && !self.is_playing() {
self.playback_state = PlaybackState::Playing;
self.start_time = Instant::now();
if self.is_paused() {
let start_frame = self.start_frame();
let end_frame = self.end_frame();

let total_frames = self.total_frames();
let duration = self.duration();
let effective_total_frames = end_frame - start_frame;
let effective_duration =
(duration * effective_total_frames / total_frames) / self.config.speed;

let current_frame = self.current_frame().clamp(start_frame, end_frame);
let frame_duration = effective_duration / effective_total_frames;

// estimate elapsed time for current frame based on direction and segments
let elapsed_time_for_current_frame = match self.direction {
Direction::Forward => (current_frame - start_frame) * frame_duration,
Direction::Reverse => (end_frame - current_frame) * frame_duration,
};

// update start_time to account for the already elapsed time
self.start_time =
Instant::now() - Duration::from_secs_f32(elapsed_time_for_current_frame);
} else {
self.start_time = Instant::now();
}

self.playback_state = PlaybackState::Playing;
true
} else {
false
Expand Down
60 changes: 48 additions & 12 deletions web-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,25 @@
</head>
<body>
<div style="max-width: 500px">
<canvas style="width: 100%"></canvas>
<canvas style="width: 100%; border: 1px solid black"></canvas>
<button id="play">play</button>
<button id="pause">pause</button>
<input
id="progress-bar"
type="range"
min="0"
max="100"
defaultValue="0"
step="0.01"
/>
</div>
<script type="module">
import createDotLottiePlayerModule from "./release/wasm/DotLottiePlayer.mjs";

const playBtn = document.querySelector("#play");
const pauseBtn = document.querySelector("#pause");
const progressBar = document.querySelector("#progress-bar");

const Module = await createDotLottiePlayerModule({
locateFile: (path, prefix) => {
if (path.endsWith(".wasm")) {
Expand All @@ -24,7 +38,7 @@
function createSegments(startFrame, endFrame) {
const vector = new Module.VectorFloat();

if (startFrame && endFrame) {
if (typeof startFrame === "number" && typeof endFrame === "number") {
vector.push_back(startFrame);
vector.push_back(endFrame);
}
Expand All @@ -39,7 +53,7 @@
speed: 1,
useFrameInterpolation: true,
segments: createSegments(0, 40),
backgroundColor: 0x9afafa8f,
backgroundColor: 0x000000,
});

// const data = await fetch(
Expand All @@ -65,11 +79,17 @@
// const loaded = dotLottiePlayer.loadAnimationData(data, width, height);
const loaded = dotLottiePlayer.loadDotLottieData(data, width, height);

dotLottiePlayer.setConfig({
...dotLottiePlayer.config(),
mode: Module.Mode.values[3],
segments: createSegments(20, 80),
});

console.log("Loaded: ", loaded);

const manifest = JSON.parse(dotLottiePlayer.manifestString());
const animationId = manifest.animations[2].id;
dotLottiePlayer.loadAnimation(animationId, width, height);
// const manifest = JSON.parse(dotLottiePlayer.manifestString());
// const animationId = manifest.animations[2].id;
// dotLottiePlayer.loadAnimation(animationId, width, height);

// dotLottiePlayer.setBackgroundColor(0x9afafa8f);

Expand All @@ -79,19 +99,35 @@
function animationLoop() {
const nextFrameNumber = dotLottiePlayer.requestFrame();
// console.log(nextFrameNumber);
dotLottiePlayer.setFrame(nextFrameNumber);
const rendered = dotLottiePlayer.render();

if (rendered) {
const frameBuffer = dotLottiePlayer.buffer();
imageData.data.set(frameBuffer);
ctx.putImageData(imageData, 0, 0);
const updated = dotLottiePlayer.setFrame(nextFrameNumber);

if (updated) {
progressBar.value =
(dotLottiePlayer.currentFrame() / dotLottiePlayer.totalFrames()) *
100;

const rendered = dotLottiePlayer.render();

if (rendered) {
const frameBuffer = dotLottiePlayer.buffer();
imageData.data.set(frameBuffer);
ctx.putImageData(imageData, 0, 0);
}
}

requestAnimationFrame(animationLoop);
}

requestAnimationFrame(animationLoop);

playBtn.addEventListener("click", () => {
dotLottiePlayer.play();
});

pauseBtn.addEventListener("click", () => {
dotLottiePlayer.pause();
});
</script>
</body>
</html>

0 comments on commit 668ee6c

Please sign in to comment.