first commit
This commit is contained in:
68
.github/workflows/docker-publish.yml
vendored
Normal file
68
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# .github/workflows/docker-publish.yml
|
||||||
|
|
||||||
|
name: Docker Image CI for Electricity Calculator
|
||||||
|
|
||||||
|
# Controls when the workflow will run
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ] # Triggers on pushes to the main branch
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_push_to_ghcr:
|
||||||
|
name: Build and Push to GitHub Container Registry
|
||||||
|
runs-on: ubuntu-latest # Use the latest Ubuntu runner
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # Needed to checkout the repository
|
||||||
|
packages: write # Needed to push to GitHub Packages (GHCR)
|
||||||
|
# id-token: write # Uncomment if using OIDC for authentication with a cloud provider
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
# This step checks out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }} # Your GitHub username or organization name
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# This step logs in to GHCR using a GITHUB_TOKEN, which is automatically generated for each job run.
|
||||||
|
# The GITHUB_TOKEN has permissions to push to GHCR if 'packages: write' is set for the job.
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository_owner }}/electricity-calculator-app
|
||||||
|
# Generates tags:
|
||||||
|
# - 'latest' for the default branch
|
||||||
|
# - Git tag if a tag is pushed
|
||||||
|
# - Git SHA as a tag
|
||||||
|
tags: |
|
||||||
|
type=schedule
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=pr
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=sha
|
||||||
|
latest
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: . # Build context is the root of the repository (where Dockerfile is)
|
||||||
|
file: ./Dockerfile # Explicitly specify the Dockerfile name if it's not 'Dockerfile' or is in a subdirectory
|
||||||
|
push: true # Actually push the image after building
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
# This step builds the Docker image using the Dockerfile in your repository
|
||||||
|
# and pushes it to GHCR with the tags generated in the previous step.
|
||||||
|
|
||||||
|
- name: Image digest
|
||||||
|
run: echo ${{ steps.build_and_push.outputs.digest }}
|
||||||
|
# Optional: Outputs the digest of the pushed image.
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Use a lightweight Nginx image
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
# Remove the default Nginx welcome page (optional, but good practice)
|
||||||
|
RUN rm -rf /usr/share/nginx/html/*
|
||||||
|
|
||||||
|
# Copy the web application files (your index.html) to the Nginx web root directory
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
|
|
||||||
|
# Expose port 80 for HTTP traffic
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# The default command for Nginx is to start the server.
|
||||||
|
# This CMD is inherited from the base nginx image, so explicitly stating it is optional
|
||||||
|
# but can be good for clarity.
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
119
README.md
Normal file
119
README.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# **Calcolatore Costi Elettricità (Electricity Cost Calculator)**
|
||||||
|
|
||||||
|
Questo progetto è una semplice applicazione web per calcolare il costo stimato del consumo di elettricità. L'utente può inserire la potenza media di un dispositivo, il costo dell'energia per kWh e la durata di utilizzo. L'applicazione simula quindi un consumo leggermente randomizzato per fornire una stima più realistica e visualizza i risultati insieme a un grafico dell'andamento del consumo.
|
||||||
|
|
||||||
|
## **✨ Caratteristiche Principali**
|
||||||
|
|
||||||
|
* **Input Utente:**
|
||||||
|
* Potenza media del dispositivo (Watt)
|
||||||
|
* Costo dell'energia per kWh (nella valuta locale)
|
||||||
|
* Durata di utilizzo (Ore)
|
||||||
|
* **Calcolo e Output:**
|
||||||
|
* Energia totale consumata (Wh, kWh o MWh, a seconda della scala)
|
||||||
|
* Costo totale stimato
|
||||||
|
* **Simulazione Realistica:**
|
||||||
|
* Introduce una leggera fluttuazione (±20%) sulla potenza media per simulare un consumo non lineare.
|
||||||
|
* **Visualizzazione Grafica:**
|
||||||
|
* Un grafico a linee mostra l'andamento simulato della potenza consumata nel tempo.
|
||||||
|
* Una linea aggiuntiva mostra la potenza media inserita per confronto.
|
||||||
|
* **Interfaccia Moderna:**
|
||||||
|
* Realizzata con Tailwind CSS per un design pulito e responsivo.
|
||||||
|
* **Localizzazione:**
|
||||||
|
* Interfaccia utente tradotta in italiano.
|
||||||
|
* **Containerizzazione:**
|
||||||
|
* Dockerfile incluso per eseguire l'applicazione con Nginx.
|
||||||
|
* **Continuous Integration:**
|
||||||
|
* Workflow GitHub Actions per buildare e pubblicare automaticamente l'immagine Docker su GitHub Container Registry (GHCR).
|
||||||
|
|
||||||
|
## **🛠️ Tecnologie Utilizzate**
|
||||||
|
|
||||||
|
* **Frontend:** HTML, CSS (Tailwind CSS), JavaScript
|
||||||
|
* **Grafici:** Chart.js
|
||||||
|
* **Web Server (in Docker):** Nginx
|
||||||
|
* **Containerizzazione:** Docker
|
||||||
|
* **Continuous Integration:** GitHub Actions
|
||||||
|
|
||||||
|
## **🚀 Come Iniziare**
|
||||||
|
|
||||||
|
### **Prerequisiti**
|
||||||
|
|
||||||
|
* Un browser web moderno (es. Chrome, Firefox, Safari, Edge)
|
||||||
|
* [Docker](https://www.docker.com/get-started) (opzionale, per l'esecuzione tramite container)
|
||||||
|
* [Git](https://git-scm.com/) (opzionale, per clonare il repository)
|
||||||
|
|
||||||
|
### **Esecuzione Locale (Senza Docker)**
|
||||||
|
|
||||||
|
1. **Clona** il repository (opzionale):
|
||||||
|
git clone \[https://github.com/dnviti/EnergyCalculatorWeb.git\](https://github.com/dnviti/EnergyCalculatorWeb.git)
|
||||||
|
cd EnergyCalculatorWeb
|
||||||
|
|
||||||
|
Oppure, scarica semplicemente il file index.html.
|
||||||
|
2. Apri il file index.html:
|
||||||
|
Fai doppio clic sul file index.html o aprilo direttamente con il tuo browser web.
|
||||||
|
|
||||||
|
### **Esecuzione con Docker**
|
||||||
|
|
||||||
|
1. **Assicurati che Docker sia in esecuzione.**
|
||||||
|
2. Costruisci l'immagine Docker:
|
||||||
|
Naviga nella directory principale del progetto (dove si trova il Dockerfile) ed esegui:
|
||||||
|
docker build \-t electricity-calculator-app .
|
||||||
|
|
||||||
|
3. **Esegui il container Docker:**
|
||||||
|
docker run \-d \-p 8080:80 electricity-calculator-app
|
||||||
|
|
||||||
|
* \-d esegue il container in background.
|
||||||
|
* \-p 8080:80 mappa la porta 8080 del tuo computer alla porta 80 del container (dove Nginx è in ascolto). Puoi cambiare 8080 se necessario.
|
||||||
|
4. Accedi all'applicazione:
|
||||||
|
Apri il tuo browser e vai a http://localhost:8080.
|
||||||
|
|
||||||
|
## **🐳 Immagine Docker**
|
||||||
|
|
||||||
|
L'applicazione può essere eseguita come un container Docker. Il Dockerfile utilizza un'immagine Nginx stable-alpine per servire il file index.html.
|
||||||
|
|
||||||
|
L'immagine Docker viene automaticamente buildata e pubblicata su GitHub Container Registry (GHCR) ad ogni push sul branch main.
|
||||||
|
|
||||||
|
**Pull dell'immagine da GHCR (esempio):**
|
||||||
|
|
||||||
|
docker pull ghcr.io/dnviti/electricity-calculator-app:latest
|
||||||
|
|
||||||
|
(Sostituisci TUO\_USERNAME con il tuo nome utente o organizzazione GitHub)
|
||||||
|
|
||||||
|
## **🔄 Continuous Integration (GitHub Actions)**
|
||||||
|
|
||||||
|
Il file .github/workflows/docker-publish.yml definisce un workflow di GitHub Actions che:
|
||||||
|
|
||||||
|
1. Si attiva ad ogni push sul branch main o manualmente.
|
||||||
|
2. Effettua il checkout del codice.
|
||||||
|
3. Esegue il login a GitHub Container Registry.
|
||||||
|
4. Estrae metadati per i tag dell'immagine Docker.
|
||||||
|
5. Costruisce l'immagine Docker utilizzando il Dockerfile presente nel repository.
|
||||||
|
6. Pubblica l'immagine Docker su GHCR (ghcr.io/TUO\_USERNAME/electricity-calculator-app).
|
||||||
|
|
||||||
|
## **💻 Come Usare l'Applicazione Web**
|
||||||
|
|
||||||
|
1. Apri l'applicazione nel tuo browser.
|
||||||
|
2. Nel pannello "Inserisci i Dati":
|
||||||
|
* Inserisci la **Potenza Media** del dispositivo in Watt.
|
||||||
|
* Inserisci il **Costo per kWh** nella tua valuta (es. 0.25).
|
||||||
|
* Inserisci la **Durata** di utilizzo in ore.
|
||||||
|
3. Clicca sul pulsante **"Calcola"**.
|
||||||
|
4. I risultati appariranno nel pannello "Risultati Stimati":
|
||||||
|
* **Energia Totale Consumata**.
|
||||||
|
* **Costo Totale Stimato**.
|
||||||
|
5. Il grafico "Andamento del Consumo Energetico Simulato" mostrerà la variazione simulata della potenza nel tempo.
|
||||||
|
|
||||||
|
## **🤝 Contributi**
|
||||||
|
|
||||||
|
I contributi sono benvenuti\! Se hai suggerimenti o miglioramenti, sentiti libero di aprire una issue o una pull request.
|
||||||
|
|
||||||
|
1. Forka il Progetto
|
||||||
|
2. Crea il tuo Branch per la Feature (git checkout \-b feature/AmazingFeature)
|
||||||
|
3. Committa le tue Modifiche (git commit \-m 'Add some AmazingFeature')
|
||||||
|
4. Pusha sul Branch (git push origin feature/AmazingFeature)
|
||||||
|
5. Apri una Pull Request
|
||||||
|
|
||||||
|
## **📄 Licenza**
|
||||||
|
|
||||||
|
Distribuito sotto la Licenza MIT. Vedi LICENSE.txt per maggiori informazioni (se presente, altrimenti si assume MIT).
|
||||||
|
|
||||||
|
*Questo README è stato generato per il progetto Calcolatore Costi Elettricità.*
|
||||||
353
index.html
Normal file
353
index.html
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Calcolatore Costi Elettricità</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
background-color: #f0f4f8; /* Sfondo grigio-blu chiaro */
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 2rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
.input-label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4a5568; /* Grigio-700 */
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.input-field {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border: 1px solid #e2e8f0; /* Grigio-300 */
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: border-color 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
.input-field:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #4299e1; /* Blu-500 */
|
||||||
|
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #4299e1; /* Blu-500 */
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.2s ease-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #3182ce; /* Blu-600 */
|
||||||
|
}
|
||||||
|
.output-value {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2c5282; /* Blu-800 */
|
||||||
|
}
|
||||||
|
.output-label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #718096; /* Grigio-500 */
|
||||||
|
}
|
||||||
|
#errorMessage {
|
||||||
|
color: #e53e3e; /* Rosso-600 */
|
||||||
|
background-color: #fed7d7; /* Rosso-200 */
|
||||||
|
border: 1px solid #f56565; /* Rosso-400 */
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen flex flex-col items-center justify-center p-4 sm:p-6">
|
||||||
|
|
||||||
|
<div class="w-full max-w-3xl">
|
||||||
|
<header class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl sm:text-4xl font-bold text-gray-800">Calcolo Consumi e Costi Elettricità</h1>
|
||||||
|
<p class="text-gray-600 mt-2">Stima il tuo consumo energetico e i relativi costi con una simulazione realistica.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<!-- Scheda Input -->
|
||||||
|
<div class="card">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-700 mb-6">Inserisci i Dati</h2>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label for="power" class="input-label block">Potenza Media (Watt)</label>
|
||||||
|
<input type="number" id="power" class="input-field" placeholder="es. 100" value="100">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="cost" class="input-label block">Costo per kWh (€, $, ecc.)</label>
|
||||||
|
<input type="number" id="cost" class="input-field" placeholder="es. 0,25" value="0.25" step="0.01"> <!-- Aggiornato placeholder per formato italiano -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="time" class="input-label block">Durata (Ore)</label>
|
||||||
|
<input type="number" id="time" class="input-field" placeholder="es. 24" value="24">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="calculateBtn" class="btn-primary w-full mt-8">Calcola</button>
|
||||||
|
<div id="errorMessage" class="hidden mt-4"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scheda Output -->
|
||||||
|
<div class="card">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-700 mb-6">Risultati Stimati</h2>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="text-center">
|
||||||
|
<p id="energyConsumed" class="output-value">--</p>
|
||||||
|
<p class="output-label">Energia Totale Consumata</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<p id="totalCost" class="output-value">--</p>
|
||||||
|
<p class="output-label">Costo Totale Stimato</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-6 text-center">
|
||||||
|
Nota: il consumo è simulato con leggere fluttuazioni (±20%) rispetto alla potenza media, per una stima più realistica.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scheda Grafico -->
|
||||||
|
<div class="card mt-6 w-full">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-700 mb-4 text-center">Andamento del Consumo Energetico Simulato</h2>
|
||||||
|
<div class="relative h-64 sm:h-80">
|
||||||
|
<canvas id="consumptionChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<p id="chartMessage" class="text-sm text-gray-500 mt-4 text-center hidden">Premi "Calcola" per generare il grafico.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="text-center mt-8 text-sm text-gray-500">
|
||||||
|
<p>© 2024 Calcolatore Energetico. Solo a scopo illustrativo.</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const powerInput = document.getElementById('power');
|
||||||
|
const costInput = document.getElementById('cost');
|
||||||
|
const timeInput = document.getElementById('time');
|
||||||
|
const calculateBtn = document.getElementById('calculateBtn');
|
||||||
|
const energyConsumedOutput = document.getElementById('energyConsumed');
|
||||||
|
const totalCostOutput = document.getElementById('totalCost');
|
||||||
|
const consumptionChartCanvas = document.getElementById('consumptionChart');
|
||||||
|
const errorMessageDiv = document.getElementById('errorMessage');
|
||||||
|
const chartMessage = document.getElementById('chartMessage');
|
||||||
|
|
||||||
|
let consumptionChart = null;
|
||||||
|
|
||||||
|
// Inizializza il messaggio del grafico
|
||||||
|
chartMessage.classList.remove('hidden');
|
||||||
|
|
||||||
|
function displayError(message) {
|
||||||
|
errorMessageDiv.textContent = message;
|
||||||
|
errorMessageDiv.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearError() {
|
||||||
|
errorMessageDiv.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateBtn.addEventListener('click', () => {
|
||||||
|
clearError();
|
||||||
|
chartMessage.classList.add('hidden');
|
||||||
|
|
||||||
|
const powerW = parseFloat(powerInput.value);
|
||||||
|
// Sostituisce la virgola con il punto per l'input del costo, se presente
|
||||||
|
const costString = costInput.value.replace(',', '.');
|
||||||
|
const costPerKwh = parseFloat(costString);
|
||||||
|
const totalHours = parseFloat(timeInput.value);
|
||||||
|
|
||||||
|
// --- Validazione Input ---
|
||||||
|
if (isNaN(powerW) || powerW <= 0) {
|
||||||
|
displayError("Inserisci un valore numerico positivo per la potenza.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(costPerKwh) || costPerKwh < 0) {
|
||||||
|
displayError("Inserisci un valore numerico valido (non negativo) per il costo per kWh.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(totalHours) || totalHours <= 0) {
|
||||||
|
displayError("Inserisci un valore numerico positivo per la durata.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Parametri Simulazione ---
|
||||||
|
const numberOfIntervals = 60; // Numero di intervalli per il grafico/simulazione
|
||||||
|
const timePerIntervalHours = totalHours / numberOfIntervals;
|
||||||
|
const fluctuationPercentage = 0.20; // Fluttuazione ±20%
|
||||||
|
|
||||||
|
let simulatedPowerDataW = [];
|
||||||
|
let timeLabels = [];
|
||||||
|
let totalSimulatedEnergyWh = 0;
|
||||||
|
|
||||||
|
// --- Simula Consumo ---
|
||||||
|
for (let i = 0; i < numberOfIntervals; i++) {
|
||||||
|
// Fluttuazione: numero casuale tra -1 e 1, poi scalato per la percentuale
|
||||||
|
const randomFluctuationFactor = (Math.random() * 2 - 1) * fluctuationPercentage;
|
||||||
|
let intervalPowerW = powerW * (1 + randomFluctuationFactor);
|
||||||
|
intervalPowerW = Math.max(0, intervalPowerW); // Assicura che la potenza non sia negativa
|
||||||
|
|
||||||
|
simulatedPowerDataW.push(intervalPowerW.toFixed(2));
|
||||||
|
|
||||||
|
// Calcola l'energia per questo intervallo e aggiungila al totale
|
||||||
|
const energyInIntervalWh = intervalPowerW * timePerIntervalHours;
|
||||||
|
totalSimulatedEnergyWh += energyInIntervalWh;
|
||||||
|
|
||||||
|
// Crea etichette temporali per il grafico
|
||||||
|
timeLabels.push(((i + 1) * timePerIntervalHours).toFixed(1) + 'h');
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Calcola Costo Totale ---
|
||||||
|
const totalSimulatedEnergyKWh = totalSimulatedEnergyWh / 1000;
|
||||||
|
const finalTotalCost = totalSimulatedEnergyKWh * costPerKwh;
|
||||||
|
|
||||||
|
// --- Mostra Risultati ---
|
||||||
|
// Formatta l'energia consumata con unità appropriate
|
||||||
|
let formattedEnergy;
|
||||||
|
if (totalSimulatedEnergyWh < 1000) {
|
||||||
|
formattedEnergy = totalSimulatedEnergyWh.toFixed(2) + " Wh";
|
||||||
|
} else if (totalSimulatedEnergyWh < 1000000) {
|
||||||
|
formattedEnergy = (totalSimulatedEnergyWh / 1000).toFixed(3) + " kWh";
|
||||||
|
} else {
|
||||||
|
formattedEnergy = (totalSimulatedEnergyWh / 1000000).toFixed(4) + " MWh";
|
||||||
|
}
|
||||||
|
energyConsumedOutput.textContent = formattedEnergy;
|
||||||
|
// Formatta il costo con due decimali e la virgola come separatore decimale per la visualizzazione
|
||||||
|
totalCostOutput.textContent = finalTotalCost.toLocaleString('it-IT', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||||
|
|
||||||
|
|
||||||
|
// --- Aggiorna Grafico ---
|
||||||
|
if (consumptionChart) {
|
||||||
|
consumptionChart.destroy(); // Distrugge l'istanza precedente del grafico
|
||||||
|
}
|
||||||
|
|
||||||
|
consumptionChart = new Chart(consumptionChartCanvas, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: timeLabels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Potenza Simulata (Watt)',
|
||||||
|
data: simulatedPowerDataW,
|
||||||
|
borderColor: '#4299e1',
|
||||||
|
backgroundColor: 'rgba(66, 153, 225, 0.1)',
|
||||||
|
tension: 0.3, // Leviga la linea
|
||||||
|
fill: true,
|
||||||
|
pointRadius: 2,
|
||||||
|
pointHoverRadius: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Potenza Media Inserita (Watt)',
|
||||||
|
data: Array(numberOfIntervals).fill(powerW),
|
||||||
|
borderColor: '#f56565',
|
||||||
|
borderDash: [5, 5], // Linea tratteggiata
|
||||||
|
tension: 0.1,
|
||||||
|
fill: false,
|
||||||
|
pointRadius: 0,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Potenza (Watt)',
|
||||||
|
font: { size: 14, weight: '500' },
|
||||||
|
color: '#4a5568'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
color: '#e2e8f0' // Linee della griglia più chiare
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: '#718096'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
x: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Durata (Ore)',
|
||||||
|
font: { size: 14, weight: '500' },
|
||||||
|
color: '#4a5568'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false // Nasconde le linee della griglia sull'asse x per un aspetto più pulito
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
color: '#718096',
|
||||||
|
maxRotation: 45,
|
||||||
|
minRotation: 0,
|
||||||
|
autoSkip: true, // Salta automaticamente le etichette se troppe
|
||||||
|
maxTicksLimit: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
labels: {
|
||||||
|
font: { size: 12 },
|
||||||
|
color: '#4a5568'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
mode: 'index',
|
||||||
|
intersect: false,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.75)',
|
||||||
|
titleFont: { size: 14, weight: 'bold' },
|
||||||
|
bodyFont: { size: 12 },
|
||||||
|
callbacks: {
|
||||||
|
label: function(context) {
|
||||||
|
let label = context.dataset.label || '';
|
||||||
|
if (label) {
|
||||||
|
label += ': ';
|
||||||
|
}
|
||||||
|
if (context.parsed.y !== null) {
|
||||||
|
// Formatta il valore nel tooltip con la virgola come separatore decimale
|
||||||
|
label += parseFloat(context.parsed.y).toLocaleString('it-IT', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' W';
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
duration: 800, // Durata animazione in ms
|
||||||
|
easing: 'easeInOutQuart' // Funzione di easing per l'animazione
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mostra il messaggio del grafico all'avvio se i campi sono vuoti
|
||||||
|
if (!powerInput.value || !costInput.value || !timeInput.value) {
|
||||||
|
chartMessage.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
// Opzionalmente, si potrebbe attivare un calcolo al caricamento:
|
||||||
|
// calculateBtn.click();
|
||||||
|
// Per ora, assicuriamoci che il messaggio sia mostrato fino al primo calcolo
|
||||||
|
if (!consumptionChart) { // Se il grafico non è ancora stato disegnato
|
||||||
|
chartMessage.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user