Latex
- TSX
- TS
import ...
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
view.add(<Latex ref={tex} tex="{{y=}}{{a}}{{x^2}}" fill="white" />);
yield* waitFor(0.2);
yield* tex().tex('{{y=}}{{a}}{{x^2}} + {{bx}}', 1);
yield* waitFor(0.2);
yield* tex().tex(
'{{y=}}{{\\left(}}{{a}}{{x^2}} + {{bx}}{{\\over 1}}{{\\right)}}',
1,
);
yield* waitFor(0.2);
yield* tex().tex('{{y=}}{{a}}{{x^2}}', 1);
});
import ...
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
const latexElement = new Latex({tex: '{{y=}}{{a}}{{x^2}}', fill: 'white'});
tex(latexElement);
view.add(latexElement);
yield* waitFor(0.2);
yield* tex.tex('{{y=}}{{a}}{{x^2}} + {{bx}}', 1);
yield* waitFor(0.2);
yield* tex.tex(
'{{y=}}{{\\left(}}{{a}}{{x^2}} + {{bx}}{{\\over 1}}{{\\right)}}',
1,
);
yield* waitFor(0.2);
yield* tex.tex('{{y=}}{{a}}{{x^2}}', 1);
});
The Latex component is used to show mathematical
formulas and animate them.
Defining LaTex
You can specify the LaTex formula to show using the tex property. Similarly to
the Txt node, you can control the color and size of
the text using the fill and fontSize properties respectively.
Make sure to always set some fill color otherwise nothing will be shown!
- TSX
- TS
import ...
export default makeScene2D(function* (view) {
view.add(
<Latex
// Try editing the formula below:
tex="a^2 + b^2 = c^2"
fill="white"
fontSize={32}
/>,
);
});
import ...
export default makeScene2D(function* (view) {
const latexElement = new Latex({
// Try editing the formula below:
tex: 'a^2 + b^2 = c^2',
fill: 'white',
fontSize: 32,
});
view.add(latexElement);
});
Animating LaTex
We can animate LaTex by tweening the tex property. To enable deletion,
insertion and transformation animation you must split the formula into several
parts. You can do this by providing an array of strings:
- TSX
- TS
<Latex tex={['a^2', '+', 'b^2', '=', 'c^2']} />
const latexElement = new Latex({tex: ['a^2', '+', 'b^2', '=', 'c^2']});
Or by using the curly bracket ({{}}) syntax:
- TSX
- TS
<Latex tex="{{a^2}} + {{b^2}} = {{c^2}}" />
// equivalent to
<Latex tex={['a^2', '+', 'b^2', '=', 'c^2']} />
const latexElement1 = new Latex({tex: '{{a^2}} + {{b^2}} = {{c^2}}'});
// equivalent to
const latexElement2 = new Latex({tex: ['a^2', '+', 'b^2', '=', 'c^2']});
You can also mix both:
- TSX
- TS
<Latex tex={['{{a}}^2', '+', '{{b}}^2', '=', '{{c}}^2']} />
// equivalent to
<Latex tex={['a','^2', '+', 'b', '^2', '=', 'c', '^2']} />
const latexElement1 = new Latex({
tex: ['{{a}}^2', '+', '{{b}}^2', '=', '{{c}}^2'],
});
// equivalent to
const latexElement2 = new Latex({
tex: ['a', '^2', '+', 'b', '^2', '=', 'c', '^2'],
});
A tex part that only exists in the source formula is considered deleted and gets faded out. Analogically, a part that only exists in the target formula is faded in. Tex parts that exist in both the source and destination formulas will be tweened:
- TSX
- TS
import ...
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
view.add(<Latex ref={tex} tex="{{1}} + {{2}}" fill="white" />);
yield* waitFor(0.5);
yield* tex().tex(['2', '+', '3', '+', '4'], 1);
});
import ...
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
const latexElement = new Latex({tex: '{{1}} + {{2}}', fill: 'white'});
tex(latexElement);
view.add(latexElement);
yield* waitFor(0.5);
yield* tex.tex(['2', '+', '3', '+', '4'], 1);
});
If a given tex part occurs multiple times in the source and target formula, but
the number of occurrences does not match, the part will duplicated or merged.
You can see this in action in the example above. The formula starts with only
one plus sign (+), but ends with two.
Tweening to specific nodes with map
You can use the map method to tween specific sub-formulae to other specific
sub-formulae.
import ...
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
view.add(
<Latex
ref={tex}
// 0 1 2 3 4
tex="{{x}}^{{2}} + {{y}}^{{2}}"
fill="white"
stroke="white"
lineWidth={0}
morpher={manimMorpher({})}
/>,
);
yield* waitFor(2);
yield* tex().lineWidth(4, 0.5);
yield* tex().fill('rgba(255, 255, 255, 0.0)', 0.5);
const pmatrixTex =
// 4 0 1 2 3 5
'\\begin{pmatrix} {{a}} & {{b}} \\\\ {{c}} & {{d}} \\end{pmatrix}';
// Mapping of original indices to target indices
// Split the plus into the matrix parenthesis, then map x -> a, y -> c, 2 -> b, 2 -> d
const pmatrixMap: number[][] = [[0], [1], [4, 5], [2], [3]];
yield* tex().map(pmatrixTex, pmatrixMap, 1);
yield* tex().fill('white', 0.5);
yield* tex().lineWidth(0, 0.5);
yield* waitFor(2);
});
For example:
- TSX
- TS
import {Latex, makeScene2D, manimMorpher} from '@canvas-commons/2d';
import {createRef, waitFor} from '@canvas-commons/core';
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
view.add(
<Latex
ref={tex}
// 0 1 2 3 4
tex="{{x}}^{{2}} + {{y}}^{{2}}"
fill="white"
stroke="white"
lineWidth={0}
morpher={manimMorpher({})}
/>,
);
yield* waitFor(2);
yield* tex().lineWidth(4, 0.5);
yield* tex().fill('rgba(255, 255, 255, 0.0)', 0.5);
const pmatrixTex =
// 4 0 1 2 3 5
'\\begin{pmatrix} {{a}} & {{b}} \\\\ {{c}} & {{d}} \\end{pmatrix}';
// Mapping of original indices to target indices
// Split the plus into the matrix parenthesis, then map x -> a, y -> c, 2 -> b, 2 -> d
const pmatrixMap: number[][] = [[0], [1], [4, 5], [2], [3]];
yield* tex().map(pmatrixTex, pmatrixMap, 1);
yield* tex().fill('white', 0.5);
yield* tex().lineWidth(0, 0.5);
yield* waitFor(2);
});
import {Latex, makeScene2D, manimMorpher} from '@canvas-commons/2d';
import {createRef, waitFor} from '@canvas-commons/core';
export default makeScene2D(function* (view) {
const tex = createRef<Latex>();
view.add(<Latex
ref={tex}
// 0 1 2 3 4
tex="{{x}}^{{2}} + {{y}}^{{2}}"
fill="white"
stroke="white"
lineWidth={0}
morpher={manimMorpher({})}
/>);
view.add(tex);
yield* waitFor(2);
yield* tex().lineWidth(4, 0.5);
yield* tex().fill('rgba(255, 255, 255, 0.0)', 0.5);
const pmatrixTex =
// 4 0 1 2 3 5
'\\begin{pmatrix} {{a}} & {{b}} \\\\ {{c}} & {{d}} \\end{pmatrix}';
// Mapping of original indices to target indices
// Split the plus into the matrix parenthesis, then map x -> a, y -> c, 2 -> b, 2 -> d
const pmatrixMap: number[][] = [[0], [1], [4, 5], [2], [3]];
yield* tex.map(pmatrixTex, pmatrixMap, 1);
yield* tex().fill('white', 0.5);
yield* tex().lineWidth(0, 0.5);
yield* waitFor(2);
});
The parameters of the map method are as many arrays as there are tex parts in
the source formula, each containing the indices of the target tex parts to map
to. For example, the mapping [[0], [1, 2]] maps source fragment 0 to target
fragment 0, and source fragment 1 to both target fragments 1 and 2.
Above, the mapping reads:
- Map
xtoa(first indexxis mapped to first indexa) - Map
2tob(second index2is mapped to second indexb) - Map
+to(and)(third index+is mapped to fourth index(and fifth index)) - Map
ytoc(fourth indexyis mapped to third indexc) - Map
2tod(fifth index2is mapped to third indexd)
The order of the indices can be unpredictable, but should be consistent between the same formulae.
Common pitfalls
Escaping slashes
The backslash character (\) is used as an escape character in JavaScript. In
order to use it as part of a LaTex formula, you need to escape it by doubling
it:
- TSX
- TS
node().tex('{{\\frac{1}{2}}}');
node.tex('{{\\frac{1}{2}}}');
Note that this does not apply inside JSX string attributes:
- TSX
- TS
// No escape needed:
<Latex tex="{{\frac{1}{2}}" />
// Escape necessary:
<Latex tex={'{{\\frac{1}{2}}'} />
// Escape needed in TS:
const latexElement = new Latex({tex: '{{\\frac{1}{2}}'});
Missing spaces
As of right now, tex parts are put together by joining them with no separator. This may break your formula if it depends on a space between two parts. For example, the following formula will break:
- TSX
- TS
<Latex tex={['\\Delta', 'y']} />
const latexElement = new Latex({tex: ['\\Delta', 'y']});
The node will attempt to parse it as \\Deltay instead of the correct
\\Delta y. To prevent it, you should wrap the y part in curly brackets:
- TSX
- TS
<Latex tex={['\\Delta', '{y}']} />
const latexElement = new Latex({tex: ['\\Delta', '{y}']});
This will be parsed as \\Delta{y} which is correct.