Skip to content

Shahxad-Akram/flutter_tex

Repository files navigation

flutter_tex

GitHub stars pub package

Contents

About

A self-contained Flutter package leveraging MathJax to deliver robust, fully offline rendering of mathematical and chemical notation. It parses multiple formats, including LaTeX, TeX, and MathML, making it a universal solution for in-app scientific and mathematical visualization.

Primary use cases include, but are not limited to:

  • General Mathematics and Statistics
  • Physics and Chemistry Equations
  • Signal Processing Expressions
  • In addition to its mathematical capabilities, the package is a powerful tool for displaying rich content, offering complete HTML and JavaScript support.

How it works?

Flutter TeX brings the power of the MathJax rendering engine to Flutter applications. As a direct port of this essential JavaScript library, it enables the display of a wide range of equations and expressions from formats like LaTeX, TeX, and MathML.

The rendering itself is handled within a webview_flutter_plus widget, allowing for a robust and faithful presentation of the original MathJax output.

We extend our sincere credit to the original MathJax developers, whose work is the foundation of this package.

Web Demo

Application Demo

Get it on Google Play

Demo Video

Screenshots

TeXWidget Quiz Sample TeX Document
Custom Fonts Image & Video Markdown

How to setup?

Minmum flutter SDK requirement is 3.27.x

1: Add flutter_tex latest pub package version under dependencies to your package's pubspec.yaml file.

dependencies:
  flutter_tex: ^5.1.4

2: You can install packages from the command line:

$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3: Now you need to put the following implementations in Android, iOS, MacOS and Web respectively.

Android

Make sure to add this line android:usesCleartextTraffic="true" in your <project-directory>/android/app/src/main/AndroidManifest.xml under application like this.

<application
       ...
       ...
       android:usesCleartextTraffic="true">
</application>

It completely works offline, without internet connection, but these are required permissions to work properly:

    <uses-permission android:name="android.permission.INTERNET" />

and intents in queries block:

<queries>
  ...
  ...
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="https" />
    </intent>

    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="sms" />
    </intent>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="tel" />
    </intent>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="mailto" />
    </intent>
    <intent>
        <action android:name="android.support.customtabs.action.CustomTabsService" />
    </intent>
</queries>

iOS

Add following lines in <project-directory>/ios/Runner/Info.plist

<key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key> <true/>
  </dict>
<key>io.flutter.embedded_views_preview</key> <true/> 
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>https</string>
    <string>http</string>
    <string>tel</string>
    <string>mailto</string>
</array> 

Web

For Web support modify <project-directory>/web/index.html like this.

<head>
    ...
    ...
  <script src="assets/packages/flutter_tex/core/flutter_tex.js"></script>
  <script src="assets/packages/flutter_tex/core/mathjax_core.js"></script>
</head>

MacOS

By default, macOS apps running in a sandboxed environment (which is the standard for Flutter apps) are not allowed to make network requests. You need to explicitly grant your application the capability to access the internet. In your Flutter project, navigate to the macos/Runner/ directory and add the following key-value pair to DebugProfile.entitlements and Release.entitlements.

<key>com.apple.security.network.client</key>
  <true/>

How to use?

In your Dart code, you can use like:

import 'package:flutter_tex/flutter_tex.dart'; 

Make sure to setup TeXRederingServer before rendering TeX:

main() async {
  await TeXRenderingServer.start();
  runApp(...);
}

Now you can use TeXView,TeXWidget or TeX2SVG as a widgets:

TeXWidget

A simple but powerful widget based on TeX2SVG. See TeXWidget Example for more details:

TeXWidget(math: r"When \(a \ne 0 \), there are two solutions to \(ax^2 + bx + c = 0\) and they are $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}$$")

TeX2SVG

A high-performance, pure Flutter solution for displaying mathematical notations. It accurately parses TeX expressions and renders them as resolution-independent SVGs via the flutter_svg library.

  • Pure Flutter: Ensures seamless integration and optimal performance within your Flutter project.
  • High-Quality Output: Renders TeX as SVG for sharp, scalable graphics on any screen size.
  • Full Render Control: Provides a comprehensive API for fine-tuning the appearance and behavior of rendered equations.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_tex/flutter_tex.dart';

main() async {
  await TeXRenderingServer.start();
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    home: TeX2SVGExample(),
  ));
}

class TeX2SVGExample extends StatefulWidget {
  const TeX2SVGExample({super.key});

  @override
  State<TeX2SVGExample> createState() => _TeX2SVGExampleState();
}

