From 9ff42f5d4d1ee80444f9b09a64ec4a039fc93e8e Mon Sep 17 00:00:00 2001 From: javi Date: Wed, 28 Aug 2013 12:38:48 +0200 Subject: [PATCH] changed point renderer --- lib/torque/renderer/point.js | 36 ++++------- vendor/carto.js | 119 ++++++++++++++++++++++++++++------- 2 files changed, 107 insertions(+), 48 deletions(-) diff --git a/lib/torque/renderer/point.js b/lib/torque/renderer/point.js index 66a6062..960557b 100644 --- a/lib/torque/renderer/point.js +++ b/lib/torque/renderer/point.js @@ -28,7 +28,6 @@ this._canvas = canvas; this._ctx = canvas.getContext('2d'); this._sprites = {}; - this._trailsSprites = []; this._shader = null; this._trailsShader = null; //carto.tree.Reference.set(torque['torque-reference']); @@ -48,22 +47,7 @@ setCartoCSS: function(cartocss) { // clean sprites this._sprites = {}; - this._trailsSprites = []; this._cartoCssStyle = new carto.RendererJS().render(cartocss); - if(this._cartoCssStyle.getLayers().length < 1) { - throw new Error("CartoCSS must have at least one layer"); - } - this._shader = this._cartoCssStyle.getDefault(); - if(!this._shader) { - throw new Error("there is not default layer in CartoCSS"); - } - - this._trailsShader = this._cartoCssStyle.findLayer({ attachment: 'trails' }); - if(this._trailsShader) { - var st = this._trailsShader.getStyle('canvas-2d', { value: 0}, {zoom: 1}); - this._trailSteps = +st['trail-steps']; - } - }, // @@ -94,11 +78,13 @@ }, renderTile: function(tile, key) { - this._renderTile(tile, key, this._sprites, this._shader); - if(this._trailsShader) { - for(var i = 0; i < this._trailSteps; ++i) { - this._trailsSprites[i] = this._trailsSprites[i] || {}; - this._renderTile(tile, key - (i + 1), this._trailsSprites[i], this._trailsShader, { 'trail-step': i + 1 }); + var layers = this._cartoCssStyle.getLayers(); + for(var i = 0, n = layers.length; i < n; ++i ) { + var layer = layers[i]; + for(var fr = 0; fr < layer.frames().length; ++fr) { + var frame = layer.frames()[fr]; + var sprites = this._sprites[frame] || (this._sprites[frame] = []); + this._renderTile(tile, key - frame, frame, sprites, layer); } } }, @@ -107,9 +93,9 @@ // renders a tile in the canvas for key defined in // the torque tile // - _renderTile: function(tile, key, sprites, shader, shaderVars) { + _renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) { if(!this._canvas) return; - //var prof = Profiler.get('render').start(); + var prof = Profiler.metric('PointRenderer:renderTile').start(); var ctx = this._ctx; var res = this.options.resolution; var activePixels = tile.timeCount[key]; @@ -124,7 +110,7 @@ if(c) { var sp = sprites[c]; if(!sp) { - sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.zoom }, shaderVars)); + sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.zoom, 'frame-offset': frame_offset }, shaderVars)); } var x = tile.x[posIdx]*res - (sp.width >> 1); var y = (256 - res - res*tile.y[posIdx]) - (sp.height >> 1); @@ -132,7 +118,7 @@ } } } - //prof.end(); + prof.end(); } }; diff --git a/vendor/carto.js b/vendor/carto.js index 37178b9..1602b94 100644 --- a/vendor/carto.js +++ b/vendor/carto.js @@ -1866,6 +1866,9 @@ function require(arg) { if(!mod) { mod = window.carto[arg] } + if(!mod) { + mod = window[arg.split('/')[1]]; + } // try global scope if(!mod) { mod = window[arg] @@ -1874,7 +1877,7 @@ function require(arg) { } var carto, tree, _; -if (typeof(process) !== 'undefined') { +if (typeof(exports) !== 'undefined') { carto = exports; tree = require('./tree'); _ = require('underscore'); @@ -2175,9 +2178,6 @@ carto.Parser = function Parser(env) { // and sorted according to specificitySort root.toList = (function() { var line, lines, column; - if (!(window && window._)) { - var _ = require('underscore')._; - } return function(env) { env.error = function(e) { if (!env.errors) env.errors = new Error(''); @@ -2501,11 +2501,13 @@ carto.Parser = function Parser(env) { var e, elements = []; var f, filters = new tree.Filterset(); var z, zoom = tree.Zoom.all; + var fo, frame_offset = tree.FrameOffset.null; var segments = 0, conditions = 0; while ( (e = $(this.element)) || (z = $(this.zoom)) || + (fo = $(this.frame_offset)) || (f = $(this.filter)) || (a = $(this.attachment)) ) { @@ -2515,6 +2517,9 @@ carto.Parser = function Parser(env) { } else if (z) { zoom &= z; conditions++; + } else if (fo) { + frame_offset = fo; + conditions++; } else if (f) { filters.add(f); conditions++; @@ -2532,7 +2537,7 @@ carto.Parser = function Parser(env) { } if (segments) { - return new tree.Selector(filters, zoom, elements, attachment, conditions, memo); + return new tree.Selector(filters, zoom, frame_offset, elements, attachment, conditions, memo); } }, @@ -2549,6 +2554,17 @@ carto.Parser = function Parser(env) { } }, + frame_offset: function() { + save(); + var op, val; + if ($(/^\[\s*frame-offset/g) && + (op = $(this.entities.comparison)) && + (val = $(/^\d+/)) && + $(']')) { + return tree.FrameOffset(op, val, memo); + } + }, + zoom: function() { save(); var op, val; @@ -2957,6 +2973,7 @@ tree.Definition = function Definition(selector, rules) { } this.filters = selector.filters; this.zoom = selector.zoom; + this.frame_offset = selector.frame_offset; this.attachment = selector.attachment || '__default__'; this.specificity = selector.specificity(); }; @@ -3614,6 +3631,33 @@ tree.FontSet.prototype.toXML = function(env) { }; })(require('../tree')); +var tree = require('../tree'); + +// Storage for Frame offset value +// and stores them as bit-sequences so that they can be combined, +// inverted, and compared quickly. +tree.FrameOffset = function(op, value, index) { + value = parseInt(value, 10); + if (value > tree.FrameOffset.max || value <= 0) { + throw { + message: 'Only frame-offset levels between 1 and ' + + tree.FrameOffset.max + ' supported.', + index: index + }; + } + + if (op !== '=') { + throw { + message: 'only = operator is supported for frame-offset', + index: index + }; + } + return value; +}; + +tree.FrameOffset.max = 32; +tree.FrameOffset.null = 0; + (function(tree) { // // RGB Colors - #ff0014, #eee @@ -4215,7 +4259,7 @@ tree.Ruleset.prototype = { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( - new tree.Selector(null, null, selector.elements.slice(1)), self)); + new tree.Selector(null, null, null, selector.elements.slice(1)), self)); } else { rules.push(rule); } @@ -4247,6 +4291,7 @@ tree.Ruleset.prototype = { // filters. This means that we only have to clone when // the zoom levels or the attachment is different too. if (parent.zoom === (parent.zoom & child.zoom) && + parent.frame_offset === child.frame_offset && parent.attachment === child.attachment) { continue; } else { @@ -4261,6 +4306,7 @@ tree.Ruleset.prototype = { var clone = Object.create(tree.Selector.prototype); clone.filters = mergedFilters; clone.zoom = parent.zoom & child.zoom; + clone.frame_offset = child.frame_offset; clone.elements = parent.elements.concat(child.elements); if (parent.attachment && child.attachment) { clone.attachment = parent.attachment + '/' + child.attachment; @@ -4307,10 +4353,11 @@ var assert = require('assert'); (function(tree) { -tree.Selector = function Selector(filters, zoom, elements, attachment, conditions, index) { +tree.Selector = function Selector(filters, zoom, frame_offset, elements, attachment, conditions, index) { this.elements = elements || []; this.attachment = attachment; this.filters = filters || {}; + this.frame_offset = frame_offset; this.zoom = typeof zoom !== 'undefined' ? zoom : tree.Zoom.all; this.conditions = conditions; this.index = index; @@ -4749,8 +4796,9 @@ function clamp(val) { } })(require('./tree')); -(function() { -var tree = require('../tree'); +(function(carto) { +var tree = require('./tree'); +var _ = require('underscore'); // monkey patch less classes tree.Value.prototype.toJS = function() { @@ -4794,12 +4842,12 @@ tree.Definition.prototype.toJS = function() { // merge conditions from filters with zoom condition of the // definition var zoom = "(" + this.zoom + " & (1 << ctx.zoom))"; - var _if = this.filters.toJS() - if(_if && _if.length > 0) { - _if += " && " + zoom; - } else { - _if = zoom; - } + var frame_offset = this.frame_offset; + var _if = this.filters.toJS(); + var filters = [zoom]; + if(_if) filters.push(_if); + if(frame_offset) filters.push('ctx["frame-offset"] === ' + frame_offset); + _if = filters.join(" && "); _.each(this.rules, function(rule) { if(rule instanceof tree.Rule) { shaderAttrs[rule.name] = shaderAttrs[rule.name] || []; @@ -4826,7 +4874,8 @@ tree.Definition.prototype.toJS = function() { }; -function CartoCSS(style) { +function CartoCSS(style, options) { + this.options = options || {}; if(style) { this.setStyle(style); } @@ -4912,7 +4961,7 @@ CartoCSS.renderers['canvas-2d'] = { } var renderer = CartoCSS.renderers['svg']; -var ref = window.carto['mapnik-reference'].version.latest; +var ref = require('mapnik-reference').version.latest; var to_load = ['polygon', 'line', 'point', 'markers']; for(var ss in to_load) { var s = to_load[ss]; @@ -4932,6 +4981,11 @@ CartoCSS.Layer.prototype = { return this.fullName().split('::')[0]; }, + // frames this layer need to be rendered + frames: function() { + return this.shader.frames; + }, + attachment: function() { return this.fullName().split('::')[1]; }, @@ -4945,7 +4999,7 @@ CartoCSS.Layer.prototype = { getStyle: function(target, props, context) { var style = {}; for(var i in this.shader) { - if(i !== 'attachment') { + if(i !== 'attachment' && i !== 'zoom' && i !== 'frames') { style[i] = this.shader[i](props, context); } } @@ -5017,7 +5071,7 @@ CartoCSS.prototype = { _createFn: function(ops) { var body = ops.join('\n'); - console.log(body); + if(this.options.debug) console.log(body); return Function("data","ctx", "var _value = null; " + body + "; return _value; "); }, @@ -5048,6 +5102,7 @@ CartoCSS.prototype = { try { ruleset = (new carto.Parser(parse_env)).parse(cartocss); } catch(e) { + console.log(e.stack); // add the style.mss string to match the response from the server parse_env.errors.push(e.message); return; @@ -5061,6 +5116,8 @@ CartoCSS.prototype = { var def = defs[i]; var key = def.elements[0] + "::" + def.attachment; var layer = layers[key] = (layers[key] || {}); + layer.frames = []; + layer.zoom = tree.Zoom.all; var props = def.toJS(); for(var v in props) { (layer[v] = (layer[v] || [])).push(props[v].join('\n')) @@ -5073,15 +5130,26 @@ CartoCSS.prototype = { for(var i = 0; i < defs.length; ++i) { var def = defs[i]; var k = def.elements[0] + "::" + def.attachment; + var layer = layers[k]; if(!done[k]) { - var layer = layers[k]; for(var prop in layer) { - layer[prop] = this._createFn(layer[prop]); + if (prop !== 'zoom' && prop !== 'frames') { + + if(this.options.debug) console.log("****", prop); + layer[prop] = this._createFn(layer[prop]); + } } layer.attachment = k; ordered_layers.push(layer); done[k] = true; } + layer.zoom |= def.zoom; + layer.frames.push(def.frame_offset); + } + + // uniq the frames + for(i = 0; i < ordered_layers.length; ++i) { + ordered_layers[i].frames = _.uniq(ordered_layers[i].frames); } return ordered_layers; @@ -5091,6 +5159,7 @@ CartoCSS.prototype = { } }; + carto.RendererJS = function (options) { this.options = options || {}; this.options.mapnik_version = this.options.mapnik_version || 'latest'; @@ -5099,7 +5168,11 @@ carto.RendererJS = function (options) { // Prepare a javascript object which contains the layers carto.RendererJS.prototype.render = function render(cartocss, callback) { tree.Reference.setVersion(this.options.mapnik_version); - return new CartoCSS(cartocss); + return new CartoCSS(cartocss, this.options); +} +if(typeof(module) !== 'undefined') { + module.exports = carto.RendererJS; } -})(); + +})(require('../carto'));