UNPKG

protomaps-leaflet

Version:

Vector tile rendering and labeling for [Leaflet](https://github.com/Leaflet/Leaflet).

106 lines (105 loc) 3.51 kB
import Point from "@mapbox/point-geometry"; // code from https://github.com/naturalatlas/linelabel (Apache2) const linelabel = (pts, maxAngleDelta, targetLen) => { const chunks = []; let a; let b; let c; let i = 0; let n = 0; let d = 0; let abmag = 0; let bcmag = 0; let abx = 0; let aby = 0; let bcx = 0; let bcy = 0; let dt = 0; let iStart = 0; let dStart = 0; if (pts.length < 2) return []; if (pts.length === 2) { d = Math.sqrt(Math.pow((pts[1].x - pts[0].x), 2) + Math.pow((pts[1].y - pts[0].y), 2)); return [ { length: d, beginIndex: 0, beginDistance: 0, endIndex: 2, endDistance: d, }, ]; } abmag = Math.sqrt(Math.pow((pts[1].x - pts[0].x), 2) + Math.pow((pts[1].y - pts[0].y), 2)); for (i = 1, n = pts.length - 1; i < n; i++) { a = pts[i - 1]; b = pts[i]; c = pts[i + 1]; abx = b.x - a.x; aby = b.y - a.y; bcx = c.x - b.x; bcy = c.y - b.y; bcmag = Math.sqrt(bcx * bcx + bcy * bcy); d += abmag; dt = Math.acos((abx * bcx + aby * bcy) / (abmag * bcmag)); if (dt > maxAngleDelta || d - dStart > targetLen) { chunks.push({ length: d - dStart, beginDistance: dStart, beginIndex: iStart, endIndex: i + 1, endDistance: d, }); iStart = i; dStart = d; } abmag = bcmag; } if (i - iStart > 0) { chunks.push({ length: d - dStart + bcmag, beginIndex: iStart, beginDistance: dStart, endIndex: i + 1, endDistance: d + bcmag, }); } return chunks; }; export function simpleLabel(mls, minimum, repeatDistance, cellSize) { const candidates = []; for (const ls of mls) { const segments = linelabel(ls, Math.PI / 45, minimum); // 4 degrees, close to a straight line for (const segment of segments) { if (segment.length >= minimum + cellSize) { const start = new Point(ls[segment.beginIndex].x, ls[segment.beginIndex].y); const end = ls[segment.endIndex - 1]; const normalized = new Point((end.x - start.x) / segment.length, (end.y - start.y) / segment.length); // offset from the start by cellSize to allow streets that meet at right angles // to both be labeled. for (let i = cellSize; i < segment.length - minimum; i += repeatDistance) { candidates.push({ start: start.add(normalized.mult(i)), end: start.add(normalized.mult(i + minimum)), }); } } } } return candidates; } export function lineCells(a, b, length, spacing) { // determine function of line const dx = b.x - a.x; const dy = b.y - a.y; const dist = Math.sqrt(Math.pow((b.x - a.x), 2) + Math.pow((b.y - a.y), 2)); const retval = []; // starting from the anchor, generate square cells, // guaranteeing to cover the endpoint for (let i = 0; i < length + spacing; i += 2 * spacing) { const factor = (i * 1) / dist; retval.push({ x: a.x + factor * dx, y: a.y + factor * dy }); } return retval; }