Angular 6中的MathJax? [英] MathJax in Angular 6?

查看:122
本文介绍了Angular 6中的MathJax?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不幸的是,关于此库的信息很少.安装后我还不清楚,我需要将什么导入到 app.module.ts 中,以及是否有需要导入的内容?我已经在index.html中指定了以下代码:

Unfortunately, very little information on this library. It is not completely clear to me after installation what I need to import into the app.module.ts and whether there is something to import there? I have prescribed the following code in the index.html:

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  tex2jax: {
    inlineMath: [['$','$'], ['\\(','\\)']]
  }
});
</script>
<script type="text/javascript" async
 src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js? 
 config=TeX-MML-AM_CHTML'>
</script>

如果我没有简单的文本,但是在某些列中出现带有公式的文本的表,该如何应用MathJax?也许您可以以某种方式将整个表转移到MathJax.Hub.Queue?

And how can I apply the MathJax, if I have not simple text, but a table in which text with formulas appears in some columns? Perhaps you can somehow transfer the entire table to MathJax.Hub.Queue?

推荐答案

像两个星期前一样,我一直在研究相同的问题,而今天我终于设法使它起作用.我不是专家,因此可能需要一些优化,但是核心功能正在发挥作用.

I was looking at the same problem like two weeks ago and today i finally manage to make it work. I'm no angular expert so it may need some optimization, but core funcionality is working.

在您的package.json文件中添加@types/mathjax依赖项.

Add @types/mathjax dependency to your package.json file.

像这样将新添加的类型添加到tsconfig.app.json:

Add newly added type to tsconfig.app.json like this:

{
  "compilerOptions": {
    "types": ["mathjax"]
  }
}

这将允许您使用诸如MathJax.Callback.Queue之类的构造,并且您的IDE不会抱怨未知类型等.

This will allow you to use constructs such as MathJax.Callback.Queue and your IDE won't complain about unkown type etc.

我在Mathml方面遇到了一些问题,因此我为数学创建了包装器,如下所示:

I had some issues with Mathml so i have created wrapper for math which looks like this :

export interface MathContent {
  latex?: string;
  mathml?: string;
}

第四步

现在,我们需要定义一个模块,该模块将通过配置注入MathJax脚本标签.因为它将动态加载async,所以我们需要确保在MathJax完全加载之前不会开始排版.最简单的方法是将Observer<any>存储到window对象中. Observer和渲染功能可以包装到服务中.

Step four

Now we need to define module which whill inject MathJax script tag with configuration. Because it will be loaded dynamically async we need to make sure typesetting doesn't start before MathJax is fully loaded. Easiest way is to store Observer<any> into window object. Observer and render functionality can be wrapped into service.

// see https://stackoverflow.com/a/12709880/1203690
declare global {
  interface Window {
    hubReady: Observer<boolean>;
  }
}

@Injectable()
export class MathServiceImpl {
  private readonly notifier: ReplaySubject<boolean>;

  constructor() {
    this.notifier = new ReplaySubject<boolean>();
    window.hubReady = this.notifier; // as said, bind to window object
  }

  ready(): Observable<boolean> {
    return this.notifier;
  }

  render(element: HTMLElement, math?: MathContent): void {
    if (math) {
      if (math.latex) {
        element.innerText = math.latex;
      } else {
        element.innerHTML = math.mathml;
      }
    }

    MathJax.Hub.Queue(['Typeset', MathJax.Hub, element]);
  }
}

第五步

现在,我们将创建指令,一旦MathJax加载,该指令将触发渲染.该指令可能如下所示:

Step five

Now we will create directive which will trigger rendering once MathJax is loaded. The directive may look like this:

@Directive({
  selector: '[appMath]'
})
export class MathDirective implements OnInit, OnChanges, OnDestroy {
  private alive$ = new Subject<boolean>();

  @Input()
  private appMath: MathContent;
  private readonly _el: HTMLElement;

  constructor(private service: MathServiceImpl,
              private el: ElementRef) {
    this._el = el.nativeElement as HTMLElement;
  }

  ngOnInit(): void {
    this.service
      .ready()
      .pipe(
        take(1),
        takeUntil(this.alive$)
      ).subscribe(res => {
        this.service.render(this._el, this.appMath);
    });
  }

  ngOnChanges(changes: SimpleChanges): void {
    console.log(changes);
  }

  ngOnDestroy(): void {
    this.alive$.next(false);
  }
}

第六步(几乎在那里)

在第四步中,我提到了async加载.根据 MathJax 上的文档,这是使用document.createElement完成的. Angular Module是此逻辑的理想之地.要在MathService上触发.ready()方法,我们将使用MathJax.Hub.Register.StartupHook并从MathService传递observable,因此我们的模块将如下所示:

Step six (almost there)

In step four i mentioned async loading. According to docs onMathJax this is done using document.createElement. Angular Module is perfect place for this logic. To trigger .ready() method on our MathService we will use MathJax.Hub.Register.StartupHook and pass observable from MathService So our module will look like this:


@NgModule({
  declarations: [MathDirective],
  exports: [MathDirective]
})
export class MathModule {
  constructor(mathService: MathServiceImpl) {
    // see https://docs.mathjax.org/en/latest/advanced/dynamic.html
    const script = document.createElement('script') as HTMLScriptElement;
    script.type = 'text/javascript';
    script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML';
    script.async = true;

    document.getElementsByTagName('head')[0].appendChild(script);

    const config = document.createElement('script') as HTMLScriptElement;
    config.type = 'text/x-mathjax-config';
    // register notifier to StartupHook and trigger .next() for all subscribers
    config.text = `
    MathJax.Hub.Config({
        skipStartupTypeset: true,
        tex2jax: { inlineMath: [["$", "$"]],displayMath:[["$$", "$$"]] }
      });
      MathJax.Hub.Register.StartupHook('End', () => {
        window.hubReady.next();
        window.hubReady.complete();
      });
    `;

    document.getElementsByTagName('head')[0].appendChild(config);
  }

  // this is needed so service constructor which will bind
  // notifier to window object before module constructor is called
  public static forRoot(): ModuleWithProviders {
    return {
      ngModule: MathModule,
      providers: [{provide: MathServiceImpl, useClass: MathServiceImpl}]
    };
  }
}

第七步:渲染数学

现在一切就绪,只需将MathModule.forRoot()导入要渲染数学的模块即可.该组件将如下所示:

Step seven: render math

Now everything is ready simply import MathModule.forRoot() in module where you want to render math. The component will look like this:

export class AppComponent {
  mathLatex: MathContent = {
    latex: 'When $a \\ne 0$, there are two solutions to $\\frac{5}{9}$'
  };

  mathMl: MathContent = {
    mathml: `<math xmlns="http://www.w3.org/1998/Math/MathML">
  <mrow>
    <mover>
      <munder>
        <mo>∫</mo>
        <mn>0</mn>
      </munder>
      <mi>∞</mi>
    </mover>
    <mtext> versus </mtext>
    <munderover>
      <mo>∫</mo>
      <mn>0</mn>
      <mi>∞</mi>
    </munderover>
  </mrow>
</math>`
  };
}

和模板

<div [appMath]="mathLatex"></div>

<div [appMath]="mathMl"></div>

<!-- will render inline element math -->
<div [appMath]>
  $E = mc^2$
</div>

应该对此进行渲染

这是工作中的stackblitz示例 https://stackblitz.com/edit/mathjax-example 这样您就可以根据实施情况检查进度

Here is working stackblitz example https://stackblitz.com/edit/mathjax-example so you can check your progress against implementation

这篇关于Angular 6中的MathJax?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