mirror of
https://github.com/flobz/psa_car_controller.git
synced 2026-08-23 18:06:15 +00:00
240 lines
7.4 KiB
JavaScript
240 lines
7.4 KiB
JavaScript
class Avg {
|
|
constructor () {
|
|
this.total = 0
|
|
this.count = 0
|
|
}
|
|
|
|
addValue (value) {
|
|
if (typeof value === 'number') {
|
|
this.count++
|
|
this.total = ((this.total * (this.count - 1)) / this.count) + (value / this.count)
|
|
}
|
|
}
|
|
|
|
average () {
|
|
return this.total
|
|
}
|
|
|
|
static getAverageFromKey (array, key) {
|
|
const avg = new Avg()
|
|
array.forEach(function (obj) { avg.addValue(obj[key]) })
|
|
return avg.average()
|
|
}
|
|
}
|
|
const logger = (function () {
|
|
let oldConsoleLog = null
|
|
const pub = {}
|
|
|
|
pub.enableLogger = function enableLogger () {
|
|
if (oldConsoleLog == null) {
|
|
return
|
|
}
|
|
|
|
window.console.log = oldConsoleLog
|
|
}
|
|
|
|
pub.disableLogger = function disableLogger () {
|
|
oldConsoleLog = console.log
|
|
window.console.log = function () {}
|
|
}
|
|
|
|
return pub
|
|
}())
|
|
function addLocaleDate (data, dateKey) {
|
|
const dateOption = [undefined, { hour: 'numeric', minute: 'numeric' }]
|
|
function dateToLocale (row, key) {
|
|
const date = new Date(row[key])
|
|
row[key] = date
|
|
row[key + '_str'] = date.toLocaleDateString(...dateOption)
|
|
}
|
|
let datasetName, dataset
|
|
for ([datasetName, dataset] of Object.entries(data)) {
|
|
dataset.forEach(function (row) {
|
|
dateKey[datasetName].forEach(key => dateToLocale(row, key))
|
|
})
|
|
}
|
|
}
|
|
|
|
function filterDataset (data, range) {
|
|
function dateFromISO (st) {
|
|
return new Date(st).getTime() / 1000
|
|
}
|
|
function isInRange (st) {
|
|
const tsDate = dateFromISO(st)
|
|
return tsDate >= range[0] && tsDate <= range[1]
|
|
}
|
|
const res = {}
|
|
res.trips = data.trips.filter(line => isInRange(line.start_at))
|
|
res.chargings = data.chargings.filter(line => isInRange(line.start_at))
|
|
console.log('filtered_dataset', res)
|
|
return res
|
|
}
|
|
|
|
function filterShortTrip (data) {
|
|
const longTrips = {
|
|
trips: data.trips.filter(line => line.distance > 10),
|
|
chargings: data.chargings
|
|
}
|
|
console.log('long trips:', longTrips)
|
|
return longTrips
|
|
}
|
|
|
|
function updateFigures (data, oldFigure, x, y) {
|
|
const trips = data.trips
|
|
const figures = []
|
|
let i = 0
|
|
y.forEach(function (yLabel) {
|
|
const xLabel = x[i]
|
|
const figure = Object.assign({}, oldFigure[i])
|
|
i++
|
|
// console.log(oldFigure[i]);
|
|
// var unique_y_label = y[i].filter((v, i, a) => a.indexOf(v) === i);
|
|
// var data_nonnull = trips
|
|
// unique_y_label.forEach(function(label) {
|
|
// data_nonnull = data_nonnull.filter(line => line[label]);
|
|
// });
|
|
if ('mapbox' in figure.layout) {
|
|
figure.data[0].lat = []
|
|
figure.data[0].lon = []
|
|
figure.data[0].hovertext = []
|
|
let trip = null
|
|
for (trip of trips) {
|
|
const xPos = trip.positions[xLabel]
|
|
figure.data[0].lat.push(...xPos, null)
|
|
figure.data[0].lon.push(...trip.positions[yLabel[0]])
|
|
figure.data[0].hovertext.push(...Array(xPos.length).fill(trip[yLabel[1]]), null)
|
|
}
|
|
if (trip) {
|
|
const lastPos = trip.positions[yLabel[0]].length - 1
|
|
figure.layout.mapbox.center.lat = trip.positions[xLabel][lastPos]
|
|
figure.layout.mapbox.center.lon = trip.positions[yLabel[0]][lastPos]
|
|
figure.data[1].lat = [figure.layout.mapbox.center.lat]
|
|
figure.data[1].lon = [figure.layout.mapbox.center.lon]
|
|
}
|
|
} else {
|
|
const xValues = trips.map(a => a[xLabel])
|
|
// for each y label
|
|
for (let j = 0; j < yLabel.length; j++) {
|
|
figure.data[j].y = trips.map(a => a[yLabel[j]])
|
|
figure.data[j].x = xValues
|
|
}
|
|
}
|
|
console.log(xLabel, figure)
|
|
figures.push(figure)
|
|
})
|
|
return figures
|
|
}
|
|
|
|
function updateTables (data, tables) {
|
|
console.log('tables', tables)
|
|
const figures = []
|
|
tables.forEach(function (table) {
|
|
figures.push(data[table.src])
|
|
})
|
|
return figures
|
|
}
|
|
|
|
function updateCardsValue (data) {
|
|
const res = {}
|
|
let avgPriceKw
|
|
let avgC02 = new Avg(); let avgKw = new Avg(); const avgTime = new Avg()
|
|
const avgPrice = new Avg()
|
|
data.chargings.forEach(function (charge) {
|
|
const diff = ((new Date(charge.stop_at)) - (new Date(charge.start_at))) / 3600000
|
|
avgKw.addValue(charge.kw)
|
|
avgC02.addValue(charge.co2)
|
|
avgPrice.addValue(charge.price)
|
|
if (diff > 0) {
|
|
avgTime.addValue(diff)
|
|
}
|
|
})
|
|
if (data.chargings.length > 0) {
|
|
avgKw = avgKw.average()
|
|
avgC02 = avgC02.average()
|
|
avgPriceKw = avgPrice.average() / avgKw
|
|
res.avg_emission_kw = avgC02
|
|
res.avg_chg_speed = avgKw / avgTime.average()
|
|
}
|
|
if (data.trips.length > 0) {
|
|
const totalDistance = Math.abs(data.trips[data.trips.length - 1].mileage - data.trips[0].mileage)
|
|
res.avg_consum_kw = Avg.getAverageFromKey(data.trips, 'consumption_km')
|
|
res.elec_consum_kw = totalDistance * res.avg_consum_kw / 100
|
|
}
|
|
if (data.trips.length > 0 && data.chargings.length > 0) {
|
|
res.avg_emission_km = res.avg_emission_kw * res.avg_consum_kw / 100
|
|
res.elec_consum_price = avgPriceKw * res.elec_consum_kw
|
|
res.avg_consum_price = avgPriceKw * res.avg_consum_kw
|
|
}
|
|
for (const [key, value] of Object.entries(res)) {
|
|
document.getElementById(key).innerHTML = value.toPrecision(3)
|
|
}
|
|
}
|
|
|
|
function sortDataset (ctx, data, tables) {
|
|
const tableId = ctx.prop_id.split('.')[0]
|
|
const table = tables.filter(table => table.table_id === tableId)[0]
|
|
if (ctx.value.length > 0 && data[table.src].length > 0) {
|
|
const asc = ctx.value[0].direction === 'asc'
|
|
let columnId = ctx.value[0].column_id
|
|
let sorted
|
|
if (columnId.endsWith('_str')) {
|
|
columnId = columnId.slice(0, -4)
|
|
sorted = data[table.src].sort(function (a, b) {
|
|
return a[columnId] - b[columnId]
|
|
})
|
|
} else if (typeof data[table.src][0][columnId] === 'number') {
|
|
sorted = data[table.src].sort(function (a, b) {
|
|
return a[columnId] - b[columnId]
|
|
})
|
|
} else {
|
|
sorted = data[table.src].sort((a, b) => a[columnId].localeCompare(b[columnId]))
|
|
}
|
|
if (asc === false) {
|
|
sorted = sorted.reverse()
|
|
}
|
|
data[table.src] = sorted
|
|
}
|
|
}
|
|
|
|
function sortMultipleTable (sortParams, data, tables) {
|
|
for (const [propId, ctxValue] of Object.entries(sortParams)) {
|
|
const ctx = {}
|
|
ctx.prop_id = propId + '.sort_by'
|
|
ctx.value = ctxValue
|
|
console.log(ctx)
|
|
sortDataset(ctx, data, tables)
|
|
}
|
|
}
|
|
|
|
function filterAndSort (data, range, figures, p, log, sort) { // eslint-disable-line no-unused-vars
|
|
if (log > 10) {
|
|
logger.disableLogger()
|
|
}
|
|
const ctx = dash_clientside.callback_context.triggered // eslint-disable-line no-undef
|
|
const outFigures = []; let dataFiltered
|
|
console.log('figures:', figures)
|
|
console.log('data:', data)
|
|
console.log('ctx', ctx)
|
|
console.log('sort', sort)
|
|
if (ctx.length > 0 && ctx[0].prop_id.endsWith('sort_by')) {
|
|
dataFiltered = filterDataset(data, range)
|
|
sortDataset(ctx[0], dataFiltered, p.table_src)
|
|
outFigures.push(...updateTables(dataFiltered, p.table_src))
|
|
outFigures.push(...figures.graph)
|
|
outFigures.push(...figures.maps)
|
|
} else {
|
|
addLocaleDate(data, p.date_columns)
|
|
dataFiltered = filterDataset(data, range)
|
|
sortMultipleTable(sort, dataFiltered, p.table_src)
|
|
outFigures.push(...updateTables(dataFiltered, p.table_src))
|
|
console.log(dataFiltered.trips.length)
|
|
const longTrips = filterShortTrip(dataFiltered)
|
|
console.log('trips', dataFiltered.trips.length)
|
|
console.log('longTrips', longTrips.trips.length)
|
|
outFigures.push(...updateFigures(longTrips, figures.graph, p.graph_x_label, p.graph_y_label))
|
|
outFigures.push(...updateFigures(dataFiltered, figures.maps, p.map_x_label, p.map_y_label))
|
|
updateCardsValue(longTrips)
|
|
}
|
|
return outFigures
|
|
}
|