pivotgrid-js 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pivotgrid.cjs.js +35 -0
- package/dist/pivotgrid.esm.js +35 -0
- package/dist/pivotgrid.js +35 -0
- package/dist/pivotgrid.min.js +8 -8
- package/package.json +1 -1
- package/src/pivot.js +31 -0
- package/widget/i18n.js +4 -0
- package/widget/pivot-widget.js +19 -0
package/dist/pivotgrid.cjs.js
CHANGED
|
@@ -926,6 +926,7 @@ class PivotGrid {
|
|
|
926
926
|
|
|
927
927
|
this._applyResult(result);
|
|
928
928
|
this._mount();
|
|
929
|
+
this._baseHeight = this.container.offsetHeight;
|
|
929
930
|
this._renderVisible();
|
|
930
931
|
this._bindScroll();
|
|
931
932
|
}
|
|
@@ -1581,6 +1582,36 @@ class PivotGrid {
|
|
|
1581
1582
|
|
|
1582
1583
|
// ── Public API ──────────────────────────────────────────────────────────
|
|
1583
1584
|
|
|
1585
|
+
/** Grows the grid container's height by one base-height increment. */
|
|
1586
|
+
growHeight() {
|
|
1587
|
+
const current = this.container.offsetHeight;
|
|
1588
|
+
this.container.style.flex = '0 0 auto';
|
|
1589
|
+
this.container.style.height = (current + this._baseHeight) + 'px';
|
|
1590
|
+
this._renderVisible();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Shrinks the grid container's height by one base-height increment.
|
|
1595
|
+
* Restores the original flex:1 sizing once back at the base height.
|
|
1596
|
+
* @returns {boolean} true if back to the original flex:1 size
|
|
1597
|
+
*/
|
|
1598
|
+
shrinkHeight() {
|
|
1599
|
+
const current = this.container.offsetHeight;
|
|
1600
|
+
const next = current - this._baseHeight;
|
|
1601
|
+
|
|
1602
|
+
if (next <= this._baseHeight) {
|
|
1603
|
+
this.container.style.flex = '1'; // вернули как было изначально
|
|
1604
|
+
this.container.style.height = '';
|
|
1605
|
+
this._renderVisible();
|
|
1606
|
+
return true;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
this.container.style.flex = '0 0 auto';
|
|
1610
|
+
this.container.style.height = next + 'px';
|
|
1611
|
+
this._renderVisible();
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1584
1615
|
/**
|
|
1585
1616
|
* Binds mousedown drag on the resize handle to adjust the row-label column width.
|
|
1586
1617
|
* @param {Element} handle
|
|
@@ -2533,6 +2564,8 @@ const I18N = {
|
|
|
2533
2564
|
ce_confirmDelete: 'Удалить конфиг «{name}»?',
|
|
2534
2565
|
ce_deleteOk: 'Конфиг «{name}» удалён',
|
|
2535
2566
|
ce_deleteFailed: 'Ошибка удаления: ',
|
|
2567
|
+
gridGrow: '⤓ Увеличить',
|
|
2568
|
+
gridShrink: '⤒ Уменьшить',
|
|
2536
2569
|
},
|
|
2537
2570
|
en: {
|
|
2538
2571
|
loading: 'Loading...',
|
|
@@ -2617,6 +2650,8 @@ const I18N = {
|
|
|
2617
2650
|
ce_confirmDelete: 'Delete config "{name}"?',
|
|
2618
2651
|
ce_deleteOk: 'Config "{name}" deleted',
|
|
2619
2652
|
ce_deleteFailed: 'Delete error: ',
|
|
2653
|
+
gridGrow: '⤓ Increase',
|
|
2654
|
+
gridShrink: '⤒ Decrease',
|
|
2620
2655
|
},
|
|
2621
2656
|
};
|
|
2622
2657
|
|
package/dist/pivotgrid.esm.js
CHANGED
|
@@ -926,6 +926,7 @@ class PivotGrid {
|
|
|
926
926
|
|
|
927
927
|
this._applyResult(result);
|
|
928
928
|
this._mount();
|
|
929
|
+
this._baseHeight = this.container.offsetHeight;
|
|
929
930
|
this._renderVisible();
|
|
930
931
|
this._bindScroll();
|
|
931
932
|
}
|
|
@@ -1581,6 +1582,36 @@ class PivotGrid {
|
|
|
1581
1582
|
|
|
1582
1583
|
// ── Public API ──────────────────────────────────────────────────────────
|
|
1583
1584
|
|
|
1585
|
+
/** Grows the grid container's height by one base-height increment. */
|
|
1586
|
+
growHeight() {
|
|
1587
|
+
const current = this.container.offsetHeight;
|
|
1588
|
+
this.container.style.flex = '0 0 auto';
|
|
1589
|
+
this.container.style.height = (current + this._baseHeight) + 'px';
|
|
1590
|
+
this._renderVisible();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Shrinks the grid container's height by one base-height increment.
|
|
1595
|
+
* Restores the original flex:1 sizing once back at the base height.
|
|
1596
|
+
* @returns {boolean} true if back to the original flex:1 size
|
|
1597
|
+
*/
|
|
1598
|
+
shrinkHeight() {
|
|
1599
|
+
const current = this.container.offsetHeight;
|
|
1600
|
+
const next = current - this._baseHeight;
|
|
1601
|
+
|
|
1602
|
+
if (next <= this._baseHeight) {
|
|
1603
|
+
this.container.style.flex = '1'; // вернули как было изначально
|
|
1604
|
+
this.container.style.height = '';
|
|
1605
|
+
this._renderVisible();
|
|
1606
|
+
return true;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
this.container.style.flex = '0 0 auto';
|
|
1610
|
+
this.container.style.height = next + 'px';
|
|
1611
|
+
this._renderVisible();
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1584
1615
|
/**
|
|
1585
1616
|
* Binds mousedown drag on the resize handle to adjust the row-label column width.
|
|
1586
1617
|
* @param {Element} handle
|
|
@@ -2533,6 +2564,8 @@ const I18N = {
|
|
|
2533
2564
|
ce_confirmDelete: 'Удалить конфиг «{name}»?',
|
|
2534
2565
|
ce_deleteOk: 'Конфиг «{name}» удалён',
|
|
2535
2566
|
ce_deleteFailed: 'Ошибка удаления: ',
|
|
2567
|
+
gridGrow: '⤓ Увеличить',
|
|
2568
|
+
gridShrink: '⤒ Уменьшить',
|
|
2536
2569
|
},
|
|
2537
2570
|
en: {
|
|
2538
2571
|
loading: 'Loading...',
|
|
@@ -2617,6 +2650,8 @@ const I18N = {
|
|
|
2617
2650
|
ce_confirmDelete: 'Delete config "{name}"?',
|
|
2618
2651
|
ce_deleteOk: 'Config "{name}" deleted',
|
|
2619
2652
|
ce_deleteFailed: 'Delete error: ',
|
|
2653
|
+
gridGrow: '⤓ Increase',
|
|
2654
|
+
gridShrink: '⤒ Decrease',
|
|
2620
2655
|
},
|
|
2621
2656
|
};
|
|
2622
2657
|
|
package/dist/pivotgrid.js
CHANGED
|
@@ -926,6 +926,7 @@ class PivotGrid {
|
|
|
926
926
|
|
|
927
927
|
this._applyResult(result);
|
|
928
928
|
this._mount();
|
|
929
|
+
this._baseHeight = this.container.offsetHeight;
|
|
929
930
|
this._renderVisible();
|
|
930
931
|
this._bindScroll();
|
|
931
932
|
}
|
|
@@ -1581,6 +1582,36 @@ class PivotGrid {
|
|
|
1581
1582
|
|
|
1582
1583
|
// ── Public API ──────────────────────────────────────────────────────────
|
|
1583
1584
|
|
|
1585
|
+
/** Grows the grid container's height by one base-height increment. */
|
|
1586
|
+
growHeight() {
|
|
1587
|
+
const current = this.container.offsetHeight;
|
|
1588
|
+
this.container.style.flex = '0 0 auto';
|
|
1589
|
+
this.container.style.height = (current + this._baseHeight) + 'px';
|
|
1590
|
+
this._renderVisible();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Shrinks the grid container's height by one base-height increment.
|
|
1595
|
+
* Restores the original flex:1 sizing once back at the base height.
|
|
1596
|
+
* @returns {boolean} true if back to the original flex:1 size
|
|
1597
|
+
*/
|
|
1598
|
+
shrinkHeight() {
|
|
1599
|
+
const current = this.container.offsetHeight;
|
|
1600
|
+
const next = current - this._baseHeight;
|
|
1601
|
+
|
|
1602
|
+
if (next <= this._baseHeight) {
|
|
1603
|
+
this.container.style.flex = '1'; // вернули как было изначально
|
|
1604
|
+
this.container.style.height = '';
|
|
1605
|
+
this._renderVisible();
|
|
1606
|
+
return true;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
this.container.style.flex = '0 0 auto';
|
|
1610
|
+
this.container.style.height = next + 'px';
|
|
1611
|
+
this._renderVisible();
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1584
1615
|
/**
|
|
1585
1616
|
* Binds mousedown drag on the resize handle to adjust the row-label column width.
|
|
1586
1617
|
* @param {Element} handle
|
|
@@ -2533,6 +2564,8 @@ const I18N = {
|
|
|
2533
2564
|
ce_confirmDelete: 'Удалить конфиг «{name}»?',
|
|
2534
2565
|
ce_deleteOk: 'Конфиг «{name}» удалён',
|
|
2535
2566
|
ce_deleteFailed: 'Ошибка удаления: ',
|
|
2567
|
+
gridGrow: '⤓ Увеличить',
|
|
2568
|
+
gridShrink: '⤒ Уменьшить',
|
|
2536
2569
|
},
|
|
2537
2570
|
en: {
|
|
2538
2571
|
loading: 'Loading...',
|
|
@@ -2617,6 +2650,8 @@ const I18N = {
|
|
|
2617
2650
|
ce_confirmDelete: 'Delete config "{name}"?',
|
|
2618
2651
|
ce_deleteOk: 'Config "{name}" deleted',
|
|
2619
2652
|
ce_deleteFailed: 'Delete error: ',
|
|
2653
|
+
gridGrow: '⤓ Increase',
|
|
2654
|
+
gridShrink: '⤒ Decrease',
|
|
2620
2655
|
},
|
|
2621
2656
|
};
|
|
2622
2657
|
|
package/dist/pivotgrid.min.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
var PivotGridLib=(()=>{class r{static ROW_HEIGHT=24;static HEADER_HEIGHT=32;static COL_HEADER_W=200;static COL_W=150;static INDENT=16;static BUFFER=5;constructor({container:e,result:t,rows:s,columns:
|
|
1
|
+
var PivotGridLib=(()=>{class r{static ROW_HEIGHT=24;static HEADER_HEIGHT=32;static COL_HEADER_W=200;static COL_W=150;static INDENT=16;static BUFFER=5;constructor({container:e,result:t,rows:s,columns:o,measure:i,fieldDefs:l={},labels:n={}}){this.container=e,this.rows=s,this.columns=o,this.measure=i,this.fieldDefs=l,this._labels=n,this._measureKey=i+"_sum",this._colHeaderW=r.COL_HEADER_W,this._hideSubtotals=!1,this.collapsed=new Set,this.collapsedCols=new Set,this.rowPool=[],this.rendered=new Map,this._applyResult(t),this._mount(),this._baseHeight=this.container.offsetHeight,this._renderVisible(),this._bindScroll()}_applyResult(e){this.cells=e.cells,this.colTree=e.colTree,this.colKeys=e.colKeys,this.tree=e.tree,this.grandTotal=e.grandTotal,e.measureKey&&(this._measureKey=e.measureKey),this._buildFlatCols(),this._buildFlatRows()}_buildFlatCols(){if(!this.colTree||!this.colTree.length){this.flatCols=[];return}const e=[],t=this.columns&&this.columns.length>1,s=o=>{for(const i of o)i.children?this.collapsedCols.has(i.code)?e.push({code:i.code,label:i.value,isSubtotal:!0,collapsed:!0}):(s(i.children),t&&!this._hideSubtotals&&e.push({code:i.code,label:"\u2211",isSubtotal:!0,collapsed:!1})):e.push({code:i.code,label:i.value,isSubtotal:!1})};s(this.colTree),this.flatCols=e}_getGroupSpan(e){if(!e.children||this.collapsedCols.has(e.code))return 1;let s=this.columns&&this.columns.length>1&&!this._hideSubtotals?1:0;for(const o of e.children)s+=this._getGroupSpan(o);return s}_colTreeDepth(){if(!this.colTree||!this.colTree.length)return 1;const e=t=>{let s=0;for(const o of t)o.children&&!this.collapsedCols.has(o.code)&&(s=Math.max(s,1+e(o.children)));return s};return 1+e(this.colTree)}_buildFlatRows(){this.flatRows=[];const e=t=>{for(const s of t)this.flatRows.push(s),s.children&&!this.collapsed.has(s.code)&&e(s.children)};this.tree&&e(this.tree),this.flatRows.push({isGrandTotal:!0})}get _headerHeight(){return r.HEADER_HEIGHT*this._colTreeDepth()}_mount(){this.container.innerHTML="",this.container.classList.add("pg-root");const e=this.flatCols.length?this.flatCols:this.colKeys;this.totalWidth=this._colHeaderW+(e.length+1)*r.COL_W,this._mountColHeader(),this._mountScrollArea()}_mountColHeader(){const e=r.HEADER_HEIGHT,t=this._colHeaderW,s=r.COL_W,o=this._colTreeDepth(),i=e*o;this.headerEl=document.createElement("div"),this.headerEl.className="pg-col-header",this.headerEl.style.cssText=`
|
|
2
2
|
position: absolute; top: 0; left: 0;
|
|
3
|
-
width: ${this.totalWidth}px; height: ${
|
|
3
|
+
width: ${this.totalWidth}px; height: ${i}px;
|
|
4
4
|
background: #fafafa; border-bottom: 1px solid #d0d0d0; z-index: 10;
|
|
5
|
-
`;const
|
|
5
|
+
`;const l=this._absCell({x:0,y:0,w:t,h:i,text:"",cls:"row-label"});this.rows.forEach((a,d)=>{const h=document.createElement("span"),u=(this.fieldDefs||{})[a]||{};if(h.textContent=u.title||u.label||a,h.style.cssText="cursor:pointer; padding: 0 2px;",h.title=`Expand to "${a}"`,d<this.rows.length-1?h.addEventListener("click",()=>this.expandToDepth(d+1)):h.style.cursor="default",d>0){const f=document.createElement("span");f.textContent=" \u203A ",f.style.color="#ccc",l.appendChild(f)}l.appendChild(h)});const n=document.createElement("div");if(n.className="pg-col-resize-handle",n.style.cssText=`
|
|
6
6
|
position: absolute; top: 0; left: ${t-4}px;
|
|
7
|
-
width: 8px; height: ${
|
|
7
|
+
width: 8px; height: ${i}px;
|
|
8
8
|
cursor: col-resize; z-index: 20;
|
|
9
|
-
`,this.headerEl.appendChild(n),this._bindResizeHandle(n),this.colTree&&this.colTree.length){let a=0;for(const d of this.colTree)a=this._renderColNode(d,0,a,
|
|
9
|
+
`,this.headerEl.appendChild(n),this._bindResizeHandle(n),this.colTree&&this.colTree.length){let a=0;for(const d of this.colTree)a=this._renderColNode(d,0,a,o)}const c=this.flatCols.length?this.flatCols:this.colKeys;this._absCell({x:t+c.length*s,y:0,w:s,h:i,text:this._labels.total||"Total",cls:"total-col"}),this.container.appendChild(this.headerEl)}_renderColNode(e,t,s,o){const i=r.HEADER_HEIGHT,l=this._colHeaderW,n=r.COL_W,c=this.collapsedCols.has(e.code),a=!e.children,d=this._getGroupSpan(e),h=a||c?(o-t)*i:i,u=c?"subtotal-col":a?"":"pg-col-header-group",f=this._absCell({x:l+s*n,y:t*i,w:d*n,h,text:e.value,cls:u});if(e.children){const p=document.createElement("span");p.className="pg-toggle"+(c?" collapsed":""),p.textContent="\u25BE",p.addEventListener("click",_=>{_.stopPropagation(),this._toggleColCollapse(e.code)}),f.insertBefore(p,f.firstChild)}if(!a&&!c){let p=s;for(const _ of e.children)p=this._renderColNode(_,t+1,p,o);if(this.columns&&this.columns.length>1&&!this._hideSubtotals){const _=(o-t-1)*i;_>0&&this._absCell({x:l+(s+d-1)*n,y:(t+1)*i,w:n,h:_,text:"\u2211",cls:"subtotal-col"})}}return s+d}_absCell({x:e,y:t,w:s,h:o,text:i,cls:l}){const n=document.createElement("div");return n.className="pg-col-header-cell"+(l?" "+l:""),n.style.cssText=`
|
|
10
10
|
position: absolute;
|
|
11
11
|
left: ${e}px; top: ${t}px;
|
|
12
|
-
width: ${s}px; height: ${
|
|
12
|
+
width: ${s}px; height: ${o}px;
|
|
13
13
|
box-sizing: border-box;
|
|
14
|
-
`,n.textContent=
|
|
14
|
+
`,n.textContent=i,this.headerEl.appendChild(n),n}_mountScrollArea(){const e=this._headerHeight;this.scrollArea=document.createElement("div"),this.scrollArea.className="pg-scroll",this.scrollArea.style.top=e+"px",this.container.appendChild(this.scrollArea),this.virtualSpace=document.createElement("div"),this.virtualSpace.style.cssText=`
|
|
15
15
|
position: relative;
|
|
16
16
|
width: ${this.totalWidth}px;
|
|
17
17
|
height: ${this.flatRows.length*r.ROW_HEIGHT}px;
|
|
18
|
-
`,this.scrollArea.appendChild(this.virtualSpace)}_renderVisible(){const e=this.scrollArea.clientHeight,t=this.scrollArea.scrollTop,s=r.ROW_HEIGHT,
|
|
18
|
+
`,this.scrollArea.appendChild(this.virtualSpace)}_renderVisible(){const e=this.scrollArea.clientHeight,t=this.scrollArea.scrollTop,s=r.ROW_HEIGHT,o=r.BUFFER,i=Math.max(0,Math.floor(t/s)-o),l=Math.min(this.flatRows.length-1,Math.ceil((t+e)/s)+o);for(const[n,c]of this.rendered)(n<i||n>l)&&(this.virtualSpace.removeChild(c),this._recycleRow(c),this.rendered.delete(n));for(let n=i;n<=l;n++){if(this.rendered.has(n))continue;const c=this._acquireRow();this._fillRow(c,this.flatRows[n],n),this.virtualSpace.appendChild(c),this.rendered.set(n,c)}}_acquireRow(){if(this.rowPool.length){const t=this.rowPool.pop();return t.className="pg-row",t.removeAttribute("style"),t.innerHTML="",t}const e=document.createElement("div");return e.className="pg-row",e}_recycleRow(e){this.rowPool.push(e)}_fillRow(e,t,s){const o=r.ROW_HEIGHT;if(e.style.top=s*o+"px",e.style.width=this.totalWidth+"px",e.style.height=o+"px",t.isGrandTotal){e.classList.add("grand-total"),this._fillGrandTotalRow(e);return}e.style.background=s%2===0?"#ffffff":"#fcfcfc",this._fillHeaderCell(e,t),this._fillValueCells(e,t)}_fillHeaderCell(e,t){const s=r.ROW_HEIGHT,o=this._colHeaderW,i=r.INDENT,l=document.createElement("div");if(l.className="pg-cell-header",l.style.cssText=`width:${o}px;height:${s}px;padding-left:${8+t.depth*i}px`,t.children){const c=document.createElement("span");c.className="pg-toggle"+(this.collapsed.has(t.code)?" collapsed":""),c.textContent="\u25BE",c.addEventListener("click",a=>{a.stopPropagation(),this._toggleCollapse(t.code)}),l.appendChild(c)}else{const c=document.createElement("span");c.className="pg-toggle-spacer",l.appendChild(c)}const n=document.createElement("span");n.className=`pg-label depth-${Math.min(t.depth,2)}`,n.textContent=t.value,l.appendChild(n),e.appendChild(l)}_fillValueCells(e,t){const s=r.ROW_HEIGHT,o=r.COL_W,i=this.flatCols.length?this.flatCols:this.colKeys;for(const a of i){const d=t.code+"||"+a.code,h=this.cells.get(d),u=document.createElement("div");u.className="pg-cell"+(h==null?" empty":"")+(a.isSubtotal?" subtotal":""),u.style.cssText=`width:${o}px;height:${s}px`,u.textContent=h!=null?this._fmt(h):"\u2014",h!=null&&u.addEventListener("click",()=>this._emitDrillthrough(t,a.code,h)),e.appendChild(u)}const l=t.code+"||__total__",n=this.cells.get(l)||0,c=document.createElement("div");c.className="pg-cell total",c.style.cssText=`width:${o}px;height:${s}px`,c.textContent=this._fmt(n),c.addEventListener("click",()=>this._emitDrillthrough(t,"__total__",n)),e.appendChild(c)}_fillGrandTotalRow(e){const t=r.ROW_HEIGHT,s=this._colHeaderW,o=r.COL_W,i=this.flatCols.length?this.flatCols:this.colKeys,l=document.createElement("div");l.className="pg-cell-header",l.style.cssText=`width:${s}px;height:${t}px;padding-left:8px`;const n=document.createElement("span");n.className="pg-toggle-spacer",l.appendChild(n);const c=document.createElement("span");c.className="pg-label depth-0",c.textContent=this._labels.total||"Total",l.appendChild(c),e.appendChild(l);for(const d of i){const h="__grand__||"+d.code,u=this.cells.get(h)||0,f=document.createElement("div");f.className="pg-cell total"+(d.isSubtotal?" subtotal":""),f.style.cssText=`width:${o}px;height:${t}px`,f.textContent=this._fmt(u),f.addEventListener("click",()=>this._emitDrillthrough({isGrandTotal:!0},d.code,u)),e.appendChild(f)}const a=document.createElement("div");a.className="pg-cell total grand-total-val",a.style.cssText=`width:${o}px;height:${t}px`,a.textContent=this._fmt(this.grandTotal||0),a.addEventListener("click",()=>this._emitDrillthrough({isGrandTotal:!0},"__total__",this.grandTotal)),e.appendChild(a)}_toggleColCollapse(e){if(this.collapsedCols.has(e)){this.collapsedCols.delete(e);const t=this._findColNode(e);if(t?.children)for(const s of t.children)s.children&&this.collapsedCols.add(s.code)}else this.collapsedCols.add(e);this._rebuildCols()}_findColNode(e,t=this.colTree){if(!t)return null;for(const s of t){if(s.code===e)return s;const o=this._findColNode(e,s.children);if(o)return o}return null}toggleSubtotals(e){this._hideSubtotals=!e,this._rebuildCols()}_rebuildCols(){this._buildFlatCols();const e=this.flatCols.length?this.flatCols:this.colKeys;this.totalWidth=this._colHeaderW+(e.length+1)*r.COL_W,this.virtualSpace.style.width=this.totalWidth+"px",this.scrollArea.style.top=this._headerHeight+"px",this.headerEl.remove(),this._mountColHeader(),this.headerEl.style.transform=`translateX(-${this.scrollArea.scrollLeft}px)`,this._redraw()}_redraw(){this.virtualSpace.style.height=this.flatRows.length*r.ROW_HEIGHT+"px";for(const[,e]of this.rendered)this.virtualSpace.removeChild(e),this._recycleRow(e);this.rendered.clear(),this._renderVisible()}_bindScroll(){let e=!1;this.scrollArea.addEventListener("scroll",()=>{this.headerEl.style.transform=`translateX(-${this.scrollArea.scrollLeft}px)`,e||(requestAnimationFrame(()=>{this._renderVisible(),e=!1}),e=!0)})}_emitDrillthrough(e,t,s){const o={};if(!e.isGrandTotal){const i=this._getNodeChain(e);for(let l=0;l<i.length;l++)o[this.rows[l]]=i[l].value}if(t!=="__total__"){const i=t.split("\u2192");for(let l=0;l<i.length;l++)this.columns[l]&&(o[this.columns[l]]=i[l])}this.container.dispatchEvent(new CustomEvent("drillthrough",{bubbles:!0,detail:{context:o,value:s}}))}_getNodeChain(e){const t=[e];if(e.depth===0)return t;const s=this.flatRows.indexOf(e);for(let o=s-1;o>=0;o--){const i=this.flatRows[o];if(!i.isGrandTotal&&i.depth===e.depth-1){if(t.unshift(i),i.depth===0)break;e=i}}return t}_fmt(e){return new Intl.NumberFormat("ru-RU",{maximumFractionDigits:0}).format(e)}growHeight(){const e=this.container.offsetHeight;this.container.style.flex="0 0 auto",this.container.style.height=e+this._baseHeight+"px",this._renderVisible()}shrinkHeight(){const t=this.container.offsetHeight-this._baseHeight;return t<=this._baseHeight?(this.container.style.flex="1",this.container.style.height="",this._renderVisible(),!0):(this.container.style.flex="0 0 auto",this.container.style.height=t+"px",this._renderVisible(),!1)}_bindResizeHandle(e){e.addEventListener("mousedown",t=>{t.preventDefault();const s=t.clientX,o=this._colHeaderW,i=n=>{const c=Math.max(r.COL_HEADER_W,o+n.clientX-s);this._colHeaderW=c,this._rebuild()},l=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",l)};document.addEventListener("mousemove",i),document.addEventListener("mouseup",l)})}_rebuild(){this.headerEl?.remove(),this.headerEl=null,this._buildFlatCols(),this._mountColHeader();for(const[,e]of this.rendered)this._recycleRow(e);this.rendered.clear(),this._renderVisible()}setResult(e,{rows:t,columns:s,measure:o,fieldDefs:i}={}){if(t&&(this.rows=t),s&&(this.columns=s),o&&(this.measure=o),i&&(this.fieldDefs=i),this.collapsedCols.clear(),this._applyResult(e),this.colTree){for(const n of this.colTree)n.children&&this.collapsedCols.add(n.code);this._buildFlatCols()}const l=this.flatCols.length?this.flatCols:this.colKeys;this.totalWidth=this._colHeaderW+(l.length+1)*r.COL_W,this.virtualSpace.style.width=this.totalWidth+"px",this.scrollArea.style.top=this._headerHeight+"px",this.headerEl.remove(),this._mountColHeader(),this._redraw()}collapseAll(){const e=t=>{if(t)for(const s of t)s.children&&(this.collapsed.add(s.code),e(s.children))};e(this.tree),this._buildFlatRows(),this._redraw()}static _detectMaxHeight(){const e=document.createElement("div");e.style.cssText="position:fixed;visibility:hidden;",document.body.appendChild(e);let t=1e6;for(;t<1e8&&(e.style.height=t+"px",!(e.offsetHeight<t));)t*=2;return e.remove(),t/2}static MAX_FLAT_ROWS=Math.floor(r._detectMaxHeight()/r.ROW_HEIGHT);_confirmLargeExpand(e,t,s){const o=(e/1e6).toFixed(1),i=(this._labels.confirmLargeExpand||"Too many rows (~{millions}M). Click OK to expand anyway.").replace("{millions}",o);window.confirm(i)?t():s?.()}_toggleCollapse(e){const t=this.collapsed.has(e);if(t?this.collapsed.delete(e):this.collapsed.add(e),this._buildFlatRows(),t&&this.flatRows.length>r.MAX_FLAT_ROWS){this._confirmLargeExpand(this.flatRows.length,()=>this._redraw(),()=>{this.collapsed.add(e),this._buildFlatRows()});return}this._redraw()}expandToDepth(e){const t=[],s=i=>{for(const l of i)l.children&&(l.depth<e-1?(this.collapsed.delete(l.code),s(l.children)):l.depth===e-1&&t.push(l))};s(this.tree);const o=t.some(i=>!this.collapsed.has(i.code));for(const i of t)o?this.collapsed.add(i.code):this.collapsed.delete(i.code);this._buildFlatRows(),this._redraw()}expandAll(){if(this.collapsed.clear(),this._buildFlatRows(),this.flatRows.length>r.MAX_FLAT_ROWS){this._confirmLargeExpand(this.flatRows.length,()=>this._redraw());return}this._redraw()}expandAllCols(){this.collapsedCols.clear(),this._rebuildCols()}collapseAllCols(){const e=t=>{if(t)for(const s of t)s.children&&(this.collapsedCols.add(s.code),e(s.children))};e(this.colTree),this._rebuildCols()}}})();
|
package/package.json
CHANGED
package/src/pivot.js
CHANGED
|
@@ -40,6 +40,7 @@ class PivotGrid {
|
|
|
40
40
|
|
|
41
41
|
this._applyResult(result);
|
|
42
42
|
this._mount();
|
|
43
|
+
this._baseHeight = this.container.offsetHeight;
|
|
43
44
|
this._renderVisible();
|
|
44
45
|
this._bindScroll();
|
|
45
46
|
}
|
|
@@ -695,6 +696,36 @@ class PivotGrid {
|
|
|
695
696
|
|
|
696
697
|
// ── Public API ──────────────────────────────────────────────────────────
|
|
697
698
|
|
|
699
|
+
/** Grows the grid container's height by one base-height increment. */
|
|
700
|
+
growHeight() {
|
|
701
|
+
const current = this.container.offsetHeight;
|
|
702
|
+
this.container.style.flex = '0 0 auto';
|
|
703
|
+
this.container.style.height = (current + this._baseHeight) + 'px';
|
|
704
|
+
this._renderVisible();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Shrinks the grid container's height by one base-height increment.
|
|
709
|
+
* Restores the original flex:1 sizing once back at the base height.
|
|
710
|
+
* @returns {boolean} true if back to the original flex:1 size
|
|
711
|
+
*/
|
|
712
|
+
shrinkHeight() {
|
|
713
|
+
const current = this.container.offsetHeight;
|
|
714
|
+
const next = current - this._baseHeight;
|
|
715
|
+
|
|
716
|
+
if (next <= this._baseHeight) {
|
|
717
|
+
this.container.style.flex = '1'; // вернули как было изначально
|
|
718
|
+
this.container.style.height = '';
|
|
719
|
+
this._renderVisible();
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
this.container.style.flex = '0 0 auto';
|
|
724
|
+
this.container.style.height = next + 'px';
|
|
725
|
+
this._renderVisible();
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
|
|
698
729
|
/**
|
|
699
730
|
* Binds mousedown drag on the resize handle to adjust the row-label column width.
|
|
700
731
|
* @param {Element} handle
|
package/widget/i18n.js
CHANGED
|
@@ -91,6 +91,8 @@ const I18N = {
|
|
|
91
91
|
ce_confirmDelete: 'Удалить конфиг «{name}»?',
|
|
92
92
|
ce_deleteOk: 'Конфиг «{name}» удалён',
|
|
93
93
|
ce_deleteFailed: 'Ошибка удаления: ',
|
|
94
|
+
gridGrow: '⤓ Увеличить',
|
|
95
|
+
gridShrink: '⤒ Уменьшить',
|
|
94
96
|
},
|
|
95
97
|
en: {
|
|
96
98
|
loading: 'Loading...',
|
|
@@ -175,5 +177,7 @@ const I18N = {
|
|
|
175
177
|
ce_confirmDelete: 'Delete config "{name}"?',
|
|
176
178
|
ce_deleteOk: 'Config "{name}" deleted',
|
|
177
179
|
ce_deleteFailed: 'Delete error: ',
|
|
180
|
+
gridGrow: '⤓ Increase',
|
|
181
|
+
gridShrink: '⤒ Decrease',
|
|
178
182
|
},
|
|
179
183
|
};
|
package/widget/pivot-widget.js
CHANGED
|
@@ -100,6 +100,9 @@ function buildHTML() {
|
|
|
100
100
|
<div class="toolbar-sep"></div>
|
|
101
101
|
<button class="toolbar-btn toolbar-btn--toggle" id="btn-subtotals">${t('subtotals')}</button>
|
|
102
102
|
<button class="toolbar-btn" id="btn-export">${t('exportCsv')}</button>
|
|
103
|
+
<div class="toolbar-sep"></div>
|
|
104
|
+
<button class="toolbar-btn" id="btn-grid-grow">${t('gridGrow')}</button>
|
|
105
|
+
<button class="toolbar-btn" id="btn-grid-shrink">${t('gridShrink')}</button>
|
|
103
106
|
</div>
|
|
104
107
|
|
|
105
108
|
<div id="loading" style="
|
|
@@ -146,6 +149,8 @@ if (isEmpty) {
|
|
|
146
149
|
pivotEl.innerHTML = buildHTML();
|
|
147
150
|
}
|
|
148
151
|
|
|
152
|
+
const flexWrapper = isEmpty ? pivotEl : document.body;
|
|
153
|
+
|
|
149
154
|
const gridEl = isEmpty
|
|
150
155
|
? document.getElementById('pivot-grid')
|
|
151
156
|
: pivotEl;
|
|
@@ -355,6 +360,20 @@ function initToolbar() {
|
|
|
355
360
|
document.getElementById('chk-fields').addEventListener('change', (e) => {
|
|
356
361
|
document.querySelector('.field-zones').style.display = e.target.checked ? '' : 'none';
|
|
357
362
|
});
|
|
363
|
+
|
|
364
|
+
document.getElementById('btn-grid-grow').addEventListener('click', () => {
|
|
365
|
+
grid?.growHeight();
|
|
366
|
+
flexWrapper.style.height = ''; // снимаем фиксированную высоту — даём расти
|
|
367
|
+
flexWrapper.style.overflow = 'auto'; // и скроллиться странице
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
document.getElementById('btn-grid-shrink').addEventListener('click', () => {
|
|
371
|
+
const backToOriginal = grid?.shrinkHeight();
|
|
372
|
+
if (backToOriginal) {
|
|
373
|
+
flexWrapper.style.height = '100dvh'; // вернули исходное поведение
|
|
374
|
+
flexWrapper.style.overflow = 'hidden';
|
|
375
|
+
}
|
|
376
|
+
});
|
|
358
377
|
}
|
|
359
378
|
|
|
360
379
|
// ── CSV export ────────────────────────────────────────────────────────────────
|