LaTeXSwiftUI

一个渲染 LaTeX 方程的 SwiftUI 视图。

Unit Tests

📖 目录

ℹ️ 关于

LaTexSwiftUI 是一个软件包,它公开了一个名为 LaTeX 的视图,该视图可以解析和渲染包含数学模式宏的 TeX 和 LaTeX 方程。

该视图利用 MathJaxSwift 软件包,使用 MathJax 渲染方程。因此,视图的局限性很大程度上受到 MathJax 的 局限性 的影响。

它可以

它不能

📦 安装

将依赖项添加到您的包清单文件中。

.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.3.2")

⌨️ 使用

导入包并使用该视图。

import LaTeXSwiftUI

struct MyView: View {

  var body: some View {
    LaTeX("Hello, $\\LaTeX$!")
  }

}

⚙️ 修饰符

LaTeX 视图的主体由 Text 视图构成,因此可以随意使用任何受支持的修饰符。

LaTeX("Hello, $\\LaTeX$!")
  .fontDesign(.serif)
  .foregroundColor(.blue)

除了支持内置的 SwiftUI 修饰符外,LaTeXSwiftUI 还定义了更多修饰符,使您可以配置视图。

🔤 解析模式

文本输入可以完全渲染,或者视图可以搜索由以下终止符分隔的顶级方程。

终止符
$...$
$$...$$
\[...\]
\begin{equation}...\end{equation}
\begin{equation*}...\end{equation*}

默认行为是仅使用 onlyEquations 渲染方程。使用 parsingMode 修饰符来更改默认行为。

// Only parse equations (default)
LaTeX("Euler's identity is $e^{i\\pi}+1=0$.")
  .font(.system(size: 18))
  .parsingMode(.onlyEquations)

// Parse the entire input
LaTeX("\\text{Euler's identity is } e^{i\\pi}+1=0\\text{.}")
  .parsingMode(.all)

🌄 图片渲染模式

您可以指定渲染方程的渲染模式,使其采用周围文本的样式,或显示 MathJax 渲染的样式。默认行为是使用 template 渲染模式,以便图像与周围的文本匹配。

// Render images to match the surrounding text
LaTeX("Hello, $\\color{red}\\LaTeX$!")
  .imageRenderingMode(.template)

// Display the original rendered image
LaTeX("Hello, ${\\color{red} \\LaTeX}$!")
  .imageRenderingMode(.original)

🚨 错误模式

当解析输入时发生错误,视图将显示原始 LaTeX。您可以通过修改视图的 errorMode 来更改此行为。

注意:当使用 rendered 模式时,MathJax 被指示加载 noerrorsnoundefined 包。在其他两种模式 originalerror 中,这些包不会被 MathJax 加载,错误要么显示在视图中,要么被捕获并替换为原始文本。

// Display the original text instead of the equation
LaTeX("$\\asdf$")
  .errorMode(.original)

// Display the error text instead of the equation
LaTeX("$\\asdf$")
  .errorMode(.error)

// Display the rendered image (if available)
LaTeX("$\\asdf$")
  .errorMode(.rendered)

🧱 块渲染模式

渲染输入的典型“LaTeX-ish”方式是使用 blockViews。这种模式像往常一样渲染文本,并将块方程渲染为...块;在它们自己的行上并居中。MathJax 3 不支持换行,因此视图将块方程放置在水平滚动视图中,以防方程的宽度大于视图的宽度。

如果您想强制将块方程作为内联,可以使用 alwaysInline 模式。您还可以使用 blockText 保留块样式,但这些块不会在其视图中居中。如果您有一个冗长的输入字符串,并且只需要在单行或几行上显示它,这些模式可能会有所帮助。

/// The default block mode 
LaTeX("The quadratic formula is $$x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$$ and it has zeros at the roots of $f(x)=ax^2+bx+c$.")
  .blockMode(.blockViews)

Divider()

/// Force blocks to render as inline
LaTeX("The quadratic formula is $$x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$$ and it has zeros at the roots of $f(x)=ax^2+bx+c$.")
  .blockMode(.alwaysInline)

Divider()

/// Force blocks to render as text with newlines
LaTeX("The quadratic formula is $$x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$$ and it has zeros at the roots of $f(x)=ax^2+bx+c$.")
  .blockMode(.blockText)

