Changing Timestamps to use thread_local + Rc + RefCell rather than Arc + Mutex
This commit is contained in:
parent
ed137a5aa1
commit
165fd7e5fa
|
@ -2,11 +2,12 @@
|
|||
extern crate stdweb;
|
||||
#[macro_use]
|
||||
extern crate dominator;
|
||||
#[macro_use]
|
||||
extern crate signals;
|
||||
|
||||
use stdweb::traits::*;
|
||||
use stdweb::web::{document, HtmlElement};
|
||||
use stdweb::web::event::{MouseDownEvent, MouseUpEvent};
|
||||
use stdweb::web::event::{MouseOverEvent, MouseOutEvent};
|
||||
use signals::signal::Signal;
|
||||
use signals::signal_vec::unsync::MutableVec;
|
||||
use dominator::traits::*;
|
||||
|
@ -18,7 +19,7 @@ use dominator::animation::unsync::MutableAnimation;
|
|||
fn make_animated_box<A>(value: u32, t: A) -> Dom where A: Signal<Item = Percentage> + Clone + 'static {
|
||||
let animation = MutableAnimation::new(3000.0);
|
||||
|
||||
let click_animation = MutableAnimation::new(500.0);
|
||||
let hover_animation = MutableAnimation::new(300.0);
|
||||
|
||||
let low: f64 = value as f64;
|
||||
let high: f64 = (value + 60) as f64;
|
||||
|
@ -37,12 +38,12 @@ fn make_animated_box<A>(value: u32, t: A) -> Dom where A: Signal<Item = Percenta
|
|||
Ok(())
|
||||
})));
|
||||
|
||||
event(clone!(click_animation => move |_: MouseDownEvent| {
|
||||
click_animation.animate_to(Percentage::new(1.0));
|
||||
event(clone!(hover_animation => move |_: MouseOverEvent| {
|
||||
hover_animation.animate_to(Percentage::new(1.0));
|
||||
}));
|
||||
|
||||
event(clone!(click_animation => move |_: MouseUpEvent| {
|
||||
click_animation.animate_to(Percentage::new(0.0));
|
||||
event(clone!(hover_animation => move |_: MouseOutEvent| {
|
||||
hover_animation.animate_to(Percentage::new(0.0));
|
||||
}));
|
||||
|
||||
style("border-radius", "10px");
|
||||
|
@ -57,7 +58,7 @@ fn make_animated_box<A>(value: u32, t: A) -> Dom where A: Signal<Item = Percenta
|
|||
style("margin-left", animation.signal()
|
||||
.map(|t| t.invert())
|
||||
.map(|t| easing::in_out(t, easing::cubic))
|
||||
.map(|t| Some(format!("{}px", t.range_inclusive(50.0, 0.0))))
|
||||
.map(|t| Some(format!("{}px", t.range_inclusive(20.0, 0.0))))
|
||||
.dynamic());
|
||||
|
||||
style("left", t.clone()
|
||||
|
@ -65,9 +66,12 @@ fn make_animated_box<A>(value: u32, t: A) -> Dom where A: Signal<Item = Percenta
|
|||
.map(|t| Some(format!("{}px", t.range_inclusive(100.0, 0.0))))
|
||||
.dynamic());
|
||||
|
||||
style("height", t.clone()
|
||||
.map(|t| easing::in_out(t, easing::cubic))
|
||||
.map(|t| Some(format!("{}px", t.range_inclusive(0.0, 5.0))))
|
||||
style("height",
|
||||
map_clone! {
|
||||
let animation = t.clone().map(|t| easing::in_out(t, easing::cubic)),
|
||||
let hover = hover_animation.signal().map(|t| easing::out(t, easing::cubic)) =>
|
||||
Some(format!("{}px", animation.range_inclusive(0.0, hover.range_inclusive(5.0, 15.0))))
|
||||
}
|
||||
.dynamic());
|
||||
|
||||
style("background-color", animation.signal()
|
||||
|
@ -127,21 +131,51 @@ fn main() {
|
|||
color += 10;
|
||||
});
|
||||
|
||||
js! { @(no_return)
|
||||
setInterval(function () {
|
||||
let _timer_id = js!(
|
||||
return setInterval(function () {
|
||||
@{f}();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
dominator::append_dom(&body,
|
||||
Dom::with_state(state, |state| {
|
||||
html!("div", {
|
||||
children(state.boxes.signal_vec()
|
||||
.animated_map(2000.0, |value, t| {
|
||||
make_animated_box(value, t)
|
||||
})
|
||||
.dynamic());
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
/*dominator::append_dom(&body,
|
||||
html!("button", {
|
||||
event(clone!(state => move |_: ClickEvent| {
|
||||
js! { @(no_return)
|
||||
clearInterval(@{&timer_id});
|
||||
}
|
||||
|
||||
state.boxes.clear();
|
||||
}));
|
||||
|
||||
children(&mut [
|
||||
text("Clear all animations")
|
||||
]);
|
||||
})
|
||||
);*/
|
||||
|
||||
for _ in 0..2 {
|
||||
dominator::append_dom(&body,
|
||||
html!("div", {
|
||||
style("display", "flex");
|
||||
|
||||
children(&mut [
|
||||
html!("div", {
|
||||
children(state.boxes.signal_vec()
|
||||
.animated_map(2000.0, |value, t| {
|
||||
make_animated_box(value, t)
|
||||
})
|
||||
.dynamic());
|
||||
}),
|
||||
|
||||
html!("div", {
|
||||
children(state.boxes.signal_vec()
|
||||
.animated_map(2000.0, |value, t| {
|
||||
make_animated_box(value, t)
|
||||
})
|
||||
.dynamic());
|
||||
}),
|
||||
]);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
123
src/animation.rs
123
src/animation.rs
|
@ -1,6 +1,6 @@
|
|||
use self::unsync::MutableAnimation;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use futures::{Async, task};
|
||||
use futures::future::Future;
|
||||
use futures::task::Task;
|
||||
|
@ -48,37 +48,45 @@ impl Drop for Raf {
|
|||
|
||||
struct TimestampsGlobal {
|
||||
raf: Option<Raf>,
|
||||
value: Option<f64>,
|
||||
// TODO make this more efficient
|
||||
states: Vec<Weak<RefCell<TimestampsState>>>,
|
||||
states: Vec<Weak<TimestampsState>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum TimestampsEnum {
|
||||
First,
|
||||
Changed,
|
||||
NotChanged,
|
||||
}
|
||||
|
||||
struct TimestampsState {
|
||||
first: bool,
|
||||
value: Option<f64>,
|
||||
task: Option<Task>,
|
||||
state: Cell<TimestampsEnum>,
|
||||
task: RefCell<Option<Task>>,
|
||||
global: Rc<RefCell<TimestampsGlobal>>,
|
||||
}
|
||||
|
||||
// TODO make this more efficient
|
||||
pub struct Timestamps(Rc<RefCell<TimestampsState>>);
|
||||
pub struct Timestamps(Rc<TimestampsState>);
|
||||
|
||||
impl Signal for Timestamps {
|
||||
type Item = Option<f64>;
|
||||
|
||||
fn poll(&mut self) -> State<Self::Item> {
|
||||
let mut lock = self.0.borrow_mut();
|
||||
|
||||
let value = lock.value.take();
|
||||
|
||||
if lock.first {
|
||||
lock.first = false;
|
||||
State::Changed(value)
|
||||
|
||||
} else if value.is_some() {
|
||||
State::Changed(value)
|
||||
|
||||
} else {
|
||||
lock.task = Some(task::current());
|
||||
State::NotChanged
|
||||
match self.0.state.get() {
|
||||
TimestampsEnum::Changed => {
|
||||
self.0.state.set(TimestampsEnum::NotChanged);
|
||||
// TODO make this more efficient ?
|
||||
State::Changed(self.0.global.borrow().value.clone())
|
||||
},
|
||||
TimestampsEnum::First => {
|
||||
self.0.state.set(TimestampsEnum::NotChanged);
|
||||
State::Changed(None)
|
||||
},
|
||||
TimestampsEnum::NotChanged => {
|
||||
*self.0.task.borrow_mut() = Some(task::current());
|
||||
State::NotChanged
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,56 +94,60 @@ impl Signal for Timestamps {
|
|||
thread_local! {
|
||||
static TIMESTAMPS: Rc<RefCell<TimestampsGlobal>> = Rc::new(RefCell::new(TimestampsGlobal {
|
||||
raf: None,
|
||||
value: None,
|
||||
states: vec![],
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn timestamps() -> Timestamps {
|
||||
let state = Rc::new(RefCell::new(TimestampsState {
|
||||
first: true,
|
||||
value: None,
|
||||
task: None,
|
||||
}));
|
||||
|
||||
TIMESTAMPS.with(|timestamps| {
|
||||
let mut lock = timestamps.borrow_mut();
|
||||
let state = Rc::new(TimestampsState {
|
||||
state: Cell::new(TimestampsEnum::First),
|
||||
task: RefCell::new(None),
|
||||
global: timestamps.clone(),
|
||||
});
|
||||
|
||||
lock.states.push(Rc::downgrade(&state));
|
||||
{
|
||||
let mut lock = timestamps.borrow_mut();
|
||||
|
||||
if let None = lock.raf {
|
||||
let timestamps = timestamps.clone();
|
||||
lock.states.push(Rc::downgrade(&state));
|
||||
|
||||
lock.raf = Some(Raf::new(move |time| {
|
||||
let mut lock = timestamps.borrow_mut();
|
||||
if let None = lock.raf {
|
||||
let timestamps = timestamps.clone();
|
||||
|
||||
lock.states.retain(|state| {
|
||||
if let Some(state) = state.upgrade() {
|
||||
let mut lock = state.borrow_mut();
|
||||
lock.raf = Some(Raf::new(move |time| {
|
||||
let mut lock = timestamps.borrow_mut();
|
||||
|
||||
// TODO it should always poll the most recent time, so this needs to be a has_changed boolean instead
|
||||
lock.value = Some(time);
|
||||
lock.value = Some(time);
|
||||
|
||||
if let Some(task) = lock.task.take() {
|
||||
drop(lock);
|
||||
task.notify();
|
||||
lock.states.retain(|state| {
|
||||
if let Some(state) = state.upgrade() {
|
||||
state.state.set(TimestampsEnum::Changed);
|
||||
|
||||
let mut lock = state.task.borrow_mut();
|
||||
|
||||
if let Some(task) = lock.take() {
|
||||
drop(lock);
|
||||
task.notify();
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
true
|
||||
|
||||
} else {
|
||||
false
|
||||
if lock.states.len() == 0 {
|
||||
lock.raf = None;
|
||||
lock.states = vec![];
|
||||
}
|
||||
});
|
||||
|
||||
if lock.states.len() == 0 {
|
||||
lock.raf = None;
|
||||
lock.states = vec![];
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Timestamps(state)
|
||||
Timestamps(state)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -593,6 +605,11 @@ pub mod easing {
|
|||
powi(p, 3)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn out<F>(p: Percentage, f: F) -> Percentage where F: FnOnce(Percentage) -> Percentage {
|
||||
f(p.invert()).invert()
|
||||
}
|
||||
|
||||
pub fn in_out<F>(p: Percentage, f: F) -> Percentage where F: FnOnce(Percentage) -> Percentage {
|
||||
p.map_unchecked(|p| {
|
||||
if p <= 0.5 {
|
||||
|
|
Loading…
Reference in New Issue