{"id":2970,"date":"2026-05-06T11:53:05","date_gmt":"2026-05-06T04:53:05","guid":{"rendered":"https:\/\/nlguitar.com\/?page_id=2970"},"modified":"2026-05-12T23:30:02","modified_gmt":"2026-05-12T16:30:02","slug":"diagram-chord-pro","status":"publish","type":"page","link":"https:\/\/nlguitar.com\/en\/diagram-chord-pro\/","title":{"rendered":"Diagram Chord Pro"},"content":{"rendered":"\t\t<div data-elementor-type=\"masteriyo-course-archive-page\" data-elementor-id=\"2970\" class=\"elementor elementor-2970\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54db9c4 e-flex e-con-boxed e-con e-parent\" data-id=\"54db9c4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fc28b3b elementor-widget elementor-widget-heading\" data-id=\"fc28b3b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Diagram Chord Pro<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ae4e04a elementor-widget elementor-widget-text-editor\" data-id=\"ae4e04a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>C\u00f4ng c\u1ee5 t\u1ea1o Chord v\u00e0 Scale cho Guitar\/Bass\/Ukulele hi\u1ec7n \u0111\u1ea1i v\u00e0 ho\u00e0n to\u00e0n mi\u1ec5n ph\u00ed.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cc0b005 e-flex e-con-boxed e-con e-parent\" data-id=\"cc0b005\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e4827d1 elementor-widget elementor-widget-shortcode\" data-id=\"e4827d1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\n    <style>\n        :root {\n            --primary-blue: #2563eb;\n            --text-dark: #334155;\n            --text-gray: #475569;\n            --border-color: #cbd5e1;\n            --bg-gray: #f8fafc;\n            --success-green: #10b981;\n            --btn-download: #23d79b;\n        }\n        .creator-container * { box-sizing: border-box; }\n        \n        .creator-container { width: 100%; max-width: 1100px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; color: var(--text-dark); background-color: #ffffff; padding: 30px; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.04); border: 1px solid #cbd5e1 !important; margin-bottom: 20px; }\n        \n        .settings-panel { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px 30px; transition: all 0.3s ease; margin-bottom: 10px; }\n        .settings-panel.collapsed .advanced-setting { display: none; }\n        .form-group { display: flex; flex-direction: column; gap: 8px; }\n        .form-group label { font-size: 14px; color: #333; font-weight: 500; margin-bottom: 0; }\n        \n        .creator-container input[type=\"text\"]:not(.dot-text-input), .creator-container input[type=\"number\"] { padding: 10px !important; border: 1px solid #cbd5e1 !important; border-radius: 6px !important; font-size: 14px !important; outline: none !important; width: 100% !important; color: var(--text-dark) !important; background: #ffffff !important; box-shadow: none !important;}\n        \n        .creator-container input[type=\"text\"].dot-text-input { \n            width: 36px !important; min-width: 36px !important; max-width: 36px !important; \n            height: 24px !important; padding: 0 !important; text-align: center !important; \n            border: 2px solid var(--primary-blue) !important; border-radius: 4px !important; \n            background: white !important; color: #333 !important; outline: none !important;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.15) !important;\n            pointer-events: auto !important; \n            position: absolute !important;\n            z-index: 100 !important;\n        }\n\n        .checkbox-group { display: flex; align-items: center; gap: 8px; margin-top: 25px; font-size: 14px;}\n        .checkbox-group input { cursor: pointer; width: 16px; height: 16px;}\n        \n        .btn-reset { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 10px; border: 1px solid #ef4444 !important; color: #ef4444; border-radius: 6px; font-weight: 500; cursor: pointer; transition: 0.2s; width: 100%; font-size: 14px; background: transparent; }\n        .btn-reset:hover { background: #fef2f2; }\n        \n        .reset-popup { position: absolute; bottom: calc(100% + 15px); left: 50%; transform: translateX(-50%); background: white; border: 1px solid #e2e8f0 !important; padding: 16px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); z-index: 110; display: flex; flex-direction: column; align-items: center; opacity: 1; visibility: visible; transition: 0.2s; min-width: 200px; }\n        .reset-popup.hidden { opacity: 0; visibility: hidden; transform: translateX(-50%) translateY(10px); }\n        .reset-popup::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 8px; border-style: solid; border-color: white transparent transparent transparent; }\n        \n        .btn-popup-yes, .btn-popup-no { background: #f1f5f9; color: #1e293b; border: none !important; padding: 8px 20px; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500; transition: 0.2s; }\n        .btn-popup-yes:hover { background: #fee2e2; color: #ef4444; }\n        .btn-popup-no:hover { background: #e2e8f0; }\n        \n        .toggle-settings { color: var(--primary-blue); background: none !important; border: none !important; font-size: 15px; cursor: pointer; display: flex; justify-content: flex-start; align-items: center; gap: 5px; padding: 10px 0; font-weight: 500; margin: 0 0 20px 0; width: 100%; }\n        \n        .workspace-area { position: relative; width: 100%; border: 1px solid #cbd5e1 !important; border-radius: 12px; background: white !important; z-index: 1; margin-bottom: 20px; overflow: hidden; }\n        .scroll-wrapper { width: 100%; overflow-x: auto; padding: 40px 10px; text-align: center; }\n        .canvas-container { position: relative; display: inline-block; text-align: left;}\n        canvas { max-width: none !important; }\n        \n        .toolbar-container { position: absolute; top: 20px; right: 20px; z-index: 100; }\n        .toolbar { display: flex; flex-direction: column; gap: 10px; }\n        \n        .btn-tool { display: flex; justify-content: center; align-items: center; width: 44px; height: 44px; border: 2px solid #e2e8f0 !important; background: white !important; color: #64748b; border-radius: 8px; cursor: pointer; transition: all 0.2s; box-shadow: 0 4px 10px rgba(0,0,0,0.03); }\n        .btn-tool:hover { color: var(--primary-blue) !important; border-color: var(--primary-blue) !important; background: #eff6ff !important; }\n        .btn-tool.active { background: var(--primary-blue) !important; color: white !important; border-color: var(--primary-blue) !important; box-shadow: 0 4px 12px rgba(37,99,235,0.25); }\n        .btn-clear { color: #94a3b8; }\n        .btn-clear:hover { background: #fef2f2 !important; color: #ef4444 !important; border-color: #ef4444 !important; }\n        .btn-tool svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }\n\n        .color-popover { position: absolute; background: white !important; border: 1px solid #cbd5e1 !important; padding: 12px; border-radius: 10px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); display: none; flex-direction: column; gap: 10px; z-index: 9999; width: 160px; }\n        .color-popover.active { display: flex; }\n\n        .download-section { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; width: 100%; }\n        .btn-dl { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 16px; border: 1px solid var(--btn-download) !important; background: white !important; color: var(--btn-download) !important; border-radius: 6px; cursor: pointer; font-weight: 600; transition: 0.2s; font-size: 14px; }\n        .btn-dl:hover { background: var(--btn-download) !important; color: white !important; }\n\n        @media (max-width: 768px) { \n            .creator-container { padding: 10px; border-radius: 8px; } \n            .settings-panel { grid-template-columns: repeat(2, 1fr); gap: 12px; } \n            .toolbar-container { position: fixed; bottom: 25px; left: 50%; right: auto; top: auto; transform: translateX(-50%); z-index: 1000; }\n            .toolbar { flex-direction: row; background: rgba(255,255,255,0.95) !important; padding: 8px; border-radius: 15px; box-shadow: 0 5px 25px rgba(0,0,0,0.2); backdrop-filter: blur(10px); gap: 10px; }\n            .scroll-wrapper { padding: 20px 5px 100px 5px; }\n            .download-section { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; width: 100%; }\n            .btn-dl { width: 100%; padding: 12px 5px; font-size: 13px; }\n        }\n    <\/style>\n\n    <div class=\"creator-container\">\n        <!-- 1. C\u00c0I \u0110\u1eb6T -->\n        <form id=\"chordForm\">\n            <div class=\"settings-panel\" id=\"settingsPanel\">\n                <div class=\"form-group\"><label>Ti\u00eau \u0111\u1ec1<\/label><input type=\"text\" id=\"chordTitle\" value=\"Cmaj7\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group\"><label>Ng\u0103n b\u1eaft \u0111\u1ea7u<\/label><input type=\"number\" id=\"startFret\" value=\"1\" min=\"1\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group\"><label>S\u1ed1 ng\u0103n<\/label><input type=\"number\" id=\"numFrets\" value=\"5\" min=\"3\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group\"><label>S\u1ed1 d\u00e2y<\/label><input type=\"number\" id=\"numStrings\" value=\"6\" min=\"4\" max=\"8\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group advanced-setting\"><label>Chi\u1ec1u cao ng\u0103n<\/label><input type=\"range\" id=\"fretHeight\" min=\"30\" max=\"100\" value=\"60\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group advanced-setting\"><label>K\u00edch th\u01b0\u1edbc n\u1ed1t<\/label><input type=\"range\" id=\"fingerSize\" min=\"8\" max=\"30\" value=\"14\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group advanced-setting\"><label>C\u1ee1 ch\u1eef trong n\u1ed1t<\/label><input type=\"range\" id=\"fingerFontSize\" min=\"8\" max=\"30\" value=\"14\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"form-group advanced-setting\"><label>C\u1ee1 ch\u1eef ti\u00eau \u0111\u1ec1<\/label><input type=\"range\" id=\"titleFontSize\" min=\"15\" max=\"50\" value=\"25\" oninput=\"drawCanvas()\"><\/div>\n                <div class=\"checkbox-group advanced-setting\"><input type=\"checkbox\" id=\"hidePosition\" onchange=\"drawCanvas()\"><label>\u1ea8n v\u1ecb tr\u00ed<\/label><\/div>\n                <div class=\"checkbox-group advanced-setting\"><input type=\"checkbox\" id=\"showMarkers\" checked onchange=\"drawCanvas()\"><label>Hi\u1ec7n d\u1ea5u ng\u0103n<\/label><\/div>\n                <div class=\"checkbox-group advanced-setting\"><input type=\"checkbox\" id=\"showFretNumbers\" onchange=\"drawCanvas()\"><label>Hi\u1ec7n s\u1ed1 ng\u0103n<\/label><\/div>\n                \n                \n                <div class=\"advanced-setting\" style=\"display: flex; align-items: center; margin-top: 25px; position: relative;\">\n                    <button type=\"button\" class=\"btn-reset\" onclick=\"toggleResetConfirm()\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"><\/path><path d=\"M3 3v5h5\"><\/path><\/svg> Kh\u00f4i ph\u1ee5c<\/button>\n                    <div id=\"resetConfirmPopup\" class=\"reset-popup hidden\">\n                        <span style=\"font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 12px; display:block; text-align:center;\">Kh\u00f4i ph\u1ee5c c\u00e0i \u0111\u1eb7t?<\/span>\n                        <div style=\"display: flex; gap: 10px; justify-content: center;\">\n                            <button type=\"button\" class=\"btn-popup-yes\" onclick=\"executeReset()\">C\u00f3<\/button>\n                            <button type=\"button\" class=\"btn-popup-no\" onclick=\"toggleResetConfirm()\">Kh\u00f4ng<\/button>\n                        <\/div>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/form>\n\n        <button class=\"toggle-settings\" id=\"btnToggle\" onclick=\"toggleSettingsPanel()\"><span id=\"toggleIcon\">\ufe3f<\/span> <span id=\"toggleText\">\u1ea8n c\u00e0i \u0111\u1eb7t...<\/span><\/button>\n\n        <!-- 2. KHU V\u1ef0C S\u01a0 \u0110\u1ed2 CH\u00cdNH -->\n        <div class=\"workspace-area\">\n            <div class=\"toolbar-container\">\n                <div class=\"toolbar\">\n                    <button class=\"btn-tool active\" id=\"btnFinger\" onclick=\"setMode('finger')\" title=\"Ch\u1ea5m N\u1ed1t\"><svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\"\/><path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\"\/><\/svg><\/button>\n                    <button class=\"btn-tool\" id=\"btnText\" onclick=\"setMode('text')\" title=\"Th\u00eam Ch\u1eef\"><svg viewBox=\"0 0 24 24\"><polyline points=\"4 7 4 4 20 4 20 7\"\/><line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"\/><\/svg><\/button>\n                    <button class=\"btn-tool\" id=\"btnColor\" onclick=\"setMode('color')\" title=\"\u0110\u1ed5i M\u00e0u\"><svg viewBox=\"0 0 24 24\"><path d=\"M12 22a10 10 0 1 1 10-10c0 2.53-2.04 4.58-4.57 4.58-1.5 0-2.81-.88-3.46-2.14a4 4 0 0 0-7.44 2A4 4 0 0 0 12 22z\"\/><circle cx=\"7.5\" cy=\"10.5\" r=\"1.5\" fill=\"currentColor\"\/><circle cx=\"11.5\" cy=\"7.5\" r=\"1.5\" fill=\"currentColor\"\/><circle cx=\"16.5\" cy=\"10.5\" r=\"1.5\" fill=\"currentColor\"\/><\/svg><\/button>\n                    <button class=\"btn-tool\" id=\"btnShape\" onclick=\"setMode('shape')\" title=\"\u0110\u1ed5i H\u00ecnh D\u1ea1ng\"><svg viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"\/><circle cx=\"17.5\" cy=\"6.5\" r=\"3.5\"\/><polygon points=\"12 21 7 14 17 14\"\/><\/svg><\/button>\n                    \n                    <button class=\"btn-tool\" onclick=\"toggleOrientation()\" title=\"Xoay d\u1ecdc \/ ngang\">\n                        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n                            <path d=\"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"><\/path>\n                            <path d=\"M3 3v5h5\"><\/path>\n                            <path d=\"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16\"><\/path>\n                            <path d=\"M21 21v-5h-5\"><\/path>\n                        <\/svg>\n                    <\/button>\n                    \n                    <button class=\"btn-tool btn-clear\" onclick=\"clearDiagram()\" title=\"L\u00e0m m\u1edbi s\u01a1 \u0111\u1ed3\"><svg viewBox=\"0 0 24 24\"><path d=\"M3 6h18\" \/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" \/><\/svg><\/button>\n                <\/div>\n            <\/div>\n            \n            <div class=\"scroll-wrapper\">\n                <div class=\"canvas-container\" id=\"mainCanvasContainer\">\n                    <canvas id=\"chordCanvas\"><\/canvas>\n                    <div id=\"textInputsContainer\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;\"><\/div>\n                    \n                    <div id=\"colorPopover\" class=\"color-popover\">\n                        <div class=\"color-presets\" style=\"display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 10px;\">\n                            <div class=\"color-box\" style=\"background: #1e293b; width: 28px; height: 28px; border-radius: 4px; cursor: pointer;\" onclick=\"updateActiveColor('#1e293b')\"><\/div>\n                            <div class=\"color-box\" style=\"background: #ef4444; width: 28px; height: 28px; border-radius: 4px; cursor: pointer;\" onclick=\"updateActiveColor('#ef4444')\"><\/div>\n                            <div class=\"color-box\" style=\"background: #2563eb; width: 28px; height: 28px; border-radius: 4px; cursor: pointer;\" onclick=\"updateActiveColor('#2563eb')\"><\/div>\n                            <div class=\"color-box\" style=\"background: #10b981; width: 28px; height: 28px; border-radius: 4px; cursor: pointer;\" onclick=\"updateActiveColor('#10b981')\"><\/div>\n                        <\/div>\n                        <input type=\"color\" id=\"brushColor\" value=\"#ef4444\" oninput=\"previewActiveColor(this.value)\" onchange=\"updateActiveColor(this.value)\" style=\"width: 100%; height: 30px; cursor: pointer; border: 1px solid #ddd; border-radius: 4px;\">\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 3. T\u00d9Y CH\u1eccN DOWNLOAD -->\n        <div class=\"download-section\">\n            <button class=\"btn-dl\" onclick=\"downloadSVG()\"><svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5l5 5 5-5m-5 5V3\"\/><\/svg> SVG<\/button>\n            <button class=\"btn-dl\" onclick=\"downloadImageScale(0.5, true)\"><svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5l5 5 5-5m-5 5V3\"\/><\/svg> PNG Nh\u1ecf<\/button>\n            <button class=\"btn-dl\" onclick=\"downloadImageScale(1, true)\"><svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5l5 5 5-5m-5 5V3\"\/><\/svg> PNG V\u1eeba<\/button>\n            <button class=\"btn-dl\" onclick=\"downloadImageScale(2, true)\"><svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5l5 5 5-5m-5 5V3\"\/><\/svg> PNG L\u1edbn<\/button>\n        <\/div>\n    <\/div>\n\n    <script>\n        function initSettings() {\n            if (window.innerWidth <= 768) {\n                document.getElementById('settingsPanel').classList.add('collapsed');\n                document.getElementById('toggleText').innerText = 'Hi\u1ec7n c\u00e0i \u0111\u1eb7t...';\n                document.getElementById('toggleIcon').innerText = '\ufe40';\n            }\n        }\n        initSettings();\n\n        let exportScale = 0; \n        let activeDotIndex = null; \n\n        document.addEventListener('pointerdown', function(e) {\n            const rp = document.getElementById('resetConfirmPopup');\n            const br = document.querySelector('.btn-reset');\n            if (rp && !rp.classList.contains('hidden')) { if (!rp.contains(e.target) && !br.contains(e.target)) rp.classList.add('hidden'); }\n            \n            const cp = document.getElementById('colorPopover');\n            if (cp && cp.classList.contains('active')) { \n                if (!cp.contains(e.target) && e.target.id !== 'chordCanvas') {\n                    cp.classList.remove('active'); \n                    activeDotIndex = null;\n                }\n            }\n        });\n\n        function toggleSettingsPanel() {\n            const p = document.getElementById('settingsPanel');\n            p.classList.toggle('collapsed');\n            document.getElementById('toggleText').innerText = p.classList.contains('collapsed') ? 'Hi\u1ec7n c\u00e0i \u0111\u1eb7t...' : '\u1ea8n c\u00e0i \u0111\u1eb7t...';\n            document.getElementById('toggleIcon').innerText = p.classList.contains('collapsed') ? '\ufe40' : '\ufe3f';\n        }\n        function toggleResetConfirm() { document.getElementById('resetConfirmPopup').classList.toggle('hidden'); }\n        \n        function executeReset() { \n            document.getElementById('chordForm').reset(); \n            drawCanvas(); \n            if(mode === 'text') renderTextInputs(); \n            toggleResetConfirm(); \n        }\n\n        function clearDiagram() { dots = []; drawCanvas(); if(mode === 'text') renderTextInputs(); document.getElementById('colorPopover').classList.remove('active'); }\n        \n        const canvas = document.getElementById('chordCanvas');\n        const ctx = canvas.getContext('2d');\n        let mode = 'finger', dots = [], isDragging = false, dragStart = null, previewBarre = null, isHorizontal = false; \n        const stringSpacing = 35, paddingX = 40, paddingY = 100, defaultColor = '#1e293b', strokeW = 2; \n        \n        const shapeLoop = ['circle', 'square', 'triangle', 'diamond', 'pentagon', 'bordered-circle'];\n        const nutShapeLoop = ['bordered-circle', 'cross', 'circle'];\n\n        function previewActiveColor(color) {\n            document.getElementById('brushColor').value = color;\n            if (activeDotIndex !== null && dots[activeDotIndex]) {\n                dots[activeDotIndex].color = color;\n                drawCanvas(false, true); \n            }\n        }\n\n        function updateActiveColor(color) {\n            document.getElementById('brushColor').value = color;\n            if (activeDotIndex !== null && dots[activeDotIndex]) {\n                dots[activeDotIndex].color = color;\n                drawCanvas(false, true);\n            }\n            document.getElementById('colorPopover').classList.remove('active');\n            activeDotIndex = null;\n        }\n\n        function setMode(nm) {\n            mode = nm;\n            document.querySelectorAll('.btn-tool').forEach(b => b.classList.remove('active'));\n            if (['finger', 'text', 'color', 'shape'].includes(nm)) document.getElementById('btn' + nm.charAt(0).toUpperCase() + nm.slice(1)).classList.add('active');\n            if (mode === 'text') renderTextInputs(); else document.getElementById('textInputsContainer').innerHTML = '';\n            if(nm !== 'color') {\n                document.getElementById('colorPopover').classList.remove('active');\n                activeDotIndex = null;\n            }\n        }\n        function toggleOrientation() { isHorizontal = !isHorizontal; document.getElementById('colorPopover').classList.remove('active'); drawCanvas(); if(mode === 'text') renderTextInputs(); }\n        \n        function getS() {\n            return {\n                title: document.getElementById('chordTitle').value,\n                startFret: parseInt(document.getElementById('startFret').value) || 1,\n                numFrets: parseInt(document.getElementById('numFrets').value) || 5,\n                numStrings: parseInt(document.getElementById('numStrings').value) || 6,\n                fretHeight: parseInt(document.getElementById('fretHeight').value) || 60,\n                fingerSize: parseInt(document.getElementById('fingerSize').value) || 14,\n                fontSize: parseInt(document.getElementById('fingerFontSize').value) || 14,\n                titleSize: parseInt(document.getElementById('titleFontSize').value) || 28,\n                hidePos: document.getElementById('hidePosition').checked,\n                showMarkers: document.getElementById('showMarkers').checked,\n                showFN: document.getElementById('showFretNumbers').checked,\n                hideWatermark: document.getElementById('hideWatermark') ? document.getElementById('hideWatermark').checked : false\n            };\n        }\n        function getStrPos(idx, s) { return isHorizontal ? (idx - 1) * stringSpacing : (s.numStrings - idx) * stringSpacing; }\n\n        function drawCanvas(isTrans = false, skipInputs = false) {\n            const s = getS();\n            let validDots = dots.filter(d => d.fret <= s.numFrets && d.string <= s.numStrings && (!d.isBarre || d.endString <= s.numStrings));\n            \n            let baseW = !isHorizontal ? paddingX * 2 + (s.numStrings - 1) * stringSpacing + 35 : paddingX * 2 + s.numFrets * s.fretHeight + 40;\n            let extraBottom = (isHorizontal && s.showFN) ? 20 : 0;\n            let baseH = !isHorizontal ? paddingY + s.numFrets * s.fretHeight + 45 : paddingY + (s.numStrings - 1) * stringSpacing + 45 + extraBottom;\n            \n            let gridCenterX = !isHorizontal ? paddingX + ((s.numStrings - 1) * stringSpacing) \/ 2 : paddingX + (s.numFrets * s.fretHeight) \/ 2;\n            let watermarkY = baseH - 12;\n\n            let dpr = exportScale > 0 ? exportScale : Math.max(2, window.devicePixelRatio || 1);\n            canvas.width = baseW * dpr; canvas.height = baseH * dpr;\n            canvas.style.width = baseW + 'px'; canvas.style.height = baseH + 'px';\n            ctx.setTransform(dpr, 0, 0, dpr, 0, 0); \n            ctx.clearRect(0, 0, baseW, baseH);\n            if(!isTrans) { ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, baseW, baseH); }\n            \n            ctx.fillStyle = '#334155'; ctx.font = `bold ${s.titleSize}px Arial`; ctx.textAlign = 'center'; \n            ctx.fillText(s.title, gridCenterX, 45);\n            \n            if (!s.showFN && !s.hidePos && s.startFret > 1) {\n                ctx.fillStyle = '#475569'; ctx.font = 'bold 15px Arial';\n                let txt = s.startFret + 'fr';\n                !isHorizontal ? ctx.fillText(txt, paddingX + (s.numStrings - 1) * stringSpacing + 32, paddingY + s.fretHeight\/2 + 5) : ctx.fillText(txt, paddingX + s.fretHeight\/2, paddingY + (s.numStrings - 1) * stringSpacing + 32);\n            }\n\n            if (s.showFN) {\n                ctx.fillStyle = '#475569'; ctx.font = 'bold 14px Arial';\n                ctx.textBaseline = 'middle'; \n                for (let f = s.startFret; f < s.startFret + s.numFrets; f++) {\n                    if ([3, 5, 7, 9, 12, 15, 17, 19, 21, 24].includes(f)) {\n                        let rel = (f - s.startFret + 0.5) * s.fretHeight;\n                        if (!isHorizontal) {\n                            ctx.textAlign = 'left';\n                            ctx.fillText(f.toString(), paddingX + (s.numStrings - 1) * stringSpacing + 32, paddingY + rel);\n                        } else {\n                            ctx.textAlign = 'center';\n                            ctx.fillText(f.toString(), paddingX + rel, paddingY + (s.numStrings - 1) * stringSpacing + 32);\n                        }\n                    }\n                }\n                ctx.textBaseline = 'alphabetic'; \n            }\n            \n            if (s.showMarkers) {\n                ctx.fillStyle = 'rgba(148, 163, 184, 0.3)';\n                for (let f = s.startFret; f < s.startFret + s.numFrets; f++) {\n                    let relF = (f - s.startFret + 0.5) * s.fretHeight;\n                    if ([3, 5, 7, 9, 15, 17, 19, 21].includes(f)) {\n                        let mid = (s.numStrings - 1) * stringSpacing \/ 2;\n                        !isHorizontal ? (ctx.beginPath(), ctx.arc(paddingX + mid, paddingY + relF, 6, 0, Math.PI*2), ctx.fill()) : (ctx.beginPath(), ctx.arc(paddingX + relF, paddingY + mid, 6, 0, Math.PI*2), ctx.fill());\n                    } else if ([12, 24].includes(f)) {\n                        let p1 = 1.5 * stringSpacing, p2 = (s.numStrings - 2.5) * stringSpacing;\n                        if (!isHorizontal) { ctx.beginPath(); ctx.arc(paddingX + p1, paddingY + relF, 6, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(paddingX + p2, paddingY + relF, 6, 0, Math.PI*2); ctx.fill(); }\n                        else { ctx.beginPath(); ctx.arc(paddingX + relF, paddingY + p1, 6, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(paddingX + relF, paddingY + p2, 6, 0, Math.PI*2); ctx.fill(); }\n                    }\n                }\n            }\n\n            ctx.lineWidth = strokeW; ctx.strokeStyle = '#334155'; ctx.beginPath();\n            if (!isHorizontal) {\n                for (let i = 0; i < s.numStrings; i++) { ctx.moveTo(paddingX+i*stringSpacing, paddingY); ctx.lineTo(paddingX+i*stringSpacing, paddingY+s.numFrets*s.fretHeight); }\n                for (let i = 0; i <= s.numFrets; i++) { ctx.moveTo(paddingX, paddingY+i*s.fretHeight); ctx.lineTo(paddingX+(s.numStrings-1)*stringSpacing, paddingY+i*s.fretHeight); }\n            } else {\n                for (let i = 0; i < s.numStrings; i++) { ctx.moveTo(paddingX, paddingY+i*stringSpacing); ctx.lineTo(paddingX+s.numFrets*s.fretHeight, paddingY+i*stringSpacing); }\n                for (let i = 0; i <= s.numFrets; i++) { ctx.moveTo(paddingX+i*s.fretHeight, paddingY); ctx.lineTo(paddingX+i*s.fretHeight, paddingY+(s.numStrings-1)*stringSpacing); }\n            }\n            ctx.stroke();\n            if (s.startFret === 1) { ctx.fillStyle = '#000'; !isHorizontal ? ctx.fillRect(paddingX-1, paddingY-4, (s.numStrings-1)*stringSpacing+2, 6) : ctx.fillRect(paddingX-4, paddingY-1, 6, (s.numStrings-1)*stringSpacing+2); }\n            \n            validDots.forEach(d => renderDot(d, s, isTrans));\n            if (previewBarre) renderDot(previewBarre, s, isTrans);\n            \n            if (!s.hideWatermark) {\n                ctx.fillStyle = '#94a3b8'; ctx.font = '14px Arial'; ctx.textAlign = 'center'; \n                ctx.fillText('nlguitar.com', gridCenterX, watermarkY);\n            }\n            \n            if (mode === 'text' && !skipInputs) renderTextInputs();\n        }\n\n        function renderDot(d, s, isTrans) {\n            let x, y, pos = getStrPos(d.string, s);\n            \n            if (d.fret === 0) {\n                if (!isHorizontal) { x = paddingX + pos; y = paddingY - 20; }\n                else { x = paddingX - 20; y = paddingY + pos; }\n            } else {\n                if (!isHorizontal) { x = paddingX + pos; y = paddingY + (d.fret - 0.5) * s.fretHeight; } \n                else { x = paddingX + (d.fret - 0.5) * s.fretHeight; y = paddingY + pos; }\n            }\n            \n            let c = d.color || defaultColor; ctx.fillStyle = c;\n            \n            if (d.isBarre) {\n                let pos2 = getStrPos(d.endString, s);\n                if (!isHorizontal) { let x2 = paddingX + pos2; let stX = Math.min(x, x2); ctx.beginPath(); ctx.roundRect(stX - s.fingerSize, y - s.fingerSize, Math.abs(x2 - x) + s.fingerSize * 2, s.fingerSize * 2, s.fingerSize); ctx.fill(); }\n                else { let y2 = paddingY + pos2; let stY = Math.min(y, y2); ctx.beginPath(); ctx.roundRect(x - s.fingerSize, stY - s.fingerSize, s.fingerSize * 2, Math.abs(y2 - y) + s.fingerSize * 2, s.fingerSize); ctx.fill(); }\n            } else {\n                ctx.beginPath(); let r = s.fingerSize;\n                if (!d.shape || d.shape === 'circle') { \n                    ctx.arc(x, y, r, 0, Math.PI*2); ctx.fill(); \n                }\n                else if (d.shape === 'square') { \n                    ctx.rect(x - r, y - r, r*2, r*2); ctx.fill(); \n                }\n                else if (d.shape === 'triangle') { \n                    ctx.moveTo(x, y - r); ctx.lineTo(x + r, y + r); ctx.lineTo(x - r, y + r); ctx.fill(); \n                }\n                else if (d.shape === 'cross') { \n                    \/\/ Thu nh\u1ecf X \u0111\u1ec3 v\u1eeba v\u1eb7n trong b\u00e1n k\u00ednh r\n                    let rx = r * 0.8; \n                    ctx.lineWidth = 3; ctx.strokeStyle = c; \n                    ctx.moveTo(x - rx, y - rx); ctx.lineTo(x + rx, y + rx); \n                    ctx.moveTo(x + rx, y - rx); ctx.lineTo(x - rx, y + rx); ctx.stroke(); \n                }\n                else if (d.shape === 'diamond') {\n                    ctx.moveTo(x, y - r); ctx.lineTo(x + r, y); ctx.lineTo(x, y + r); ctx.lineTo(x - r, y); ctx.fill();\n                }\n                else if (d.shape === 'pentagon') { \n                    for (let j = 0; j < 5; j++) {\n                        let px = x + r * Math.sin(j * 2 * Math.PI \/ 5);\n                        let py = y - r * Math.cos(j * 2 * Math.PI \/ 5);\n                        if (j === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py);\n                    }\n                    ctx.closePath(); ctx.fill();\n                }\n                else if (d.shape === 'bordered-circle') { \n                    \/\/ Tr\u1eeb hao vi\u1ec1n \u0111\u1ec3 O v\u00e0 ch\u1ea5m \u0111en b\u1eb1ng nhau\n                    let br = Math.max(1, r - 1.25); \n                    ctx.save();\n                    ctx.globalCompositeOperation = 'destination-out';\n                    ctx.beginPath(); ctx.arc(x, y, br, 0, Math.PI*2); ctx.fill();\n                    ctx.restore();\n                    ctx.beginPath(); ctx.arc(x, y, br, 0, Math.PI*2); \n                    ctx.lineWidth = 2.5; ctx.strokeStyle = c; ctx.stroke(); \n                }\n            }\n            \n            \/\/ Kh\u00f4ng render ch\u1eef cho d\u1ea5u X\n            if (d.text && d.shape !== 'cross') {\n                ctx.fillStyle = (d.shape === 'bordered-circle') ? c : '#fff'; \n                ctx.font = `bold ${s.fontSize}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';\n                let tx = x, ty = y;\n                if (d.isBarre) { if (!isHorizontal) tx = paddingX + (getStrPos(d.string, s) + getStrPos(d.endString, s)) \/ 2; else ty = paddingY + (getStrPos(d.string, s) + getStrPos(d.endString, s)) \/ 2; }\n                ctx.fillText(d.text, tx, ty);\n            }\n        }\n\n        function renderTextInputs() {\n            const container = document.getElementById('textInputsContainer'); \n            container.innerHTML = ''; \n            if (mode !== 'text') return; \n            const s = getS();\n            let validDots = dots.filter(d => d.fret <= s.numFrets && d.string <= s.numStrings && (!d.isBarre || d.endString <= s.numStrings));\n            \n            validDots.forEach((dot) => {\n                \/\/ Kh\u00f4ng hi\u1ec3n th\u1ecb \u00f4 nh\u1eadp ch\u1eef cho d\u1ea5u X\n                if (dot.shape === 'cross') return; \n                \n                let x, y, pos = getStrPos(dot.string, s);\n                if (dot.fret === 0) {\n                    if (!isHorizontal) { x = paddingX + pos; y = paddingY - 20; }\n                    else { x = paddingX - 20; y = paddingY + pos; }\n                } else {\n                    if (!isHorizontal) { x = paddingX + pos; y = paddingY + (dot.fret - 0.5) * s.fretHeight; if (dot.isBarre) x = paddingX + (getStrPos(dot.string, s) + getStrPos(dot.endString, s)) \/ 2; } \n                    else { x = paddingX + (dot.fret - 0.5) * s.fretHeight; y = paddingY + pos; if (dot.isBarre) y = paddingY + (getStrPos(dot.string, s) + getStrPos(dot.endString, s)) \/ 2; }\n                }\n                \n                const i = document.createElement('input'); \n                i.type = 'text'; \n                i.maxLength = 3; \n                i.value = dot.text || '';\n                i.className = 'dot-text-input'; \n                \n                Object.assign(i.style, { left: (x - 18) + 'px', top: (y - 12) + 'px' });\n                \n                i.addEventListener('input', (e) => { \n                    dot.text = e.target.value; \n                    drawCanvas(false, true); \n                }); \n                \n                i.addEventListener('mousedown', (e) => e.stopPropagation());\n                i.addEventListener('touchstart', (e) => e.stopPropagation());\n                \n                container.appendChild(i);\n            });\n        }\n\n        function getCoords(e) {\n            const rect = canvas.getBoundingClientRect(), s = getS();\n            let cX, cY;\n            if (e.changedTouches && e.changedTouches.length > 0) { cX = e.changedTouches[0].clientX; cY = e.changedTouches[0].clientY; } \n            else if (e.touches && e.touches.length > 0) { cX = e.touches[0].clientX; cY = e.touches[0].clientY; } \n            else { cX = e.clientX; cY = e.clientY; }\n            let extraBottom = (isHorizontal && s.showFN) ? 20 : 0;\n            let baseW = !isHorizontal ? paddingX * 2 + (s.numStrings - 1) * stringSpacing + 35 : paddingX * 2 + s.numFrets * s.fretHeight + 40;\n            let baseH = !isHorizontal ? paddingY + s.numFrets * s.fretHeight + 45 : paddingY + (s.numStrings - 1) * stringSpacing + 45 + extraBottom;\n            const cx = (cX - rect.left) * (baseW \/ rect.width);\n            const cy = (cY - rect.top) * (baseH \/ rect.height);\n            let string, fret;\n            if (!isHorizontal) { \n                let idx = Math.round((cx - paddingX) \/ stringSpacing); \n                string = s.numStrings - idx; \n                if (cy < paddingY && cy > paddingY - 40) fret = 0; \n                else fret = Math.ceil((cy - paddingY) \/ s.fretHeight); \n            } \n            else { \n                let idx = Math.round((cy - paddingY) \/ stringSpacing); \n                string = idx + 1; \n                if (cx < paddingX && cx > paddingX - 40) fret = 0; \n                else fret = Math.ceil((cx - paddingX) \/ s.fretHeight); \n            }\n            return { string, fret, rawX: cx, rawY: cy };\n        }\n\n        let touchTimer = null, isTouchPressing = false, touchHasMoved = false, touchStartX = 0, touchStartY = 0, lastTouchE = null;\n\n        canvas.addEventListener('mousedown', function(e) {\n            if (mode === 'text') return;\n            const s = getS(), pos = getCoords(e);\n            if (pos.string < 1 || pos.string > s.numStrings) return;\n            \n            let f = Math.max(0, Math.min(pos.fret, s.numFrets));\n            let idx = dots.findIndex(d => d.fret === f && ((!d.isBarre && d.string === pos.string) || (d.isBarre && pos.string >= Math.min(d.string, d.endString) && pos.string <= Math.max(d.string, d.endString))));\n            \n            if (e.button === 2) { \n                if (idx >= 0) { \n                    let loop = f === 0 ? nutShapeLoop : shapeLoop;\n                    let def = f === 0 ? 'bordered-circle' : 'circle';\n                    let si = loop.indexOf(dots[idx].shape || def); \n                    dots[idx].shape = loop[(si + 1) % loop.length]; \n                    drawCanvas(); \n                } \n                return; \n            }\n            \n            if (e.button === 0) {\n                if (mode === 'finger') { \n                    if (idx >= 0) { \n                        dots.splice(idx, 1); \n                        drawCanvas(); \n                    } else { \n                        if (f > 0) {\n                            isDragging = true; dragStart = {string: pos.string, fret: f}; \n                        } else {\n                            dots.push({ fret: 0, string: pos.string, isBarre: false, text: '', shape: 'bordered-circle' }); \n                            drawCanvas(); \n                        }\n                    } \n                } \n                else if (idx >= 0) { \n                    if (mode === 'color') { \n                        activeDotIndex = idx;\n                        const p = document.getElementById('colorPopover');\n                        p.classList.add('active');\n                        p.style.left = (pos.rawX + 20) + 'px'; \n                        p.style.top = (pos.rawY - 50) + 'px'; \n                        p.style.transform = 'none';\n                    } else if (mode === 'shape') { \n                        let loop = f === 0 ? nutShapeLoop : shapeLoop;\n                        let def = f === 0 ? 'bordered-circle' : 'circle';\n                        let si = loop.indexOf(dots[idx].shape || def); \n                        dots[idx].shape = loop[(si + 1) % loop.length]; \n                        drawCanvas(); \n                    } \n                } else if (mode === 'color') {\n                    document.getElementById('colorPopover').classList.remove('active');\n                    activeDotIndex = null;\n                }\n            }\n        });\n        canvas.addEventListener('mousemove', function(e) {\n            if (!isDragging || mode !== 'finger') return;\n            const s = getS(), pos = getCoords(e);\n            let currentString = Math.max(1, Math.min(pos.string, s.numStrings));\n            if (currentString !== dragStart.string) previewBarre = { fret: dragStart.fret, string: dragStart.string, endString: currentString, isBarre: true, color: 'rgba(37, 99, 235, 0.4)' }; else previewBarre = null;\n            drawCanvas();\n        });\n        window.addEventListener('mouseup', function(e) {\n            if (!isDragging) return; const s = getS(), pos = getCoords(e); isDragging = false;\n            let currentString = previewBarre ? previewBarre.endString : getCoords(e).string;\n            currentString = Math.max(1, Math.min(currentString, s.numStrings));\n            let f = dragStart.fret;\n            if (dragStart.string !== currentString) dots.push({ fret: f, string: dragStart.string, endString: currentString, isBarre: true, text: '', shape: 'circle' });\n            else dots.push({ fret: f, string: dragStart.string, isBarre: false, text: '', shape: 'circle' });\n            previewBarre = null; drawCanvas();\n        });\n\n        canvas.addEventListener('touchstart', function(e) {\n            if (e.touches.length > 1 || mode === 'text') return;\n            lastTouchE = e; touchStartX = e.touches[0].clientX; touchStartY = e.touches[0].clientY; touchHasMoved = false; isTouchPressing = false;\n            touchTimer = setTimeout(() => {\n                isTouchPressing = true;\n                const pos = getCoords(lastTouchE); const s = getS();\n                if (pos.string >= 1 && pos.string <= s.numStrings) {\n                    let f = Math.max(0, Math.min(pos.fret, s.numFrets));\n                    let idx = dots.findIndex(d => d.fret === f && ((!d.isBarre && d.string === pos.string) || (d.isBarre && pos.string >= Math.min(d.string, d.endString) && pos.string <= Math.max(d.string, d.endString))));\n                    if (idx < 0 && mode === 'finger' && f > 0) { isDragging = true; dragStart = {string: pos.string, fret: f}; }\n                }\n            }, 250);\n        }, {passive: false});\n\n        canvas.addEventListener('touchmove', (e) => {\n            if (e.touches.length > 1 || mode === 'text') return;\n            const dist = Math.hypot(e.touches[0].clientX - touchStartX, e.touches[0].clientY - touchStartY);\n            if (!touchHasMoved && dist > 10) { touchHasMoved = true; if (!isTouchPressing) clearTimeout(touchTimer); }\n            if (isTouchPressing) {\n                if (e.cancelable) e.preventDefault();\n                if (!isDragging || mode !== 'finger') return;\n                const s = getS(), pos = getCoords(e);\n                let currentString = Math.max(1, Math.min(pos.string, s.numStrings));\n                if (currentString !== dragStart.string) previewBarre = { fret: dragStart.fret, string: dragStart.string, endString: currentString, isBarre: true, color: 'rgba(37, 99, 235, 0.4)' }; else previewBarre = null;\n                drawCanvas();\n            }\n        }, {passive: false});\n\n        canvas.addEventListener('touchend', (e) => {\n            if (mode === 'text') return;\n            clearTimeout(touchTimer); const pos = getCoords(lastTouchE || e); const s = getS();\n            if (!touchHasMoved) {\n                if (e.cancelable) e.preventDefault();\n                if (pos.string >= 1 && pos.string <= s.numStrings) {\n                    let f = Math.max(0, Math.min(pos.fret, s.numFrets));\n                    let idx = dots.findIndex(d => d.fret === f && ((!d.isBarre && d.string === pos.string) || (d.isBarre && pos.string >= Math.min(d.string, d.endString) && pos.string <= Math.max(d.string, d.endString))));\n                    \n                    if (mode === 'finger') { \n                        if (idx >= 0) dots.splice(idx, 1); \n                        else { \n                            let defaultShape = f === 0 ? 'bordered-circle' : 'circle';\n                            dots.push({ fret: f, string: pos.string, isBarre: false, text: '', shape: defaultShape }); \n                        } \n                    } \n                    else if (idx >= 0) {\n                        if (mode === 'color') {\n                            activeDotIndex = idx;\n                            const p = document.getElementById('colorPopover');\n                            p.classList.add('active');\n                            p.style.left = '50%'; p.style.top = (pos.rawY - 80) + 'px'; p.style.transform = 'translateX(-50%)';\n                        }\n                        else if (mode === 'shape') { \n                            let loop = f === 0 ? nutShapeLoop : shapeLoop;\n                            let def = f === 0 ? 'bordered-circle' : 'circle';\n                            let si = loop.indexOf(dots[idx].shape || def); \n                            dots[idx].shape = loop[(si + 1) % loop.length]; \n                        }\n                    } else if (mode === 'color') {\n                        document.getElementById('colorPopover').classList.remove('active');\n                        activeDotIndex = null;\n                    }\n                    drawCanvas();\n                }\n            } else if (isTouchPressing && isDragging) {\n                if (e.cancelable) e.preventDefault();\n                let currentString = previewBarre ? previewBarre.endString : pos.string;\n                currentString = Math.max(1, Math.min(currentString, s.numStrings));\n                if (dragStart.string !== currentString) dots.push({ fret: dragStart.fret, string: dragStart.string, endString: currentString, isBarre: true, text: '', shape: 'circle' });\n                else dots.push({ fret: dragStart.fret, string: dragStart.string, isBarre: false, text: '', shape: 'circle' });\n                previewBarre = null; drawCanvas();\n            }\n            isTouchPressing = false; touchHasMoved = false; isDragging = false; previewBarre = null;\n        }, {passive: false});\n\n        canvas.addEventListener('contextmenu', (e) => e.preventDefault());\n\n        function downloadImageScale(scaleMultiplier, isT) {\n            exportScale = scaleMultiplier * 2; \n            drawCanvas(isT);\n            const l = document.createElement('a'); l.download = `${document.getElementById('chordTitle').value || 'chord'}.png`;\n            l.href = canvas.toDataURL('image\/png', 1.0); l.click(); exportScale = 0; drawCanvas(false);\n        }\n\n        function downloadSVG() {\n            const s = getS(); \n            let validDots = dots.filter(d => d.fret <= s.numFrets && d.string <= s.numStrings && (!d.isBarre || d.endString <= s.numStrings));\n            \n            let extraBottom = (isHorizontal && s.showFN) ? 20 : 0;\n            let baseW = !isHorizontal ? paddingX * 2 + (s.numStrings - 1) * stringSpacing + 35 : paddingX * 2 + s.numFrets * s.fretHeight + 40;\n            let baseH = !isHorizontal ? paddingY + s.numFrets * s.fretHeight + 45 : paddingY + (s.numStrings - 1) * stringSpacing + 45 + extraBottom;\n            let gridCenterX = !isHorizontal ? paddingX + ((s.numStrings - 1) * stringSpacing) \/ 2 : paddingX + (s.numFrets * s.fretHeight) \/ 2;\n            let watermarkY = baseH - 12;\n            \n            let svg = `<svg width=\"${baseW}\" height=\"${baseH}\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">`;\n            svg += `<text x=\"${gridCenterX}\" y=\"45\" font-family=\"Arial\" font-size=\"${s.titleSize}\" font-weight=\"bold\" fill=\"#334155\" text-anchor=\"middle\">${s.title}<\/text>`;\n            \n            svg += `<defs><mask id=\"grid-mask\"><rect width=\"100%\" height=\"100%\" fill=\"white\" \/>`;\n            validDots.forEach(d => {\n                if (d.shape === 'bordered-circle') {\n                    let x, y, pos = isHorizontal ? (d.string-1)*stringSpacing : (s.numStrings-d.string)*stringSpacing;\n                    if (d.fret === 0) {\n                        x = !isHorizontal ? paddingX + pos : paddingX - 20;\n                        y = !isHorizontal ? paddingY - 20 : paddingY + pos;\n                    } else {\n                        x = !isHorizontal ? paddingX + pos : paddingX + (d.fret-0.5)*s.fretHeight;\n                        y = !isHorizontal ? paddingY + (d.fret-0.5)*s.fretHeight : paddingY + pos;\n                    }\n                    let br = Math.max(1, s.fingerSize - 1.25);\n                    svg += `<circle cx=\"${x}\" cy=\"${y}\" r=\"${br}\" fill=\"black\" \/>`;\n                }\n            });\n            svg += `<\/mask><\/defs>`;\n            \n            if (!s.showFN && !s.hidePos && s.startFret > 1) {\n                let txt = s.startFret + 'fr';\n                !isHorizontal ? svg += `<text x=\"${paddingX + (s.numStrings-1)*stringSpacing + 32}\" y=\"${paddingY + s.fretHeight\/2 + 5}\" font-family=\"Arial\" font-size=\"15\" font-weight=\"bold\" fill=\"#475569\" dominant-baseline=\"central\">${txt}<\/text>` : svg += `<text x=\"${paddingX + s.fretHeight\/2}\" y=\"${paddingY + (s.numStrings-1)*stringSpacing + 32}\" font-family=\"Arial\" font-size=\"15\" font-weight=\"bold\" fill=\"#475569\" text-anchor=\"middle\">${txt}<\/text>`;\n            }\n            if (s.showFN) {\n                for (let f = s.startFret; f < s.startFret + s.numFrets; f++) {\n                    if ([3, 5, 7, 9, 12, 15, 17, 19, 21, 24].includes(f)) {\n                        let rel = (f - s.startFret + 0.5) * s.fretHeight;\n                        !isHorizontal ? svg += `<text x=\"${paddingX + (s.numStrings-1)*stringSpacing + 30}\" y=\"${paddingY + rel}\" font-family=\"Arial\" font-size=\"14\" font-weight=\"bold\" fill=\"#475569\" dominant-baseline=\"central\" text-anchor=\"start\">${f}<\/text>` : svg += `<text x=\"${paddingX + rel}\" y=\"${paddingY + (s.numStrings-1)*stringSpacing + 30}\" font-family=\"Arial\" font-size=\"14\" font-weight=\"bold\" fill=\"#475569\" dominant-baseline=\"central\" text-anchor=\"middle\">${f}<\/text>`;\n                    }\n                }\n            } \n            \n            svg += `<g mask=\"url(#grid-mask)\">`;\n            if (s.showMarkers) {\n                for (let f = s.startFret; f < s.startFret + s.numFrets; f++) {\n                    let relF = (f - s.startFret + 0.5) * s.fretHeight;\n                    if ([3, 5, 7, 9, 15, 17, 19, 21].includes(f)) {\n                        let mid = (s.numStrings - 1) * stringSpacing \/ 2;\n                        !isHorizontal ? svg += `<circle cx=\"${paddingX + mid}\" cy=\"${paddingY + relF}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>` : svg += `<circle cx=\"${paddingX + relF}\" cy=\"${paddingY + mid}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>`;\n                    } else if ([12, 24].includes(f)) {\n                        let p1 = 1.5 * stringSpacing, p2 = (s.numStrings - 2.5) * stringSpacing;\n                        if (!isHorizontal) { svg += `<circle cx=\"${paddingX + p1}\" cy=\"${paddingY + relF}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>`; svg += `<circle cx=\"${paddingX + p2}\" cy=\"${paddingY + relF}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>`; }\n                        else { svg += `<circle cx=\"${paddingX + relF}\" cy=\"${paddingY + p1}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>`; svg += `<circle cx=\"${paddingX + relF}\" cy=\"${paddingY + p2}\" r=\"6\" fill=\"rgba(148, 163, 184, 0.3)\" \/>`; }\n                    }\n                }\n            }\n            if (!isHorizontal) {\n                for(let i=0; i<s.numStrings; i++) svg += `<rect x=\"${paddingX+i*stringSpacing - 1}\" y=\"${paddingY - 1}\" width=\"2\" height=\"${s.numFrets*s.fretHeight + 2}\" fill=\"#334155\" \/>`;\n                for(let i=0; i<=s.numFrets; i++) svg += `<rect x=\"${paddingX - 1}\" y=\"${paddingY+i*s.fretHeight - 1}\" width=\"${(s.numStrings-1)*stringSpacing + 2}\" height=\"2\" fill=\"#334155\" \/>`;\n            } else {\n                for(let i=0; i<s.numStrings; i++) svg += `<rect x=\"${paddingX - 1}\" y=\"${paddingY+i*stringSpacing - 1}\" width=\"${s.numFrets*s.fretHeight + 2}\" height=\"2\" fill=\"#334155\" \/>`;\n                for(let i=0; i<=s.numFrets; i++) svg += `<rect x=\"${paddingX+i*s.fretHeight - 1}\" y=\"${paddingY - 1}\" width=\"2\" height=\"${(s.numStrings-1)*stringSpacing + 2}\" fill=\"#334155\" \/>`;\n            }\n            if (s.startFret === 1) {\n                if (!isHorizontal) svg += `<rect x=\"${paddingX-1}\" y=\"${paddingY-4}\" width=\"${(s.numStrings-1)*stringSpacing + 2}\" height=\"6\" fill=\"#000\" \/>`;\n                else svg += `<rect x=\"${paddingX-4}\" y=\"${paddingY-1}\" width=\"6\" height=\"${(s.numStrings-1)*stringSpacing + 2}\" fill=\"#000\" \/>`;\n            }\n            svg += `<\/g>`;\n\n            validDots.forEach(d => {\n                let x, y, pos = isHorizontal ? (d.string-1)*stringSpacing : (s.numStrings-d.string)*stringSpacing;\n                \n                if (d.fret === 0) {\n                    x = !isHorizontal ? paddingX + pos : paddingX - 20;\n                    y = !isHorizontal ? paddingY - 20 : paddingY + pos;\n                } else {\n                    x = !isHorizontal ? paddingX + pos : paddingX + (d.fret-0.5)*s.fretHeight;\n                    y = !isHorizontal ? paddingY + (d.fret-0.5)*s.fretHeight : paddingY + pos;\n                }\n                \n                let c = d.color || defaultColor;\n                if (d.isBarre) {\n                    let p2 = getStrPos(d.endString, s);\n                    if (!isHorizontal) { let x2 = paddingX + p2, stX = Math.min(x, x2), wb = Math.abs(x2 - x) + s.fingerSize * 2; svg += `<rect x=\"${stX - s.fingerSize}\" y=\"${y - s.fingerSize}\" width=\"${wb}\" height=\"${s.fingerSize*2}\" rx=\"${s.fingerSize}\" fill=\"${c}\" \/>`; }\n                    else { let y2 = paddingY + p2, stY = Math.min(y, y2), hb = Math.abs(y2 - y) + s.fingerSize * 2; svg += `<rect x=\"${x - s.fingerSize}\" y=\"${stY - s.fingerSize}\" width=\"${s.fingerSize*2}\" height=\"${hb}\" rx=\"${s.fingerSize}\" fill=\"${c}\" \/>`; }\n                } else if (!d.shape || d.shape === 'circle') svg += `<circle cx=\"${x}\" cy=\"${y}\" r=\"${s.fingerSize}\" fill=\"${c}\" \/>`;\n                else if (d.shape === 'square') svg += `<rect x=\"${x-s.fingerSize}\" y=\"${y-s.fingerSize}\" width=\"${s.fingerSize*2}\" height=\"${s.fingerSize*2}\" fill=\"${c}\" \/>`;\n                else if (d.shape === 'triangle') svg += `<polygon points=\"${x},${y-s.fingerSize} ${x+s.fingerSize},${y+s.fingerSize} ${x-s.fingerSize},${y+s.fingerSize}\" fill=\"${c}\" \/>`;\n                else if (d.shape === 'cross') {\n                    let rx = s.fingerSize * 0.7;\n                    svg += `<path d=\"M${x-rx} ${y-rx} L${x+rx} ${y+rx} M${x+rx} ${y-rx} L${x-rx} ${y+rx}\" stroke=\"${c}\" stroke-width=\"3\" \/>`;\n                }\n                else if (d.shape === 'diamond') {\n                    svg += `<polygon points=\"${x},${y-s.fingerSize} ${x+s.fingerSize},${y} ${x},${y+s.fingerSize} ${x-s.fingerSize},${y}\" fill=\"${c}\" \/>`;\n                }\n                else if (d.shape === 'pentagon') {\n                    let pts = \"\";\n                    for (let j = 0; j < 5; j++) {\n                        let hX = x + s.fingerSize * Math.sin(j * 2 * Math.PI \/ 5);\n                        let hY = y - s.fingerSize * Math.cos(j * 2 * Math.PI \/ 5);\n                        pts += `${hX},${hY} `;\n                    }\n                    svg += `<polygon points=\"${pts.trim()}\" fill=\"${c}\" \/>`;\n                }\n                else if (d.shape === 'bordered-circle') {\n                    let br = Math.max(1, s.fingerSize - 1.25);\n                    svg += `<circle cx=\"${x}\" cy=\"${y}\" r=\"${br}\" fill=\"none\" stroke=\"${c}\" stroke-width=\"2.5\" \/>`;\n                }\n                \n                \/\/ Kh\u00f4ng in ch\u1eef tr\u00ean d\u1ea5u X\n                if (d.text && d.shape !== 'cross') {\n                    let tFill = (d.shape === 'bordered-circle' || d.shape === 'cross') ? c : '#fff';\n                    svg += `<text x=\"${x}\" y=\"${y}\" font-family=\"Arial\" font-size=\"${s.fontSize}\" font-weight=\"bold\" fill=\"${tFill}\" text-anchor=\"middle\" dominant-baseline=\"central\">${d.text}<\/text>`;\n                }\n            });\n            \n            if (!s.hideWatermark) {\n                svg += `<text x=\"${gridCenterX}\" y=\"${watermarkY}\" font-family=\"Arial\" font-size=\"14\" fill=\"#94a3b8\" text-anchor=\"middle\">nlguitar.com<\/text>`;\n            }\n            \n            svg += `<\/svg>`; \n            \n            const l = document.createElement('a'); l.href = URL.createObjectURL(new Blob([svg], {type: 'image\/svg+xml'}));\n            l.download = `${s.title || 'chord'}.svg`; l.click();\n        }\n\n        setTimeout(drawCanvas, 100);\n    <\/script>\n\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Diagram Chord Pro C\u00f4ng c\u1ee5 t\u1ea1o Chord v\u00e0 Scale cho Guitar\/Bass\/Ukulele hi\u1ec7n \u0111\u1ea1i v\u00e0 ho\u00e0n to\u00e0n mi\u1ec5n ph\u00ed.<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-2970","page","type-page","status-publish","hentry"],"blocksy_meta":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.5 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Diagram Chord Pro - NL Guitar<\/title>\n<meta name=\"description\" content=\"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nlguitar.com\/en\/diagram-chord-pro\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Diagram Chord Pro\" \/>\n<meta property=\"og:description\" content=\"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nlguitar.com\/en\/diagram-chord-pro\/\" \/>\n<meta property=\"og:site_name\" content=\"NL Guitar\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/nlguitarclass\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-12T16:30:02+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/\",\"name\":\"Diagram Chord Pro - NL Guitar\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#website\"},\"datePublished\":\"2026-05-06T04:53:05+00:00\",\"dateModified\":\"2026-05-12T16:30:02+00:00\",\"description\":\"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nlguitar.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Diagram Chord Pro\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#website\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/\",\"name\":\"NL Guitar\",\"description\":\"Kh\u00f3a h\u1ecdc Guitar Online, Tabs &amp; S\u00e1ch Guitar Chuy\u00ean s\u00e2u\",\"publisher\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/nlguitar.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Organization\",\"Place\"],\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#organization\",\"name\":\"NL Guitar\",\"alternateName\":\"NL Guitar Class\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/\",\"logo\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/#local-main-organization-logo\"},\"image\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/#local-main-organization-logo\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/nlguitarclass\\\/\"],\"description\":\"Chuy\u00ean cung c\u1ea5p c\u00e1c kho\u00e1 h\u1ecdc Guitar chuy\u00ean nghi\u1ec7p, Guitar Tabs, S\u00e1ch v\u00e0 Gi\u00e1o Tr\u00ecnh\",\"telephone\":[],\"openingHoursSpecification\":[{\"@type\":\"OpeningHoursSpecification\",\"dayOfWeek\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"],\"opens\":\"09:00\",\"closes\":\"17:00\"}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/diagram-chord-pro\\\/#local-main-organization-logo\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-Logo-26-2.png\",\"contentUrl\":\"https:\\\/\\\/nlguitar.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-Logo-26-2.png\",\"width\":512,\"height\":512,\"caption\":\"NL Guitar\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Diagram Chord Pro - NL Guitar","description":"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/nlguitar.com\/en\/diagram-chord-pro\/","og_locale":"en_US","og_type":"article","og_title":"Diagram Chord Pro","og_description":"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro","og_url":"https:\/\/nlguitar.com\/en\/diagram-chord-pro\/","og_site_name":"NL Guitar","article_publisher":"https:\/\/www.facebook.com\/nlguitarclass\/","article_modified_time":"2026-05-12T16:30:02+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/","url":"https:\/\/nlguitar.com\/diagram-chord-pro\/","name":"Diagram Chord Pro - NL Guitar","isPartOf":{"@id":"https:\/\/nlguitar.com\/#website"},"datePublished":"2026-05-06T04:53:05+00:00","dateModified":"2026-05-12T16:30:02+00:00","description":"C\u00f4ng c\u1ee5 t\u1ea1o s\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m, Diagram Chord, S\u01a1 \u0111\u1ed3 h\u1ee3p \u00e2m chuy\u00ean nghi\u1ec7p, s\u01a1 \u0111\u1ed3 mi\u1ec5n ph\u00ed NL Guitar Diagram Chord Pro","breadcrumb":{"@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nlguitar.com\/diagram-chord-pro\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nlguitar.com\/"},{"@type":"ListItem","position":2,"name":"Diagram Chord Pro"}]},{"@type":"WebSite","@id":"https:\/\/nlguitar.com\/#website","url":"https:\/\/nlguitar.com\/","name":"NL Guitar","description":"Kh\u00f3a h\u1ecdc Guitar Online, Tabs &amp; S\u00e1ch Guitar Chuy\u00ean s\u00e2u","publisher":{"@id":"https:\/\/nlguitar.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nlguitar.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Organization","Place"],"@id":"https:\/\/nlguitar.com\/#organization","name":"NL Guitar","alternateName":"NL Guitar Class","url":"https:\/\/nlguitar.com\/","logo":{"@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/#local-main-organization-logo"},"image":{"@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/#local-main-organization-logo"},"sameAs":["https:\/\/www.facebook.com\/nlguitarclass\/"],"description":"Chuy\u00ean cung c\u1ea5p c\u00e1c kho\u00e1 h\u1ecdc Guitar chuy\u00ean nghi\u1ec7p, Guitar Tabs, S\u00e1ch v\u00e0 Gi\u00e1o Tr\u00ecnh","telephone":[],"openingHoursSpecification":[{"@type":"OpeningHoursSpecification","dayOfWeek":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"opens":"09:00","closes":"17:00"}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nlguitar.com\/diagram-chord-pro\/#local-main-organization-logo","url":"https:\/\/nlguitar.com\/wp-content\/uploads\/2026\/04\/cropped-Logo-26-2.png","contentUrl":"https:\/\/nlguitar.com\/wp-content\/uploads\/2026\/04\/cropped-Logo-26-2.png","width":512,"height":512,"caption":"NL Guitar"}]}},"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/comments?post=2970"}],"version-history":[{"count":12,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2970\/revisions"}],"predecessor-version":[{"id":3408,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2970\/revisions\/3408"}],"wp:attachment":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/media?parent=2970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}