Skip to content

Commit

Permalink
fix icon text fit
Browse files Browse the repository at this point in the history
We're adding a 1 pixel border around all icons when adding them to the image atlas texture to avoid having neighboring icons bleed into the current image when using linear texture interpolation. When stretching icons to fit the text's dimensions with `icon-text-fit`, however, we didn't account for this correctly: We didn't add the border in this case, resulting in stretched icons that didn't quite cover the whole text. When the difference between the icon's original size and the stretched size was small, this wasn't really noticeable, especially in cases where we were using nearest neighbor texture interpolation instead of linear interpolation. When accounting for the 1 pixel border, have to to take into account that there's no longer a 1:1 mapping between vertex units and pixel units, and expand the vertices adequately.
  • Loading branch information
kkaefer committed Sep 9, 2019
1 parent b8b3f7c commit 49f27a0
Show file tree
Hide file tree
Showing 28 changed files with 230 additions and 58 deletions.
75 changes: 41 additions & 34 deletions src/symbol/quads.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,43 +58,50 @@ export function getIconQuads(anchor: Anchor,
// on one edge in some cases.
const border = 1;

const top = shapedIcon.top - border / image.pixelRatio;
const left = shapedIcon.left - border / image.pixelRatio;
const bottom = shapedIcon.bottom + border / image.pixelRatio;
const right = shapedIcon.right + border / image.pixelRatio;
let tl, tr, br, bl;

// text-fit mode
if (layout.get('icon-text-fit') !== 'none' && shapedText) {
const iconWidth = (right - left),
iconHeight = (bottom - top),
size = layout.get('text-size').evaluate(feature, {}) / 24,
textLeft = shapedText.left * size,
textRight = shapedText.right * size,
textTop = shapedText.top * size,
textBottom = shapedText.bottom * size,
textWidth = textRight - textLeft,
textHeight = textBottom - textTop,
padT = layout.get('icon-text-fit-padding')[0],
padR = layout.get('icon-text-fit-padding')[1],
padB = layout.get('icon-text-fit-padding')[2],
padL = layout.get('icon-text-fit-padding')[3],
offsetY = layout.get('icon-text-fit') === 'width' ? (textHeight - iconHeight) * 0.5 : 0,
offsetX = layout.get('icon-text-fit') === 'height' ? (textWidth - iconWidth) * 0.5 : 0,
width = layout.get('icon-text-fit') === 'width' || layout.get('icon-text-fit') === 'both' ? textWidth : iconWidth,
height = layout.get('icon-text-fit') === 'height' || layout.get('icon-text-fit') === 'both' ? textHeight : iconHeight;
tl = new Point(textLeft + offsetX - padL, textTop + offsetY - padT);
tr = new Point(textLeft + offsetX + padR + width, textTop + offsetY - padT);
br = new Point(textLeft + offsetX + padR + width, textTop + offsetY + padB + height);
bl = new Point(textLeft + offsetX - padL, textTop + offsetY + padB + height);
// Normal icon size mode
const size = layout.get('text-size').evaluate(feature, {}) / 24;
const stretchX = layout.get('icon-text-fit') === 'width' || layout.get('icon-text-fit') === 'both';
const stretchY = layout.get('icon-text-fit') === 'height' || layout.get('icon-text-fit') === 'both';

let left, right;
if (shapedText && stretchX) {
// Stretched horizontally
const padL = layout.get('icon-text-fit-padding')[3];
const padR = layout.get('icon-text-fit-padding')[1];
const textLeft = shapedText.left * size;
const textRight = shapedText.right * size;
const textWidth = textRight - textLeft;
// Expand the box to respect the 1 pixel border in the atlas image.
const expandX = (textWidth * image.paddedRect.w / (image.paddedRect.w - 2 * border) - textWidth) / 2;
left = textLeft - expandX - padL;
right = textRight + expandX + padR;
} else {
tl = new Point(left, top);
tr = new Point(right, top);
br = new Point(right, bottom);
bl = new Point(left, bottom);
// Normal icon size mode
left = shapedIcon.left - border / image.pixelRatio;
right = shapedIcon.right + border / image.pixelRatio;
}

let top, bottom;
if (shapedText && stretchY) {
// Stretched vertically
const padT = layout.get('icon-text-fit-padding')[0];
const padB = layout.get('icon-text-fit-padding')[2];
const textTop = shapedText.top * size;
const textBottom = shapedText.bottom * size;
const textHeight = textBottom - textTop;
// Expand the box to respect the 1 pixel border in the atlas image.
const expandY = (textHeight * image.paddedRect.h / (image.paddedRect.h - 2 * border) - textHeight) / 2;
top = textTop - expandY - padT;
bottom = textBottom + expandY + padB;
} else {
top = shapedIcon.top - border / image.pixelRatio;
bottom = shapedIcon.bottom + border / image.pixelRatio;
}

const tl = new Point(left, top);
const tr = new Point(right, top);
const br = new Point(right, bottom);
const bl = new Point(left, bottom);

const angle = layer.layout.get('icon-rotate').evaluate(feature, {}) * Math.PI / 180;

if (angle) {
Expand Down
7 changes: 0 additions & 7 deletions test/ignores.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@
"render-tests/mixed-zoom/z10-z11": "current behavior conflicts with https://github.com/mapbox/mapbox-gl-js/pull/6803. can be fixed when https://github.com/mapbox/api-maps/issues/1480 is done",
"render-tests/fill-extrusion-pattern/tile-buffer": "https://github.com/mapbox/mapbox-gl-js/issues/4403",
"render-tests/symbol-sort-key/text-ignore-placement": "skip - text drawn over icons",
"render-tests/icon-text-fit/both-padding": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/both": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/height-padding": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/height": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/placement-line": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/width-padding": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/icon-text-fit/width": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/regressions/mapbox-gl-js#5631": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/text-variable-anchor/all-anchors-icon-text-fit": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
"render-tests/text-variable-anchor/icon-text-fit-collision-box": "https://github.com/mapbox/mapbox-gl-js/issues/8583",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/integration/render-tests/icon-text-fit/both/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"version": 8,
"metadata": {
"test": {
"width": 150,
"height": 64
}
},
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "Point",
"coordinates": [
0,
0
]
}
}
},
"sprite": "local://sprites/icon-text-fit",
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"layout": {
"text-field": "ABCD efgh",
"text-size": 24,
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"icon-image": "small-box",
"icon-text-fit": "both",
"icon-text-fit-padding": [ 12, 8, 4, 2 ]
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"version": 8,
"metadata": {
"test": {
"width": 128,
"height": 64
}
},
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "Point",
"coordinates": [
0,
0
]
}
}
},
"sprite": "local://sprites/icon-text-fit",
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"layout": {
"text-field": "ABCD efgh",
"text-size": 24,
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"icon-image": "small-box",
"icon-text-fit": "both"
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"version": 8,
"metadata": {
"test": {
"width": 128,
"height": 64
}
},
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "Point",
"coordinates": [
0,
0
]
}
}
},
"sprite": "local://sprites/icon-text-fit",
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"layout": {
"text-field": "ABCD efgh",
"text-size": 24,
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"icon-image": "small-box",
"icon-text-fit": "height"
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"version": 8,
"metadata": {
"test": {
"width": 128,
"height": 64
}
},
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "Point",
"coordinates": [
0,
0
]
}
}
},
"sprite": "local://sprites/icon-text-fit",
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"layout": {
"text-field": "ABCD efgh",
"text-size": 24,
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"icon-image": "small-box",
"icon-text-fit": "width"
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": 8,
"metadata": {
"test": {
"width": 64,
"width": 96,
"height": 64
}
},
Expand Down
Binary file modified test/integration/render-tests/icon-text-fit/height/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": 8,
"metadata": {
"test": {
"width": 64,
"width": 96,
"height": 64
}
},
Expand Down
Binary file modified test/integration/render-tests/icon-text-fit/none/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": 8,
"metadata": {
"test": {
"width": 64,
"width": 96,
"height": 64
}
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/integration/render-tests/icon-text-fit/width/expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions test/integration/sprites/icon-text-fit.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@
"label": {
"x": 0,
"y": 0,
"width": 240,
"height": 60,
"width": 76,
"height": 38,
"pixelRatio": 1,
"sdf": false
},
"small-box": {
"x": 76,
"y": 0,
"width": 18,
"height": 10,
"pixelRatio": 1,
"sdf": false
},
"tall-box": {
"x": 76,
"y": 10,
"width": 18,
"height": 28,
"pixelRatio": 1,
"sdf": false
}
Expand Down
Binary file modified test/integration/sprites/icon-text-fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 7 additions & 12 deletions test/integration/sprites/icon-text-fit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 49f27a0

Please sign in to comment.