Add history display
This commit is contained in:
parent
76557c7428
commit
fdbc654a86
6 changed files with 220 additions and 19 deletions
35
package-lock.json
generated
35
package-lock.json
generated
|
@ -907,6 +907,35 @@
|
||||||
"supports-color": "^5.3.0"
|
"supports-color": "^5.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"chart.js": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chartjs-color": "^2.1.0",
|
||||||
|
"moment": "^2.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chartjs-color": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chartjs-color-string": "^0.6.0",
|
||||||
|
"color-convert": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chartjs-color-string": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
|
||||||
|
@ -3828,6 +3857,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||||
|
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@beyonk/google-fonts-webpack-plugin": "^1.2.3",
|
"@beyonk/google-fonts-webpack-plugin": "^1.2.3",
|
||||||
|
"chart.js": "^2.9.3",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"css-loader": "^3.4.2",
|
"css-loader": "^3.4.2",
|
||||||
"google-fonts-webpack-plugin": "^0.4.4",
|
"google-fonts-webpack-plugin": "^0.4.4",
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
{#each $counters as counter}
|
{#each $counters as counter}
|
||||||
<Counter counterId={ counter.id }></Counter>
|
<Counter counterId={ counter.id }></Counter>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
|
||||||
<button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
|
<button class="add" on:click="{ showAdd }"><i class="material-icons">add</i></button>
|
||||||
|
</div>
|
||||||
{#if showAddDialog}
|
{#if showAddDialog}
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
|
@ -60,6 +60,8 @@ function add(){
|
||||||
bottom: 15px;
|
bottom: 15px;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
background-color: #90C090;
|
background-color: #90C090;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|
||||||
|
@ -72,13 +74,16 @@ function add(){
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-content button {
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app {
|
.app {
|
||||||
padding: 5px 5px 60px 5px;
|
padding: 5px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -7,8 +7,11 @@
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button on:click={ () => { showIncrement = true; } }><i class="material-icons">add</i></button>
|
<button on:click={ () => { showIncrement = true; } }><i class="material-icons">add</i></button>
|
||||||
<button on:click={ () => { showSet = true; } }><i class="material-icons">edit</i></button>
|
<button on:click={ () => { showSet = true; } }><i class="material-icons">edit</i></button>
|
||||||
<button class="reset" on:click={ reset }><i class="material-icons">undo</i></button>
|
<button class="reset" on:click={ reset }><i class="material-icons">replay</i></button>
|
||||||
<button on:click={ startEdit }><i class="material-icons">edit</i></button>
|
{#if counter.saveHistory}
|
||||||
|
<button class="history" on:click={ () => { showHistory = true; } }><i class="material-icons">show_chart</i></button>
|
||||||
|
{/if}
|
||||||
|
<button on:click={ startEdit }><i class="material-icons">settings</i></button>
|
||||||
<button on:click={ remove }><i class="material-icons">delete</i></button>
|
<button on:click={ remove }><i class="material-icons">delete</i></button>
|
||||||
</div>
|
</div>
|
||||||
{#if showValueDialog}
|
{#if showValueDialog}
|
||||||
|
@ -33,15 +36,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if showHistory}
|
||||||
|
<History { counterId } on:close={ () => { showHistory = false; } }></History>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
import MyProgress from './MyProgress.svelte';
|
import MyProgress from './MyProgress.svelte';
|
||||||
|
import History from './History.svelte';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { counters } from './db.js';
|
import { counters } from './db.js';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
export let counterId;
|
export let counterId;
|
||||||
|
|
||||||
$: counter = $counters.find(x => x.id == counterId);
|
$: counter = $counters.find(x => x.id == counterId);
|
||||||
|
@ -51,6 +55,7 @@ let showIncrement;
|
||||||
let showSet;
|
let showSet;
|
||||||
let showEditDialog;
|
let showEditDialog;
|
||||||
let editingCounter;
|
let editingCounter;
|
||||||
|
let showHistory;
|
||||||
|
|
||||||
$: showValueDialog = showIncrement || showSet;
|
$: showValueDialog = showIncrement || showSet;
|
||||||
|
|
||||||
|
@ -125,6 +130,10 @@ function remove(){
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.counter:last-child {
|
||||||
|
margin-bottom: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -142,9 +151,17 @@ header {
|
||||||
}
|
}
|
||||||
|
|
||||||
.reset {
|
.reset {
|
||||||
|
margin-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset + button {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-value {
|
.dialog-value {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
|
@ -153,10 +170,4 @@ header {
|
||||||
.ok {
|
.ok {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-content button {
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
143
src/ncounter/History.svelte
Normal file
143
src/ncounter/History.svelte
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
<div class="history-container">
|
||||||
|
<header>
|
||||||
|
<h1>{ counter.title }</h1>
|
||||||
|
<button class="close" on:click={ close }><i class="material-icons">close</i></button>
|
||||||
|
</header>
|
||||||
|
<canvas class="chart-container" bind:this={ chartEl } width="{ window.outerWidth }" height="250">
|
||||||
|
</canvas>
|
||||||
|
<div class="table-container">
|
||||||
|
<table class="history">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Time</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each history as data}
|
||||||
|
<tr>
|
||||||
|
<td>{ data.time }</td>
|
||||||
|
<td>{ data.value }</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { counters } from './db.js';
|
||||||
|
import Chart from 'chart.js';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
const formatter = new Intl.DateTimeFormat('en-US',
|
||||||
|
{
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: 'numeric'
|
||||||
|
});
|
||||||
|
|
||||||
|
$: counter = $counters.find(x => x.id == counterId);
|
||||||
|
$: history = counter.history.map(x => {
|
||||||
|
return {
|
||||||
|
time: formatter.format(x.time),
|
||||||
|
value: x.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$: dataset = counter.history.reduce((acc, x) => {
|
||||||
|
return {
|
||||||
|
labels: [...acc.labels, x.time],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [...acc.datasets[0].data, x.value]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
labels: [],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
export let counterId;
|
||||||
|
|
||||||
|
let chartEl;
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if(chartEl){
|
||||||
|
new Chart(chartEl, {
|
||||||
|
type: 'line',
|
||||||
|
data: dataset,
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
xAxes: [
|
||||||
|
{
|
||||||
|
type: 'time'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close(){
|
||||||
|
dispatch('close');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.history-container{
|
||||||
|
background-color: white;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 3;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history th {
|
||||||
|
font-weight: 600;
|
||||||
|
position: sticky;
|
||||||
|
background-color: white;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history th, .history td {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -70,6 +70,12 @@ button {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-content button {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"] {
|
input[type="number"] {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue