You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
6.1 KiB
120 lines
6.1 KiB
|
|
|
|
interface SimulationParameters { |
|
batteryCapacity: number, |
|
additionalWeight: number, |
|
climateZone: string, |
|
dailyDistance: number, |
|
dailyAscendingElevation: number |
|
} |
|
|
|
function runSimulation(parameters: SimulationParameters): Simulator.SimulationResult { |
|
let climateData = (<any>window)['climate-zones-data.csv']; |
|
|
|
let vehicle = new Simulator.Vehicle(); |
|
vehicle.batteryCapacity = parameters.batteryCapacity; |
|
vehicle.additionalWeight = parameters.additionalWeight; |
|
let solarIrradiance: number[] = climateData[parameters.climateZone.toLowerCase()]; |
|
let planning = new Simulator.OutingPlanning(parameters.dailyDistance, parameters.dailyAscendingElevation); |
|
|
|
let simulationResult = Simulator.simulate(vehicle, solarIrradiance, planning); |
|
//console.log(solarIrradiance); |
|
//console.log(simulationResult); |
|
|
|
return simulationResult; |
|
} |
|
|
|
function initializeSimulator(container: HTMLElement) { |
|
// Insert HTML code in the container |
|
container.innerHTML += (<any>window)['simulator.html']; |
|
|
|
// In order to be able to style SVG elements with CSS, and register events with javascript, we must use inline SVG (we can't use an img tag) |
|
// For this purpose, the SVG file contents are embedded in a javascript file |
|
container.querySelector('.zones-map').innerHTML = (<any>window)['climate-zones-map.svg']; |
|
|
|
container.querySelectorAll("[data-activate-modal]").forEach(elt => { |
|
elt.addEventListener('click', e => { |
|
container.querySelector('.'+elt.getAttribute('data-activate-modal')).classList.toggle('is-active', true); |
|
}); |
|
}); |
|
|
|
container.querySelectorAll('.modal-close, .modal-card-head .delete').forEach(elt => { |
|
elt.addEventListener('click', e => { |
|
HtmlUtils.closest(elt, e => e.classList.contains('modal')).classList.toggle('is-active', false); |
|
}); |
|
}); |
|
|
|
let zoneSelector = <HTMLSelectElement>container.querySelector('.zone-selector'); |
|
container.querySelectorAll('.climate-zone').forEach(elt => { |
|
elt.addEventListener('click', e => { |
|
let zoneName = elt.getAttribute('id'); |
|
zoneSelector.value = zoneName; |
|
HtmlUtils.closest(elt, e => e.classList.contains('modal')).classList.toggle('is-active', false); |
|
}); |
|
}); |
|
|
|
container.querySelector('.simulate-button').addEventListener('click', e => { |
|
let parameters: SimulationParameters = { |
|
batteryCapacity: Number((<HTMLInputElement>container.querySelector('[name=battery-capacity]')).value), |
|
additionalWeight: Number((<HTMLInputElement>container.querySelector('[name=additional-weight]')).value), |
|
climateZone: (<HTMLSelectElement>container.querySelector('.zone-selector')).value, |
|
dailyDistance: Number((<HTMLInputElement>container.querySelector('[name=daily-distance]')).value), |
|
dailyAscendingElevation: Number((<HTMLInputElement>container.querySelector('[name=daily-elevation]')).value), |
|
}; |
|
|
|
let simulationResult = runSimulation(parameters); |
|
|
|
let resultsContainer = container.querySelector('.simulation-results'); |
|
|
|
let averageKwhCost = 0.1558; // in €/kWh |
|
let totalConsumedGridPower = simulationResult.cumulatedGridRechargeEnergy / simulationResult.vehicle.batteryEfficiency / simulationResult.vehicle.gridTransformerEfficiency; |
|
|
|
let solarRechargeRatio = Math.round(100*(simulationResult.cumulatedSolarRechargeEnergy/(simulationResult.cumulatedSolarRechargeEnergy + simulationResult.cumulatedGridRechargeEnergy))); |
|
resultsContainer.querySelector('.result-info').innerHTML = ` |
|
<p>Il faudra recharger le vhélio sur secteur environ ${simulationResult.gridChargeCount} fois sur l'année.</p> |
|
<p>Cela coûtera ${Math.round(totalConsumedGridPower/1000*averageKwhCost*100)/100}€ sur l'année.</p> |
|
<p>Le vhélio sera rechargé à ${solarRechargeRatio}% par le soleil, ${100-solarRechargeRatio}% sur secteur.</p> |
|
`; |
|
//<p>${Math.round(100*(simulationResult.cumulatedSolarRechargeEnergy/simulationResult.vehicle.batteryEfficiency) / simulationResult.totalProducedSolarEnergy)}% de l'énergie produite par le panneau photovoltaïque sera utilisée pour recharger le vhélio.</p> |
|
|
|
let batteryChargeGraph = new SvgDrawing.SvgElement(resultsContainer.querySelector('.battery-charge-graph svg')); |
|
|
|
batteryChargeGraph.clear(); |
|
|
|
let marginTop = 10; |
|
let marginBottom = 20; |
|
let marginLeft = 35; |
|
let marginRight = 5; |
|
|
|
batteryChargeGraph.line({ x: marginLeft, y: marginBottom }, { x: batteryChargeGraph.width - marginRight, y: marginBottom }); |
|
batteryChargeGraph.line({ x: marginLeft, y: marginBottom }, { x:marginLeft, y: batteryChargeGraph.height - marginTop }); |
|
|
|
batteryChargeGraph.text({ x: marginLeft-3, y: marginBottom }, '0%', 'end', 0.6); |
|
batteryChargeGraph.text({ x: marginLeft-3, y: batteryChargeGraph.height - marginTop }, '100%', 'end', 0.6); |
|
|
|
batteryChargeGraph.viewport.setData({ x: 0, y: 0, width: 365*24, height: parameters.batteryCapacity }); |
|
batteryChargeGraph.viewport.setView({ x: marginLeft, y: batteryChargeGraph.height - marginBottom, width: batteryChargeGraph.width - (marginLeft+marginRight), height: -batteryChargeGraph.height+(marginTop+marginBottom) }); |
|
batteryChargeGraph.graph(simulationResult.batteryLevel, simulationResult.batteryLevel.map((x, idx) => x == 0 || idx == simulationResult.batteryLevel.length - 2 ? 1 : 0), [{className: ''}, {className: 'grid-recharge'}]); |
|
let months = ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jui', 'Jui', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec']; |
|
let monthWidth = 365*24/12 |
|
for(let month = 0; month < 12; ++month) { |
|
batteryChargeGraph.text({ x: (month+0.5)*monthWidth, y: 0 }, months[month], 'middle', -0.1); |
|
} |
|
|
|
batteryChargeGraph.viewport.setData({ x: 0, y: 0, width: 365*24, height: 1 }); |
|
batteryChargeGraph.viewport.setView({ x: marginLeft, y: batteryChargeGraph.height - marginBottom, width: batteryChargeGraph.width - (marginLeft+marginRight), height: -15 }); |
|
for(let month = 0; month < 13; ++month) { |
|
batteryChargeGraph.line({ x: month*monthWidth, y: 0 }, { x: month*monthWidth, y: -1 }); |
|
} |
|
|
|
resultsContainer.classList.toggle('is-hidden', false); |
|
}); |
|
} |
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
// Load CSS |
|
document.getElementsByTagName('head')[0].innerHTML += (<any>window)['simulator.css']; |
|
|
|
let container = document.getElementById('simulator'); |
|
initializeSimulator(container); |
|
});
|
|
|