From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 91B651FF13A for ; Wed, 27 May 2026 11:40:49 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 80BC516521; Wed, 27 May 2026 11:40:47 +0200 (CEST) From: Dominik Csapak To: yew-devel@lists.proxmox.com Subject: [PATCH yew-widget-toolkit] widget: charts: map: update info location if page is scrolled Date: Wed, 27 May 2026 11:37:57 +0200 Message-ID: <20260527094043.1472756-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.049 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record TVD_PH_SUBJ_META1 0.001 Email has a Phishy looking subject line URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [mod.rs] Message-ID-Hash: CYANIQSK2RQPYTQQCJPQAVXLIXGLY5XH X-Message-ID-Hash: CYANIQSK2RQPYTQQCJPQAVXLIXGLY5XH X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Yew framework devel list at Proxmox List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When the map is part of a scrollable container and the info is shown, scrolling the container does not move the info box. To fix that, install a capturing scroll event handler that triggers on all scroll events on the page, and trigger an alignment update of the info box. Signed-off-by: Dominik Csapak --- This is sadly the only way to "fix" this issue and also keep the current behaviour (drawing on top of other elements, etc.) until we can use the anchor positioning api which is (at least partially) implemented in all browsers, but only very recently (~end of last year). src/widget/charts/map/mod.rs | 78 +++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/src/widget/charts/map/mod.rs b/src/widget/charts/map/mod.rs index 330c5fb..39b0c9c 100644 --- a/src/widget/charts/map/mod.rs +++ b/src/widget/charts/map/mod.rs @@ -1,5 +1,8 @@ use std::marker::PhantomData; +use wasm_bindgen::prelude::Closure; +use wasm_bindgen::{JsCast, UnwrapThrowExt}; + mod map_point; pub use map_point::{ MapPointData, PointsRenderArgs, render_info_default, render_point_default, @@ -93,6 +96,7 @@ pub enum Msg { ToggleInfo(usize), CloseInfo, Drag(GestureDragEvent), + UpdateInfoAlignment, } #[derive(PartialEq, Clone)] @@ -117,6 +121,7 @@ pub struct MapComp { // set while a drag is in progress so the trailing synthetic click does not dismiss the info card dragged: bool, clusters: Vec, + scroll_handler: Closure, _phantom_data: PhantomData, } @@ -192,6 +197,39 @@ impl MapComp { } self.clusters = clusters; } + + fn update_info_alignment(&self, ctx: &Context) { + if let (Some(_), Some(anchor), Some(el)) = ( + self.info_visible, + self.info_anchor_ref.get(), + self.info_ref.get(), + ) { + let _ = align_to( + anchor, + el, + Some( + AlignOptions::new( + crate::dom::align::Point::Top, + crate::dom::align::Point::Bottom, + crate::dom::align::GrowDirection::None, + ) + .offset(0.0, ctx.props().info_point_radius * 2.0), + ), + ); + } + } +} + +impl Drop for MapComp { + fn drop(&mut self) { + gloo_utils::document() + .remove_event_listener_with_callback_and_bool( + "scroll", + self.scroll_handler.as_ref().unchecked_ref(), + true, + ) + .unwrap_throw(); + } } impl yew::Component for MapComp { @@ -206,6 +244,22 @@ impl yew::Component for MapComp { 2.0 * props.info_point_radius, ); + let link = ctx.link().clone(); + let scroll_handler = Closure::new(move || { + link.send_message(Msg::UpdateInfoAlignment); + }); + + // capturing event handler, triggers for *all* scroll events on the page + // even unrelated ones, but it's still cheaper than attaching an event handler + // to every ancestor that might scroll + gloo_utils::document() + .add_event_listener_with_callback_and_bool( + "scroll", + scroll_handler.as_ref().unchecked_ref(), + true, + ) + .unwrap_throw(); + let mut this = Self { zoom, pinch_start_scale: 1.0, @@ -220,6 +274,7 @@ impl yew::Component for MapComp { grab_start: None, dragged: false, clusters: Vec::new(), + scroll_handler, _phantom_data: PhantomData::, }; @@ -339,6 +394,10 @@ impl yew::Component for MapComp { } self.info_visible = None; } + Msg::UpdateInfoAlignment => { + self.update_info_alignment(ctx); + return false; + } } true } @@ -564,23 +623,6 @@ impl yew::Component for MapComp { crate::dom::align::Point::TopStart, ); } - if let (Some(_), Some(anchor), Some(el)) = ( - self.info_visible, - self.info_anchor_ref.get(), - self.info_ref.get(), - ) { - let _ = align_to( - anchor, - el, - Some( - AlignOptions::new( - crate::dom::align::Point::Top, - crate::dom::align::Point::Bottom, - crate::dom::align::GrowDirection::None, - ) - .offset(0.0, ctx.props().info_point_radius * 2.0), - ), - ); - } + self.update_info_alignment(ctx); } } -- 2.47.3