{"spec_id":"subplot-mosaic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// subplot-mosaic: Mosaic Subplot Layout with Varying Sizes\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 94/100 | Created: 2026-09-09\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Deterministic PRNG (LCG) -----------------------------------------------\nfunction makeLcg(seed) {\n  let state = seed;\n  return () => {\n    state = (state * 1664525 + 1013904223) % 4294967296;\n    return state / 4294967296;\n  };\n}\nconst rand = makeLcg(42);\n\n// --- Data --------------------------------------------------------------\n// Panel A: dominant overview — weekly website traffic across a full year.\nconst weeks = Array.from({ length: 52 }, (_, i) => `W${i + 1}`);\nconst weeklyVisits = weeks.map((_, i) => {\n  const trend = 8200 + i * 42;\n  const seasonal = 900 * Math.sin((i / 52) * 4 * Math.PI) + (i > 40 ? 2400 * ((i - 40) / 12) : 0);\n  const noise = (rand() - 0.5) * 800;\n  return Math.round(trend + seasonal + noise);\n});\n\n// Panel B: medium detail — traffic share by device.\nconst devices = [\"Desktop\", \"Mobile\", \"Tablet\"];\nconst deviceVisits = [186000, 142000, 31000];\n\n// Panel C: medium detail — session duration vs. pages viewed.\nconst sessionPoints = Array.from({ length: 45 }, () => {\n  const pages = Number((1 + rand() * 9).toFixed(1));\n  const duration = Number((pages * 1.7 + rand() * 3.5).toFixed(1));\n  return [pages, duration];\n});\n\n// Panels D/E/F: small quarterly metric tiles.\nconst quarters = [\"Q1\", \"Q2\", \"Q3\", \"Q4\"];\nconst bounceRate = [52, 47, 44, 41];\nconst avgSessionMin = [3.1, 3.4, 3.8, 4.2];\nconst conversionRate = [2.1, 2.4, 2.9, 3.3];\n\n// --- Mosaic layout geometry (percent of container) --------------------------\n// Pattern:  AAAA\n//           BBCC\n//           DEF\n// A wide overview on top, two medium detail panels in the middle row,\n// three small metric tiles on the bottom row.\nconst GRID_A = { left: \"5%\", right: \"5%\", top: \"13%\", height: \"26%\", containLabel: true };\nconst GRID_B = { left: \"5%\", width: \"42%\", top: \"46%\", height: \"22%\", containLabel: true };\nconst GRID_C = { left: \"53%\", width: \"42%\", top: \"46%\", height: \"22%\", containLabel: true };\nconst GRID_D = { left: \"5%\", width: \"27%\", top: \"76%\", height: \"18%\", containLabel: true };\nconst GRID_E = { left: \"36.5%\", width: \"27%\", top: \"76%\", height: \"18%\", containLabel: true };\nconst GRID_F = { left: \"68%\", width: \"27%\", top: \"76%\", height: \"18%\", containLabel: true };\n\nconst tileAxis = {\n  axisLabel: { color: t.inkSoft, fontSize: 11 },\n  axisLine: { show: false },\n  axisTick: { show: false },\n};\n\n// --- Init ---------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option ---------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  textStyle: { color: t.inkSoft },\n  title: [\n    {\n      text: \"subplot-mosaic · javascript · echarts · anyplot.ai\",\n      left: \"center\",\n      top: \"2%\",\n      textStyle: { color: t.ink, fontSize: 22 },\n    },\n    { text: \"Weekly Website Traffic — Full Year\", left: \"5%\", top: \"9%\",\n      textStyle: { color: t.ink, fontSize: 16, fontWeight: 500 } },\n    { text: \"Traffic Share by Device\", left: \"5%\", top: \"42%\",\n      textStyle: { color: t.ink, fontSize: 15, fontWeight: 500 } },\n    { text: \"Session Duration vs. Pages Viewed\", left: \"53%\", top: \"42%\",\n      textStyle: { color: t.ink, fontSize: 15, fontWeight: 500 } },\n    { text: \"Bounce Rate (%)\", left: \"5%\", top: \"72%\",\n      textStyle: { color: t.inkSoft, fontSize: 13, fontWeight: 500 } },\n    { text: \"Avg. Session (min)\", left: \"36.5%\", top: \"72%\",\n      textStyle: { color: t.inkSoft, fontSize: 13, fontWeight: 500 } },\n    { text: \"Conversion Rate (%)\", left: \"68%\", top: \"72%\",\n      textStyle: { color: t.inkSoft, fontSize: 13, fontWeight: 500 } },\n  ],\n  grid: [GRID_A, GRID_B, GRID_C, GRID_D, GRID_E, GRID_F],\n  xAxis: [\n    { gridIndex: 0, type: \"category\", data: weeks, boundaryGap: false,\n      axisLabel: { color: t.inkSoft, fontSize: 12, interval: 7 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false } },\n    { gridIndex: 1, type: \"category\", data: devices,\n      axisLabel: { color: t.inkSoft, fontSize: 13 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false } },\n    { gridIndex: 2, type: \"value\", name: \"Pages / Session\", nameLocation: \"middle\", nameGap: 28,\n      nameTextStyle: { color: t.inkSoft, fontSize: 12 },\n      axisLabel: { color: t.inkSoft, fontSize: 12 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false },\n      splitLine: { lineStyle: { color: t.grid } } },\n    { gridIndex: 3, type: \"category\", data: quarters, ...tileAxis },\n    { gridIndex: 4, type: \"category\", data: quarters, ...tileAxis },\n    { gridIndex: 5, type: \"category\", data: quarters, ...tileAxis },\n  ],\n  yAxis: [\n    { gridIndex: 0, type: \"value\",\n      axisLabel: { color: t.inkSoft, fontSize: 12 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false },\n      splitLine: { lineStyle: { color: t.grid } } },\n    { gridIndex: 1, type: \"value\",\n      axisLabel: { color: t.inkSoft, fontSize: 12 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false },\n      splitLine: { lineStyle: { color: t.grid } } },\n    { gridIndex: 2, type: \"value\", name: \"Duration (min)\", nameLocation: \"middle\", nameGap: 40,\n      nameTextStyle: { color: t.inkSoft, fontSize: 12 },\n      axisLabel: { color: t.inkSoft, fontSize: 12 },\n      axisLine: { lineStyle: { color: t.inkSoft } }, axisTick: { show: false },\n      splitLine: { lineStyle: { color: t.grid } } },\n    { gridIndex: 3, type: \"value\", ...tileAxis, splitLine: { show: false } },\n    { gridIndex: 4, type: \"value\", ...tileAxis, splitLine: { show: false } },\n    { gridIndex: 5, type: \"value\", ...tileAxis, splitLine: { show: false } },\n  ],\n  series: [\n    { name: \"Weekly Visits\", type: \"line\", xAxisIndex: 0, yAxisIndex: 0,\n      data: weeklyVisits, smooth: true, symbol: \"none\",\n      lineStyle: { width: 3 }, areaStyle: { opacity: 0.15 },\n      markLine: {\n        symbol: \"none\",\n        lineStyle: { color: t.inkSoft, type: \"dashed\", width: 1.5 },\n        label: { color: t.inkSoft, fontSize: 12, formatter: (p) => `avg ${Math.round(p.value).toLocaleString()}` },\n        data: [{ type: \"average\", name: \"Average\" }],\n      },\n      markPoint: {\n        symbol: \"circle\",\n        symbolSize: 11,\n        itemStyle: { color: t.palette[0], borderColor: t.pageBg, borderWidth: 2 },\n        label: { position: \"top\", color: t.ink, fontSize: 13, fontWeight: 600,\n          formatter: (p) => Math.round(p.value).toLocaleString() },\n        data: [{ type: \"max\", name: \"Peak\" }],\n      } },\n    { name: \"Visits by Device\", type: \"bar\", xAxisIndex: 1, yAxisIndex: 1,\n      data: deviceVisits, barWidth: \"50%\", itemStyle: { opacity: 0.85 } },\n    { name: \"Sessions\", type: \"scatter\", xAxisIndex: 2, yAxisIndex: 2,\n      data: sessionPoints, symbolSize: 12, itemStyle: { opacity: 0.85 } },\n    { name: \"Bounce Rate\", type: \"bar\", xAxisIndex: 3, yAxisIndex: 3,\n      data: bounceRate, barWidth: \"55%\", itemStyle: { opacity: 0.6 } },\n    { name: \"Avg Session\", type: \"line\", xAxisIndex: 4, yAxisIndex: 4,\n      data: avgSessionMin, smooth: true, symbol: \"circle\", symbolSize: 8,\n      lineStyle: { width: 3, opacity: 0.6 }, itemStyle: { opacity: 0.6 } },\n    { name: \"Conversion\", type: \"bar\", xAxisIndex: 5, yAxisIndex: 5,\n      data: conversionRate, barWidth: \"55%\", itemStyle: { opacity: 0.6 } },\n  ],\n});\n"}