Skip to content

Commit d918802

Browse files
committed
Fix some alignment issues
1 parent f8ed1fe commit d918802

File tree

3 files changed

+141
-70
lines changed

3 files changed

+141
-70
lines changed

preview/index.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
p.setup = async function () {
2727
// TODO: make this work without a name
28-
f = await p.loadFont('font/BricolageGrotesque-Variable.ttf', 'Bricolage')
28+
f = await p.loadFont('font/Lato-Black.ttf', 'Lato')
2929
p.createCanvas(200, 200, testWebgl ? p.WEBGL : undefined);
3030
};
3131

@@ -34,15 +34,16 @@
3434
if (testWebgl) p.translate(-p.width/2, -p.height/2);
3535

3636
p.fill('white');
37-
p.textSize(80);
38-
p.textAlign(p.LEFT, p.TOP)
37+
p.textSize(60);
38+
p.textAlign(p.RIGHT, p.CENTER)
3939
p.textFont(f)
40-
p.text('hello, world!', 10, 30, p.width);
40+
p.text('hello, world!', 0, p.height/2, p.width);
4141
};
4242
};
4343

4444
new p5(sketch);
4545
</script>
46+
<p style="font-family: Lato">hello, world!</p>
4647
</body>
4748

4849
</html>

src/type/p5.Font.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ function font(p5, fn) {
5353
this.face = fontFace;
5454
}
5555

