From 47ef5407a95a473cea1ea5d26582b27b06e14640 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Mon, 4 Sep 2023 13:32:47 -0700 Subject: [PATCH 1/3] Add start/stop events and EMA smoothing to the bridge perf core --- examples/bridge_echo/shared/src/app.rs | 164 ++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/examples/bridge_echo/shared/src/app.rs b/examples/bridge_echo/shared/src/app.rs index 0fbe857a5..43d9e835f 100644 --- a/examples/bridge_echo/shared/src/app.rs +++ b/examples/bridge_echo/shared/src/app.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + // ANCHOR: app use crux_core::render::Render; use crux_macros::Effect; @@ -5,14 +7,20 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug)] pub enum Event { + Start(usize), + Stop, Tick, NewPeriod, } +const EMA_ALPHA: f64 = 0.2; // TODO tune! + #[derive(Default, Debug, PartialEq)] pub struct Model { + sample_period: Option, log: Vec, count: usize, + rate: f64, // per second } #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] @@ -38,9 +46,48 @@ impl crux_core::App for App { fn update(&self, event: Self::Event, model: &mut Self::Model, caps: &Self::Capabilities) { match event { - Event::Tick => model.count += 1, + Event::Start(msecs) => { + if model.sample_period.is_some() { + return; + } + + model.count = 0; + model.rate = 0.0; + model.log = vec![]; + model.sample_period = Some(Duration::from_millis(msecs as u64)); + } + Event::Stop => { + if model.sample_period.is_none() { + return; + } + + model.sample_period = None; + } + Event::Tick => { + if model.sample_period.is_none() { + return; + } + + model.count += 1 + } Event::NewPeriod => { - model.log.push(model.count); + let Some(period_duration) = model.sample_period else { + return; + }; + + // Normalise count to 'per second' scale + let count_per_second = + model.count as f64 * (1000.0 / period_duration.as_millis() as f64); + + model.log.push(count_per_second as usize); + + // Filter with an exponential moving average + model.rate = if model.rate > 0.0 { + model.rate * (1.0 - EMA_ALPHA) + EMA_ALPHA * count_per_second + } else { + count_per_second + }; + model.count = 0; } }; @@ -61,6 +108,94 @@ mod test { use super::*; use crux_core::{assert_effect, testing::AppTester}; + #[test] + fn start_resets_everything() { + let app = AppTester::::default(); + let mut model = Model { + sample_period: None, + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + app.update(Event::Start(1000), &mut model); + + let expected = Model { + sample_period: Some(Duration::from_millis(1000)), + log: vec![], + count: 0, + rate: 0.0, + }; + + assert_eq!(model, expected); + } + + #[test] + fn start_does_nothing_when_already_running() { + let app = AppTester::::default(); + let mut model = Model { + sample_period: Some(Duration::from_millis(300)), + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + app.update(Event::Start(1000), &mut model); + + let expected = Model { + sample_period: Some(Duration::from_millis(300)), + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + assert_eq!(model, expected); + } + + #[test] + fn stop_resets_sample_period() { + let app = AppTester::::default(); + let mut model = Model { + sample_period: Some(Duration::from_millis(300)), + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + app.update(Event::Stop, &mut model); + + let expected = Model { + sample_period: None, + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + assert_eq!(model, expected); + } + + #[test] + fn stop_does_nothing_when_not_running() { + let app = AppTester::::default(); + let mut model = Model { + sample_period: None, + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + app.update(Event::Stop, &mut model); + + let expected = Model { + sample_period: None, + log: vec![20, 23, 42], + count: 57, + rate: 45.0, + }; + + assert_eq!(model, expected); + } + #[test] fn shows_initial_count() { let app = AppTester::::default(); @@ -73,10 +208,11 @@ mod test { } #[test] - fn increments_count() { + fn increments_count_when_running() { let app = AppTester::::default(); let mut model = Model::default(); + app.update(Event::Start(500), &mut model); app.update(Event::Tick, &mut model); app.update(Event::Tick, &mut model); app.update(Event::Tick, &mut model); @@ -87,11 +223,27 @@ mod test { assert_eq!(actual_view, expected_view); } + #[test] + fn ignores_tick_when_not_running() { + let app = AppTester::::default(); + let mut model = Model::default(); + + app.update(Event::Tick, &mut model); + app.update(Event::Tick, &mut model); + app.update(Event::Tick, &mut model); + + let actual_view = app.view(&model); + let expected_view = ViewModel { count: 0 }; + + assert_eq!(actual_view, expected_view); + } + #[test] fn logs_previous_counts() { let app = AppTester::::default(); let mut model = Model::default(); + app.update(Event::Start(200), &mut model); app.update(Event::Tick, &mut model); app.update(Event::Tick, &mut model); app.update(Event::Tick, &mut model); @@ -102,8 +254,10 @@ mod test { app.update(Event::Tick, &mut model); let expected = Model { - log: vec![3, 2], + sample_period: Some(Duration::from_millis(200)), + log: vec![15, 10], count: 1, + rate: 15.0 * (1.0 - EMA_ALPHA) + 10.0 * EMA_ALPHA, }; assert_eq!(model, expected); } @@ -113,6 +267,7 @@ mod test { let app = AppTester::::default(); let mut model = Model::default(); + app.update(Event::Start(500), &mut model); let update = app.update(Event::Tick, &mut model); assert_effect!(update, Effect::Render(_)); @@ -123,6 +278,7 @@ mod test { let app = AppTester::::default(); let mut model = Model::default(); + app.update(Event::Start(500), &mut model); let update = app.update(Event::NewPeriod, &mut model); assert_effect!(update, Effect::Render(_)); From cfd7676b49d40875bf5d90ccb8ee111498b69614 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Mon, 4 Sep 2023 18:21:44 -0700 Subject: [PATCH 2/3] Update ViewModel and Leptos shell --- examples/bridge_echo/shared/src/app.rs | 26 ++++++++++-- examples/bridge_echo/web-leptos/index.html | 13 +++--- examples/bridge_echo/web-leptos/src/main.rs | 47 +++++++++++++++------ 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/examples/bridge_echo/shared/src/app.rs b/examples/bridge_echo/shared/src/app.rs index 43d9e835f..b32827ed0 100644 --- a/examples/bridge_echo/shared/src/app.rs +++ b/examples/bridge_echo/shared/src/app.rs @@ -26,6 +26,8 @@ pub struct Model { #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub struct ViewModel { pub count: usize, + pub rate: f64, + pub running: bool, } #[cfg_attr(feature = "typegen", derive(crux_macros::Export))] @@ -96,7 +98,11 @@ impl crux_core::App for App { } fn view(&self, model: &Self::Model) -> Self::ViewModel { - ViewModel { count: model.count } + ViewModel { + count: model.count, + rate: model.rate, + running: model.sample_period.is_some(), + } } } // ANCHOR_END: impl_app @@ -202,7 +208,11 @@ mod test { let model = Model::default(); let actual_view = app.view(&model); - let expected_view = ViewModel { count: 0 }; + let expected_view = ViewModel { + count: 0, + rate: 0.0, + running: false, + }; assert_eq!(actual_view, expected_view); } @@ -218,7 +228,11 @@ mod test { app.update(Event::Tick, &mut model); let actual_view = app.view(&model); - let expected_view = ViewModel { count: 3 }; + let expected_view = ViewModel { + count: 3, + rate: 0.0, + running: true, + }; assert_eq!(actual_view, expected_view); } @@ -233,7 +247,11 @@ mod test { app.update(Event::Tick, &mut model); let actual_view = app.view(&model); - let expected_view = ViewModel { count: 0 }; + let expected_view = ViewModel { + count: 0, + rate: 0.0, + running: false, + }; assert_eq!(actual_view, expected_view); } diff --git a/examples/bridge_echo/web-leptos/index.html b/examples/bridge_echo/web-leptos/index.html index 8368d02e5..936986547 100644 --- a/examples/bridge_echo/web-leptos/index.html +++ b/examples/bridge_echo/web-leptos/index.html @@ -1,11 +1,14 @@ - + + - Leptos Counter + Leptos Bridge Benchmark - - - + + + + + diff --git a/examples/bridge_echo/web-leptos/src/main.rs b/examples/bridge_echo/web-leptos/src/main.rs index 69df9a814..62573ff59 100644 --- a/examples/bridge_echo/web-leptos/src/main.rs +++ b/examples/bridge_echo/web-leptos/src/main.rs @@ -4,11 +4,13 @@ use std::time::Duration; use leptos::{ component, create_effect, create_signal, set_timeout, view, IntoView, Scope, SignalGet, - SignalSet, SignalUpdate, + SignalGetUntracked, SignalSet, SignalUpdate, }; use shared::Event; +const PERIOD: u64 = 1000; + #[component] fn RootComponent(cx: Scope) -> impl IntoView { let core = core::new(); @@ -20,27 +22,46 @@ fn RootComponent(cx: Scope) -> impl IntoView { core::update(&core, event.get(), render); }); - // When render happens, send a new tick immediately + // When render happens, send a new tick immediately, if running create_effect(cx, move |_| { - view.get(); - set_timeout(move || set_event.set(Event::Tick), Duration::from_millis(0)); + if view.get().running { + set_timeout(move || set_event.set(Event::Tick), Duration::from_millis(0)); + } }); // Start a new period every second create_effect(cx, move |_| { clock.get(); - set_timeout( - move || { - set_event.set(Event::NewPeriod); - set_clock.update(|c| *c += 1); - }, - Duration::from_millis(1000), - ) + if view.get_untracked().running { + set_timeout( + move || { + set_event.set(Event::NewPeriod); + set_clock.update(|c| *c += 1); + }, + Duration::from_millis(PERIOD), + ) + } }); view! {cx, -
-

