Notation.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2018-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Implements utilities for notations for menclose elements
  19. *
  20. * @author dpvc@mathjax.org (Davide Cervone)
  21. */
  22. import {SVGmenclose} from './Wrappers/menclose.js';
  23. import * as Notation from '../common/Notation.js';
  24. export * from '../common/Notation.js';
  25. /*******************************************************************/
  26. /**
  27. * Shorthand for SVGmenclose
  28. */
  29. export type Menclose = SVGmenclose<any, any, any>;
  30. /*
  31. * Shorthands for common types
  32. */
  33. export type RENDERER<N, T, D> = Notation.Renderer<SVGmenclose<N, T, D>, N>;
  34. export type DEFPAIR<N, T, D> = Notation.DefPair<SVGmenclose<N, T, D>, N>;
  35. /**
  36. * The kinds of lines that can be drawn
  37. */
  38. export type LineName = Notation.Side | ('vertical' | 'horizontal' | 'up' | 'down');
  39. /**
  40. * [x1,y1, x2,y2] endpoints for a line
  41. */
  42. export type LineData = [number, number, number, number];
  43. /**
  44. * Functions for computing the line data for each type of line
  45. */
  46. export const computeLineData = {
  47. top: (h, _d, w, t) => [0, h - t, w, h - t],
  48. right: (h, d, w, t) => [w - t, -d, w - t, h],
  49. bottom: (_h, d, w, t) => [0, t - d, w, t - d],
  50. left: (h, d, _w, t) => [t, -d, t, h],
  51. vertical: (h, d, w, _t) => [w / 2, h, w / 2, -d],
  52. horizontal: (h, d, w, _t) => [0, (h - d) / 2, w, (h - d) / 2],
  53. up: (h, d, w, t) => [t, t - d, w - t, h - t],
  54. down: (h, d, w, t) => [t, h - t, w - t, t - d]
  55. } as {[kind: string]: (h: number, d: number, w: number, t: number) => LineData};
  56. /**
  57. * The data for a given line as two endpoints: [x1, y1, x2, y1]
  58. *
  59. * @param {Menclose} node The node whose line is to be drawn
  60. * @param {LineName} kind The type of line to draw for the node
  61. * @param {string} offset The offset direction, if any
  62. * @return {LineData} The coordinates of the two endpoints
  63. */
  64. export const lineData = function(node: Menclose, kind: LineName, offset: string = ''): LineData {
  65. const {h, d, w} = node.getBBox();
  66. const t = node.thickness / 2;
  67. return lineOffset(computeLineData[kind](h, d, w, t), node, offset);
  68. };
  69. /**
  70. * Recenter the line data for vertical and horizontal lines
  71. *
  72. * @param {LineData} data The line endpoints to adjust
  73. * @param {Menclose} node The menclose node
  74. * @param {string} offset The direction to offset
  75. */
  76. export const lineOffset = function(data: LineData, node: Menclose, offset: string): LineData {
  77. if (offset) {
  78. const d = node.getOffset(offset);
  79. if (d) {
  80. if (offset === 'X') {
  81. data[0] -= d;
  82. data[2] -= d;
  83. } else {
  84. data[1] -= d;
  85. data[3] -= d;
  86. }
  87. }
  88. }
  89. return data;
  90. };
  91. /*******************************************************************/
  92. /**
  93. * @param {LineName} line The name of the line to create
  94. * @return {RENDERER} The renderer function for the given line
  95. */
  96. export const RenderLine = function<N, T, D>(line: LineName, offset: string = ''): RENDERER<N, T, D> {
  97. return ((node, _child) => {
  98. const L = node.line(lineData(node, line, offset));
  99. node.adaptor.append(node.element, L);
  100. });
  101. };
  102. /*******************************************************************/
  103. /**
  104. * @param {Notation.Side} side The kind of line (side, diagonal, etc.)
  105. * @return {DEFPAIR} The notation definition for the notation having a line on the given side
  106. */
  107. export const Border = function<N, T, D>(side: Notation.Side): DEFPAIR<N, T, D> {
  108. return Notation.CommonBorder<SVGmenclose<N, T, D>, N>((node, _child) => {
  109. node.adaptor.append(node.element, node.line(lineData(node, side)));
  110. })(side);
  111. };
  112. /**
  113. * @param {string} name The name of the notation to define
  114. * @param {Notation.Side} side1 The first side to get a border
  115. * @param {Notation.Side} side2 The second side to get a border
  116. * @return {DEFPAIR} The notation definition for the notation having lines on two sides
  117. */
  118. export const Border2 = function<N, T, D>(name: string, side1: Notation.Side, side2: Notation.Side): DEFPAIR<N, T, D> {
  119. return Notation.CommonBorder2<SVGmenclose<N, T, D>, N>((node, _child) => {
  120. node.adaptor.append(node.element, node.line(lineData(node, side1)));
  121. node.adaptor.append(node.element, node.line(lineData(node, side2)));
  122. })(name, side1, side2);
  123. };
  124. /*******************************************************************/
  125. /**
  126. * @param {LineName} name The name of the diagonal strike to define
  127. * @return {DEFPAIR} The notation definition for the diagonal strike
  128. */
  129. export const DiagonalStrike = function<N, T, D>(name: LineName): DEFPAIR<N, T, D> {
  130. return Notation.CommonDiagonalStrike<SVGmenclose<N, T, D>, N>((_cname: string) => (node, _child) => {
  131. node.adaptor.append(node.element, node.line(lineData(node, name)));
  132. })(name);
  133. };
  134. /*******************************************************************/
  135. /**
  136. * @param {string} name The name of the diagonal arrow to define
  137. * @return {DEFPAIR} The notation definition for the diagonal arrow
  138. */
  139. export const DiagonalArrow = function<N, T, D>(name: string): DEFPAIR<N, T, D> {
  140. return Notation.CommonDiagonalArrow<SVGmenclose<N, T, D>, N>((node, arrow) => {
  141. node.adaptor.append(node.element, arrow);
  142. })(name);
  143. };
  144. /**
  145. * @param {string} name The name of the horizontal or vertical arrow to define
  146. * @return {DEFPAIR} The notation definition for the arrow
  147. */
  148. export const Arrow = function<N, T, D>(name: string): DEFPAIR<N, T, D> {
  149. return Notation.CommonArrow<SVGmenclose<N, T, D>, N>((node, arrow) => {
  150. node.adaptor.append(node.element, arrow);
  151. })(name);
  152. };
  153. /*******************************************************************/