{"spec_id":"barcode-code128","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// barcode-code128: Code 128 Barcode\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-01\n\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Code 128 symbology table (Code Set B) ----------------------------------\n// Index 0-102: data symbols (ASCII 32-126, offset by 32). Index 103-105:\n// START A/B/C. Index 106: STOP body (an extra 2-module termination bar is\n// appended separately, per the standard's 13-module stop character). Each\n// string is the 11-bit bar/space run pattern (1 = bar, 0 = space), always\n// starting with a bar.\nconst CODE128 = [\n  \"11011001100\", \"11001101100\", \"11001100110\", \"10010011000\", \"10010001100\",\n  \"10001001100\", \"10011001000\", \"10011000100\", \"10001100100\", \"11001001000\",\n  \"11001000100\", \"11000100100\", \"10110011100\", \"10011011100\", \"10011001110\",\n  \"10111001100\", \"10011101100\", \"10011100110\", \"11001110010\", \"11001011100\",\n  \"11001001110\", \"11011100100\", \"11001110100\", \"11101101110\", \"11101001100\",\n  \"11100101100\", \"11100100110\", \"11101100100\", \"11100110100\", \"11100110010\",\n  \"11011011000\", \"11011000110\", \"11000110110\", \"10100011000\", \"10001011000\",\n  \"10001000110\", \"10110001000\", \"10001101000\", \"10001100010\", \"11010001000\",\n  \"11000101000\", \"11000100010\", \"10110111000\", \"10110001110\", \"10001101110\",\n  \"10111011000\", \"10111000110\", \"10001110110\", \"11101110110\", \"11010001110\",\n  \"11000101110\", \"11011101000\", \"11011100010\", \"11011101110\", \"11101011000\",\n  \"11101000110\", \"11100010110\", \"11101101000\", \"11101100010\", \"11100011010\",\n  \"11101111010\", \"11001000010\", \"11110001010\", \"10100110000\", \"10100001100\",\n  \"10010110000\", \"10010000110\", \"10000101100\", \"10000100110\", \"10110010000\",\n  \"10110000100\", \"10011010000\", \"10011000010\", \"10000110100\", \"10000110010\",\n  \"11000010010\", \"11001010000\", \"11110111010\", \"11000010100\", \"10001111010\",\n  \"10100111100\", \"10010111100\", \"10010011110\", \"10111100100\", \"10011110100\",\n  \"10011110010\", \"11110100100\", \"11110010100\", \"11110010010\", \"11011011110\",\n  \"11011110110\", \"11110110110\", \"10101111000\", \"10100011110\", \"10001011110\",\n  \"10111101000\", \"10111100010\", \"11110101000\", \"11110100010\", \"10111011110\",\n  \"10111101110\", \"11101011110\", \"11110101110\", \"11010000100\", \"11010010000\",\n  \"11010011100\", \"11000111010\",\n];\nconst START_B = 104;\nconst STOP = 106;\n\n// --- Data: a shipping label, encoded with Code Set B ------------------------\nconst content = \"SHIP-2024-ABC123\";\nconst values = content.split(\"\").map((ch) => ch.charCodeAt(0) - 32);\nlet checksum = START_B;\nvalues.forEach((value, position) => {\n  checksum += value * (position + 1);\n});\nchecksum %= 103;\nconst symbols = [START_B, ...values, checksum, STOP];\n\n// Concatenate every symbol's module pattern into one continuous string, then\n// pad both ends with a quiet zone (spec note: \"include quiet zones on left\n// and right sides for reliable scanning\").\nconst QUIET_ZONE_MODULES = 10;\nlet modules = \"0\".repeat(QUIET_ZONE_MODULES);\nsymbols.forEach((value) => {\n  modules += CODE128[value];\n  if (value === STOP) modules += \"11\"; // trailing termination bar\n});\nmodules += \"0\".repeat(QUIET_ZONE_MODULES);\n\n// --- Fixed \"print\" colors ----------------------------------------------------\n// A barcode must stay high-contrast black-on-white to remain scannable\n// regardless of the surrounding page theme (spec note: \"high contrast black\n// bars on white background for maximum scan reliability\"). So the label card\n// and bars reuse the light-theme paper/ink tokens as FIXED colors — unlike\n// the title chrome below, which still flips with ANYPLOT_THEME. This mirrors\n// the library's own rule that data colors stay identical across themes.\nconst CARD_BG = \"#FAF8F1\";\nconst BAR_INK = \"#1A1A17\";\nconst BAR_INK_SOFT = \"rgba(26, 26, 23, 0.65)\";\nconst CARD_RULE = \"rgba(26, 26, 23, 0.25)\";\n\nconst BAR_TOP = 1;\nconst BAR_BOTTOM = 0.32; // reserves the lower ~32% of the chart area for the human-readable text band\n\nconst labels = modules.split(\"\").map((_, i) => String(i));\nconst data = modules.split(\"\").map((bit) => (bit === \"1\" ? [BAR_BOTTOM, BAR_TOP] : null));\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Plugin: paint the fixed \"label card\" behind the bars, then draw the\n// mandatory human-readable text beneath them (spec note: \"human-readable text\n// should appear below the barcode for visual verification\"). ---------------\nconst labelCardPlugin = {\n  id: \"labelCard\",\n  beforeDatasetsDraw(chart) {\n    const { ctx, chartArea: area } = chart;\n    ctx.save();\n    ctx.fillStyle = CARD_BG;\n    ctx.fillRect(area.left, area.top, area.width, area.height);\n    ctx.strokeStyle = CARD_RULE;\n    ctx.lineWidth = 2;\n    ctx.strokeRect(area.left + 1, area.top + 1, area.width - 2, area.height - 2);\n    ctx.restore();\n  },\n  afterDatasetsDraw(chart) {\n    const { ctx, chartArea: area } = chart;\n    const centerX = area.left + area.width / 2;\n    const bandTop = area.top + area.height * (1 - BAR_BOTTOM * 0.55);\n    ctx.save();\n    ctx.textAlign = \"center\";\n    ctx.textBaseline = \"middle\";\n    ctx.fillStyle = BAR_INK;\n    ctx.font = \"600 30px 'Courier New', monospace\";\n    ctx.fillText(content, centerX, bandTop);\n    ctx.fillStyle = BAR_INK_SOFT;\n    ctx.font = \"400 18px 'Courier New', monospace\";\n    ctx.fillText(`Code 128B · check digit ${checksum} (mod 103)`, centerX, bandTop + 34);\n    ctx.restore();\n  },\n};\n\n// --- Chart -------------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"bar\",\n  data: {\n    labels,\n    datasets: [\n      {\n        data,\n        backgroundColor: BAR_INK,\n        borderWidth: 0,\n        categoryPercentage: 1,\n        barPercentage: 1,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    layout: { padding: { left: 60, right: 60, top: 20, bottom: 40 } },\n    plugins: {\n      title: {\n        display: true,\n        text: \"barcode-code128 · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22, weight: 600 },\n        padding: { bottom: 24 },\n      },\n      legend: { display: false },\n      tooltip: { enabled: false },\n    },\n    scales: {\n      x: { display: false, grid: { display: false } },\n      y: { display: false, min: 0, max: 1, grid: { display: false } },\n    },\n  },\n  plugins: [labelCardPlugin],\n});\n"}