tile-painter
Version:
Parse Mapbox style documents into rendering functions
62 lines (48 loc) • 1.87 kB
JavaScript
import { initTextLabeler } from "./text.js";
import { initIconLabeler } from "./icons.js";
export function initLabeler(layout, paint, sprite, tileSize) {
// Skip unsupported symbol types
if (layout["symbol-placement"]() === "line") return () => undefined;
return function(ctx, zoom, data, boxes, scale = 1) {
const font = data.properties.font;
const textLabeler = initTextLabeler(zoom, layout, paint, font);
const iconLabeler = initIconLabeler(zoom, layout, paint, sprite);
const tileScale = tileSize * scale;
const tileBox = [[0, 0], [tileScale, tileScale]];
if (scale != 1) {
let invScale = 1 / scale;
ctx.scale(invScale, invScale);
}
textLabeler.setState(ctx);
data.compressed.forEach(drawLabel);
if (scale != 1) ctx.scale(scale, scale);
function drawLabel(feature) {
// Find bounding box and other info for the sprite and text
let icon = iconLabeler.measure(feature, scale);
if ( icon && collides(icon.bbox) ) return;
let text = textLabeler.measure(feature, scale);
if ( text && collides(text.bbox) ) return;
if (icon) boxes.push(icon.bbox);
if (text) boxes.push(text.bbox);
// Draw the labels, IF they are inside the tile
if ( icon && intersects(tileBox, icon.bbox) ) {
iconLabeler.draw(ctx, icon);
}
if ( text && intersects(tileBox, text.bbox) ) {
textLabeler.draw(ctx, text);
}
}
function collides(newBox) {
if (!newBox) return false;
return boxes.some( box => intersects(box, newBox) );
}
}
}
function intersects(box1, box2) {
// box[0] = [xmin, ymin]; box[1] = [xmax, ymax]
if (box1[0][0] > box2[1][0]) return false;
if (box2[0][0] > box1[1][0]) return false;
if (box1[0][1] > box2[1][1]) return false;
if (box2[0][1] > box1[1][1]) return false;
return true;
}