mirror of
https://github.com/elisspace/FxLifeSheet.git
synced 2026-08-29 15:44:00 +00:00
Add support for group by week
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'airbnb-base',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {
|
||||
},
|
||||
};
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'airbnb-base',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {},
|
||||
};
|
||||
@@ -30,6 +30,8 @@ class API
|
||||
row[:sum] = row[:sum].truncate(5).to_s('F').to_f # convert from BigFloat to float
|
||||
if group_by == :yearmonth
|
||||
row[:as_date] = Date.strptime(row[:yearmonth].to_s, "%Y%m")
|
||||
elsif group_by == :yearweek
|
||||
row[:as_date] = Date.strptime(row[:yearweek].to_s, "%Y%W")
|
||||
else
|
||||
raise "not yet implemented"
|
||||
end
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<head>
|
||||
<script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form id="mainForm" onSubmit="return false;">
|
||||
<span id="keysContainer">
|
||||
<span id="keysContainer">
|
||||
<table id="keysTable">
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
@@ -15,33 +16,33 @@
|
||||
<th>Shown</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select class="keys" id="keys-0" onchange="updateKeys(0)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-0" onchange="updateKeys(0)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-0" onchange="updateKeys(0)" checked="checked" /></td>
|
||||
<td><select class="keys" id="keys-0" onchange="reloadIndex(0)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-0" onchange="reloadIndex(0)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-0" onchange="reloadIndex(0)" checked="checked" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select class="keys" id="keys-1" onchange="updateKeys(1)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-1" onchange="updateKeys(1)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-1" onchange="updateKeys(1)" checked="checked" /></td>
|
||||
<td><select class="keys" id="keys-1" onchange="reloadIndex(1)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-1" onchange="reloadIndex(1)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-1" onchange="reloadIndex(1)" checked="checked" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select class="keys" id="keys-2" onchange="updateKeys(2)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-2" onchange="updateKeys(2)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-2" onchange="updateKeys(2)" checked="checked" /></td>
|
||||
<td><select class="keys" id="keys-2" onchange="reloadIndex(2)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-2" onchange="reloadIndex(2)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-2" onchange="reloadIndex(2)" checked="checked" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select class="keys" id="keys-3" onchange="updateKeys(3)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-3" onchange="updateKeys(3)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-3" onchange="updateKeys(3)" checked="checked" /></td>
|
||||
<td><select class="keys" id="keys-3" onchange="reloadIndex(3)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-3" onchange="reloadIndex(3)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-3" onchange="reloadIndex(3)" checked="checked" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select class="keys" id="keys-4" onchange="updateKeys(4)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-4" onchange="updateKeys(4)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-4" onchange="updateKeys(4)" checked="checked" /></td>
|
||||
<td><select class="keys" id="keys-4" onchange="reloadIndex(4)" /></td>
|
||||
<td><input type="checkbox" id="keys-avg-4" onchange="reloadIndex(4)" checked="checked" /></td>
|
||||
<td><input type="checkbox" id="keys-show-4" onchange="reloadIndex(4)" checked="checked" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</span>
|
||||
<span id="attributesContainer">
|
||||
<span id="attributesContainer">
|
||||
<h2>Attributes</h2>
|
||||
<table id="attributesTable">
|
||||
<tr>
|
||||
@@ -53,14 +54,24 @@
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Group By</td>
|
||||
<td>
|
||||
<select id="group-by" onchange="updateGroupBy()">
|
||||
<option value="month" selected="selected">Month</option>
|
||||
<option value="week">Week</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start date</td>
|
||||
<td><input type="text" value="2019-04" id="start-date" name="start-date" onchange="updatedAttribute()" /></td>
|
||||
<td><input type="text" value="2019-04" id="start-date" name="start-date" onchange="reloadAllData()" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</span>
|
||||
</form>
|
||||
<div id='myGraph' />
|
||||
</body>
|
||||
<script type="text/javascript" src="/frontend.js"></script>
|
||||
</html>
|
||||
</body>
|
||||
<script type="text/javascript" src="/frontend.js"></script>
|
||||
|
||||
</html>
|
||||
@@ -1,157 +1,162 @@
|
||||
const host = 'http://127.0.0.1:4567';
|
||||
let keys = [];
|
||||
const allData = [];
|
||||
let groupBy = 'month';
|
||||
// Multiple axis https://plotly.com/javascript/multiple-axes/
|
||||
for (const currentIndex of Array(5).keys()) {
|
||||
const current = {
|
||||
x: [],
|
||||
y: [],
|
||||
name: `yaxis${currentIndex + 1} data`,
|
||||
type: 'scatter',
|
||||
line: { shape: 'spline' },
|
||||
};
|
||||
if (currentIndex > 0) { current.yaxis = `y${currentIndex + 1}`; }
|
||||
allData.push(current);
|
||||
const current = {
|
||||
x: [],
|
||||
y: [],
|
||||
name: `yaxis${currentIndex + 1} data`,
|
||||
type: 'scatter',
|
||||
line: { shape: 'spline' },
|
||||
};
|
||||
if (currentIndex > 0) { current.yaxis = `y${currentIndex + 1}`; }
|
||||
allData.push(current);
|
||||
}
|
||||
console.log(allData);
|
||||
|
||||
const layout = {
|
||||
title: 'Life Sheet Data',
|
||||
barmode: 'group',
|
||||
yaxis: {
|
||||
titlefont: { color: '#1f77b4' },
|
||||
tickfont: { color: '#1f77b4' },
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis2: {
|
||||
titlefont: { color: '#ff7f0e' },
|
||||
tickfont: { color: '#ff7f0e' },
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis3: {
|
||||
titlefont: { color: '#d62728' },
|
||||
tickfont: { color: '#d62728' },
|
||||
anchor: 'x',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis4: {
|
||||
titlefont: { color: '#9467bd' },
|
||||
tickfont: { color: '#9467bd' },
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis5: {
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
title: 'Life Sheet Data',
|
||||
barmode: 'group',
|
||||
yaxis: {
|
||||
titlefont: { color: '#1f77b4' },
|
||||
tickfont: { color: '#1f77b4' },
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis2: {
|
||||
titlefont: { color: '#ff7f0e' },
|
||||
tickfont: { color: '#ff7f0e' },
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis3: {
|
||||
titlefont: { color: '#d62728' },
|
||||
tickfont: { color: '#d62728' },
|
||||
anchor: 'x',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis4: {
|
||||
titlefont: { color: '#9467bd' },
|
||||
tickfont: { color: '#9467bd' },
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
yaxis5: {
|
||||
anchor: 'free',
|
||||
overlaying: 'y',
|
||||
showgrid: false,
|
||||
zeroline: false,
|
||||
showticklabels: false,
|
||||
},
|
||||
};
|
||||
|
||||
Plotly.newPlot('myGraph', allData, layout);
|
||||
|
||||
function loadKeys(callback) {
|
||||
httpGetAsync(`${host}/keys`, (data) => {
|
||||
keys = data;
|
||||
selects = document.getElementsByClassName('keys');
|
||||
for (let i = 0; i < selects.length; i++) {
|
||||
data.forEach((row) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = row.key;
|
||||
opt.innerHTML = `${row.key} (${row.count})`;
|
||||
selects[i].appendChild(opt);
|
||||
});
|
||||
}
|
||||
callback(keys);
|
||||
});
|
||||
}
|
||||
|
||||
function updateKeys(index) {
|
||||
select = document.getElementById(`keys-${index}`);
|
||||
loadData(select.value, index);
|
||||
}
|
||||
|
||||
function updatedAttribute() {
|
||||
for (const currentIndex of Array(5).keys()) {
|
||||
updateKeys(currentIndex);
|
||||
}
|
||||
httpGetAsync(`${host}/keys`, (data) => {
|
||||
keys = data;
|
||||
selects = document.getElementsByClassName('keys');
|
||||
for (let i = 0; i < selects.length; i++) {
|
||||
data.forEach((row) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = row.key;
|
||||
opt.innerHTML = `${row.key} (${row.count})`;
|
||||
selects[i].appendChild(opt);
|
||||
});
|
||||
}
|
||||
callback(keys);
|
||||
});
|
||||
}
|
||||
|
||||
function updateGraphType() {
|
||||
const graphType = document.getElementById('graph-type').value;
|
||||
for (let i = 0; i < allData.length; i++) {
|
||||
allData[i].type = graphType;
|
||||
if (graphType == 'scatter') {
|
||||
allData[i].yaxis = allData[i].yaxisBak;
|
||||
} else {
|
||||
allData[i].yaxisBak = allData[i].yaxis;
|
||||
delete allData[i].yaxis;
|
||||
const graphType = document.getElementById('graph-type').value;
|
||||
for (let i = 0; i < allData.length; i++) {
|
||||
allData[i].type = graphType;
|
||||
if (graphType == 'scatter') {
|
||||
allData[i].yaxis = allData[i].yaxisBak;
|
||||
} else {
|
||||
allData[i].yaxisBak = allData[i].yaxis;
|
||||
delete allData[i].yaxis;
|
||||
}
|
||||
}
|
||||
}
|
||||
Plotly.redraw('myGraph');
|
||||
Plotly.redraw('myGraph');
|
||||
}
|
||||
|
||||
function loadData(key, index) {
|
||||
// TODO: remove the line below
|
||||
select = document.getElementById(`keys-${index}`);
|
||||
select.value = key;
|
||||
function updateGroupBy() {
|
||||
groupBy = document.getElementById("group-by").value;
|
||||
reloadAllData();
|
||||
}
|
||||
|
||||
const startDate = document.getElementById('start-date');
|
||||
const isShown = document.getElementById(`keys-show-${index}`).checked;
|
||||
function updateKeyForIndex(key, index) {
|
||||
document.getElementById(`keys-${index}`).value = key;
|
||||
reloadIndex(index);
|
||||
}
|
||||
|
||||
if (isShown) {
|
||||
httpGetAsync(`${host}/data?group_by=month&key=${key}&start_date=${startDate.value}`, (data) => {
|
||||
allData[index].x = data.rows.map((r) => r.as_date);
|
||||
if (document.getElementById(`keys-avg-${index}`).checked) {
|
||||
allData[index].y = data.rows.map((r) => Math.round(r.avg * 1000) / 1000);
|
||||
} else {
|
||||
allData[index].y = data.rows.map((r) => Math.round(r.sum * 1000) / 1000);
|
||||
}
|
||||
allData[index].name = key;
|
||||
function reloadIndex(index) {
|
||||
const key = document.getElementById(`keys-${index}`).value;
|
||||
const startDate = document.getElementById('start-date');
|
||||
const isShown = document.getElementById(`keys-show-${index}`).checked;
|
||||
|
||||
Plotly.redraw('myGraph');
|
||||
console.log(allData);
|
||||
console.log(layout);
|
||||
});
|
||||
} else {
|
||||
allData[index].y = [];
|
||||
Plotly.redraw('myGraph');
|
||||
}
|
||||
if (isShown) {
|
||||
httpGetAsync(`${host}/data?group_by=${groupBy}&key=${key}&start_date=${startDate.value}`, (data) => {
|
||||
allData[index].x = data.rows.map((r) => r.as_date);
|
||||
if (document.getElementById(`keys-avg-${index}`).checked) {
|
||||
allData[index].y = data.rows.map((r) => Math.round(r.avg * 1000) / 1000);
|
||||
} else {
|
||||
allData[index].y = data.rows.map((r) => Math.round(r.sum * 1000) / 1000);
|
||||
}
|
||||
allData[index].name = key;
|
||||
|
||||
Plotly.redraw('myGraph');
|
||||
console.log(allData);
|
||||
console.log(layout);
|
||||
});
|
||||
} else {
|
||||
allData[index].y = [];
|
||||
Plotly.redraw('myGraph');
|
||||
}
|
||||
}
|
||||
|
||||
function httpGetAsync(theUrl, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
|
||||
callback(JSON.parse(xmlHttp.responseText));
|
||||
}
|
||||
};
|
||||
xmlHttp.open('GET', theUrl, true);
|
||||
xmlHttp.send(null);
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function() {
|
||||
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
|
||||
callback(JSON.parse(xmlHttp.responseText));
|
||||
}
|
||||
};
|
||||
xmlHttp.open('GET', theUrl, true);
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
loadKeys(() => {
|
||||
loadData(keys[0].key, 0);
|
||||
loadData(keys[1].key, 1);
|
||||
loadData(keys[2].key, 2);
|
||||
loadData(keys[3].key, 3);
|
||||
loadData(keys[4].key, 4);
|
||||
// loadData('mood', 0);
|
||||
// loadData('excitedAboutFuture', 1);
|
||||
// loadData('sleepDurationWithings', 2);
|
||||
// loadData('bedTime', 3);
|
||||
// loadData('gym', 4);
|
||||
updateKeyForIndex('mood', 0);
|
||||
updateKeyForIndex('excitedAboutFuture', 1);
|
||||
updateKeyForIndex('sleepDurationWithings', 2);
|
||||
updateKeyForIndex('bedTime', 3);
|
||||
updateKeyForIndex('gym', 4);
|
||||
// reloadAllData();
|
||||
|
||||
// updateKeyForIndex(keys[0].key, 0);
|
||||
// updateKeyForIndex(keys[1].key, 1);
|
||||
// updateKeyForIndex(keys[2].key, 2);
|
||||
// updateKeyForIndex(keys[3].key, 3);
|
||||
// updateKeyForIndex(keys[4].key, 4);
|
||||
});
|
||||
|
||||
function reloadAllData() {
|
||||
for (const currentIndex of Array(5).keys()) {
|
||||
reloadIndex(currentIndex);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user