Skip to content

Commit

Permalink
Merge branch 'tree-browser'
Browse files Browse the repository at this point in the history
# Conflicts:
#	package-lock.json
  • Loading branch information
lynn committed May 9, 2024
2 parents cf4e058 + fce0ad0 commit f7d15cc
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 76 deletions.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"dependencies": {
"@types/nearley": "^2.11.2",
"@types/yargs": "^17.0.20",
"better-react-mathjax": "^2.0.3",
"canvas": "^2.11.2",
"discord.js": "^14.13.0",
"lodash": "^4.17.21",
Expand Down
24 changes: 12 additions & 12 deletions src/semantics/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,9 @@ const latex: Format = {
quantifierSymbols: {
some: '\\exists',
every: '\\forall',
every_sing: '\\forall_{\\text{\\large SING}}',
every_cuml: '\\forall_{\\text{\\large CUML}}',
gen: '\\text{\\large GEN}\\ ',
every_sing: '\\forall_{\\mathrm{\\large SING}}',
every_cuml: '\\forall_{\\mathrm{\\large CUML}}',
gen: '\\mathrm{\\large GEN}\\ ',
lambda: '\\lambda',
},
quantifier: (symbol, name, body) => `${symbol} ${name}.\\ ${body}`,
Expand Down Expand Up @@ -307,26 +307,26 @@ const latex: Format = {
ime: '\\text{íme}',
suo: '\\text{súo}',
ama: '\\text{áma}',
agent: '\\text{A\\large GENT}',
subject: '\\text{S\\large UBJ}',
agent: '\\mathrm{A\\large GENT}',
subject: '\\mathrm{S\\large UBJ}',
she: '\\text{She}',
animate: '\\text{animate}',
inanimate: '\\text{inanimate}',
abstract: '\\text{abstract}',
real_world: '\\mathrm{w}',
inertia_worlds: '\\text{I\\large W}',
inertia_worlds: '\\mathrm{I\\large W}',
alternative: '\\mathrm{A}',
temporal_trace: '\\tau',
expected_start: '\\text{ExpStart}',
expected_end: '\\text{ExpEnd}',
speech_time: '\\mathrm{t_0}',
content: '\\text{Cont}',
assert: '\\text{A\\large SSERT}',
perform: '\\text{P\\large ERFORM}',
wish: '\\text{W\\large ISH}',
promise: '\\text{P\\large ROMISE}',
permit: '\\text{P\\large ERMIT}',
warn: '\\text{W\\large ARN}',
assert: '\\mathrm{A\\large SSERT}',
perform: '\\mathrm{P\\large ERFORM}',
wish: '\\mathrm{W\\large ISH}',
promise: '\\mathrm{P\\large ROMISE}',
permit: '\\mathrm{P\\large ERMIT}',
warn: '\\mathrm{W\\large ARN}',
},
quote: text => `“${text}”`,
};
Expand Down
61 changes: 30 additions & 31 deletions src/tree/draw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,14 @@ import {
RenderedDenotation,
TreePlacer,
} from './place';
import { Theme, ThemeName, themes } from './theme';

interface Location {
x: number;
y: number;
width: number;
}

export type ThemeName = 'dark' | 'light';

export interface Theme {
backgroundColor: string;
textColor: string;
denotationColor: string;
wordColor: string;
}

const themes: Record<ThemeName, Theme> = {
dark: {
backgroundColor: '#36393E',
textColor: '#DCDDDE',
denotationColor: '#FF4466',
wordColor: '#99EEFF',
},
light: {
backgroundColor: '#FFFFFF',
textColor: '#000000',
denotationColor: '#FF0000',
wordColor: '#3399FF',
},
};

class TreeDrawer {
private margin = 40;
private font = '27px Noto Sans Math, Noto Sans';
Expand Down Expand Up @@ -85,7 +62,7 @@ class TreeDrawer {
}

private drawText(
text: string | RenderedDenotation,
text: string | RenderedDenotation<CanvasRenderingContext2D>,
x: number,
y: number,
color: string,
Expand All @@ -109,7 +86,11 @@ class TreeDrawer {
if (maxY > this.extent.maxY) this.extent.maxY = maxY;
}

private drawLabel(x: number, y: number, tree: PlacedTree): void {
private drawLabel(
x: number,
y: number,
tree: PlacedTree<CanvasRenderingContext2D>,
): void {
if (tree.coindex) {
const w1 = this.ctx.measureText(tree.label).width;
const w2 = this.ctx.measureText(tree.coindex).width;
Expand All @@ -120,7 +101,11 @@ class TreeDrawer {
}
}

private drawLeaf(x: number, y: number, tree: PlacedLeaf): void {
private drawLeaf(
x: number,
y: number,
tree: PlacedLeaf<CanvasRenderingContext2D>,
): void {
this.drawLabel(x, y, tree);
if (tree.denotation) {
this.drawText(tree.denotation, x, y + 30, this.theme.denotationColor);
Expand All @@ -145,7 +130,11 @@ class TreeDrawer {
}
}

private drawBranch(x: number, y: number, tree: PlacedBranch): void {
private drawBranch(
x: number,
y: number,
tree: PlacedBranch<CanvasRenderingContext2D>,
): void {
this.drawLabel(x, y, tree);
if (tree.denotation) {
this.drawText(tree.denotation, x, y + 30, this.theme.denotationColor);
Expand All @@ -159,7 +148,11 @@ class TreeDrawer {
}
}

private drawTree(x: number, y: number, tree: PlacedTree): void {
private drawTree(
x: number,
y: number,
tree: PlacedTree<CanvasRenderingContext2D>,
): void {
if ('word' in tree) {
this.drawLeaf(x, y, tree);
} else {
Expand Down Expand Up @@ -200,7 +193,10 @@ class TreeDrawer {

public async drawToCanvas(
tree: Tree | DTree,
renderer: (denotation: CompactExpr, theme: Theme) => RenderedDenotation,
renderer: (
denotation: CompactExpr,
theme: Theme,
) => RenderedDenotation<CanvasRenderingContext2D>,
): Promise<Canvas> {
const placer = new TreePlacer(this.ctx, this.theme, renderer);
const placed = placer.placeTree(tree);
Expand All @@ -216,7 +212,10 @@ export function drawTreeToCanvas(options: {
theme: ThemeName;
tall: boolean;
tree: Tree | DTree;
renderer: (denotation: CompactExpr, theme: Theme) => RenderedDenotation;
renderer: (
denotation: CompactExpr,
theme: Theme,
) => RenderedDenotation<CanvasRenderingContext2D>;
}): Promise<Canvas> {
const { theme, tall, tree, renderer } = options;
const layerHeight = tall ? 150 : 100;
Expand Down
64 changes: 37 additions & 27 deletions src/tree/place.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SVG } from 'mathjax-full/js/output/svg';
import { AllPackages } from 'mathjax-full/js/input/tex/AllPackages';
import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor';
import { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html';
import { Theme } from './draw';
import { Theme } from './theme';

const adaptor = liteAdaptor();
RegisterHTMLHandler(adaptor);
Expand All @@ -34,22 +34,27 @@ export function get_mathjax_svg(math: string): {
return { width, height, svg: adaptor.innerHTML(node) };
}

export interface RenderedDenotation {
export interface DrawContext {
measureText(text: string): { width: number };
}

export interface RenderedDenotation<C extends DrawContext> {
draw: (
ctx: CanvasRenderingContext2D,
ctx: C,
centerX: number,
bottomY: number,
color: string,
) => Promise<void>;
width(ctx: CanvasRenderingContext2D): number;
height(ctx: CanvasRenderingContext2D): number;
width(ctx: C): number;
height(ctx: C): number;
denotation: CompactExpr;
}

interface PlacedLeafBase {
interface PlacedLeafBase<C extends DrawContext> {
depth: 0;
width: number;
label: string;
denotation?: RenderedDenotation;
denotation?: RenderedDenotation<C>;
id?: string;
movedTo?: string;
coindex?: string;
Expand All @@ -64,21 +69,22 @@ interface NoWord {
word: undefined;
}

export type PlacedLeaf = PlacedLeafBase & (HasWord | NoWord);
export type PlacedLeaf<C extends DrawContext> = PlacedLeafBase<C> &
(HasWord | NoWord);

export interface PlacedBranch {
export interface PlacedBranch<C extends DrawContext> {
depth: number;
width: number;
label: string;
denotation?: RenderedDenotation;
denotation?: RenderedDenotation<C>;
distanceBetweenChildren: number;
children: PlacedTree[];
children: PlacedTree<C>[];
coindex?: string;
}

export type PlacedTree = PlacedLeaf | PlacedBranch;
export type PlacedTree<C extends DrawContext> = PlacedLeaf<C> | PlacedBranch<C>;

function getLabel(tree: Tree | DTree): string {
export function getLabel(tree: Tree | DTree): string {
return 'denotation' in tree && tree.denotation !== null
? `${tree.label} : ${typeToPlainText(tree.denotation.type)}`
: tree.label;
Expand All @@ -87,7 +93,7 @@ function getLabel(tree: Tree | DTree): string {
export function denotationRenderText(
denotation: CompactExpr,
theme: Theme,
): RenderedDenotation {
): RenderedDenotation<CanvasRenderingContext2D> {
const text = toPlainText(denotation);
return {
async draw(ctx, centerX, bottomY, color) {
Expand All @@ -100,13 +106,14 @@ export function denotationRenderText(
height(ctx) {
return 30;
},
denotation,
};
}

export function denotationRenderLatex(
denotation: CompactExpr,
theme: Theme,
): RenderedDenotation {
): RenderedDenotation<CanvasRenderingContext2D> {
const latex = toLatex(denotation);
let { width, height, svg } = get_mathjax_svg('\\LARGE ' + latex);
svg = svg.replace(/currentColor/g, theme.denotationColor);
Expand Down Expand Up @@ -140,10 +147,13 @@ export function denotationRenderLatex(
height(ctx) {
return pxHeight;
},
denotation,
};
}

function layerExtents(tree: PlacedTree): { left: number; right: number }[] {
function layerExtents<C extends DrawContext>(
tree: PlacedTree<C>,
): { left: number; right: number }[] {
let extents = [];
let frontier = [{ x: 0, tree }];
while (frontier.length) {
Expand All @@ -155,7 +165,7 @@ function layerExtents(tree: PlacedTree): { left: number; right: number }[] {
if ('word' in e.tree) {
newFrontier.push({
x: e.x,
tree: { width: e.tree.width, children: [] } as any as PlacedTree,
tree: { width: e.tree.width, children: [] } as any as PlacedTree<C>,
});
continue;
}
Expand All @@ -171,19 +181,19 @@ function layerExtents(tree: PlacedTree): { left: number; right: number }[] {
return extents;
}

export class TreePlacer {
export class TreePlacer<C extends DrawContext> {
constructor(
private ctx: CanvasRenderingContext2D,
private ctx: C,
private theme: Theme,
private denotationRenderer: (
denotation: Expr,
theme: Theme,
) => RenderedDenotation,
) => RenderedDenotation<C>,
) {}

private placeLeaf(
leaf: Leaf | (Leaf & { denotation: Expr | null }),
): PlacedLeaf {
): PlacedLeaf<C> {
const gloss = leaf.word.covert ? undefined : leaf.word.entry?.gloss;
const label = getLabel(leaf);
const word = leaf.word.covert ? leaf.word.value : leaf.word.text;
Expand Down Expand Up @@ -211,9 +221,9 @@ export class TreePlacer {

private makePlacedBranch(
label: string,
denotation: RenderedDenotation | undefined,
children: PlacedTree[],
): PlacedBranch {
denotation: RenderedDenotation<C> | undefined,
children: PlacedTree<C>[],
): PlacedBranch<C> {
const depth = Math.max(...children.map(c => c.depth)) + 1;
const width = Math.max(
this.ctx.measureText(label).width,
Expand Down Expand Up @@ -242,7 +252,7 @@ export class TreePlacer {

private placeBranch(
branch: Branch<Tree> | (Branch<DTree> & { denotation: Expr | null }),
): PlacedBranch {
): PlacedBranch<C> {
const denotation =
'denotation' in branch && branch.denotation !== null
? this.denotationRenderer(branch.denotation, this.theme)
Expand All @@ -254,12 +264,12 @@ export class TreePlacer {
return this.makePlacedBranch(getLabel(branch), denotation, children);
}

private placeRose(rose: Rose<Tree>): PlacedBranch {
private placeRose(rose: Rose<Tree>): PlacedBranch<C> {
const children = rose.children.map(c => this.placeTree(c));
return this.makePlacedBranch(rose.label, undefined, children);
}

public placeTree(tree: Tree | DTree): PlacedTree {
public placeTree(tree: Tree | DTree): PlacedTree<C> {
return 'word' in tree
? this.placeLeaf(tree)
: 'children' in tree
Expand Down
Loading

0 comments on commit f7d15cc

Please sign in to comment.