class _TeX2SVGExampleState extends State<TeX2SVGExample> {
  double fontSize = 18.0;
  TextStyle baseStyle = TextStyle(fontSize: 18.0, color: Colors.black);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: const Text("TeX2SVG Example"),
      ),
      body: ListView(
        shrinkWrap: true,
        padding: const EdgeInsets.all(16.0),
        children: [
          Container(
            padding: const EdgeInsets.all(8.0),
            decoration: BoxDecoration(
              border: Border.all(color: Colors.red, width: 4),
              borderRadius: BorderRadius.circular(8.0),
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("Quadratic Formula",
                    style: baseStyle.copyWith(
                      fontSize: fontSize * 1.5,
                      color: Colors.black,
                    )),
                RichText(
                  text: TextSpan(
                    style: baseStyle,
                    children: <InlineSpan>[
                      const TextSpan(text: 'When '),
                      WidgetSpan(
                        alignment: PlaceholderAlignment.middle,
                        child: TeX2SVG(
                          teXInputType: TeXInputType.teX,
                          math: r"a \ne 0",
                        ),
                      ),
                      const TextSpan(text: ', there are two solutions to'),
                      WidgetSpan(
                        alignment: PlaceholderAlignment.middle,
                        child: TeX2SVG(
                          math: r"ax^2 + bx + c = 0",
                        ),
                      ),
                      const TextSpan(text: ' and they are:'),
                    ],
                  ),
                ),
                Divider(
                  height: 20,
                  color: Colors.transparent,
                ),
                TeX2SVG(
                  math: r"""x = {-b \pm \sqrt{b^2-4ac} \over 2a}""",
                  formulaWidgetBuilder: (context, svg) {
                    double displayFontSize = fontSize * 3;
                    return SvgPicture.string(
                      svg,
                      height: displayFontSize,
                      width: displayFontSize,
                      fit: BoxFit.contain,
                      alignment: Alignment.center,
                    );
                  },
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

TeXView

This is an advanced widget based on webview_flutter_plus, engineered for a rich user experience. It excels at rendering complex mathematical equations and offers a flexible environment for dynamic content through its support for:

  • Inline HTML: Directly embed and render HTML content.
  • JavaScript: Execute custom scripts for interactive elements.
  • Markdown: Display text with Markdown formatting.
TeXView(
    child: TeXViewColumn(children: [
      TeXViewInkWell(
        id: "id_0",
        child: TeXViewColumn(children: [
          TeXViewDocument(r"""<h2>Flutter \( \rm\\TeX \)</h2>""",
              style: TeXViewStyle(textAlign: TeXViewTextAlign.center)),
          TeXViewContainer(
            child: TeXViewImage.network(
                'https://raw.githubusercontent.com/Shahxad-Akram/flutter_tex/master/example/assets/flutter_tex_banner.png'),
            style: TeXViewStyle(
              margin: TeXViewMargin.all(10),
              borderRadius: TeXViewBorderRadius.all(20),
            ),
          ),
          TeXViewDocument(r"""<p>                                
                       When \(a \ne 0 \), there are two solutions to \(ax^2 + bx + c = 0\) and they are
                       $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$</p>""",
              style: TeXViewStyle.fromCSS(
                  'padding: 15px; color: white; background: green'))
        ]),
      )
    ]),
    style: TeXViewStyle(
      elevation: 10,
      borderRadius: TeXViewBorderRadius.all(25),
      border: TeXViewBorder.all(TeXViewBorderDecoration(
          borderColor: Colors.blue,
          borderStyle: TeXViewBorderStyle.solid,
          borderWidth: 5)),
      backgroundColor: Colors.white,
    ),
   );

More Examples

MathJax Configurations - TeXView

To apply a custom MathJax configuration, create a file named mathjax_config.js in the root of your project's assets directory, your project structure should look like this:

your_flutter_app/
├── assets/
│   └── mathjax_config.js
├── lib/
...

and make sure to add this into pubspec.yaml like:

flutter:
  uses-material-design: true
  assets:
    - assets/mathjax_config.js

An example mathjax_config.js file:

window.MathJax = {
    tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']],
        displayMath: [['$$', '$$'], ['\\[', '\\]']],
    },
    svg: {
        fontCache: 'global'
    }
};

For more info please refer to the MathJax Docs

Custom Fonts - TeXView

To use custom fonts for TeXView, create a create a file named flutter_tex.css in the root of your project's assets directory, this style file should define your custom fonts. Your project structure should look like this:

├── assets/
│   ├── fonts/
│   └── flutter_tex.css
├── lib/
...

and make sure to add this into pubspec.yaml like:

flutter:
  uses-material-design: true
  assets:
    - assets/flutter_tex.css

An example flutter_tex.css file defining a custom font:

@font-face {
    font-family: 'army';
    src: url("fonts/Army.ttf");
}

Then you can use this custom font in your TeXViewStyle like this:

TeXViewStyle(
  fontStyle: TeXViewFontStyle(
      fontFamily: 'army'),
)

API Usage - TeXView

  • children A list of TeXViewWidget

  • heightOffset Height offset to be added to the rendered height.

  • TeXViewWidgets

    • TeXViewDocument Holds TeX data by using a raw string e.g. r"""$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$<br> """ You can also put HTML and Javascript code in it.
    • TeXViewMarkdown Holds markdown data.
    • TeXViewContainer Holds a single TeXViewWidget with styling.
    • TeXViewImage renders image from assets or network.
    • TeXViewColumn holds a list of TeXViewWidget vertically.
    • TeXViewInkWell for listening tap events..
    • TeXViewDetails like html <details>.
  • TeXViewStyle() You can style each and everything using TeXViewStyle() or by using custom CSS code by TeXViewStyle.fromCSS() where you can pass hard coded String containing CSS code. For more information please check the example.

  • loadingWidgetBuilder Shows a loading widget before rendering completes.

  • onRenderFinished Callback with the rendered page height, when TEX rendering finishes.

For more please see the Example.

API Changes

Limitations

To ensure your app remains fast and responsive, it is important to understand the performance implications of TeXView. As this widget utilizes webview_flutter_plus, each TeXView effectively embeds a web browser.

Therefore, we advise against using multiple TeXView instances on a single page. For layouts requiring multiple TeX elements, please use the TeXViewWidget as a container. This approach is optimized for performance and is the preferred method for building complex views.

For practical examples, browse the example folder. If you run into problems, you can report an issue.

About

A Flutter Package to render Mathematics, Physics and Chemistry Equations based on LaTeX

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 9