diff --git a/app/models/formats/svg.js b/app/models/formats/svg.js index 3bad9e85..ea30f7ce 100644 --- a/app/models/formats/svg.js +++ b/app/models/formats/svg.js @@ -18,10 +18,9 @@ function SvgFormat() { this.totalRows = 0; this.bbox = null; // will be computed during the results scan + this.buffer = ''; - this.polys = []; - this.lines = []; - this.points = []; + this._streamingStarted = false; } SvgFormat.prototype = new pg('svg'); @@ -48,62 +47,15 @@ SvgFormat.prototype.getQuery = function(sql, options) { + '_dimension, ST_AsSVG(ST_TransScale(' + gn + ', ' + '-x0, -y0, s, s), 0, ' + dp + ') as ' + gn //+ ', ex0, ey0, ew, eh, s ' // DEBUG ONLY - + ' FROM trans, extent_info, source'; + + ' FROM trans, extent_info, source' + + ' ORDER BY the_geom_dimension ASC'; }; -SvgFormat.prototype.handleQueryRow = function(row) { - this.totalRows++; - - if ( ! row.hasOwnProperty(this.opts.gn) ) { - this.error = new Error('column "' + this.opts.gn + '" does not exist'); - } - - var g = row[this.opts.gn]; - if ( ! g ) return; // null or empty - - var gdims = row[this.opts.gn + '_dimension']; - // TODO: add an identifier, if any of "cartodb_id", "oid", "id", "gid" are found - // TODO: add "class" attribute to help with styling ? - if ( gdims == '0' ) { - this.points.push(''); - } else if ( gdims == '1' ) { - // Avoid filling closed linestrings - this.lines.push(''); - } else if ( gdims == '2' ) { - this.polys.push(''); - } - - if ( ! this.bbox ) { - // Parse layer extent: "BOX(x y, X Y)" - // NOTE: the name of the extent field is - // determined by the same code adding the - // ST_AsSVG call (in queryResult) - // - var bbox = row[this.opts.gn + '_box']; - bbox = bbox.match(/BOX\(([^ ]*) ([^ ,]*),([^ ]*) ([^)]*)\)/); - this.bbox = { - xmin: parseFloat(bbox[1]), - ymin: parseFloat(bbox[2]), - xmax: parseFloat(bbox[3]), - ymax: parseFloat(bbox[4]) - }; - } -}; - -SvgFormat.prototype.handleQueryEnd = function() { - if ( this.error ) { - this.callback(this.error); - return; - } - +SvgFormat.prototype.startStreaming = function() { if (this.opts.beforeSink) { this.opts.beforeSink(); } - if ( this.opts.profiler ) { - this.opts.profiler.done('gotRows'); - } - var header = [ '', '' @@ -128,20 +80,81 @@ SvgFormat.prototype.handleQueryEnd = function() { + '; stroke-width:' + stroke_width + '; fill:' + fill_color + '" '; - rootTag += 'xmlns="http://www.w3.org/2000/svg" version="1.1">'; + rootTag += 'xmlns="http://www.w3.org/2000/svg" version="1.1">\n'; header.push(rootTag); this.opts.sink.write(header.join('\n')); - this.opts.sink.write(this.points.join('\n')); - this.points = []; - this.opts.sink.write(this.lines.join('\n')); - this.lines = []; - this.opts.sink.write(this.polys.join('\n')); - this.polys = []; + this._streamingStarted = true; +}; + +SvgFormat.prototype.handleQueryRow = function(row) { + this.totalRows++; + + if ( ! row.hasOwnProperty(this.opts.gn) ) { + this.error = new Error('column "' + this.opts.gn + '" does not exist'); + } + + var g = row[this.opts.gn]; + if ( ! g ) return; // null or empty + + var gdims = row[this.opts.gn + '_dimension']; + // TODO: add an identifier, if any of "cartodb_id", "oid", "id", "gid" are found + // TODO: add "class" attribute to help with styling ? + if ( gdims == '0' ) { + this.buffer += '\n'; + } else if ( gdims == '1' ) { + // Avoid filling closed linestrings + this.buffer += '\n'; + } else if ( gdims == '2' ) { + this.buffer += '\n'; + } + + if ( ! this.bbox ) { + // Parse layer extent: "BOX(x y, X Y)" + // NOTE: the name of the extent field is + // determined by the same code adding the + // ST_AsSVG call (in queryResult) + // + var bbox = row[this.opts.gn + '_box']; + bbox = bbox.match(/BOX\(([^ ]*) ([^ ,]*),([^ ]*) ([^)]*)\)/); + this.bbox = { + xmin: parseFloat(bbox[1]), + ymin: parseFloat(bbox[2]), + xmax: parseFloat(bbox[3]), + ymax: parseFloat(bbox[4]) + }; + } + + if (!this._streamingStarted && this.bbox) { + this.startStreaming(); + } + + if (this._streamingStarted && (this.totalRows % (this.opts.bufferedRows || 1000))) { + this.opts.sink.write(this.buffer); + this.buffer = ''; + } +}; + +SvgFormat.prototype.handleQueryEnd = function() { + if ( this.error ) { + this.callback(this.error); + return; + } + + if ( this.opts.profiler ) { + this.opts.profiler.done('gotRows'); + } + + if (!this._streamingStarted) { + this.startStreaming(); + } + // rootTag close - this.opts.sink.write(''); + this.buffer += '\n'; + + this.opts.sink.write(this.buffer); this.opts.sink.end(); this.callback();