Skip to content

Commit

Permalink
feat(dash): Topsheet + Pie are more or less working
Browse files Browse the repository at this point in the history
  • Loading branch information
billyc committed Jul 16, 2021
1 parent abb58e9 commit 3698bc1
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 31 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SimWrapper",
"version": "3.0.0",
"name": "simwrapper",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
83 changes: 83 additions & 0 deletions src/cards/pie.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<template lang="pug">
vue-plotly(:data="data" :layout="layout" :options="options")

</template>

<script lang="ts">
import { Vue, Component, Watch, Prop } from 'vue-property-decorator'
import VuePlotly from '@statnett/vue-plotly'
import { FileSystemConfig } from '@/Globals'
import truncate from '@turf/truncate'
const mockData = {
car: 34,
bike: 18,
pt: 30,
walk: 8,
}
@Component({ components: { VuePlotly } })
export default class VueComponent extends Vue {
@Prop({ required: true }) fileSystemConfig!: FileSystemConfig
@Prop({ required: true }) subfolder!: string
@Prop({ required: true }) files!: string[]
@Prop({ required: true }) config!: any
private mounted() {
this.$emit('isLoaded')
}
private layout = {
height: 300,
// width: 500,
margin: { t: 30, b: 5, l: 0, r: 0 },
}
private data = [
{
// title: 'hello',
labels: Object.keys(mockData),
values: Object.values(mockData),
type: 'pie',
hole: 0.3,
textinfo: 'label+percent',
textposition: 'inside',
automargin: true,
},
]
private options = {
displaylogo: false,
responsive: true,
modeBarButtonsToRemove: [
'pan2d',
'zoom2d',
'select2d',
'lasso2d',
'zoomIn2d',
'zoomOut2d',
'autoScale2d',
'hoverClosestCartesian',
'hoverCompareCartesian',
'resetScale2d',
'toggleSpikelines',
'resetViewMapbox',
],
toImageButtonOptions: {
format: 'svg', // one of png, svg, jpeg, webp
filename: 'incidenceByAgeGroupOverTime',
width: 800,
height: 800,
scale: 1.0, // Multiply title/legend/axis/canvas sizes by this factor
},
}
}
</script>

<style scoped lang="scss">
@import '@/styles.scss';
@media only screen and (max-width: 640px) {
}
</style>
3 changes: 1 addition & 2 deletions src/components/BlankComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { Vue, Component, Watch, Prop } from 'vue-property-decorator'
@Component({ components: {}, props: {} })
export default class VueComponent extends Vue {
// @Prop({ required: true })
// private viz!: Viz
// @Prop({ required: true }) viz!: Viz
}
</script>

Expand Down
12 changes: 7 additions & 5 deletions src/components/TopSheet/TopSheet.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template lang="pug">
.topsheet.curate-content(v-if="table.length")
h3.curate-heading {{ title }}
.topsheet.curate-content
h3.curate-heading(v-if="title") {{ title }}

.output-table
.output-table(v-if="entries.length")
.row(v-for="row,i in entries" :key="'entry'+i")
.cell.top-label(:style="row.style") {{ row.title }}
input.input.is-small.cell.top-value(:style="row.style" v-model="row.value" @change="boxChanged")

