1 /**
  2  * Source: Layer.js
  3  * Copyright (c) 2013-2014 Oculus Info Inc.
  4  * @fileOverview Aperture Abstract Layer Class Implementation
  5  */
  6 
  7 /**
  8  * @namespace
  9  * @ignore
 10  * Ensure namespace exists
 11  */
 12 aperture = (
 13 /** @private */
 14 function(namespace) {
 15 
 16 	
 17 	// PRIVATE REFERENCES AND FUNCTIONS
 18 	/**
 19 	 * Keep a running globally unique id set such that each render node can have a
 20 	 * unique id.  This allows nodes to be easily hashed.
 21 	 */
 22 	var log = aperture.log,
 23 		nextUid = 1,
 24 		NO_GRAPHICS = aperture.canvas.NO_GRAPHICS,
 25 		
 26 		// util is always defined by this point
 27 		util = aperture.util,
 28 		forEach = util.forEach,
 29 		indexOf = util.indexOf;
 30 
 31 	/**
 32 	 * Given a Node object create a derived node that shares the source's
 33 	 * core features (such as position, anchor, etc) but has a fresh (empty) userData
 34 	 * object
 35 	 */
 36 	function addNode( layer, parent, prev, data ) {
 37 		// Derive an object
 38 		var node = util.viewOf( parent ),
 39 			sibs = parent.kids,
 40 			luid = layer.uid;
 41 		
 42 		// append ourselves to existing siblings.
 43 		(sibs[luid] || (sibs[luid] = [])).push(node);
 44 		
 45 		// Initialize unique properties.
 46 		node.uid      = (nextUid++).toString();
 47 		node.parent   = parent;
 48 		node.layer    = layer;
 49 		node.kids     = {};
 50 		node.userData = {};
 51 		node.graphics = NO_GRAPHICS;
 52 
 53 		// Set data if given, otherwise it will inherit it.
 54 		if( data ) {
 55 			node.data = data;
 56 			node.idFn = layer.idFunction;
 57 		}
 58 		
 59 		// do graphics construction.
 60 		updateVisibility(node);
 61 		
 62 		linkNode(node, prev);
 63 		
 64 		return node;
 65 	}
 66 
 67 	
 68 	/**
 69 	 * Default data item function
 70 	 */
 71 	var inherited = (function() {
 72 		var copydata = [null], nodata = []; // use these once
 73 		
 74 		return function(data) {
 75 			return data? copydata : nodata;
 76 		};
 77 	}());
 78 	
 79 	
 80 	/**
 81 	 * Updates the visibility, creating the graphics for the first time if necessary,
 82 	 * and returns true if showing. 
 83 	 */
 84 	function updateVisibility( node ) {
 85 		var layer = node.layer;
 86 		
 87 		if (layer) {
 88 		
 89 			var show = layer.valueFor('visible', node.data, true );
 90 
 91 			// reset.
 92 			node.appearing = false;
 93 		
 94 			if (show) {
 95 				if (node.graphics === NO_GRAPHICS && node.parent.graphics) {
 96 					var g = node.graphics = layer.canvas_.graphics( node.parent.graphics ).data( node );
 97 				
 98 					// event hooks for any current events
 99 					forEach(layer.handlers_, function(h, key) {
100 						g.on(key, this);
101 					}, layer);
102 				
103 					node.appearing = true;
104 				
105 				} else {
106 					node.appearing = node.graphics.display(true);
107 				}
108 			
109 			} else if (node.graphics) {
110 				node.graphics.display(false);
111 			}
112 		
113 			return show;
114 		}
115 	}
116 
117 	/**
118 	 * Link a new node into the list. For optimal traversal and removal nodes
119 	 * store references their adjacent nodes rather than externalizing that in a list structure.
120 	 */
121 	function linkNode( node, prev ) {
122 		
123 		// assume next is handled. this is a private and optimized process.
124 		if (prev == null) {
125 			node.layer.nodes_ = node;
126 			node.prev = null;
127 		} else {
128 			prev.next = node;
129 			node.prev = prev;
130 		}
131 	}
132 
133 	/**
134 	 * Remove a node from the linked list.
135 	 */
136 	function unlinkNode( c ) {
137 		
138 		// stitch
139 		if (c.prev) {
140 			c.prev.next = c.next;
141 		} else {
142 			c.layer.nodes_ = c.next;
143 		}
144 		
145 		if (c.next) {
146 			c.next.prev = c.prev;
147 		} 
148 	}
149 	
150 	/**
151 	 * node removal function.
152 	 */
153 	function removeNode(c) {
154 		var sibs = c.parent.kids[c.layer.uid],
155 			ixMe = indexOf(sibs, c);
156 		
157 		if (ixMe !== -1) {
158 			sibs.splice(ixMe, 1);
159 		}
160 		
161 		// cleanup graphics.
162 		c.graphics.remove();
163 		c.graphics = null;
164 		c.layer = null;
165 	}
166 	
167 	/**
168 	 * Private function called by processChangeSet invoked if the layer has local data and
169 	 * is not being built up from scratch.
170 	 */
171 	function processDataChanges( myChangeSet, parentChangeSet ) {
172 		var chgs = myChangeSet.changed, c;
173 
174 		
175 		// DATA CHANGED? SORT *ALL* CHANGES OUT AND RETURN
176 		// if our data changes, we have to execute a full pass through everything
177 		// to sort into add/changed/removed. EVERYTHING is touched. this could be made more
178 		// efficient if data models exposed chg fns to the user - i.e. w/ adds, joins etc.
179 		if (myChangeSet.dataChanged) {
180 			var allParents  = (this.parentLayer_ && this.parentLayer_.nodes_) || this.rootNode_,
181 				adds = myChangeSet.added,
182 				rmvs = myChangeSet.removed,
183 				myUid = this.uid,
184 				idFunction = this.idFunction,
185 				prev, dad, i;
186 			
187 			// form new ordered list of nodes.
188 			this.nodes_ = null;
189 			
190 			// re-compare EVERYTHING and sort into add/changed/removed
191 			for (dad = allParents; dad != null; dad = dad.next) {
192 				var existing = indexNodes(dad.kids[myUid]),
193 					newkids = dad.kids[myUid] = [];
194 				
195 				// for all my new items, look for matches in existing.
196 				forEach( this.dataItems( dad.data ), function( dataItem ) {
197 					c = null;
198 					
199 					var dataId = idFunction? idFunction.call(dataItem) : dataItem;
200 						
201 					for (i = existing.next; i != null; i = i.next) {
202 						c = i.node;
203 
204 						// match?
205 						if ((c.idFn? c.idFn.call(c.data) : c.data) === dataId) {
206 							// remove it by stitching adjacent nodes together.
207 							// Makes subsequent searches faster and will leave
208 							// existing with only the things that have been removed.
209 							i.prev.next = i.next;
210 							if (i.next) {
211 								i.next.prev = i.prev;
212 							}
213 							
214 							break;
215 							
216 						} else {
217 							c = null;
218 						}
219 					}
220 					
221 					// found? process change
222 					if (c) {
223 
224 						// readd to fresh kid list
225 						newkids.push(c);
226 						
227 						// link it back in.
228 						linkNode( c, prev );
229 					
230 						// update data reference.
231 						c.data = dataItem;
232 						c.idFn = idFunction;
233 
234 						// only process further if showing.
235 						if (updateVisibility(c)) {
236 							chgs.push(c);
237 						}
238 						
239 					// else make new
240 					} else {
241 						adds.push( c = addNode( this, dad, prev, dataItem ) );
242 						
243 					}
244 					
245 					prev = c;
246 					
247 				}, this);
248 
249 				if (prev) {
250 					prev.next = null;
251 				}
252 				
253 				// whatever is left is trash. these are already removed from our locally linked list.
254 				for (i = existing.next; i != null; i = i.next) {
255 					rmvs.push(i.node);
256 				}
257 			}
258 			
259 		// SHORTCUT: EVERYTHING IS A SIMPLE UPDATE AND I AM THE ROOT
260 		// last of the special cases. If we receive this we are the first in traversal
261 		// that contains data and our job is to simply to add everything visible as changed.
262 		// thereafter children will pick it up properly and interpret in the node of any data changes.
263 		// we know there are no removes or adds, since we are top in the chain and we already looked locally
264 		} else if (myChangeSet.updateAll) {
265 			for (c = this.nodes_; c != null; c = c.next) {
266 				if (updateVisibility(c)) {
267 					chgs.push(c);
268 				}
269 			}
270 			
271 		// else process parent changes as usual.
272 		} else {					
273 			return false;
274 		}
275 		
276 		// clear
277 		myChangeSet.updateAll = false;
278 		
279 		return true;
280 	}
281 
282 	/**
283 	 * Creates and returns an iterable, modifiable snapshot of the specified node list,
284 	 * where the first element is a non-node reference to the first node.
285 	 */
286 	function indexNodes(nodes) {
287 		var h = {}; // head element is not a node.
288 
289 		if (nodes) {
290 			var n = nodes.length, 
291 				i, it = h;
292 			
293 			for (i=0; i< n; ++i) {
294 				it = it.next = {
295 					prev : it,
296 					node : nodes[i]
297 				};
298 			}
299 		}
300 		
301 		return h;
302 	}
303 	
304 	/**
305 	 * Default idFunctions, if id's exist or not.
306 	 */
307 	function getId() {
308 		return this.id;
309 	}
310 
311 	
312 	
313 	// LAYER CLASS
314 	var Layer = aperture.Class.extend( 'aperture.Layer',
315 
316 		/** @lends aperture.Layer# */
317 		{
318 			/**
319 			 * @class A layer represents a set of like graphical elements which are mapped
320 			 * in a spatial node. Layer is the abstract base class of all graphical layers.
321 			 *
322 			 * Layer is abstract and not to be constructed directly.
323 			 * See {@link aperture.PlotLayer#addLayer addLayer} for an example of how to add layers
324 			 * to a vizlet.
325 			 *
326 			 * All layers observe the following mapping:
327 
328 			 * @mapping {Boolean=true} visible
329 			 *   Whether or not a layer item should be displayed.
330 			 *
331 			 * @constructs
332 			 * @factoryMade
333 			 * @extends aperture.Class
334 			 *
335 			 * @param {Object} spec
336 			 *   A specification object that contains initial values for the layer.
337 			 *   
338 			 * @param {aperture.PlotLayer} spec.parent
339 			 *   The parent layer for this layer. May be null.
340 			 *   
341 			 * @param {aperture.canvas.Canvas} spec.parentCanvas
342 			 *   The parent's canvas, never null.
343 			 *   
344 			 * @param {Object} [spec.mappings]
345 			 *   Optional initial simple property : value mappings. More advanced
346 			 *   mappings can be defined post-construction using the {@link #map}
347 			 *   function.
348 			 */
349 			init : function( spec, mappings ) {
350 
351 				spec = spec || {};
352 
353 				/**
354 				 * @private
355 				 * 
356 				 * A Unique layer id string.
357 				 */
358 				this.uid = (nextUid++).toString();
359 
360 				/**
361 				 * @private
362 				 * This layer's parent layer
363 				 */
364 				this.parentLayer_ = spec.parent;
365 
366 				/**
367 				 * @private
368 				 * This layer's root vizlet node.
369 				 */
370 				this.rootNode_ = spec.rootNode;
371 				
372 				/**
373 				 * @private
374 				 * This layer's root vizlet.
375 				 */
376 				this.vizlet_ = spec.vizlet || this;
377 				
378 				/**
379 				 * @private
380 				 * This layer's canvas
381 				 */
382 				this.canvas_ = spec.parentCanvas && spec.parentCanvas.canvas(this.canvasType);
383 
384 				/**
385 				 * @private
386 				 * An object containing the currently mapped event handlers registered by
387 				 * a call to on().  This object is structured as a map of event types to
388 				 * an array of callback functions.
389 				 */
390 				this.handlers_ = {};
391 
392 				/**
393 				 * @private
394 				 * Tracks switches between local and inherited only data.
395 				 */
396 				this.renderedLocalData_ = false;
397 				
398 				
399 				/**
400 				 * @private
401 				 * An array of nodes rendered by this layer.  Generally this
402 				 * list should only be used by the internal logic responsible for the layer
403 				 * rendering management.
404 				 */
405 				this.nodes_ = undefined;
406 
407 				/**
408 				 * @private
409 				 * A data accessor function which returns an array of data items. 
410 				 * The function will take a parent data item as an argument, which will be
411 				 * ignored if data values were set explicitly. Unless data is explicitly set
412 				 * for this layer this function will return an array containing a single local data
413 				 * element of undefined, reflecting an inheritance of the parent data item.
414 				 */
415 				this.dataItems = inherited;
416 
417 				/**
418 				 * @private
419 				 * True if the layer has locally defined data, false if inherited.
420 				 */
421 				this.hasLocalData = false;
422 				
423 				/**
424 				 * @private
425 				 * A hash of visualProperty names to mapping information objects.  Inherits parent's
426 				 * mappings if this layer has a parent.
427 				 */
428 				if( this.parentLayer_ && this.parentLayer_.mappings ) {
429 					// Inherit mappings from parent
430 					this.maps_ = util.viewOf( this.parentLayer_.mappings() );
431 				} else {
432 					// No parent mappings, no inherit
433 					this.maps_ = {};
434 				}
435 
436 				// Add all initial mappings (order is important here)
437 				this.mapAll(spec.mappings);
438 				this.mapAll(mappings);
439 			},
440 
441 			/**
442 			 * Removes a layer from its parent.
443 			 *
444 			 * @returns {aperture.Layer}
445 			 *      This layer.
446 			 */
447 			remove : function( ) {
448 				if (this.parentLayer_) {
449 
450 					// Remove from layer list
451 					this.parentLayer_.layers_ = util.without( this.parentLayer_.layers_, this );
452 					this.parentLayer_ = null;
453 
454 					// remove all graphics
455 					var c;
456 					for (c = this.nodes_; c != null; c = c.next) {
457 						removeNode(c);
458 					}
459 					
460 					this.nodes_ = null;
461 				}
462 
463 				return this;
464 			},
465 
466 			/**
467 			 * Returns a {@link aperture.Mapping Mapping} for a given graphic property
468 			 * to map it from source values. Map is a key function in layers, responsible
469 			 * for the transformation of data into visuals. Mappings inherit from parent
470 			 * mappings in the layer hierarchy unless cleared or overridden.
471 			 *
472 			 * @param {String} graphicProperty
473 			 *      The graphic property to return a map for.
474 			 *
475 			 * @returns {aperture.Mapping}
476 			 *      A mapping for this property.
477 			 */
478 			map : function ( graphicProperty ) {
479 				var maps = this.maps_;
480 				
481 				// If already have our own local mapping for this, return it
482 				if( maps.hasOwnProperty(graphicProperty) ) {
483 					return maps[graphicProperty];
484 				} 
485 
486 				// Else must derive a mapping from the parent's mapping 
487 				// This allows us to first map 'x' in a child layer and then
488 				// map 'x' in the parent and the mappings will still be shared
489 				var mapping = this.parentLayer_? 
490 					util.viewOf(this.parentLayer_.map( graphicProperty )) :
491 						new namespace.Mapping(graphicProperty);
492 
493 				return (maps[graphicProperty] = mapping);
494 			},
495 
496 			/**
497 			 * Takes an object and maps all properties as simple values.
498 			 *
499 			 * @param {Object} propertyValues
500 			 *      The object with property values to map.
501 			 *
502 			 * @returns {aperture.Layer}
503 			 *      This layer.
504 			 */
505 			mapAll : function ( propertyValues ) {
506 				forEach(propertyValues, function(value,key) {
507 					this.map(key).asValue(value);
508 				}, this);
509 			},
510 
511 			/**
512 			 * Returns an object with properties and their mappings.
513 			 * @returns {Object} An object with properties and their mappings.
514 			 */
515 			mappings : function( ) {
516 				return this.maps_;
517 			},
518 
519 			/**
520 			 * @private
521 			 * Returns the value for a supplied visual property given the  object that
522 			 * will be the source of the data for the mapping.  If the name of the property
523 			 * does not have a corresponding mapping undefined will be returned.
524 			 *
525 			 * @param {String} property
526 			 *      The name of the visual property for which a value is requested
527 			 * @param {Object} dataItem
528 			 *      The data item that will be used as the data source for the mapping
529 			 * @param {Object} [defaultValue]
530 			 *      An optional default value that will be returned if a mapping for this
531 			 *      visual property does not exist.
532 			 * @param {Number} [index]
533 			 *      One or more optional indexes to use if this is an array-based visual property
534 			 *
535 			 * @returns the value of the visual property based on the mapping or undefined
536 			 * if no mapping is defined.
537 			 */
538 			valueFor : function( property, dataItem, defaultValue, index ) {
539 				// NOTE TO SELF: would be more optimal if index... was an array rather than args
540 
541 				var mapping = this.maps_[property];
542 				if( mapping ) {
543 					// Create arguments to pass to "valueFor" [layer, dataItem, index, ...]
544 					var args = Array.prototype.slice.call(arguments, 3);
545 					var value = mapping.valueFor( dataItem, args );
546 
547 					if (value != null) {
548 						return value;
549 					}
550 				}
551 				// No parent, no value, use default (or return undefined)
552 				return defaultValue;
553 			},
554 
555 			/**
556 			 * @private
557 			 * Returns one or more values transformed using registered mappings. This method
558 			 * is similar to valueFor but excludes the data lookup.
559 			 *
560 			 * @param {Object|String,Object} properties
561 			 *      Named property values to transform using the layer's mapping, supplied
562 			 *      as an object or a name argument and value argument.
563 			 *
564 			 * @returns the values of the visual properties as an object if called with an object,
565 			 * 		or as a single transformed value if called with name, value arguments. If
566 			 * 		no mapping exists this method will return undefined.
567 			 */
568 			transform : function( properties, value, filterData, filterIndex ) {
569 				var mapping;
570 				
571 				if (properties) {
572 					if (arguments.length > 1) {
573 						if (mapping = this.maps_[properties]) {
574 							return mapping.value( value, filterData, filterIndex );
575 						}
576 					} else {
577 						var mapped = {};
578 						var maps = this.maps_;
579 						
580 						forEach(properties, function(value, value) {
581 							if (mapping = maps[name]) {
582 								mapped[name] = mapping.value( value, filterData, filterIndex );
583 							}
584 						});
585 						
586 						return mapped;
587 					}
588 				}
589 			},
590 
591 			/**
592 			 * @private
593 			 * Returns the values for a supplied set of visual properties given the object that
594 			 * will be the source of the data for the mapping.  If the name of the property
595 			 * does not have a corresponding mapping undefined will be returned.
596 			 *
597 			 * @param {Object} properties
598 			 *      The visual properties for which values are requested, with default
599 			 *      values.
600 			 * @param {Object} dataItem
601 			 *      The data item that will be used as the data source for the mapping
602 			 * @param {Object} [index]
603 			 *      An optional index to use if this is an indexed set of visual properties
604 			 *
605 			 * @returns {Object} the values of the visual properties based on the mappings.
606 			 *
607 			 */
608 			valuesFor : function( properties, dataItem, index ) {
609 				var property, mapping, value, values= {};
610 
611 				for (property in properties) {
612 					if (properties.hasOwnProperty(property)) {
613 						values[property] = (mapping = this.maps_[property]) &&
614 							(value = mapping.valueFor( dataItem, index || [] )) != null?
615 									value : properties[property];
616 					}
617 				}
618 
619 				return values;
620 			},
621 
622 			/**
623 			 * @private
624 			 * The type of canvas that this layer requires to render.  At minimum,
625 			 * the following types are supported:
626 			 * <ul>
627 			 * <li>aperture.canvas.DIV_CANVAS</li>
628 			 * <li>aperture.canvas.VECTOR_CANVAS</li>
629 			 * </ul>
630 			 * The canvasType property is used by parent layers to attempt to provide the
631 			 * desired {@link aperture.Layer.Node} to this layer during
632 			 * render.
633 			 */
634 			canvasType : aperture.canvas.DIV_CANVAS,
635 
636 
637 			/**
638 			 * Returns the logical set of all layer nodes, or (re)declares it by providing source data
639 			 * for each node to be mapped from. 
640 			 *
641 			 * @param {Array|Object|Function} data
642 			 *      the array of data objects, from which each node will be mapped.  May be an array 
643 			 *      of data objects, a single data object, or a function that subselects data objects
644 			 *      from each parent data object.  If an array of data is given a graphic
645 			 *      will be created for each item in the array.  If the parent layer has more than
646 			 *      one data item, data items will be rendered per parent data
647 			 *      item.  
648 			 *      
649 			 * @param {Function|String} [idFunction]
650 			 *      optionally a function or field name that supplies the id for a data item to
651 			 *      match items from one update to another. If a function is supplied it will be called 
652 			 *      with the item as a parameter. If not supplied, id functions will be remembered from 
653 			 *      previous calls to this method, but can be cleared by specifying null. If never
654 			 *      supplied, a best guess is made using item.id for matching if found in the data set 
655 			 *      supplied, or exact object instances if not.
656 			 *      
657 			 * @returns {aperture.Layer.NodeSet}
658 			 *      the logic set of all layer nodes.
659 			 */
660 			all : function ( data, idFunction ) {
661 				return this.join.apply( this, arguments ); // not implemented yet.
662 			},
663 
664 			/**
665 			 * Merges in new data, returning the logical set of all layer nodes. This method differs
666 			 * from {@link #all} only in that it compares the new data set to the old data set and if 
667 			 * the same node is identified in both it will update the existing one rather than creating a
668 			 * new one. A common use case for joins is to animate transitions between data sets.
669 			 */
670 			join : function( data, idFunction ) {
671 				if (arguments.length !== 0) {
672 					this.dataItems = inherited;
673 					this.hasLocalData = false;
674 					
675 					// Set new data mapping/array if given
676 					if ( data ) {
677 						this.hasLocalData = true;
678 						
679 						// Mapping function for parent data
680 						if( util.isFunction(data) ) {
681 							this.dataItems = data;
682 							data = null;
683 							
684 						} else {
685 							// If not an array, assume a single data object, create an array of 1
686 							if ( !util.isArray(data) ) {
687 								data = [data];
688 							}
689 							this.dataItems = function() {
690 								return data;
691 							};
692 							this.dataItems.values = data;
693 						}
694 					}
695 					
696 					// handle simple field names as well as functions.
697 					if ( idFunction !== undefined ) {
698 						if ( util.isString(idFunction) ) {
699 							this.idFunction = idFunction === 'id'? getId : function() {
700 								return this[idFunction];
701 							};
702 						} else {
703 							this.idFunction = idFunction;
704 						}
705 						
706 					} else if (!this.idFunction) {
707 						// best guess: use id if it seems to be there, otherwise test the instance.
708 						this.idFunction = data && data.length && data[0].id? getId : null;
709 					}
710 					
711 					// mark changed for next render loop.
712 					this.dataChanged = true;
713 				}
714 				
715 				return new aperture.Layer.LogicalNodeSet(this);
716 			},
717 			
718 			/**
719 			 * TODO: implement. Adds to the logical set of all layer nodes, returning the set of added items.
720 			 * 
721 			 * @param {Array|Object} data
722 			 *      the array of data objects, from which each node will be mapped.  May be an array 
723 			 *      of data objects or a single data object, and may not be a data subselection function.  
724 			 *      If this layer already gets its data from a subselection function set through {@link #all} 
725 			 *      or {@link #join}, this function will fail.
726 			 *      
727 			 * @returns {aperture.Layer.NodeSet}
728 			 *      the set of added layer nodes.
729 			 */
730 			add : function( data ) {
731 				
732 			},
733 			
734 			/**
735 			 * @private
736 			 * Forms the change list for this layer and returns it.  An object containing information about the data or
737 			 * visual changes as they pertain to the parent layer is provided.
738 			 * 
739 			 * @param {Object} parentChangeSet
740 			 * @param {Array} parentChangeSet.updates a list of visible Nodes that are added or changed.
741 			 * this is the list that a graphic child should redraw.
742 			 * @param {Array} parentChangeSet.added a list of new Node objects pertaining to added data
743 			 * @param {Array} parentChangeSet.changed a list of visible Node objects pertaining to changed data.
744 			 * @param {Array} parentChangeSet.removed a list of Nodes that should be removed due to the
745 			 * removal of the corresponding data
746 			 *
747 			 * @returns {Object}
748 			 *      the changeSet object that this layer may be given to render itself
749 			 */
750 			processChangeSet : function ( parentChangeSet ) {
751 				
752 				var myChangeSet = util.viewOf( parentChangeSet ),
753 					myUid = this.uid,
754 					hasLocalData = this.hasLocalData,
755 					c, i, n;
756 
757 				// inherit most things but not these
758 				var chgs = myChangeSet.changed = [],
759 					adds = myChangeSet.added = [],
760 					rmvs = myChangeSet.removed = [];
761 				
762 				// is data changed locally or in a parent that we subselect from?
763 				myChangeSet.dataChanged = this.dataChanged || (parentChangeSet.dataChanged && hasLocalData && !this.dataItems.values);
764 
765 				
766 				// reset now that we're going to process.
767 				this.dataChanged = false;
768 
769 				
770 				// SHORTCUT REMOVAL
771 				// if we rendered local data last time and not this, or vice versa,
772 				// we need to destroy everything and rebuild to respect new orders of data.
773 				if (this.renderedLocalData_ != hasLocalData) {
774 					this.renderedLocalData_ = hasLocalData;
775 	
776 					for (c = this.nodes_; c != null; c = c.next) {
777 						rmvs.push(c); // don't need to unlink - we are resetting the list.
778 					}
779 					
780 					this.nodes_ = null; // trigger rebuild below
781 				}
782 				
783 				
784 				var prev, dad;
785 				
786 				// SHORTCUT REBUILD
787 				// if complete build, spawn all new nodes.
788 				if ( !this.nodes_ ) {
789 					for (dad = (this.parentLayer_ && this.parentLayer_.nodes_) || this.rootNode_; dad != null; dad = dad.next) {
790 						forEach( this.dataItems( dad.data ), function( dataItem ) {
791 							adds.push( prev = addNode( this, dad, prev, dataItem ) );
792 							
793 						}, this);
794 					}
795 					
796 					// if we are in the change set but have no nodes of our own, implicitly
797 					// select all children. set this flag for descendants to find.
798 					if ( !this.nodes_ && myChangeSet.rootSet.hasLayer(this) ) {
799 						myChangeSet.updateAll = true;
800 					}
801 					
802 					
803 				// NO DATA OF OUR OWN?
804 				// when we own data we maintain a node set PER parent node, else there is one per parent node.
805 				// if we didn't build have been this way before and we know we can trust the list of parent changes.
806 				} else if( !hasLocalData || !processDataChanges.call( this, myChangeSet, parentChangeSet )) {
807 					
808 					// REMOVE ALL MY CHILDREN OF REMOVED
809 					forEach( parentChangeSet.removed, function(dad) {
810 						var mine = dad.kids[myUid];
811 						
812 						n = mine && mine.length;
813 							
814 						// append to removals and remove from local linked list.
815 						if (n) {
816 							for (i=0; i<n; ++i) {
817 								rmvs.push( c = mine[i] );
818 								unlinkNode(c);
819 							}
820 						}
821 						
822 					}, this);
823 					
824 					// CHANGE ALL MY VISIBLE CHILDREN OF CHANGED
825 					// notice currently that a change to a parent means a change to all children.
826 					forEach( parentChangeSet.changed, function(dad) {
827 						var mine = dad.kids[myUid];
828 						n = mine && mine.length;
829 						
830 						if (n) {
831 							for (i=0; i<n; ++i) {
832 								if (updateVisibility( c = mine[i] )) {
833 									chgs.push(c);
834 								}
835 							}
836 						}
837 						
838 					}, this);
839 
840 					// THEN ADD ALL CHILDREN OF ADDS.
841 					// then finally process all adds. we do this last so as not to search these in change matching
842 					forEach( parentChangeSet.added, function(dad) {
843 						var pk = dad.prev && dad.prev.kids[myUid];
844 						
845 						// insert in the same place locally as in parent, though it doesn't really matter.
846 						prev = pk && pk.length && pk[pk.length-1];
847 						
848 						forEach( this.dataItems( dad.data ), function( dataItem ) {
849 							adds.push(prev = addNode( this, dad, prev, dataItem ));
850 							
851 						}, this);
852 						
853 					}, this);
854 					
855 				}
856 	
857 				
858 
859 				// CLEAN UP REMOVALS
860 				// finish processing all removals by destroying their graphics.
861 				forEach( rmvs, function(c) {
862 					removeNode(c);
863 				}, this);
864 
865 			
866 				
867 				// ALSO ANY OF MY NODES MARKED INDEPENDENTLY AS CHANGED
868 				if (myChangeSet.rootSet.hasLayer(this)) {
869 					for (i = myChangeSet.rootSet.nodes(this); (c = i.next()) != null;) {
870 						// only add to list if showing (removals will not be showing either) and not already there
871 						// Add node to list of changes (if not already there)
872 						if( indexOf(chgs, c) === -1 && indexOf(adds, c) === -1 && updateVisibility(c) ) {
873 							chgs.push(c); // TODO: hash?
874 						}
875 					}
876 				}
877 
878 				
879 				// FORM JOINED LIST OF UPDATED NODES
880 				// adds always propagate down, but not changes if they are not visible.
881 				// form the list here of everything that need drawing/redrawing.
882 				if (adds.length !== 0) {
883 					var draw = myChangeSet.updates = myChangeSet.changed.splice();
884 					
885 					// on construction we did not create graphics unless it was visible
886 					forEach(adds, function(c) {
887 						if (c.graphics !== NO_GRAPHICS) {
888 							draw.push(c);
889 						}
890 					}, this);
891 					
892 				} else {
893 					myChangeSet.updates = myChangeSet.changed;
894 					
895 				}
896 				
897 				
898 				// DEBUG - log all updates.
899 				if ( log.isLogging(log.LEVEL.DEBUG ) ) {
900 					var alist = ' + ', clist = ' * ', rlist= ' - ';
901 					
902 					forEach(myChangeSet.added, function(c){
903 						alist+= c.uid + ', ';
904 					});
905 					forEach(myChangeSet.changed, function(c){
906 						clist+= c.uid + ', ';
907 					});
908 					forEach(myChangeSet.removed, function(c){
909 						rlist+= c.uid + ', ';
910 					});
911 					
912 					log.debug('>> ' + this.typeOf());
913 					log.debug(alist);
914 					log.debug(clist);
915 					log.debug(rlist);
916 				}
917 				
918 				return myChangeSet;
919 			},
920 			
921 
922 			/**
923 			 * Brings this layer to the front of its parent layer.
924 			 * 
925 			 * @returns {this}
926 			 *      this layer
927 			 */
928 			toFront : function () {
929 				if (this.parentLayer_) {
930 					var p = this.parentLayer_.layers_,
931 						i = indexOf(p, this),
932 						c;
933 					if (i !== p.length-1) {
934 						p.push(p.splice(i, 1)[0]);
935 						
936 						for (c = this.nodes_; c != null; c = c.next) {
937 							c.graphics.toFront();
938 						}
939 					}
940 				}
941 				return this;
942 			},
943 			
944 			/**
945 			 * Pushes this layer to the back of its parent layer.
946 			 * 
947 			 * @returns {this}
948 			 *      this layer
949 			 */
950 			toBack : function () {
951 				if (this.parentLayer_) {
952 					var p = this.parentLayer_.layers_,
953 						i = indexOf(p, this), 
954 						c;
955 					if (i !== 0) {
956 						p.splice(0,0,p.splice(i, 1)[0]);
957 						
958 						for (c = this.nodes_; c != null; c = c.next) {
959 							c.graphics.toBack();
960 						}
961 					}
962 				}
963 				return this;
964 			},
965 			
966 			/**
967 			 * @private
968 			 * The render function is called by the default implementation of a parent layer render()
969 			 * should be implemented to actually perform this layer's render logic.
970 			 * The changeSet object will contain Node objects that pertain to this
971 			 * layer's data.
972 			 *
973 			 * If this layer is responsible for drawing visual items, this function should
974 			 * update all visuals as described by the adds, changes, and removes in the
975 			 * changeSet object.  The Node objects provided in the changeSet object are owned
976 			 * by this layer and not shared with any other layer.  This layer is free to
977 			 * modify the Node.userData object and store any data-visual specific
978 			 * objects.  The same Node object will be maintained through all calls
979 			 * to render thoughout the life of the associated data object.
980 			 *
981 			 * @param {Object} changeSet
982 			 * @param {Array} changeSet.updates a list of visible Nodes that are added or changed.
983 			 * this is the list that a graphic child should redraw.
984 			 * @param {Array} changeSet.added a list of new Node objects pertaining to added data
985 			 * @param {Array} changeSet.changed a list of visible Node objects pertaining to changed data
986 			 * @param {Array} changeSet.removed a list of Nodes that should be removed due to the
987 			 * removal of the corresponding data
988 			 */
989 			render : function( changeSet ) {
990 			},
991 
992 			/**
993 			 * Registers a callback function for a given event type on the visuals
994 			 * drawn by this layer.  Valid event types include DOM mouse events plus some
995 			 * custom events:
996 			 * <ul>
997 			 * <li>click</li>
998 			 * <li>dblclick</li>
999 			 * <li>mousedown</li>
1000 			 * <li>mousemove</li>
1001 			 * <li>mouseout</li>
1002 			 * <li>mouseover</li>
1003 			 * <li>mouseup</li>
1004 			 * <li>touchstart</li>
1005 			 * <li>touchmove</li>
1006 			 * <li>touchend</li>
1007 			 * <li>touchcancel</li>
1008 			 * <li>drag</li>
1009 			 * <li>dragstart*</li>
1010 			 * <li>dragend*</li>
1011 			 * </ul>
1012 			 *
1013 			 * Returning a truthy value from a callback indicates that the event is consumed
1014 			 * and should not be propogated further.<br><br>
1015 			 * 
1016 			 * *Note that registration for <code>drag</code> events will result in the drag
1017 			 * handler being called for drag, dragstart, and dragend events, distinguishable
1018 			 * by the eventType property of the Event object. Attempts to register for dragstart and
1019 			 * dragend events individually will have no effect.
1020 			 * 
1021 			 * @param {String} eventType
1022 			 *      the DOM event name corresponding to the event type for which this callback
1023 			 *      will be registered
1024 			 * @param {Function} callback
1025 			 *      the callback function that will be called when this event is triggered.
1026 			 *      The callback function will be called in the this-node of this layer.
1027 			 *      The function will be passed an object of type {@link aperture.Layer.Event}
1028 			 */
1029 			on : function( eventType, callback ) {
1030 				var h = this.handlers_, c;
1031 				
1032 				if (!h[eventType]) {
1033 					h[eventType] = [callback];
1034 					
1035 					// need one hook only for all clients
1036 					for (c = this.nodes_; c != null; c = c.next) {
1037 						c.graphics.on(eventType, this);
1038 					}
1039 					
1040 				} else {
1041 					h[eventType].push(callback);
1042 				}
1043 			},
1044 
1045 			/**
1046 			 * Removes a registered callback(s) for the given event type.
1047 			 *
1048 			 * @param {String} eventType
1049 			 *      the DOM event name corresponding to the event type to unregister
1050 			 * @param {Function} [callback]
1051 			 *      an optional callback function.  If given this specific callback
1052 			 *      is removed from the event listeners on this layer.  If omitted,
1053 			 *      all callbacks for this eventType are removed.
1054 			 */
1055 			off : function( eventType, callback ) {
1056 				var h = this.handlers_, c;
1057 				
1058 				if( callback ) {
1059 					h[eventType] = util.without( h[eventType], callback );
1060 				} else {
1061 					h[eventType] = [];
1062 				}
1063 				
1064 				// all handlers gone for this? then remove hook.
1065 				if (h[eventType].length === 0) {
1066 					for (c = this.nodes_; c != null; c = c.next) {
1067 						c.graphics.off(eventType, this);
1068 					}
1069 					
1070 					h[eventType] = null;
1071 				}
1072 			},
1073 
1074 			/**
1075 			 * Fires the specified event to all handlers for the given event type.
1076 			 *
1077 			 * @param {String} eventType
1078 			 *      the DOM event name corresponding to the event type to fire
1079 			 * @param {aperture.Layer.Event} event
1080 			 *      the event object that will be broadcast to all listeners
1081 			 */
1082 			trigger : function( eventType, e ) {
1083 				var r = util.forEachUntil( this.handlers_[eventType], function( listener ) {
1084 					return listener.call(this, e);
1085 				}, true, this);
1086 				
1087 				if (r && e && e.source) {
1088 					e = e.source;
1089 					
1090 					if (e.stopPropagation) {
1091 						e.stopPropagation();
1092 					} else {
1093 						e.cancelBubble = true;
1094 					}
1095 				}
1096 
1097 				return r;
1098 			},
1099 
1100 			/**
1101 			 * Returns the parent (if it exists) of this layer.
1102 			 */
1103 			parent : function() {
1104 				return this.parentLayer_;
1105 			},
1106 
1107 
1108 			/**
1109 			 * Returns the containing vizlet for this layer.
1110 			 */
1111 			vizlet : function() {
1112 				return this.vizlet_;
1113 			}
1114 			
1115 		}
1116 	);
1117 
1118 	// expose item
1119 	namespace.Layer = Layer;
1120 
1121 
1122 
1123 	var PlotLayer = Layer.extend( 'aperture.PlotLayer',
1124 	/** @lends aperture.PlotLayer# */
1125 	{
1126 		/**
1127 		 * @class An extension of layer, Plot layers can contain child layers.
1128 		 * @augments aperture.Layer
1129 		 *
1130 		 * @constructs
1131 		 * @factoryMade
1132 		 */
1133 		init : function(spec, mappings) {
1134 			aperture.Layer.prototype.init.call(this, spec, mappings);
1135 
1136 			/**
1137 			 * @private
1138 			 * An array of child layer objects
1139 			 */
1140 			this.layers_ = [];
1141 
1142 		},
1143 
1144 		/**
1145 		 * Creates and adds a child layer of the specified type.
1146 		 * Child layers will inherit all mappings and data from their parent layer.
1147 		 *
1148 		 * @example
1149 		 * plot.addLayer( aperture.LabelLayer, {
1150 		 *      font-family: 'Segoe UI',
1151 		 *      fill: 'white'
1152 		 * });
1153 		 *
1154 		 * @param {aperture.Layer} layer
1155 		 *      The type of layer to construct and add.
1156 		 *
1157 		 * @param {Object} [mappings]
1158 		 *      Optional initial simple property : value mappings. More advanced
1159 		 *      mappings can be defined post-construction using the {@link #map}
1160 		 *      function.
1161 		 *
1162 		 * @param {Object} [spec]
1163 		 *      An optional object containing specifications to pass to the layer constructor.
1164 		 *      This specification will be extended with parent and canvas information.
1165 		 *
1166 		 * @returns {aperture.Layer}
1167 		 *      the created child layer
1168 		 */
1169 		addLayer : function( layerCtor, mappings, spec ) {
1170 
1171 			spec = spec || {};
1172 
1173 			util.extend( spec, {
1174 					parent : this,
1175 					vizlet : this.vizlet_,
1176 					rootNode : this.rootNode_,
1177 					parentCanvas : this.canvas_
1178 				}, this.layerSpec_ );
1179 
1180 			var layer = new layerCtor(spec, mappings);
1181 
1182 			// Add to layer list
1183 			this.layers_.push( layer );
1184 
1185 			return layer;
1186 		},
1187 
1188 		/**
1189 		 * @private
1190 		 * 
1191 		 * Overrides the base Layer implementation of render to draw children.
1192 		 */
1193 		render : function( changeSet ) {
1194 			
1195 			if ( log.isLogging(log.LEVEL.DEBUG ) ) {
1196 				log.indent(4);
1197 			}
1198 			
1199 			// invoke draw of all child layers after building a change set for each.
1200 			forEach( this.layers_, function (layer) {
1201 				this.renderChild( layer, layer.processChangeSet(changeSet) );
1202 				
1203 			}, this);
1204 
1205 			if ( log.isLogging(log.LEVEL.DEBUG ) ) {
1206 				log.indent(-4);
1207 			}
1208 			
1209 		},
1210 
1211 		/**
1212 		 * @private
1213 		 * 
1214 		 * Overridden to remove and clean up child layers.
1215 		 */
1216 		remove : function( ) {
1217 			if (this.parentLayer_) {
1218 				aperture.Layer.prototype.remove.call(this);
1219 				
1220 				// destroye all sublayers
1221 				forEach( this.layers_, function (layer) {
1222 					layer.remove();
1223 				});
1224 				
1225 				this.layers_ = [];
1226 			}
1227 
1228 			return this;
1229 		},
1230 
1231 		/**
1232 		 * @private
1233 		 * Subclasses of PlotLayer may override this function and update the provided
1234 		 * Node objects that are bound for the given child layer before
1235 		 * rendering it.
1236 		 * For example, a plot layer that alters the size of the canvases
1237 		 * that its children should render to can update the node position and
1238 		 * width/height fields in the provided nodes before they are passed
1239 		 * down to the child layer.
1240 		 *
1241 		 * Note that this is called for each child layer.  If all child layers should
1242 		 * get the same modifications to their render nodes, changes can be made
1243 		 * once to this layer's nodes in render.  These changes will be applied
1244 		 * before the call to this function.
1245 		 * 
1246 		 * @param {aperture.Layer} layer
1247 		 *      The child layer that for which this set of nodes is bound
1248 		 * @param {Object} changeSet
1249 		 *      The changeSet object destined for the given layer
1250 		 * @param {Array} changeSet.updates 
1251 		 *      a list of visible Nodes that are added or changed.
1252 		 *      this is the list that a graphic child should redraw.
1253 		 * @param {Array} changeSet.added
1254 		 *      a list of new Node objects pertaining to added data
1255 		 * @param {Array} changeSet.changed
1256 		 *      a list of visible Node objects pertaining to changed data
1257 		 * @param {Array} changeSet.removed
1258 		 *      a list of Nodes that should be removed due to the
1259 		 *      removal of the corresponding data
1260 		 *
1261 		 */
1262 		renderChild : function( layer, changeSet ) {
1263 			layer.render( changeSet );
1264 		}
1265 		
1266 	});
1267 
1268 	namespace.PlotLayer = PlotLayer;
1269 	
1270 	/* ******************************************************************************* */
1271 
1272 	/**
1273 	 * @name aperture.Layer.Node
1274 	 * @class A Node object contains information and methods that layer implementations
1275 	 * can use to obtain the constructs they need to render their content.  For example, the node
1276 	 * provides a vector graphics interface which child layers may use to create and manage their
1277 	 * visual representations.
1278 	 * 
1279 	 * @private
1280 	 */
1281 
1282 	/**
1283 	 * @name aperture.Layer.Node#data
1284 	 * @type Object
1285 	 * @description the data item that to which this node pertains.
1286 	 * 
1287 	 * @private
1288 	 */
1289 
1290 	/**
1291 	 * @name aperture.Layer.Node#parent
1292 	 * @type aperture.Layer.Node
1293 	 * @description an explicit reference to the parent render node for this node, if it
1294 	 * exists.  Generally a node will inherit all properties of its parent but it is occasionally
1295 	 * useful to be able to access the unadulterated values such as position.
1296 	 * 
1297 	 * @private
1298 	 */
1299 
1300 	/**
1301 	 * @name aperture.Layer.Node#userData
1302 	 * @type Object
1303 	 * @description an object that can be freely used by the rendering layer to store
1304 	 * information.  Since the same node object will be given to the layer on subsequent
1305 	 * renders of the same data item the layer can store information that allows rendering to
1306 	 * be more efficient, for example visual objects that are created and can be reused.
1307 	 * 
1308 	 * @private
1309 	 */
1310 
1311 	/**
1312 	 * @name aperture.Layer.Node#width
1313 	 * @type Number
1314 	 * @description The width of the canvas in pixels.  If the child layer does not have a mapping
1315 	 * that specifies the render width of its visuals, the canvas size should be used.
1316 	 * 
1317 	 * @private
1318 	 */
1319 
1320 	/**
1321 	 * @name aperture.Layer.Node#height
1322 	 * @type Number
1323 	 * @description The height of the canvas in pixels.  If the child layer does not have a mapping
1324 	 * that specifies the render width of its visuals, the canvas size should be used.
1325 	 * 
1326 	 * @private
1327 	 */
1328 
1329 	/**
1330 	 * @name aperture.Layer.Node#position
1331 	 * @type Array
1332 	 * @description The [x,y] position in pixels within the canvas that the child visual should
1333 	 * draw itself.  Typically top-level visuals will be positioned at [0,0] and will be expected
1334 	 * to fill the entire canvas (as dictated by width/height).  Otherwise, child visuals should
1335 	 * translate the local-coordinate point specified by {@link #anchorPoint} to this position
1336 	 * within the canvas.
1337 	 * 
1338 	 * @private
1339 	 */
1340 
1341 	/**
1342 	 * @name aperture.Layer.Node#anchorPoint
1343 	 * @type Array
1344 	 * @description The anchor point is an [x,y] position in [0,1] space that specifies how the child
1345 	 * layer should draw its visuals with respect to the provided canvas {@link #position}.  The x-anchor
1346 	 * point is in the range [0,1] where 0 represents an anchor on the left edge of the visual and 1
1347 	 * represents an anchor on the right edge.  The y-anchor point is also in the range [0,1] where
1348 	 * 0 represents an anchor on the top edge and 1 represents an anchor on the bottom edge.  [0.5, 0.5]
1349 	 * would mean the child visual is centered on the provided canvas {@link #position}.
1350 	 * 
1351 	 * @private
1352 	 */
1353 
1354 	/**
1355 	 * @name aperture.Layer.Node#graphics
1356 	 * @type aperture.canvas.Graphics
1357 	 * @description A graphics interface with which to create and update graphics, typically
1358 	 * a {@link aperture.canvas.VectorGraphics VectorGraphics} object.
1359 	 * 
1360 	 * @private
1361 	 */
1362 
1363 	/* ******************************************************************************* */
1364 
1365 	/**
1366 	 * @name aperture.Layer.Event
1367 	 * @class An event object that is passed to handlers upon the trigger of a requested
1368 	 * event.
1369 	 */
1370 
1371 	/**
1372 	 * @name aperture.Layer.Event#eventType
1373 	 * @type String
1374 	 * @description the type of the event being triggered
1375 	 */
1376 
1377 	/**
1378 	 * @name aperture.Layer.Event#source
1379 	 * @type Object
1380 	 * @description the source event
1381 	 */
1382 
1383 	/**
1384 	 * @name aperture.Layer.Event#data
1385 	 * @type Object
1386 	 * @description the data object for the node that triggered the event
1387 	 */
1388 
1389 	/**
1390 	 * @name aperture.Layer.Event#node
1391 	 * @type aperture.Layer.NodeSet
1392 	 * @description the node that triggered the event
1393 	 */
1394 
1395 	/**
1396 	 * @name aperture.Layer.Event#index
1397 	 * @type Array
1398 	 * @description an optional property that contains the index into the data item
1399 	 * in the case that the data item contains a sequence of values, such as a line
1400 	 * series.  In the case of indexed values, this field will be an array
1401 	 * of indicies in the order they are referred to in the mappings.  For example,
1402 	 * ${a[].b[].c} will have two items in the index array.  Otherwise, undefined.
1403 	 */
1404 
1405 	/**
1406 	 * @name aperture.Layer.Event#dx
1407 	 * @type Number
1408 	 * @description when dragging, the cumulative x offset, otherwise undefined.
1409 	 */
1410 
1411 	/**
1412 	 * @name aperture.Layer.Event#dy
1413 	 * @type Number
1414 	 * @description when dragging, the cumulative y offset, otherwise undefined.
1415 	 */
1416 
1417 
1418 	return namespace;
1419 
1420 }(aperture || {}));
1421