@@ -17,6 +17,11 @@ var PivotView = function (controller, container) {
1717
1818 this . controller = controller ;
1919
20+ /**
21+ * @private
22+ */
23+ this . _scrollListener = null ;
24+
2025 this . init ( ) ;
2126
2227} ;
@@ -39,6 +44,104 @@ PivotView.prototype._columnClickHandler = function (columnIndex) {
3944
4045} ;
4146
47+ /**
48+ * Create clones of headers with fixed sizes.
49+ *
50+ * @param {HTMLElement } tableElement
51+ */
52+ PivotView . prototype . fixHeaders = function ( tableElement ) {
53+
54+ var fhx , temp , hHead , fhy , c1 , c2 , d1 , d2 , st ;
55+
56+ var getChildrenByTagName = function ( element , tagName ) {
57+ var cls = [ ] ;
58+ for ( var c in element . childNodes ) {
59+ if ( element . childNodes [ c ] . tagName === tagName . toUpperCase ( ) ) {
60+ cls . push ( element . childNodes [ c ] ) ;
61+ }
62+ }
63+ return cls ;
64+ } ;
65+
66+ var fixSizes = function ( baseElement , elementToFix ) {
67+
68+ if ( ! elementToFix . style ) return false ;
69+
70+ for ( var i in elementToFix . childNodes ) {
71+ fixSizes ( baseElement . childNodes [ i ] , elementToFix . childNodes [ i ] ) ;
72+ }
73+
74+ if ( baseElement [ "triggerFunction" ] ) {
75+ elementToFix . addEventListener ( "click" , baseElement [ "triggerFunction" ] ) ;
76+ }
77+
78+ var style = window . getComputedStyle ( baseElement , null ) ;
79+ elementToFix . style . width = style . getPropertyValue ( "width" ) ;
80+ elementToFix . style . height = style . getPropertyValue ( "height" ) ;
81+
82+ } ;
83+
84+ if ( ! tableElement . parentNode ) console . warn ( "Missing fix headers: before function call to " +
85+ "fixHeaders() table element must be attached to DOM." ) ;
86+
87+ // clone thead
88+ temp = fhx = getChildrenByTagName ( tableElement , "thead" ) [ 0 ] ;
89+ if ( ! fhx ) {
90+ console . error ( "Unable to fix headers: no \"thead\" in basic table." ) ; return false ;
91+ }
92+ fhx = fhx . cloneNode ( true ) ;
93+ fhx . className = "fixedHeader" ;
94+ fhx . style . zIndex = 2 ;
95+ fixSizes ( temp , fhx ) ;
96+ fhx . style . width = "" ;
97+
98+ // clone top left corner
99+ hHead = temp . childNodes [ 0 ] . childNodes [ 0 ] . cloneNode ( true ) ;
100+ st = window . getComputedStyle ( temp . childNodes [ 0 ] . childNodes [ 0 ] , null ) ;
101+ hHead . style . width = st . getPropertyValue ( "width" ) ;
102+ hHead . style . height = st . getPropertyValue ( "height" ) ;
103+ temp = document . createElement ( "thead" ) ;
104+ temp . appendChild ( document . createElement ( "tr" ) ) . appendChild ( hHead ) ;
105+ temp . className = "fixedHeader" ;
106+ temp . style . zIndex = 3 ;
107+ hHead = temp ;
108+
109+ // clone body headers
110+ temp = fhy = getChildrenByTagName ( tableElement , "tbody" ) [ 0 ] ;
111+ if ( ! fhy ) {
112+ console . error ( "Unable to fix headers: no \"tbody\" in basic table." ) ; return false ;
113+ }
114+ fhy = fhy . cloneNode ( false ) ;
115+ fhy . className = "fixedHeader" ;
116+ fhy . style . top = temp . offsetTop - 2 + "px" ;
117+ c1 = getChildrenByTagName ( temp , "tr" ) ;
118+ for ( var i in c1 ) {
119+ fhy . appendChild ( d1 = c1 [ i ] . cloneNode ( false ) ) ;
120+ c2 = getChildrenByTagName ( c1 [ i ] , "th" ) ;
121+ for ( var u in c2 ) {
122+ d1 . appendChild ( d2 = c2 [ u ] . cloneNode ( true ) ) ;
123+ }
124+ }
125+ fixSizes ( temp , fhy ) ;
126+ fhy . style . width = "" ;
127+ fhy . style . zIndex = 1 ;
128+
129+ // add scroll listener
130+ tableElement . parentNode . addEventListener ( "scroll" , this . _scrollListener = function ( ) {
131+ hHead . style . top = fhx . style . top = tableElement . parentNode . scrollTop + "px" ;
132+ hHead . style . left = fhy . style . left = tableElement . parentNode . scrollLeft + "px" ;
133+ } , false ) ;
134+
135+ // append new elements
136+ tableElement . appendChild ( fhx ) ;
137+ tableElement . appendChild ( fhy ) ;
138+ tableElement . appendChild ( hHead ) ;
139+
140+ // call scroll handler because of render may be performed anytime
141+ this . _scrollListener ( ) ;
142+
143+ } ;
144+
42145/**
43146 * Raw data - plain 2-dimensional array of data to render.
44147 *
@@ -56,6 +159,11 @@ PivotView.prototype.renderRawData = function (data) {
56159 return ;
57160 }
58161
162+ if ( this . _scrollListener ) {
163+ this . elements . tableContainer . removeEventListener ( "scroll" , this . _scrollListener ) ;
164+ this . _scrollListener = null ;
165+ }
166+
59167 var table = document . createElement ( "table" ) ,
60168 thead = document . createElement ( "thead" ) ,
61169 tbody = document . createElement ( "tbody" ) ,
@@ -110,7 +218,7 @@ PivotView.prototype.renderRawData = function (data) {
110218 td = document . createElement ( data [ y ] [ x ] . isCaption ? "th" : "td" ) ;
111219 }
112220 if ( x >= headLeftColsNum && y === headColsNum - 1 ) { // clickable cells (sort option)
113- if ( td ) ( function ( x ) { td . addEventListener ( "click" , function ( ) {
221+ if ( td ) ( function ( x ) { td . addEventListener ( "click" , td [ "triggerFunction" ] = function ( ) {
114222 var colNum = x - headLeftColsNum ;
115223 _ . _columnClickHandler . call ( _ , colNum ) ;
116224 } ) } ) ( x ) ;
@@ -127,148 +235,6 @@ PivotView.prototype.renderRawData = function (data) {
127235 table . appendChild ( tbody ) ;
128236 this . elements . tableContainer . textContent = "" ;
129237 this . elements . tableContainer . appendChild ( table ) ;
238+ this . fixHeaders ( table ) ;
130239
131- } ;
132-
133- PivotView . prototype . renderHierarchy = function ( data ) {
134-
135- if ( data . error ) {
136- this . elements . tableContainer . innerHTML = "<h1>Unable to render data</h1><p>"
137- + data . error + "</p>" ;
138- return ;
139- }
140-
141- var vTree , horDimArr = [ ] , tableWidth , td , extraTh , tr , i ,
142- _ = this ,
143- table = document . createElement ( "table" ) ,
144- thead = document . createElement ( "thead" ) ,
145- tbody = document . createElement ( "tbody" ) ;
146-
147- var columnClickHandler = function ( columnIndex ) {
148- _ . controller . dataController . sortByColumn ( columnIndex ) ;
149- } ;
150-
151- this . elements . tableContainer . textContent = "" ;
152-
153- var build = function ( tree , barr , dim ) {
154-
155- var d = [ ] , ch , n , o , nn = 0 ;
156-
157- if ( barr ) {
158- if ( ! dim ) dim = 0 ;
159- if ( ! horDimArr [ dim ] ) horDimArr [ dim ] = [ ] ;
160- }
161-
162- for ( var i in tree ) {
163- ch = tree [ i ] . children ? build ( tree [ i ] . children , barr , barr ? dim + 1 : dim ) : null ;
164- n = ch ? ch . numOfChildren : 1 ;
165- nn += n ;
166- d . push ( o = {
167- caption : tree [ i ] . caption ,
168- dimension : tree [ i ] . dimension ,
169- path : tree [ i ] . path ,
170- children : ch ? ch . children : ch ,
171- numOfChildren : n
172- } ) ;
173- if ( barr ) horDimArr [ dim ] . push ( o ) ;
174- }
175-
176- return {
177- children : d ,
178- numOfChildren : nn
179- }
180-
181- } ;
182-
183- var prepend = function ( cont , el ) {
184- cont . insertBefore ( el , cont . firstChild ) ;
185- } ;
186-
187- var lastTr ,
188- trs = [ ] ,
189- maxLev = 1 ;
190-
191- var verticalTree = function ( children , sti , lev ) {
192-
193- if ( ! sti ) sti = 0 ;
194- if ( ! lev ) lev = 1 ;
195- if ( lev > maxLev ) maxLev = lev ;
196-
197- for ( var i in children ) {
198-
199- var ch = children [ i ] ,
200- td ;
201-
202- if ( ch . children ) {
203- verticalTree ( ch . children , sti , lev + 1 ) ;
204- td = document . createElement ( "th" ) ;
205- td . setAttribute ( "rowspan" , ch . numOfChildren ) ;
206- td . textContent = ch . caption || "" ;
207- prepend ( trs [ sti ] , td ) ;
208- sti += ch . numOfChildren ;
209- } else {
210- trs . push ( lastTr = document . createElement ( "tr" ) ) ;
211- tbody . appendChild ( lastTr ) ;
212- td = document . createElement ( "th" ) ;
213- td . textContent = ch . caption || "" ;
214- prepend ( lastTr , td ) ;
215- }
216-
217- }
218-
219- } ;
220-
221- build ( data . dimensions [ 0 ] , 1 ) ;
222- tableWidth = horDimArr [ horDimArr . length - 1 ] . length ;
223- vTree = build ( data . dimensions [ 1 ] ) ;
224-
225- verticalTree ( vTree . children ) ;
226-
227- for ( var u = 0 ; u < horDimArr . length ; u ++ ) {
228-
229- tr = document . createElement ( "tr" ) ;
230-
231- if ( u == 0 ) {
232- var cornerTd = document . createElement ( "th" ) ;
233- cornerTd . innerHTML = data . info [ "cubeName" ] || "" ;
234- cornerTd . setAttribute ( "rowspan" , horDimArr . length . toString ( ) ) ;
235- cornerTd . setAttribute ( "colspan" , maxLev . toString ( ) ) ;
236- tr . appendChild ( cornerTd ) ;
237- }
238-
239- for ( i in horDimArr [ u ] ) {
240-
241- var ch = horDimArr [ u ] [ i ] ;
242-
243- td = document . createElement ( "th" ) ;
244-
245- ( function ( i ) { td . onclick = function ( ) { columnClickHandler ( i ) ; } ; } ) ( i ) ;
246-
247- td . textContent = ch . caption || "" ;
248- td . setAttribute ( "colspan" , ch . numOfChildren ) ;
249- tr . appendChild ( td ) ;
250-
251- }
252-
253- thead . appendChild ( tr ) ;
254-
255- }
256-
257- for ( i = 0 ; i < data . dataArray . length ; i ++ ) {
258- td = document . createElement ( "td" ) ;
259- td . textContent = data . dataArray [ i ] ;
260- tr = trs [ Math . floor ( i / tableWidth ) ] ;
261- if ( ! tr ) {
262- trs [ Math . floor ( i / tableWidth ) ] = tr = document . createElement ( "tr" ) ;
263- extraTh = document . createElement ( "th" ) ;
264- tr . appendChild ( extraTh ) ;
265- tbody . appendChild ( tr ) ;
266- }
267- tr . appendChild ( td ) ;
268- }
269-
270- table . appendChild ( thead ) ;
271- table . appendChild ( tbody ) ;
272- this . elements . tableContainer . appendChild ( table ) ;
273-
274- } ;
240+ } ;
0 commit comments