From 7686cb8de8a27a2d29eea542e343c8ebfa59c95c Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 23 May 2023 11:59:50 +1000 Subject: [PATCH] Fix misaligned image occlusions (#2512) * Cloze styling is not required in I/O notetype * Use raw string for IO template * Rename to notetype.css and use more specific ids * Move internal i/o styling into runtime Storing it in the notetype makes it difficult to make changes, and makes it easier for the user to break. * Fix misaligned occlusions At larger screen sizes, the canvas was not increasing above its configured size, so it ended up being placed top center instead of expanding to fit the entire container area. To resolve this, both the image and canvas are forced to the container size, and the container is constrained to the size of the viewport, with the same aspect ratio as the image. Closes #2492 --- build/configure/src/web.rs | 4 +- .../image_occlusion_styling.css | 41 ------------------- rslib/src/image_occlusion/imagedata.rs | 5 +-- rslib/src/image_occlusion/notetype.css | 14 +++++++ rslib/src/image_occlusion/notetype.rs | 24 +++++------ ts/image-occlusion/review.scss | 28 +++++++++++++ ts/reviewer/image_occlusion.ts | 17 ++++---- ts/reviewer/reviewer.scss | 1 + 8 files changed, 64 insertions(+), 70 deletions(-) delete mode 100644 rslib/src/image_occlusion/image_occlusion_styling.css create mode 100644 rslib/src/image_occlusion/notetype.css create mode 100644 ts/image-occlusion/review.scss diff --git a/build/configure/src/web.rs b/build/configure/src/web.rs index 2312eb541..52e096177 100644 --- a/build/configure/src/web.rs +++ b/build/configure/src/web.rs @@ -394,7 +394,7 @@ fn build_and_check_editor(build: &mut Build) -> Result<()> { } fn build_and_check_reviewer(build: &mut Build) -> Result<()> { - let reviewer_deps = inputs![":ts:lib", glob!("ts/reviewer/**")]; + let reviewer_deps = inputs![":ts:lib", glob!("ts/reviewer/**"),]; build.add( "ts:reviewer:reviewer.js", EsbuildScript { @@ -410,7 +410,7 @@ fn build_and_check_reviewer(build: &mut Build) -> Result<()> { CompileSass { input: inputs!["ts/reviewer/reviewer.scss"], output: "ts/reviewer/reviewer.css", - deps: ":sass".into(), + deps: inputs![":sass", "ts/image-occlusion/review.scss"], load_paths: vec!["."], }, )?; diff --git a/rslib/src/image_occlusion/image_occlusion_styling.css b/rslib/src/image_occlusion/image_occlusion_styling.css deleted file mode 100644 index ac8a7e25b..000000000 --- a/rslib/src/image_occlusion/image_occlusion_styling.css +++ /dev/null @@ -1,41 +0,0 @@ -.image-occlusion-canvas { - --inactive-shape-color: #ffeba2; - --active-shape-color: #ff8e8e; - --inactive-shape-border: 1px #212121; - --active-shape-border: 1px #212121; -} - -.card { - font-family: arial; - font-size: 20px; - text-align: center; - color: black; - background-color: white; -} - -.cloze { - font-weight: bold; - color: blue; -} - -.nightMode .cloze { - color: lightblue; -} - -#container { - position: relative; -} - -img { - position: absolute; - top: 0; - left: 50%; - transform: translate(-50%, 0); -} - -#canvas { - position: absolute; - top: 0; - left: 50%; - transform: translate(-50%, 0); -} diff --git a/rslib/src/image_occlusion/imagedata.rs b/rslib/src/image_occlusion/imagedata.rs index 9e103f27b..bf85448c6 100644 --- a/rslib/src/image_occlusion/imagedata.rs +++ b/rslib/src/image_occlusion/imagedata.rs @@ -47,10 +47,7 @@ impl Collection { let mgr = MediaManager::new(&self.media_folder, &self.media_db)?; let actual_image_name_after_adding = mgr.add_file(&image_filename, &image_bytes)?; - let image_tag = format!( - r#""#, - &actual_image_name_after_adding - ); + let image_tag = format!(r#""#, &actual_image_name_after_adding); let current_deck = self.get_current_deck()?; self.transact(Op::ImageOcclusion, |col| { diff --git a/rslib/src/image_occlusion/notetype.css b/rslib/src/image_occlusion/notetype.css new file mode 100644 index 000000000..359781dbb --- /dev/null +++ b/rslib/src/image_occlusion/notetype.css @@ -0,0 +1,14 @@ +#image-occlusion-canvas { + --inactive-shape-color: #ffeba2; + --active-shape-color: #ff8e8e; + --inactive-shape-border: 1px #212121; + --active-shape-border: 1px #212121; +} + +.card { + font-family: arial; + font-size: 20px; + text-align: center; + color: black; + background-color: white; +} diff --git a/rslib/src/image_occlusion/notetype.rs b/rslib/src/image_occlusion/notetype.rs index e0e2febb7..a192e0083 100644 --- a/rslib/src/image_occlusion/notetype.rs +++ b/rslib/src/image_occlusion/notetype.rs @@ -51,7 +51,7 @@ impl Collection { } pub(crate) fn image_occlusion_notetype(tr: &I18n) -> Notetype { - const IMAGE_CLOZE_CSS: &str = include_str!("image_occlusion_styling.css"); + const IMAGE_CLOZE_CSS: &str = include_str!("notetype.css"); let mut nt = empty_stock( NotetypeKind::Cloze, OriginalStockKind::ImageOcclusion, @@ -71,31 +71,29 @@ pub(crate) fn image_occlusion_notetype(tr: &I18n) -> Notetype { let err_loading = tr.notetypes_error_loading_image_occlusion(); let qfmt = format!( - "\ -{{{{#{header}}}}}
{{{{{header}}}}}
{{{{/{header}}}}} -
{{{{cloze:{occlusion}}}}}
-
-
+ r#"{{{{#{header}}}}}
{{{{{header}}}}}
{{{{/{header}}}}} +
{{{{cloze:{occlusion}}}}}
+
+
{{{{{image}}}}} - +
-" +"# ); let toggle_masks = tr.notetypes_toggle_masks(); let afmt = format!( - "\ -{qfmt} -
+ r#"{qfmt} +
{{{{#{back_extra}}}}}
{{{{{back_extra}}}}}
{{{{/{back_extra}}}}} -", +"#, ); nt.add_template(nt.name.clone(), qfmt, afmt); nt diff --git a/ts/image-occlusion/review.scss b/ts/image-occlusion/review.scss new file mode 100644 index 000000000..d640b4986 --- /dev/null +++ b/ts/image-occlusion/review.scss @@ -0,0 +1,28 @@ +#image-occlusion-container { + position: relative; + // if height-constrained, ensure container is centered + left: 50%; + transform: translate(-50%, 0); + // allow for 20px margin on html element, or short windows can truncate + // image + max-height: calc(95vh - 40px); +} + +#image-occlusion-container img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + // remove the default image limits, as we rely on container + max-width: unset; + max-height: unset; +} + +#image-occlusion-canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/ts/reviewer/image_occlusion.ts b/ts/reviewer/image_occlusion.ts index 319e27221..454f371a4 100644 --- a/ts/reviewer/image_occlusion.ts +++ b/ts/reviewer/image_occlusion.ts @@ -12,17 +12,14 @@ export function setupImageCloze(): void { } function setupImageClozeInner(): void { - const canvas = document.querySelector("canvas") as HTMLCanvasElement | null; + const canvas = document.querySelector("#image-occlusion-canvas") as HTMLCanvasElement | null; if (canvas == null) { return; } - canvas.style.maxWidth = "100%"; - canvas.style.maxHeight = "95vh"; - const ctx: CanvasRenderingContext2D = canvas.getContext("2d")!; - const container = document.getElementById("container") as HTMLDivElement; - const image = document.getElementById("img") as HTMLImageElement; + const container = document.getElementById("image-occlusion-container") as HTMLDivElement; + const image = document.querySelector("#image-occlusion-container img") as HTMLImageElement; if (image == null) { container.innerText = tr.notetypeErrorNoImageToShow(); return; @@ -32,8 +29,8 @@ function setupImageClozeInner(): void { canvas.width = size.width; canvas.height = size.height; - // set height for div container (used 'relative' in css) - container.style.height = `${image.height}px`; + // Enforce aspect ratio of image + container.style.aspectRatio = `${size.width / size.height}`; // setup button for toggle image occlusion const button = document.getElementById("toggle"); @@ -151,7 +148,7 @@ function getShapeProperty(): { activeBorder: { width: number; color: string }; inActiveBorder: { width: number; color: string }; } { - const canvas = document.getElementById("canvas"); + const canvas = document.getElementById("image-occlusion-canvas"); const computedStyle = window.getComputedStyle(canvas!); // it may throw error if the css variable is not defined try { @@ -199,7 +196,7 @@ function getShapeProperty(): { } const toggleMasks = (): void => { - const canvas = document.getElementById("canvas") as HTMLCanvasElement; + const canvas = document.getElementById("image-occlusion-canvas") as HTMLCanvasElement; const display = canvas.style.display; if (display === "none") { canvas.style.display = "unset"; diff --git a/ts/reviewer/reviewer.scss b/ts/reviewer/reviewer.scss index 5f1e9d97f..dde99dee3 100644 --- a/ts/reviewer/reviewer.scss +++ b/ts/reviewer/reviewer.scss @@ -2,6 +2,7 @@ * License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */ @use "sass/vars"; +@use "ts/image-occlusion/review"; hr { background-color: vars.palette(darkgray, 0);