{
  "version": 3,
  "sources": ["route_profile.js"],
  "sourcesContent": ["/*\n * static/js/route_profile.js \u2014 the route profile: one drawing, three pages\n * (SNOW-1215).\n *\n * The lane the map's route panel draws \u2014 one fill per leg under one\n * outline, distance ticks along its foot, and, while a point is placed, a\n * vertical cursor line with a dot where it crosses the outline and the\n * point's elevation and distance beside it. Until SNOW-1215 the drawing\n * lived inside route_rail.js, and the trip pages drew a different profile\n * of their own (trip_map.js's single-colour area). The Plan page and the\n * trip page now draw THIS, from the same markup\n * (templates/includes/_route_profile.html), so a route reads the same on\n * the map, while planning, and on the page the group is sent.\n *\n * DRAWING ONLY. What places the point \u2014 a tap, a scrub, the map's line \u2014\n * is the caller's; route_rail.js owns all of that for the map. A caller\n * hands `cursor(index)` the index it wants drawn, or null to clear it.\n * All the arithmetic is route_rail_core.js's.\n *\n * WHY THE FIGURES ARE HTML. The lane is stretched with\n * `preserveAspectRatio=\"none\"`, which would squash a circle or a glyph, so\n * the tick labels, the dot and the readout are HTML placed by percentage\n * over and under it.\n *\n * Publishes (frozen `window.pwaRouteProfile`):\n *\n *   mount(root, strings) \u2192 view, or null when `root` holds no lane\n *     view.draw(profile, legs, sampleCount, spanM, name)\n *                  \u2014 draw the lane for one route: a `readProfile` result,\n *                    its wire legs, N (the segments the legs index; 0 for\n *                    the outline alone), the route's length for the\n *                    ticks, and its name for the lane's label\n *     view.cursor(index)\n *                  \u2014 draw the cursor line and readout at a sample index,\n *                    or clear them with null\n *     view.indexAt(clientX)\n *                  \u2014 the sample under a viewport x on the lane, clamped\n *                    to the route; null before a draw with legs, or while\n *                    the lane has no width\n *     view.lane    \u2014 the lane's <svg>, for the caller's pointer handlers\n *\n *   read(feature) \u2192 {profile, legs, slope, sampleCount, spanM}\n *                  \u2014 what `draw` takes, read off a route Feature whose\n *                    nested properties may arrive JSON-encoded\n *   sampleCountOf(slope, legs) \u2192 N\n *                  \u2014 `slope.angles`' length when the route has one, else\n *                    the last leg's `to` plus one: legs ride on an\n *                    unsampled route too, in the segment indices its\n *                    record will have (apps/routes/services/leg_wire.py)\n *\n *   `strings` holds `unit-m`, `unit-km` and `lane-label`, the partial's\n *   strings template's keys.\n */\n\n(function routeProfileInit() {\n  'use strict';\n\n  var SVG_NS = 'http://www.w3.org/2000/svg';\n  /** The space between the cursor line and its figures, px: clear of the dot. */\n  var READOUT_GAP_PX = 9;\n\n  /**\n   * Create one SVG element with attributes.\n   *\n   * @param {string} tag\n   * @param {Object<string, string>} attrs\n   * @returns {SVGElement}\n   */\n  function svgEl(tag, attrs) {\n    var el = document.createElementNS(SVG_NS, tag);\n    Object.keys(attrs).forEach(function (key) {\n      el.setAttribute(key, attrs[key]);\n    });\n    return el;\n  }\n\n  /**\n   * Read a feature property that may arrive JSON-encoded.\n   *\n   * The routes cache holds real objects, but a feature MapLibre handed\n   * back stringifies nested properties, and a caller may pass either.\n   *\n   * @param {*} value\n   * @returns {*}\n   */\n  function readJson(value) {\n    if (typeof value !== 'string') return value;\n    try {\n      return JSON.parse(value);\n    } catch (_err) {\n      return null;\n    }\n  }\n\n  /**\n   * N, the segments a route's legs index.\n   *\n   * @param {?{angles?: Array}} slope The route's slope record, or null.\n   * @param {Array} legs The route's wire legs.\n   * @returns {number} 0 with neither.\n   */\n  function sampleCountOf(slope, legs) {\n    if (slope && Array.isArray(slope.angles) && slope.angles.length) {\n      return slope.angles.length;\n    }\n    var last = legs.length ? legs[legs.length - 1] : null;\n    return last && Number.isInteger(last.to) ? last.to + 1 : 0;\n  }\n\n  /**\n   * Read what `draw` takes off one route Feature.\n   *\n   * A route with no legs at all \u2014 no elevation, or too short \u2014 reads as\n   * N = 0 and no legs: the outline alone, with no point to place.\n   *\n   * @param {{geometry?: {coordinates?: Array}, properties?: object}} feature\n   * @returns {{profile: object, legs: Array, slope: *, sampleCount: number, spanM: number}}\n   */\n  function read(feature) {\n    var props = (feature && feature.properties) || {};\n    var slope = readJson(props.slope);\n    var wireLegs = readJson(props.legs);\n    var legs = Array.isArray(wireLegs) ? wireLegs : [];\n    var sampleCount = sampleCountOf(slope, legs);\n    if (!(sampleCount > 0)) legs = [];\n    var coordinates = feature && feature.geometry && feature.geometry.coordinates;\n    var profile = self.pwaElevationProfileCore.readProfile(\n      Array.isArray(coordinates) ? coordinates : [],\n    );\n    var spanM = typeof props.distance_m === 'number' ? props.distance_m : profile.distanceM;\n    return { profile: profile, legs: legs, slope: slope, sampleCount: sampleCount, spanM: spanM };\n  }\n\n  /**\n   * Bind a view to one profile's markup.\n   *\n   * @param {ParentNode} root An element holding _route_profile.html.\n   * @param {Object<string, string>} strings The partial's strings.\n   * @returns {?{draw: Function, cursor: Function, indexAt: function(number): ?number, lane: Element}}\n   */\n  function mount(root, strings) {\n    var lane = root && root.querySelector('[data-route-rail-lane]');\n    var ticksEl = root && root.querySelector('[data-route-rail-ticks]');\n    if (!lane || !ticksEl) return null;\n    var readoutEl = /** @type {HTMLElement|null} */ (root.querySelector('[data-route-rail-readout]'));\n    var dotEl = /** @type {HTMLElement|null} */ (root.querySelector('[data-route-rail-dot]'));\n    var elevationEl = /** @type {HTMLElement|null} */ (root.querySelector('[data-route-rail-elevation]'));\n    var distanceEl = /** @type {HTMLElement|null} */ (root.querySelector('[data-route-rail-distance]'));\n    var interpolate = self.pwaStrings.interpolate;\n    var units = { m: strings['unit-m'], km: strings['unit-km'] };\n\n    /** The drawn route's readProfile result, or null. */\n    var profile = null;\n    /** N, the segments the drawn route's legs index; 0 with no legs. */\n    var sampleCount = 0;\n    /** The route's length a point's distance is a share of. */\n    var spanM = 0;\n\n    /**\n     * Draw the lane: the leg fills, the outline, the tick marks, and the\n     * tick labels under it.\n     *\n     * @param {object} nextProfile A readProfile result.\n     * @param {Array} legs The route's wire legs.\n     * @param {number} nextSampleCount N; 0 when the route has no legs.\n     * @param {number} nextSpanM The route's length for the tick labels.\n     * @param {string} name The route's name, for the lane's label.\n     */\n    function draw(nextProfile, legs, nextSampleCount, nextSpanM, name) {\n      var core = self.pwaRouteRailCore;\n      var box = core.BOX;\n      profile = nextProfile;\n      sampleCount = nextSampleCount;\n      spanM = nextSpanM;\n      lane.replaceChildren();\n      ticksEl.replaceChildren();\n      lane.setAttribute('viewBox', '0 0 ' + box.width + ' ' + box.height);\n      lane.setAttribute('aria-label', interpolate(strings['lane-label'], { name: name }));\n\n      var paths = core.legPaths(profile, legs, sampleCount, box);\n\n      paths.legs.forEach(function (fill) {\n        lane.appendChild(svgEl('path', {\n          d: fill.d,\n          class: 'route-rail-leg',\n          'data-climbing': fill.climbing ? 'true' : 'false',\n        }));\n      });\n\n      if (paths.outline) {\n        lane.appendChild(svgEl('path', {\n          d: paths.outline,\n          fill: 'none',\n          stroke: 'currentColor',\n          'stroke-width': '1.5',\n          'stroke-linejoin': 'round',\n          'vector-effect': 'non-scaling-stroke',\n          'pointer-events': 'none',\n        }));\n      }\n\n      if (!(spanM > 0)) return;\n      core.ticks(spanM, units).forEach(function (tick) {\n        var fraction = tick.d / spanM;\n        var x = (fraction * box.width).toFixed(2);\n        lane.appendChild(svgEl('line', {\n          x1: x,\n          x2: x,\n          y1: String(box.height - (tick.major ? 8 : 4)),\n          y2: String(box.height),\n          stroke: 'currentColor',\n          'stroke-opacity': tick.major ? '0.5' : '0.25',\n          'vector-effect': 'non-scaling-stroke',\n          'pointer-events': 'none',\n          class: 'text-text-3',\n        }));\n        if (!tick.label) return;\n        var label = document.createElement('span');\n        // The first label hangs right of its tick and the rest are centred\n        // on theirs, so \"0 km\" is not cut off at the lane's left edge. None\n        // wraps: an absolute box near the right edge shrinks to the space\n        // left, which broke \"15 km\" over two lines on a phone.\n        label.className = fraction === 0\n          ? 'absolute top-0 whitespace-nowrap'\n          : 'absolute top-0 -translate-x-1/2 whitespace-nowrap';\n        label.style.left = (fraction * 100).toFixed(3) + '%';\n        label.textContent = tick.label;\n        ticksEl.appendChild(label);\n      });\n    }\n\n    /**\n     * Place the dot and the two figures for the cursor index, or hide them.\n     *\n     * The dot sits where the line crosses the outline (`profileY`); a point\n     * on a stretch with no elevation gets no dot and no elevation, and\n     * still its distance. The figures go right of the line, left-aligned,\n     * unless they would not fit before the lane's right edge\n     * (`readoutSide`).\n     *\n     * @param {?number} index The cursor index; null to hide.\n     */\n    function paintReadout(index) {\n      if (!readoutEl || !dotEl || !elevationEl || !distanceEl) return;\n      var core = self.pwaRouteRailCore;\n      if (index === null || !(sampleCount > 0) || !profile) {\n        readoutEl.hidden = true;\n        return;\n      }\n      var fraction = (index + 0.5) / sampleCount;\n      var percent = fraction * 100;\n      var elevation = core.pointElevation(profile, index, sampleCount, units);\n      var distance = core.pointDistance(index, sampleCount, spanM, units);\n      var y = core.profileY(profile, fraction * profile.distanceM);\n\n      elevationEl.textContent = elevation || '';\n      elevationEl.hidden = !elevation;\n      distanceEl.textContent = distance || '';\n      distanceEl.hidden = !distance;\n      dotEl.hidden = y === null;\n      if (y !== null) {\n        dotEl.style.left = percent.toFixed(3) + '%';\n        dotEl.style.top = ((y / core.BOX.height) * 100).toFixed(3) + '%';\n      }\n      readoutEl.hidden = false;\n\n      // Measured once shown, so the widths are the rendered ones.\n      var laneWidth = lane.getBoundingClientRect().width;\n      var widest = Math.max(\n        elevationEl.getBoundingClientRect().width,\n        distanceEl.getBoundingClientRect().width,\n      );\n      var side = core.readoutSide(fraction * laneWidth, laneWidth, widest, READOUT_GAP_PX);\n      readoutEl.setAttribute('data-side', side);\n      [elevationEl, distanceEl].forEach(function (label) {\n        if (side === 'right') {\n          label.style.left = 'calc(' + percent.toFixed(3) + '% + ' + READOUT_GAP_PX + 'px)';\n          label.style.right = '';\n        } else {\n          label.style.right = 'calc(' + (100 - percent).toFixed(3) + '% + ' + READOUT_GAP_PX + 'px)';\n          label.style.left = '';\n        }\n      });\n    }\n\n    /**\n     * Draw the cursor index as a vertical line across the lane (SNOW-1019),\n     * with its dot and its figures (2026-10-02).\n     *\n     * Placed by share, the rule the leg fills follow: sample i owns the\n     * i-th of N shares, and the line sits at its middle. Removed while the\n     * index is null.\n     *\n     * @param {?number} index The cursor index.\n     */\n    function cursor(index) {\n      var line = lane.querySelector('[data-route-rail-cursor]');\n      if (index === null || index === undefined || !(sampleCount > 0)) {\n        if (line) line.remove();\n        paintReadout(null);\n        return;\n      }\n      var box = self.pwaRouteRailCore.BOX;\n      if (!line) {\n        line = svgEl('line', {\n          'data-route-rail-cursor': '',\n          y1: '0',\n          y2: String(box.height),\n          stroke: 'currentColor',\n          'stroke-width': '1.5',\n          'vector-effect': 'non-scaling-stroke',\n          'pointer-events': 'none',\n          class: 'text-text-1',\n        });\n        lane.appendChild(line);\n      }\n      var x = (((index + 0.5) / sampleCount) * box.width).toFixed(2);\n      line.setAttribute('x1', x);\n      line.setAttribute('x2', x);\n      paintReadout(index);\n    }\n\n    /**\n     * The sample under a viewport x on the lane, clamped to the route.\n     *\n     * The inverse of `cursor`'s placement: sample i owns the i-th of N\n     * equal shares of the lane's width.\n     *\n     * @param {number} clientX The pointer's x.\n     * @returns {?number} Null with no legs drawn or no lane width.\n     */\n    function indexAt(clientX) {\n      if (!(sampleCount > 0)) return null;\n      var rect = lane.getBoundingClientRect();\n      if (!(rect.width > 0)) return null;\n      var at = Math.floor(((clientX - rect.left) / rect.width) * sampleCount);\n      return Math.min(sampleCount - 1, Math.max(0, at));\n    }\n\n    return Object.freeze({ draw: draw, cursor: cursor, indexAt: indexAt, lane: lane });\n  }\n\n  self.pwaRouteProfile = Object.freeze({\n    mount: mount,\n    read: read,\n    sampleCountOf: sampleCountOf,\n  });\n})();\n"],
  "mappings": "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",
  "names": ["SVG_NS", "READOUT_GAP_PX", "svgEl", "tag", "attrs", "el", "key", "readJson", "value", "sampleCountOf", "slope", "legs", "last", "read", "feature", "props", "wireLegs", "sampleCount", "coordinates", "profile", "spanM", "mount", "root", "strings", "lane", "ticksEl", "readoutEl", "dotEl", "elevationEl", "distanceEl", "interpolate", "units", "draw", "nextProfile", "nextSampleCount", "nextSpanM", "name", "core", "box", "paths", "fill", "tick", "fraction", "x", "label", "paintReadout", "index", "percent", "elevation", "distance", "y", "laneWidth", "widest", "side", "cursor", "line", "indexAt", "clientX", "rect", "at"]
}
