Skip to content

Commit 256f758

Browse files
committed
Make SVG and HTML more consistent with percent-width tables, in particular when the width exceeds the container width.
1 parent 306f08d commit 256f758

File tree

5 files changed

+78
-19
lines changed

5 files changed

+78
-19
lines changed

mathjax3-ts/output/chtml/Wrappers/mtable.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,8 @@ CommonMtableMixin<CHTMLmtd<N, T, D>, CHTMLmtr<N, T, D>, CHTMLConstructor<N, T, D
415415
W = this.em(this.length2em(W) + 2 * this.fLine);
416416
}
417417
const table = adaptor.firstChild(this.chtml) as N;
418-
adaptor.setStyle(table, 'minWidth', W);
418+
adaptor.setStyle(table, 'width', W);
419+
adaptor.setStyle(table, 'minWidth', this.em(w));
419420
if (L || R) {
420421
adaptor.setStyle(this.chtml, 'margin', '');
421422
if (L === R) {

mathjax3-ts/output/common/Wrappers/mtable.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ export interface CommonMtable<C extends AnyWrapper, R extends CommonMtr<C>> exte
103103
*/
104104
pwidthCells: [C, number][];
105105

106+
/**
107+
* The full width of a percentage-width table
108+
*/
109+
pWidth: number;
110+
106111
/**
107112
* The rows of the table
108113
*/
@@ -181,6 +186,11 @@ export interface CommonMtable<C extends AnyWrapper, R extends CommonMtr<C>> exte
181186
*/
182187
getPadAlignShift(side: string): [number, string, number];
183188

189+
/**
190+
* @return {number} The true width of the table (without labels)
191+
*/
192+
getWidth(): number;
193+
184194
/**
185195
* @return {number} The maximum height of a row
186196
*/
@@ -373,6 +383,10 @@ export function CommonMtableMixin<C extends AnyWrapper,
373383
*/
374384
public pwidthCells: [C, number][] = [];
375385

386+
/**
387+
* The full width of a percentage-width table
388+
*/
389+
public pWidth: number = 0;
376390

377391
/**
378392
* @return {R[]} The rows of the table
@@ -651,18 +665,21 @@ export function CommonMtableMixin<C extends AnyWrapper,
651665
this.container.bbox.pwidth = '';
652666
}
653667
const {w, L, R} = this.bbox;
654-
const W = Math.max(w, this.length2em(width, cwidth));
668+
const W = Math.max(w, this.length2em(width, Math.max(cwidth, L + w + R)));
655669
const cols = (this.node.attributes.get('equalcolumns') as boolean ?
656670
Array(this.numCols).fill(this.percent(1 / Math.max(1, this.numCols))) :
657671
this.getColumnAttributes('columnwidth', 0));
658672
this.cWidths = this.getColumnWidthsFixed(cols, W);
659673
const CW = this.getComputedWidths();
660-
this.bbox.w = sum(CW.concat(this.cLines, this.cSpace)) + 2 * (this.fLine + this.fSpace[0]);
674+
this.pWidth = sum(CW.concat(this.cLines, this.cSpace)) + 2 * (this.fLine + this.fSpace[0]);
675+
if (this.isTop) {
676+
this.bbox.w = this.pWidth;
677+
}
661678
this.setColumnPWidths();
662-
if (this.bbox.w !== w) {
679+
if (this.pWidth !== w) {
663680
this.parent.invalidateBBox();
664681
}
665-
return this.bbox.w !== w;
682+
return this.pWidth !== w;
666683
}
667684

668685
/**
@@ -748,6 +765,13 @@ export function CommonMtableMixin<C extends AnyWrapper,
748765
[this.container.getChildAlign(this.containerI), 0] as [string, number]);
749766
}
750767

768+
/**
769+
* @return {number} The true width of the table (without labels)
770+
*/
771+
public getWidth() {
772+
return this.pWidth || this.getBBox().w;
773+
}
774+
751775
/******************************************************************/
752776

753777
/**

mathjax3-ts/output/svg/Wrappers/mtable.ts

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
9494
this.handleColumnLines(svg);
9595
this.handleRowLines(svg);
9696
this.handleFrame(svg);
97-
this.handleLabels(svg, parent);
97+
const dx = this.handlePWidth(svg);
98+
this.handleLabels(svg, parent, dx);
9899
}
99100

100101
/**
@@ -131,6 +132,17 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
131132

132133
/******************************************************************/
133134

135+
/**
136+
* @override
137+
*/
138+
public handleColor() {
139+
super.handleColor();
140+
const rect = this.adaptor.firstChild(this.element);
141+
if (rect) {
142+
this.adaptor.setAttribute(rect, 'width', this.fixed(this.getWidth()));
143+
}
144+
}
145+
134146
/**
135147
* Add vertical lines between columns
136148
*
@@ -188,6 +200,25 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
188200
}
189201
}
190202

203+
/**
204+
* @return {number} The x-adjustement needed to handle the true size of percentage-width tables
205+
*/
206+
protected handlePWidth(svg: N) {
207+
if (!this.pWidth) return 0;
208+
const {w, L, R} = this.getBBox();
209+
const W = L + this.pWidth + R;
210+
const [align, shift] = this.getAlignShift();
211+
const CW = Math.max(this.isTop ? W : 0, this.container.getWrapWidth(this.containerI)) - L - R;
212+
const dw = w - (this.pWidth > CW ? CW: this.pWidth);
213+
const dx = (align === 'left' ? 0 : align === 'right' ? dw : dw / 2);
214+
if (dx) {
215+
const table = this.svg('g', {}, this.adaptor.childNodes(svg));
216+
this.place(dx, 0, table);
217+
this.adaptor.append(svg, table);
218+
}
219+
return dx;
220+
}
221+
191222
/******************************************************************/
192223

193224
/**
@@ -256,10 +287,11 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
256287
/**
257288
* Handle addition of labels to the table
258289
*
259-
* @param {N} svg The container for the table contents
260-
* @param {N} parent The parent containing the the table
290+
* @param {N} svg The container for the table contents
291+
* @param {N} parent The parent containing the the table
292+
* @param {number} dx The adjustement for percentage width tables
261293
*/
262-
protected handleLabels(svg: N, parent: N) {
294+
protected handleLabels(svg: N, parent: N, dx: number) {
263295
if (!this.hasLabels) return;
264296
const labels = this.labels;
265297
const attributes = this.node.attributes;
@@ -276,7 +308,7 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
276308
// Handle top-level table to make it adapt to container size
277309
// but place subtables explicitly
278310
//
279-
this.isTop ? this.nestTable(svg, labels, side) : this.subTable(svg, labels, side);
311+
this.isTop ? this.topTable(svg, labels, side) : this.subTable(svg, labels, side, dx);
280312
}
281313

282314
/**
@@ -313,9 +345,10 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
313345
* @param {N} labels The group of labels
314346
* @param {string} side The side alignment (left or right)
315347
*/
316-
protected nestTable(svg: N, labels: N, side: string) {
348+
protected topTable(svg: N, labels: N, side: string) {
317349
const adaptor = this.adaptor;
318350
const {h, d, w, L, R} = this.getBBox();
351+
const W = L + (this.pWidth || w) + R;
319352
const LW = this.getTableData().L;
320353
const [pad, align, shift] = this.getPadAlignShift(side);
321354
const translate = (shift ? ` translate(${this.fixed(shift)} 0)` : '');
@@ -324,7 +357,7 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
324357
let table = this.svg('svg', {
325358
'data-table': true, transform: transform,
326359
preserveAspectRatio: (align === 'left' ? 'xMinYMid' : align === 'right' ? 'xMaxYMid' : 'xMidYMid'),
327-
viewBox: [this.fixed(-L), this.fixed(-h), this.fixed(L + w + R), this.fixed(h + d)].join(' ')
360+
viewBox: [this.fixed(-L), this.fixed(-h), this.fixed(W), this.fixed(h + d)].join(' ')
328361
}, [
329362
this.svg('g', {transform: 'matrix(1 0 0 -1 0 0)' + translate}, adaptor.childNodes(svg))
330363
]);
@@ -342,17 +375,18 @@ CommonMtableMixin<SVGmtd<N, T, D>, SVGmtr<N, T, D>, SVGConstructor<N, T, D>>(SVG
342375
* @param {N} svg The SVG container for the table
343376
* @param {N} labels The group of labels
344377
* @param {string} side The side alignment (left or right)
378+
* @param {number} dx The adjustement for percentage width tables
345379
*/
346-
protected subTable(svg: N, labels: N, side: string) {
380+
protected subTable(svg: N, labels: N, side: string, dx: number) {
347381
const adaptor = this.adaptor;
348-
const {h, d, w, L, R} = this.getBBox();
349-
const W = L + w + R;
382+
const {w, L, R} = this.getBBox();
383+
const W = L + (this.pWidth || w) + R;
350384
const labelW = this.getTableData().L;
351385
const [align, shift] = this.getAlignShift();
352386
const CW = Math.max(W, this.container.getWrapWidth(this.containerI));
353387
this.place(side === 'left' ?
354-
(align === 'left' ? 0 : align === 'right' ? W - CW : (W - CW) / 2) - L :
355-
(align === 'left' ? CW : align === 'right' ? W : (CW + W) / 2) - L - labelW,
388+
(align === 'left' ? 0 : align === 'right' ? W - CW + dx : (W - CW) / 2 + dx) - L :
389+
(align === 'left' ? CW : align === 'right' ? W + dx : (CW + W) / 2 + dx) - L - labelW,
356390
0, labels);
357391
adaptor.append(svg, labels);
358392
}

mathjax3-ts/output/svg/Wrappers/mtr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export class SVGmtr<N, T, D> extends CommonMtrMixin<SVGmtd<N, T, D>, SVGConstruc
122122
const [TS, BS] = [this.tSpace, this.bSpace];
123123
const [H, D] = [this.H, this.D];
124124
adaptor.setAttribute(child, 'y', this.fixed(-(D + BS + BL)));
125-
adaptor.setAttribute(child, 'width', this.fixed(this.parent.getBBox().w));
125+
adaptor.setAttribute(child, 'width', this.fixed(this.parent.getWidth()));
126126
adaptor.setAttribute(child, 'height', this.fixed(TL + TS + H + D + BS + BL));
127127
}
128128
}

mathjax3-ts/util/string.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function unicodeChars(text: string) {
6767
* @return {boolean} True if the string ends with a percent sign
6868
*/
6969
export function isPercent(x: string) {
70-
return x.match(/%\s*$/);
70+
return !!x.match(/%\s*$/);
7171
}
7272

7373
/**

0 commit comments

Comments
 (0)