@@ -0,0 +1,173 @@
1+use dodrio::bumpalo::{self, Bump};
2+use dodrio::{Node, Render, Vdom};
3+use std::cell::RefCell;
5+use wasm_bindgen::prelude::*;
6+use wasm_bindgen::JsCast;
9+// Triangle container defining target size.
15+ // Construct a new container.
16+ pub fn new() -> Container {
17+ Container { size: 25.0 }
20+ // Generate the container style to fluctuate triangle width.
21+ fn container_transform<'a, 'bump>(&'a self, bump: &'bump Bump, elapsed: f64) -> &'bump str
25+ let t = elapsed % 10.0;
26+ let scale = 0.45 + (if t > 5.0 { 10.0 - t } else { t }) / 40.0;
27+ let transform = bumpalo::format!(
29+ "transform: scaleX({}) scaleY(0.7) translateZ(0.1px)",
32+ transform.into_bump_str()
35+ // Generate the dot's position on the grid.
36+ fn dot_style<'a, 'bump>(&'a self, bump: &'bump Bump, x: f64, y: f64) -> &'bump str
40+ let s = self.size * 1.3;
41+ let radius = s / 2.0;
42+ let styles = bumpalo::format!(
52+ s, s, x, y, radius, s
54+ styles.into_bump_str()
57+ // Create a dot node.
58+ fn dot<'a, 'bump>(&'a self, bump: &'bump Bump, x: f64, y: f64, content: u32) -> Node<'bump>
62+ use dodrio::builder::{div, text};
65+ .attr("class", "dot")
66+ .attr("style", self.dot_style(bump, x, y))
68+ bumpalo::format!(in bump, "{}", content).into_bump_str(),
73+ // Create a flattened vector of dot nodes (arranged in recursive triangles)
74+ fn triangle<'a, 'bump>(
81+ children: &mut bumpalo::collections::Vec<Node<'bump>>,
86+ children.push(self.dot(bump, x, y, content));
93+ self.triangle(bump, x, y - (s / 2.0), s, content, children);
94+ // Bottom-left of triangle
95+ self.triangle(bump, x - s, y + (s / 2.0), s, content, children);
96+ // Bottom-right of triangle
97+ self.triangle(bump, x + s, y + (s / 2.0), s, content, children);
101+impl Render for Container {
102+ fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
106+ use dodrio::builder::div;
108+ let elapsed = web_sys::window()
115+ let modulus = elapsed as u32 % 10;
117+ let mut children = bumpalo::collections::Vec::new_in(bump);
118+ self.triangle(bump, 0.0, 0.0, 1000.0, modulus, &mut children);
121+ .attr("class", "container")
122+ .attr("style", self.container_transform(bump, elapsed))
128+// Kick off a loop that keeps re-rendering on every animation frame.
129+fn animate(window: Window, vdom: Vdom) {
130+ let rc: Rc<RefCell<Option<Closure<FnMut()>>>> = Rc::new(RefCell::new(None));
131+ let rc2 = rc.clone();
132+ let window2 = window.clone();
133+ let weak = vdom.weak();
134+ let f = Closure::wrap(Box::new(move || {
135+ weak.schedule_render();
137+ .request_animation_frame(
142+ .unchecked_ref::<js_sys::Function>(),
145+ }) as Box<FnMut()>);
147+ .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
149+ *rc2.borrow_mut() = Some(f);
151+ // Run the virtual DOM and its listeners forever.
155+#[wasm_bindgen(start)]
157+ // Set up the panic hook
158+ console_error_panic_hook::set_once();
160+ // Get the scene element to render within
161+ let window = web_sys::window().unwrap();
162+ let document = window.document().unwrap();
163+ let scene = document.get_element_by_id("scene").unwrap();
165+ // Construct a new Container component.
166+ let container = Container::new();
168+ // Mount our container component to the scene div.
169+ let vdom = Vdom::new(&scene, container);
171+ // Kick off animation loop
172+ animate(window, vdom);