Skip to content

Commit 1c8bc67

Browse files
fixed table headers, fixes for cross-browser support
1 parent 3b45f37 commit 1c8bc67

3 files changed

Lines changed: 136 additions & 154 deletions

File tree

example/index.html

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818

1919
</div>
2020
<div>Variants:
21-
<a href="#0" onclick="window.location.reload(true);">0</a>,
22-
<a href="#1" onclick="window.location.reload(true);">1</a>,
23-
<a href="#2" onclick="window.location.reload(true);">2</a>,
24-
<a href="#3" onclick="window.location.reload(true);">3</a>,
25-
<a href="#4" onclick="window.location.reload(true);">4</a>,
26-
<a href="#5" onclick="window.location.reload(true);">5</a>,
27-
<a href="#6" onclick="window.location.reload(true);">6</a>,
28-
<a href="#7" onclick="window.location.reload(true);">7</a>,
29-
<a href="#8" onclick="window.location.reload(true);">8</a>
21+
<a href="#0" onclick="rSoon()">0</a>,
22+
<a href="#1" onclick="rSoon()">1</a>,
23+
<a href="#2" onclick="rSoon()">2</a>,
24+
<a href="#3" onclick="rSoon()">3</a>,
25+
<a href="#4" onclick="rSoon()">4</a>,
26+
<a href="#5" onclick="rSoon()">5</a>,
27+
<a href="#6" onclick="rSoon()">6</a>,
28+
<a href="#7" onclick="rSoon()">7</a>,
29+
<a href="#8" onclick="rSoon()">8</a>
3030
</div>
3131
<div id="mdx"></div>
3232
<form id="mdxForm" onsubmit="return false;">
@@ -37,6 +37,9 @@
3737
</form>
3838
<script type="text/javascript">
3939

40+
// reloads the page.
41+
var rSoon = function () { setTimeout(function () { window.location.reload(true); }, 1); };
42+
4043
var mdxTo = document.getElementById("mdx"),
4144
v = parseInt(location.hash.slice(1)) || 0,
4245
req = [

source/css/LightPivot.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
border-radius: 5px;
77
}
88

9+
.lpt table {
10+
position: relative;
11+
width: 100%;
12+
}
13+
14+
.lpt .fixedHeader {
15+
position: absolute;
16+
left: 0;
17+
top: 0;
18+
background: white;
19+
}
20+
921
.lpt > .tableContainer {
1022
overflow: auto;
1123
width: 100%;
@@ -15,6 +27,7 @@
1527
.lpt > .tableContainer > table {
1628
min-width: 100%;
1729
min-height: 100%;
30+
height: 100%;
1831
}
1932

2033
.lpt > .tableContainer td, .lpt > .tableContainer th {

source/js/PivotView.js

Lines changed: 111 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)