Skip to content

Commit

Permalink
add support for text box stroke (and alpha on box fill and stroke col…
Browse files Browse the repository at this point in the history
…ors)
  • Loading branch information
bcamper committed Jul 21, 2020
1 parent fd58bb5 commit f4d7fea
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 37 deletions.
35 changes: 27 additions & 8 deletions src/styles/text/text_canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default class TextCanvas {

// Computes width and height of text based on current font style
// Includes word wrapping, returns size info for whole text block and individual lines
textSize (style, text, {transform, text_wrap, max_lines, stroke_width = 0, background, supersample}) {
textSize(style, text, { transform, text_wrap, max_lines, stroke_width = 0, background_color, background_stroke_width, supersample}) {
// Check cache first
TextCanvas.cache.text[style] = TextCanvas.cache.text[style] || {};
if (TextCanvas.cache.text[style][text]) {
Expand All @@ -147,7 +147,7 @@ export default class TextCanvas {
const ctx = this.context;
const vertical_buffer = this.vertical_text_buffer * dpr;
const horizontal_buffer = dpr * (stroke_width + this.horizontal_text_buffer);
const background_size = background ? this.background_size * dpr : 0;
const background_size = background_color ? (this.background_size + background_stroke_width) * dpr : 0;
const leading = 2 * dpr; // make configurable and/or use Canvas TextMetrics when available
const line_height = this.px_size + leading; // px_size already in device pixels

Expand Down Expand Up @@ -188,16 +188,35 @@ export default class TextCanvas {
const { dpr, collision_size, texture_size, line_height, horizontal_buffer, vertical_buffer } = size;

// draw optional background box
if (text_settings.background) {
// TODO: allow background stroke without fill?
if (text_settings.background_color) {
const background_stroke_color = text_settings.background_stroke_color;
const background_stroke_width = text_settings.background_stroke_width * dpr;

this.context.save();
this.context.fillStyle = text_settings.background;
this.context.fillStyle = text_settings.background_color;
this.context.fillRect(
// shift to "foreground" stroke texture for curved labels (separate stroke and fill textures)
x + horizontal_buffer + (label_type === 'curved' ? texture_size[0] : 0),
y + vertical_buffer,
dpr * collision_size[0],
dpr * collision_size[1]
x + horizontal_buffer + (label_type === 'curved' ? texture_size[0] : 0) + background_stroke_width,
y + vertical_buffer + background_stroke_width,
dpr * collision_size[0] - background_stroke_width * 2,
dpr * collision_size[1] - background_stroke_width * 2
);

// optional stroke around background box
if (background_stroke_color && background_stroke_width) {
this.context.strokeStyle = background_stroke_color;
this.context.lineWidth = background_stroke_width;
this.context.strokeRect(
// shift to "foreground" stroke texture for curved labels (separate stroke and fill textures)
x + horizontal_buffer + (label_type === 'curved' ? texture_size[0] : 0) + background_stroke_width * 0.5,
y + vertical_buffer + background_stroke_width * 0.5,
dpr * collision_size[0] - background_stroke_width,
dpr * collision_size[1] - background_stroke_width
);

}

this.context.restore();
}

Expand Down
12 changes: 11 additions & 1 deletion src/styles/text/text_labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,28 @@ export const TextLabels = {

// Colors
draw.font.fill = StyleParser.createPropertyCache(draw.font.fill);
draw.font.background = StyleParser.createPropertyCache(draw.font.background);
draw.font.alpha = StyleParser.createPropertyCache(draw.font.alpha);
if (draw.font.stroke) {
draw.font.stroke.color = StyleParser.createPropertyCache(draw.font.stroke.color);
draw.font.stroke.alpha = StyleParser.createPropertyCache(draw.font.stroke.alpha);
}
if (draw.font.background) {
draw.font.background.color = StyleParser.createPropertyCache(draw.font.background.color);
draw.font.background.alpha = StyleParser.createPropertyCache(draw.font.background.alpha);
if (draw.font.background.stroke) {
draw.font.background.stroke.color = StyleParser.createPropertyCache(draw.font.background.stroke.color);
draw.font.background.stroke.alpha = StyleParser.createPropertyCache(draw.font.background.stroke.alpha);
}
}

// Convert font and text stroke sizes
draw.font.px_size = StyleParser.createPropertyCache(draw.font.size || TextSettings.defaults.size, TextCanvas.fontPixelSize, TextCanvas.fontPixelSize);
if (draw.font.stroke && draw.font.stroke.width != null) {
draw.font.stroke.width = StyleParser.createPropertyCache(draw.font.stroke.width, StyleParser.parsePositiveNumber);
}
if (draw.font.background && draw.font.background.stroke && draw.font.background.stroke.width != null) {
draw.font.background.stroke.width = StyleParser.createPropertyCache(draw.font.background.stroke.width, StyleParser.parsePositiveNumber);
}

// Offset (2d array)
draw.offset = StyleParser.createPropertyCache(draw.offset,
Expand Down
79 changes: 51 additions & 28 deletions src/styles/text/text_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const TextSettings = {
settings.fill,
settings.stroke,
settings.stroke_width,
settings.background,
settings.background_color,
settings.background_stroke_color,
settings.background_stroke_width,
settings.transform,
settings.text_wrap,
settings.max_lines,
Expand Down Expand Up @@ -45,25 +47,61 @@ const TextSettings = {
// LineString labels can articulate while point labels cannot. Needed for future texture coordinate calculations.
style.can_articulate = draw.can_articulate;

// Use fill if specified, or default
// Text fill
style.fill = draw.font.fill && StyleParser.evalCachedColorProperty(draw.font.fill, context);
if (!style.can_articulate) { // background color box for point labels only
style.background = draw.font.background && StyleParser.evalCachedColorProperty(draw.font.background, context);
}

// optional alpha override
const alpha = StyleParser.evalCachedProperty(draw.font.alpha, context);
const alpha = StyleParser.evalCachedProperty(draw.font.alpha, context); // optional alpha override
if (alpha != null) {
style.fill = [...(style.fill ? style.fill : this.defaults.fill_array)]; // copy to avoid modifying underlying object
style.fill[3] = alpha;
}
style.fill = (style.fill && Utils.toCSSColor(style.fill)) || this.defaults.fill; // convert to CSS for Canvas

if (style.background) {
style.background = [...style.background]; // copy to avoid modifying underlying object
style.background[3] = alpha;
// Text stroke
if (draw.font.stroke && draw.font.stroke.color) {
style.stroke = StyleParser.evalCachedColorProperty(draw.font.stroke.color, context);
if (style.stroke) {
// optional alpha override
const stroke_alpha = StyleParser.evalCachedProperty(draw.font.stroke.alpha, context);
if (stroke_alpha != null) {
style.stroke = [...style.stroke]; // copy to avoid modifying underlying object
style.stroke[3] = stroke_alpha;
}
style.stroke = Utils.toCSSColor(style.stroke); // convert to CSS for Canvas
}
style.stroke_width = StyleParser.evalCachedProperty(draw.font.stroke.width, context);
}

// Background box
if (draw.font.background && !style.can_articulate) { // supported for point labels only
// Background fill
style.background_color = draw.font.background.color && StyleParser.evalCachedColorProperty(draw.font.background.color, context);
if (style.background_color) {
const background_alpha = draw.font.background.alpha && StyleParser.evalCachedProperty(draw.font.background.alpha, context);
if (background_alpha) {
style.background_color = [...style.background_color];
style.background_color[3] = background_alpha;
}
style.background_color = Utils.toCSSColor(style.background_color); // convert to CSS for Canvas
}

// Background stroke
style.background_stroke_color =
draw.font.background.stroke &&
draw.font.background.stroke.color &&
StyleParser.evalCachedColorProperty(draw.font.background.stroke.color, context);
if (style.background_stroke_color) {
const background_stroke_alpha = draw.font.background.stroke.alpha && StyleParser.evalCachedProperty(draw.font.background.stroke.alpha, context);
if (background_stroke_alpha) {
style.background_stroke_color = [...style.background_stroke_color];
style.background_stroke_color[3] = background_stroke_alpha;
}
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;
}
}
style.fill = (style.fill && Utils.toCSSColor(style.fill)) || this.defaults.fill; // convert to CSS for Canvas
style.background = (style.background && Utils.toCSSColor(style.background));

// Font properties are modeled after CSS names:
// - family: Helvetica, Futura, etc.
Expand Down Expand Up @@ -93,21 +131,6 @@ const TextSettings = {
style.supersample = draw.supersample_text ? 1.5 : 1; // optionally render text at 150% to improve clarity
style.px_size = StyleParser.evalCachedProperty(draw.font.px_size, context) * style.supersample;

// Use stroke if specified
if (draw.font.stroke && draw.font.stroke.color) {
style.stroke = StyleParser.evalCachedColorProperty(draw.font.stroke.color, context);
if (style.stroke) {
// optional alpha override
const stroke_alpha = StyleParser.evalCachedProperty(draw.font.stroke.alpha, context);
if (stroke_alpha != null) {
style.stroke = [...style.stroke]; // copy to avoid modifying underlying object
style.stroke[3] = stroke_alpha;
}
style.stroke = Utils.toCSSColor(style.stroke); // convert to CSS for Canvas
}
style.stroke_width = StyleParser.evalCachedProperty(draw.font.stroke.width, context);
}

style.font_css = this.fontCSS(style);

// Word wrap and text alignment
Expand Down

0 comments on commit f4d7fea

Please sign in to comment.