Incorrect base anchors for equations
In Issue #683 Content-Relative Anchors and #684 PR, CeTZ added support for base anchors, which works well for text. However, I observed incorrect results when using base anchors with equations. Below are examples demonstrating the issue, along with a proposed solution.
Examples of Incorrect Base Anchors
-
Inline Equation
The equation is
$limits(sum)_(i in I)F(U_i)$
- TikZ (expected result): Overleaf Link
- CeTZ (incorrect result): Typst App Link. The base anchor is positioned lower than in TikZ
-
Block Equation
The equation is
$ limits(sum)_(i in I)F(U_i) $
- TikZ (expected result): Overleaf Link
- CeTZ (incorrect result): Typst App Link. The base anchor coincides with the south anchor.
Proposed Solution
The #684 PR introduced a measure function to calculate the base anchor. While it works for text, it fails to measure equation baselines correctly.
@Enter-tainer suggested a way to accurately calculate the baseline of equations. I adapted this approach from the rehype-typst project and created a demo measure_equation.typ. The code for measure_equation.typ is hosted on (Typst App) and here are some tests for this baseline measure function:
This method uses the following strategy:
- Define
heightas the part of the equation above the baseline. - Define
depthas the part below the baseline. - Insert a function call
pin(label)at the start of the equation.
The function is triggered when the equation is displayed at the top-left corner of the page. Within the function,// a dict that stores the height of equations #let s = state("eq_height_dict", (:)) // when called, retrieves the height of the equation, which is then stored in a state variable #let pin(label) = context { let height = measure(line(length: here().position().y)).width s.update(it => it.insert(label, height) + it) } // get the bounding box of an equation #let bounded(eq) = text(top-edge: "bounds", bottom-edge: "bounds", eq) // insert a function call `pin(label)`` at the start of the equation. #let add_pin(eq) = { let label = repr(eq) let formula = if eq.block == true { $ pin(label)#eq $ } else { $pin(label)#eq$ } bounded(formula) }here().position().yretrieves the height of the equation, which is then stored in a state variable. - Calculate
height + depthusingmeasure(text(top-edge: "bounds", bottom-edge: "bounds", eq)), and subtract theheightto derivedepth. - The equation must be displayed before any call to
state.get(). Thehidefunction is used to display the equation "virtually", preventing the equation from appearing in the final output.
Accurate base anchor for equation is crucial in math diagramming, as we expect math formulas within a line to align perfectly by their baselines. This alignment is essential for achieving a professional and polished look in mathematical diagrams. Currently, the incorrect calculation of base anchors blocks me from using Typst for diagram drawing, as demonstrated as follows:
I hope we could introduce a specialized method for measuring equation to ensure correct base anchors, achieving functionality on par with LaTeX TikZ, and making it a more viable option for math diagrams. Let me know if there’s more I can do to help!