Merge branch 'master' of github.com:okfn/recline
This commit is contained in:
commit
722b7dcbf8
@ -14,6 +14,7 @@
|
||||
<link rel="stylesheet" href="{{page.root}}css/grid.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/slickgrid.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/graph.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/flot.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/transform.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/map.css">
|
||||
<link rel="stylesheet" href="{{page.root}}css/multiview.css">
|
||||
@ -27,6 +28,10 @@
|
||||
<script type="text/javascript" src="{{page.root}}vendor/mustache/0.5.0-dev/mustache.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}vendor/bootstrap/2.0.2/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}vendor/flotr2/flotr2.js"></script>
|
||||
<!--[if lte IE 8]>
|
||||
<script language="javascript" type="text/javascript" src="{{page.root}}vendor/flot/excanvas.min.js"></script>
|
||||
<![endif]-->
|
||||
<script type="text/javascript" src="{{page.root}}vendor/flot/jquery.flot.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}vendor/leaflet/0.4.4/leaflet.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}vendor/leaflet.markercluster/leaflet.markercluster.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}vendor/slickgrid/2.0.1/jquery-ui-1.8.16.custom.min.js"></script>
|
||||
@ -62,6 +67,7 @@
|
||||
<script type="text/javascript" src="{{page.root}}src/view.transform.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/data.transform.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/view.graph.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/view.flot.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/view.map.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/view.timeline.js"></script>
|
||||
<script type="text/javascript" src="{{page.root}}src/widget.pager.js"></script>
|
||||
|
||||
26
css/flot.css
Normal file
26
css/flot.css
Normal file
@ -0,0 +1,26 @@
|
||||
.recline-graph .graph {
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.recline-graph .legend table {
|
||||
width: auto;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.recline-graph .legend td {
|
||||
padding: 5px;
|
||||
line-height: 13px;
|
||||
}
|
||||
|
||||
.recline-graph .graph .alert {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
#recline-graph-tooltip {
|
||||
position: absolute;
|
||||
background-color: #FEE !important;
|
||||
color: #000000 !important;
|
||||
opacity: 0.8 !important;
|
||||
border: 1px solid #fdd !important;
|
||||
}
|
||||
3
dist/recline.js
vendored
3
dist/recline.js
vendored
@ -4986,6 +4986,8 @@ my.Pager = Backbone.View.extend({
|
||||
e.preventDefault();
|
||||
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
||||
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
||||
newFrom = Math.max(newFrom, 0);
|
||||
newSize = Math.max(newSize, 1);
|
||||
this.model.set({size: newSize, from: newFrom});
|
||||
},
|
||||
onPaginationUpdate: function(e) {
|
||||
@ -4997,6 +4999,7 @@ my.Pager = Backbone.View.extend({
|
||||
} else {
|
||||
newFrom = this.model.get('from') + this.model.get('size');
|
||||
}
|
||||
newFrom = Math.max(newFrom, 0);
|
||||
this.model.set({from: newFrom});
|
||||
},
|
||||
render: function() {
|
||||
|
||||
473
src/view.flot.js
Normal file
473
src/view.flot.js
Normal file
@ -0,0 +1,473 @@
|
||||
/*jshint multistr:true */
|
||||
|
||||
this.recline = this.recline || {};
|
||||
this.recline.View = this.recline.View || {};
|
||||
|
||||
(function($, my) {
|
||||
|
||||
// ## Graph view for a Dataset using Flot graphing library.
|
||||
//
|
||||
// Initialization arguments (in a hash in first parameter):
|
||||
//
|
||||
// * model: recline.Model.Dataset
|
||||
// * state: (optional) configuration hash of form:
|
||||
//
|
||||
// {
|
||||
// group: {column name for x-axis},
|
||||
// series: [{column name for series A}, {column name series B}, ... ],
|
||||
// graphType: 'line'
|
||||
// }
|
||||
//
|
||||
// NB: should *not* provide an el argument to the view but must let the view
|
||||
// generate the element itself (you can then append view.el to the DOM.
|
||||
my.Flot = Backbone.View.extend({
|
||||
template: ' \
|
||||
<div class="recline-graph"> \
|
||||
<div class="panel graph" style="display: block;"> \
|
||||
<div class="js-temp-notice alert alert-block"> \
|
||||
<h3 class="alert-heading">Hey there!</h3> \
|
||||
<p>There\'s no graph here yet because we don\'t know what fields you\'d like to see plotted.</p> \
|
||||
<p>Please tell us by <strong>using the menu on the right</strong> and a graph will automatically appear.</p> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
',
|
||||
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.graphColors = ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"];
|
||||
|
||||
this.el = $(this.el);
|
||||
_.bindAll(this, 'render', 'redraw', '_toolTip', '_xaxisLabel');
|
||||
this.needToRedraw = false;
|
||||
this.model.bind('change', this.render);
|
||||
this.model.fields.bind('reset', this.render);
|
||||
this.model.fields.bind('add', this.render);
|
||||
this.model.records.bind('add', this.redraw);
|
||||
this.model.records.bind('reset', this.redraw);
|
||||
var stateData = _.extend({
|
||||
group: null,
|
||||
// so that at least one series chooser box shows up
|
||||
series: [],
|
||||
graphType: 'lines-and-points'
|
||||
},
|
||||
options.state
|
||||
);
|
||||
this.state = new recline.Model.ObjectState(stateData);
|
||||
this.previousTooltipPoint = {x: null, y: null};
|
||||
this.editor = new my.FlotControls({
|
||||
model: this.model,
|
||||
state: this.state.toJSON()
|
||||
});
|
||||
this.editor.state.bind('change', function() {
|
||||
self.state.set(self.editor.state.toJSON());
|
||||
self.redraw();
|
||||
});
|
||||
this.elSidebar = this.editor.el;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
var tmplData = this.model.toTemplateJSON();
|
||||
var htmls = Mustache.render(this.template, tmplData);
|
||||
$(this.el).html(htmls);
|
||||
this.$graph = this.el.find('.panel.graph');
|
||||
this.$graph.on("plothover", this._toolTip);
|
||||
return this;
|
||||
},
|
||||
|
||||
redraw: function() {
|
||||
// There are issues generating a Flot graph if either:
|
||||
// * The relevant div that graph attaches to his hidden at the moment of creating the plot -- Flot will complain with
|
||||
// Uncaught Invalid dimensions for plot, width = 0, height = 0
|
||||
// * There is no data for the plot -- either same error or may have issues later with errors like 'non-existent node-value'
|
||||
var areWeVisible = !jQuery.expr.filters.hidden(this.el[0]);
|
||||
if ((!areWeVisible || this.model.records.length === 0)) {
|
||||
this.needToRedraw = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// check we have something to plot
|
||||
if (this.state.get('group') && this.state.get('series')) {
|
||||
// faff around with width because flot draws axes *outside* of the element
|
||||
// width which means graph can get push down as it hits element next to it
|
||||
this.$graph.width(this.el.width() - 240);
|
||||
var series = this.createSeries();
|
||||
var options = this.getGraphOptions(this.state.attributes.graphType, series[0].data.length);
|
||||
this.plot = $.plot(this.$graph, series, options);
|
||||
}
|
||||
},
|
||||
|
||||
show: function() {
|
||||
// because we cannot redraw when hidden we may need to when becoming visible
|
||||
if (this.needToRedraw) {
|
||||
this.redraw();
|
||||
}
|
||||
},
|
||||
|
||||
// infoboxes on mouse hover on points/bars etc
|
||||
_toolTip: function (event, pos, item) {
|
||||
if (item) {
|
||||
if (this.previousTooltipPoint.x !== item.dataIndex ||
|
||||
this.previousTooltipPoint.y !== item.seriesIndex) {
|
||||
this.previousTooltipPoint.x = item.dataIndex;
|
||||
this.previousTooltipPoint.y = item.seriesIndex;
|
||||
$("#recline-graph-tooltip").remove();
|
||||
|
||||
var x = item.datapoint[0].toFixed(2),
|
||||
y = item.datapoint[1].toFixed(2);
|
||||
|
||||
var content = _.template('<%= group %> = <%= x %>, <%= series %> = <%= y %>', {
|
||||
group: this.state.attributes.group,
|
||||
x: this._xaxisLabel(x),
|
||||
series: item.series.label,
|
||||
y: y
|
||||
});
|
||||
|
||||
// use a different tooltip location offset for bar charts
|
||||
var xLocation, yLocation;
|
||||
if (this.state.attributes.graphType === 'bars') {
|
||||
xLocation = item.pageX + 15;
|
||||
yLocation = item.pageY;
|
||||
} else {
|
||||
xLocation = item.pageX + 10;
|
||||
yLocation = item.pageY - 20;
|
||||
}
|
||||
|
||||
$('<div id="recline-graph-tooltip">' + content + '</div>').css({
|
||||
top: yLocation,
|
||||
left: xLocation
|
||||
}).appendTo("body").fadeIn(200);
|
||||
}
|
||||
} else {
|
||||
$("#recline-graph-tooltip").remove();
|
||||
this.previousTooltipPoint.x = null;
|
||||
this.previousTooltipPoint.y = null;
|
||||
}
|
||||
},
|
||||
|
||||
_xaxisLabel: function (x) {
|
||||
var xfield = this.model.fields.get(this.state.attributes.group);
|
||||
|
||||
// time series
|
||||
var xtype = xfield.get('type');
|
||||
var isDateTime = (xtype === 'date' || xtype === 'date-time' || xtype === 'time');
|
||||
|
||||
if (this.model.records.models[parseInt(x, 10)]) {
|
||||
x = this.model.records.models[parseInt(x, 10)].get(this.state.attributes.group);
|
||||
if (isDateTime) {
|
||||
x = new Date(x).toLocaleDateString();
|
||||
}
|
||||
} else if (isDateTime) {
|
||||
x = new Date(parseInt(x, 10)).toLocaleDateString();
|
||||
}
|
||||
|
||||
return x;
|
||||
},
|
||||
|
||||
// ### getGraphOptions
|
||||
//
|
||||
// Get options for Flot Graph
|
||||
//
|
||||
// needs to be function as can depend on state
|
||||
//
|
||||
// @param typeId graphType id (lines, lines-and-points etc)
|
||||
// @param numPoints the number of points that will be plotted
|
||||
getGraphOptions: function(typeId, numPoints) {
|
||||
var self = this;
|
||||
|
||||
var tickFormatter = function (x) {
|
||||
// convert x to a string and make sure that it is not too long or the
|
||||
// tick labels will overlap
|
||||
// TODO: find a more accurate way of calculating the size of tick labels
|
||||
var label = self._xaxisLabel(x);
|
||||
|
||||
if (typeof label !== 'string') {
|
||||
label = label.toString();
|
||||
}
|
||||
if (label.length > 8) {
|
||||
label = label.slice(0, 5) + "...";
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
var xaxis = {};
|
||||
xaxis.tickFormatter = tickFormatter;
|
||||
|
||||
// calculate the x-axis ticks
|
||||
//
|
||||
// the number of ticks should be a multiple of the number of points so that
|
||||
// each tick lines up with a point
|
||||
if (numPoints) {
|
||||
var ticks = [],
|
||||
maxTicks = 10,
|
||||
x = 1,
|
||||
i = 0;
|
||||
|
||||
while (x <= maxTicks) {
|
||||
if ((numPoints / x) <= maxTicks) {
|
||||
break;
|
||||
}
|
||||
x = x + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < numPoints; i = i + x) {
|
||||
ticks.push(i);
|
||||
}
|
||||
|
||||
xaxis.ticks = ticks;
|
||||
}
|
||||
|
||||
var yaxis = {};
|
||||
yaxis.autoscale = true;
|
||||
yaxis.autoscaleMargin = 0.02;
|
||||
|
||||
var legend = {};
|
||||
legend.position = 'ne';
|
||||
|
||||
var grid = {};
|
||||
grid.hoverable = true;
|
||||
grid.clickable = true;
|
||||
grid.borderColor = "#aaaaaa";
|
||||
grid.borderWidth = 1;
|
||||
|
||||
var optionsPerGraphType = {
|
||||
lines: {
|
||||
legend: legend,
|
||||
colors: this.graphColors,
|
||||
lines: { show: true },
|
||||
xaxis: xaxis,
|
||||
yaxis: yaxis,
|
||||
grid: grid
|
||||
},
|
||||
points: {
|
||||
legend: legend,
|
||||
colors: this.graphColors,
|
||||
points: { show: true, hitRadius: 5 },
|
||||
xaxis: xaxis,
|
||||
yaxis: yaxis,
|
||||
grid: grid
|
||||
},
|
||||
'lines-and-points': {
|
||||
legend: legend,
|
||||
colors: this.graphColors,
|
||||
points: { show: true, hitRadius: 5 },
|
||||
lines: { show: true },
|
||||
xaxis: xaxis,
|
||||
yaxis: yaxis,
|
||||
grid: grid
|
||||
},
|
||||
bars: {
|
||||
legend: legend,
|
||||
colors: this.graphColors,
|
||||
lines: { show: false },
|
||||
xaxis: xaxis,
|
||||
yaxis: yaxis,
|
||||
bars: {
|
||||
show: true,
|
||||
horizontal: false,
|
||||
shadowSize: 0,
|
||||
align: 'center',
|
||||
barWidth: 0.8
|
||||
},
|
||||
grid: grid
|
||||
}
|
||||
};
|
||||
return optionsPerGraphType[typeId];
|
||||
},
|
||||
|
||||
createSeries: function() {
|
||||
var self = this;
|
||||
var series = [];
|
||||
_.each(this.state.attributes.series, function(field) {
|
||||
var points = [];
|
||||
_.each(self.model.records.models, function(doc, index) {
|
||||
var xfield = self.model.fields.get(self.state.attributes.group);
|
||||
var x = doc.getFieldValue(xfield);
|
||||
|
||||
// time series
|
||||
var xtype = xfield.get('type');
|
||||
var isDateTime = (xtype === 'date' || xtype === 'date-time' || xtype === 'time');
|
||||
|
||||
if (isDateTime) {
|
||||
// datetime
|
||||
if (self.state.attributes.graphType != 'bars') {
|
||||
x = new Date(x).getTime();
|
||||
} else {
|
||||
x = index;
|
||||
}
|
||||
} else if (typeof x === 'string') {
|
||||
x = index;
|
||||
}
|
||||
|
||||
var yfield = self.model.fields.get(field);
|
||||
var y = doc.getFieldValue(yfield);
|
||||
|
||||
points.push([x, y]);
|
||||
});
|
||||
series.push({
|
||||
data: points,
|
||||
label: field,
|
||||
hoverable: true
|
||||
});
|
||||
});
|
||||
return series;
|
||||
}
|
||||
});
|
||||
|
||||
my.FlotControls = Backbone.View.extend({
|
||||
className: "editor",
|
||||
template: ' \
|
||||
<div class="editor"> \
|
||||
<form class="form-stacked"> \
|
||||
<div class="clearfix"> \
|
||||
<label>Graph Type</label> \
|
||||
<div class="input editor-type"> \
|
||||
<select> \
|
||||
<option value="lines-and-points">Lines and Points</option> \
|
||||
<option value="lines">Lines</option> \
|
||||
<option value="points">Points</option> \
|
||||
<option value="bars">Bars</option> \
|
||||
</select> \
|
||||
</div> \
|
||||
<label>X-Axis</label> \
|
||||
<div class="input editor-group"> \
|
||||
<select> \
|
||||
<option value="">Please choose ...</option> \
|
||||
{{#fields}} \
|
||||
<option value="{{id}}">{{label}}</option> \
|
||||
{{/fields}} \
|
||||
</select> \
|
||||
</div> \
|
||||
<div class="editor-series-group"> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class="editor-buttons"> \
|
||||
<button class="btn editor-add">Add Additional Y-Axis Plot</button> \
|
||||
</div> \
|
||||
<div class="editor-buttons editor-submit" comment="hidden temporarily" style="display: none;"> \
|
||||
<button class="editor-save">Save</button> \
|
||||
<input type="hidden" class="editor-id" value="chart-1" /> \
|
||||
</div> \
|
||||
</form> \
|
||||
</div> \
|
||||
',
|
||||
templateSeriesEditor: ' \
|
||||
<div class="editor-series js-series-{{seriesIndex}}"> \
|
||||
<label>Y-Axis (<span>{{seriesName}})</span> \
|
||||
[<a href="#remove" class="action-remove-series">Remove</a>] \
|
||||
</label> \
|
||||
<div class="input"> \
|
||||
<select> \
|
||||
{{#fields}} \
|
||||
<option value="{{id}}">{{label}}</option> \
|
||||
{{/fields}} \
|
||||
</select> \
|
||||
</div> \
|
||||
</div> \
|
||||
',
|
||||
events: {
|
||||
'change form select': 'onEditorSubmit',
|
||||
'click .editor-add': '_onAddSeries',
|
||||
'click .action-remove-series': 'removeSeries'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.el = $(this.el);
|
||||
_.bindAll(this, 'render');
|
||||
this.model.fields.bind('reset', this.render);
|
||||
this.model.fields.bind('add', this.render);
|
||||
this.state = new recline.Model.ObjectState(options.state);
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
var tmplData = this.model.toTemplateJSON();
|
||||
var htmls = Mustache.render(this.template, tmplData);
|
||||
this.el.html(htmls);
|
||||
|
||||
// set up editor from state
|
||||
if (this.state.get('graphType')) {
|
||||
this._selectOption('.editor-type', this.state.get('graphType'));
|
||||
}
|
||||
if (this.state.get('group')) {
|
||||
this._selectOption('.editor-group', this.state.get('group'));
|
||||
}
|
||||
// ensure at least one series box shows up
|
||||
var tmpSeries = [""];
|
||||
if (this.state.get('series').length > 0) {
|
||||
tmpSeries = this.state.get('series');
|
||||
}
|
||||
_.each(tmpSeries, function(series, idx) {
|
||||
self.addSeries(idx);
|
||||
self._selectOption('.editor-series.js-series-' + idx, series);
|
||||
});
|
||||
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) {
|
||||
var select = this.el.find('.editor-group select');
|
||||
var $editor = this;
|
||||
var $series = this.el.find('.editor-series select');
|
||||
var series = $series.map(function () {
|
||||
return $(this).val();
|
||||
});
|
||||
var updatedState = {
|
||||
series: $.makeArray(series),
|
||||
group: this.el.find('.editor-group select').val(),
|
||||
graphType: this.el.find('.editor-type select').val()
|
||||
};
|
||||
this.state.set(updatedState);
|
||||
},
|
||||
|
||||
// Public: Adds a new empty series select box to the editor.
|
||||
//
|
||||
// @param [int] idx index of this series in the list of series
|
||||
//
|
||||
// Returns itself.
|
||||
addSeries: function (idx) {
|
||||
var data = _.extend({
|
||||
seriesIndex: idx,
|
||||
seriesName: String.fromCharCode(idx + 64 + 1)
|
||||
}, this.model.toTemplateJSON());
|
||||
|
||||
var htmls = Mustache.render(this.templateSeriesEditor, data);
|
||||
this.el.find('.editor-series-group').append(htmls);
|
||||
return this;
|
||||
},
|
||||
|
||||
_onAddSeries: function(e) {
|
||||
e.preventDefault();
|
||||
this.addSeries(this.state.get('series').length);
|
||||
},
|
||||
|
||||
// Public: Removes a series list item from the editor.
|
||||
//
|
||||
// Also updates the labels of the remaining series elements.
|
||||
removeSeries: function (e) {
|
||||
e.preventDefault();
|
||||
var $el = $(e.target);
|
||||
$el.parent().parent().remove();
|
||||
this.onEditorSubmit();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, recline.View);
|
||||
|
||||
@ -32,6 +32,8 @@ my.Pager = Backbone.View.extend({
|
||||
e.preventDefault();
|
||||
var newFrom = parseInt(this.el.find('input[name="from"]').val());
|
||||
var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom;
|
||||
newFrom = Math.max(newFrom, 0);
|
||||
newSize = Math.max(newSize, 1);
|
||||
this.model.set({size: newSize, from: newFrom});
|
||||
},
|
||||
onPaginationUpdate: function(e) {
|
||||
@ -43,6 +45,7 @@ my.Pager = Backbone.View.extend({
|
||||
} else {
|
||||
newFrom = this.model.get('from') + this.model.get('size');
|
||||
}
|
||||
newFrom = Math.max(newFrom, 0);
|
||||
this.model.set({from: newFrom});
|
||||
},
|
||||
render: function() {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<link rel="stylesheet" href="qunit/qunit.css" type="text/css" media="screen" />
|
||||
<!-- need this stylesheet because flot will complain if canvas does not have a height -->
|
||||
<link rel="stylesheet" href="../css/graph.css" type="text/css" media="screen" />
|
||||
<link rel="stylesheet" href="../css/flot.css" type="text/css" media="screen" />
|
||||
|
||||
<script type="text/javascript" src="../vendor/jquery/1.7.1/jquery.js"></script>
|
||||
<script type="text/javascript" src="../vendor/underscore/1.4.2/underscore.js"></script>
|
||||
|
||||
@ -55,6 +55,7 @@
|
||||
<script type="text/javascript" src="../src/view.slickgrid.js"></script>
|
||||
<script type="text/javascript" src="../src/view.transform.js"></script>
|
||||
<script type="text/javascript" src="../src/view.graph.js"></script>
|
||||
<script type="text/javascript" src="../src/view.flot.js"></script>
|
||||
<script type="text/javascript" src="../src/view.map.js"></script>
|
||||
<script type="text/javascript" src="../src/view.timeline.js"></script>
|
||||
<script type="text/javascript" src="../src/widget.pager.js"></script>
|
||||
@ -66,6 +67,7 @@
|
||||
<script type="text/javascript" src="view.grid.test.js"></script>
|
||||
<script type="text/javascript" src="view.slickgrid.test.js"></script>
|
||||
<script type="text/javascript" src="view.graph.test.js"></script>
|
||||
<script type="text/javascript" src="view.flot.test.js"></script>
|
||||
<script type="text/javascript" src="view.map.test.js"></script>
|
||||
<script type="text/javascript" src="view.timeline.test.js"></script>
|
||||
<script type="text/javascript" src="view.multiview.test.js"></script>
|
||||
|
||||
71
test/view.flot.test.js
Normal file
71
test/view.flot.test.js
Normal file
@ -0,0 +1,71 @@
|
||||
module("View - Flot");
|
||||
|
||||
test('basics', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.Flot({
|
||||
model: dataset
|
||||
});
|
||||
$('.fixtures').append(view.el);
|
||||
equal(view.state.get('graphType'), 'lines-and-points');
|
||||
// view will auto render ...
|
||||
assertPresent('.editor', view.elSidebar);
|
||||
view.remove();
|
||||
});
|
||||
|
||||
test('initialize', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.Flot({
|
||||
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.elSidebar.find('.editor-type select').val(), 'lines');
|
||||
equal(view.elSidebar.find('.editor-group select').val(), 'x');
|
||||
var out = _.map(view.elSidebar.find('.editor-series select'), function($el) {
|
||||
return $($el).val();
|
||||
});
|
||||
deepEqual(out, ['y', 'z']);
|
||||
|
||||
view.remove();
|
||||
});
|
||||
|
||||
test('dates in graph view', function () {
|
||||
expect(0);
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.Flot({
|
||||
model: dataset,
|
||||
state: {
|
||||
'graphType': 'lines',
|
||||
'group': 'date',
|
||||
'series': ['y', 'z']
|
||||
}
|
||||
});
|
||||
$('.fixtures').append(view.el);
|
||||
|
||||
view.remove();
|
||||
});
|
||||
|
||||
test('FlotControls basics', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.FlotControls({
|
||||
model: dataset,
|
||||
state: {
|
||||
graphType: 'bars',
|
||||
series: []
|
||||
}
|
||||
});
|
||||
$('.fixtures').append(view.el);
|
||||
equal(view.state.get('graphType'), 'bars');
|
||||
// view will auto render ...
|
||||
assertPresent('.editor', view.el);
|
||||
view.remove();
|
||||
});
|
||||
|
||||
1428
vendor/flot/excanvas.js
vendored
Normal file
1428
vendor/flot/excanvas.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
vendor/flot/excanvas.min.js
vendored
Normal file
1
vendor/flot/excanvas.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2664
vendor/flot/jquery.flot.js
vendored
Normal file
2664
vendor/flot/jquery.flot.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user