-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for multiline labels using explicit newline character. #4306
Changes from all commits
d47f517
bac19f0
1afb9a9
81a3a78
42c0fe9
c4b8703
9f8e686
58cc9bb
7e65a65
77ed7b4
88bc7c3
08ed5f5
1ca1c89
d25dcdd
2d2c7c2
306ca1a
6f9f57c
78156d7
6fd89ca
a41e167
1084cc7
cc49261
a5d426d
1a62c75
84d0071
e17a393
8fbfaa3
40737cb
bcc1f86
72697cf
6539033
ef86d83
02c6d93
fe84bef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,9 @@ define([ | |
this.dimensions = dimensions; | ||
} | ||
|
||
// Traditionally, leading is %20 of the font size. | ||
var defaultLineSpacingPercent = 1.2; | ||
|
||
var whitePixelCanvasId = 'ID_WHITE_PIXEL'; | ||
var whitePixelSize = new Cartesian2(4, 4); | ||
var whitePixelBoundingRegion = new BoundingRectangle(1, 1, 1, 1); | ||
|
@@ -135,7 +138,7 @@ define([ | |
// presize glyphs to match the new text length | ||
glyphs.length = textLength; | ||
|
||
var showBackground = label._showBackground && (glyphs.length > 0); | ||
var showBackground = label._showBackground && (text.split('\n').join('').length > 0); | ||
var backgroundBillboard = label._backgroundBillboard; | ||
var backgroundBillboardCollection = labelCollection._backgroundBillboardCollection; | ||
if (!showBackground) { | ||
|
@@ -267,107 +270,142 @@ define([ | |
label._repositionAllGlyphs = true; | ||
} | ||
|
||
function calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding) { | ||
if (horizontalOrigin === HorizontalOrigin.CENTER) { | ||
return -lineWidth / 2; | ||
} else if (horizontalOrigin === HorizontalOrigin.RIGHT) { | ||
return -(lineWidth + backgroundPadding.x); | ||
} | ||
return backgroundPadding.x; | ||
} | ||
|
||
// reusable Cartesian2 instances | ||
var glyphPixelOffset = new Cartesian2(); | ||
var scratchBackgroundPadding = new Cartesian2(); | ||
|
||
function repositionAllGlyphs(label, resolutionScale) { | ||
var glyphs = label._glyphs; | ||
var text = label._text; | ||
var glyph; | ||
var dimensions; | ||
var totalWidth = 0; | ||
var maxDescent = Number.NEGATIVE_INFINITY; | ||
var maxY = 0; | ||
var lastLineWidth = 0; | ||
var maxLineWidth = 0; | ||
var lineWidths = []; | ||
var maxGlyphDescent = Number.NEGATIVE_INFINITY; | ||
var maxGlyphY = 0; | ||
var numberOfLines = 1; | ||
var glyphIndex = 0; | ||
var glyphLength = glyphs.length; | ||
|
||
var backgroundBillboard = label._backgroundBillboard; | ||
var backgroundPadding = scratchBackgroundPadding; | ||
Cartesian2.clone( | ||
(defined(backgroundBillboard) ? label._backgroundPadding : Cartesian2.ZERO), | ||
backgroundPadding); | ||
|
||
var glyphIndex = 0; | ||
var glyphLength = glyphs.length; | ||
for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) { | ||
glyph = glyphs[glyphIndex]; | ||
dimensions = glyph.dimensions; | ||
maxY = Math.max(maxY, dimensions.height - dimensions.descent); | ||
maxDescent = Math.max(maxDescent, dimensions.descent); | ||
|
||
//Computing the total width must also account for the kering that occurs between letters. | ||
totalWidth += dimensions.width - dimensions.bounds.minx; | ||
if (glyphIndex < glyphLength - 1) { | ||
totalWidth += glyphs[glyphIndex + 1].dimensions.bounds.minx; | ||
if (text.charAt(glyphIndex) === '\n') { | ||
lineWidths.push(lastLineWidth); | ||
++numberOfLines; | ||
lastLineWidth = 0; | ||
} else { | ||
glyph = glyphs[glyphIndex]; | ||
dimensions = glyph.dimensions; | ||
maxGlyphY = Math.max(maxGlyphY, dimensions.height - dimensions.descent); | ||
maxGlyphDescent = Math.max(maxGlyphDescent, dimensions.descent); | ||
|
||
//Computing the line width must also account for the kerning that occurs between letters. | ||
lastLineWidth += dimensions.width - dimensions.bounds.minx; | ||
if (glyphIndex < glyphLength - 1) { | ||
lastLineWidth += glyphs[glyphIndex + 1].dimensions.bounds.minx; | ||
} | ||
maxLineWidth = Math.max(maxLineWidth, lastLineWidth); | ||
} | ||
} | ||
var maxHeight = maxY + maxDescent; | ||
lineWidths.push(lastLineWidth); | ||
var maxLineHeight = maxGlyphY + maxGlyphDescent; | ||
|
||
var scale = label._scale; | ||
var horizontalOrigin = label._horizontalOrigin; | ||
var widthOffset = 0; | ||
if (horizontalOrigin === HorizontalOrigin.CENTER) { | ||
widthOffset -= totalWidth / 2 * scale; | ||
} else if (horizontalOrigin === HorizontalOrigin.RIGHT) { | ||
widthOffset -= (totalWidth + backgroundPadding.x) * scale; | ||
} else { | ||
widthOffset += backgroundPadding.x * scale; | ||
} | ||
var verticalOrigin = label._verticalOrigin; | ||
var lineIndex = 0; | ||
var lineWidth = lineWidths[lineIndex]; | ||
var widthOffset = calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding); | ||
var lineSpacing = defaultLineSpacingPercent * maxLineHeight; | ||
var otherLinesHeight = lineSpacing * (numberOfLines - 1); | ||
|
||
glyphPixelOffset.x = widthOffset * resolutionScale; | ||
glyphPixelOffset.x = widthOffset * scale * resolutionScale; | ||
glyphPixelOffset.y = 0; | ||
|
||
var verticalOrigin = label._verticalOrigin; | ||
var lineOffsetY = 0; | ||
for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) { | ||
glyph = glyphs[glyphIndex]; | ||
dimensions = glyph.dimensions; | ||
|
||
if (verticalOrigin === VerticalOrigin.BASELINE) { | ||
glyphPixelOffset.y = -dimensions.descent * scale; | ||
} else if (verticalOrigin === VerticalOrigin.TOP) { | ||
glyphPixelOffset.y = -(maxY - dimensions.height + dimensions.descent + backgroundPadding.y) * scale; | ||
} else if (verticalOrigin === VerticalOrigin.CENTER) { | ||
glyphPixelOffset.y = -(maxY - dimensions.height) / 2 * scale - dimensions.descent * scale; | ||
if (text.charAt(glyphIndex) === '\n') { | ||
++lineIndex; | ||
lineOffsetY += lineSpacing; | ||
lineWidth = lineWidths[lineIndex]; | ||
widthOffset = calculateWidthOffset(lineWidth, horizontalOrigin, backgroundPadding); | ||
glyphPixelOffset.x = widthOffset * scale * resolutionScale; | ||
} else { | ||
// VerticalOrigin.BOTTOM | ||
glyphPixelOffset.y = (maxDescent - dimensions.descent + backgroundPadding.y) * scale; | ||
} | ||
glyph = glyphs[glyphIndex]; | ||
dimensions = glyph.dimensions; | ||
|
||
if (verticalOrigin === VerticalOrigin.TOP) { | ||
glyphPixelOffset.y = dimensions.height - maxGlyphY - backgroundPadding.y; | ||
} else if (verticalOrigin === VerticalOrigin.CENTER) { | ||
glyphPixelOffset.y = (otherLinesHeight + dimensions.height - maxGlyphY) / 2; | ||
} else if (verticalOrigin === VerticalOrigin.BASELINE) { | ||
glyphPixelOffset.y = otherLinesHeight; | ||
} else { | ||
// VerticalOrigin.BOTTOM | ||
glyphPixelOffset.y = otherLinesHeight + maxGlyphDescent + backgroundPadding.y; | ||
} | ||
glyphPixelOffset.y = (glyphPixelOffset.y - dimensions.descent - lineOffsetY) * scale * resolutionScale; | ||
|
||
glyphPixelOffset.y *= resolutionScale; | ||
if (defined(glyph.billboard)) { | ||
glyph.billboard._setTranslate(glyphPixelOffset); | ||
} | ||
|
||
if (defined(glyph.billboard)) { | ||
glyph.billboard._setTranslate(glyphPixelOffset); | ||
//Compute the next x offset taking into acocunt the kerning performed | ||
//on both the current letter as well as the next letter to be drawn | ||
//as well as any applied scale. | ||
if (glyphIndex < glyphLength - 1) { | ||
var nextGlyph = glyphs[glyphIndex + 1]; | ||
glyphPixelOffset.x += ((dimensions.width - dimensions.bounds.minx) + nextGlyph.dimensions.bounds.minx) * scale * resolutionScale; | ||
} | ||
} | ||
} | ||
|
||
//Compute the next x offset taking into acocunt the kerning performed | ||
//on both the current letter as well as the next letter to be drawn | ||
//as well as any applied scale. | ||
if (glyphIndex < glyphLength - 1) { | ||
var nextGlyph = glyphs[glyphIndex + 1]; | ||
glyphPixelOffset.x += ((dimensions.width - dimensions.bounds.minx) + nextGlyph.dimensions.bounds.minx) * scale * resolutionScale; | ||
if (defined(backgroundBillboard) && (text.split('\n').join('').length > 0)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a more memory efficient way to do this? text.split('\n').join('').length > 0 If so, does it matter here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This too is part of |
||
if (horizontalOrigin === HorizontalOrigin.CENTER) { | ||
widthOffset = -maxLineWidth / 2 - backgroundPadding.x; | ||
} else if (horizontalOrigin === HorizontalOrigin.RIGHT) { | ||
widthOffset = -(maxLineWidth + backgroundPadding.x * 2); | ||
} else { | ||
widthOffset = 0; | ||
} | ||
} | ||
glyphPixelOffset.x = widthOffset * scale * resolutionScale; | ||
|
||
if (defined(backgroundBillboard) && (glyphLength > 0)) { | ||
glyphPixelOffset.x = (widthOffset - backgroundPadding.x * scale) * resolutionScale; | ||
if (verticalOrigin === VerticalOrigin.BASELINE) { | ||
glyphPixelOffset.y = -backgroundPadding.y * scale - maxDescent * scale; | ||
} else if (verticalOrigin === VerticalOrigin.TOP) { | ||
glyphPixelOffset.y = -(maxY - maxHeight) * scale - maxDescent * scale; | ||
if (verticalOrigin === VerticalOrigin.TOP) { | ||
glyphPixelOffset.y = maxLineHeight - maxGlyphY - maxGlyphDescent; | ||
} else if (verticalOrigin === VerticalOrigin.CENTER) { | ||
glyphPixelOffset.y = -(maxY - maxHeight) / 2 * scale - maxDescent * scale; | ||
glyphPixelOffset.y = (maxLineHeight - maxGlyphY) / 2 - maxGlyphDescent; | ||
} else if (verticalOrigin === VerticalOrigin.BASELINE) { | ||
glyphPixelOffset.y = -backgroundPadding.y - maxGlyphDescent; | ||
} else { | ||
// VerticalOrigin.BOTTOM | ||
glyphPixelOffset.y = 0; | ||
} | ||
glyphPixelOffset.y *= resolutionScale; | ||
backgroundBillboard.width = totalWidth + (backgroundPadding.x * 2); | ||
backgroundBillboard.height = maxHeight + (backgroundPadding.y * 2); | ||
glyphPixelOffset.y = glyphPixelOffset.y * scale * resolutionScale; | ||
|
||
backgroundBillboard.width = maxLineWidth + (backgroundPadding.x * 2); | ||
backgroundBillboard.height = maxLineHeight + otherLinesHeight + (backgroundPadding.y * 2); | ||
backgroundBillboard._setTranslate(glyphPixelOffset); | ||
} | ||
} | ||
|
||
function destroyLabel(labelCollection, label) { | ||
var glyphs = label._glyphs; | ||
for ( var i = 0, len = glyphs.length; i < len; ++i) { | ||
for (var i = 0, len = glyphs.length; i < len; ++i) { | ||
unbindGlyph(labelCollection, glyphs[i]); | ||
} | ||
if (defined(label._backgroundBillboard)) { | ||
|
@@ -628,7 +666,7 @@ define([ | |
LabelCollection.prototype.removeAll = function() { | ||
var labels = this._labels; | ||
|
||
for ( var i = 0, len = labels.length; i < len; ++i) { | ||
for (var i = 0, len = labels.length; i < len; ++i) { | ||
destroyLabel(this, labels[i]); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a scratch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My hope is we don't need a scratch in this case. This function only gets called when the glyphs all need to be repositioned, which is an expensive operation we try to avoid (using the delay tactics you pointed out in the label background PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK