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
This commit is contained in:
Damien Elmes 2023-05-23 11:59:50 +10:00 committed by GitHub
parent 581f82c589
commit 7686cb8de8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 70 deletions

View File

@ -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!["."],
},
)?;

View File

@ -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);
}

View File

@ -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#"<img id="img" src="{}">"#,
&actual_image_name_after_adding
);
let image_tag = format!(r#"<img src="{}">"#, &actual_image_name_after_adding);
let current_deck = self.get_current_deck()?;
self.transact(Op::ImageOcclusion, |col| {

View File

@ -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;
}

View File

@ -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}}}}}<div>{{{{{header}}}}}</div>{{{{/{header}}}}}
<div style=\"display: none\">{{{{cloze:{occlusion}}}}}</div>
<div id=\"err\"></div>
<div id=container>
r#"{{{{#{header}}}}}<div>{{{{{header}}}}}</div>{{{{/{header}}}}}
<div style="display: none">{{{{cloze:{occlusion}}}}}</div>
<div id="err"></div>
<div id="image-occlusion-container">
{{{{{image}}}}}
<canvas id=\"canvas\" class=\"image-occlusion-canvas\"></canvas>
<canvas id="image-occlusion-canvas"></canvas>
</div>
<script>
try {{
anki.setupImageCloze();
}} catch (exc) {{
document.getElementById(\"err\").innerHTML = `{err_loading}<br><br>${{exc}}`;
document.getElementById("err").innerHTML = `{err_loading}<br><br>${{exc}}`;
}}
</script>
"
"#
);
let toggle_masks = tr.notetypes_toggle_masks();
let afmt = format!(
"\
{qfmt}
<div><button id=\"toggle\">{toggle_masks}</button></div>
r#"{qfmt}
<div><button id="toggle">{toggle_masks}</button></div>
{{{{#{back_extra}}}}}<div>{{{{{back_extra}}}}}</div>{{{{/{back_extra}}}}}
",
"#,
);
nt.add_template(nt.name.clone(), qfmt, afmt);
nt

View File

@ -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%;
}

View File

@ -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";

View File

@ -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);