[#85,view-graph][m]: graph controls are now correctly configure themselves from loaded state.
* Also heavily refactor to have a cleaner and better code e.g. using templating to add new series.
This commit is contained in:
@@ -30,7 +30,11 @@ var ExplorerApp = Backbone.View.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dataset = null;
|
var dataset = null;
|
||||||
if (state.dataset || state.url) {
|
if (
|
||||||
|
(state.dataset || state.url) &&
|
||||||
|
// special cases for demo / memory dataset
|
||||||
|
!(state.url === 'demo' || state.backend === 'memory'))
|
||||||
|
{
|
||||||
dataset = recline.Model.Dataset.restore(state);
|
dataset = recline.Model.Dataset.restore(state);
|
||||||
} else {
|
} else {
|
||||||
dataset = localDataset();
|
dataset = localDataset();
|
||||||
|
|||||||
@@ -48,22 +48,13 @@ my.Graph = Backbone.View.extend({
|
|||||||
<label>Group Column (x-axis)</label> \
|
<label>Group Column (x-axis)</label> \
|
||||||
<div class="input editor-group"> \
|
<div class="input editor-group"> \
|
||||||
<select> \
|
<select> \
|
||||||
|
<option value="">Please choose ...</option> \
|
||||||
{{#fields}} \
|
{{#fields}} \
|
||||||
<option value="{{id}}">{{label}}</option> \
|
<option value="{{id}}">{{label}}</option> \
|
||||||
{{/fields}} \
|
{{/fields}} \
|
||||||
</select> \
|
</select> \
|
||||||
</div> \
|
</div> \
|
||||||
<div class="editor-series-group"> \
|
<div class="editor-series-group"> \
|
||||||
<div class="editor-series"> \
|
|
||||||
<label>Series <span>A (y-axis)</span></label> \
|
|
||||||
<div class="input"> \
|
|
||||||
<select> \
|
|
||||||
{{#fields}} \
|
|
||||||
<option value="{{id}}">{{label}}</option> \
|
|
||||||
{{/fields}} \
|
|
||||||
</select> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
</div> \
|
||||||
</div> \
|
</div> \
|
||||||
<div class="editor-buttons"> \
|
<div class="editor-buttons"> \
|
||||||
@@ -78,10 +69,25 @@ my.Graph = Backbone.View.extend({
|
|||||||
<div class="panel graph"></div> \
|
<div class="panel graph"></div> \
|
||||||
</div> \
|
</div> \
|
||||||
',
|
',
|
||||||
|
templateSeriesEditor: ' \
|
||||||
|
<div class="editor-series js-series-{{seriesIndex}}"> \
|
||||||
|
<label>Series <span>{{seriesName}} (y-axis)</span> \
|
||||||
|
[<a href="#remove" class="action-remove-series">Remove</a>] \
|
||||||
|
</label> \
|
||||||
|
<div class="input"> \
|
||||||
|
<select> \
|
||||||
|
<option value="">Please choose ...</option> \
|
||||||
|
{{#fields}} \
|
||||||
|
<option value="{{id}}">{{label}}</option> \
|
||||||
|
{{/fields}} \
|
||||||
|
</select> \
|
||||||
|
</div> \
|
||||||
|
</div> \
|
||||||
|
',
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'change form select': 'onEditorSubmit',
|
'change form select': 'onEditorSubmit',
|
||||||
'click .editor-add': 'addSeries',
|
'click .editor-add': '_onAddSeries',
|
||||||
'click .action-remove-series': 'removeSeries',
|
'click .action-remove-series': 'removeSeries',
|
||||||
'click .action-toggle-help': 'toggleHelp'
|
'click .action-toggle-help': 'toggleHelp'
|
||||||
},
|
},
|
||||||
@@ -98,7 +104,8 @@ my.Graph = Backbone.View.extend({
|
|||||||
this.model.currentDocuments.bind('reset', this.redraw);
|
this.model.currentDocuments.bind('reset', this.redraw);
|
||||||
var stateData = _.extend({
|
var stateData = _.extend({
|
||||||
group: null,
|
group: null,
|
||||||
series: [],
|
// so that at least one series chooser box shows up
|
||||||
|
series: [""],
|
||||||
graphType: 'lines-and-points'
|
graphType: 'lines-and-points'
|
||||||
},
|
},
|
||||||
options.state
|
options.state
|
||||||
@@ -108,21 +115,45 @@ my.Graph = Backbone.View.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
htmls = $.mustache(this.template, this.model.toTemplateJSON());
|
var self = this;
|
||||||
|
var tmplData = this.model.toTemplateJSON();
|
||||||
|
var htmls = $.mustache(this.template, tmplData);
|
||||||
$(this.el).html(htmls);
|
$(this.el).html(htmls);
|
||||||
// now set a load of stuff up
|
|
||||||
this.$graph = this.el.find('.panel.graph');
|
this.$graph = this.el.find('.panel.graph');
|
||||||
// for use later when adding additional series
|
|
||||||
// could be simpler just to have a common template!
|
// set up editor from state
|
||||||
this.$seriesClone = this.el.find('.editor-series').clone();
|
if (this.state.get('graphType')) {
|
||||||
this._updateSeries();
|
this._selectOption('.editor-type', this.state.get('graphType'));
|
||||||
|
}
|
||||||
|
if (this.state.get('group')) {
|
||||||
|
this._selectOption('.editor-group', this.state.get('group'));
|
||||||
|
}
|
||||||
|
_.each(this.state.get('series'), function(series, idx) {
|
||||||
|
self.addSeries(idx);
|
||||||
|
self._selectOption('.editor-series.js-series-' + idx, series);
|
||||||
|
});
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Private: Helper function to select an option from a select list
|
||||||
|
//
|
||||||
|
_selectOption: function(id,value){
|
||||||
|
var options = this.el.find(id + ' select > option');
|
||||||
|
if (options) {
|
||||||
|
options.each(function(opt){
|
||||||
|
if (this.value == value) {
|
||||||
|
$(this).attr('selected','selected');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onEditorSubmit: function(e) {
|
onEditorSubmit: function(e) {
|
||||||
var select = this.el.find('.editor-group select');
|
var select = this.el.find('.editor-group select');
|
||||||
$editor = this;
|
var $editor = this;
|
||||||
var series = this.$series.map(function () {
|
var $series = this.el.find('.editor-series select');
|
||||||
|
var series = $series.map(function () {
|
||||||
return $(this).val();
|
return $(this).val();
|
||||||
});
|
});
|
||||||
var updatedState = {
|
var updatedState = {
|
||||||
@@ -297,23 +328,25 @@ my.Graph = Backbone.View.extend({
|
|||||||
|
|
||||||
// Public: Adds a new empty series select box to the editor.
|
// Public: Adds a new empty series select box to the editor.
|
||||||
//
|
//
|
||||||
// All but the first select box will have a remove button that allows them
|
// @param [int] idx index of this series in the list of series
|
||||||
// to be removed.
|
|
||||||
//
|
//
|
||||||
// Returns itself.
|
// Returns itself.
|
||||||
addSeries: function (e) {
|
addSeries: function (idx) {
|
||||||
e.preventDefault();
|
var data = _.extend({
|
||||||
var element = this.$seriesClone.clone(),
|
seriesIndex: idx,
|
||||||
label = element.find('label'),
|
seriesName: String.fromCharCode(idx + 64 + 1),
|
||||||
index = this.$series.length;
|
}, this.model.toTemplateJSON());
|
||||||
|
|
||||||
this.el.find('.editor-series-group').append(element);
|
var htmls = $.mustache(this.templateSeriesEditor, data);
|
||||||
this._updateSeries();
|
this.el.find('.editor-series-group').append(htmls);
|
||||||
label.append(' [<a href="#remove" class="action-remove-series">Remove</a>]');
|
|
||||||
label.find('span').text(String.fromCharCode(this.$series.length + 64));
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onAddSeries: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.addSeries(this.state.get('series').length);
|
||||||
|
},
|
||||||
|
|
||||||
// Public: Removes a series list item from the editor.
|
// Public: Removes a series list item from the editor.
|
||||||
//
|
//
|
||||||
// Also updates the labels of the remaining series elements.
|
// Also updates the labels of the remaining series elements.
|
||||||
@@ -321,26 +354,12 @@ my.Graph = Backbone.View.extend({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var $el = $(e.target);
|
var $el = $(e.target);
|
||||||
$el.parent().parent().remove();
|
$el.parent().parent().remove();
|
||||||
this._updateSeries();
|
|
||||||
this.$series.each(function (index) {
|
|
||||||
if (index > 0) {
|
|
||||||
var labelSpan = $(this).prev().find('span');
|
|
||||||
labelSpan.text(String.fromCharCode(index + 65));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.onEditorSubmit();
|
this.onEditorSubmit();
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleHelp: function() {
|
toggleHelp: function() {
|
||||||
this.el.find('.editor-info').toggleClass('editor-hide-info');
|
this.el.find('.editor-info').toggleClass('editor-hide-info');
|
||||||
},
|
},
|
||||||
|
|
||||||
// Private: Resets the series property to reference the select elements.
|
|
||||||
//
|
|
||||||
// Returns itself.
|
|
||||||
_updateSeries: function () {
|
|
||||||
this.$series = this.el.find('.editor-series select');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})(jQuery, recline.View);
|
})(jQuery, recline.View);
|
||||||
|
|||||||
@@ -11,3 +11,28 @@ test('basics', function () {
|
|||||||
assertPresent('.editor', view.el);
|
assertPresent('.editor', view.el);
|
||||||
view.remove();
|
view.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('initialize', function () {
|
||||||
|
var dataset = Fixture.getDataset();
|
||||||
|
var view = new recline.View.Graph({
|
||||||
|
model: dataset,
|
||||||
|
state: {
|
||||||
|
'graphType': 'lines',
|
||||||
|
'group': 'x',
|
||||||
|
'series': ['y', 'z']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.fixtures').append(view.el);
|
||||||
|
equal(view.state.get('graphType'), 'lines');
|
||||||
|
deepEqual(view.state.get('series'), ['y', 'z']);
|
||||||
|
|
||||||
|
// check we have updated editor with state info
|
||||||
|
equal(view.el.find('.editor-type select').val(), 'lines');
|
||||||
|
equal(view.el.find('.editor-group select').val(), 'x');
|
||||||
|
var out = _.map(view.el.find('.editor-series select'), function($el) {
|
||||||
|
return $($el).val();
|
||||||
|
});
|
||||||
|
deepEqual(out, ['y', 'z']);
|
||||||
|
|
||||||
|
// view.remove();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user