tangram
Version:
WebGL Maps for Vector Tiles
153 lines (125 loc) • 5.96 kB
JavaScript
import Utils from '../../utils/utils';
import StyleParser from '../style_parser';
const TextSettings = {
// A key for grouping all labels of the same text style (e.g. same Canvas state, to minimize state changes)
key (settings) {
return [
settings.style,
settings.weight,
settings.family,
settings.px_size,
settings.fill,
settings.stroke,
settings.stroke_width,
settings.underline_width,
settings.background_color,
settings.background_width,
settings.background_stroke_color,
settings.background_stroke_width,
settings.transform,
settings.text_wrap,
settings.max_lines,
settings.supersample,
Utils.device_pixel_ratio
].join('/');
},
defaults: {
style: 'normal',
weight: 'normal',
size: '12px',
px_size: 12,
family: 'Helvetica',
fill: [1, 1, 1, 1],
text_wrap: 15,
max_lines: 5,
align: 'center'
},
compute (draw, context) {
const style = {};
draw.font = draw.font || this.defaults;
style.supersample = draw.supersample_text ? 1.5 : 1; // optionally render text at 150% to improve clarity
// LineString labels can articulate while point labels cannot. Needed for future texture coordinate calculations.
style.can_articulate = draw.can_articulate;
// Text fill
style.fill = StyleParser.evalCachedColorPropertyWithAlpha(draw.font.fill, draw.font.alpha, context);
style.fill = Utils.toCSSColor(style.fill); // convert to CSS for Canvas
// Text stroke
if (draw.font.stroke && draw.font.stroke.color) {
style.stroke = StyleParser.evalCachedColorPropertyWithAlpha(draw.font.stroke.color, draw.font.stroke.alpha, context);
style.stroke = Utils.toCSSColor(style.stroke); // convert to CSS for Canvas
style.stroke_width = StyleParser.evalCachedProperty(draw.font.stroke.width, context);
}
// Text underline
if (draw.font.underline === true && !style.can_articulate) {
style.underline_width = 1.5 * style.supersample;
}
// Background box
if (draw.font.background && !style.can_articulate) { // supported for point labels only
// Background fill
style.background_color = StyleParser.evalCachedColorPropertyWithAlpha(draw.font.background.color, draw.font.background.alpha, context);
style.background_color = Utils.toCSSColor(style.background_color); // convert to CSS for Canvas
if (style.background_color) {
style.background_width = StyleParser.evalCachedProperty(draw.font.background.width, context);
}
// Background stroke
style.background_stroke_color =
draw.font.background.stroke &&
draw.font.background.stroke.color &&
StyleParser.evalCachedColorPropertyWithAlpha(draw.font.background.stroke.color, draw.font.background.stroke.alpha, context);
if (style.background_stroke_color) {
style.background_stroke_color = Utils.toCSSColor(style.background_stroke_color); // convert to CSS for Canvas
// default background stroke to 1px when stroke color but no stroke width specified
style.background_stroke_width = draw.font.background.stroke.width != null ?
StyleParser.evalCachedProperty(draw.font.background.stroke.width, context) : 1;
}
}
// Font properties are modeled after CSS names:
// - family: Helvetica, Futura, etc.
// - size: in pt, px, or em
// - style: normal, italic, oblique
// - weight: normal, bold, etc.
// - transform: capitalize, uppercase, lowercase
// clamp weight to 1-1000 (see https://drafts.csswg.org/css-fonts-4/#valdef-font-weight-number)
style.weight = StyleParser.evalCachedProperty(draw.font.weight, context) || this.defaults.weight;
if (typeof style.weight === 'number') {
style.weight = Math.min(Math.max(style.weight, 1), 1000);
}
if (draw.font.family) {
style.family = draw.font.family;
if (style.family !== this.defaults.family) {
style.family += ', ' + this.defaults.family;
}
}
else {
style.family = this.defaults.family;
}
style.style = draw.font.style || this.defaults.style;
style.transform = draw.font.transform;
// calculated pixel size
style.px_size = StyleParser.evalCachedProperty(draw.font.px_size, context) * style.supersample;
style.font_css = this.fontCSS(style);
// Word wrap and text alignment
// Not a font properties, but affect atlas of unique text textures
let text_wrap = draw.text_wrap; // use explicitly set value
if (text_wrap == null && !style.can_articulate) {
// point labels (for point and polygon features) have word wrap on w/default max length,
// line labels default off
text_wrap = true;
}
// setting to 'true' causes default wrap value to be used
if (text_wrap === true) {
text_wrap = this.defaults.text_wrap;
}
style.text_wrap = text_wrap;
// max_lines setting to truncate very long labels with an ellipsis
style.max_lines = draw.max_lines || this.defaults.max_lines;
return style;
},
// Build CSS-style font string (to set Canvas draw state)
fontCSS ({ style, weight, px_size, family }) {
return [style, weight, px_size + 'px', family]
.filter(x => x) // remove null props
.join(' ');
}
};
export default TextSettings;