{"spec_id":"chessboard-basic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// chessboard-basic: Chess Board Grid Visualization\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 88/100 | Created: 2026-09-01\n//# anyplot-orientation: square\n// anyplot.ai\n// chessboard-basic: Chess Board Grid Visualization\n// Library: Highcharts 12.6.0 | Node 22\n// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license)\n// Quality: pending | Created: 2026-09-01\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\nconst files = [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"];\nconst ranks = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\"];\n\n// Only the dark squares are rendered as points — the light squares are the\n// plain page background showing through, so the two-tone contrast comes from\n// the surface rather than a second invented data color. Standard chess\n// coloring puts light squares on h1 and a8, so a square is dark when the\n// file index + rank index is even.\nconst darkSquares = [];\nfor (let file = 0; file < 8; file++) {\n  for (let rank = 0; rank < 8; rank++) {\n    if ((file + rank) % 2 === 0) {\n      darkSquares.push({ x: file, y: rank, name: files[file] + ranks[rank] });\n    }\n  }\n}\n\n// --- Chart -------------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"scatter\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    events: {\n      load: function () {\n        // Square markers are sized in pixels, not data units, so the exact\n        // tile size is only known once the plot area is laid out. Category\n        // axes reserve 0.5 units of padding on each side by default, so each\n        // of the 8 cells spans plotSize / 9 pixels — size the marker radius\n        // to that so adjacent squares tile edge-to-edge with no gaps.\n        const cell = Math.min(this.plotSizeX, this.plotSizeY) / 9;\n        this.series[0].points.forEach((point) => {\n          point.update({ marker: { radius: cell / 2 } }, false);\n        });\n        this.redraw();\n      },\n    },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"chessboard-basic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  xAxis: {\n    categories: files,\n    lineWidth: 0,\n    tickLength: 0,\n    gridLineWidth: 0,\n    labels: { style: { color: t.inkSoft, fontSize: \"18px\" } },\n  },\n  yAxis: {\n    categories: ranks,\n    lineWidth: 0,\n    tickLength: 0,\n    gridLineWidth: 0,\n    title: { text: null },\n    labels: { style: { color: t.inkSoft, fontSize: \"18px\" } },\n  },\n  legend: { enabled: false },\n  tooltip: {\n    backgroundColor: t.elevatedBg,\n    style: { color: t.ink, fontSize: \"14px\" },\n    formatter: function () {\n      return \"Square \" + this.point.name;\n    },\n  },\n  plotOptions: {\n    series: { animation: false, states: { hover: { enabled: false } } },\n  },\n  series: [\n    {\n      name: \"Dark squares\",\n      data: darkSquares,\n      // Semantic exception (default-style-guide.md): wood -> ochre, not the\n      // ordinal-first brand green, so the board reads as an authentic chess\n      // board rather than an abstract checker grid.\n      color: t.palette[3],\n      marker: { symbol: \"square\", radius: 40, lineWidth: 0 },\n    },\n  ],\n});\n"}