{move || view.get().count}

+
+
+

{move || format!("{:.2}", view.get().rate)}

+

{move || view.get().count}

+

+ +

+
} } From e244caad2e403ebe8e54600ffeddab7a6ab63233 Mon Sep 17 00:00:00 2001 From: Viktor Charypar Date: Mon, 4 Sep 2023 19:19:32 -0700 Subject: [PATCH 3/3] Crud chart display in Leptos --- examples/bridge_echo/Cargo.lock | 226 +++++++++++++++++++- examples/bridge_echo/shared/src/app.rs | 5 + examples/bridge_echo/web-leptos/Cargo.toml | 1 + examples/bridge_echo/web-leptos/src/main.rs | 28 +++ 4 files changed, 254 insertions(+), 6 deletions(-) diff --git a/examples/bridge_echo/Cargo.lock b/examples/bridge_echo/Cargo.lock index a3ccc2622..432626740 100644 --- a/examples/bridge_echo/Cargo.lock +++ b/examples/bridge_echo/Cargo.lock @@ -146,6 +146,15 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f768393e7fabd388fe8409b13faa4d93ab0fef35db1508438dfdb066918bcf38" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "askama" version = "0.12.0" @@ -471,6 +480,12 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "bytes" version = "0.5.6" @@ -530,6 +545,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +dependencies = [ + "num-traits", +] + [[package]] name = "ciborium" version = "0.2.1" @@ -1038,6 +1062,12 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "1.9.0" @@ -1684,6 +1714,17 @@ dependencies = [ "typed-builder", ] +[[package]] +name = "leptos_chart" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fead51e104614563b9b1f952e0489da0ea40160ec7f58a4b5f58a641b69de171" +dependencies = [ + "leptos", + "log", + "theta-chart", +] + [[package]] name = "leptos_config" version = "0.4.8" @@ -1882,6 +1923,16 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1930,6 +1981,33 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nalgebra" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "nom" version = "7.1.3" @@ -1961,6 +2039,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1971,6 +2058,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -2051,6 +2149,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63" +[[package]] +name = "palette" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e2f34147767aa758aa649415b50a69eeb46a67f9dc7db8011eeb3d84b351dc" +dependencies = [ + "approx", + "fast-srgb8", + "palette_derive", + "phf 0.11.2", +] + +[[package]] +name = "palette_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7db010ec5ff3d4385e4f133916faacd9dad0f6a09394c92d825b3aed310fa0a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "parking" version = "2.1.0" @@ -2148,18 +2269,38 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ - "phf_macros", - "phf_shared", + "phf_macros 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros 0.11.2", + "phf_shared 0.11.2", +] + [[package]] name = "phf_generator" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_shared", + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", "rand 0.8.5", ] @@ -2169,14 +2310,27 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "phf_shared" version = "0.10.0" @@ -2186,6 +2340,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -2428,6 +2591,12 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "redox_syscall" version = "0.3.5" @@ -2613,6 +2782,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -2704,7 +2882,7 @@ checksum = "f8c9331265d81c61212dc75df7b0836544ed8e32dba77a522f113805ff9a948e" dependencies = [ "heck 0.3.3", "include_dir", - "phf", + "phf 0.10.1", "serde", "serde-reflection", "textwrap", @@ -2925,6 +3103,19 @@ dependencies = [ "libc", ] +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -3145,6 +3336,18 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "theta-chart" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1c58ed53cc331cbf490d4ba183b9941361c6765a20cadb473dac9c59fb5b5" +dependencies = [ + "approx", + "chrono", + "nalgebra", + "palette", +] + [[package]] name = "thiserror" version = "1.0.45" @@ -3740,6 +3943,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "leptos", + "leptos_chart", "log", "shared", ] @@ -3763,6 +3967,16 @@ dependencies = [ "nom", ] +[[package]] +name = "wide" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/examples/bridge_echo/shared/src/app.rs b/examples/bridge_echo/shared/src/app.rs index b32827ed0..bd0461bca 100644 --- a/examples/bridge_echo/shared/src/app.rs +++ b/examples/bridge_echo/shared/src/app.rs @@ -27,6 +27,7 @@ pub struct Model { pub struct ViewModel { pub count: usize, pub rate: f64, + pub log: Vec, pub running: bool, } @@ -101,6 +102,7 @@ impl crux_core::App for App { ViewModel { count: model.count, rate: model.rate, + log: model.log.clone(), running: model.sample_period.is_some(), } } @@ -211,6 +213,7 @@ mod test { let expected_view = ViewModel { count: 0, rate: 0.0, + log: vec![], running: false, }; @@ -231,6 +234,7 @@ mod test { let expected_view = ViewModel { count: 3, rate: 0.0, + log: vec![], running: true, }; @@ -250,6 +254,7 @@ mod test { let expected_view = ViewModel { count: 0, rate: 0.0, + log: vec![], running: false, }; diff --git a/examples/bridge_echo/web-leptos/Cargo.toml b/examples/bridge_echo/web-leptos/Cargo.toml index caabc6a14..2b606cd63 100644 --- a/examples/bridge_echo/web-leptos/Cargo.toml +++ b/examples/bridge_echo/web-leptos/Cargo.toml @@ -7,5 +7,6 @@ edition = "2021" console_error_panic_hook = "0.1.7" console_log = "1.0.0" leptos = { version = "0.4.8", features = ["csr"] } +leptos_chart = {version = "0.1.0", features = ["LineChart"]} log = "0.4.20" shared = { path = "../shared" } diff --git a/examples/bridge_echo/web-leptos/src/main.rs b/examples/bridge_echo/web-leptos/src/main.rs index 62573ff59..9e96103f0 100644 --- a/examples/bridge_echo/web-leptos/src/main.rs +++ b/examples/bridge_echo/web-leptos/src/main.rs @@ -7,6 +7,7 @@ use leptos::{ SignalGetUntracked, SignalSet, SignalUpdate, }; +use leptos_chart::{Cartesian, LineChart, Series}; use shared::Event; const PERIOD: u64 = 1000; @@ -43,6 +44,28 @@ fn RootComponent(cx: Scope) -> impl IntoView { } }); + let chart = move || { + clock.get(); + + let log: Vec<_> = view.get_untracked().log; + + let count = log.len() as i64; + let max = *log.iter().max().unwrap_or(&0); + + let (x, y) = if count > 0 { + ( + (1..=count).collect::>(), + log.iter().map(|i| *i as f64).collect::>(), + ) + } else { + (vec![0, 1], vec![0.0, 1.0]) + }; + + log::debug!("Chart: {:?}, {:?}", x, y); + + Cartesian::new(Series::from(x), Series::from(y)).set_view(420, 380, 3, 100, 100, 20) + }; + view! {cx,
@@ -62,6 +85,11 @@ fn RootComponent(cx: Scope) -> impl IntoView {

+ {move || { + let chart = chart(); + + view! {cx, } + }}
} }