diff options
-rw-r--r-- | css/garden.css | 18 | ||||
-rw-r--r-- | garden.js | 153 | ||||
-rw-r--r-- | index.html | 16 |
3 files changed, 100 insertions, 87 deletions
diff --git a/css/garden.css b/css/garden.css index 2077bd6..796fa73 100644 --- a/css/garden.css +++ b/css/garden.css @@ -437,7 +437,7 @@ table { } th, td { - padding: 10px; + padding: 0.5rem; margin: 0; } @@ -446,24 +446,19 @@ tbody tr:nth-child(odd) { } tbody tr td:nth-child(n+2) { - font-size: 20pt; border-left: 2px solid #fff; } img.icon { display: block; - width: 24px; - max-width: 24px; - height: 24px; - max-height: 24px; + width: 1.5rem; + height: 1.5rem; margin: 0 auto; } img.key { - width: 24px; - max-width: 24px; - height: 24px; - max-height: 24px; + width: 1.5rem; + height: 1.5rem; } a { @@ -475,7 +470,8 @@ a:visited { } .crop { - color: #fff; + text-decoration-line: underline; + text-decoration-style: dotted; } .crop:hover { @@ -226,6 +226,7 @@ const CROPS = [ springPlant: 0 }), new Crop("Kale", { + fallCrop: true, headStart: 4, maturity: 4, species: ["brassica napus", "brassica oleracea"], @@ -268,6 +269,7 @@ const CROPS = [ maturity: 14, multisow: 3, spacing: 4, + species: ["allium cepa"], springPlant: -4, transplant: true }), @@ -387,14 +389,14 @@ function makeCropSchedule(crop, season) { return crop.interval > 0 && offset >= crop.springPlant && offset <= fallPlant && - (offset <= crop.pause || - offset >= season.length - crop.resume) && + (offset <= crop.pause || offset >= resume) && (offset - start) % crop.interval == 0; } const springStart = crop.springPlant - crop.headStart; const fallPlant = season.length - crop.maturity - FALL_FACTOR; const fallStart = fallPlant - crop.headStart; + const resume = season.length - crop.resume; return season.weeks.map(week => { function action(type) { @@ -443,6 +445,79 @@ function monthAndDay(date) { return (date.getUTCMonth() + 1) + "/" + date.getUTCDate(); } +function viewCropDetails(crop) { + function close() { + container.removeChild(overlay); + } + + function addDetail(name, detail) { + const p = document.createElement("p"); + p.appendChild(document.createTextNode(`${name}: ${detail}`)); + modal.appendChild(p); + } + + const container = document.getElementById("container"); + const overlay = document.createElement("div"); + const modal = document.createElement("div"); + const heading = document.createElement("h2"); + const subheading = document.createElement("h4"); + const speciesDetail = `(${crop.species.join(", ")})`; + heading.appendChild(document.createTextNode(crop.name)); + subheading.appendChild(document.createTextNode(speciesDetail)); + subheading.classList.add("detail-subheading"); + modal.classList.add("modal"); + modal.appendChild(heading); + modal.appendChild(subheading); + addDetail("Average time to maturity", + `${crop.maturity} weeks from ${crop.transplant ? "transplant" : "seed"}`); + if(crop.springPlant == -1) { + addDetail("Spring planting time", `1 week before last frost`); + } else if(crop.springPlant < 0) { + addDetail("Spring planting time", + `${Math.abs(crop.springPlant)} weeks before last frost`); + } else if(crop.springPlant == 1) { + addDetail("Spring planting time", `1 week after last frost`); + } else if(crop.springPlant > 0) { + addDetail("Spring planting time", + `${crop.springPlant} weeks after last frost`); + } else if(crop.springPlant == 0) { + addDetail("Spring planting time", "On the last frost date"); + } else { + addDetail("Spring planting time", "Not a spring crop"); + } + if(crop.fallCrop) { + addDetail("Fall planting time", `${crop.maturity + FALL_FACTOR} weeks before first frost`); + } else if(crop.resume != 99) { + addDetail("Fall planting time", `Succession planted ${crop.resume} weeks before first frost`); + } else if(crop.interval > 0) { + addDetail("Fall planting time", `Succession planted until ${crop.maturity + FALL_FACTOR} weeks before first frost`); + } else { + addDetail("Fall planting time", "Not a fall crop"); + } + addDetail("Planting method", crop.transplant ? "Transplant" : "Direct sow"); + if(crop.transplant) { + addDetail("Start indoors", `${crop.headStart} weeks before planting`); + } + if(crop.interval > 0) { + addDetail("Succession planting interval", `Every ${crop.interval} weeks`); + } + if(crop.multisow > 1) { + addDetail("Multisow", `${crop.multisow} seeds per module`); + } else { + addDetail("Multisow", "No"); + } + if(crop.spacing >= 1) { + addDetail("Spacing", `${crop.spacing} ${crop.multisow > 1 ? "clumps" : "plants"} per square foot`); + } else { + addDetail("Spacing", `1 per ${Math.floor(1 / crop.spacing)} square feet`); + } + addDetail("Needs a trellis", crop.trellis ? "Yes" : "No"); + overlay.classList.add("overlay"); + overlay.appendChild(modal); + container.appendChild(overlay); + overlay.addEventListener("click", event => close()); +} + function makeDetailLink(crop) { const span = document.createElement("span"); span.classList.add("crop"); @@ -550,15 +625,21 @@ function refreshInstructions(crops, season, schedule) { weekDiv.appendChild(heading); actions.forEach(action => { const p = document.createElement("p"); - let text; + let prefix; + let suffix; if(action.type == "start") { - text = `Start ${action.crop.name} indoors.`; + prefix = "Start "; + suffix = " indoors."; } else if(action.type == "sow") { - text = `Sow ${action.crop.name} outdoors.`; + prefix = "Sow "; + suffix = " outdoors."; } else if(action.type == "transplant") { - text = `Transplant ${action.crop.name} outdoors.`; + prefix = "Transplant "; + suffix = " outdoors."; } - p.appendChild(document.createTextNode(text)); + p.appendChild(document.createTextNode(prefix)); + p.appendChild(makeDetailLink(action.crop)); + p.appendChild(document.createTextNode(suffix)); weekDiv.appendChild(p); }); instructionsDiv.appendChild(weekDiv); @@ -583,64 +664,6 @@ function refreshView() { } } -function viewCropDetails(crop) { - function close() { - container.removeChild(overlay); - } - - function addDetail(name, detail) { - const p = document.createElement("p"); - p.appendChild(document.createTextNode(`${name}: ${detail}`)); - modal.appendChild(p); - } - - const container = document.getElementById("container"); - const overlay = document.createElement("div"); - const modal = document.createElement("div"); - const heading = document.createElement("h2"); - const subheading = document.createElement("h4"); - const speciesDetail = `(${crop.species.join(", ")})`; - heading.appendChild(document.createTextNode(crop.name)); - subheading.appendChild(document.createTextNode(speciesDetail)); - subheading.classList.add("detail-subheading"); - modal.classList.add("modal"); - modal.appendChild(heading); - modal.appendChild(subheading); - if(crop.spacing >= 1) { - addDetail("Spacing", `${crop.spacing} per square foot`); - } else { - addDetail("Spacing", `1 per ${Math.floor(1 / crop.spacing)} square feet`); - } - addDetail("Average time to maturity", - `${crop.maturity} weeks from ${crop.transplant ? "transplant" : "seed"}`); - if(crop.springPlant < 0) { - addDetail("Earliest planting time", - `${Math.abs(crop.springPlant)} weeks before last frost`); - } else if(crop.springPlant > 0) { - addDetail("Earliest planting time", - `${crop.springPlant} weeks after last frost`); - } else { - addDetail("Earliest planting time", "week of last frost"); - } - addDetail("Planting method", crop.transplant ? "Transplant" : "Direct sow"); - if(crop.transplant) { - addDetail("Start indoors", `${crop.headStart} weeks before planting`); - } - if(crop.multisow > 1) { - addDetail("Multisow", `${crop.multisow} seeds per module`); - } else { - addDetail("Multisow", "No"); - } - addDetail("Needs a trellis", crop.trellis ? "Yes" : "No"); - if(crop.interval > 0) { - addDetail("Succession planting interval", `Every ${crop.interval} weeks`); - } - overlay.classList.add("overlay"); - overlay.appendChild(modal); - container.appendChild(overlay); - overlay.addEventListener("click", event => close()); -} - function getLastFrostDateInput() { return document.querySelector("input[name='last-frost-date']"); } @@ -12,10 +12,11 @@ This handy tool helps plan your intensively planted, organic, no-dig, home vegetable garden. Just select your first and last frost dates and a planting schedule will be generated for - you. + you. Click on a crop's name to view additional details about + that crop. </p> <p> - The schedule works by using generalized information about + The algorithm works by using generalized information about different types of crops such as average weeks to maturity, whether direct sowing or transplanting is preferred, weeks between plantings for continuous harvests, when and how a fall @@ -27,15 +28,8 @@ bush beans. </p> <p> - My gardening style is a combination of several intensive - growing strategies in an attempt to grow as much food as - possible using the least space and least effort. Those - strategies are: square foot gardening, "no dig" AKA "no till", - multisowing, and succession planting. - </p> - <p> - Finally, this planner is intended for gardeners located in the - nothern areas of the northern hemisphere (USDA zone 7 and below) + This planner works best for gardeners located in the nothern + areas of the northern hemisphere (USDA zone 7 and below) where we need to start many summer crops indoors and cannot harvest during winter without season extension. All planting dates are made under the assumption that no season extension |