56+
verticalAlign(size) {
57+
const { sCapHeight } = this.data?.['OS/2'] || {};
58+
const { unitsPerEm = 1000 } = this.data?.head || {};
59+
const { ascender = 0, descender = 0 } = this.data?.hhea || {};
60+
const current = ascender / 2;
61+
const target = (sCapHeight || (ascender + descender)) / 2;
62+
const offset = target - current;
63+
return offset * size / unitsPerEm;
64+
}
65+
5666
variations() {
5767
let vars = {};
5868
if (this.data) {

src/type/text2d.js

Lines changed: 126 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -762,38 +762,6 @@ function text2d(p5, fn) {
762762
// return { x, y, w, h };
763763
// };
764764

765-
/*
766-
Position the lines of text based on their textAlign/textBaseline properties
767-
*/
768-
Renderer.prototype._positionLines = function (x, y, width, height, lines) {
769-
770-
let { textLeading, textAlign } = this.states;
771-
let adjustedX, lineData = new Array(lines.length);
772-
let adjustedW = typeof width === 'undefined' ? 0 : width;
773-
let adjustedH = typeof height === 'undefined' ? 0 : height;
774-
775-
for (let i = 0; i < lines.length; i++) {
776-
switch (textAlign) {
777-
case fn.START:
778-
throw new Error('textBounds: START not yet supported for textAlign'); // default to LEFT
779-
case fn.LEFT:
780-
adjustedX = x;
781-
break;
782-
case fn.CENTER:
783-
adjustedX = x + adjustedW / 2;
784-
break;
785-
case fn.RIGHT:
786-
adjustedX = x + adjustedW;
787-
break;
788-
case fn.END: // TODO: add fn.END:
789-
throw new Error('textBounds: END not yet supported for textAlign');
790-
}
791-
lineData[i] = { text: lines[i], x: adjustedX, y: y + i * textLeading };
792-
}
793-
794-
return this._yAlignOffset(lineData, adjustedH);
795-
};
796-
797765
/*
798766
Process the text string to handle line-breaks and text wrapping
799767
@param {string} str - the text to process
@@ -860,40 +828,6 @@ function text2d(p5, fn) {
860828
}
861829
}
862830

863-
/*
864-
Get the y-offset for text given the height, leading, line-count and textBaseline property
865-
*/
866-
Renderer.prototype._yAlignOffset = function (dataArr, height) {
867-
868-
if (typeof height === 'undefined') {
869-
throw Error('_yAlignOffset: height is required');
870-
}
871-
872-
let { textLeading, textBaseline } = this.states;
873-
let yOff = 0, numLines = dataArr.length;
874-
let ydiff = height - (textLeading * (numLines - 1));
875-
switch (textBaseline) { // drawingContext ?
876-
case fn.TOP:
877-
break; // ??
878-
case fn.BASELINE:
879-
break;
880-
case fn._CTX_MIDDLE:
881-
yOff = ydiff / 2;
882-
break;
883-
case fn.BOTTOM:
884-
yOff = ydiff;
885-
break;
886-
case fn.IDEOGRAPHIC:
887-
console.warn('textBounds: IDEOGRAPHIC not yet supported for textBaseline'); // FES?
888-
break;
889-
case fn.HANGING:
890-
console.warn('textBounds: HANGING not yet supported for textBaseline'); // FES?
891-
break;
892-
}
893-
dataArr.forEach(ele => ele.y += yOff);
894-
return dataArr;
895-
}
896-
897831
/*
898832
Align the bounding box based on the current rectMode setting
899833
*/
@@ -1179,6 +1113,72 @@ function text2d(p5, fn) {
11791113

11801114
this.pop();
11811115
};
1116+
1117+
/*
1118+
Position the lines of text based on their textAlign/textBaseline properties
1119+
*/
1120+
p5.Renderer2D.prototype._positionLines = function (x, y, width, height, lines) {
1121+
1122+
let { textLeading, textAlign } = this.states;
1123+
let adjustedX, lineData = new Array(lines.length);
1124+
let adjustedW = typeof width === 'undefined' ? 0 : width;
1125+
let adjustedH = typeof height === 'undefined' ? 0 : height;
1126+
1127+
for (let i = 0; i < lines.length; i++) {
1128+
switch (textAlign) {
1129+
case fn.START:
1130+
throw new Error('textBounds: START not yet supported for textAlign'); // default to LEFT
1131+
case fn.LEFT:
1132+
adjustedX = x;
1133+
break;
1134+
case fn.CENTER:
1135+
adjustedX = x + adjustedW / 2;
1136+
break;
1137+
case fn.RIGHT:
1138+
adjustedX = x + adjustedW;
1139+
break;
1140+
case fn.END: // TODO: add fn.END:
1141+
throw new Error('textBounds: END not yet supported for textAlign');
1142+
}
1143+
lineData[i] = { text: lines[i], x: adjustedX, y: y + i * textLeading };
1144+
}
1145+
1146+
return this._yAlignOffset(lineData, adjustedH);
1147+
};
1148+
1149+
/*
1150+
Get the y-offset for text given the height, leading, line-count and textBaseline property
1151+
*/
1152+
p5.Renderer2D.prototype._yAlignOffset = function (dataArr, height) {
1153+
1154+
if (typeof height === 'undefined') {
1155+
throw Error('_yAlignOffset: height is required');
1156+
}
1157+
1158+
let { textLeading, textBaseline } = this.states;
1159+
let yOff = 0, numLines = dataArr.length;
1160+
let ydiff = height - (textLeading * (numLines - 1));
1161+
switch (textBaseline) { // drawingContext ?
1162+
case fn.TOP:
1163+
break; // ??
1164+
case fn.BASELINE:
1165+
break;
1166+
case fn._CTX_MIDDLE:
1167+
yOff = ydiff / 2;
1168+
break;
1169+
case fn.BOTTOM:
1170+
yOff = ydiff;
1171+
break;
1172+
case fn.IDEOGRAPHIC:
1173+
console.warn('textBounds: IDEOGRAPHIC not yet supported for textBaseline'); // FES?
1174+
break;
1175+
case fn.HANGING:
1176+
console.warn('textBounds: HANGING not yet supported for textBaseline'); // FES?
1177+
break;
1178+
}
1179+
dataArr.forEach(ele => ele.y += yOff);
1180+
return dataArr;
1181+
}
11821182
}
11831183
if (p5.RendererGL) {
11841184
p5.RendererGL.prototype.textDrawingContext = function() {
@@ -1190,6 +1190,66 @@ function text2d(p5, fn) {
11901190
}
11911191
return this._textDrawingContext;
11921192
};
1193+
1194+
p5.RendererGL.prototype._positionLines = function (x, y, width, height, lines) {
1195+
1196+
let { textLeading, textAlign } = this.states;
1197+
const widths = lines.map((line) => this._fontWidthSingle(line));
1198+
let adjustedX, lineData = new Array(lines.length);
1199+
let adjustedW = typeof width === 'undefined' ? Math.max(0, ...widths) : width;
1200+
let adjustedH = typeof height === 'undefined' ? 0 : height;
1201+
1202+
for (let i = 0; i < lines.length; i++) {
1203+
switch (textAlign) {
1204+
case fn.START:
1205+
throw new Error('textBounds: START not yet supported for textAlign'); // default to LEFT
1206+
case fn.LEFT:
1207+
adjustedX = x;
1208+
break;
1209+
case fn._CTX_MIDDLE:
1210+
adjustedX = x + (adjustedW - widths[i]) / 2;
1211+
break;
1212+
case fn.RIGHT:
1213+
adjustedX = x + adjustedW - widths[i];
1214+
break;
1215+
case fn.END: // TODO: add fn.END:
1216+
throw new Error('textBounds: END not yet supported for textAlign');
1217+
}
1218+
lineData[i] = { text: lines[i], x: adjustedX, y: y + i * textLeading };
1219+
}
1220+
1221+
return this._yAlignOffset(lineData, adjustedH);
1222+
};
1223+
1224+
p5.RendererGL.prototype._yAlignOffset = function (dataArr, height) {
1225+
1226+
if (typeof height === 'undefined') {
1227+
throw Error('_yAlignOffset: height is required');
1228+
}
1229+
1230+
let { textLeading, textBaseline, textSize, textFont } = this.states;
1231+
let yOff = 0, numLines = dataArr.length;
1232+
let totalHeight = textSize * numLines + ((textLeading - textSize) * (numLines - 1));
1233+
switch (textBaseline) { // drawingContext ?
1234+
case fn.TOP:
1235+
yOff = textSize;
1236+
break;
1237+
case fn.BASELINE:
1238+
break;
1239+
case fn._CTX_MIDDLE:
1240+
yOff = -totalHeight / 2 + textSize;
1241+
break;
1242+
case fn.BOTTOM:
1243+
yOff = -(totalHeight - textSize);
1244+
break;
1245+
default:
1246+
console.warn(`${textBaseline} is not supported in WebGL mode.`); // FES?
1247+
break;
1248+
}
1249+
yOff += this.states.textFont.font?.verticalAlign(textSize) || 0;
1250+
dataArr.forEach(ele => ele.y += yOff);
1251+
return dataArr;
1252+
}
11931253
}
11941254
}
11951255

0 commit comments

Comments
 (0)