🔢 带编号的块方程

LaTeX 视图可以使用 blockViews 块模式对块方程进行简单的编号。

方程编号模式

使用 equationNumberMode 修饰符在 leftrightnone 之间切换。

方程编号起始值

默认起始编号为 1,但如果您需要从不同的值开始,可以使用 equationNumberStart 修饰符指定它。

方程编号偏移量

要更改方程编号的左侧或右侧偏移量,请使用 equationNumberOffset 修饰符。

格式化方程编号

您可以在视图上设置一个闭包来执行您自己的自定义格式。formatEquationNumber 修饰符接受一个闭包,该闭包传递方程编号并返回一个字符串。

LaTeX("$$E = mc^2$$")
  .equationNumberMode(.right)
  .equationNumberOffset(10)
  .padding([.bottom])

LaTeX("$$E = mc^2$$ $$E = mc^2$$")
  .equationNumberMode(.right)
  .equationNumberOffset(10)
  .equationNumberStart(2)
  .formatEquationNumber { n in
    return "~[\(n)]~"
  }

🔗 解码 HTML

输入可能包含 HTML 实体,例如 <,LaTeX 不会将其解析为任何有意义的内容。在这种情况下,您可以使用 unencoded 修饰符。

LaTeX("$x^2<1$")
  .errorMode(.error)

// Replace "&lt;" with "<"
LaTeX("$x^2&lt;1$")
  .unencoded()

🕶️ 渲染样式

该视图有四种渲染样式。wait 样式是默认样式,并在主队列上同步加载视图。为了获得更好的性能并将 SVG 渲染从主队列中移出,请使用其他三种样式中的任何一种。

样式 异步 描述
empty 在完成渲染之前,视图保持为空。
original 在完成渲染之前,视图显示输入文本。
progress 在完成渲染之前,视图显示一个进度视图。
wait (默认) 视图阻塞主队列,直到完成渲染。

🪩 渲染动画

当使用异步渲染样式 emptyoriginalprogress 时,使用此修饰符确定应用于视图之间过渡的动画。默认值为 none

LaTeX(input)
  .renderingStyle(.original)
  .renderingAnimation(.easeIn)

在上面的示例中,将显示输入文本,直到 SVG 被渲染完成,此时渲染的视图将动画进入视图。

🪮 样式

您可以使用提供的视图样式或创建自己的样式。

// The default view style.
LaTeX(input)
  .latexStyle(.automatic)

// A "standard" style with HTML elements unencoded and block equations numbered.
LaTeX(input)
  .latexStyle(.standard)  

要创建您自己的样式,请遵循 LaTeXStyle 协议。它的 makeBody(content:) 方法接受一个 LaTeX 视图并返回该视图的风格化版本。

以下将为本 README 顶部使用的第一个标题创建一个样式。

@available(iOS 16.1, *)
public struct TitleLaTeXStyle: LaTeXStyle {
  
  public func makeBody(content: LaTeX) -> some View {
    content
      .fontDesign(.serif)
      .font(.largeTitle)
      .foregroundStyle(
          LinearGradient(
            colors: [.red, .orange, .yellow, .green, .blue, .indigo, .purple],
            startPoint: .leading,
            endPoint: .trailing
          )
        )
  }
  
}

🗄️ 缓存

LaTeXSwiftUI 缓存来自 MathJax 的 SVG 响应以及由于视图环境而渲染的图像。 如果您想控制缓存,则可以访问静态 dataCacheimageCache 属性。

// Clear the SVG data cache.
LaTeX.dataCache.removeAllObjects()

// Clear the rendered image cache.
LaTeX.imageCache.removeAllObjects()

🏃‍♀️ 预加载

SVG 和图像按需渲染和缓存,但在某些情况下,您可能希望预加载数据,以便在视图出现时延迟最小。

VStack {
  ForEach(expressions, id: \.self) { expression in
    LaTeX(expression)
      .font(.caption2)
      .foregroundColor(.green)
      .unencoded()
      .errorMode(.error)
      .processEscapes()
      .preload()
  }
}

SVG 和图像是由于视图环境而渲染的,因此如果您使用它,请务必在视图的修饰符链中最后调用 preload 方法。