.output-table(style="margin-top: 1rem")
.output-table(v-if="table.length" style="margin-top: 1rem")
.row(v-for="row,i in table" :key="'row'+i")
.cell.top-label(:style="row.style") {{ row.title }}
.cell.top-value(:style="row.style") {{ formattedValue(row.value) }}
Expand Down Expand Up @@ -43,14 +43,15 @@ export default class VueComponent extends Vue {
private table: TableRow[] = []
private entries: { key: string; title: string; value: any }[] = []
private title = 'Topsheet'
private title = ''
private formattedValue(value: any) {
if (!isNaN(value)) return value.toLocaleString([this.$store.state.locale, 'en'])
return value
}
private mounted() {
console.log('TOPSHEET YAML IS', this.yaml)
if (this.files.length) this.runTopSheet()
}
Expand Down Expand Up @@ -99,6 +100,7 @@ export default class VueComponent extends Vue {
this.table = []
// this.table = [{ title: message, value: '', style: { backgroundColor: 'yellow' } }]
}
this.$emit('isLoaded')
}
}
</script>
Expand Down
8 changes: 4 additions & 4 deletions src/components/TopSheet/TopSheetWorker.thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ expose({

getTitle(locale: string) {
console.log('getTitle locale', locale)
let title = 'Topsheet'
let title = ''

if (locale === 'en') title = _yaml.title_en || _yaml.title || _yaml.title_de || 'Topsheet'
else title = _yaml.title_de || _yaml.title || _yaml.title_en || 'Topsheet'
if (locale === 'en') title = _yaml.title_en || _yaml.title || _yaml.title_de || ''
else title = _yaml.title_de || _yaml.title || _yaml.title_en || ''

return title
},
Expand Down Expand Up @@ -282,7 +282,7 @@ function getFileVariableReplacements(expr: string) {
}

async function getYaml() {
const text = await _fileSystem.getFileText(_yamlFile)
const text = await _fileSystem.getFileText(_subfolder + '/' + _yamlFile)
const yaml = YAML.parse(text) as TopsheetYaml
return yaml
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/TopsheetsFinder/TopsheetsFinder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class VueComponent extends Vue {
// use local files in this folder instead of any we just found
const matches = micromatch(this.files, ['topsheet*.y?(a)ml'])
for (const match of matches) topsheets[match] = `${this.subfolder}/${match}`
for (const match of matches) topsheets[match] = `${match}`
return Object.values(topsheets)
}
Expand Down
109 changes: 92 additions & 17 deletions src/views/DashBoard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@
p {{ description }}

.dash-row(v-for="row,i in rows" :key="i")
.dash-card(v-for="card,j in row" :key="`${i}/${j}`" :id="card.id"

.dash-card-frame(v-for="card,j in row" :key="`${i}/${j}`"
:style="getCardStyle(card)")

h3 {{ card.title }}

.spinner-box(:id="card.id" v-if="getCardComponent(card)")
component.dash-card(
:is="getCardComponent(card)"
:fileSystemConfig="fileSystemConfig"
:subfolder="xsubfolder"
:files="fileList"
:yaml="card.props.configFile"
:config="card.props"
:style="{opacity: opacity[card.id]}"
@isLoaded="handleCardIsLoaded(card.id)"
)

</template>

<script lang="ts">
Expand All @@ -19,32 +32,60 @@ import YAML from 'yaml'
import HTTPFileSystem from '@/util/HTTPFileSystem'
import { FileSystem, FileSystemConfig } from '@/Globals'
import PieChart from '@/cards/pie.vue'
import TopSheet from '@/components/TopSheet/TopSheet.vue'
@Component({ components: {}, props: {} })
@Component({ components: { TopSheet, PieChart }, props: {} })
export default class VueComponent extends Vue {
@Prop({ required: true }) private root!: string
@Prop({ required: true }) private xsubfolder!: string
private fileSystemConfig!: FileSystemConfig
private fileApi!: HTTPFileSystem
private yaml: any
private title = ''
private description = ''
private rows: any[] = []
private mounted() {
this.fileApi = new HTTPFileSystem(this.getFileSystem(this.root))
private fileList: string[] = []
private async mounted() {
this.fileSystemConfig = this.getFileSystem(this.root)
this.fileApi = new HTTPFileSystem(this.fileSystemConfig)
this.fileList = await this.getFiles()
this.setupDashboard()
}
private async getFiles() {
console.log(1)
const folderContents = await this.fileApi.getDirectory(this.xsubfolder)
console.log(2)
// hide dot folders
const files = folderContents.files.filter(f => !f.startsWith('.')).sort()
return files
}
private getCardComponent(card: any) {
switch (card.card) {
case 'topsheet':
return 'TopSheet'
case 'pie':
return 'PieChart'
default:
return undefined
}
}
private getCardStyle(card: any) {
const hue = Math.floor(360 * Math.random())
const flex = card.width || 1
const height = card.height ? card.height * 60 : undefined
const style: any = {
backgroundColor: `hsl(${hue}, 60%, 80%)`,
margin: '0.5rem 0.5rem 0 0',
// backgroundColor: 'white', // `hsl'(${hue}, 80%, 80%)`,
margin: '2rem 2rem 0 0',
position: 'relative',
flex,
}
Expand All @@ -69,20 +110,23 @@ export default class VueComponent extends Vue {
const yaml = await this.fileApi.getFileText(`${this.xsubfolder}/dashboard.yaml`)
this.yaml = YAML.parse(yaml)
console.log(this.yaml)
// set header
this.title = this.yaml.header.title || 'Dashboard'
this.description = this.yaml.header.description || ''
// build rows
let numCard = 0
for (const rowId of Object.keys(this.yaml.cards)) {
const cards: any[] = this.yaml.cards[rowId]
for (const rowId of Object.keys(this.yaml.layout)) {
const cards: any[] = this.yaml.layout[rowId]
cards.forEach(card => {
card.id = `card-id-${numCard}`
// Vue is weird about new properties: use Vue.set() instead
// this.opacity[card.id] = 0.5
Vue.set(this.opacity, card.id, 0.2)
numCard++
})
Expand All @@ -96,13 +140,33 @@ export default class VueComponent extends Vue {
}
}
private spinners: any = {}
private opacity: any = {}
private initializeCard(card: any) {
console.log('initializing card:', card.type)
this.spinners[card.id] = new Spinner({
color: this.$store.state.isDarkMode ? '#6677ee' : '#551188', // 551188
lines: 10,
rotate: 18,
length: 4,
width: 3,
radius: 8,
})
const target = document.getElementById(card.id) as any
this.spinners[card.id].spin(target)
}
// let target = document.getElementById(card.id) as any
// new Spinner({ color: '#518', lines: 10, rotate: 18, length: 4, width: 3, radius: 8 }).spin(
// target
// )
private async handleCardIsLoaded(id: string) {
console.log('unspin', id)
await this.$nextTick()
this.opacity[id] = 1.0
const target = document.getElementById(id) as any
if (this.spinners[id]) {
this.spinners[id].stop()
delete this.spinners[id]
}
}
}
</script>
Expand All @@ -112,7 +176,8 @@ export default class VueComponent extends Vue {
@import '../../node_modules/spin.js/spin.css';
.dashboard {
padding: 1rem 0.5rem 1rem 1rem;
padding: 1rem 0rem 1rem 2rem;
background-color: var(--bgBold);
}
.header {
Expand All @@ -127,11 +192,21 @@ export default class VueComponent extends Vue {
flex-direction: row;
}
.dash-card {
.dash-card-frame {
display: flex;
flex-direction: column;
h3 {
border-top: 3px solid var(--splitPanel);
font-size: 1.3rem;
line-height: 1.5rem;
padding-top: 0.1rem;
margin-bottom: 0.5rem;
color: var(--link);
}
}
.dash-card {
transition: opacity 0.5s;
}
</style>

0 comments on commit 3698bc1

Please sign in to comment.