Compare commits

...

5 Commits

Author SHA1 Message Date
2470005892 refactor: comments + print 2025-04-14 20:24:17 +02:00
b4c90af4f3 fix: use label class correctly 2025-04-14 20:21:23 +02:00
9f716e68a5 feat: Add cage calc that shows requirements for a number of rats 2025-04-14 19:00:49 +02:00
884840eb6e feat: reset bulma colors 2025-04-13 22:21:55 +02:00
e743608539 fix: Use real FA icon 2025-04-13 22:21:38 +02:00
5 changed files with 122 additions and 24 deletions

View File

@@ -8,8 +8,8 @@
"depth-cm": "Tiefe (cm)", "depth-cm": "Tiefe (cm)",
"height-cm": "Höhe (cm)", "height-cm": "Höhe (cm)",
"full-floors": "Vollebenen", "full-floors": "Vollebenen",
"number-of-rats": "Anzahl an Ratten",
"result": "Ergebnis", "result": "Ergebnis",
"number-of-rats": "Anzahl an Ratten",
"change-language": "Sprache ändern", "change-language": "Sprache ändern",
"failed-base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² (also z.B. 100x50cm) betragen.", "failed-base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² (also z.B. 100x50cm) betragen.",
"failed-overall-area": "Die Gesamtfläche im Käfig ist zu klein.", "failed-overall-area": "Die Gesamtfläche im Käfig ist zu klein.",
@@ -18,6 +18,12 @@
"failed-num-rats": "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.", "failed-num-rats": "Es müssen mindestens 3 Ratten zusammenleben, Paarhaltung ist nicht artgerecht.",
"failed-minimum-length-long-side": "Die lange Seite des Käfig muss mindestens {{ minimum_length_long_side }}cm lang sein um Rennen zu ermöglichen.", "failed-minimum-length-long-side": "Die lange Seite des Käfig muss mindestens {{ minimum_length_long_side }}cm lang sein um Rennen zu ermöglichen.",
"failed-minimum-length-short-side": "Die kurze Seite des Käfig muss mindestens {{ minimum_length_short_side }}cm lang sein.", "failed-minimum-length-short-side": "Die kurze Seite des Käfig muss mindestens {{ minimum_length_short_side }}cm lang sein.",
"base-area": "Die Mindestgrundfläche des Käfigs muss {{ MINIMUM_BASE_AREA }}m² betragen.",
"fall-height": "Die mögliche Fallhöhe darf nicht mehr als {{ maximum_fall_height }}cm betragen.",
"floor-height": "Der Mindestabstand zwischen Ebenen muss {{ minimum_floor_height }}cm betragen.",
"minimum-length-long-side": "Die lange Seite des Käfig muss mindestens {{ minimum_length_long_side }}cm lang sein um Rennen zu ermöglichen.",
"minimum-length-short-side": "Die kurze Seite des Käfig muss mindestens {{ minimum_length_short_side }}cm lang sein.",
"cage-complies-with-all-criteria": "Der Käfig erfüllt alle Kriterien!", "cage-complies-with-all-criteria": "Der Käfig erfüllt alle Kriterien!",
"cage-for-x-rats": "Käfig für {{ num_rats }} Ratten" "cage-for-x-rats": "Käfig für {{ num_rats }} Ratten",
"overall-area": "Die Gesamtfläche für {{ numRats }} Ratten muss mindestens {{ minimumOverallArea }}m² betragen."
} }

View File

