diff --git a/README.md b/README.md
index 27bd9b63..dd13e2f7 100755
--- a/README.md
+++ b/README.md
@@ -17,6 +17,22 @@ A simple but powerful library for building data applications in pure Javascript
Running the tests by opening `test/index.html` in your browser.
+### Contributing
+
+We welcome patches and pull requests and have a few guidelines.
+
+For small bugfixes or enhancements:
+
+* Please run the tests
+
+For larger changes:
+
+* Cleanup your code and affected code parts
+* Run the tests from test/index.html in different browsers (at least Chrome and FF)
+* Update the documentation and tutorials where necessary
+* Update _layouts/recline-deps.html if you change required files (e.g. leaflet libraries)
+* Try to build the demos in /demos with jekyll and then check out the demos/multiview/ which utilizes most aspects of Recline
+
## Changelog
diff --git a/_includes/recline-deps.html b/_includes/recline-deps.html
index ee0d4750..ad926765 100644
--- a/_includes/recline-deps.html
+++ b/_includes/recline-deps.html
@@ -1,6 +1,6 @@
-
+
@@ -21,7 +21,7 @@
-
+
diff --git a/demos/couchdb/app.js b/demos/couchdb/app.js
new file mode 100755
index 00000000..c02fe9e7
--- /dev/null
+++ b/demos/couchdb/app.js
@@ -0,0 +1,73 @@
+jQuery(function($) {
+ window.dataExplorer = null;
+ window.explorerDiv = $('.data-explorer-here');
+
+ var queryParameters = recline.View.parseQueryString(decodeURIComponent(window.location.search));
+
+ var dataset = new recline.Model.Dataset({
+ db_url: queryParameters['url'] || '/couchdb/yourcouchdb',
+ view_url: queryParameters['view_url'] || '/couchdb/yourcouchdb/_design/yourdesigndoc/_view/yourview',
+ backend: 'couchdb',
+ query_options: {
+ 'key': '_id'
+ }
+ });
+
+ dataset.fetch().done(function(dataset) {
+ console.log('records: ' + dataset.records);
+ });
+
+ createExplorer(dataset);
+});
+
+// make Explorer creation / initialization in a function so we can call it
+// again and again
+var createExplorer = function(dataset, state) {
+ // remove existing data explorer view
+ var reload = false;
+ if (window.dataExplorer) {
+ window.dataExplorer.remove();
+ reload = true;
+ }
+ window.dataExplorer = null;
+ var $el = $('
To use this demo you will need a CouchDB instance running and accessible over HTTP. You should then pass the following 2 query parameters to this page:
Note that if the CouchDB database is not running on the same domain as this page then the host it is on must support CORS – the simplest approach here is probably to set up a reverse proxy or proxy so your CouchDB database appears on the local domain at e.g. /mycouchdb/.
Using CouchDB with Recline Multiview to provide an elegant powerful browser for a CouchDB database and view.
+
+
+
+
+
+
+
+
+
diff --git a/dist/recline.js b/dist/recline.js
index 11910563..f3d4605a 100644
--- a/dist/recline.js
+++ b/dist/recline.js
@@ -159,8 +159,14 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
//
// @param {String} s The string to convert
// @param {Object} options Options for loading CSV including
- // @param {Boolean} [trim=false] If set to True leading and trailing whitespace is stripped off of each non-quoted field as it is imported
- // @param {String} [separator=','] Separator for CSV file
+ // @param {Boolean} [trim=false] If set to True leading and trailing
+ // whitespace is stripped off of each non-quoted field as it is imported
+ // @param {String} [delimiter=','] A one-character string used to separate
+ // fields. It defaults to ','
+ // @param {String} [quotechar='"'] A one-character string used to quote
+ // fields containing special characters, such as the delimiter or
+ // quotechar, or which contain new-line characters. It defaults to '"'
+ //
// Heavily based on uselesscode's JS CSV parser (MIT Licensed):
// http://www.uselesscode.org/javascript/csv/
my.parseCSV= function(s, options) {
@@ -169,8 +175,8 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
var options = options || {};
var trm = (options.trim === false) ? false : true;
- var separator = options.separator || ',';
- var delimiter = options.delimiter || '"';
+ var delimiter = options.delimiter || ',';
+ var quotechar = options.quotechar || '"';
var cur = '', // The character we are currently processing.
inQuote = false,
@@ -205,7 +211,7 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
cur = s.charAt(i);
// If we are at a EOF or EOR
- if (inQuote === false && (cur === separator || cur === "\n")) {
+ if (inQuote === false && (cur === delimiter || cur === "\n")) {
field = processField(field);
// Add the current field to the current row
row.push(field);
@@ -218,8 +224,8 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
field = '';
fieldQuoted = false;
} else {
- // If it's not a delimiter, add it to the field buffer
- if (cur !== delimiter) {
+ // If it's not a quotechar, add it to the field buffer
+ if (cur !== quotechar) {
field += cur;
} else {
if (!inQuote) {
@@ -227,9 +233,9 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
inQuote = true;
fieldQuoted = true;
} else {
- // Next char is delimiter, this is an escaped delimiter
- if (s.charAt(i + 1) === delimiter) {
- field += delimiter;
+ // Next char is quotechar, this is an escaped quotechar
+ if (s.charAt(i + 1) === quotechar) {
+ field += quotechar;
// Skip the next char
i += 1;
} else {
@@ -249,23 +255,48 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
return out;
};
- // Converts an array of arrays into a Comma Separated Values string.
- // Each array becomes a line in the CSV.
+ // ### serializeCSV
+ //
+ // Convert an Object or a simple array of arrays into a Comma
+ // Separated Values string.
//
// Nulls are converted to empty fields and integers or floats are converted to non-quoted numbers.
//
// @return The array serialized as a CSV
// @type String
//
- // @param {Array} a The array of arrays to convert
- // @param {Object} options Options for loading CSV including
- // @param {String} [separator=','] Separator for CSV file
- // Heavily based on uselesscode's JS CSV parser (MIT Licensed):
+ // @param {Object or Array} dataToSerialize The Object or array of arrays to convert. Object structure must be as follows:
+ //
+ // {
+ // fields: [ {id: .., ...}, {id: ...,
+ // records: [ { record }, { record }, ... ]
+ // ... // more attributes we do not care about
+ // }
+ //
+ // @param {object} options Options for serializing the CSV file including
+ // delimiter and quotechar (see parseCSV options parameter above for
+ // details on these).
+ //
+ // Heavily based on uselesscode's JS CSV serializer (MIT Licensed):
// http://www.uselesscode.org/javascript/csv/
- my.serializeCSV= function(a, options) {
+ my.serializeCSV= function(dataToSerialize, options) {
+ var a = null;
+ if (dataToSerialize instanceof Array) {
+ a = dataToSerialize;
+ } else {
+ a = [];
+ var fieldNames = _.pluck(dataToSerialize.fields, 'id');
+ a.push(fieldNames);
+ _.each(dataToSerialize.records, function(record, index) {
+ var tmp = _.map(fieldNames, function(fn) {
+ return record[fn];
+ });
+ a.push(tmp);
+ });
+ }
var options = options || {};
- var separator = options.separator || ',';
- var delimiter = options.delimiter || '"';
+ var delimiter = options.delimiter || ',';
+ var quotechar = options.quotechar || '"';
var cur = '', // The character we are currently processing.
field = '', // Buffer for building up the current field
@@ -281,7 +312,7 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
field = '';
} else if (typeof field === "string" && rxNeedsQuoting.test(field)) {
// Convert string to delimited string
- field = delimiter + field + delimiter;
+ field = quotechar + field + quotechar;
} else if (typeof field === "number") {
// Convert number to string
field = field.toString(10);
@@ -302,7 +333,7 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
row = '';
} else {
// Add the current field to the current row
- row += field + separator;
+ row += field + delimiter;
}
// Flush the field buffer
field = '';
@@ -1848,26 +1879,27 @@ my.Graph = Backbone.View.extend({
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 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 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) {
@@ -1938,18 +1970,18 @@ my.Graph = Backbone.View.extend({
xaxis: yaxis,
yaxis: xaxis,
mouse: {
- track: true,
- relative: true,
- trackFormatter: trackFormatter,
- fillColor: '#FFFFFF',
- fillOpacity: 0.3,
- position: 'e'
+ track: true,
+ relative: true,
+ trackFormatter: trackFormatter,
+ fillColor: '#FFFFFF',
+ fillOpacity: 0.3,
+ position: 'e'
},
bars: {
- show: true,
- horizontal: true,
- shadowSize: 0,
- barWidth: 0.8
+ show: true,
+ horizontal: true,
+ shadowSize: 0,
+ barWidth: 0.8
},
},
columns: {
@@ -2470,6 +2502,11 @@ this.recline.View = this.recline.View || {};
// latField: {id of field containing latitude in the dataset}
// }
//
+//
+// Useful attributes to know about (if e.g. customizing)
+//
+// * map: the Leaflet map (L.Map)
+// * features: Leaflet GeoJSON layer containing all the features (L.GeoJSON)
my.Map = Backbone.View.extend({
template: ' \
\
@@ -2488,6 +2525,8 @@ my.Map = Backbone.View.extend({
this.el = $(this.el);
this.visible = true;
this.mapReady = false;
+ // this will be the Leaflet L.Map object (setup below)
+ this.map = null;
var stateData = _.extend({
geomField: null,
@@ -2525,6 +2564,34 @@ my.Map = Backbone.View.extend({
this.elSidebar = this.menu.el;
},
+ // ## Customization Functions
+ //
+ // The following methods are designed for overriding in order to customize
+ // behaviour
+
+ // ### infobox
+ //
+ // Function to create infoboxes used in popups. The default behaviour is very simple and just lists all attributes.
+ //
+ // Users should override this function to customize behaviour i.e.
+ //
+ // view = new View({...});
+ // view.infobox = function(record) {
+ // ...
+ // }
+ infobox: function(record) {
+ var html = '';
+ for (key in record.attributes){
+ if (!(this.state.get('geomField') && key == this.state.get('geomField'))){
+ html += '
' + key + ': '+ record.attributes[key] + '
';
+ }
+ }
+ return html;
+ },
+
+ // END: Customization section
+ // ----
+
// ### Public: Adds the necessary elements to the page.
//
// Also sets up the editor fields and the map if necessary.
@@ -2619,19 +2686,12 @@ my.Map = Backbone.View.extend({
// Empty field
return true;
} else if (feature instanceof Object){
- // Build popup contents
- // TODO: mustache?
- html = '';
- for (key in doc.attributes){
- if (!(self.state.get('geomField') && key == self.state.get('geomField'))){
- html += '
' + key + ': '+ doc.attributes[key] + '
';
- }
- }
- feature.properties = {popupContent: html};
-
- // Add a reference to the model id, which will allow us to
- // link this Leaflet layer to a Recline doc
- feature.properties.cid = doc.cid;
+ feature.properties = {
+ popupContent: self.infobox(doc),
+ // Add a reference to the model id, which will allow us to
+ // link this Leaflet layer to a Recline doc
+ cid: doc.cid
+ };
try {
self.features.addData(feature);
diff --git a/docs/src/backend.ckan.html b/docs/src/backend.ckan.html
new file mode 100644
index 00000000..0727be5b
--- /dev/null
+++ b/docs/src/backend.ckan.html
@@ -0,0 +1,87 @@
+ backend.ckan.js
\ No newline at end of file
diff --git a/docs/src/backend.couchdb.html b/docs/src/backend.couchdb.html
index c2602fdf..f126f2d1 100644
--- a/docs/src/backend.couchdb.html
+++ b/docs/src/backend.couchdb.html
@@ -1,17 +1,17 @@
- backend.couchdb.js
Connecting to [CouchDB] (http://www.couchdb.apache.org/) endpoints.
@param {String} endpoint: url for CouchDB database, e.g. for Couchdb running
on localhost:5984 with database // ckan-std it would be:
-
http://localhost:5984/ckan-std
+
TODO Add user/password arguments for couchdb authentication support.
-
TODO Add user/password arguments for couchdb authentication support.
var dataset = new recline.Model.Dataset({ ... }, 'couchdb');
dataset.fetch();
-var results = dataset.query(query_obj);
+var results = dataset.query(query_obj);
+
-
Additionally, the Dataset instance may define three methods:
- function recordupdate (record, document) { ... }
+
Additionally, the Dataset instance may define three methods:
+
+
function recordupdate (record, document) { ... }
function recorddelete (record, document) { ... }
- function recordcreate (record, document) { ... }
-Where record is the JSON representation of the Record/Document instance
+ function record_create (record, document) { ... }
+
+
Where record is the JSON representation of the Record/Document instance
and document is the JSON document stored in couchdb.
-When _all
docs view is used (default), a record is the same as a document
+When alldocs view is used (default), a record is the same as a document
so these methods need not be defined.
They are most useful when using a custom view that performs a map-reduce
operation on each document to yield a record. Hence, when the record is
@@ -422,8 +425,8 @@ we should remove it before sending it to the server.
\ No newline at end of file
diff --git a/docs/src/backend.csv.html b/docs/src/backend.csv.html
index c0092c84..33c222f2 100644
--- a/docs/src/backend.csv.html
+++ b/docs/src/backend.csv.html
@@ -1,4 +1,4 @@
- backend.csv.js
this.recline=this.recline||{};this.recline.Backend=this.recline.Backend||{};this.recline.Backend.CSV=this.recline.Backend.CSV||{};
@@ -57,15 +57,21 @@ Each line in the CSV becomes an array.
@param {String} s The string to convert
@param {Object} options Options for loading CSV including
- @param {Boolean} [trim=false] If set to True leading and trailing whitespace is stripped off of each non-quoted field as it is imported
-@param {String} [separator=','] Separator for CSV file
-Heavily based on uselesscode's JS CSV parser (MIT Licensed):
+ @param {Boolean} [trim=false] If set to True leading and trailing
+ whitespace is stripped off of each non-quoted field as it is imported
+ @param {String} [delimiter=','] A one-character string used to separate
+ fields. It defaults to ','
+ @param {String} [quotechar='"'] A one-character string used to quote
+ fields containing special characters, such as the delimiter or
+ quotechar, or which contain new-line characters. It defaults to '"'
+
+
Heavily based on uselesscode's JS CSV parser (MIT Licensed):
http://www.uselesscode.org/javascript/csv/
s=chomp(s);varoptions=options||{};vartrm=(options.trim===false)?false:true;
- varseparator=options.separator||',';
- vardelimiter=options.delimiter||'"';
+ vardelimiter=options.delimiter||',';
+ varquotechar=options.quotechar||'"';varcur='',// The character we are currently processing.inQuote=false,
@@ -90,19 +96,19 @@ http://www.uselesscode.org/javascript/csv/
Convert an Object or a simple array of arrays into a Comma
+Separated Values string.
Nulls are converted to empty fields and integers or floats are converted to non-quoted numbers.
@return The array serialized as a CSV
@type String
-
@param {Array} a The array of arrays to convert
-@param {Object} options Options for loading CSV including
-@param {String} [separator=','] Separator for CSV file
-Heavily based on uselesscode's JS CSV parser (MIT Licensed):
-http://www.uselesscode.org/javascript/csv/
my.serializeCSV=function(a,options){
+
@param {Object or Array} dataToSerialize The Object or array of arrays to convert. Object structure must be as follows:
+
+
{
+ fields: [ {id: .., ...}, {id: ...,
+ records: [ { record }, { record }, ... ]
+ ... // more attributes we do not care about
+}
+
+
+
@param {object} options Options for serializing the CSV file including
+ delimiter and quotechar (see parseCSV options parameter above for
+ details on these).
+
+
Heavily based on uselesscode's JS CSV serializer (MIT Licensed):
+http://www.uselesscode.org/javascript/csv/
my.serializeCSV=function(dataToSerialize,options){
+ vara=null;
+ if(dataToSerializeinstanceofArray){
+ a=dataToSerialize;
+ }else{
+ a=[];
+ varfieldNames=_.pluck(dataToSerialize.fields,'id');
+ a.push(fieldNames);
+ _.each(dataToSerialize.records,function(record,index){
+ vartmp=_.map(fieldNames,function(fn){
+ returnrecord[fn];
+ });
+ a.push(tmp);
+ });
+ }varoptions=options||{};
- varseparator=options.separator||',';
- vardelimiter=options.delimiter||'"';
+ vardelimiter=options.delimiter||',';
+ varquotechar=options.quotechar||'"';varcur='',// The character we are currently processing.field='',// Buffer for building up the current field
@@ -140,7 +172,7 @@ http://www.uselesscode.org/javascript/csv/
this.recline=this.recline||{};this.recline.Backend=this.recline.Backend||{};this.recline.Backend.ElasticSearch=this.recline.Backend.ElasticSearch||{};
@@ -104,6 +104,16 @@ on http://localhost:9200 with index twitter and type tweet it would be:
});}returnout;
+ },
convert from Recline sort structure to ES form
+http://www.elasticsearch.org/guide/reference/api/search/sort.html
this._normalizeSort=function(sort){
+ varout=_.map(sort,function(sortObj){
+ var_tmp={};
+ var_tmp2=_.clone(sortObj);
+ delete_tmp2['field'];
+ _tmp[sortObj.field]=_tmp2;
+ return_tmp;
+ });
+ returnout;},this._convertFilter=function(filter){
@@ -117,14 +127,16 @@ on http://localhost:9200 with index twitter and type tweet it would be:
out.geo_distance.unit=filter.unit;}returnout;
- },
this.query=function(queryObj){varesQuery=(queryObj&&queryObj.toJSON)?queryObj.toJSON():_.extend({},queryObj);
- varqueryNormalized=this._normalizeQuery(queryObj);
+ esQuery.query=this._normalizeQuery(queryObj);deleteesQuery.q;deleteesQuery.filters;
- esQuery.query=queryNormalized;
+ if(esQuery.sort&&esQuery.sort.length>0){
+ esQuery.sort=this._normalizeSort(esQuery.sort);
+ }vardata={source:JSON.stringify(esQuery)};varurl=this.endpoint+'/_search';varjqxhr=makeRequest({
@@ -134,10 +146,10 @@ on http://localhost:9200 with index twitter and type tweet it would be:
});returnjqxhr;}
- };
my.fetch=function(dataset){vares=newmy.Wrapper(dataset.url,my.esOptions);vardfd=$.Deferred();es.mapping().done(function(schema){
@@ -145,7 +157,7 @@ via the url attribute.
if(!schema){dfd.reject({'message':'Elastic Search did not return a mapping'});return;
- }
only one top level key in ES = the type so we can ignore it
varkey=_.keys(schema)[0];varfieldData=_.map(schema[key].properties,function(dict,fieldName){dict.id=fieldName;returndict;
@@ -158,7 +170,7 @@ via the url attribute.
my.save=function(changes,dataset){vares=newmy.Wrapper(dataset.url,my.esOptions);if(changes.creates.length+changes.updates.length+changes.deletes.length>1){vardfd=$.Deferred();
@@ -175,7 +187,7 @@ via the url attribute.
my.query=function(queryObj,dataset){vardfd=$.Deferred();vares=newmy.Wrapper(dataset.url,my.esOptions);varjqxhr=es.query(queryObj);
@@ -201,7 +213,7 @@ via the url attribute.
this.recline=this.recline||{};this.recline.Backend=this.recline.Backend||{};this.recline.Backend.Memory=this.recline.Backend.Memory||{};
@@ -60,13 +60,14 @@ from the data.
Restore a Dataset instance from a serialized state. Serialized state for a
-Dataset is an Object like:
-
-
-{
- backend: {backend type - i.e. value of dataset.backend.type}
- dataset: {dataset info needed for loading -- result of dataset.toJSON() would be sufficient but can be simpler }
- // convenience - if url provided and dataste not this be used as dataset url
- url: {dataset url}
- ...
-}
Override Backbone save, fetch and destroy so they do nothing
Instead, Dataset object that created this Record should take care of
handling these changes (discovery will occur via event notifications)
WARNING: these will not persist unless you call save on Dataset
if a hash not passed in the first argument throw error
if('0'indata){thrownewError('Looks like you did not pass a proper hash with id to Field constructor');}if(this.attributes.label===null){
@@ -366,7 +341,7 @@ WARNING: these will not persist unless you call save on Dataset
}}elseif(format=='plain'){returnval;
- }else{
my.Query=Backbone.Model.extend({constructor:functionQuery(){Backbone.Model.prototype.constructor.apply(this,arguments);},
@@ -396,7 +371,7 @@ here that are not actually strings
Add a new filter (appended to the list of filters)
-
@param filter an object specifying the filter - see _filterTemplates for examples. If only type is provided will generate a filter by cloning _filterTemplates
not full specified so use template and over-write
+
@param filter an object specifying the filter - see _filterTemplates for examples. If only type is provided will generate a filter by cloning _filterTemplates
not full specified so use template and over-write
3 as for 'type', 'field' and 'fieldType'
if(_.keys(filter).length<=3){ourfilter=_.extend(this._filterTemplates[filter.type],ourfilter);}
@@ -426,19 +401,19 @@ here that are not actually strings
my.Facet=Backbone.Model.extend({constructor:functionFacet(){Backbone.Model.prototype.constructor.apply(this,arguments);},
@@ -471,15 +446,15 @@ here that are not actually strings
/*jshint multistr:true */this.recline=this.recline||{};this.recline.View=this.recline.View||{};
@@ -102,29 +102,28 @@ generate the element itself (you can then append view.el to the DOM.
vartickFormatter=function(x){returngetFormattedX(x);};
-
- vartrackFormatter=function(obj){
- varx=obj.x;
- vary=obj.y;
varisDateTime=xfield.get('type')==='date';if(self.model.records.models[parseInt(x)]){x=self.model.records.models[parseInt(x)].get(self.state.attributes.group);
@@ -151,7 +150,7 @@ generate the element itself (you can then append view.el to the DOM.
varlegend={};legend.position='ne';
-
x=parseFloat(x);if(isNaN(x)){x=index;}
@@ -246,7 +245,7 @@ generate the element itself (you can then append view.el to the DOM.
varyfield=self.model.fields.get(field);vary=doc.getFieldValue(yfield);
-
if(self.state.attributes.graphType=='bars'){points.push([y,x]);}else{points.push([x,y]);
@@ -330,12 +329,12 @@ generate the element itself (you can then append view.el to the DOM.
varself=this;vartmplData=this.model.toTemplateJSON();varhtmls=Mustache.render(this.template,tmplData);
- this.el.html(htmls);
vartmpSeries=[""];if(this.state.get('series').length>0){tmpSeries=this.state.get('series');}
@@ -344,7 +343,7 @@ generate the element itself (you can then append view.el to the DOM.
self._selectOption('.editor-series.js-series-'+idx,series);});returnthis;
- },
Private: Helper function to select an option from a select list
_selectOption:function(id,value){varoptions=this.el.find(id+' select > option');if(options){options.each(function(opt){
@@ -369,7 +368,7 @@ generate the element itself (you can then append view.el to the DOM.
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
@@ -387,7 +386,7 @@ generate the element itself (you can then append view.el to the DOM.
_onAddSeries:function(e){e.preventDefault();this.addSeries(this.state.get('series').length);
- },
/*jshint multistr:true */this.recline=this.recline||{};this.recline.View=this.recline.View||{};
@@ -20,7 +20,14 @@ have the following (optional) configuration options:
lonField: {id of field containing longitude in the dataset}
latField: {id of field containing latitude in the dataset}
}
-
my.Map=Backbone.View.extend({
+
+
+
Useful attributes to know about (if e.g. customizing)
+
+
+
map: the Leaflet map (L.Map)
+
features: Leaflet GeoJSON layer containing all the features (L.GeoJSON)
+
my.Map=Backbone.View.extend({template:' \ <div class="recline-map"> \ <div class="panel map"></div> \
@@ -34,7 +41,7 @@ If not found, the user will need to define the fields via the editor.
varself=this;this.el=$(this.el);this.visible=true;
- this.mapReady=false;
+ this.mapReady=false;
this will be the Leaflet L.Map object (setup below)
this.map=null;varstateData=_.extend({geomField:null,
@@ -44,16 +51,16 @@ If not found, the user will need to define the fields via the editor.
},options.state);
- this.state=newrecline.Model.ObjectState(stateData);
this.model.records.bind('add',function(doc){self.redraw('add',doc);});this.model.records.bind('change',function(doc){self.redraw('remove',doc);self.redraw('add',doc);});
- this.model.records.bind('remove',function(doc){self.redraw('remove',doc)});
- this.model.records.bind('reset',function(){self.redraw('reset')});
+ this.model.records.bind('remove',function(doc){self.redraw('remove',doc);});
+ this.model.records.bind('reset',function(){self.redraw('reset');});this.menu=newmy.MapMenu({model:this.model,
@@ -64,7 +71,28 @@ If not found, the user will need to define the fields via the editor.
self.redraw();});this.elSidebar=this.menu.el;
- },
Also sets up the editor fields and the map if necessary.
render:function(){varself=this;
@@ -74,7 +102,7 @@ If not found, the user will need to define the fields via the editor.
this.$map=this.el.find('.panel.map');this.redraw();returnthis;
- },
if(!self._geomReady()){self._setupGeometryField();}if(!self.mapReady){
@@ -111,7 +139,7 @@ If not found, the user will need to define the fields via the editor.
}},
- show:function(){
For each record passed, a GeoJSON geometry will be extracted and added
to the features layer. If an exception is thrown, the process will be
@@ -141,22 +169,22 @@ stopped and an error notification shown.
We'll create a GeoJSON like point object from the two lat/lon fields
varlon=doc.get(this.state.get('lonField'));varlat=doc.get(this.state.get('latField'));if(!isNaN(parseFloat(lon))&&!isNaN(parseFloat(lat))){return{
@@ -227,10 +255,10 @@ link this Leaflet layer to a Recline doc
Private: Helper function to select an option from a select list
_selectOption:function(id,value){varoptions=$('.'+id+' > select > option');if(options){options.each(function(opt){
@@ -368,7 +372,7 @@ In the meantime we add it manually to our layer.
events:{'click .editor-update-map':'onEditorSubmit','change .editor-field-type':'onFieldTypeChange','click #editor-auto-zoom':'onAutoZoomChange'
@@ -382,7 +386,7 @@ In the meantime we add it manually to our layer.