fix: Use SVGs for some stacked delims (#3686)
* fix: Use SVGs for some stacked delims * Account for script level & correct some geometry * Fix script level adjustment * Updated screenshotter images * Change \vert to round cap * Fix \vert geometry * Update screenshotter images
@@ -25,7 +25,7 @@ import ParseError from "./ParseError";
|
||||
import Style from "./Style";
|
||||
|
||||
import {PathNode, SvgNode, SymbolNode} from "./domTree";
|
||||
import {sqrtPath, innerPath} from "./svgGeometry";
|
||||
import {sqrtPath, innerPath, tallDelim} from "./svgGeometry";
|
||||
import buildCommon from "./buildCommon";
|
||||
import {getCharacterMetrics} from "./fontMetrics";
|
||||
import symbols from "./symbols";
|
||||
@@ -229,6 +229,8 @@ const makeStackedDelim = function(
|
||||
let middle;
|
||||
let repeat;
|
||||
let bottom;
|
||||
let svgLabel = "";
|
||||
let viewBoxWidth = 0;
|
||||
top = repeat = bottom = delim;
|
||||
middle = null;
|
||||
// Also keep track of what font the delimiters are in
|
||||
@@ -255,44 +257,64 @@ const makeStackedDelim = function(
|
||||
bottom = "\\Downarrow";
|
||||
} else if (utils.contains(verts, delim)) {
|
||||
repeat = "\u2223";
|
||||
svgLabel = "vert";
|
||||
viewBoxWidth = 333;
|
||||
} else if (utils.contains(doubleVerts, delim)) {
|
||||
repeat = "\u2225";
|
||||
svgLabel = "doublevert";
|
||||
viewBoxWidth = 556;
|
||||
} else if (delim === "[" || delim === "\\lbrack") {
|
||||
top = "\u23a1";
|
||||
repeat = "\u23a2";
|
||||
bottom = "\u23a3";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "lbrack";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "]" || delim === "\\rbrack") {
|
||||
top = "\u23a4";
|
||||
repeat = "\u23a5";
|
||||
bottom = "\u23a6";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "rbrack";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "\\lfloor" || delim === "\u230a") {
|
||||
repeat = top = "\u23a2";
|
||||
bottom = "\u23a3";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "lfloor";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "\\lceil" || delim === "\u2308") {
|
||||
top = "\u23a1";
|
||||
repeat = bottom = "\u23a2";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "lceil";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "\\rfloor" || delim === "\u230b") {
|
||||
repeat = top = "\u23a5";
|
||||
bottom = "\u23a6";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "rfloor";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "\\rceil" || delim === "\u2309") {
|
||||
top = "\u23a4";
|
||||
repeat = bottom = "\u23a5";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "rceil";
|
||||
viewBoxWidth = 667;
|
||||
} else if (delim === "(" || delim === "\\lparen") {
|
||||
top = "\u239b";
|
||||
repeat = "\u239c";
|
||||
bottom = "\u239d";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "lparen";
|
||||
viewBoxWidth = 875;
|
||||
} else if (delim === ")" || delim === "\\rparen") {
|
||||
top = "\u239e";
|
||||
repeat = "\u239f";
|
||||
bottom = "\u23a0";
|
||||
font = "Size4-Regular";
|
||||
svgLabel = "rparen";
|
||||
viewBoxWidth = 875;
|
||||
} else if (delim === "\\{" || delim === "\\lbrace") {
|
||||
top = "\u23a7";
|
||||
middle = "\u23a8";
|
||||
@@ -365,12 +387,32 @@ const makeStackedDelim = function(
|
||||
// Calculate the depth
|
||||
const depth = realHeightTotal / 2 - axisHeight;
|
||||
|
||||
|
||||
// Now, we start building the pieces that will go into the vlist
|
||||
// Keep a list of the pieces of the stacked delimiter
|
||||
const stack = [];
|
||||
|
||||
// Add the bottom symbol
|
||||
if (svgLabel.length > 0) {
|
||||
// Instead of stacking glyphs, create a single SVG.
|
||||
// This evades browser problems with imprecise positioning of spans.
|
||||
const midHeight = realHeightTotal - topHeightTotal - bottomHeightTotal;
|
||||
const viewBoxHeight = Math.round(realHeightTotal * 1000);
|
||||
const pathStr = tallDelim(svgLabel, Math.round(midHeight * 1000));
|
||||
const path = new PathNode(svgLabel, pathStr);
|
||||
const width = (viewBoxWidth / 1000).toFixed(3) + "em";
|
||||
const height = (viewBoxHeight / 1000).toFixed(3) + "em";
|
||||
const svg = new SvgNode([path], {
|
||||
"width": width,
|
||||
"height": height,
|
||||
"viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
||||
});
|
||||
const wrapper = buildCommon.makeSvgSpan([], [svg], options);
|
||||
wrapper.height = viewBoxHeight / 1000;
|
||||
wrapper.style.width = width;
|
||||
wrapper.style.height = height;
|
||||
stack.push({type: "elem", elem: wrapper});
|
||||
} else {
|
||||
// Stack glyphs
|
||||
// Start by adding the bottom symbol
|
||||
stack.push(makeGlyphSpan(bottom, font, mode));
|
||||
stack.push(lap); // overlap
|
||||
|
||||
@@ -383,8 +425,8 @@ const makeStackedDelim = function(
|
||||
} else {
|
||||
// When there is a middle bit, we need the middle part and two repeated
|
||||
// sections
|
||||
const innerHeight = (realHeightTotal - topHeightTotal - bottomHeightTotal -
|
||||
middleHeightTotal) / 2 + 2 * lapInEms;
|
||||
const innerHeight = (realHeightTotal - topHeightTotal -
|
||||
bottomHeightTotal - middleHeightTotal) / 2 + 2 * lapInEms;
|
||||
stack.push(makeInner(repeat, innerHeight, options));
|
||||
// Now insert the middle of the brace.
|
||||
stack.push(lap);
|
||||
@@ -396,6 +438,7 @@ const makeStackedDelim = function(
|
||||
// Add the top symbol
|
||||
stack.push(lap);
|
||||
stack.push(makeGlyphSpan(top, font, mode));
|
||||
}
|
||||
|
||||
// Finally, build the vlist
|
||||
const newOptions = options.havingBaseStyle(Style.TEXT);
|
||||
|
@@ -487,3 +487,59 @@ c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,
|
||||
c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z
|
||||
M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`,
|
||||
};
|
||||
|
||||
export const tallDelim = function(label: string, midHeight: number): string {
|
||||
switch (label) {
|
||||
case "lbrack":
|
||||
return `M403 1759 V84 H666 V0 H319 V1759 v${midHeight} v1759 h347 v-84
|
||||
H403z M403 1759 V0 H319 V1759 v${midHeight} v1759 h84z`;
|
||||
case "rbrack":
|
||||
return `M347 1759 V0 H0 V84 H263 V1759 v${midHeight} v1759 H0 v84 H347z
|
||||
M347 1759 V0 H263 V1759 v${midHeight} v1759 h84z`;
|
||||
case "vert":
|
||||
return `M145 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
|
||||
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
|
||||
c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v${midHeight} v585 h43z`;
|
||||
case "doublevert":
|
||||
return `M145 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
|
||||
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
|
||||
c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v${midHeight} v585 h43z
|
||||
M367 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
|
||||
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
|
||||
c-10,0,-16.667,5,-20,15z M410 15 H367 v585 v${midHeight} v585 h43z`;
|
||||
case "lfloor":
|
||||
return `M319 602 V0 H403 V602 v${midHeight} v1715 h263 v84 H319z
|
||||
MM319 602 V0 H403 V602 v${midHeight} v1715 H319z`;
|
||||
case "rfloor":
|
||||
return `M319 602 V0 H403 V602 v${midHeight} v1799 H0 v-84 H319z
|
||||
MM319 602 V0 H403 V602 v${midHeight} v1715 H319z`;
|
||||
case "lceil":
|
||||
return `M403 1759 V84 H666 V0 H319 V1759 v${midHeight} v602 h84z
|
||||
M403 1759 V0 H319 V1759 v${midHeight} v602 h84z`;
|
||||
case "rceil":
|
||||
return `M347 1759 V0 H0 V84 H263 V1759 v${midHeight} v602 h84z
|
||||
M347 1759 V0 h-84 V1759 v${midHeight} v602 h84z`;
|
||||
case "lparen":
|
||||
return `M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1
|
||||
c-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349,
|
||||
-36,557 l0,${midHeight + 84}c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210,
|
||||
949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9
|
||||
c0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5,
|
||||
-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189
|
||||
l0,-${midHeight + 92}c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3,
|
||||
-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z`;
|
||||
case "rparen":
|
||||
return `M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3,
|
||||
63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5
|
||||
c11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,${midHeight + 9}
|
||||
c-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664
|
||||
c-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11
|
||||
c0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17
|
||||
c242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558
|
||||
l0,-${midHeight + 144}c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7,
|
||||
-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z`;
|
||||
default:
|
||||
// We should not ever get here.
|
||||
throw new Error("Unknown stretchy delimiter.");
|
||||
}
|
||||
};
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.2 KiB |