[#88,refactor/state,api-change][m]: FlotGraph now uses state plus DataExplorer takes care of parsing state from Hash.
* First test for FlotGraph view (#45) * Move convenience functions for testing present of elements to test/base.js from view-grid.test.js
This commit is contained in:
@@ -7,10 +7,10 @@ this.recline.View = this.recline.View || {};
|
|||||||
|
|
||||||
// ## Graph view for a Dataset using Flot graphing library.
|
// ## Graph view for a Dataset using Flot graphing library.
|
||||||
//
|
//
|
||||||
// Initialization arguments:
|
// Initialization arguments (in a hash in first parameter):
|
||||||
//
|
//
|
||||||
// * model: recline.Model.Dataset
|
// * model: recline.Model.Dataset
|
||||||
// * config: (optional) graph configuration hash of form:
|
// * state: (optional) configuration hash of form:
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// group: {column name for x-axis},
|
// group: {column name for x-axis},
|
||||||
@@ -86,7 +86,7 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
'click .action-toggle-help': 'toggleHelp'
|
'click .action-toggle-help': 'toggleHelp'
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function(options, config) {
|
initialize: function(options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.el = $(this.el);
|
this.el = $(this.el);
|
||||||
_.bindAll(this, 'render', 'redraw');
|
_.bindAll(this, 'render', 'redraw');
|
||||||
@@ -96,18 +96,14 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
this.model.fields.bind('add', this.render);
|
this.model.fields.bind('add', this.render);
|
||||||
this.model.currentDocuments.bind('add', this.redraw);
|
this.model.currentDocuments.bind('add', this.redraw);
|
||||||
this.model.currentDocuments.bind('reset', this.redraw);
|
this.model.currentDocuments.bind('reset', this.redraw);
|
||||||
var configFromHash = my.parseHashQueryString().graph;
|
var stateData = _.extend({
|
||||||
if (configFromHash) {
|
|
||||||
configFromHash = JSON.parse(configFromHash);
|
|
||||||
}
|
|
||||||
this.chartConfig = _.extend({
|
|
||||||
group: null,
|
group: null,
|
||||||
series: [],
|
series: [],
|
||||||
graphType: 'lines-and-points'
|
graphType: 'lines-and-points'
|
||||||
},
|
},
|
||||||
configFromHash,
|
options.state
|
||||||
config
|
);
|
||||||
);
|
this.state = new recline.Model.ObjectState(stateData);
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -129,13 +125,12 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
var series = this.$series.map(function () {
|
var series = this.$series.map(function () {
|
||||||
return $(this).val();
|
return $(this).val();
|
||||||
});
|
});
|
||||||
this.chartConfig.series = $.makeArray(series);
|
var updatedState = {
|
||||||
this.chartConfig.group = this.el.find('.editor-group select').val();
|
series: $.makeArray(series),
|
||||||
this.chartConfig.graphType = this.el.find('.editor-type select').val();
|
group: this.el.find('.editor-group select').val(),
|
||||||
// update navigation
|
graphType: this.el.find('.editor-type select').val()
|
||||||
var qs = my.parseHashQueryString();
|
};
|
||||||
qs.graph = JSON.stringify(this.chartConfig);
|
this.state.set(updatedState);
|
||||||
my.setHashQueryString(qs);
|
|
||||||
this.redraw();
|
this.redraw();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -151,7 +146,7 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var series = this.createSeries();
|
var series = this.createSeries();
|
||||||
var options = this.getGraphOptions(this.chartConfig.graphType);
|
var options = this.getGraphOptions(this.state.attributes.graphType);
|
||||||
this.plot = $.plot(this.$graph, series, options);
|
this.plot = $.plot(this.$graph, series, options);
|
||||||
this.setupTooltips();
|
this.setupTooltips();
|
||||||
// create this.plot and cache it
|
// create this.plot and cache it
|
||||||
@@ -172,7 +167,7 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
// special tickformatter to show labels rather than numbers
|
// special tickformatter to show labels rather than numbers
|
||||||
var tickFormatter = function (val) {
|
var tickFormatter = function (val) {
|
||||||
if (self.model.currentDocuments.models[val]) {
|
if (self.model.currentDocuments.models[val]) {
|
||||||
var out = self.model.currentDocuments.models[val].get(self.chartConfig.group);
|
var out = self.model.currentDocuments.models[val].get(self.state.attributes.group);
|
||||||
// if the value was in fact a number we want that not the
|
// if the value was in fact a number we want that not the
|
||||||
if (typeof(out) == 'number') {
|
if (typeof(out) == 'number') {
|
||||||
return val;
|
return val;
|
||||||
@@ -255,14 +250,14 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
var y = item.datapoint[1];
|
var y = item.datapoint[1];
|
||||||
// convert back from 'index' value on x-axis (e.g. in cases where non-number values)
|
// convert back from 'index' value on x-axis (e.g. in cases where non-number values)
|
||||||
if (self.model.currentDocuments.models[x]) {
|
if (self.model.currentDocuments.models[x]) {
|
||||||
x = self.model.currentDocuments.models[x].get(self.chartConfig.group);
|
x = self.model.currentDocuments.models[x].get(self.state.attributes.group);
|
||||||
} else {
|
} else {
|
||||||
x = x.toFixed(2);
|
x = x.toFixed(2);
|
||||||
}
|
}
|
||||||
y = y.toFixed(2);
|
y = y.toFixed(2);
|
||||||
|
|
||||||
var content = _.template('<%= group %> = <%= x %>, <%= series %> = <%= y %>', {
|
var content = _.template('<%= group %> = <%= x %>, <%= series %> = <%= y %>', {
|
||||||
group: self.chartConfig.group,
|
group: self.state.attributes.group,
|
||||||
x: x,
|
x: x,
|
||||||
series: item.series.label,
|
series: item.series.label,
|
||||||
y: y
|
y: y
|
||||||
@@ -280,25 +275,23 @@ my.FlotGraph = Backbone.View.extend({
|
|||||||
createSeries: function () {
|
createSeries: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var series = [];
|
var series = [];
|
||||||
if (this.chartConfig) {
|
$.each(this.state.attributes.series, function (seriesIndex, field) {
|
||||||
$.each(this.chartConfig.series, function (seriesIndex, field) {
|
var points = [];
|
||||||
var points = [];
|
$.each(self.model.currentDocuments.models, function (index, doc) {
|
||||||
$.each(self.model.currentDocuments.models, function (index, doc) {
|
var x = doc.get(self.state.attributes.group);
|
||||||
var x = doc.get(self.chartConfig.group);
|
var y = doc.get(field);
|
||||||
var y = doc.get(field);
|
if (typeof x === 'string') {
|
||||||
if (typeof x === 'string') {
|
x = index;
|
||||||
x = index;
|
}
|
||||||
}
|
// horizontal bar chart
|
||||||
// horizontal bar chart
|
if (self.state.attributes.graphType == 'bars') {
|
||||||
if (self.chartConfig.graphType == 'bars') {
|
points.push([y, x]);
|
||||||
points.push([y, x]);
|
} else {
|
||||||
} else {
|
points.push([x, y]);
|
||||||
points.push([x, y]);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
series.push({data: points, label: field});
|
|
||||||
});
|
});
|
||||||
}
|
series.push({data: points, label: field});
|
||||||
|
});
|
||||||
return series;
|
return series;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
25
src/view.js
25
src/view.js
@@ -155,11 +155,7 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
// note this.model and dataset returned are the same
|
// note this.model and dataset returned are the same
|
||||||
this.model.fetch()
|
this.model.fetch()
|
||||||
.done(function(dataset) {
|
.done(function(dataset) {
|
||||||
var queryState = my.parseHashQueryString().reclineQuery;
|
self.model.query(self.state.get('query'));
|
||||||
if (queryState) {
|
|
||||||
queryState = JSON.parse(queryState);
|
|
||||||
}
|
|
||||||
self.model.query(queryState);
|
|
||||||
})
|
})
|
||||||
.fail(function(error) {
|
.fail(function(error) {
|
||||||
my.notify(error.message, {category: 'error', persist: true});
|
my.notify(error.message, {category: 'error', persist: true});
|
||||||
@@ -238,16 +234,33 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
|
|
||||||
_setupState: function(initialState) {
|
_setupState: function(initialState) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var qs = my.parseHashQueryString();
|
||||||
|
var query = qs.reclineQuery;
|
||||||
|
query = query ? JSON.parse(query) : self.model.queryState.toJSON();
|
||||||
|
// backwards compatability (now named view-graph but was named graph)
|
||||||
|
var graphState = qs['view-graph'] || qs.graph;
|
||||||
|
graphState = graphState ? JSON.parse(graphState) : {};
|
||||||
var stateData = _.extend({
|
var stateData = _.extend({
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
query: self.model.queryState.toJSON(),
|
query: query,
|
||||||
|
'view-graph': graphState,
|
||||||
currentView: null
|
currentView: null
|
||||||
},
|
},
|
||||||
initialState);
|
initialState);
|
||||||
this.state.set(stateData);
|
this.state.set(stateData);
|
||||||
|
|
||||||
|
// now do updates based on state
|
||||||
if (this.state.get('readOnly')) {
|
if (this.state.get('readOnly')) {
|
||||||
this.setReadOnly();
|
this.setReadOnly();
|
||||||
}
|
}
|
||||||
|
_.each(this.pageViews, function(pageView) {
|
||||||
|
var viewId = 'view-' + pageView.id;
|
||||||
|
if (viewId in self.state.attributes) {
|
||||||
|
pageView.view.state.set(self.state.get(viewId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// bind for changes state in associated objects
|
||||||
this.model.queryState.bind('change', function() {
|
this.model.queryState.bind('change', function() {
|
||||||
self.state.set({queryState: self.model.queryState.toJSON()});
|
self.state.set({queryState: self.model.queryState.toJSON()});
|
||||||
});
|
});
|
||||||
|
|||||||
11
test/base.js
11
test/base.js
@@ -14,3 +14,14 @@ var Fixture = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function assertPresent(selector, el) {
|
||||||
|
var found = el ? $(el).find(selector) : $(selector);
|
||||||
|
ok(found.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertNotPresent(selector, el) {
|
||||||
|
var found = el ? $(el).find(selector) : $(selector);
|
||||||
|
ok(found.length > 0);
|
||||||
|
equal(found.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,9 @@
|
|||||||
<script type="text/javascript" src="../src/view.js"></script>
|
<script type="text/javascript" src="../src/view.js"></script>
|
||||||
<script type="text/javascript" src="../src/view-grid.js"></script>
|
<script type="text/javascript" src="../src/view-grid.js"></script>
|
||||||
<script type="text/javascript" src="../src/view-transform-dialog.js"></script>
|
<script type="text/javascript" src="../src/view-transform-dialog.js"></script>
|
||||||
|
<script type="text/javascript" src="../src/view-flot-graph.js"></script>
|
||||||
<script type="text/javascript" src="view-grid.test.js"></script>
|
<script type="text/javascript" src="view-grid.test.js"></script>
|
||||||
|
<script type="text/javascript" src="view-graph.test.js"></script>
|
||||||
<script type="text/javascript" src="view.test.js"></script>
|
<script type="text/javascript" src="view.test.js"></script>
|
||||||
<script type="text/javascript" src="util.test.js"></script>
|
<script type="text/javascript" src="util.test.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
13
test/view-graph.test.js
Normal file
13
test/view-graph.test.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module("View - FlotGraph");
|
||||||
|
|
||||||
|
test('basics', function () {
|
||||||
|
var dataset = Fixture.getDataset();
|
||||||
|
var view = new recline.View.FlotGraph({
|
||||||
|
model: dataset
|
||||||
|
});
|
||||||
|
$('.fixtures').append(view.el);
|
||||||
|
equal(view.state.get('graphType'), 'lines-and-points');
|
||||||
|
// view will auto render ...
|
||||||
|
assertPresent('.editor', view.el);
|
||||||
|
view.remove();
|
||||||
|
});
|
||||||
@@ -2,16 +2,6 @@
|
|||||||
|
|
||||||
module("View - DataGrid");
|
module("View - DataGrid");
|
||||||
|
|
||||||
function assertPresent(selector) {
|
|
||||||
var found = $(selector);
|
|
||||||
ok(found.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertNotPresent(selector) {
|
|
||||||
var found = $(selector);
|
|
||||||
equal(found.length, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('menu - hideColumn', function () {
|
test('menu - hideColumn', function () {
|
||||||
var dataset = Fixture.getDataset();
|
var dataset = Fixture.getDataset();
|
||||||
var view = new recline.View.DataGrid({
|
var view = new recline.View.DataGrid({
|
||||||
|
|||||||
@@ -36,7 +36,10 @@ test('initialize state', function () {
|
|||||||
var explorer = new recline.View.DataExplorer({
|
var explorer = new recline.View.DataExplorer({
|
||||||
model: dataset,
|
model: dataset,
|
||||||
state: {
|
state: {
|
||||||
readOnly: true
|
readOnly: true,
|
||||||
|
'view-grid': {
|
||||||
|
hiddenFields: ['x']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var state = explorer.getState();
|
var state = explorer.getState();
|
||||||
|
|||||||
Reference in New Issue
Block a user