@@ -8,8 +8,8 @@
"depth-cm": "Depth (cm)", "depth-cm": "Depth (cm)",
"height-cm": "Height (cm)", "height-cm": "Height (cm)",
"full-floors": "Full floors", "full-floors": "Full floors",
"number-of-rats": "Number of Rats",
"result": "Result", "result": "Result",
"number-of-rats": "Number of Rats",
"change-language": "Change language", "change-language": "Change language",
"failed-base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².", "failed-base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².",
"failed-overall-area": "The overall area in the cage is to small.", "failed-overall-area": "The overall area in the cage is to small.",
@@ -18,6 +18,12 @@
"failed-num-rats": "Rats must live in a group of at least three rats, pairs or lone rats are not species-appropriate.", "failed-num-rats": "Rats must live in a group of at least three rats, pairs or lone rats are not species-appropriate.",
"failed-minimum-length-long-side": "The long side of the cage must be at least {{ minimum_length_long_side }}cm long to enable running.", "failed-minimum-length-long-side": "The long side of the cage must be at least {{ minimum_length_long_side }}cm long to enable running.",
"failed-minimum-length-short-side": "The short side of the cage must be at least {{ minimum_length_short_side }}cm.", "failed-minimum-length-short-side": "The short side of the cage must be at least {{ minimum_length_short_side }}cm.",
"base-area": "The base area of the cage must not be below {{ MINIMUM_BASE_AREA }}m².",
"fall-height": "The possible fall height between floors must not be above {{ maximum_fall_height }}cm.",
"floor-height": "The height between floors must be above {{ minimum_floor_height }}cm.",
"minimum-length-long-side": "The long side of the cage must be at least {{ minimum_length_long_side }}cm long to enable running.",
"minimum-length-short-side": "The short side of the cage must be at least {{ minimum_length_short_side }}cm.",
"cage-complies-with-all-criteria": "This cage complies with all criteria!", "cage-complies-with-all-criteria": "This cage complies with all criteria!",
"cage-for-x-rats": "Cage for {{ num_rats }} rats" "cage-for-x-rats": "Cage for {{ num_rats }} rats",
"overall-area": "The overall area in the cage must be above {{ minimumOverallArea }}m² for {{ numRats }} rats."
} }

View File

@@ -29,7 +29,7 @@
<li class="is-active" data-tab-id="1"> <li class="is-active" data-tab-id="1">
<a> <a>
<span class="icon is-small"> <span class="icon is-small">
<i class="fas fa-number" aria-hidden="true"></i> <i class="fas fa-hashtag" aria-hidden="true"></i>
</span> </span>
<p data-i18n="how-many-rats-does-this-cage-fit">How many rats does this cage fit?</p> <p data-i18n="how-many-rats-does-this-cage-fit">How many rats does this cage fit?</p>
</a> </a>
@@ -55,6 +55,7 @@
</div> </div>
<div id="tab-content"> <div id="tab-content">
<!--- Check how many rats fit --->
<div class="is-active" data-content-id="1"> <div class="is-active" data-content-id="1">
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
@@ -118,13 +119,38 @@
</div> </div>
</div> </div>
</div> </div>
<!--- Cage calc --->
<div class="" data-content-id="2"> <div class="" data-content-id="2">
<p>Here is a list of cages you can get.</p> <div class="card">
<div class="card-content">
<h2 class="title is-4">
<label data-i18n="number-of-rats" class="label" for="cage-calc">Anzahl der Ratten</label>
</h2>
<form id="cage-calc">
<div class="column">
<label id="cageCalcLabelNumRats" for="cageCalcNumRats" class="label"></label>
<input type="range" min="3" max="15" value="4" class="slider" id="cageCalcNumRats">
<img class="inline-icon" src="assets/img/logo_transparent.png" alt="Kleine Ratte">
</div>
</form>
</div>
<div class="card-footer is-fullwidth">
<div class="card result-card" id="cage-calc-result-card">
<div class="card-header">
<h2 class="card-header-title is-3 is-centered" data-i18n="result">Ergebnis</h2>
</div>
<div class="card-content">
<div id="cageCalcResultsDiv"></div>
</div>
</div>
</div>
</div>
</div> </div>
<!--- Check cage --->
<div class="" data-content-id="3"> <div class="" data-content-id="3">
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<h2 class="title is-4"><label data-i18n="cage-measurements" <h2 class="title is-4"><label class="label" data-i18n="cage-measurements"
for="form-cage-measurements">Käfigmaße</label></h2> for="form-cage-measurements">Käfigmaße</label></h2>
<form id="form-cage-measurements" class="form-measurements"> <form id="form-cage-measurements" class="form-measurements">

