brouter-web: white+black casing under the slope-colored route

leaflet-hotline has a single outlineColor, so render the colored core thin
(outlineWidth 0) and add two plain polylines beneath it in a dedicated pane
just under the hotline pane: a wide black one and a narrower white one — black
rim, white rim, colored core, legible on any map background. Map captured via
L.Map addInitHook to build the casing pane.
This commit is contained in:
4aiman 2026-09-10 00:17:42 +03:00
commit d504315229

View file

@ -120,6 +120,35 @@
var d = prev.distanceTo(cur); if (!d) return 0;
return Math.abs(100 * (((cur.alt) || 0) - ((prev.alt) || 0)) / d); // |grade %|
}
// White+black casing under the colored line so it reads on any background. leaflet-hotline
// has only ONE outlineColor, so we render the colored core thin (no built-in outline) and
// add two plain polylines beneath it in a dedicated pane below the hotline pane: a wide
// black one and a narrower white one — black rim, white rim, colored core.
var CASE_PANE = "baldavCasingPane";
function ensureCasingPane() {
var m = window.BR && BR.__map;
if (!m) return null;
if (!m.getPane(CASE_PANE)) {
m.createPane(CASE_PANE);
var p = m.getPane(CASE_PANE);
if (p) p.style.zIndex = 449; // routingQualityPane is 450 → casings sit just under it
}
return m.getPane(CASE_PANE) ? CASE_PANE : null;
}
function makeCasings(segments) {
var pane = ensureCasingPane(), out = [];
for (var i = 0; segments && i < segments.length; i++) {
var seg = segments[i], r;
if (!seg || !seg.getLatLngs) continue;
if (null !== (r = seg._routing) && void 0 !== r && r.beeline) continue; // skip beelines, as brouter does
var lls = seg.getLatLngs();
var base = { opacity: 1, interactive: false, lineCap: "round", lineJoin: "round" };
if (pane) base.pane = pane;
out.push(L.polyline(lls, L.extend({}, base, { color: "#000000", weight: 12 })));
out.push(L.polyline(lls, L.extend({}, base, { color: "#ffffff", weight: 8 })));
}
return out;
}
function applySlopeProvider(ctrl) {
try {
var pr = ctrl && ctrl.providers && ctrl.providers.incline && ctrl.providers.incline.provider;
@ -127,14 +156,31 @@
pr.hotlineOptions.min = 0;
pr.hotlineOptions.max = 10;
pr.hotlineOptions.palette = slopePalette();
pr.hotlineOptions.weight = 4; // thin colored core over the casings
pr.hotlineOptions.outlineWidth = 0; // no built-in outline; casings provide it
pr.valueFunction = slopeValue;
ctrl._initialProvider = "incline";
ctrl.selectedProvider = "incline";
// Prepend black+white casings to whatever hotlines the provider computes (added first
// = under the colored line). Wrap once.
if (!pr.__baldavCased && typeof pr.computeLayers === "function") {
var orig = pr.computeLayers.bind(pr);
pr.computeLayers = function (segments) {
var hotlines = orig(segments);
try { return makeCasings(segments).concat(hotlines); } catch (e) { return hotlines; }
};
pr.__baldavCased = true;
}
return true;
} catch (e) { return false; }
}
var rqHooked = false;
var rqHooked = false, mapHooked = false;
function registerRouteQuality() {
// Capture the map instance as it's created (needed to make the casing pane).
if (!mapHooked && window.L && L.Map && L.Map.addInitHook) {
mapHooked = true;
L.Map.addInitHook(function () { window.BR = window.BR || {}; BR.__map = this; });
}
if (rqHooked) return;
if (!(window.BR && BR.RoutingPathQuality && BR.RoutingPathQuality.addInitHook)) return;
rqHooked = true;