Skip to content

Commit 88c6881

Browse files
authored
Merge pull request #657 from jonobr1/issue-653-text-measure
[Issue 653] Accurate Text Measurements
2 parents 18dc99b + 3148e92 commit 88c6881

File tree

5 files changed

+150
-73
lines changed

5 files changed

+150
-73
lines changed

build/two.js

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,8 @@ var Two = (() => {
731731
svg: "SVGRenderer",
732732
canvas: "CanvasRenderer"
733733
},
734-
Version: "v0.8.10",
735-
PublishDate: "2022-06-09T16:09:22.888Z",
734+
Version: "v0.8.11",
735+
PublishDate: "2022-08-15T20:06:30.856Z",
736736
Identifier: "two-",
737737
Resolution: 12,
738738
AutoCalculateImportedMatrices: true,
@@ -3044,13 +3044,13 @@ var Two = (() => {
30443044
var CanvasShim = {
30453045
Image: null,
30463046
isHeadless: false,
3047-
shim: function(canvas2, Image) {
3048-
Renderer.Utils.shim(canvas2);
3047+
shim: function(canvas3, Image) {
3048+
Renderer.Utils.shim(canvas3);
30493049
if (typeof Image !== "undefined") {
30503050
CanvasShim.Image = Image;
30513051
}
30523052
CanvasShim.isHeadless = true;
3053-
return canvas2;
3053+
return canvas3;
30543054
}
30553055
};
30563056

@@ -5543,8 +5543,12 @@ var Two = (() => {
55435543
}
55445544

55455545
// src/text.js
5546+
var canvas2;
55465547
var min4 = Math.min;
55475548
var max4 = Math.max;
5549+
if (root.document) {
5550+
canvas2 = document.createElement("canvas");
5551+
}
55485552
var _Text = class extends Shape {
55495553
_flagValue = true;
55505554
_flagFamily = true;
@@ -5606,6 +5610,31 @@ var Two = (() => {
56065610
}
56075611
}
56085612
}
5613+
static Measure(text) {
5614+
if (canvas2) {
5615+
const ctx = canvas2.getContext("2d");
5616+
ctx.font = [
5617+
text._style,
5618+
text._weight,
5619+
`${text._size}px/${text._leading}px`,
5620+
text._family
5621+
].join(" ");
5622+
const metrics = ctx.measureText(text.value, 0, 0);
5623+
const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
5624+
return {
5625+
width: metrics.width,
5626+
height
5627+
};
5628+
} else {
5629+
const width = this.value.length * this.size * _Text.Ratio;
5630+
const height = this.leading;
5631+
console.warn("Two.Text: unable to accurately measure text, so using an approximation.");
5632+
return {
5633+
width,
5634+
height
5635+
};
5636+
}
5637+
}
56095638
clone(parent) {
56105639
const clone = new _Text(this.value);
56115640
clone.translation.copy(this.translation);
@@ -5652,8 +5681,7 @@ var Two = (() => {
56525681
let left, right, top, bottom;
56535682
this._update(true);
56545683
matrix3 = shallow ? this._matrix : getComputedMatrix(this);
5655-
const height = this.leading;
5656-
const width = this.value.length * this.size * _Text.Ratio;
5684+
const { width, height } = _Text.Measure(this);
56575685
const border = (this._linewidth || 0) / 2;
56585686
switch (this.alignment) {
56595687
case "left":
@@ -5669,17 +5697,13 @@ var Two = (() => {
56695697
right = width / 2 + border;
56705698
}
56715699
switch (this.baseline) {
5672-
case "top":
5673-
top = -border;
5674-
bottom = height + border;
5700+
case "middle":
5701+
top = -(height / 2 + border);
5702+
bottom = height / 2 + border;
56755703
break;
5676-
case "bottom":
5704+
default:
56775705
top = -(height + border);
56785706
bottom = border;
5679-
break;
5680-
default:
5681-
top = -(height / 2 + border);
5682-
bottom = height / 2 + border;
56835707
}
56845708
a = matrix3.multiply(left, top, 1);
56855709
b = matrix3.multiply(left, bottom, 1);
@@ -8833,7 +8857,7 @@ var Two = (() => {
88338857
let prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
88348858
let isOffset;
88358859
const commands = elem._renderer.vertices;
8836-
const canvas2 = this.canvas;
8860+
const canvas3 = this.canvas;
88378861
const ctx = this.ctx;
88388862
const scale = elem._renderer.scale;
88398863
const stroke = elem._stroke;
@@ -8847,12 +8871,12 @@ var Two = (() => {
88478871
const dashes = elem.dashes;
88488872
const length = commands.length;
88498873
const last = length - 1;
8850-
canvas2.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
8851-
canvas2.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
8874+
canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
8875+
canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
88528876
const centroid = elem._renderer.rect.centroid;
88538877
const cx = centroid.x;
88548878
const cy = centroid.y;
8855-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
8879+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
88568880
if (fill) {
88578881
if (typeof fill === "string") {
88588882
ctx.fillStyle = fill;
@@ -9132,7 +9156,7 @@ var Two = (() => {
91329156
points: {
91339157
updateCanvas: function(elem) {
91349158
let isOffset;
9135-
const canvas2 = this.canvas;
9159+
const canvas3 = this.canvas;
91369160
const ctx = this.ctx;
91379161
const stroke = elem._stroke;
91389162
const linewidth = elem._linewidth;
@@ -9144,12 +9168,12 @@ var Two = (() => {
91449168
if (!webgl.isHidden.test(stroke)) {
91459169
dimension += linewidth;
91469170
}
9147-
canvas2.width = getPoT(dimension);
9148-
canvas2.height = canvas2.width;
9149-
const aspect = dimension / canvas2.width;
9150-
const cx = canvas2.width / 2;
9151-
const cy = canvas2.height / 2;
9152-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
9171+
canvas3.width = getPoT(dimension);
9172+
canvas3.height = canvas3.width;
9173+
const aspect = dimension / canvas3.width;
9174+
const cx = canvas3.width / 2;
9175+
const cy = canvas3.height / 2;
9176+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
91539177
if (fill) {
91549178
if (typeof fill === "string") {
91559179
ctx.fillStyle = fill;
@@ -9300,7 +9324,7 @@ var Two = (() => {
93009324
},
93019325
text: {
93029326
updateCanvas: function(elem) {
9303-
const canvas2 = this.canvas;
9327+
const canvas3 = this.canvas;
93049328
const ctx = this.ctx;
93059329
const scale = elem._renderer.scale;
93069330
const stroke = elem._stroke;
@@ -9309,14 +9333,14 @@ var Two = (() => {
93099333
const opacity = elem._renderer.opacity || elem._opacity;
93109334
const dashes = elem.dashes;
93119335
const decoration = elem._decoration;
9312-
canvas2.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
9313-
canvas2.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
9336+
canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
9337+
canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
93149338
const centroid = elem._renderer.rect.centroid;
93159339
const cx = centroid.x;
93169340
const cy = centroid.y;
93179341
let a, b, c, d, e, sx, sy, x1, y1, x2, y2;
93189342
const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset;
9319-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
9343+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
93209344
if (!isOffset) {
93219345
ctx.font = [elem._style, elem._weight, elem._size + "px/" + elem._leading + "px", elem._family].join(" ");
93229346
}

build/two.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/two.module.js

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,8 @@ var Constants = {
707707
svg: "SVGRenderer",
708708
canvas: "CanvasRenderer"
709709
},
710-
Version: "v0.8.10",
711-
PublishDate: "2022-06-09T16:09:22.888Z",
710+
Version: "v0.8.11",
711+
PublishDate: "2022-08-15T20:06:30.856Z",
712712
Identifier: "two-",
713713
Resolution: 12,
714714
AutoCalculateImportedMatrices: true,
@@ -3020,13 +3020,13 @@ function isDefaultMatrix(m) {
30203020
var CanvasShim = {
30213021
Image: null,
30223022
isHeadless: false,
3023-
shim: function(canvas2, Image) {
3024-
Renderer.Utils.shim(canvas2);
3023+
shim: function(canvas3, Image) {
3024+
Renderer.Utils.shim(canvas3);
30253025
if (typeof Image !== "undefined") {
30263026
CanvasShim.Image = Image;
30273027
}
30283028
CanvasShim.isHeadless = true;
3029-
return canvas2;
3029+
return canvas3;
30303030
}
30313031
};
30323032

@@ -5519,8 +5519,12 @@ function FlagRadius() {
55195519
}
55205520

55215521
// src/text.js
5522+
var canvas2;
55225523
var min4 = Math.min;
55235524
var max4 = Math.max;
5525+
if (root.document) {
5526+
canvas2 = document.createElement("canvas");
5527+
}
55245528
var _Text = class extends Shape {
55255529
constructor(message, x, y, styles) {
55265530
super();
@@ -5582,6 +5586,31 @@ var _Text = class extends Shape {
55825586
}
55835587
}
55845588
}
5589+
static Measure(text) {
5590+
if (canvas2) {
5591+
const ctx = canvas2.getContext("2d");
5592+
ctx.font = [
5593+
text._style,
5594+
text._weight,
5595+
`${text._size}px/${text._leading}px`,
5596+
text._family
5597+
].join(" ");
5598+
const metrics = ctx.measureText(text.value, 0, 0);
5599+
const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
5600+
return {
5601+
width: metrics.width,
5602+
height
5603+
};
5604+
} else {
5605+
const width = this.value.length * this.size * _Text.Ratio;
5606+
const height = this.leading;
5607+
console.warn("Two.Text: unable to accurately measure text, so using an approximation.");
5608+
return {
5609+
width,
5610+
height
5611+
};
5612+
}
5613+
}
55855614
clone(parent) {
55865615
const clone = new _Text(this.value);
55875616
clone.translation.copy(this.translation);
@@ -5628,8 +5657,7 @@ var _Text = class extends Shape {
56285657
let left, right, top, bottom;
56295658
this._update(true);
56305659
matrix3 = shallow ? this._matrix : getComputedMatrix(this);
5631-
const height = this.leading;
5632-
const width = this.value.length * this.size * _Text.Ratio;
5660+
const { width, height } = _Text.Measure(this);
56335661
const border = (this._linewidth || 0) / 2;
56345662
switch (this.alignment) {
56355663
case "left":
@@ -5645,17 +5673,13 @@ var _Text = class extends Shape {
56455673
right = width / 2 + border;
56465674
}
56475675
switch (this.baseline) {
5648-
case "top":
5649-
top = -border;
5650-
bottom = height + border;
5676+
case "middle":
5677+
top = -(height / 2 + border);
5678+
bottom = height / 2 + border;
56515679
break;
5652-
case "bottom":
5680+
default:
56535681
top = -(height + border);
56545682
bottom = border;
5655-
break;
5656-
default:
5657-
top = -(height / 2 + border);
5658-
bottom = height / 2 + border;
56595683
}
56605684
a = matrix3.multiply(left, top, 1);
56615685
b = matrix3.multiply(left, bottom, 1);
@@ -8809,7 +8833,7 @@ var webgl = {
88098833
let prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
88108834
let isOffset;
88118835
const commands = elem._renderer.vertices;
8812-
const canvas2 = this.canvas;
8836+
const canvas3 = this.canvas;
88138837
const ctx = this.ctx;
88148838
const scale = elem._renderer.scale;
88158839
const stroke = elem._stroke;
@@ -8823,12 +8847,12 @@ var webgl = {
88238847
const dashes = elem.dashes;
88248848
const length = commands.length;
88258849
const last = length - 1;
8826-
canvas2.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
8827-
canvas2.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
8850+
canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
8851+
canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
88288852
const centroid = elem._renderer.rect.centroid;
88298853
const cx = centroid.x;
88308854
const cy = centroid.y;
8831-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
8855+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
88328856
if (fill) {
88338857
if (typeof fill === "string") {
88348858
ctx.fillStyle = fill;
@@ -9108,7 +9132,7 @@ var webgl = {
91089132
points: {
91099133
updateCanvas: function(elem) {
91109134
let isOffset;
9111-
const canvas2 = this.canvas;
9135+
const canvas3 = this.canvas;
91129136
const ctx = this.ctx;
91139137
const stroke = elem._stroke;
91149138
const linewidth = elem._linewidth;
@@ -9120,12 +9144,12 @@ var webgl = {
91209144
if (!webgl.isHidden.test(stroke)) {
91219145
dimension += linewidth;
91229146
}
9123-
canvas2.width = getPoT(dimension);
9124-
canvas2.height = canvas2.width;
9125-
const aspect = dimension / canvas2.width;
9126-
const cx = canvas2.width / 2;
9127-
const cy = canvas2.height / 2;
9128-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
9147+
canvas3.width = getPoT(dimension);
9148+
canvas3.height = canvas3.width;
9149+
const aspect = dimension / canvas3.width;
9150+
const cx = canvas3.width / 2;
9151+
const cy = canvas3.height / 2;
9152+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
91299153
if (fill) {
91309154
if (typeof fill === "string") {
91319155
ctx.fillStyle = fill;
@@ -9276,7 +9300,7 @@ var webgl = {
92769300
},
92779301
text: {
92789302
updateCanvas: function(elem) {
9279-
const canvas2 = this.canvas;
9303+
const canvas3 = this.canvas;
92809304
const ctx = this.ctx;
92819305
const scale = elem._renderer.scale;
92829306
const stroke = elem._stroke;
@@ -9285,14 +9309,14 @@ var webgl = {
92859309
const opacity = elem._renderer.opacity || elem._opacity;
92869310
const dashes = elem.dashes;
92879311
const decoration = elem._decoration;
9288-
canvas2.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
9289-
canvas2.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
9312+
canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
9313+
canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
92909314
const centroid = elem._renderer.rect.centroid;
92919315
const cx = centroid.x;
92929316
const cy = centroid.y;
92939317
let a, b, c, d, e, sx, sy, x1, y1, x2, y2;
92949318
const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset;
9295-
ctx.clearRect(0, 0, canvas2.width, canvas2.height);
9319+
ctx.clearRect(0, 0, canvas3.width, canvas3.height);
92969320
if (!isOffset) {
92979321
ctx.font = [elem._style, elem._weight, elem._size + "px/" + elem._leading + "px", elem._family].join(" ");
92989322
}

0 commit comments

Comments
 (0)