View File

@@ -71,7 +71,6 @@ function bindLocaleSwitcher(initialValue) {
////////// //////////
function initTabs(tabs, tabContent, activationClass) { function initTabs(tabs, tabContent, activationClass) {
tabs.forEach((tab) => { tabs.forEach((tab) => {
tab.addEventListener('click', (e) => { tab.addEventListener('click', (e) => {
@@ -122,13 +121,21 @@ const MINIMUM_LENGTH_LONG_SIDE = 0.8;
const MINIMUM_LENGTH_SHORT_SIDE = 0.5; const MINIMUM_LENGTH_SHORT_SIDE = 0.5;
const MINIMUM_FLOOR_HEIGHT = 0.25; const MINIMUM_FLOOR_HEIGHT = 0.25;
const FAILED_BASE_AREA = "base_area"; const FAILED_BASE_AREA = "failed_base_area";
const FAILED_OVERALL_AREA = "overall_area"; const FAILED_OVERALL_AREA = "failed_overall_area";
const FAILED_FALL_HEIGHT = "fall_height"; const FAILED_FALL_HEIGHT = "failed_fall_height";
const FAILED_NUM_RATS = "num_rats"; const FAILED_NUM_RATS = "failed_num_rats";
const FAILED_MINIMUM_LENGTH_LONG_SIDE = "length_long_side"; const FAILED_MINIMUM_LENGTH_LONG_SIDE = "failed_length_long_side";
const FAILED_MINIMUM_LENGTH_SHORT_SIDE = "length_short_side"; const FAILED_MINIMUM_LENGTH_SHORT_SIDE = "failed_length_short_side";
const FAILED_FLOOR_HEIGHT = "floor_height" const FAILED_FLOOR_HEIGHT = "failed_floor_height"
const CRITERIA_BASE_AREA = "base_area";
const CRITERIA_FALL_HEIGHT = "fall_height";
const CRITERIA_MINIMUM_LENGTH_LONG_SIDE = "length_long_side";
const CRITERIA_MINIMUM_LENGTH_SHORT_SIDE = "length_short_side";
const CRITERIA_FLOOR_HEIGHT = "floor_height"
const CRITERIA_OVERALL_AREA = "overall_area"
class Validator { class Validator {
@@ -142,6 +149,13 @@ class Validator {
[FAILED_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("failed-minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}), [FAILED_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("failed-minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}),
[FAILED_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("failed-minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}), [FAILED_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("failed-minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}),
}; };
this.STATIC_CRITERIA = {
[CRITERIA_BASE_AREA]: i18next.t('base-area', {"MINIMUM_BASE_AREA": MINIMUM_BASE_AREA}),
[CRITERIA_FALL_HEIGHT]: i18next.t("fall-height", {"maximum_fall_height": (MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}),
[CRITERIA_FLOOR_HEIGHT]: i18next.t("floor-height", {"minimum_floor_height": (MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}),
[CRITERIA_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}),
[CRITERIA_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}),
}
} }
overallAreaNeeded(numOfRats) { overallAreaNeeded(numOfRats) {
@@ -155,9 +169,7 @@ class Validator {
/* /*
Calculates the number of rats that are allowed for a certain overall area. Calculates the number of rats that are allowed for a certain overall area.
*/ */
let result = 3.0 + (overallArea-MINIMUM_AREA_THREE_RATS) / AREA_PER_ADDITIONAL_RAT; let result = 3.0 + (overallArea - MINIMUM_AREA_THREE_RATS) / AREA_PER_ADDITIONAL_RAT;
console.log(`Area left: ${overallArea-MINIMUM_AREA_THREE_RATS}`);
console.log(`Result: ${result}`);
if (result < 3) { if (result < 3) {
throw new Error("Cages must be for three rats or more"); throw new Error("Cages must be for three rats or more");
} }
@@ -243,6 +255,10 @@ class Dimensions {
// DOCUMENT INTERACTION // // DOCUMENT INTERACTION //
////////////////////////// //////////////////////////
///////
// 1 //
///////
const numRatsCalculatorInputWidth = document.getElementById("num-rats-width"); const numRatsCalculatorInputWidth = document.getElementById("num-rats-width");
numRatsCalculatorInputWidth.onchange = updateNumRatsCalculator; numRatsCalculatorInputWidth.onchange = updateNumRatsCalculator;
const numRatsCalculatorInputDepth = document.getElementById("num-rats-depth"); const numRatsCalculatorInputDepth = document.getElementById("num-rats-depth");
@@ -255,6 +271,23 @@ numRatsNumFullFloors.oninput = function () {
updateNumRatsCalculator(); updateNumRatsCalculator();
} }
///////
// 2 //
///////
let cageCalcLabelNumRats = document.getElementById("cageCalcLabelNumRats");
let cageCalcRatSlider = document.getElementById("cageCalcNumRats");
cageCalcRatSlider.oninput = function () {
updateCageCalc();
}
///////
// 3 //
///////
const inputWidth = document.getElementById("width"); const inputWidth = document.getElementById("width");
inputWidth.onchange = updateCageCheck; inputWidth.onchange = updateCageCheck;
@@ -295,6 +328,18 @@ function getResultFromChecks(checks) {
} }
function formatCriteria(criteria) {
const ul = document.createElement('ul');
for (const key in criteria) {
const li = document.createElement('li');
li.textContent = `☑️ ` + criteria[key];
ul.appendChild(li);
}
return ul;
}
function updateCageCheck() { function updateCageCheck() {
labelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": ratSlider.value}); labelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": ratSlider.value});
@@ -312,6 +357,23 @@ function updateCageCheck() {
resultsDiv.appendChild(result); resultsDiv.appendChild(result);
} }
function updateCageCalc() {
let numRats = cageCalcRatSlider.value
cageCalcLabelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": numRats});
const validator = new Validator();
let criteria = validator.STATIC_CRITERIA;
let minimumOverallArea = validator.overallAreaNeeded(cageCalcRatSlider.value);
criteria[CRITERIA_OVERALL_AREA] = i18next.t('overall-area', {"numRats": numRats, "minimumOverallArea": minimumOverallArea});
let resultsDiv = document.getElementById("cageCalcResultsDiv");
const result = formatCriteria(criteria);
resultsDiv.innerHTML = "";
resultsDiv.appendChild(result);
}
function updateNumRatsCalculator() { function updateNumRatsCalculator() {
const width = numRatsCalculatorInputWidth.value const width = numRatsCalculatorInputWidth.value
@@ -332,8 +394,6 @@ function updateNumRatsCalculator() {
} }
console.log(`Allowed number: ${allowedNumRats}`);
let resultsDiv = document.getElementById("num-rats-resultsDiv"); let resultsDiv = document.getElementById("num-rats-resultsDiv");
const result = getResultFromChecks(failed_checks); const result = getResultFromChecks(failed_checks);

View File

@@ -8,10 +8,6 @@ $beige-lighter: #eff0eb;
// Path to Bulma's sass folder // Path to Bulma's sass folder
@use "bulma/sass" with ( @use "bulma/sass" with (
$family-primary: '"Nunito", sans-serif', $family-primary: '"Nunito", sans-serif',
$grey-dark: $brown,
$grey-light: $beige-light,
$primary: $purple,
$link: $pink,
$control-border-width: 2px, $control-border-width: 2px,
$input-shadow: none $input-shadow: none
); );
@@ -32,6 +28,10 @@ body {
width: 100%; width: 100%;
} }
.inline-icon {
height: 1.5rem;
}
// Import the Google Font // Import the Google Font
@import url("https://fonts.googleapis.com/css?family=Nunito:400,700"); @import url("https://fonts.googleapis.com/css?family=Nunito:400,700");