1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 'use strict'; 6 7 base.requireStylesheet('ui.quad_stack'); 8 9 base.require('base.properties'); 10 base.require('base.bbox2'); 11 base.require('base.quad'); 12 base.require('base.utils'); 13 base.require('base.raf'); 14 base.require('ui.quad_view'); 15 base.require('cc.region'); 16 base.require('ui.camera'); 17 base.require('ui.rect_view'); 18 19 base.exportTo('ui', function() { 20 var QuadView = ui.QuadView; 21 22 function validateQuads(quads) { 23 for (var i = 0; i < quads.length; i++) { 24 if (quads[i].stackingGroupId === undefined) 25 throw new Error('All quads must have stackingGroupIds'); 26 } 27 } 28 29 /** 30 * @constructor 31 */ 32 var QuadStack = ui.define('quad-stack'); 33 34 QuadStack.prototype = { 35 __proto__: HTMLUnknownElement.prototype, 36 37 decorate: function() { 38 this.contentContainer_ = document.createElement('view-container'); 39 this.appendChild(this.contentContainer_); 40 this.viewport_ = undefined; 41 this.worldViewportRectView_ = new ui.RectView(); 42 this.quads_ = undefined; 43 }, 44 45 initialize: function(unpaddedWorldRect, opt_worldViewportRect) { 46 this.viewport_ = new ui.QuadViewViewport(unpaddedWorldRect); 47 48 this.viewport_.addEventListener('change', function() { 49 this.worldViewportRectView_.viewport = this.viewport_; 50 }.bind(this)); 51 52 this.worldViewportRect_ = base.Rect.FromXYWH( 53 opt_worldViewportRect.x || 0, 54 opt_worldViewportRect.y || 0, 55 opt_worldViewportRect.width, 56 opt_worldViewportRect.height 57 ); 58 59 this.worldViewportRectView_.viewport = this.viewport_; 60 this.worldViewportRectView_.rect = this.worldViewportRect_; 61 }, 62 63 get layers() { 64 return this.layers_; 65 }, 66 67 set layers(newValue) { 68 base.setPropertyAndDispatchChange(this, 'layers', newValue); 69 }, 70 71 get quads() { 72 return this.quads_; 73 }, 74 75 set quads(quads) { 76 validateQuads(quads); 77 this.quads_ = quads; 78 this.updateContents_(); 79 }, 80 81 get viewport() { 82 return this.viewport_; 83 }, 84 85 get worldViewportRect() { 86 return this.worldViewportRect_; 87 }, 88 89 get worldViewportRectView() { 90 return this.worldViewportRectView_; 91 }, 92 93 get contentContainer() { 94 return this.contentContainer_; 95 }, 96 97 updateContents_: function() { 98 // Build the stacks. 99 var stackingGroupsById = {}; 100 var quads = this.quads; 101 for (var i = 0; i < quads.length; i++) { 102 var quad = quads[i]; 103 if (stackingGroupsById[quad.stackingGroupId] === undefined) 104 stackingGroupsById[quad.stackingGroupId] = []; 105 stackingGroupsById[quad.stackingGroupId].push(quad); 106 } 107 108 // Remove worldViewportRectView to re-insert after Quads. 109 if (this.worldViewportRectView_.parentNode === this.contentContainer_) 110 this.contentContainer_.removeChild(this.worldViewportRectView_); 111 112 // Get rid of old quad views if needed. 113 var numStackingGroups = base.dictionaryValues(stackingGroupsById).length; 114 while (this.contentContainer_.children.length > numStackingGroups) { 115 var n = this.contentContainer_.children.length - 1; 116 this.contentContainer_.removeChild( 117 this.contentContainer_.children[n]); 118 } 119 120 // Helper function to create a new quad view and track the current one. 121 var that = this; 122 var curQuadViewIndex = -1; 123 var curQuadView = undefined; 124 function appendNewQuadView() { 125 curQuadViewIndex++; 126 if (curQuadViewIndex < that.contentContainer_.children.length) { 127 curQuadView = that.contentContainer_.children[curQuadViewIndex]; 128 } else { 129 curQuadView = new QuadView(); 130 that.contentContainer_.appendChild(curQuadView); 131 } 132 curQuadView.quads = undefined; 133 curQuadView.viewport = that.viewport_; 134 curQuadView.pendingQuads = []; 135 curQuadView.region = new cc.Region(); 136 return curQuadView; 137 } 138 139 appendNewQuadView(); 140 for (var stackingGroupId in stackingGroupsById) { 141 var stackingGroup = stackingGroupsById[stackingGroupId]; 142 var bbox = new base.BBox2(); 143 stackingGroup.forEach(function(q) { bbox.addQuad(q); }); 144 var bboxRect = bbox.asRect(); 145 146 if (curQuadView.region.rectIntersects(bboxRect)) 147 appendNewQuadView(); 148 curQuadView.region.rects.push(bboxRect); 149 stackingGroup.forEach(function(q) { 150 curQuadView.pendingQuads.push(q); 151 }); 152 } 153 154 // Add worldViewportRectView after the Quads. 155 this.contentContainer_.appendChild(this.worldViewportRectView_); 156 157 for (var i = 0; i < this.contentContainer_.children.length; i++) { 158 var child = this.contentContainer_.children[i]; 159 if (child instanceof ui.QuadView) { 160 child.quads = child.pendingQuads; 161 delete child.pendingQuads; 162 } 163 } 164 165 this.viewport.updateBoxSize(this.contentContainer_); 166 this.layers = this.contentContainer_.children; 167 }, 168 169 170 }; 171 172 return { 173 QuadStack: QuadStack 174 }; 175 }); 176