Skip to content

Commit

Permalink
✨ Merged heatmaps into timeline visualisation, added ability to filter
Browse files Browse the repository at this point in the history
all visualisations.

Closes #14, #13
  • Loading branch information
saul committed Feb 23, 2016
1 parent 9de7753 commit 5c05cb5
Show file tree
Hide file tree
Showing 14 changed files with 356 additions and 358 deletions.
8 changes: 2 additions & 6 deletions components/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,11 @@
</div>

<ul class="nav nav-tabs" role="tablist">
<li><a href="#heatmap" data-toggle="tab">Heatmap</a></li>
<li class="active"><a href="#timeline" data-toggle="tab">Timeline</a></li>
<li class="active"><a href="#timeline" data-toggle="tab">Visualisation</a></li>
</ul>

<div class="tab-content">
<div role="tabpanel" class="tab-pane" id="heatmap">
<gv-heatmap-visualisation></gv-heatmap-visualisation>
</div>

<!-- TODO: add tabbing -->
<div role="tabpanel" class="tab-pane active" id="timeline">
<gv-timeline-visualisation></gv-timeline-visualisation>
</div>
Expand Down
34 changes: 0 additions & 34 deletions components/Canvas.vue

This file was deleted.

89 changes: 89 additions & 0 deletions components/EventFilterList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<template>
<label>{{all.length | pluralize 'Filter'}} ({{all.length}})</label>

<div class="form-group-flex form-group" v-for="filter in all" track-by="id">
<select class="form-control width--auto" v-model="filter.target">
<option value="_event">Event</option>
<option v-for="entity in event.entities" :value="entity" :selected="$index == 0">
{{entity | capitalize}}
</option>
</select>

<input type="text" class="form-control" v-model="filter.prop">

<select class="form-control width--auto" v-model="filter.comparator">
<option v-for="comparator in comparators" :value="comparator" :selected="$index == 0">
{{{ comparator.text }}}
</option>
</select>

<input type="text" class="form-control" v-model="filter.value">

<button type="button" class="btn btn-danger" @click="remove($index)">
<span class="glyphicon glyphicon-minus-sign"></span>
</button>
</div>

<div class="form-group clearfix">
<button type="button" class="btn btn-default pull-right" @click="add">
<span class="glyphicon glyphicon-filter"></span>
</button>
</div>
</template>

<script type="text/babel">
export default {
props: {
event: {
required: true
}
},
data() {
return {
atomicId: 0,
all: [],
comparators: [
{text: '=', sql: '=', cast: 'text'},
{text: '&ne;', sql: '!=', cast: 'text'},
{text: '&lt;', sql: '<', cast: 'int'},
{text: '&le;', sql: '<=', cast: 'int'},
{text: '&gt;', sql: '>', cast: 'int'},
{text: '&ge;', sql: '>=', cast: 'int'}
]
}
},
methods: {
add() {
this.all.push({
id: this.atomicId++,
target: null,
prop: '',
comparator: null,
value: ''
});
},
remove(index) {
this.all.splice(index, 1);
},
sql() {
return this.all.map(filter => {
if (filter.target === '_event') {
return `AND (events.data->>${db.escape(filter.prop)})::${filter.comparator.cast} ${filter.comparator.sql} ${db.escape(filter.value)}`;
}
return `AND ((
SELECT entity_props.value
FROM entity_props
WHERE entity_props.index = (events.entities->>${db.escape(filter.target)})::int
AND entity_props.tick <= events.tick
AND entity_props.prop = ${db.escape(filter.prop)}
AND entity_props.session_id = events.session_id
ORDER BY entity_props.tick DESC
LIMIT 1
)->>'value')::${filter.comparator.cast} ${filter.comparator.sql} ${db.escape(filter.value)}`;
})
.join('\n');
}
}
}
</script>
47 changes: 47 additions & 0 deletions components/HeatmapGradientSelect.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div class="form-group">
<label>Colour gradient</label>

<select class="form-control" v-model="selected" :disabled="all.length == 0">
<option v-for="gradient in all" value="{{ gradient.path }}">
{{ gradient.baseName | capitalize }}
</option>
</select>
</div>
</template>

<script type="text/babel">
const assert = window.require('assert');
const fs = window.require('fs');
const path = window.require('path');
// path to the gradient textures directory
const GRADIENT_BASE = 'img/gradients';
export default {
props: {
selected: {
required: true,
twoWay: true,
}
},
data() {
return {
all: []
}
},
ready() {
fs.readdir(GRADIENT_BASE, (err, files) => {
assert.ifError(err);
this.all = files.filter(name => !name.startsWith('.'))
.map(file => {
return {
path: path.join(GRADIENT_BASE, file),
baseName: path.parse(file).name
}
});
});
}
}
</script>
Loading

0 comments on commit 5c05cb5

Please sign in to comment.