Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed grid-size inside dynamic width/height (flexbox) #728

Open
krilllind opened this issue Jul 27, 2017 · 8 comments
Open

Fixed grid-size inside dynamic width/height (flexbox) #728

krilllind opened this issue Jul 27, 2017 · 8 comments

Comments

@krilllind
Copy link

Hi!
I have been looking all over the place for a solution to this problem, but I just can´t seem to find it.

Is is possible to generate a grid-stack area with given x and y columns inside a fluid width/height flexbox div? So when the window resizes the grid changes width and height but keeps the same amount of x and y columns. From my experience I can only get the width to become fluid, but the height keeps on growing when i drop an item below the current grid height.

I have looked at this one #118 and this one #404 but it´s not quite right.

Thanks for an awesome library.

Feel free to ask me if you need any more information.

@krilllind
Copy link
Author

Manage to solve this by calculating the cellHeight when the grid is initilized, and then use the same method to recalculate the cellHeight when my grid "wrapper" changed height.

The only problem now is that IF a widget is for example 12 out of 12 cells in height, it will not resize when the grid does, it get stuck in the bottom of the grid and it's not updating the height. This might be some sort of bug but I don't know?

For all of you who wants to calculate the height can use this function!
This is written in TS!

public calcHeight(numberOfCells: number = 12, gutter: number = 20): number {
    const parentHeight: number = this.elementRef.nativeElement.parentElement.offsetHeight;
    const useableHeight: number = (parentHeight - (gutter * Math.abs(numberOfCells - 1)));
    const cellHeight: number = useableHeight / numberOfCells;

    return cellHeight;
  }

And use this for the resize event!

jQuery(window).on('resize', () => {
      this.gridstackObject.data('gridstack').batchUpdate();
      const cellHeight = this.calcHeight(this.options.height, this.options.verticalMargin);
      this.gridstackObject.data('gridstack').cellHeight(cellHeight);
      this.gridstackObject.data('gridstack').commit();
    });

@demedos
Copy link
Contributor

demedos commented Aug 2, 2017

You should probably throttle or at least debounce the resize event to prevent it from firing too many times causing the app to become unresponsive; the resize event can easily fire hundreds of times on a single resize action.

Based on yours, I'm using a very similar approach in my React component (simplified for clarity) with the extra throttling:

import React from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';

class TabHeader extends React.Component {
  constructor(props) {
    super(props);
    this.updateGridStack = _.throttle(this.updateGridStack.bind(this), 66);
    //66 == 15fps
  }

componentDidMount() {
    window.addEventListener("resize", this.updateGridStack);
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateGridStack);
  }

updateGridStack() {
    var selector = "#myGridContainer" + " > .grid-stack"; 
    var grid = $(selector).data('gridstack');
    if (grid) {
      grid.batchUpdate();

      var containerHeight = $('.content-container').height();
      var rowsCount = 3;
      var height = containerHeight / rowsCount;

      grid.cellHeight(height);
      grid.commit();
    }
  }

I found using lodash much easier and faster than implementing my own logic, but it's not very complicated if you'd want to.
Here is a very nice article about the differences of throttling, debouncing and rAF techniques.

@krilllind
Copy link
Author

@demedos Good thinking! But I don't feel like using lodash in my Angular IO (4) application, and I am already using Rxjs Observables. So with your comment in mind, I tweaked my solution to debounce the amount of event.

Here is my code reworked with Rxjs!

Observable.fromEvent(window, 'resize')
      .debounceTime(500)
      .subscribe((event: Event) => {
        this.gridstackObject.data('gridstack').batchUpdate();
        const cellHeight = this.calcHeight(this.options.height, this.options.verticalMargin);
        this.gridstackObject.data('gridstack').cellHeight(cellHeight);
        this.gridstackObject.data('gridstack').commit();
      });

Thank you for pointing it out to me, I totally forgot about it! :)

@krilllind
Copy link
Author

So does anyone have anything new about this?

The main problem is still how to calculate a fixed grid-item height with a verticalMargin of 10px
on 12 rows, so you can limit the amount of grid-items that can fit in one column.

@radiolips
Copy link
Member

@adumesny Aren't you doing something similar with the height? I assume the x problem is easy because the grid already isn't changing number of columns, only rows.

@krilllind
Copy link
Author

@radiolips Okey so here is a full explanation of what I am trying to do...

I want to be able to change the amount of columns and rows of my gridstack area from (lets say two simple inputs). As an example I will start of with a 12x12 grid. Then I am generating a stylesheet with the right amount of column.
This is done from this code:

public generateStyleGrid(): void {
   const columns = this.options.width;
   const columnPercentage = 100 / columns;
   const styleElement = document.createElement('style');
   styleElement.type = "text/css";

   let style: string = "";
   for (let x = 0; x <= columns; x++) {
     style += `
     .grid-stack > .grid-stack-item[data-gs-width='${x}'] {
       width: ${x * columnPercentage}%;
     }
     .grid-stack > .grid-stack-item[data-gs-x='${x}'] {
       left: ${x * columnPercentage}%;
     }
     .grid-stack > .grid-stack-item[data-gs-min-width='${x}'] {
       min-width: ${x * columnPercentage}%;
     }
     .grid-stack > .grid-stack-item[data-gs-max-width='${x}'] {
       max-width: ${x * columnPercentage}%;
     }
     `;
   }

   this.removeStyleGrid();
   styleElement.appendChild(document.createTextNode(style));
   this.gridstackStyleNode = document.head.appendChild(styleElement);
   this.resize();
 }

Then listen for a window resize and recalculate the cellHeight from the new container with, but here is where I want to have a verticalMargin.

The function I am using right now looks something like this:

public calcHeight(numberOfCells: number = 12, gutter: number = 20): number {
    const parentHeight: number = this.elementRef.nativeElement.parentElement.clientHeight;
    // const useableHeight: number = (parentHeight - (gutter * (numberOfCells)));
    const cellHeight: number = parentHeight / numberOfCells;
    return cellHeight;
  }

  public resize(): void {
    const cellHeight = this.calcHeight(this.options.height, this.options.verticalMargin);
    this.instance.batchUpdate();
    this.instance.cellHeight(cellHeight);
    this.instance.commit();
  }

@demedos
Copy link
Contributor

demedos commented Sep 20, 2017

I'll go for a quick example, since it's something I need to do too.

example

So, my page is always 100vh (viewport height), and will never exceed that height.
Now, let's say I move item 3 below item 4, I would need the grid to vertical resize all the items to fit in my view, like so

example2

@adumesny
Copy link
Member

adumesny commented Sep 20, 2017

@radiolips thanks, yes this is very similar to what I'm trying to do in #787 - other than my grid being nested inside another grid-item, but I also want it to take 100% height and adjust cellHeight to fit, including during drag&drop changes. Nested grid seem to have more side affect as I'm seeing parent cellHeight apparently also changing (see #726 )!

I really like the idea of having a cellHeight = "dynamic" (in addition to the auto and pixel #) as a way to say make it fit inside it's parent and fix drag&drop behavior too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants