Graph update and little noe ui tweaks
This commit is contained in:
1 parent
d3acd62688
commit
c61f0c0198
12 files changed
+1341
-356
No files matched your search
@@ -1,4 +1,4 @@
|
||||
<style>
|
||||
<style scoped>
|
||||
div.no-padding {
|
||||
padding: 10px 0 40px !important;
|
||||
box-sizing: border-box;
|
||||
@@ -233,16 +233,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
.an-graph {
|
||||
background: #fefefe82;
|
||||
.days-ago-display {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.input-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.bottom.aligned.row {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="squire-box no-padding" ref="scrollcontainer">
|
||||
|
||||
<!-- intro modal -->
|
||||
<modal v-if="!noteId" :click-out-close="false">
|
||||
<div class="ui segment">
|
||||
<div class="ui center aligned middle aligned grid">
|
||||
@@ -273,10 +283,10 @@
|
||||
</div>
|
||||
|
||||
<!-- section 1 entry -->
|
||||
<section class="swipe-section">
|
||||
<section class="swipe-section" v-if="true">
|
||||
<!-- <delete-button v-if="noteId > 0" class="ui small button" :note-id="noteId" /> -->
|
||||
<div class="ui small centered dividing header">
|
||||
Metric Tracking Bet
|
||||
Metric Tracking
|
||||
<span class="sub header"><i class="small lock icon"></i>All data Encrypted. Only accessible by you.</span>
|
||||
</div>
|
||||
|
||||
@@ -314,10 +324,18 @@
|
||||
<!-- data input -->
|
||||
<div class="ui basic segment">
|
||||
<div class="ui very compact grid">
|
||||
<div class="ui twelve wide middle aligned column">
|
||||
<div class="four wide column"></div>
|
||||
<div class="ui eight wide middle aligned center aligned column">
|
||||
<div class="ui header">
|
||||
Entry for {{ calendar.monthName }},
|
||||
<span :class="{'loading-day-title':loadingDay}">{{ calendar.today }}</span>
|
||||
<span :class="{'loading-day-title':loadingDay}">
|
||||
{{ calendar.monthName }}
|
||||
{{ calendar.today }}, {{ calendar.dayName }}
|
||||
<span class="days-ago-display">
|
||||
<!-- <span v-if="calendar.daysAgo == 0">Today</span> -->
|
||||
<span v-if="calendar.daysAgo == 1"><br>{{ calendar.daysAgo }} day ago</span>
|
||||
<span v-if="calendar.daysAgo > 1"><br>{{ calendar.daysAgo }} days ago</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui four wide right aligned middle aligned column">
|
||||
@@ -339,77 +357,89 @@
|
||||
<div class="ui form" :class="{'loading-day':loadingDay}">
|
||||
<draggable v-model="fields" class="ui compact grid" ghost-class="ghost" @end="onDragEnd" handle=".draggable">
|
||||
<div v-for="field in fields" :key="field"
|
||||
:class="userFields[field]?.width ? userFields[field]?.width+' wide column':'eight wide column'">
|
||||
<!-- field label display -->
|
||||
<div class="ui very compact grid">
|
||||
<div class="ui sixteen wide center aligned column">
|
||||
<i :class="`${getFieldColor(field)} ${getFieldIcon(field)} icon`"></i>
|
||||
<b>{{ userFields[field]?.label }}</b>
|
||||
<span>{{ field }}</span>
|
||||
</div>
|
||||
</div>
|
||||
:class="userFields[field]?.width ? userFields[field]?.width+' wide stretched column':'eight wide stretched column'">
|
||||
|
||||
<!-- float -->
|
||||
<div v-if="userFields[field]?.type == 'float'" class="ui fluid input">
|
||||
<input type="text" :placeholder="userFields[field]?.label" v-on:keyup="e => saveField(field, e.target.value)" :value="openDay[field]">
|
||||
</div>
|
||||
|
||||
<!-- range -->
|
||||
<div v-if="userFields[field]?.type == 'shortRange'">
|
||||
<div :class="{green:(openDay[field] == 1)}" v-on:click="saveField(field, 1)" class="ui button">1</div>
|
||||
<div :class="{green:(openDay[field] == 2)}" v-on:click="saveField(field, 2)" class="ui button">2</div>
|
||||
<div :class="{green:(openDay[field] == 3)}" v-on:click="saveField(field, 3)" class="ui button">3</div>
|
||||
<div :class="{green:(openDay[field] == 4)}" v-on:click="saveField(field, 4)" class="ui button">4</div>
|
||||
<div :class="{green:(openDay[field] == 5)}" v-on:click="saveField(field, 5)" class="ui button">5</div>
|
||||
</div>
|
||||
|
||||
<!-- text area -->
|
||||
<div v-if="userFields[field]?.type == 'text'">
|
||||
<textarea rows="3" v-on:keyup="e => saveField(field, e.target.value, 2000)" :value="openDay[field]">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<!-- boolean -->
|
||||
<div v-if="userFields[field]?.type == 'boolean'">
|
||||
<div :class="{green:(openDay[field] == 1)}" v-on:click="saveField(field, 1)" class="ui button">Yes</div>
|
||||
<div :class="{green:(openDay[field] == 2)}" v-on:click="saveField(field, 2)" class="ui button">No</div>
|
||||
</div>
|
||||
|
||||
<div v-if="['sex','period','mucus','pms'].includes(userFields[field]?.type)">
|
||||
<div class="option-buttons">
|
||||
<div :class="{green:(openDay[field] == key)}" v-on:click="saveField(field, key)" class="ui compact button" v-for="(item,key) in fieldTypes[userFields[field]?.type].split(',')">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="userFields[field]?.type == 'custom'">
|
||||
<div class="option-buttons">
|
||||
<div
|
||||
v-for="(item, value) in userFields[field]?.customOptions.split(',')"
|
||||
v-on:click="saveField(field, value)"
|
||||
:class="{green:(openDay[field] == value) && openDay[field] !== ''}"
|
||||
class="ui compact button">
|
||||
{{ item.trim() }}
|
||||
<div class="ui very compact grid input-grid">
|
||||
<!-- field label display -->
|
||||
<div class="row">
|
||||
<div class="ui sixteen wide column">
|
||||
<b><i :class="`${getFieldColor(field)} ${getFieldIcon(field)} icon`"></i>
|
||||
{{ userFields[field]?.label }}</b>
|
||||
<!-- <span>{{ field }}</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- input display -->
|
||||
<div class="row">
|
||||
<div class="sixteen wide column">
|
||||
|
||||
<div class="ui very compact grid">
|
||||
<div class="ui six wide column">
|
||||
<span v-on:click="editField(field)">
|
||||
<i class="clickable grey edit outline icon"></i>
|
||||
</span>
|
||||
<!-- float -->
|
||||
<div v-if="userFields[field]?.type == 'float'" class="ui fluid input">
|
||||
<input type="text" :placeholder="userFields[field]?.label" v-on:keyup="e => saveField(field, e.target.value)" :value="openDay[field]">
|
||||
</div>
|
||||
|
||||
<!-- range -->
|
||||
<div v-if="userFields[field]?.type == 'shortRange'">
|
||||
<div :class="{green:(openDay[field] == 1)}" v-on:click="saveField(field, 1)" class="ui button">1</div>
|
||||
<div :class="{green:(openDay[field] == 2)}" v-on:click="saveField(field, 2)" class="ui button">2</div>
|
||||
<div :class="{green:(openDay[field] == 3)}" v-on:click="saveField(field, 3)" class="ui button">3</div>
|
||||
<div :class="{green:(openDay[field] == 4)}" v-on:click="saveField(field, 4)" class="ui button">4</div>
|
||||
<div :class="{green:(openDay[field] == 5)}" v-on:click="saveField(field, 5)" class="ui button">5</div>
|
||||
</div>
|
||||
|
||||
<!-- text area -->
|
||||
<div v-if="userFields[field]?.type == 'text'">
|
||||
<textarea rows="3" v-on:keyup="e => saveField(field, e.target.value, 2000)" :value="openDay[field]">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<!-- boolean -->
|
||||
<div v-if="userFields[field]?.type == 'boolean'">
|
||||
<div class="option-buttons">
|
||||
<div :class="{green:(openDay[field] == 1)}" v-on:click="saveField(field, 1)" class="ui compact button">Yes</div>
|
||||
<div :class="{green:(openDay[field] == 2)}" v-on:click="saveField(field, 2)" class="ui compact button">No</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="['sex','period','mucus','pms'].includes(userFields[field]?.type)">
|
||||
<div class="option-buttons">
|
||||
<div :class="{green:(openDay[field] == key)}" v-on:click="saveField(field, key)" class="ui compact button" v-for="(item,key) in fieldTypesDef[userFields[field]?.type].split(',')">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="userFields[field]?.type == 'custom'">
|
||||
<div class="option-buttons">
|
||||
<div
|
||||
v-for="(item, value) in userFields[field]?.customOptions.split(',')"
|
||||
v-on:click="saveField(field, value)"
|
||||
:class="{green:(openDay[field] == value) && openDay[field] !== ''}"
|
||||
class="ui compact button">
|
||||
{{ item.trim() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="four wide center aligned column draggable">
|
||||
<span>
|
||||
<i class="grey grip lines icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ui six wide right aligned column">
|
||||
<span v-if="openDay[field] !== ''" v-on:click="saveField(field, '')">
|
||||
<i class="grey clickable reply icon"></i>
|
||||
</span>
|
||||
|
||||
<div class="bottom aligned row">
|
||||
<div class="ui six wide column">
|
||||
<span v-on:click="editField(field)">
|
||||
<i class="clickable grey edit outline icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="four wide center aligned column draggable">
|
||||
<span>
|
||||
<i class="grey grip lines icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ui six wide right aligned column">
|
||||
<span v-if="openDay[field] !== ''" v-on:click="saveField(field, '')">
|
||||
<i class="grey clickable reply icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -420,7 +450,7 @@
|
||||
</section>
|
||||
|
||||
<!-- section 2 analysis -->
|
||||
<section class="swipe-section">
|
||||
<section class="swipe-section" v-if="!loading">
|
||||
|
||||
<div class="ui small centered dividing header">
|
||||
Review Data
|
||||
@@ -445,7 +475,7 @@
|
||||
</div>
|
||||
|
||||
<!-- calendar -->
|
||||
<div class="calendar">
|
||||
<div class="calendar" v-if="false">
|
||||
|
||||
<div v-for="day in calendar.weekdays" class="day">
|
||||
{{ day }}
|
||||
@@ -476,7 +506,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui segment">
|
||||
<div class="ui segment" v-if="false">
|
||||
<a class="ui clickable" v-on:click="toggleFolded('key')">
|
||||
<i class="tiny circular blue clickable plus icon"></i>
|
||||
Calendar Explanation
|
||||
@@ -558,31 +588,40 @@
|
||||
<!-- Temp graph -->
|
||||
<div class="ui basic segment" >
|
||||
<div class="ui dividing header">
|
||||
Chart data for the last {{ tempChartDays }} days
|
||||
Chart data for the last {{ tempChartDays }} entries
|
||||
</div>
|
||||
<div class="ui tiny compact fluid buttons">
|
||||
<div :class="{'green':(tempChartDays == 1000000)}" v-on:click="tempChartDays = 1000000; graphCurrentData()" class="ui button">ALL</div>
|
||||
<div :class="{'green':(tempChartDays == 90)}" v-on:click="tempChartDays = 90; graphCurrentData()" class="ui button">90</div>
|
||||
<div :class="{'green':(tempChartDays == 60)}" v-on:click="tempChartDays = 60; graphCurrentData()" class="ui button">60</div>
|
||||
<div :class="{'green':(tempChartDays == 30)}" v-on:click="tempChartDays = 30; graphCurrentData()" class="ui button">30</div>
|
||||
<div :class="{'green':(tempChartDays == 7)}" v-on:click="tempChartDays = 7; graphCurrentData()" class="ui button">7</div>
|
||||
<div :class="{'green':(tempChartDays == 1000000)}" v-on:click="tempChartDays = 1000000; " class="ui button">ALL</div>
|
||||
<div :class="{'green':(tempChartDays == 90)}" v-on:click="tempChartDays = 90; " class="ui button">90</div>
|
||||
<div :class="{'green':(tempChartDays == 60)}" v-on:click="tempChartDays = 60; " class="ui button">60</div>
|
||||
<div :class="{'green':(tempChartDays == 30)}" v-on:click="tempChartDays = 30; " class="ui button">30</div>
|
||||
<div :class="{'green':(tempChartDays == 15)}" v-on:click="tempChartDays = 15; " class="ui button">15</div>
|
||||
<div :class="{'green':(tempChartDays == 7)}" v-on:click="tempChartDays = 7; " class="ui button">7</div>
|
||||
</div>
|
||||
|
||||
<!-- <div id="graphdiv" style="width: 100%; min-height: 320px;"></div> -->
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<div v-for="(graph, index) in graphs" class="an-graph">
|
||||
<div class="ui small dividing header">
|
||||
{{ graph?.title }}
|
||||
</div>
|
||||
<div :id="`graphdiv${index}`" style="width: 100%; min-height: 320px;"></div>
|
||||
<br>
|
||||
<MetricGraphs
|
||||
:key="'graph-updates-'+graphUpdates"
|
||||
:tempChartDays="tempChartDays"
|
||||
:fields="fields"
|
||||
:userFields="userFields"
|
||||
:graphs="graphs"
|
||||
:cycleData="cycleData"
|
||||
:calendar="calendar"
|
||||
@saveGraphs="saveGraphs"
|
||||
@toggleEditGraphs="toggleEditGraphs"
|
||||
:editGraphs="editGraphs"
|
||||
/>
|
||||
|
||||
<div class="ui very padded basic segment">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- notes -->
|
||||
<div class="ui basic segment">
|
||||
<div class="ui basic segment" v-if="false">
|
||||
<div class="ui clickable" v-on:click="toggleFolded('notes')">
|
||||
<i class="tiny circular blue clickable plus icon"></i>
|
||||
Additional Notes
|
||||
@@ -780,21 +819,21 @@
|
||||
</div>
|
||||
<div v-for="(entry, key) in fieldDefinition" class="row" v-if="!['id'].includes(key)">
|
||||
|
||||
<div v-if="fieldDefinitionOptions[key]" class="sixteen wide column">
|
||||
<div v-if="fieldDefinitionOptionsDef[key]" class="sixteen wide column">
|
||||
{{ mapFormTerm(key) }}
|
||||
|
||||
<div v-if="fieldDefinitionOptions[key].type == 'text'" class="ui fluid input">
|
||||
<div v-if="fieldDefinitionOptionsDef[key].type == 'text'" class="ui fluid input">
|
||||
<input type="text" :value="editFieldObject[key]" v-on:keyup="e => setNewFieldOption(e, key)">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div v-if="fieldDefinitionOptions[key].type == 'commatextoptions' && editFieldObject?.type == 'custom'" class="ui fluid input">
|
||||
<div v-if="fieldDefinitionOptionsDef[key].type == 'commatextoptions' && editFieldObject?.type == 'custom'" class="ui fluid input">
|
||||
<input type="text" :value="editFieldObject[key]" v-on:keyup="e => setNewFieldOption(e, key)">
|
||||
</div>
|
||||
|
||||
<div v-if="fieldDefinitionOptions[key].type == 'option'">
|
||||
<div v-for="option in fieldDefinitionOptions[key].options"
|
||||
<div v-if="fieldDefinitionOptionsDef[key].type == 'option'">
|
||||
<div v-for="option in fieldDefinitionOptionsDef[key].options"
|
||||
v-on:click="setNewFieldOption(null, key, option)"
|
||||
:class="{'green':editFieldObject[key] == option}"
|
||||
class="ui button">
|
||||
@@ -802,8 +841,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="fieldDefinitionOptions[key].type == 'icons'">
|
||||
<div v-for="option in fieldDefinitionOptions[key].options"
|
||||
<div v-if="fieldDefinitionOptionsDef[key].type == 'icons'">
|
||||
<div v-for="option in fieldDefinitionOptionsDef[key].options"
|
||||
v-on:click="setNewFieldOption(null, key, option)"
|
||||
:class="{'green':editFieldObject[key] == option}"
|
||||
class="ui icon button">
|
||||
@@ -812,8 +851,8 @@
|
||||
</div>
|
||||
|
||||
<!-- :class="{'green':}" -->
|
||||
<div v-if="fieldDefinitionOptions[key].type == 'color'">
|
||||
<div v-for="option in fieldDefinitionOptions[key].options"
|
||||
<div v-if="fieldDefinitionOptionsDef[key].type == 'color'">
|
||||
<div v-for="option in fieldDefinitionOptionsDef[key].options"
|
||||
v-on:click="setNewFieldOption(null, key, option)"
|
||||
:class="`ui ${option} icon button`">
|
||||
<i v-if="editFieldObject[key] == option" class="white check icon"></i>
|
||||
@@ -865,10 +904,6 @@
|
||||
import axios from 'axios'
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
import { Chart } from 'chart.js/auto'
|
||||
|
||||
var BASAL_TEMP = 'BT'
|
||||
|
||||
export default {
|
||||
name: 'MetricTracking',
|
||||
components: {
|
||||
@@ -876,6 +911,7 @@
|
||||
'delete-button': require('@/components/NoteDeleteButtonComponent.vue').default,
|
||||
'modal': require('@/components/ModalComponent.vue').default,
|
||||
draggable,
|
||||
'MetricGraphs':require('@/components/Metrictracking/MetricGraphsComponent.vue').default,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -886,15 +922,8 @@
|
||||
showNotes: false,
|
||||
fields:[], // Array of field IDs
|
||||
userFields:{}, // Objects of field definitions
|
||||
graphs:[
|
||||
// types [null, 'lastDone', 'pillCalendar']
|
||||
{type:'pillCalendar', title:'Pill Cal', fieldIds:['JX3QD','K3KII']},
|
||||
{type:'lastDone', title:'Last Done', fieldIds:['JX3QD','K3KII']},
|
||||
{title:'Basal Temp', fieldIds:['BT']},
|
||||
{title:'Basal Temp - Cervical Fluid', fieldIds:['BT','CM']},
|
||||
{title:'Test Graph', fieldIds:['40DA6','MI9B9']},
|
||||
],
|
||||
fieldTypes:{
|
||||
graphs:[],
|
||||
fieldTypesDef:{
|
||||
'float':'Precise Number',
|
||||
'shortRange':'Options 1-5',
|
||||
'longRange':'Options 1-10',
|
||||
@@ -922,7 +951,7 @@
|
||||
fieldDefinition:{
|
||||
'id':'','type':'','label':'','icon':'','color':'','width':'','customOptions':''
|
||||
},
|
||||
fieldDefinitionOptions:{
|
||||
fieldDefinitionOptionsDef:{
|
||||
label:{'type':'text'},
|
||||
customOptions:{'type':'commatextoptions'},
|
||||
icon:{'type':'icons', 'options':['heart','smile','cat','crow','dog','dove','dragon','feather','feather alternate','fish','frog','hippo','horse','horse head','kiwi bird','otter','paw','spider','video','headphones','motorcycle','truck','monster truck','campground','cloud sun','drumstick bite','football ball','fruit-apple','hiking','mountain','tractor','tree','wind','wine bottle','coffee','flask','glass cheers','glass martini','beer','toilet paper','gift','globe','hand holding heart','comment','graduation cap','hat cowboy','hat wizard','mitten','user tie','laptop code','microchip','shield alternate','mouse','plug','power off','satellite','hammer','wrench','bell','eye','marker','paperclip','atom','award','theater masks','music','grin alternate','grin tongue squint outline','laugh wink','fire','fire alternate','poop','sun','money bill alternate','piggy bank','heart outline','heartbeat','running','walking','bacon','bone','bread slice','candy cane','carrot','cheese','cloud meatball','cookie','egg','hamburger','hotdog','ice cream','lemon','lemon outline','pepper hot','pizza slice','seedling','stroopwafel','leaf','book dead','broom','cloud moon','ghost','mask','skull crossbones','certificate','check','check circle','joint','cannabis','bong','gem','futbol','brain','dna','hand spock','hand spock outline','meteor','moon','moon outline','robot','rocket','satellite dish','space shuttle','user astronaut','fingerprint','thumbs up','thumbs down']},
|
||||
@@ -931,15 +960,18 @@
|
||||
},
|
||||
cycleData: {},
|
||||
totalEntries: 0,
|
||||
openDay: {},
|
||||
openDay: {}, // current day values, updates into cycleData when saved
|
||||
loadingDayTimeout: null,
|
||||
loadingDay: false,
|
||||
saveDataDebounce:null,
|
||||
loading: true,
|
||||
saving: 0, // 0 blank, 1 modified, 2 saving, 3 saved
|
||||
calendar: {
|
||||
dateObject: null,
|
||||
dateCode: null,
|
||||
monthName: '',
|
||||
dayName:'',
|
||||
daysAgo:0,
|
||||
month: '',
|
||||
year: '',
|
||||
days: [],
|
||||
@@ -952,6 +984,8 @@
|
||||
editFieldId:'',
|
||||
editFieldObject:{},
|
||||
appDataImport:'',
|
||||
graphUpdates:0,
|
||||
editGraphs: false,
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
@@ -972,11 +1006,6 @@
|
||||
location.reload();
|
||||
})
|
||||
|
||||
// Include JS libraries
|
||||
let graphsScript = document.createElement('script')
|
||||
graphsScript.setAttribute('src', '//cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.js')
|
||||
document.head.appendChild(graphsScript)
|
||||
|
||||
// setup date to today
|
||||
this.setupCalendar()
|
||||
|
||||
@@ -1035,6 +1064,19 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveGraphs(newGraphData){
|
||||
|
||||
this.graphs = newGraphData
|
||||
this.saveCycleData()
|
||||
|
||||
// re-render graph data on update
|
||||
this.$nextTick(() => {
|
||||
this.graphUpdates++
|
||||
})
|
||||
},
|
||||
toggleEditGraphs(){
|
||||
this.editGraphs = !this.editGraphs
|
||||
},
|
||||
getFieldColor(field){
|
||||
|
||||
let color = null
|
||||
@@ -1134,14 +1176,14 @@
|
||||
validateCustomFieldsForm(){
|
||||
|
||||
const checks = [] //check
|
||||
const checkFields = Object.keys(this.fieldDefinitionOptions)
|
||||
const checkFields = Object.keys(this.fieldDefinitionOptionsDef)
|
||||
|
||||
checkFields.forEach(row => {
|
||||
|
||||
// console.log(this.editFieldObject[row])
|
||||
|
||||
// don't worry about optional fields
|
||||
if(this.fieldDefinitionOptions[row].optional){
|
||||
if(this.fieldDefinitionOptionsDef[row].optional){
|
||||
checks.push(true)
|
||||
return
|
||||
}
|
||||
@@ -1323,98 +1365,6 @@
|
||||
this.fields.push(fieldId)
|
||||
this.saveCycleData()
|
||||
},
|
||||
graphCurrentData(){
|
||||
|
||||
const graphOptions = {
|
||||
interactionModel: {},
|
||||
// pointClickCallback: function(e, pt){
|
||||
// console.log(e)
|
||||
// console.log(pt)
|
||||
// console.log(this.getValue(pt.idx, 0))
|
||||
// }
|
||||
}
|
||||
|
||||
// Excel date format YYYYMMDD
|
||||
const convertToExcelDate = (dateCode) => {
|
||||
return dateCode
|
||||
.split('.')
|
||||
.reverse()
|
||||
.map(item => String(item).padStart(2,0))
|
||||
.join('')
|
||||
}
|
||||
|
||||
const sortableDate = (dateCode) => {
|
||||
return parseInt(
|
||||
dateCode
|
||||
.split('.')
|
||||
.map(i => String(i).padStart(2, '0'))
|
||||
.reverse()
|
||||
.join('')
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Generate set of keys for graph length
|
||||
let dataKeys = Object.keys(this.cycleData)
|
||||
dataKeys.sort((a,b) => {
|
||||
a = sortableDate(a)
|
||||
b = sortableDate(b)
|
||||
return b - a
|
||||
})
|
||||
dataKeys = dataKeys.splice(0, this.tempChartDays)
|
||||
|
||||
// build CSV data for each graph
|
||||
this.graphs.forEach((graph,index) => {
|
||||
|
||||
// CSV or path to a CSV file.
|
||||
let dataString = ""
|
||||
|
||||
// Lookup graph field titles
|
||||
let graphLabels = ['Date']
|
||||
graph.fieldIds.forEach(fieldId => {
|
||||
const graphLabel = this.userFields[fieldId]?.label
|
||||
graphLabels.push(graphLabel)
|
||||
})
|
||||
dataString += graphLabels.join(',') + '\n'
|
||||
|
||||
|
||||
// build each row, for each day
|
||||
for (var i = 0; i < dataKeys.length; i++) {
|
||||
|
||||
let nextFragment = []
|
||||
// push date code to first column
|
||||
nextFragment.push(convertToExcelDate(dataKeys[i]))
|
||||
|
||||
graph.fieldIds.forEach(fieldId => {
|
||||
|
||||
const currentEntry = this.cycleData[dataKeys[i]]
|
||||
let currentValue = currentEntry[fieldId]
|
||||
|
||||
|
||||
if(fieldId == 'BT'){
|
||||
// parse temp to fixed length float 00.00
|
||||
currentValue = parseFloat(currentValue).toFixed(2)
|
||||
}
|
||||
if(fieldId == 'CM'){
|
||||
currentValue = parseFloat('97.'+currentValue)
|
||||
}
|
||||
|
||||
nextFragment.push(currentValue)
|
||||
|
||||
})
|
||||
|
||||
dataString += nextFragment.join(',') + "\n"
|
||||
}
|
||||
|
||||
|
||||
let graphDiv = document.getElementById("graphdiv"+index)
|
||||
const g = new Dygraph(graphDiv, dataString ,graphOptions)
|
||||
|
||||
})
|
||||
|
||||
return
|
||||
|
||||
},
|
||||
saveField(fieldId, value, optionalTimeout){
|
||||
|
||||
// Dont save value if it hasn't changed
|
||||
@@ -1472,8 +1422,6 @@
|
||||
this.cycleData[this.calendar.dateCode] = cleanDayData
|
||||
}
|
||||
|
||||
this.graphCurrentData()
|
||||
|
||||
this.saveCycleData()
|
||||
|
||||
},
|
||||
@@ -1499,6 +1447,7 @@
|
||||
axios.post('/api/metric-tracking/get')
|
||||
.then(({ data }) => {
|
||||
|
||||
this.loading = false
|
||||
this.setApplicationStateJson(data)
|
||||
|
||||
})
|
||||
@@ -1532,27 +1481,49 @@
|
||||
this.cycleData = json?.cycleData || this.cycleData
|
||||
this.fields = [...new Set(json?.fields)] || this.fields
|
||||
this.userFields = json?.userFields || this.userFields
|
||||
// this.graphs = json?.graphs || this.graphs
|
||||
|
||||
// console.log(this.fields)
|
||||
this.graphs = json?.graphs || this.graphs
|
||||
|
||||
this.$nextTick(() => {
|
||||
|
||||
this.getApplicationStateJson()
|
||||
|
||||
this.totalEntries = Object.keys(this.cycleData).length
|
||||
this.setupFields()
|
||||
this.openDayData(this.calendar.dateCode)
|
||||
|
||||
this.graphCurrentData()
|
||||
|
||||
this.generateTonsOfRandomData()
|
||||
|
||||
})
|
||||
},
|
||||
getApplicationStateJson(){
|
||||
|
||||
// convert date code into sortable int
|
||||
const sortableDate = (code) => {
|
||||
code = code
|
||||
.split('.')
|
||||
.reverse()
|
||||
.map(i => String(i).padStart(2, '0'))
|
||||
.join('')
|
||||
return parseInt(code)
|
||||
}
|
||||
|
||||
// Sort cycle data, newest first
|
||||
let sortedData = Object.keys(this.cycleData)
|
||||
.sort((a,b) => {
|
||||
return sortableDate(b) - sortableDate(a)
|
||||
})
|
||||
|
||||
// setup new object with sorted data
|
||||
let sortedCycleData = sortedData.reduce((result, key) => {
|
||||
result[key] = this.cycleData[key]
|
||||
return result
|
||||
},{})
|
||||
|
||||
return JSON.stringify({
|
||||
fields: this.fields,
|
||||
cycleData: this.cycleData,
|
||||
cycleData: sortedCycleData,
|
||||
userFields: this.userFields,
|
||||
// graphs: this.graphs,
|
||||
graphs: this.graphs,
|
||||
})
|
||||
},
|
||||
saveCycleData(){
|
||||
@@ -1624,6 +1595,7 @@
|
||||
},
|
||||
setupCalendar(date){
|
||||
|
||||
// visualize each day change
|
||||
this.working = true
|
||||
setTimeout(() => {
|
||||
this.working = false
|
||||
@@ -1640,6 +1612,13 @@
|
||||
|
||||
this.calendar.dateCode = this.generateDateCode(date)
|
||||
|
||||
// calculate days ago since current date
|
||||
const now = new Date()
|
||||
const diffSeconds = Math.floor((now - date) / 1000) // subtract unix timestamps, convert MS to S
|
||||
const dayInterval = diffSeconds / 86400 // seconds in a day
|
||||
this.calendar.daysAgo = Math.floor(dayInterval)
|
||||
|
||||
|
||||
|
||||
// ------------
|
||||
// setup calendar display
|
||||
@@ -1656,6 +1635,7 @@
|
||||
const currentYear = date.getFullYear();
|
||||
const currentMonth = date.getMonth() + 1;
|
||||
this.calendar.monthName = date.toLocaleString("en-US", { month: "long" });
|
||||
this.calendar.dayName = date.toLocaleString("en-US", { weekday: "long" });
|
||||
this.calendar.year = currentYear
|
||||
const daysInCurrentMonth = getDaysInMonth(currentYear, currentMonth);
|
||||
|
||||
@@ -1704,7 +1684,6 @@
|
||||
workingDate.setDate(workingDate.getDate()-1)
|
||||
}
|
||||
|
||||
this.graphCurrentData(5000)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user