{"spec_id":"area-mountain-panorama","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// area-mountain-panorama: Mountain Panorama Profile with Labeled Peaks\n// Library: highcharts 12.6.0 | JavaScript 22.23.0\n// Quality: 84/100 | Created: 2026-06-30\n\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\nconst THEME = window.ANYPLOT_THEME;\n\n// Spec requires 'dark solid color silhouette / evening/dusk feel' — rock and sky\n// tones use thematic custom colors for geographic authenticity (justified by spec).\nconst ROCK_FILL  = THEME === \"dark\" ? \"#3A3830\" : \"#29261F\";\nconst ROCK_LINE  = THEME === \"dark\" ? \"#5A5750\" : \"#3F3C35\";\nconst SKY_TOP    = THEME === \"dark\" ? \"#0D1820\" : \"#BBD5E8\";\nconst SKY_BOTTOM = THEME === \"dark\" ? \"#1A1A17\" : \"#FAF8F1\";\n\n// --- Ridgeline control points: [panorama_x (0–1000), elevation_m] ---\n// Wallis (Valais) Alps panorama viewed from Gornergrat area — SSE to NNW\n// x=0 ≈ 155° bearing (SSE), x=1000 ≈ 330° bearing (NNW)\nconst ctrlPts = [\n  [0,    2600],\n  [30,   3100],\n  [60,   4634],  // Monte Rosa / Dufourspitze  4634 m\n  [95,   3750],\n  [130,  4527],  // Liskamm                    4527 m\n  [158,  3580],\n  [185,  4223],  // Castor                     4223 m\n  [210,  3960],\n  [225,  4092],  // Pollux                     4092 m\n  [248,  3720],\n  [272,  4164],  // Breithorn                  4164 m\n  [305,  3350],\n  [330,  2900],  // col toward Zermatt valley\n  [360,  3200],\n  [380,  3700],\n  [400,  4478],  // Matterhorn — focal peak    4478 m\n  [420,  3600],  // steep east flank\n  [445,  2950],\n  [490,  3100],\n  [540,  4358],  // Dent Blanche               4358 m\n  [568,  3500],\n  [590,  4063],  // Ober Gabelhorn             4063 m\n  [610,  3750],\n  [640,  4221],  // Zinalrothorn               4221 m\n  [668,  3580],\n  [720,  4506],  // Weisshorn                  4506 m\n  [755,  3650],\n  [820,  4545],  // Dom                        4545 m (highest peak entirely in Switzerland)\n  [842,  4200],\n  [858,  4491],  // Täschhorn                  4491 m\n  [875,  3850],\n  [890,  4206],  // Alphubel                   4206 m\n  [908,  3900],\n  [925,  4027],  // Allalinhorn                4027 m\n  [942,  3950],\n  [955,  4199],  // Rimpfischhorn              4199 m\n  [970,  4020],\n  [980,  4190],  // Strahlhorn                 4190 m\n  [1000, 3200],\n];\n\n// Piecewise-linear ridgeline with deterministic LCG noise (seed 42, sharp rocky texture)\nlet _lcgS = 42 >>> 0;\nconst ridgelineData = [];\nfor (let i = 0; i < 800; i++) {\n  const x = (i / 799) * 1000;\n  let lo = 0;\n  for (let j = 0; j < ctrlPts.length - 1; j++) {\n    if (ctrlPts[j][0] <= x) lo = j;\n  }\n  const hi = Math.min(lo + 1, ctrlPts.length - 1);\n  const span = ctrlPts[hi][0] - ctrlPts[lo][0];\n  const frac = span > 0 ? (x - ctrlPts[lo][0]) / span : 0;\n  const elev = ctrlPts[lo][1] + frac * (ctrlPts[hi][1] - ctrlPts[lo][1]);\n  _lcgS = (_lcgS * 1664525 + 1013904223) >>> 0;\n  ridgelineData.push([Math.round(x * 10) / 10, Math.round(elev + (_lcgS / 4294967296 - 0.5) * 55)]);\n}\n\n// --- Peak annotations ---\n// yOff: pixels above summit (negative = up); xOff: horizontal shift to stagger clustered labels\nconst annotatedPeaks = [\n  { name: \"Monte Rosa\",     sub: \"4634 m\", x: 60,  elev: 4634, yOff: -65,  xOff: 0   },\n  { name: \"Liskamm\",        sub: \"4527 m\", x: 130, elev: 4527, yOff: -90,  xOff: 0   },\n  { name: \"Castor\",         sub: \"4223 m\", x: 185, elev: 4223, yOff: -55,  xOff: -18 },\n  { name: \"Pollux\",         sub: \"4092 m\", x: 225, elev: 4092, yOff: -85,  xOff: 18  },\n  { name: \"Breithorn\",      sub: \"4164 m\", x: 272, elev: 4164, yOff: -60,  xOff: 0   },\n  { name: \"Matterhorn\",     sub: \"4478 m\", x: 400, elev: 4478, yOff: -120, xOff: 0   },\n  { name: \"Dent Blanche\",   sub: \"4358 m\", x: 540, elev: 4358, yOff: -65,  xOff: 0   },\n  { name: \"Ober Gabelhorn\", sub: \"4063 m\", x: 590, elev: 4063, yOff: -85,  xOff: -25 },\n  { name: \"Zinalrothorn\",   sub: \"4221 m\", x: 640, elev: 4221, yOff: -60,  xOff: 20  },\n  { name: \"Weisshorn\",      sub: \"4506 m\", x: 720, elev: 4506, yOff: -90,  xOff: 0   },\n  { name: \"Dom\",            sub: \"4545 m\", x: 820, elev: 4545, yOff: -65,  xOff: -45 },\n  { name: \"Täschhorn\",      sub: \"4491 m\", x: 858, elev: 4491, yOff: -100, xOff: 25  },\n  { name: \"Alphubel\",       sub: \"4206 m\", x: 890, elev: 4206, yOff: -68,  xOff: -35 },\n  { name: \"Allalinhorn\",    sub: \"4027 m\", x: 925, elev: 4027, yOff: -130, xOff: -30 },\n  { name: \"Rimpfischhorn\",  sub: \"4199 m\", x: 955, elev: 4199, yOff: -80,  xOff: 25  },\n  { name: \"Strahlhorn\",     sub: \"4190 m\", x: 980, elev: 4190, yOff: -120, xOff: 10  },\n];\n\nconst TITLE =\n  \"Wallis Alps Panorama · area-mountain-panorama · javascript · highcharts · anyplot.ai\";\n\n// --- Chart ---\nconst chart = Highcharts.chart(\"container\", {\n  chart: {\n    type: \"area\",\n    backgroundColor: \"transparent\",\n    plotBackgroundColor: {\n      linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },\n      stops: [[0, SKY_TOP], [1, SKY_BOTTOM]],\n    },\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    margin: [130, 35, 55, 80],\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: TITLE,\n    style: { color: t.ink, fontSize: \"18px\", fontWeight: \"600\" },\n    y: 24,\n  },\n  xAxis: {\n    min: 0,\n    max: 1000,\n    // compass bearing labels at S=143, SW=400, W=657, NW=914\n    tickPositions: [143, 400, 657, 914],\n    labels: {\n      formatter: function () {\n        const compassLabels = { 143: \"S\", 400: \"SW\", 657: \"W\", 914: \"NW\" };\n        return compassLabels[this.value] || \"\";\n      },\n      style: { color: t.inkSoft, fontSize: \"13px\" },\n    },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineWidth: 0,\n    title: { text: null },\n  },\n  yAxis: {\n    min: 2500,\n    title: {\n      text: \"Elevation (m)\",\n      style: { color: t.inkSoft, fontSize: \"14px\" },\n    },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: \"13px\" } },\n  },\n  legend: { enabled: false },\n  tooltip: { enabled: false },\n  plotOptions: {\n    series: { animation: false },\n    area: {\n      lineWidth: 1.5,\n      lineColor: ROCK_LINE,\n      fillColor: ROCK_FILL,\n      marker: { enabled: false },\n    },\n  },\n  series: [{ name: \"Ridgeline\", data: ridgelineData }],\n});\n\n// --- Peak annotations: thin leader lines + two-line labels via SVGRenderer ---\nannotatedPeaks.forEach(function (peak) {\n  const px = chart.xAxis[0].toPixels(peak.x, false);\n  const py = chart.yAxis[0].toPixels(peak.elev, false);\n  const lx = px + peak.xOff;\n  const ly = py + peak.yOff;\n  const isMatterhorn = peak.name === \"Matterhorn\";\n\n  // Thin leader line from summit point to label anchor\n  chart.renderer\n    .path([\"M\", px, py - 10, \"L\", lx, ly + 22])\n    .attr({ stroke: t.inkSoft, \"stroke-width\": 0.8, zIndex: 4 })\n    .add();\n\n  // Peak name — Matterhorn gets stronger visual weight as the focal peak\n  chart.renderer\n    .text(peak.name, lx, ly)\n    .attr({ align: \"center\", zIndex: 5 })\n    .css({\n      color: isMatterhorn ? t.ink : t.inkSoft,\n      fontSize: isMatterhorn ? \"12px\" : \"11px\",\n      fontWeight: isMatterhorn ? \"800\" : \"700\",\n    })\n    .add();\n\n  // Elevation sub-label\n  chart.renderer\n    .text(peak.sub, lx, ly + 14)\n    .attr({ align: \"center\", zIndex: 5 })\n    .css({ color: t.inkSoft, fontSize: \"10px\" })\n    .add();\n});\n"}