diff --git a/src/symbol/projection.js b/src/symbol/projection.js index c242bfc0858..177b81528b6 100644 --- a/src/symbol/projection.js +++ b/src/symbol/projection.js @@ -6,8 +6,6 @@ const mat4 = require('@mapbox/gl-matrix').mat4; const vec4 = require('@mapbox/gl-matrix').vec4; const symbolSize = require('./symbol_size'); -const offscreenPoint = new Point(-Infinity, -Infinity); - module.exports = { updateLineLabels: updateLineLabels, getLabelPlaneMatrix: getLabelPlaneMatrix, @@ -140,12 +138,8 @@ function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, vec4.transformMat4(anchorPos, anchorPos, posMatrix); // Don't bother calculating the correct point for invisible labels. - // Hide them by moving them offscreen. We still need to add them to the buffer - // because the dynamic buffer is paired with a static buffer that doesn't get updated. if (!isVisible(anchorPos, symbol, clippingBuffer, painter)) { - for (let i = symbol.numGlyphs; i > 0; i--) { - addGlyph(offscreenPoint, 0, dynamicLayoutVertexArray); - } + hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray); continue; } @@ -178,8 +172,18 @@ function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, glyphsBackward.push(glyph); } } - processDirection(glyphsForward, 1, flip, symbol, lineVertexArray, dynamicLayoutVertexArray, labelPlaneMatrix, fontScale); - processDirection(glyphsBackward, -1, flip, symbol, lineVertexArray, dynamicLayoutVertexArray, labelPlaneMatrix, fontScale); + + const returnGlyphs = []; + if ( + processDirection(returnGlyphs, glyphsForward, 1, flip, symbol, lineVertexArray, labelPlaneMatrix, fontScale) && + processDirection(returnGlyphs, glyphsBackward, -1, flip, symbol, lineVertexArray, labelPlaneMatrix, fontScale)) { + for (const glyph of returnGlyphs) { + addGlyph(glyph.point, glyph.angle, dynamicLayoutVertexArray); + } + } else { + hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray); + continue; + } } if (isText) { @@ -189,7 +193,7 @@ function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, } } -function processDirection(glyphs, dir, flip, symbol, lineVertexArray, dynamicLayoutVertexArray, labelPlaneMatrix, fontScale) { +function processDirection(returnGlyphs, glyphs, dir, flip, symbol, lineVertexArray, labelPlaneMatrix, fontScale) { assert(symbol.lineLength > 1); let prev = project(new Point(symbol.anchorX, symbol.anchorY), labelPlaneMatrix); @@ -225,7 +229,8 @@ function processDirection(glyphs, dir, flip, symbol, lineVertexArray, dynamicLay // If the current segment doesn't have enough remaining space, iterate forward along the line. // Since all the glyphs are sorted by their distance from the anchor you never need to iterate backwards. // This way line vertices are projected at most once. - while (offsetX >= segmentDistance + previousDistance && Math.abs(vertexIndex) < numVertices) { + while (offsetX >= segmentDistance + previousDistance) { + if (Math.abs(vertexIndex) >= numVertices) return false; previousDistance += segmentDistance; prev = next; next = project(lineVertexArray.get(vertexStartIndex + vertexIndex), labelPlaneMatrix); @@ -237,10 +242,20 @@ function processDirection(glyphs, dir, flip, symbol, lineVertexArray, dynamicLay // The point is on the current segment. Interpolate to find it. const segmentInterpolationT = (offsetX - previousDistance) / segmentDistance; const p = next.sub(prev)._mult(segmentInterpolationT)._add(prev); - addGlyph(p, segmentAngle, dynamicLayoutVertexArray); + returnGlyphs.push({ point: p, angle: segmentAngle }); } + return true; } +const offscreenPoint = new Point(-Infinity, -Infinity); + +// Hide them by moving them offscreen. We still need to add them to the buffer +// because the dynamic buffer is paired with a static buffer that doesn't get updated. +function hideGlyphs(num, dynamicLayoutVertexArray) { + for (let i = 0; i < num; i++) { + addGlyph(offscreenPoint, 0, dynamicLayoutVertexArray); + } +} function addGlyph(p, angle, dynamicLayoutVertexArray) { dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle); dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle);