Dynamic grid row height — различия между версиями

Материал из YourcmcWiki
Перейти к: навигация, поиск
м
м
 
(не показана одна промежуточная версия этого же участника)
Строка 1: Строка 1:
 +
…Impossible in almost all JS grids with virtual scrolling.
 +
 
https://www.ag-grid.com/javascript-grid-row-height/
 
https://www.ag-grid.com/javascript-grid-row-height/
  
 
«By default, the grid will display rows at 25px. You can change this for each row individually to give each row a different height.»
 
«By default, the grid will display rows at 25px. You can change this for each row individually to give each row a different height.»
 +
 +
«Grid, fixed row height (no word wrap, no multi line) — Grid — Kendo UI …»
 +
 +
But we have a solution :)
  
 
* Use reasonable fixed minimum row height
 
* Use reasonable fixed minimum row height
Строка 7: Строка 13:
 
* Find maximum possible viewport start (in units of item number + % of item)
 
* Find maximum possible viewport start (in units of item number + % of item)
 
* Measure average height of last rows
 
* Measure average height of last rows
* avgHeight = max(minHeight, lastRowAvgHeight)
+
* {{cmd|1=avgHeight = max(minHeight, lastRowAvgHeight)}}
* targetHeight = avgHeight*rowCount + headerHeight
+
* {{cmd|1=targetHeight = avgHeight*rowCount + headerHeight}}
 
* Set sizer to targetHeight
 
* Set sizer to targetHeight
* scrollPos = targetHeight > offsetHeight ? min(1, scrollTop / (targetHeight — offsetHeight)) : 0
+
* {{cmd|1=scrollPos = targetHeight > offsetHeight ? min(1, scrollTop / (targetHeight - offsetHeight)) : 0}}
* First visible item will be Math.floor(scrollPos*maxPossibleViewportStart)
+
* First visible item will be {{cmd|1=Math.floor(scrollPos*maxPossibleViewportStart)}}
* Additional scroll offset will be itemOffset = scrollPos*maxPossibleViewportStart-Math.floor(scrollPos*maxPossibleViewportStart)*firstVisibleItemHeight
+
* Additional scroll offset will be {{cmd|1=itemOffset = scrollPos*maxPossibleViewportStart - Math.floor(scrollPos*maxPossibleViewportStart)*firstVisibleItemHeight}}
* First (top) placeholder height will be scrollTop-firstVisibleItemHeight+itemOffset
+
* First (top) placeholder height will be {{cmd|1=scrollTop-firstVisibleItemHeight+itemOffset}}
* Second (middle) placeholder height will be avgHeight*nodeCount — sum(heights of all rendered rows) — (first placeholder height)
+
* Second (middle) placeholder height will be {{cmd|1=avgHeight*nodeCount - sum(heights of all rendered rows) - (first placeholder height)}}
 +
 
 +
I.e. it’s like:
 +
 
 +
<pre>
 +
state = { avgRowHeight, topPlaceholderHeight, firstVisibleItem, middleItemCount, middlePlaceholderHeight, lastItemCount, itemScrollTop, viewportHeight }
 +
 
 +
<top placeholder>
 +
middleItemCount ? <middle items> : null
 +
middlePlaceholderHeight ? <middle placeholder> : null
 +
<last items>
 +
</pre>
 +
 
 +
* Initial render: 0 / 0 / 0 / 0
 +
* Render 1: set viewportHeight, set lastItemCount => 0 / 0 / 0 / set
 +
* Render 2: set itemScrollHeight (scroll height in items+%), set avgRowHeight, set sizer targetHeight, set firstVisibleItem => set / set / 0 / set
 +
* Render 3: set middlePlaceholderHeight, (for a table with fixed column: sync fixed column row heights) => set / set / set / set
 +
* After that each scroll takes 2 renders to complete (re-render items, re-set placeholder height)
 +
* If it’s not a table then it’s possible to do absolute positioning instead of placeholders and only do a single render by positioning last items at the bottom of scroll container, because we already know targetHeight before the first render of two

Текущая версия на 14:19, 8 октября 2018

…Impossible in almost all JS grids with virtual scrolling.

https://www.ag-grid.com/javascript-grid-row-height/

«By default, the grid will display rows at 25px. You can change this for each row individually to give each row a different height.»

«Grid, fixed row height (no word wrap, no multi line) — Grid — Kendo UI …»

But we have a solution :)

  • Use reasonable fixed minimum row height
  • Always render (screen/minHeight) last rows
  • Find maximum possible viewport start (in units of item number + % of item)
  • Measure average height of last rows
  • avgHeight = max(minHeight, lastRowAvgHeight)
  • targetHeight = avgHeight*rowCount + headerHeight
  • Set sizer to targetHeight
  • scrollPos = targetHeight > offsetHeight ? min(1, scrollTop / (targetHeight - offsetHeight)) : 0
  • First visible item will be Math.floor(scrollPos*maxPossibleViewportStart)
  • Additional scroll offset will be itemOffset = scrollPos*maxPossibleViewportStart - Math.floor(scrollPos*maxPossibleViewportStart)*firstVisibleItemHeight
  • First (top) placeholder height will be scrollTop-firstVisibleItemHeight+itemOffset
  • Second (middle) placeholder height will be avgHeight*nodeCount - sum(heights of all rendered rows) - (first placeholder height)

I.e. it’s like:

state = { avgRowHeight, topPlaceholderHeight, firstVisibleItem, middleItemCount, middlePlaceholderHeight, lastItemCount, itemScrollTop, viewportHeight }

<top placeholder>
middleItemCount ? <middle items> : null
middlePlaceholderHeight ? <middle placeholder> : null
<last items>
  • Initial render: 0 / 0 / 0 / 0
  • Render 1: set viewportHeight, set lastItemCount => 0 / 0 / 0 / set
  • Render 2: set itemScrollHeight (scroll height in items+%), set avgRowHeight, set sizer targetHeight, set firstVisibleItem => set / set / 0 / set
  • Render 3: set middlePlaceholderHeight, (for a table with fixed column: sync fixed column row heights) => set / set / set / set
  • After that each scroll takes 2 renders to complete (re-render items, re-set placeholder height)
  • If it’s not a table then it’s possible to do absolute positioning instead of placeholders and only do a single render by positioning last items at the bottom of scroll container, because we already know targetHeight before the first render of two