Implement showing color on mouse hover.
This commit is contained in:
parent
c4140a0618
commit
9b31cb88d4
@ -8,6 +8,9 @@
|
|||||||
<link rel="modulepreload" href="/pkg/package.js" as="script" type="text/javascript">
|
<link rel="modulepreload" href="/pkg/package.js" as="script" type="text/javascript">
|
||||||
<link rel="preload" href="/pkg/package_bg.wasm" as="fetch" type="application/wasm" crossorigin="anonymous">
|
<link rel="preload" href="/pkg/package_bg.wasm" as="fetch" type="application/wasm" crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://jenil.github.io/bulmaswatch/cyborg/bulmaswatch.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" integrity="sha512-SzlrxWUlpfuzQ+pcUCosxcglQRNAq/DZjVsC0lE40xsADsfeQoEypE+enwcOiGjk/bSuGGKHEyjSoQ1zVisanQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
<link data-trunk rel="css" href="index.css" />
|
<link data-trunk rel="css" href="index.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
299
src/lib.rs
299
src/lib.rs
@ -3,14 +3,17 @@
|
|||||||
// but some rules are too "annoying" or are not applicable for your case.)
|
// but some rules are too "annoying" or are not applicable for your case.)
|
||||||
#![allow(clippy::wildcard_imports)]
|
#![allow(clippy::wildcard_imports)]
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use chrono::{Local, NaiveDateTime, TimeZone};
|
use chrono::{Local, NaiveDateTime, TimeZone};
|
||||||
use log::{info, Level};
|
use log::{info, Level};
|
||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasm_timer::{SystemTime, UNIX_EPOCH};
|
use wasm_timer::{SystemTime, UNIX_EPOCH};
|
||||||
use web_sys::{ContextAttributes2d, HtmlCanvasElement, HtmlImageElement};
|
use web_sys::{ContextAttributes2d, Event, HtmlCanvasElement, HtmlImageElement};
|
||||||
|
|
||||||
const ROOT_URL: &'static str = "/www/tracer";
|
const ROOT_URL: &'static str = "/www/tracer";
|
||||||
|
|
||||||
@ -38,6 +41,8 @@ fn init(_: Url, orders: &mut impl Orders<Msg>) -> Model {
|
|||||||
image_ref: ElRef::<HtmlImageElement>::default(),
|
image_ref: ElRef::<HtmlImageElement>::default(),
|
||||||
zoom: 1.0,
|
zoom: 1.0,
|
||||||
offset: [0., 0.],
|
offset: [0., 0.],
|
||||||
|
current_image_idx: None,
|
||||||
|
mouse_position: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +59,8 @@ struct Model {
|
|||||||
image_ref: ElRef<HtmlImageElement>,
|
image_ref: ElRef<HtmlImageElement>,
|
||||||
zoom: f64,
|
zoom: f64,
|
||||||
offset: [f64; 2],
|
offset: [f64; 2],
|
||||||
|
current_image_idx: Option<usize>,
|
||||||
|
mouse_position: Option<(i32, i32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ ------
|
// ------ ------
|
||||||
@ -67,11 +74,11 @@ enum Msg {
|
|||||||
OnError(AppError),
|
OnError(AppError),
|
||||||
Rendered,
|
Rendered,
|
||||||
Received(Data),
|
Received(Data),
|
||||||
Reset,
|
|
||||||
SetZoom(f64, [i32; 2]),
|
SetZoom(f64, [i32; 2]),
|
||||||
Zoom(f64, [i32; 2]),
|
Zoom(f64, [i32; 2]),
|
||||||
Move([f64; 2]),
|
Move([f64; 2]),
|
||||||
UrlChanged(subs::UrlChanged),
|
UrlChanged(subs::UrlChanged),
|
||||||
|
SetMousePosition(i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
// `update` describes how to handle each `Msg`.
|
// `update` describes how to handle each `Msg`.
|
||||||
@ -127,10 +134,6 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
// TODO(wathiede): can this be done less often?
|
// TODO(wathiede): can this be done less often?
|
||||||
orders.after_next_render(|_| Msg::Rendered).skip();
|
orders.after_next_render(|_| Msg::Rendered).skip();
|
||||||
}
|
}
|
||||||
Msg::Reset => {
|
|
||||||
model.zoom = 1.;
|
|
||||||
model.offset = [0., 0.];
|
|
||||||
}
|
|
||||||
Msg::SetZoom(scale, offset) => {
|
Msg::SetZoom(scale, offset) => {
|
||||||
if scale < 0.1 {
|
if scale < 0.1 {
|
||||||
model.zoom = 0.1;
|
model.zoom = 0.1;
|
||||||
@ -157,6 +160,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
Msg::UrlChanged(subs::UrlChanged(url)) => {
|
Msg::UrlChanged(subs::UrlChanged(url)) => {
|
||||||
info!("url changed {}", url);
|
info!("url changed {}", url);
|
||||||
}
|
}
|
||||||
|
Msg::SetMousePosition(x, y) => model.mouse_position = Some((x, y)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -199,17 +203,30 @@ pub enum ImageType {
|
|||||||
// ------ ------
|
// ------ ------
|
||||||
// View
|
// View
|
||||||
// ------ ------
|
// ------ ------
|
||||||
fn view_metadata_table(data: &Data) -> Node<Msg> {
|
fn row<T>(name: &str, value: T) -> Node<Msg>
|
||||||
fn row<T>(name: &str, value: T) -> Node<Msg>
|
where
|
||||||
where
|
T: Any + std::fmt::Debug,
|
||||||
T: std::fmt::Debug,
|
{
|
||||||
{
|
let value_any = &value as &dyn Any;
|
||||||
let mut v = format!("{:?}", value);
|
let t_string = TypeId::of::<String>();
|
||||||
if &v == "None" {
|
let t_f32 = TypeId::of::<f32>();
|
||||||
v = "❌".to_string();
|
let t_f64 = TypeId::of::<f64>();
|
||||||
}
|
let t_t = TypeId::of::<T>();
|
||||||
tr![td![name], td![v]]
|
let mut v = if t_t == t_string {
|
||||||
|
format!("{}", value_any.downcast_ref::<String>().unwrap())
|
||||||
|
} else if t_t == t_f32 {
|
||||||
|
format!("{:.2}", value_any.downcast_ref::<f32>().unwrap())
|
||||||
|
} else if t_t == t_f64 {
|
||||||
|
format!("{:.2}", value_any.downcast_ref::<f64>().unwrap())
|
||||||
|
} else {
|
||||||
|
format!("{value:?}")
|
||||||
|
};
|
||||||
|
if &v == "None" {
|
||||||
|
v = "❌".to_string();
|
||||||
}
|
}
|
||||||
|
tr![td![name], td![C!["has-text-right"], v]]
|
||||||
|
}
|
||||||
|
fn view_metadata_table(data: &Data) -> Vec<Node<Msg>> {
|
||||||
//❌
|
//❌
|
||||||
//✔️
|
//✔️
|
||||||
let d = SystemTime::now()
|
let d = SystemTime::now()
|
||||||
@ -223,26 +240,32 @@ fn view_metadata_table(data: &Data) -> Node<Msg> {
|
|||||||
let dt = NaiveDateTime::from_timestamp_opt(data.timestamp, 0).unwrap();
|
let dt = NaiveDateTime::from_timestamp_opt(data.timestamp, 0).unwrap();
|
||||||
let dt = Local.from_local_datetime(&dt).unwrap();
|
let dt = Local.from_local_datetime(&dt).unwrap();
|
||||||
let rendered_at = dt.format("%Y-%m-%d %H:%M:%S").to_string();
|
let rendered_at = dt.format("%Y-%m-%d %H:%M:%S").to_string();
|
||||||
div![
|
/*
|
||||||
div!["Rendered @ ", &rendered_at],
|
a![
|
||||||
div![
|
span![C!["icon"], i![C!["fa-solid", "fa-up-right-from-square"]]],
|
||||||
C![IF!(fresh => "fresh")],
|
ev(
|
||||||
humantime::format_duration(d).to_string(),
|
Ev::Click,
|
||||||
" ago"
|
make_external_link(format!("{ROOT_URL}/{}?t={}", im.image, data.timestamp))
|
||||||
|
)
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
nodes![
|
||||||
|
tr![th![attrs! {At::ColSpan=>2}, "Render settings"]],
|
||||||
|
tr![
|
||||||
|
td![rendered_at,],
|
||||||
|
td![
|
||||||
|
C![IF!(fresh => "fresh")],
|
||||||
|
humantime::format_duration(d).to_string(),
|
||||||
|
" ago"
|
||||||
|
]
|
||||||
],
|
],
|
||||||
table![
|
row("render_time_seconds", data.render_time_seconds),
|
||||||
C!["table", "is-striped", "is-narrow"],
|
row("subsamples", data.scene.subsamples),
|
||||||
tbody![
|
row("adaptive_subsampling", data.scene.adaptive_subsampling),
|
||||||
tr![th!["Name"], th!["Value"]],
|
row("num_threads", data.scene.num_threads),
|
||||||
row("render_time_seconds", data.render_time_seconds),
|
row("width", data.scene.width),
|
||||||
row("subsamples", data.scene.subsamples),
|
row("height", data.scene.height),
|
||||||
row("adaptive_subsampling", data.scene.adaptive_subsampling),
|
row("global_illumination", data.scene.global_illumination),
|
||||||
row("num_threads", data.scene.num_threads),
|
|
||||||
row("width", data.scene.width),
|
|
||||||
row("height", data.scene.height),
|
|
||||||
row("global_illumination", data.scene.global_illumination),
|
|
||||||
],
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,8 +316,10 @@ fn draw(
|
|||||||
&image, sx, sy, sw, sh, dx, dy, dw, dh,
|
&image, sx, sy, sw, sh, dx, dy, dw, dh,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
//let color = ctx.get_image_data(10.0, 10.0, 11.0, 11.0).unwrap().data();
|
fn make_external_link(href: String) -> impl FnOnce(Event) + Clone {
|
||||||
|
|_| Url::go_and_load_with_str(href)
|
||||||
}
|
}
|
||||||
fn view_image(
|
fn view_image(
|
||||||
im: &ImageMetadata,
|
im: &ImageMetadata,
|
||||||
@ -303,15 +328,13 @@ fn view_image(
|
|||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
) -> Node<Msg> {
|
) -> Node<Msg> {
|
||||||
let url = format!("{ROOT_URL}/{}?t={}", im.image, timestamp);
|
let url = format!("{ROOT_URL}/{}?t={}", im.image, timestamp);
|
||||||
let href = url.clone();
|
|
||||||
let go = |_| Url::go_and_load_with_str(href);
|
|
||||||
let attrs = if let Some(canvas) = image_canvas.get() {
|
let attrs = if let Some(canvas) = image_canvas.get() {
|
||||||
// Width based on browser layout of canvas and it's parent (which would be set to
|
// Width based on browser layout of canvas and it's parent (which would be set to
|
||||||
// 'width:100%' in CSS.
|
// 'width:100%' in CSS.
|
||||||
let width = canvas.client_width();
|
let width = canvas.client_width();
|
||||||
// But we need to compute an aspect correct height, because the browser can't figure this
|
// But we need to compute an aspect correct height, because the browser can't figure this
|
||||||
// out for us (because I don't know CSS that well).
|
// out for us (because I don't know CSS that well).
|
||||||
let height = width as f32 * im.ratio;
|
let height = width as f32 / im.ratio;
|
||||||
Some(attrs![
|
Some(attrs![
|
||||||
At::Width => px(width),
|
At::Width => px(width),
|
||||||
At::Height => px(height),
|
At::Height => px(height),
|
||||||
@ -332,7 +355,7 @@ fn view_image(
|
|||||||
if e.buttons() != 0 {
|
if e.buttons() != 0 {
|
||||||
Msg::Move([e.movement_x() as f64, e.movement_y() as f64])
|
Msg::Move([e.movement_x() as f64, e.movement_y() as f64])
|
||||||
} else {
|
} else {
|
||||||
Msg::Move([0., 0.])
|
Msg::SetMousePosition(e.offset_x(), e.offset_y())
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
wheel_ev(Ev::Wheel, |event| {
|
wheel_ev(Ev::Wheel, |event| {
|
||||||
@ -345,7 +368,6 @@ fn view_image(
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
button![C!["button"], "View image", ev(Ev::Click, go)],
|
|
||||||
img![
|
img![
|
||||||
el_ref(image_ref),
|
el_ref(image_ref),
|
||||||
attrs! {
|
attrs! {
|
||||||
@ -363,9 +385,9 @@ fn view_debug_buttons(
|
|||||||
canvas_size: (i32, i32),
|
canvas_size: (i32, i32),
|
||||||
zoom: f64,
|
zoom: f64,
|
||||||
offset: [f64; 2],
|
offset: [f64; 2],
|
||||||
) -> Node<Msg> {
|
image_canvas: &ElRef<HtmlCanvasElement>,
|
||||||
let zoom_in = 0.1;
|
mouse_position: Option<(i32, i32)>,
|
||||||
let zoom_out = -0.1;
|
) -> Vec<Node<Msg>> {
|
||||||
let (image_width, image_height) = image_size;
|
let (image_width, image_height) = image_size;
|
||||||
let (canvas_width, canvas_height) = canvas_size;
|
let (canvas_width, canvas_height) = canvas_size;
|
||||||
let one2one = image_width as f64 / canvas_width as f64;
|
let one2one = image_width as f64 / canvas_width as f64;
|
||||||
@ -373,85 +395,30 @@ fn view_debug_buttons(
|
|||||||
(canvas_width - image_width as i32) / 2,
|
(canvas_width - image_width as i32) / 2,
|
||||||
(canvas_height - image_height as i32) / 2,
|
(canvas_height - image_height as i32) / 2,
|
||||||
];
|
];
|
||||||
div![
|
let (r, g, b) = get_hover_color(image_canvas, mouse_position);
|
||||||
p![format!(
|
nodes![
|
||||||
"Z: {:.4} Off: {:.2}x{:.2}",
|
tr![th![attrs! {At::ColSpan=>2}, "View settings"]],
|
||||||
zoom, offset[0], offset[1]
|
row("Zoom", format!("{:.2}", zoom)),
|
||||||
)],
|
row("X Offset", format!("{:.2}", offset[0])),
|
||||||
p![format!("Mid {}x{}", canvas_width / 2, canvas_height / 2)],
|
row("Y Offset", format!("{:.2}", offset[1])),
|
||||||
p![format!("Max {}x{}", canvas_width, canvas_height)],
|
tr![td!["Hover"],td![
|
||||||
div![
|
style! {
|
||||||
C!["buttons", "has-addons"],
|
St::BackgroundColor => format!("rgb({},{},{})",r,g,b),
|
||||||
button![
|
},
|
||||||
C!["button", "is-danger", "is-fullwidth"],
|
]]
|
||||||
ev(Ev::Click, |_| Msg::Reset),
|
tr![th![attrs! {At::ColSpan=>2}, "Set Zoom"]],
|
||||||
"Reset",
|
tr![
|
||||||
],
|
td![button![
|
||||||
],
|
|
||||||
div![
|
|
||||||
C!["buttons", "has-addons", "is-centered"],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
C!["button"],
|
||||||
ev(Ev::Click, move |_| Msg::SetZoom(one2one, one2one_offset)),
|
ev(Ev::Click, move |_| Msg::SetZoom(one2one, one2one_offset)),
|
||||||
"1:1",
|
"1:1",
|
||||||
],
|
],],
|
||||||
button![
|
td![button![
|
||||||
C!["button"],
|
C!["button"],
|
||||||
ev(Ev::Click, move |_| Msg::SetZoom(1., [0, 0])),
|
ev(Ev::Click, move |_| Msg::SetZoom(1., [0, 0])),
|
||||||
"Fit",
|
"Fit",
|
||||||
],
|
]]
|
||||||
],
|
]
|
||||||
div![
|
|
||||||
C!["buttons", "has-addons", "is-centered"],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(zoom_in, [0, 0])),
|
|
||||||
"+ @ 0x0",
|
|
||||||
],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(zoom_out, [0, 0])),
|
|
||||||
"- @ 0x0",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
div![
|
|
||||||
C!["buttons", "has-addons", "is-centered"],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(
|
|
||||||
zoom_in,
|
|
||||||
[canvas_width / 2, canvas_height / 2]
|
|
||||||
)),
|
|
||||||
"+ @ mid",
|
|
||||||
],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(
|
|
||||||
zoom_out,
|
|
||||||
[canvas_width / 2, canvas_height / 2]
|
|
||||||
)),
|
|
||||||
"- @ mid",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
div![
|
|
||||||
C!["buttons", "has-addons", "is-centered"],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(
|
|
||||||
zoom_in,
|
|
||||||
[canvas_width, canvas_height]
|
|
||||||
)),
|
|
||||||
"+ @ max",
|
|
||||||
],
|
|
||||||
button![
|
|
||||||
C!["button"],
|
|
||||||
ev(Ev::Click, move |_| Msg::Zoom(
|
|
||||||
zoom_out,
|
|
||||||
[canvas_width, canvas_height]
|
|
||||||
)),
|
|
||||||
"- @ max",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,30 +428,59 @@ fn view_data(
|
|||||||
image_ref: &ElRef<HtmlImageElement>,
|
image_ref: &ElRef<HtmlImageElement>,
|
||||||
zoom: f64,
|
zoom: f64,
|
||||||
offset: [f64; 2],
|
offset: [f64; 2],
|
||||||
|
mouse_position: Option<(i32, i32)>,
|
||||||
) -> Node<Msg> {
|
) -> Node<Msg> {
|
||||||
let mut canvas_width = 128;
|
let mut canvas_width = 1024;
|
||||||
let mut canvas_height = 128;
|
let mut canvas_height = 1024;
|
||||||
if let Some(c) = image_canvas.get() {
|
if let Some(c) = image_canvas.get() {
|
||||||
canvas_width = c.width() as i32;
|
canvas_width = c.width() as i32;
|
||||||
canvas_height = c.height() as i32;
|
canvas_height = c.height() as i32;
|
||||||
}
|
}
|
||||||
let im = data.image_metadata.iter().nth(0);
|
let im = data.image_metadata.iter().nth(0);
|
||||||
let image_size = im.map(|im| im.size).unwrap_or((512, 512));
|
let image_size = im.map(|im| im.size).unwrap_or((1024, 1024));
|
||||||
div![
|
div![
|
||||||
C!["columns"],
|
C!["columns"],
|
||||||
div![
|
div![
|
||||||
C!["column"],
|
C!["column"],
|
||||||
div![
|
div![
|
||||||
C!["tabs"],
|
C!["tabs"],
|
||||||
ul![data.image_metadata.iter().map(|im| li![a![&im.name]])]
|
ul![data
|
||||||
|
.image_metadata
|
||||||
|
.iter()
|
||||||
|
.map(|im| li![a![span![&im.name],]])]
|
||||||
],
|
],
|
||||||
im.map(|im| view_image(im, image_canvas, image_ref, data.timestamp))
|
im.map(|im| view_image(im, image_canvas, image_ref, data.timestamp)),
|
||||||
],
|
],
|
||||||
div![
|
div![
|
||||||
C!["column", "is-narrow"],
|
C!["column", "is-narrow"],
|
||||||
view_metadata_table(data),
|
table![
|
||||||
view_debug_buttons(image_size, (canvas_width, canvas_height), zoom, offset),
|
C!["table", "is-striped", "is-size-7"],
|
||||||
],
|
tbody![
|
||||||
|
view_metadata_table(data),
|
||||||
|
view_debug_buttons(
|
||||||
|
image_size,
|
||||||
|
(canvas_width, canvas_height),
|
||||||
|
zoom,
|
||||||
|
offset,
|
||||||
|
image_canvas,
|
||||||
|
mouse_position
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
im.map(|im| {
|
||||||
|
let url = format!("{ROOT_URL}/{}?t={}", im.image, data.timestamp);
|
||||||
|
div![
|
||||||
|
C!["buttons", "has-addons", "is-centered"],
|
||||||
|
button![
|
||||||
|
C!["button"],
|
||||||
|
"View image",
|
||||||
|
ev(Ev::Click, make_external_link(url.clone()))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
*/
|
||||||
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,9 +498,13 @@ fn view(model: &Model) -> Node<Msg> {
|
|||||||
&model.image_canvas,
|
&model.image_canvas,
|
||||||
&model.image_ref,
|
&model.image_ref,
|
||||||
model.zoom,
|
model.zoom,
|
||||||
model.offset
|
model.offset,
|
||||||
|
model.mouse_position,
|
||||||
),
|
),
|
||||||
None => h1!["Loading...."],
|
None => section![
|
||||||
|
C!["content", "hero", "is-large", "is-fullheight"],
|
||||||
|
div![C!["hero-body"], p![C!["title"], "Loading...."]]
|
||||||
|
],
|
||||||
},
|
},
|
||||||
error,
|
error,
|
||||||
div![
|
div![
|
||||||
@ -517,6 +517,49 @@ fn view(model: &Model) -> Node<Msg> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_hover_color(
|
||||||
|
image_canvas: &ElRef<HtmlCanvasElement>,
|
||||||
|
mouse_position: Option<(i32, i32)>,
|
||||||
|
) -> (u8, u8, u8) {
|
||||||
|
let mouse_position = if let Some(mouse_position) = mouse_position {
|
||||||
|
mouse_position
|
||||||
|
} else {
|
||||||
|
return (0, 0, 0);
|
||||||
|
};
|
||||||
|
let canvas = if let Some(canvas) = image_canvas.get() {
|
||||||
|
canvas
|
||||||
|
} else {
|
||||||
|
return (0, 0, 0);
|
||||||
|
};
|
||||||
|
let mut ca2 = ContextAttributes2d::new();
|
||||||
|
// Chrome warning:
|
||||||
|
// Canvas2D: Multiple readback operations using getImageData are faster with the
|
||||||
|
// willReadFrequently attribute set to true. See:
|
||||||
|
// https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently
|
||||||
|
ca2.will_read_frequently(true);
|
||||||
|
let ctx = canvas
|
||||||
|
.get_context_with_context_options("2d", &ca2)
|
||||||
|
.expect("Problem getting canvas context")
|
||||||
|
.expect("The canvas context is empty")
|
||||||
|
.dyn_into::<web_sys::CanvasRenderingContext2d>()
|
||||||
|
.expect("Problem casting as web_sys::CanvasRenderingContext2d");
|
||||||
|
|
||||||
|
let x = mouse_position.0 as f64;
|
||||||
|
let y = mouse_position.1 as f64;
|
||||||
|
let c = ctx.get_image_data(x, y, x + 1., y + 1.).unwrap().data();
|
||||||
|
(c[0], c[1], c[2])
|
||||||
|
/*
|
||||||
|
let c_str = format!("{},{},{}", c[0], c[1], c[2]);
|
||||||
|
button![
|
||||||
|
C!["button", "is-fullwidth"],
|
||||||
|
style! {
|
||||||
|
St::BackgroundColor => format!("rgb({c_str})"),
|
||||||
|
},
|
||||||
|
c_str
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// ------ ------
|
// ------ ------
|
||||||
// Start
|
// Start
|
||||||
// ------ ------
|
// ------ ------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user