{"id":8907,"date":"2026-08-19T06:23:23","date_gmt":"2026-08-19T06:23:23","guid":{"rendered":"https:\/\/aiper.com\/blogs\/?page_id=8907"},"modified":"2026-10-21T09:12:57","modified_gmt":"2026-10-21T09:12:57","slug":"visualizador-espaciamiento-plantas","status":"publish","type":"page","link":"https:\/\/aiper.com\/blogs\/es\/visualizador-espaciamiento-plantas\/","title":{"rendered":"Visualizador de Espaciamiento de Plantas \u2013 Disena tu jardin antes de plantar"},"content":{"rendered":"\n<style>\n\/* ==========================================================================\n   Plant & Tree Spacing Visualizer \u2014 Brand: #1ecad3 + #9486f7 blended\n   Pure DOM\/CSS visualization (no Canvas). WAF-compatible: no inline styles.\n   ========================================================================== *\/\n#plant-visualizer {\n    max-width: 750px;\n    margin: 20px auto;\n    padding: 0 16px;\n    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n    box-sizing: border-box;\n}\n#plant-visualizer *, #plant-visualizer *::before, #plant-visualizer *::after { box-sizing: border-box; }\n\n\/* \u2500\u2500 Title \u2500\u2500 *\/\n.pv-title { text-align: center; font-size: 1.4rem; font-weight: 700; color: #1a202c; margin-bottom: 4px; }\n.pv-subtitle { text-align: center; font-size: 14px; color: #64748b; margin-bottom: 20px; }\n\n\/* \u2500\u2500 Unit Toggle \u2500\u2500 *\/\n.pv-unit-toggle { display: flex; justify-content: center; gap: 0; margin-bottom: 20px; }\n.pv-unit-btn {\n    padding: 10px 24px; font-size: 13px; font-weight: 600;\n    background: #f5f7fa; color: #64748b; border: 1px solid #e2e8f0;\n    cursor: pointer; transition: all 0.2s ease;\n}\n.pv-unit-btn:first-child { border-radius: 8px 0 0 8px; }\n.pv-unit-btn:last-child { border-radius: 0 8px 8px 0; }\n.pv-unit-btn:hover { background: #e8f7f8; color: #1ecad3; }\n.pv-unit-btn.active {\n    background: linear-gradient(135deg, #1ecad3, #9486f7);\n    color: #fff; border-color: transparent;\n}\n.pv-unit-btn:focus, .pv-unit-btn:active { outline: none; }\n\n\/* \u2500\u2500 Controls Grid \u2500\u2500 *\/\n.pv-controls {\n    display: grid; grid-template-columns: 1fr 1fr; gap: 14px;\n    margin-bottom: 16px;\n}\n.pv-field { display: flex; flex-direction: column; }\n.pv-field label {\n    font-size: 13px; font-weight: 600; color: #2c3e50; margin-bottom: 4px;\n}\n.pv-field input {\n    padding: 10px 12px; border: 1px solid #e2e8f0; border-radius: 8px;\n    font-size: 14px; color: #2c3e50; transition: border-color 0.2s ease;\n    background: #fff;\n}\n.pv-field input:focus { border-color: #9486f7; outline: none; box-shadow: 0 0 0 3px rgba(148,134,247,0.1); }\n.pv-unit-suffix { font-size: 11px; color: #94a3b8; margin-left: 2px; }\n\n\/* \u2500\u2500 Presets \u2500\u2500 *\/\n.pv-preset-label { font-size: 13px; font-weight: 600; color: #2c3e50; margin-bottom: 8px; }\n.pv-preset-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }\n.pv-preset-btn {\n    padding: 8px 14px; font-size: 12px; font-weight: 600;\n    border: 1px solid #e2e8f0; border-radius: 20px;\n    background: #fff; color: #475569; cursor: pointer;\n    transition: all 0.2s ease;\n}\n.pv-preset-btn:hover { border-color: #b2dfdb; background: #f8fdfc; }\n.pv-preset-btn:focus, .pv-preset-btn:active { color: #2c3e50; outline: none; }\n.pv-preset-btn.selected {\n    border-color: #9486f7; background: #f5f3ff; color: #2c3e50;\n    box-shadow: 0 0 0 2px rgba(148,134,247,0.12);\n}\n\n\/* \u2500\u2500 Pattern Selector \u2500\u2500 *\/\n.pv-pattern-label { font-size: 13px; font-weight: 600; color: #2c3e50; margin-bottom: 8px; }\n.pv-pattern-buttons { display: flex; gap: 10px; margin-bottom: 16px; }\n.pv-pattern-btn {\n    flex: 1; padding: 12px 16px; font-size: 13px; font-weight: 600;\n    border: 2px solid #e2e8f0; border-radius: 10px;\n    background: #fff; color: #475569; cursor: pointer;\n    transition: all 0.2s ease; text-align: center;\n}\n.pv-pattern-btn:hover { border-color: #b2dfdb; }\n.pv-pattern-btn:focus, .pv-pattern-btn:active { color: #2c3e50; outline: none; }\n.pv-pattern-btn.selected {\n    border-color: #9486f7; background: #f5f3ff; color: #2c3e50;\n}\n\n\/* \u2500\u2500 Bed Visualization Area \u2500\u2500 *\/\n.pv-canvas-wrapper {\n    text-align: center; margin-bottom: 16px;\n    background: #fafafa; border-radius: 12px; padding: 20px 16px 40px;\n    border: 1px solid #e2e8f0;\n}\n#pv-bed-frame {\n    position: relative; display: inline-block;\n    max-width: 100%;\n}\n#pv-dim-label {\n    text-align: center; font-size: 11px; color: #2c3e50; font-weight: 600;\n    margin-bottom: 6px;\n}\n#pv-bed-area {\n    position: relative; background: #f5ebe0;\n    border: 2px solid #8B7355; border-radius: 2px;\n    margin: 0 auto;\n}\n.pv-grid-line-h, .pv-grid-line-v {\n    position: absolute; pointer-events: none;\n}\n.pv-grid-line-h { left: 0; right: 0; border-top: 1px dashed #d5c4a1; }\n.pv-grid-line-v { top: 0; bottom: 0; border-left: 1px dashed #d5c4a1; }\n.pv-plant {\n    position: absolute; border-radius: 50%; transform: translate(-50%, -50%);\n}\n.pv-plant-canopy {\n    background: rgba(143, 188, 143, 0.45);\n    border: 1px solid #5b8c5a;\n}\n.pv-plant-stem {\n    background: #5b8c5a; z-index: 1;\n}\n#pv-scale-bar {\n    display: flex; align-items: center; justify-content: center;\n    margin-top: 10px; gap: 6px;\n}\n#pv-scale-line {\n    height: 1.5px; background: #2c3e50;\n}\n#pv-scale-label {\n    font-size: 11px; color: #2c3e50; white-space: nowrap;\n}\n\n\/* \u2500\u2500 Results \u2500\u2500 *\/\n.pv-results {\n    display: flex; flex-wrap: wrap; justify-content: center; gap: 12px 24px;\n    padding: 14px 20px; background: #f5f7fa; border-radius: 10px;\n    margin-bottom: 20px;\n}\n.pv-result-item { text-align: center; }\n.pv-result-value { font-size: 1.3rem; font-weight: 700; color: #1ecad3; }\n.pv-result-label { font-size: 11px; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; }\n\n\/* \u2500\u2500 Tool Links (cross-refs) \u2500\u2500 *\/\n.pv-tool-links { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 20px; }\n.pv-tool-link {\n    display: inline-block; padding: 8px 16px;\n    background: #f5f7fa; color: #6b5ce7; border: 1px solid #e8e3fc;\n    border-radius: 22px; font-size: 12px; font-weight: 600;\n    text-decoration: none; transition: all 0.2s ease;\n}\n.pv-tool-link:hover { background: #ede9fe; color: #5a4bd1; border-color: #9486f7; }\n.pv-tool-link:focus, .pv-tool-link:active { color: #5a4bd1; outline: none; }\n\n\/* \u2500\u2500 CTA \u2500\u2500 *\/\n.pv-cta {\n    padding: 16px 20px; background: #f0fcfc; border-radius: 12px;\n    border: 1px solid #b2dfdb; text-align: center; margin-bottom: 20px;\n}\n.pv-cta p { margin: 0 0 8px; font-size: 13px; color: #475569; line-height: 1.5; }\n.pv-cta a {\n    display: inline-block; padding: 10px 24px;\n    background: linear-gradient(135deg, #1ecad3, #9486f7);\n    color: #fff; border-radius: 8px; text-decoration: none;\n    font-weight: 700; font-size: 14px;\n    transition: all 0.2s ease;\n}\n.pv-cta a:hover { transform: translateY(-1px); box-shadow: 0 4px 16px rgba(148,134,247,0.35); }\n\n\/* \u2500\u2500 Validation \u2500\u2500 *\/\n.pv-error { color: #e53e3e; font-size: 11px; margin-top: 2px; min-height: 16px; }\n\n\/* \u2500\u2500 JS Status \/ Error Banner \u2500\u2500 *\/\n#pv-js-status {\n    text-align: center; padding: 8px 12px; margin-bottom: 12px;\n    background: #fffbe6; border: 1px solid #f6e05e; border-radius: 8px;\n    font-size: 12px; font-weight: 600; color: #975a16;\n}\n#pv-error-msg {\n    display: none; padding: 12px 16px; background: #fff5f5;\n    border: 1px solid #feb2b2; border-radius: 8px;\n    color: #c53030; font-size: 13px; margin-bottom: 16px;\n}\n\n\/* \u2500\u2500 Responsive \u2500\u2500 *\/\n@media (max-width: 600px) {\n    .pv-controls { grid-template-columns: 1fr; }\n    .pv-preset-buttons { justify-content: center; }\n    .pv-preset-btn { flex: 1; min-width: 80px; text-align: center; }\n    .pv-results { flex-direction: column; gap: 8px; }\n    .pv-canvas-wrapper { padding: 12px 8px 32px; }\n    #plant-visualizer { padding: 0 8px; }\n}\n<\/style>\n\n<div id=\"plant-visualizer\">\n    <div id=\"pv-js-status\">LOADING&#8230; JS not yet executed<\/div>\n\n    <div class=\"pv-title\" id=\"pv-title\">Plant &amp; Tree Spacing Visualizer<\/div>\n    <div class=\"pv-subtitle\" id=\"pv-subtitle\">See how your plants will look before you dig<\/div>\n\n    <div id=\"pv-error-msg\"><\/div>\n\n    <!-- Unit Toggle -->\n    <div class=\"pv-unit-toggle\" role=\"radiogroup\" aria-label=\"Unit System\">\n        <button type=\"button\" class=\"pv-unit-btn active\" data-unit=\"imperial\" id=\"pv-unit-imp\">ft \/ in<\/button>\n        <button type=\"button\" class=\"pv-unit-btn\" data-unit=\"metric\" id=\"pv-unit-met\">m \/ cm<\/button>\n    <\/div>\n\n    <!-- Bed Dimensions -->\n    <div class=\"pv-controls\">\n        <div class=\"pv-field\">\n            <label for=\"pv-bed-width\" id=\"pv-label-width\">Bed Width (<span class=\"pv-unit-suffix\" id=\"pv-unit-w\">ft<\/span>)<\/label>\n            <input type=\"number\" id=\"pv-bed-width\" step=\"any\" min=\"0.1\" value=\"8\" placeholder=\"e.g. 8\" inputmode=\"decimal\">\n            <div class=\"pv-error\" id=\"pv-err-width\"><\/div>\n        <\/div>\n        <div class=\"pv-field\">\n            <label for=\"pv-bed-length\" id=\"pv-label-length\">Bed Length (<span class=\"pv-unit-suffix\" id=\"pv-unit-l\">ft<\/span>)<\/label>\n            <input type=\"number\" id=\"pv-bed-length\" step=\"any\" min=\"0.1\" value=\"12\" placeholder=\"e.g. 12\" inputmode=\"decimal\">\n            <div class=\"pv-error\" id=\"pv-err-length\"><\/div>\n        <\/div>\n    <\/div>\n\n    <!-- Plant Type Presets -->\n    <div class=\"pv-preset-label\" id=\"pv-preset-label\">Quick Presets<\/div>\n    <div class=\"pv-preset-buttons\" id=\"pv-presets\"><\/div>\n\n    <!-- Spacing + Canopy -->\n    <div class=\"pv-controls\">\n        <div class=\"pv-field\">\n            <label for=\"pv-spacing\" id=\"pv-label-spacing\">Plant Spacing (<span class=\"pv-unit-suffix\" id=\"pv-unit-s\">in<\/span>)<\/label>\n            <input type=\"number\" id=\"pv-spacing\" step=\"any\" min=\"0.1\" value=\"18\" placeholder=\"e.g. 18\" inputmode=\"decimal\">\n            <div class=\"pv-error\" id=\"pv-err-spacing\"><\/div>\n        <\/div>\n        <div class=\"pv-field\">\n            <label for=\"pv-canopy\" id=\"pv-label-canopy\">Canopy at Maturity (<span class=\"pv-unit-suffix\" id=\"pv-unit-c\">in<\/span>)<\/label>\n            <input type=\"number\" id=\"pv-canopy\" step=\"any\" min=\"0.1\" value=\"14\" placeholder=\"e.g. 14\" inputmode=\"decimal\">\n            <div class=\"pv-error\" id=\"pv-err-canopy\"><\/div>\n        <\/div>\n    <\/div>\n\n    <!-- Layout Pattern -->\n    <div class=\"pv-pattern-label\" id=\"pv-pattern-label\">Layout Pattern<\/div>\n    <div class=\"pv-pattern-buttons\" role=\"radiogroup\" aria-label=\"Layout Pattern\">\n        <button type=\"button\" class=\"pv-pattern-btn selected\" data-pattern=\"square\" id=\"pv-pat-square\">Square Grid<\/button>\n        <button type=\"button\" class=\"pv-pattern-btn\" data-pattern=\"staggered\" id=\"pv-pat-staggered\">Staggered \/ Triangular<\/button>\n    <\/div>\n\n    <!-- Bed Visualization (DOM-based, no Canvas) -->\n    <div class=\"pv-canvas-wrapper\">\n        <div id=\"pv-dim-label\"><\/div>\n        <div id=\"pv-bed-frame\">\n            <div id=\"pv-bed-area\"><\/div>\n        <\/div>\n        <div id=\"pv-scale-bar\">\n            <span id=\"pv-scale-left\"><\/span>\n            <span id=\"pv-scale-line\"><\/span>\n            <span id=\"pv-scale-right\"><\/span>\n            <span id=\"pv-scale-label\"><\/span>\n        <\/div>\n    <\/div>\n\n    <!-- Results -->\n    <div class=\"pv-results\" id=\"pv-results\">\n        <div class=\"pv-result-item\">\n            <div class=\"pv-result-value\" id=\"pv-val-total\">0<\/div>\n            <div class=\"pv-result-label\" id=\"pv-lbl-total\">Total Plants<\/div>\n        <\/div>\n        <div class=\"pv-result-item\">\n            <div class=\"pv-result-value\" id=\"pv-val-rows\">0<\/div>\n            <div class=\"pv-result-label\" id=\"pv-lbl-rows\">Rows<\/div>\n        <\/div>\n        <div class=\"pv-result-item\">\n            <div class=\"pv-result-value\" id=\"pv-val-cols\">0<\/div>\n            <div class=\"pv-result-label\" id=\"pv-lbl-cols\">Columns<\/div>\n        <\/div>\n        <div class=\"pv-result-item\">\n            <div class=\"pv-result-value\" id=\"pv-val-area\">0<\/div>\n            <div class=\"pv-result-label\" id=\"pv-lbl-area\">Bed Area<\/div>\n        <\/div>\n    <\/div>\n\n    <!-- CTA -->\n    <div class=\"pv-cta\" id=\"pv-cta\">\n        <p id=\"pv-cta-text\"><\/p>\n        <a href=\"https:\/\/aiper.com\/blogs\/plant-spacing-calculator\/\" id=\"pv-cta-link\">Calculate plant quantity<\/a>\n    <\/div>\n\n    <!-- Cross-reference tool links -->\n    <div class=\"pv-tool-links\" id=\"pv-tools\"><\/div>\n<\/div>\n\n<script>\n(function() {\n    \/\/ \u2500\u2500 Labels \u2500\u2500\n    var LABELS = {\"title\": \"Visualizador de espaciamiento de plantas\", \"subtitle\": \"Vea c\u00f3mo se ver\u00e1n sus plantas antes de excavar\", \"unitImperial\": \"ft \/ in\", \"unitMetric\": \"m \/ cm\", \"bedLabelWidth\": \"Ancho del bancal\", \"bedLabelLength\": \"Largo del bancal\", \"bedLabelWidthM\": \"Ancho del bancal (m)\", \"bedLabelLengthM\": \"Largo del bancal (m)\", \"unitFt\": \"ft\", \"unitIn\": \"in\", \"unitM\": \"m\", \"unitCm\": \"cm\", \"unitSqft\": \"ft\u00b2\", \"unitSqm\": \"m\u00b2\", \"presetLabel\": \"Preajustes r\u00e1pidos\", \"presetKeys\": [\"vegetables\", \"root_veg\", \"leafy\", \"hedge\", \"shrubs\", \"trees_small\", \"custom\"], \"presets\": {\"vegetables\": {\"label\": \"Hortalizas (tomates, pimientos)\", \"spacing_in\": 24, \"canopy_in\": 18}, \"root_veg\": {\"label\": \"Ra\u00edces (zanahorias, cebollas)\", \"spacing_in\": 4, \"canopy_in\": 3}, \"leafy\": {\"label\": \"Hojas verdes (lechuga, col rizada)\", \"spacing_in\": 12, \"canopy_in\": 10}, \"hedge\": {\"label\": \"Setos \/ borduras\", \"spacing_in\": 16, \"canopy_in\": 14}, \"shrubs\": {\"label\": \"Arbustos \/ matorrales\", \"spacing_in\": 36, \"canopy_in\": 30}, \"trees_small\": {\"label\": \"\u00c1rboles peque\u00f1os (1,8-2,4 m)\", \"spacing_in\": 84, \"canopy_in\": 72}, \"custom\": {\"label\": \"Personalizado\", \"spacing_in\": 0, \"canopy_in\": 0}}, \"spacingLabel\": \"Espaciamiento de plantas\", \"canopyLabel\": \"Di\u00e1metro de la copa\", \"patternLabel\": \"Dise\u00f1o de plantaci\u00f3n\", \"patternSquare\": \"Cuadr\u00edcula cuadrada\", \"patternStaggered\": \"Tresbolillo \/ triangular\", \"resultTotalPlants\": \"Total de plantas\", \"resultRows\": \"Filas\", \"resultCols\": \"Columnas\", \"resultArea\": \"Superficie del bancal\", \"toolLinks\": {\"plantCalc\": {\"href\": \"https:\/\/aiper.com\/blogs\/es\/calculadora-espaciamiento-plantas\/\", \"label\": \"calculadora espaciamiento plantas\"}, \"soilCalc\": {\"href\": \"https:\/\/aiper.com\/blogs\/es\/calculadora-tierra-jardin\/\", \"label\": \"calculadora tierra jard\u00edn\"}, \"mulchCalc\": {\"href\": \"https:\/\/aiper.com\/blogs\/es\/calculadora-mantillo\/\", \"label\": \"calculadora mantillo\"}, \"grassSeed\": {\"href\": \"https:\/\/aiper.com\/blogs\/es\/calculadora-semillas-cesped\/\", \"label\": \"calculadora semillas c\u00e9sped\"}}, \"validationError\": \"Ingrese un n\u00famero positivo\", \"canopyWarning\": \"Di\u00e1metro > espaciamiento: las plantas podr\u00edan superponerse\", \"canvasPlaceholder\": \"Ingrese dimensiones del bancal y espaciamiento para ver el dise\u00f1o\", \"ctaText\": \"\u00bfListo para comprar? Use nuestra <strong>calculadora de espaciamiento de plantas<\/strong> para obtener la cantidad exacta de plantas, semillas o bulbos que necesita \u2014 con margen incluido.\", \"ctaLink\": \"Calcular cantidad de plantas\"};\n\n    \/\/ \u2500\u2500 Helpers \u2500\u2500\n    var $ = function(id) { return document.getElementById(id); };\n    function L(path) {\n        var keys = path.split('.'), v = LABELS;\n        for (var i = 0; i < keys.length; i++) { v = v[keys[i]]; if (v === undefined) return ''; }\n        return v;\n    }\n    function setText(id, txt) { var e = $(id); if (e) e.textContent = txt; }\n    function _and() { var n = arguments.length; while (n--) { if (!arguments[n]) return false; } return true; }\n\n    \/\/ \u2500\u2500 State \u2500\u2500\n    var state = { unit: 'imperial', bedW: 8, bedL: 12, spacing: 18, canopy: 14, pattern: 'square' };\n\n    \/\/ \u2500\u2500 DOM refs \u2500\u2500\n    var bedAreaEl = $('pv-bed-area');\n    var bedFrameEl = $('pv-bed-frame');\n    var dimLabel = $('pv-dim-label');\n    var scaleBar = $('pv-scale-bar');\n    var scaleLine = $('pv-scale-line');\n    var scaleLabel = $('pv-scale-label');\n    var scaleLeft = $('pv-scale-left');\n    var scaleRight = $('pv-scale-right');\n\n    \/\/ \u2500\u2500 Set initial UI text \u2500\u2500\n    setText('pv-title', L('title'));\n    setText('pv-subtitle', L('subtitle'));\n    setText('pv-unit-imp', L('unitImperial'));\n    setText('pv-unit-met', L('unitMetric'));\n    setText('pv-preset-label', L('presetLabel'));\n    setText('pv-pattern-label', L('patternLabel'));\n    setText('pv-pat-square', L('patternSquare'));\n    setText('pv-pat-staggered', L('patternStaggered'));\n    setText('pv-lbl-total', L('resultTotalPlants'));\n    setText('pv-lbl-rows', L('resultRows'));\n    setText('pv-lbl-cols', L('resultCols'));\n    setText('pv-lbl-area', L('resultArea'));\n    var ctaTextEl = $('pv-cta-text');\n    if (ctaTextEl) ctaTextEl.innerHTML = L('ctaText');\n    setText('pv-cta-link', L('ctaLink'));\n\n    \/\/ \u2500\u2500 Build preset buttons \u2500\u2500\n    var presetDiv = $('pv-presets');\n    var pkeys = L('presetKeys');\n    if (_and(presetDiv, pkeys, pkeys.length)) {\n        presetDiv.innerHTML = '';\n        for (var i = 0; i < pkeys.length; i++) {\n            var key = pkeys[i];\n            var p = L('presets.' + key);\n            if (!p || !p.label) continue;\n            var btn = document.createElement('button');\n            btn.type = 'button';\n            btn.className = 'pv-preset-btn';\n            btn.setAttribute('data-preset', key);\n            btn.textContent = p.label;\n            btn.addEventListener('click', (function(k) { return function() { applyPreset(k); }; })(key));\n            presetDiv.appendChild(btn);\n        }\n    }\n\n    \/\/ \u2500\u2500 Build tool links \u2500\u2500\n    var toolsDiv = $('pv-tools');\n    if (toolsDiv) {\n        toolsDiv.innerHTML = '';\n        var tlKeys = Object.keys(LABELS.toolLinks || {});\n        for (var j = 0; j < tlKeys.length; j++) {\n            var tl = L('toolLinks.' + tlKeys[j]);\n            if (!tl || !tl.href) continue;\n            var a = document.createElement('a');\n            a.className = 'pv-tool-link';\n            a.href = tl.href;\n            a.textContent = tl.label;\n            toolsDiv.appendChild(a);\n        }\n    }\n\n    \/\/ \u2500\u2500 Unit labels \u2500\u2500\n    function updateUnitLabels() {\n        var isImp = state.unit === 'imperial';\n        var unitLen = isImp ? L('unitFt') : L('unitM');\n        var unitSmall = isImp ? L('unitIn') : L('unitCm');\n        var labelW = $('pv-label-width');\n        if (labelW) labelW.innerHTML = L('bedLabelWidth') + ' (<span class=\"pv-unit-suffix\" id=\"pv-unit-w\">' + unitLen + '<\/span>)';\n        var labelL = $('pv-label-length');\n        if (labelL) labelL.innerHTML = L('bedLabelLength') + ' (<span class=\"pv-unit-suffix\" id=\"pv-unit-l\">' + unitLen + '<\/span>)';\n        var spLabel = $('pv-label-spacing');\n        if (spLabel) spLabel.innerHTML = L('spacingLabel') + ' (<span class=\"pv-unit-suffix\" id=\"pv-unit-s\">' + unitSmall + '<\/span>)';\n        var cnLabel = $('pv-label-canopy');\n        if (cnLabel) cnLabel.innerHTML = L('canopyLabel') + ' (<span class=\"pv-unit-suffix\" id=\"pv-unit-c\">' + unitSmall + '<\/span>)';\n        var bwEl = $('pv-bed-width'); if (bwEl) bwEl.placeholder = isImp ? 'e.g. 8' : 'e.g. 2.5';\n        var blEl = $('pv-bed-length'); if (blEl) blEl.placeholder = isImp ? 'e.g. 12' : 'e.g. 3.5';\n        var spEl = $('pv-spacing'); if (spEl) spEl.placeholder = isImp ? 'e.g. 18' : 'e.g. 45';\n        var cnEl = $('pv-canopy'); if (cnEl) cnEl.placeholder = isImp ? 'e.g. 14' : 'e.g. 35';\n    }\n    updateUnitLabels();\n\n    \/\/ \u2500\u2500 Apply Preset \u2500\u2500\n    function applyPreset(key) {\n        var btns = document.querySelectorAll('.pv-preset-btn');\n        btns.forEach(function(b) { b.classList.remove('selected'); });\n        var active = document.querySelector('.pv-preset-btn[data-preset=\"' + key + '\"]');\n        if (active) active.classList.add('selected');\n        if (key === 'custom') return;\n        var p = L('presets.' + key);\n        if (!p) return;\n        if (state.unit === 'imperial') { state.spacing = p.spacing_in; state.canopy = p.canopy_in; }\n        else { state.spacing = Math.round(p.spacing_in * 2.54 * 10) \/ 10; state.canopy = Math.round(p.canopy_in * 2.54 * 10) \/ 10; }\n        var spEl = $('pv-spacing'); if (spEl) spEl.value = state.spacing;\n        var cnEl = $('pv-canopy'); if (cnEl) cnEl.value = state.canopy;\n        draw();\n    }\n\n    \/\/ \u2500\u2500 Unit Toggle \u2500\u2500\n    function setUnit(unit) {\n        if (state.unit === unit) return;\n        var wasImp = state.unit === 'imperial', nowImp = unit === 'imperial';\n        state.unit = unit;\n        var impBtn = $('pv-unit-imp'), metBtn = $('pv-unit-met');\n        if (impBtn) { impBtn.classList.remove('active'); if (nowImp) impBtn.classList.add('active'); }\n        if (metBtn) { metBtn.classList.remove('active'); if (!nowImp) metBtn.classList.add('active'); }\n        if (_and(wasImp, !nowImp)) {\n            state.bedW = Math.round(state.bedW * 0.3048 * 100) \/ 100;\n            state.bedL = Math.round(state.bedL * 0.3048 * 100) \/ 100;\n            state.spacing = Math.round(state.spacing * 2.54 * 10) \/ 10;\n            state.canopy = Math.round(state.canopy * 2.54 * 10) \/ 10;\n        } else if (_and(!wasImp, nowImp)) {\n            state.bedW = Math.round(state.bedW \/ 0.3048 * 100) \/ 100;\n            state.bedL = Math.round(state.bedL \/ 0.3048 * 100) \/ 100;\n            state.spacing = Math.round(state.spacing \/ 2.54 * 10) \/ 10;\n            state.canopy = Math.round(state.canopy \/ 2.54 * 10) \/ 10;\n        }\n        var bwEl = $('pv-bed-width'); if (bwEl) bwEl.value = state.bedW;\n        var blEl = $('pv-bed-length'); if (blEl) blEl.value = state.bedL;\n        var spEl = $('pv-spacing'); if (spEl) spEl.value = state.spacing;\n        var cnEl = $('pv-canopy'); if (cnEl) cnEl.value = state.canopy;\n        updateUnitLabels();\n        draw();\n    }\n\n    \/\/ \u2500\u2500 Event Listeners \u2500\u2500\n    $('pv-unit-imp').addEventListener('click', function() { setUnit('imperial'); });\n    $('pv-unit-met').addEventListener('click', function() { setUnit('metric'); });\n    $('pv-pat-square').addEventListener('click', function() {\n        state.pattern = 'square';\n        $('pv-pat-square').classList.add('selected');\n        $('pv-pat-staggered').classList.remove('selected');\n        draw();\n    });\n    $('pv-pat-staggered').addEventListener('click', function() {\n        state.pattern = 'staggered';\n        $('pv-pat-staggered').classList.add('selected');\n        $('pv-pat-square').classList.remove('selected');\n        draw();\n    });\n\n    function readInputs() {\n        var bwEl = $('pv-bed-width'), blEl = $('pv-bed-length');\n        var spEl = $('pv-spacing'), cnEl = $('pv-canopy');\n        if (!bwEl || !blEl || !spEl || !cnEl) return;\n        var bw = parseFloat(bwEl.value), bl = parseFloat(blEl.value);\n        var sp = parseFloat(spEl.value), cn = parseFloat(cnEl.value);\n        var valid = true;\n        var errW = $('pv-err-width'), errL = $('pv-err-length');\n        var errS = $('pv-err-spacing'), errC = $('pv-err-canopy');\n        if (isNaN(bw) || bw <= 0) { if (errW) errW.textContent = L('validationError'); valid = false; }\n        else { if (errW) errW.textContent = ''; state.bedW = bw; }\n        if (isNaN(bl) || bl <= 0) { if (errL) errL.textContent = L('validationError'); valid = false; }\n        else { if (errL) errL.textContent = ''; state.bedL = bl; }\n        if (isNaN(sp) || sp <= 0) { if (errS) errS.textContent = L('validationError'); valid = false; }\n        else { if (errS) errS.textContent = ''; state.spacing = sp; }\n        if (isNaN(cn) || cn <= 0) { if (errC) errC.textContent = L('validationError'); valid = false; }\n        else if (cn > sp) { if (errC) errC.textContent = L('canopyWarning'); state.canopy = cn; }\n        else { if (errC) errC.textContent = ''; state.canopy = cn; }\n        var btns = document.querySelectorAll('.pv-preset-btn');\n        btns.forEach(function(b) { b.classList.remove('selected'); });\n        if (valid) draw();\n    }\n\n    function debounce(fn, delay) { var t; return function() { clearTimeout(t); t = setTimeout(fn, delay); }; }\n    ['pv-bed-width','pv-bed-length','pv-spacing','pv-canopy'].forEach(function(id) {\n        var el = $(id); if (el) el.addEventListener('input', debounce(readInputs, 200));\n    });\n\n    \/\/ \u2500\u2500 DOM-based Drawing (no Canvas) \u2500\u2500\n    var MAX_PX = 550;  \/\/ max bed display width in px\n\n    function draw() {\n        if (!bedAreaEl || !bedFrameEl) return;\n\n        \/\/ Normalize to bed units (ft or m)\n        var unitFactor = state.unit === 'imperial' ? 12 : 100;\n        var spacingBU = state.spacing \/ unitFactor;\n        var canopyBU = state.canopy \/ unitFactor;\n\n        \/\/ Compute positions first (for results + draw)\n        var rows, cols, positions = [];\n        if (_and(state.bedW > 0, state.bedL > 0, spacingBU > 0)) {\n            if (state.pattern === 'square') {\n                cols = Math.floor(state.bedW \/ spacingBU);\n                rows = Math.floor(state.bedL \/ spacingBU);\n                if (_and(cols > 0, rows > 0)) {\n                    var edgeX = (state.bedW - (cols - 1) * spacingBU) \/ 2;\n                    var edgeY = (state.bedL - (rows - 1) * spacingBU) \/ 2;\n                    for (var r = 0; r < rows; r++) {\n                        for (var c = 0; c < cols; c++) {\n                            positions.push({ x: edgeX + c * spacingBU, y: edgeY + r * spacingBU });\n                        }\n                    }\n                }\n            } else {\n                var rowSpacing = spacingBU * Math.sqrt(3) \/ 2;\n                cols = Math.floor(state.bedW \/ spacingBU);\n                rows = Math.floor((state.bedL - spacingBU) \/ rowSpacing) + 1;\n                if (_and(cols > 0, rows > 0)) {\n                    var edgeX = (state.bedW - (cols - 1) * spacingBU) \/ 2;\n                    var edgeY = (state.bedL - (rows - 1) * rowSpacing) \/ 2;\n                    for (var r = 0; r < rows; r++) {\n                        var offset = (r % 2 === 1) ? spacingBU \/ 2 : 0;\n                        var colsInRow = (_and(r % 2 === 1, (edgeX + (cols - 1) * spacingBU + offset + spacingBU \/ 2) > state.bedW)) ? cols - 1 : cols;\n                        for (var c = 0; c < colsInRow; c++) {\n                            positions.push({ x: edgeX + c * spacingBU + offset, y: edgeY + r * rowSpacing });\n                        }\n                    }\n                }\n            }\n        }\n        if (cols < 1) cols = 0;\n        if (rows < 1) rows = 0;\n\n        \/\/ \u2500\u2500 Render bed area as DOM \u2500\u2500\n        var aspect = _and(state.bedW > 0, state.bedL > 0) ? state.bedW \/ state.bedL : 1.33;\n        var pxW, pxH;\n        if (aspect >= 1) { pxW = MAX_PX; pxH = Math.round(MAX_PX \/ aspect); }\n        else { pxH = MAX_PX; pxW = Math.round(MAX_PX * aspect); }\n\n        bedFrameEl.style.width = pxW + 'px';\n        bedAreaEl.style.width = pxW + 'px';\n        bedAreaEl.style.height = pxH + 'px';\n\n        \/\/ Scale factor: px per bed unit\n        var scale = pxW \/ state.bedW;\n\n        \/\/ Clear previous plants and grid lines\n        bedAreaEl.innerHTML = '';\n\n        \/\/ Draw grid lines\n        if (spacingBU > 0) {\n            var x = spacingBU;\n            while (x < state.bedW) {\n                var gx = Math.round(x * scale);\n                var line = document.createElement('div');\n                line.className = 'pv-grid-line-v';\n                line.style.left = gx + 'px';\n                bedAreaEl.appendChild(line);\n                x += spacingBU;\n            }\n            var y = spacingBU;\n            while (y < state.bedL) {\n                var gy = Math.round(y * scale);\n                var line = document.createElement('div');\n                line.className = 'pv-grid-line-h';\n                line.style.top = gy + 'px';\n                bedAreaEl.appendChild(line);\n                y += spacingBU;\n            }\n        }\n\n        \/\/ Draw plants\n        for (var i = 0; i < positions.length; i++) {\n            var px = Math.round(positions[i].x * scale);\n            var py = Math.round(positions[i].y * scale);\n            var canopyPx = Math.max(Math.round(canopyBU * scale), 3);\n\n            \/\/ Canopy circle\n            var canopy = document.createElement('div');\n            canopy.className = 'pv-plant pv-plant-canopy';\n            canopy.style.left = px + 'px';\n            canopy.style.top = py + 'px';\n            canopy.style.width = canopyPx + 'px';\n            canopy.style.height = canopyPx + 'px';\n            bedAreaEl.appendChild(canopy);\n\n            \/\/ Stem dot\n            var stemPx = Math.max(Math.round(canopyPx * 0.25), 2);\n            var stem = document.createElement('div');\n            stem.className = 'pv-plant pv-plant-stem';\n            stem.style.left = px + 'px';\n            stem.style.top = py + 'px';\n            stem.style.width = stemPx + 'px';\n            stem.style.height = stemPx + 'px';\n            bedAreaEl.appendChild(stem);\n        }\n\n        \/\/ Dimension label\n        var dimUnit = state.unit === 'imperial' ? L('unitFt') : L('unitM');\n        dimLabel.textContent = state.bedW + ' ' + dimUnit + ' x ' + state.bedL + ' ' + dimUnit;\n\n        \/\/ Scale bar\n        var scaleBarLen = Math.min(100, pxW * 0.35);\n        var scaleVal, scaleUnitLbl;\n        if (state.unit === 'imperial') {\n            var ftPer100 = 100 \/ scale;\n            if (ftPer100 < 1) { scaleVal = 1; scaleUnitLbl = L('unitFt'); scaleBarLen = Math.round(1 * scale); }\n            else if (ftPer100 < 5) { scaleVal = Math.round(ftPer100); scaleUnitLbl = L('unitFt'); scaleBarLen = Math.round(scaleVal * scale); }\n            else { scaleVal = Math.round(ftPer100 \/ 5) * 5; scaleUnitLbl = L('unitFt'); scaleBarLen = Math.round(scaleVal * scale); }\n        } else {\n            var mPer100 = 100 \/ scale;\n            if (mPer100 < 0.3) { scaleVal = Math.round(mPer100 * 100 \/ 10) * 10; scaleUnitLbl = L('unitCm'); scaleBarLen = Math.round(scaleVal \/ 100 * scale); }\n            else { scaleVal = Math.round(mPer100 * 10) \/ 10; scaleUnitLbl = L('unitM'); scaleBarLen = Math.round(scaleVal * scale); }\n        }\n        scaleLine.style.width = Math.max(scaleBarLen, 20) + 'px';\n        scaleLabel.textContent = scaleVal + ' ' + scaleUnitLbl;\n\n        \/\/ Results\n        updateResults(positions.length, rows, cols, state.bedW * state.bedL);\n    }\n\n    function updateResults(total, rows, cols, area) {\n        var vt = $('pv-val-total'); if (vt) vt.textContent = total;\n        var vr = $('pv-val-rows'); if (vr) vr.textContent = rows;\n        var vc = $('pv-val-cols'); if (vc) vc.textContent = cols;\n        var va = $('pv-val-area');\n        if (va) { var isImp = state.unit === 'imperial'; va.textContent = Math.round(area * 100) \/ 100 + ' ' + (isImp ? L('unitSqft') : L('unitSqm')); }\n    }\n\n    \/\/ \u2500\u2500 Initial draw \u2500\u2500\n    draw();\n\n    \/\/ Hide loading banner\n    var statusEl = $('pv-js-status');\n    if (statusEl) { statusEl.textContent = ''; statusEl.style.display = 'none'; }\n})();\n<\/script>\n<h2 class=\"wp-block-heading\">C\u00f3mo funciona este visualizador<\/h2>\n\n<p class=\"wp-block-paragraph\">Esta herramienta interactiva dibuja una vista superior a escala de su bancal de jard\u00edn, mostrando exactamente c\u00f3mo se dispondr\u00e1n sus plantas, arbustos o \u00e1rboles. Ajuste las dimensiones, el espaciamiento y el dise\u00f1o de plantaci\u00f3n para ver el resultado en tiempo real \u2014 sin conjeturas ni papel milimetrado.<\/p>\n\n<h3 class=\"wp-block-heading\">Paso 1: Establezca las dimensiones de su bancal<\/h3>\n\n<p class=\"wp-block-paragraph\">Ingrese el ancho y largo de su bancal en pies o metros. El lienzo se escala autom\u00e1ticamente para adaptarse a las proporciones de su bancal, por lo que tanto un bancal largo y estrecho como uno cuadrado se muestran correctamente.<\/p>\n\n<h3 class=\"wp-block-heading\">Paso 2: Elija el tipo de planta y el espaciamiento<\/h3>\n\n<p class=\"wp-block-paragraph\">Use los <strong>preajustes r\u00e1pidos<\/strong> para completar autom\u00e1ticamente los valores t\u00edpicos de espaciamiento y di\u00e1metro de copa para tipos de plantas comunes \u2014 hortalizas como tomates y zanahorias, arbustos y \u00e1rboles peque\u00f1os. O ingrese valores personalizados manualmente. El di\u00e1metro de la copa controla el tama\u00f1o de los c\u00edrculos de plantas en el diagrama.<\/p>\n\n<h3 class=\"wp-block-heading\">Paso 3: Elija un dise\u00f1o de plantaci\u00f3n<\/h3>\n\n<p class=\"wp-block-paragraph\"><strong>Cuadr\u00edcula cuadrada<\/strong> organiza las plantas en filas y columnas rectas \u2014 ideal para cultivos en hilera y jardines formales. <strong>Tresbolillo (triangular)<\/strong> desplaza cada fila alterna la mitad del espaciamiento, permitiendo hasta un 15 % m\u00e1s de plantas en la misma superficie. Es el patr\u00f3n que usan los cultivadores comerciales.<\/p>\n\n<h3 class=\"wp-block-heading\">Paso 4: Visualice y ajuste<\/h3>\n\n<p class=\"wp-block-paragraph\">El lienzo se actualiza al instante al cambiar cualquier par\u00e1metro. Modifique el espaciamiento o cambie el patr\u00f3n para ver c\u00f3mo cambia el n\u00famero de plantas. El panel de resultados muestra el total de plantas, filas, columnas y superficie del bancal de un vistazo.<\/p>\n\n<p class=\"wp-block-paragraph\">Cuando est\u00e9 satisfecho con la disposici\u00f3n, visite nuestra <a href=\"https:\/\/aiper.com\/blogs\/es\/calculadora-espaciamiento-plantas\/\">calculadora de espaciamiento de plantas<\/a> para obtener la cantidad exacta de plantas, semillas o bulbos que necesita \u2014 con margen incluido para p\u00e9rdidas.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>LOADING&#8230; JS not yet executed Plant &amp; Tree Spacing Visualizer See how your plants will look before you dig ft \/ in m \/ cm Bed Width (ft) Bed Length (ft) Quick Presets Plant Spacing (in) Canopy at Maturity (in) Layout Pattern Square Grid Staggered \/ Triangular 0 Total Plants 0 Rows 0 Columns 0 [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"aiper_reading_time":2,"aiper_last_reviewed":"","aiper_reviewer":0,"aiper_related_ids":[],"aiper_layout":"","footnotes":""},"class_list":["post-8907","page","type-page","status-publish","hentry"],"lang":"es","translations":{"es":8907,"de":8905,"en":8904,"fr":8906},"_links":{"self":[{"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/pages\/8907","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/comments?post=8907"}],"version-history":[{"count":8,"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/pages\/8907\/revisions"}],"predecessor-version":[{"id":11851,"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/pages\/8907\/revisions\/11851"}],"wp:attachment":[{"href":"https:\/\/aiper.com\/blogs\/wp-json\/wp\/v2\/media?parent=8907"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}