From 6ceff22b1519f948e2bb947cda9a7abe41e0bdb5 Mon Sep 17 00:00:00 2001 From: John Glover Date: Tue, 5 Feb 2013 16:37:02 +0100 Subject: [PATCH 01/19] Return to first page of records after filter update. Also add missing radix parameter to parseInt call. --- src/widget.filtereditor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget.filtereditor.js b/src/widget.filtereditor.js index 28c80bb3..14112511 100644 --- a/src/widget.filtereditor.js +++ b/src/widget.filtereditor.js @@ -141,7 +141,7 @@ my.FilterEditor = Backbone.View.extend({ var $input = $(input); var filterType = $input.attr('data-filter-type'); var fieldId = $input.attr('data-filter-field'); - var filterIndex = parseInt($input.attr('data-filter-id')); + var filterIndex = parseInt($input.attr('data-filter-id'), 10); var name = $input.attr('name'); var value = $input.val(); @@ -162,7 +162,7 @@ my.FilterEditor = Backbone.View.extend({ break; } }); - self.model.queryState.set({filters: filters}); + self.model.queryState.set({filters: filters, from: 0}); self.model.queryState.trigger('change'); } }); From 2d5291b201f5072d776231d5310e779d71cff354 Mon Sep 17 00:00:00 2001 From: John Glover Date: Tue, 5 Feb 2013 17:32:06 +0100 Subject: [PATCH 02/19] Rename x-axis and y-axis in view.graph.js. Changed to Axis 1 and Axis 2 to avoid confusion in bar graph (when axes are inverted). --- src/view.graph.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/view.graph.js b/src/view.graph.js index d0371d69..dc640ca0 100644 --- a/src/view.graph.js +++ b/src/view.graph.js @@ -320,7 +320,7 @@ my.GraphControls = Backbone.View.extend({ \ \ \ - \ + \
\ \
\ - \ + \
\ \ + \ + \ + \ + \ + \ + \ +
\ + \ +
\ + \ +
\ +
\ +
\ + \ +
\ + \ +
\ + \ + \ + \ +', + templateSeriesEditor: ' \ +
\ + \ +
\ + \ +
\ +
\ + ', + 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); +/*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): @@ -2295,7 +2800,7 @@ my.GraphControls = Backbone.View.extend({ \ \ \ - \ + \
\ \ + \ + \ + \ + \ + \ + \ +
\ + \ +
\ + \ +
\ +
\ +
\ + \ +
\ + \ +
\ + \ + \ + \ +', + templateSeriesEditor: ' \ +
\ + \ +
\ + \ +
\ +
\ + ', + 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); + diff --git a/src/view.graph.js b/src/view.graph.js index dc640ca0..0517b2f8 100644 --- a/src/view.graph.js +++ b/src/view.graph.js @@ -1,462 +1,5 @@ -/*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', -// graphOptions: {custom [Flotr2 options](http://www.humblesoftware.com/flotr2/documentation#configuration)} -// } -// -// 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.Graph = Backbone.View.extend({ - template: ' \ -
\ -
\ -
\ -

Hey there!

\ -

There\'s no graph here yet because we don\'t know what fields you\'d like to see plotted.

\ -

Please tell us by using the menu on the right and a graph will automatically appear.

\ -
\ -
\ -
\ -', - - initialize: function(options) { - var self = this; - this.graphColors = ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"]; - - this.el = $(this.el); - _.bindAll(this, 'render', 'redraw'); - 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.editor = new my.GraphControls({ - 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'); - return this; - }, - - redraw: function() { - // There appear to be 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() - 20); - var series = this.createSeries(); - var options = this.getGraphOptions(this.state.attributes.graphType); - this.plot = Flotr.draw(this.$graph.get(0), series, options); - } - }, - - show: function() { - // because we cannot redraw when hidden we may need to when becoming visible - if (this.needToRedraw) { - this.redraw(); - } - }, - - // ### getGraphOptions - // - // Get options for Flot Graph - // - // needs to be function as can depend on state - // - // @param typeId graphType id (lines, lines-and-points etc) - getGraphOptions: function(typeId) { - var self = this; - - var tickFormatter = function (x) { - return getFormattedX(x); - }; - - // infoboxes on mouse hover on points/bars etc - var trackFormatter = function (obj) { - var x = obj.x; - var y = obj.y; - // it's horizontal so we have to flip - if (self.state.attributes.graphType === 'bars') { - var _tmp = x; - x = y; - y = _tmp; - } - - x = getFormattedX(x); - - var content = _.template('<%= group %> = <%= x %>, <%= series %> = <%= y %>', { - group: self.state.attributes.group, - x: x, - series: obj.series.label, - y: y - }); - - return content; - }; - - var getFormattedX = function (x) { - var xfield = self.model.fields.get(self.state.attributes.group); - - // time series - var xtype = xfield.get('type'); - var isDateTime = (xtype === 'date' || xtype === 'date-time' || xtype === 'time'); - - if (self.model.records.models[parseInt(x)]) { - x = self.model.records.models[parseInt(x)].get(self.state.attributes.group); - if (isDateTime) { - x = new Date(x).toLocaleDateString(); - } - } else if (isDateTime) { - x = new Date(parseInt(x)).toLocaleDateString(); - } - return x; - } - - var xaxis = {}; - xaxis.tickFormatter = tickFormatter; - - var yaxis = {}; - yaxis.autoscale = true; - yaxis.autoscaleMargin = 0.02; - - var mouse = {}; - mouse.track = true; - mouse.relative = true; - mouse.trackFormatter = trackFormatter; - - var legend = {}; - legend.position = 'ne'; - - // mouse.lineColor is set in createSeries - var optionsPerGraphType = { - lines: { - legend: legend, - colors: this.graphColors, - lines: { show: true }, - xaxis: xaxis, - yaxis: yaxis, - mouse: mouse - }, - points: { - legend: legend, - colors: this.graphColors, - points: { show: true, hitRadius: 5 }, - xaxis: xaxis, - yaxis: yaxis, - mouse: mouse, - grid: { hoverable: true, clickable: true } - }, - 'lines-and-points': { - legend: legend, - colors: this.graphColors, - points: { show: true, hitRadius: 5 }, - lines: { show: true }, - xaxis: xaxis, - yaxis: yaxis, - mouse: mouse, - grid: { hoverable: true, clickable: true } - }, - bars: { - legend: legend, - colors: this.graphColors, - lines: { show: false }, - xaxis: yaxis, - yaxis: xaxis, - mouse: { - track: true, - relative: true, - trackFormatter: trackFormatter, - fillColor: '#FFFFFF', - fillOpacity: 0.3, - position: 'e' - }, - bars: { - show: true, - horizontal: true, - shadowSize: 0, - barWidth: 0.8 - } - }, - columns: { - legend: legend, - colors: this.graphColors, - lines: { show: false }, - xaxis: xaxis, - yaxis: yaxis, - mouse: { - track: true, - relative: true, - trackFormatter: trackFormatter, - fillColor: '#FFFFFF', - fillOpacity: 0.3, - position: 'n' - }, - bars: { - show: true, - horizontal: false, - shadowSize: 0, - barWidth: 0.8 - } - }, - grid: { hoverable: true, clickable: true } - }; - - if (self.state.get('graphOptions')){ - return _.extend(optionsPerGraphType[typeId], - self.state.get('graphOptions') - ) - }else{ - 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' && self.state.attributes.graphType != 'columns') { - // not bar or column - x = new Date(x).getTime(); - } else { - // bar or column - x = index; - } - } else if (typeof x === 'string') { - // string - x = parseFloat(x); - if (isNaN(x)) { - x = index; - } - } - - var yfield = self.model.fields.get(field); - var y = doc.getFieldValue(yfield); - - // horizontal bar chart - if (self.state.attributes.graphType == 'bars') { - points.push([y, x]); - } else { - points.push([x, y]); - } - }); - series.push({data: points, label: field, mouse:{lineColor: self.graphColors[series.length]}}); - }); - return series; - } -}); - -my.GraphControls = Backbone.View.extend({ - className: "editor", - template: ' \ -
\ -
\ -
\ - \ -
\ - \ -
\ - \ -
\ - \ -
\ -
\ -
\ -
\ -
\ - \ -
\ - \ -
\ -
\ -', - templateSeriesEditor: ' \ -
\ - \ -
\ - \ -
\ -
\ - ', - 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); +this.recline.View.Graph = this.recline.View.Flot; +this.recline.View.GraphControls = this.recline.View.FlotControls; diff --git a/test/index.html b/test/index.html index e9152613..0bf98a62 100644 --- a/test/index.html +++ b/test/index.html @@ -53,8 +53,9 @@ - + + @@ -65,7 +66,7 @@ - + diff --git a/test/view.graph.test.js b/test/view.flotr2.test.js similarity index 87% rename from test/view.graph.test.js rename to test/view.flotr2.test.js index 25a04d6c..89edfada 100644 --- a/test/view.graph.test.js +++ b/test/view.flotr2.test.js @@ -1,8 +1,8 @@ -module("View - Graph"); +module("View - Flotr2"); test('basics', function () { var dataset = Fixture.getDataset(); - var view = new recline.View.Graph({ + var view = new recline.View.Flotr2({ model: dataset }); $('.fixtures').append(view.el); @@ -14,7 +14,7 @@ test('basics', function () { test('initialize', function () { var dataset = Fixture.getDataset(); - var view = new recline.View.Graph({ + var view = new recline.View.Flotr2({ model: dataset, state: { 'graphType': 'lines', @@ -40,7 +40,7 @@ test('initialize', function () { test('dates in graph view', function () { expect(0); var dataset = Fixture.getDataset(); - var view = new recline.View.Graph({ + var view = new recline.View.Flotr2({ model: dataset, state: { 'graphType': 'lines', @@ -53,9 +53,9 @@ test('dates in graph view', function () { view.remove(); }); -test('GraphControls basics', function () { +test('Flotr2Controls basics', function () { var dataset = Fixture.getDataset(); - var view = new recline.View.GraphControls({ + var view = new recline.View.Flotr2Controls({ model: dataset, state: { graphType: 'bars', @@ -72,7 +72,7 @@ test('GraphControls basics', function () { test('Overriding graph options', function () { var dataset = Fixture.getDataset(); var randomWidth = Math.random(); - var view = new recline.View.Graph({ + var view = new recline.View.Flotr2({ model: dataset, state: { 'graphType': 'bars', @@ -83,4 +83,4 @@ test('Overriding graph options', function () { }); equal(view.getGraphOptions('bars').bars.barWidth, randomWidth) view.remove(); -}); \ No newline at end of file +}); From e77d6c4d369f4ecd18d7f92c608f8bd4486b794c Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 16:20:59 +0000 Subject: [PATCH 12/19] [site][s]: some minor tweaks to css and fix a typo in map tutorial. --- css-site/style.css | 18 +++++++++++++++--- docs/tutorial-maps.markdown | 4 +--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/css-site/style.css b/css-site/style.css index b1c5b023..dea128c3 100644 --- a/css-site/style.css +++ b/css-site/style.css @@ -21,13 +21,25 @@ Author URI: http://www.mintcanary.com/ @import url(http://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700); +body, p { + font-family: 'PT Sans',Helvetica,Arial,sans-serif; + font-size: 15px; +} + h1, h2, h3, h4, h5, h6 { font-family:'PT Sans',Helvetica, Arial, sans-serif; } -body, p { - font-family: 'PT Sans',Helvetica,Arial,sans-serif; - font-size: 15px; +h2 { + font-size: 24px; +} + +h3 { + font-size: 20px; +} + +h4 { + font-size: 18px; } a { diff --git a/docs/tutorial-maps.markdown b/docs/tutorial-maps.markdown index 6d67f62d..914d7d52 100644 --- a/docs/tutorial-maps.markdown +++ b/docs/tutorial-maps.markdown @@ -20,9 +20,7 @@ See the instructions in the [basic views tutorial](tutorial-views.html). ### Creating a Dataset -Again like the views tutorial: - -Here's some example data We are going to work with: +Just like in the main tutorial, here's some example data We are going to work with: {% highlight javascript %} {% include data.js %} From 67e9f61d859bcadeb1b9390ca44f823b151be27a Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 16:22:25 +0000 Subject: [PATCH 13/19] [docs][xs]: download referenced correct location for flot charts. --- download.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/download.markdown b/download.markdown index 8ad29dde..41b72ea0 100644 --- a/download.markdown +++ b/download.markdown @@ -85,7 +85,7 @@ All the views require, in addition to those needed for recline.dataset.js: Individual views have additional dependencies such as: -* [JQuery Flot](http://code.google.com/p/flot/) >= 0.7 (required for for graph view) +* [JQuery Flot](http://www.flotcharts.org/) >= 0.7 (required for for graph view) * [Leaflet](http://leaflet.cloudmade.com/) >= 0.4.4 (required for map view) * [Leaflet.markercluster](https://github.com/danzel/Leaflet.markercluster) as of 2012-09-12 (required for marker clustering) * [Verite Timeline](https://github.com/VeriteCo/Timeline/) as of 2012-05-02 (required for the timeline view) From 7c54e051418c03825e98616e398453983cae30bd Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 18:15:13 +0000 Subject: [PATCH 14/19] [build][xs]: regular build. --- dist/recline.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dist/recline.js b/dist/recline.js index 17947727..32db2ce5 100644 --- a/dist/recline.js +++ b/dist/recline.js @@ -2508,7 +2508,7 @@ this.recline.View = this.recline.View || {}; (function($, my) { -// ## Graph view for a Dataset using Flot graphing library. +// ## Graph view for a Dataset using Flotr2 graphing library. // // Initialization arguments (in a hash in first parameter): // @@ -2524,7 +2524,7 @@ this.recline.View = this.recline.View || {}; // // 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.Graph = Backbone.View.extend({ +my.Flotr2 = Backbone.View.extend({ template: ' \
\
\ @@ -2558,7 +2558,7 @@ my.Graph = Backbone.View.extend({ options.state ); this.state = new recline.Model.ObjectState(stateData); - this.editor = new my.GraphControls({ + this.editor = new my.Flotr2Controls({ model: this.model, state: this.state.toJSON() }); @@ -2579,9 +2579,9 @@ my.Graph = Backbone.View.extend({ }, redraw: function() { - // There appear to be issues generating a Flot graph if either: + // There appear to be issues generating a Flotr2 graph if either: - // * The relevant div that graph attaches to his hidden at the moment of creating the plot -- Flot will complain with + // * The relevant div that graph attaches to his hidden at the moment of creating the plot -- Flotr2 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' @@ -2610,7 +2610,7 @@ my.Graph = Backbone.View.extend({ // ### getGraphOptions // - // Get options for Flot Graph + // Get options for Flotr2 Graph // // needs to be function as can depend on state // @@ -2807,7 +2807,7 @@ my.Graph = Backbone.View.extend({ } }); -my.GraphControls = Backbone.View.extend({ +my.Flotr2Controls = Backbone.View.extend({ className: "editor", template: ' \
\ @@ -2963,6 +2963,11 @@ my.GraphControls = Backbone.View.extend({ })(jQuery, recline.View); +this.recline = this.recline || {}; +this.recline.View = this.recline.View || {}; +this.recline.View.Graph = this.recline.View.Flot; +this.recline.View.GraphControls = this.recline.View.FlotControls; + /*jshint multistr:true */ this.recline = this.recline || {}; From d369c9d95864a060405c554f3d53bc23df8a5509 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 18:29:02 +0000 Subject: [PATCH 15/19] [bugfix,view/flot][xs]: do not subtract 240px from rhs of flot graph (fix appears to be no longer needed and is breaking in most cases ...). --- src/view.flot.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/view.flot.js b/src/view.flot.js index d810b723..fe595e81 100644 --- a/src/view.flot.js +++ b/src/view.flot.js @@ -90,9 +90,6 @@ my.Flot = Backbone.View.extend({ // 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); From b6e179e3e77bec0b640ab8c8edb8b25a9dc35df2 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 18:29:44 +0000 Subject: [PATCH 16/19] [#287,view/flot][s]: s/recline-graph/recline-flot/g. --- css/flot.css | 10 +++++----- src/view.flot.js | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/css/flot.css b/css/flot.css index 03f21e56..cf203cda 100644 --- a/css/flot.css +++ b/css/flot.css @@ -1,23 +1,23 @@ -.recline-graph .graph { +.recline-flot .graph { height: 500px; overflow: hidden; } -.recline-graph .legend table { +.recline-flot .legend table { width: auto; margin-bottom: 0; } -.recline-graph .legend td { +.recline-flot .legend td { padding: 5px; line-height: 13px; } -.recline-graph .graph .alert { +.recline-flot .graph .alert { width: 450px; } -#recline-graph-tooltip { +#recline-flot-tooltip { position: absolute; background-color: #FEE !important; color: #000000 !important; diff --git a/src/view.flot.js b/src/view.flot.js index fe595e81..ea87f40f 100644 --- a/src/view.flot.js +++ b/src/view.flot.js @@ -23,7 +23,7 @@ this.recline.View = this.recline.View || {}; // generate the element itself (you can then append view.el to the DOM. my.Flot = Backbone.View.extend({ template: ' \ -
\ +
\
\
\

Hey there!

\ @@ -110,7 +110,7 @@ my.Flot = Backbone.View.extend({ this.previousTooltipPoint.y !== item.seriesIndex) { this.previousTooltipPoint.x = item.dataIndex; this.previousTooltipPoint.y = item.seriesIndex; - $("#recline-graph-tooltip").remove(); + $("#recline-flot-tooltip").remove(); var x = item.datapoint[0].toFixed(2), y = item.datapoint[1].toFixed(2); @@ -132,13 +132,13 @@ my.Flot = Backbone.View.extend({ yLocation = item.pageY - 20; } - $('
' + content + '
').css({ + $('
' + content + '
').css({ top: yLocation, left: xLocation }).appendTo("body").fadeIn(200); } } else { - $("#recline-graph-tooltip").remove(); + $("#recline-flot-tooltip").remove(); this.previousTooltipPoint.x = null; this.previousTooltipPoint.y = null; } From ba7e747b97aaeee469dc4c8e697eb7b4288950cc Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 9 Feb 2013 18:30:11 +0000 Subject: [PATCH 17/19] [build][xs]: build. --- dist/recline.css | 10 +++++----- dist/recline.js | 11 ++++------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/dist/recline.css b/dist/recline.css index 610a56a7..bc71116c 100644 --- a/dist/recline.css +++ b/dist/recline.css @@ -1,23 +1,23 @@ -.recline-graph .graph { +.recline-flot .graph { height: 500px; overflow: hidden; } -.recline-graph .legend table { +.recline-flot .legend table { width: auto; margin-bottom: 0; } -.recline-graph .legend td { +.recline-flot .legend td { padding: 5px; line-height: 13px; } -.recline-graph .graph .alert { +.recline-flot .graph .alert { width: 450px; } -#recline-graph-tooltip { +#recline-flot-tooltip { position: absolute; background-color: #FEE !important; color: #000000 !important; diff --git a/dist/recline.js b/dist/recline.js index 32db2ce5..297cc26b 100644 --- a/dist/recline.js +++ b/dist/recline.js @@ -2024,7 +2024,7 @@ this.recline.View = this.recline.View || {}; // generate the element itself (you can then append view.el to the DOM. my.Flot = Backbone.View.extend({ template: ' \ -
\ +
\
\
\

Hey there!

\ @@ -2091,9 +2091,6 @@ my.Flot = Backbone.View.extend({ // 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); @@ -2114,7 +2111,7 @@ my.Flot = Backbone.View.extend({ this.previousTooltipPoint.y !== item.seriesIndex) { this.previousTooltipPoint.x = item.dataIndex; this.previousTooltipPoint.y = item.seriesIndex; - $("#recline-graph-tooltip").remove(); + $("#recline-flot-tooltip").remove(); var x = item.datapoint[0].toFixed(2), y = item.datapoint[1].toFixed(2); @@ -2136,13 +2133,13 @@ my.Flot = Backbone.View.extend({ yLocation = item.pageY - 20; } - $('
' + content + '
').css({ + $('
' + content + '
').css({ top: yLocation, left: xLocation }).appendTo("body").fadeIn(200); } } else { - $("#recline-graph-tooltip").remove(); + $("#recline-flot-tooltip").remove(); this.previousTooltipPoint.x = null; this.previousTooltipPoint.y = null; } From 6f82c4c5ccd2367384ef8f1cb4fc296ed4a34e97 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sun, 10 Feb 2013 17:05:30 +0000 Subject: [PATCH 18/19] [#314,be/solr][s]: remove solr backend from core as in separate repo [1]. [1]: https://github.com/Recline/backend.solr --- demos/search/demo.search.app.js | 26 ---------- demos/search/index.html | 2 +- src/backend.solr.js | 68 -------------------------- test/backend.solr.test.js | 85 --------------------------------- test/index.html | 2 - 5 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 src/backend.solr.js delete mode 100644 test/backend.solr.test.js diff --git a/demos/search/demo.search.app.js b/demos/search/demo.search.app.js index 72b5937a..49f5f9b9 100644 --- a/demos/search/demo.search.app.js +++ b/demos/search/demo.search.app.js @@ -207,32 +207,6 @@ var templates = { data: data }); }, - 'http://openspending.org/api/search': function(record) { - record['time'] = record['time.label_facet'] - var template = '
\ -

\ - {{record.dataset}} {{record.time}} \ - – {{amount_formatted}} \ -

\ -
    \ - {{#data}} \ -
  • {{key}}: {{value}}
  • \ - {{/data}} \ -
\ -
\ - '; - var data = []; - _.each(_.keys(record), function(key) { - if (key !='_id' && key != 'id') { - data.push({ key: key, value: record[key] }); - } - }); - return Mustache.render(template, { - record: record, - amount_formatted: formatAmount(record['amount']), - data: data - }); - }, 'https://docs.google.com/spreadsheet/ccc?key=0Aon3JiuouxLUdExXSTl2Y01xZEszOTBFZjVzcGtzVVE': function(record) { var template = '
\

\ diff --git a/demos/search/index.html b/demos/search/index.html index e19ada5b..28d3bb6a 100644 --- a/demos/search/index.html +++ b/demos/search/index.html @@ -86,7 +86,7 @@ ul.facet-items {

This demo shows how Recline can be used to build a search app. It includes faceting as well as search. You can find the source javascript here (plus prettified version of source for readability) – please feel free to reuse!

-

The default setup uses local example data but you can also connect directly to any other backend supported by Recline, for example SOLR, ElasticSearch or even a google docs spreadsheet. As an example: here's an example running against the SOLR-style OpenSpending API and here's an example running against a GDocs spreadsheet (Oil spills in the Niger Delta).

+

The default setup uses local example data but you can also connect directly to any other backend supported by Recline, for example SOLR, ElasticSearch or even a google docs spreadsheet. Here's an example running against a GDocs spreadsheet (Oil spills in the Niger Delta).


diff --git a/src/backend.solr.js b/src/backend.solr.js deleted file mode 100644 index 36e465f0..00000000 --- a/src/backend.solr.js +++ /dev/null @@ -1,68 +0,0 @@ -this.recline = this.recline || {}; -this.recline.Backend = this.recline.Backend || {}; -this.recline.Backend.Solr = this.recline.Backend.Solr || {}; - -(function($, my) { - my.__type__ = 'solr'; - - // use either jQuery or Underscore Deferred depending on what is available - var Deferred = _.isUndefined(this.jQuery) ? _.Deferred : jQuery.Deferred; - - // ### fetch - // - // dataset must have a solr or url attribute pointing to solr endpoint - my.fetch = function(dataset) { - var jqxhr = $.ajax({ - url: dataset.solr || dataset.url, - data: { - rows: 1, - wt: 'json' - }, - dataType: 'jsonp', - jsonp: 'json.wrf' - }); - var dfd = new Deferred(); - jqxhr.done(function(results) { - // if we get 0 results we cannot get fields - var fields = [] - if (results.response.numFound > 0) { - fields = _.map(_.keys(results.response.docs[0]), function(fieldName) { - return { id: fieldName }; - }); - } - var out = { - fields: fields, - useMemoryStore: false - }; - dfd.resolve(out); - }); - return dfd.promise(); - } - - // TODO - much work on proper query support is needed!! - my.query = function(queryObj, dataset) { - var q = queryObj.q || '*:*'; - var data = { - q: q, - rows: queryObj.size, - start: queryObj.from, - wt: 'json' - }; - var jqxhr = $.ajax({ - url: dataset.solr || dataset.url, - data: data, - dataType: 'jsonp', - jsonp: 'json.wrf' - }); - var dfd = new Deferred(); - jqxhr.done(function(results) { - var out = { - total: results.response.numFound, - hits: results.response.docs - }; - dfd.resolve(out); - }); - return dfd.promise(); - }; - -}(jQuery, this.recline.Backend.Solr)); diff --git a/test/backend.solr.test.js b/test/backend.solr.test.js deleted file mode 100644 index 2b7ec65a..00000000 --- a/test/backend.solr.test.js +++ /dev/null @@ -1,85 +0,0 @@ -(function ($) { -module("Backend SOLR"); - -test("fetch", function() { - var dataset = new recline.Model.Dataset({ - url: 'http://openspending.org/api/search', - backend: 'solr' - }); - // stop(); - - var stub = sinon.stub($, 'ajax', function(options) { - return { - done: function(callback) { - callback(sample_data); - return this; - }, - fail: function() { - } - }; - }); - - dataset.fetch().done(function(dataset) { - var exp = [ - "_id", - "amount", - "category.label_facet", - "dataset", - "from.label_facet", - "id", - "subcategory.label_facet", - "time.label_facet", - "to.label_facet" - ]; - deepEqual( - exp, - _.pluck(dataset.fields.toJSON(), 'id') - ); - // check we've mapped types correctly - equal(dataset.fields.get('amount').get('type'), 'string'); - - // fetch does a query so we can check for records - equal(dataset.recordCount, 10342132); - equal(dataset.records.length, 2); - equal(dataset.records.at(0).get('id'), '3e3e25d7737634127b76d5ee4a7df280987013c7'); - // start(); - }); - $.ajax.restore(); -}); - -var sample_data = { - "response": { - "docs": [ - { - "_id": "south-african-national-gov-budget-2012-13::3e3e25d7737634127b76d5ee4a7df280987013c7", - "amount": 30905738200000.0, - "category.label_facet": "General public services", - "dataset": "south-african-national-gov-budget-2012-13", - "from.label_facet": "National Treasury", - "id": "3e3e25d7737634127b76d5ee4a7df280987013c7", - "subcategory.label_facet": "Transfers of a general character between different levels of government", - "time.label_facet": "01. April 2012", - "to.label_facet": "Provincial Equitable Share" - }, - { - "_id": "south-african-national-gov-budget-2012-13::738849e28e6b3c45e5b0001e142b51479b3a3e41", - "amount": 8938807300000.0, - "category.label_facet": "General public services", - "dataset": "south-african-national-gov-budget-2012-13", - "from.label_facet": "National Treasury", - "id": "738849e28e6b3c45e5b0001e142b51479b3a3e41", - "subcategory.label_facet": "Public debt transactions", - "time.label_facet": "01. April 2012", - "to.label_facet": "State Debt Costs" - } - ], - "numFound": 10342132, - "start": 0 - }, - "responseHeader": { - "QTime": 578, - "status": 0 - } -}; - -})(this.jQuery); diff --git a/test/index.html b/test/index.html index 0bf98a62..cfa1151e 100644 --- a/test/index.html +++ b/test/index.html @@ -38,7 +38,6 @@ - @@ -47,7 +46,6 @@ - From c3f18ab1edff8e72ba1451dbce890c112df7e5b6 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sun, 10 Feb 2013 18:26:06 +0000 Subject: [PATCH 19/19] [site/theme][xs]: add github buttons to navbar in place of simple link. --- _layouts/default.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_layouts/default.html b/_layouts/default.html index 03f35f4f..f293915c 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -59,9 +59,9 @@