mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Fix IO text size in review screen (#2986)
* Store relative font size * Handle multi-line text Thanks to @glutanimate
This commit is contained in:
parent
1a868bcaaf
commit
351aa96dfc
6 changed files with 51 additions and 12 deletions
|
@ -128,6 +128,11 @@ pub fn get_image_cloze_data(text: &str) -> String {
|
|||
result.push_str(&format!("data-scale=\"{}\" ", property.value));
|
||||
}
|
||||
}
|
||||
"fs" => {
|
||||
if !property.value.is_empty() {
|
||||
result.push_str(&format!("data-font-size=\"{}\" ", property.value));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,23 +291,41 @@ function drawShape({
|
|||
ctx.restore();
|
||||
} else if (shape instanceof Text) {
|
||||
ctx.save();
|
||||
ctx.font = `40px ${TEXT_FONT_FAMILY}`;
|
||||
ctx.font = `${shape.fontSize}px ${TEXT_FONT_FAMILY}`;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.scale(shape.scaleX, shape.scaleY);
|
||||
const textMetrics = ctx.measureText(shape.text);
|
||||
const lines = shape.text.split("\n");
|
||||
const baseMetrics = ctx.measureText("M");
|
||||
const fontHeight = baseMetrics.actualBoundingBoxAscent + baseMetrics.actualBoundingBoxDescent;
|
||||
const lineHeight = 1.5 * fontHeight;
|
||||
const linePositions: { text: string; x: number; y: number; width: number; height: number }[] = [];
|
||||
let maxWidth = 0;
|
||||
let totalHeight = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const textMetrics = ctx.measureText(lines[i]);
|
||||
linePositions.push({
|
||||
text: lines[i],
|
||||
x: shape.left / shape.scaleX,
|
||||
y: shape.top / shape.scaleY + i * lineHeight,
|
||||
width: textMetrics.width,
|
||||
height: lineHeight,
|
||||
});
|
||||
if (textMetrics.width > maxWidth) {
|
||||
maxWidth = textMetrics.width;
|
||||
}
|
||||
totalHeight += lineHeight;
|
||||
}
|
||||
ctx.fillStyle = TEXT_BACKGROUND_COLOR;
|
||||
ctx.fillRect(
|
||||
shape.left / shape.scaleX,
|
||||
shape.top / shape.scaleY,
|
||||
textMetrics.width + TEXT_PADDING,
|
||||
textMetrics.actualBoundingBoxDescent + TEXT_PADDING,
|
||||
maxWidth + TEXT_PADDING,
|
||||
totalHeight + TEXT_PADDING,
|
||||
);
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.fillText(
|
||||
shape.text,
|
||||
shape.left / shape.scaleX,
|
||||
shape.top / shape.scaleY,
|
||||
);
|
||||
for (const line of linePositions) {
|
||||
ctx.fillText(line.text, line.x, line.y);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ function extractShapeFromRenderedCloze(cloze: HTMLDivElement): Shape | null {
|
|||
points: cloze.dataset.points,
|
||||
text: cloze.dataset.text,
|
||||
scale: cloze.dataset.scale,
|
||||
fs: cloze.dataset.fontSize,
|
||||
};
|
||||
return buildShape(type, props);
|
||||
}
|
||||
|
@ -118,11 +119,15 @@ function buildShape(type: ShapeType, props: Record<string, any>): Shape {
|
|||
return new Polygon(props);
|
||||
}
|
||||
case "text": {
|
||||
return new Text({
|
||||
const textProps: Record<string, any> = {
|
||||
...props,
|
||||
scaleX: parseFloat(props.scale),
|
||||
scaleY: parseFloat(props.scale),
|
||||
});
|
||||
};
|
||||
if (props.fs) {
|
||||
textProps.fontSize = parseFloat(props.fs);
|
||||
}
|
||||
return new Text(textProps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { fabric } from "fabric";
|
||||
|
||||
import { TEXT_BACKGROUND_COLOR, TEXT_FONT_FAMILY, TEXT_PADDING } from "../tools/lib";
|
||||
import { TEXT_BACKGROUND_COLOR, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_PADDING } from "../tools/lib";
|
||||
import type { ConstructorParams, Size } from "../types";
|
||||
import type { ShapeDataForCloze } from "./base";
|
||||
import { Shape } from "./base";
|
||||
|
@ -13,17 +13,20 @@ export class Text extends Shape {
|
|||
text: string;
|
||||
scaleX: number;
|
||||
scaleY: number;
|
||||
fontSize: number | undefined;
|
||||
|
||||
constructor({
|
||||
text = "",
|
||||
scaleX = 1,
|
||||
scaleY = 1,
|
||||
fontSize,
|
||||
...rest
|
||||
}: ConstructorParams<Text> = {}) {
|
||||
super(rest);
|
||||
this.text = text;
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
this.fontSize = fontSize;
|
||||
}
|
||||
|
||||
toDataForCloze(): TextDataForCloze {
|
||||
|
@ -32,6 +35,7 @@ export class Text extends Shape {
|
|||
text: this.text,
|
||||
// scaleX and scaleY are guaranteed to be equal since we lock the aspect ratio
|
||||
scale: floatToDisplay(this.scaleX),
|
||||
fs: this.fontSize ? floatToDisplay(this.fontSize) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -42,12 +46,15 @@ export class Text extends Shape {
|
|||
fontFamily: TEXT_FONT_FAMILY,
|
||||
backgroundColor: TEXT_BACKGROUND_COLOR,
|
||||
padding: TEXT_PADDING,
|
||||
lineHeight: 1,
|
||||
});
|
||||
}
|
||||
|
||||
toNormal(size: Size): Text {
|
||||
const fontSize = this.fontSize ? this.fontSize : TEXT_FONT_SIZE;
|
||||
return new Text({
|
||||
...this,
|
||||
fontSize: fontSize / size.height,
|
||||
...super.normalPosition(size),
|
||||
});
|
||||
}
|
||||
|
@ -55,6 +62,7 @@ export class Text extends Shape {
|
|||
toAbsolute(size: Size): Text {
|
||||
return new Text({
|
||||
...this,
|
||||
fontSize: this.fontSize ? this.fontSize * size.height : TEXT_FONT_SIZE,
|
||||
...super.absolutePosition(size),
|
||||
});
|
||||
}
|
||||
|
@ -63,4 +71,5 @@ export class Text extends Shape {
|
|||
interface TextDataForCloze extends ShapeDataForCloze {
|
||||
text: string;
|
||||
scale: string;
|
||||
fs: string | undefined;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ export const BORDER_COLOR = "#212121";
|
|||
export const TEXT_BACKGROUND_COLOR = "#ffffff";
|
||||
export const TEXT_FONT_FAMILY = "Arial";
|
||||
export const TEXT_PADDING = 5;
|
||||
export const TEXT_FONT_SIZE = 40;
|
||||
|
||||
let _clipboard;
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ export const drawText = (canvas: fabric.Canvas): void => {
|
|||
backgroundColor: TEXT_BACKGROUND_COLOR,
|
||||
padding: TEXT_PADDING,
|
||||
opacity: get(opacityStateStore) ? 0.4 : 1,
|
||||
lineHeight: 1,
|
||||
});
|
||||
text["id"] = "text-" + new Date().getTime();
|
||||
|
||||
|
|
Loading…
Reference in a new issue