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

Predefine the size of dragable elements in sidebbar of Two Grids Demo #933

Closed
Hedva opened this issue Aug 7, 2018 · 9 comments
Closed

Comments

@Hedva
Copy link

Hedva commented Aug 7, 2018

I can't figure out how to predefine the size of the items in the sidebar of Two Grids Demo

So as long they're in the sidebar, i'm fine with the items begin a fixed size like 150x150px. But when I drag them into a grid, I want them to be a predefined size. Like 2x2 or 1x1.

At this moment it seems they're always 2x2.

It this possible? Using data-gs-width="1" data-gs-height="1" doesn't seem to work.

@ermcgrat
Copy link

Definitely in for this. Haven't had any success getting it to work. Even if I specify the data-gs-width and data-gs-height attributes (as you said) they seem to get ignored and the element always becomes a 2x2.

@ermcgrat
Copy link

@ermcgrat
Copy link

I found a hacky workaround after reviewing the library's source. The library is trying to be smart when you drag outside widgets into the grid (using acceptWidgets). It determines the width and height of the grid, and then calculates what the width of each column/cell in that grid should be (note this changes on the two grid demo depending on how wide the viewport is). Then it looks at the width (and height) of the widget you are bringing into the grid and determines how many columns/rows it should occupy. Unfortunately, the data attributes are not considered in any of this. Here is the relevant function:

.on(self.container, 'dropover', function(event, ui) {

You can see it checks if there is any existing data for the widget, and falls back to the calculations if there isn't. Ideally the code would check for the attributes before resorting to calculations. Assuming we can't change the library, what we can do is add this data it is looking for, specifying the width and height we want. Then you can drag an html element of any dimension into the grid and have it occupy the width/height of your choosing. Eg, add to end of two-grid demo:

            $('.sidebar .grid-stack-item').each(function () {
                $(this).data('_gridstack_node', {
                    width: 1,
                    height: 1
                });
            });

@Hedva
Copy link
Author

Hedva commented Aug 29, 2018

Great solution! Thanks for sharing, really appreciate it!

@Hedva
Copy link
Author

Hedva commented Aug 30, 2018

@ermcgrat although the sizing for the items works, in some situations the placeholder width/height doesn't correspondent with the width of the placed items. It seems that after 1 drag and drop the data-gs-width and data-gs-height changes back to some default values (1 and 2)

First drag/drop from sidebar:

<div class="grid-stack-item ui-draggable ui-resizable ui-resizable-autohide" data-gs-width="4" data-gs-height="1" data-gs-min-width="4" data-gs-x="1" data-gs-y="3">

Second drag/drop from sidebar:

<div class="grid-stack-item ui-draggable ui-resizable ui-resizable-autohide" data-gs-width="1" data-gs-height="2" data-gs-min-width="4" data-gs-x="0" data-gs-y="2">

To prevent this; put the @ermcgrat code inside $('.sidebar').on.('dragstart', function(event, ui){}.

Example:

<div class="grid-stack-item" data-gs-width="4" data-gs-height="3" data-gs-min-width="4">
  <div class="grid-stack-item-content">Item 1</div>
</div>
<div class="grid-stack-item" data-gs-width="4" data-gs-height="1" data-gs-min-width="4">
  <div class="grid-stack-item-content">Item 2</div>
</div>
<div class="grid-stack-item" data-gs-width="2" data-gs-height="1" data-gs-min-width="2">
  <div class="grid-stack-item-content">Item 3</div>
</div>
$('.sidebar').on('dragstart', function(event, ui) {

  $('.sidebar .grid-stack-item').each(function () {
    let elementData = $(this).context.dataset

    $(this).data('_gridstack_node', {
      width: elementData.gsWidth,
      height: elementData.gsHeight,
    });
  });
});

This does work in most cases. Although there are some cases the placeholder doesn't size properly. But I'm not sure what causes that. I was not able to determine when that exactly happens.

@Hedva
Copy link
Author

Hedva commented Aug 30, 2018

Just found out that if you have an item with a `min-width', and you resize it smaller than the min-width, the placeholder is able to resize smaller than the given min-width but the item itself is not.

So redragging the item gets you a item with the right size, but with a smaller placeholder.
This is probably a separate issue

@Hedva
Copy link
Author

Hedva commented Aug 30, 2018

Also found a partial fix for this. It doesn't work in all cases.

Add the following lines in the library's source at onStartMoving:

gridstack.js/dist/gridstack.js

Lines 1215 to 1240 in 7d9ac26

var onStartMoving = function(event, ui) {
self.container.append(self.placeholder);
var o = $(this);
self.grid.cleanNodes();
self.grid.beginUpdate(node);
cellWidth = self.cellWidth();
var strictCellHeight = Math.ceil(o.outerHeight() / o.attr('data-gs-height'));
cellHeight = self.container.height() / parseInt(self.container.attr('data-gs-current-height'));
self.placeholder
.attr('data-gs-x', o.attr('data-gs-x'))
.attr('data-gs-y', o.attr('data-gs-y'))
.attr('data-gs-width', o.attr('data-gs-width'))
.attr('data-gs-height', o.attr('data-gs-height'))
.show();
node.el = self.placeholder;
node._beforeDragX = node.x;
node._beforeDragY = node.y;
node._prevYPix = ui.position.top;
self.dd.resizable(el, 'option', 'minWidth', cellWidth * (node.minWidth || 1));
self.dd.resizable(el, 'option', 'minHeight', strictCellHeight * (node.minHeight || 1));
if (event.type == 'resizestart') {
o.find('.grid-stack-item').trigger('resizestart');
}
};

.attr('data-gs-min-width', (o.attr('data-gs-min-width') || 0))
.attr('data-gs-max-width', (o.attr('data-gs-max-width') || 0))
.attr('data-gs-min-height', (o.attr('data-gs-min-height') || 0))
.attr('data-gs-max-height', (o.attr('data-gs-max-height') || 0))

So it looks like this:

var onStartMoving = function(event, ui) {
  self.container.append(self.placeholder);
  var o = $(this);
  self.grid.cleanNodes();
  self.grid.beginUpdate(node);
  cellWidth = self.cellWidth();
  var strictCellHeight = Math.ceil(o.outerHeight() / o.attr('data-gs-height'));
  cellHeight = self.container.height() / parseInt(self.container.attr('data-gs-current-height'));
  self.placeholder
    .attr('data-gs-x', o.attr('data-gs-x'))
    .attr('data-gs-y', o.attr('data-gs-y'))
    .attr('data-gs-width', o.attr('data-gs-width'))
    .attr('data-gs-height', o.attr('data-gs-height'))
    .attr('data-gs-min-width', (o.attr('data-gs-min-width') || 0))
    .attr('data-gs-max-width', (o.attr('data-gs-max-width') || 0))
    .attr('data-gs-min-height', (o.attr('data-gs-min-height') || 0))
    .attr('data-gs-max-height', (o.attr('data-gs-max-height') || 0))
    .show();
  
  node.el = self.placeholder;
  node._beforeDragX = node.x;
  node._beforeDragY = node.y;
  node._prevYPix = ui.position.top;

  self.dd.resizable(el, 'option', 'minWidth', cellWidth * (node.minWidth || 1));
  self.dd.resizable(el, 'option', 'minHeight', strictCellHeight * (node.minHeight || 1));

  if (event.type == 'resizestart') {
    o.find('.grid-stack-item').trigger('resizestart');
  }
};

As said earlier, this doesn't fix all cases(new drag/drop gets old placeholder sizes), but it does fix it for resizing.

@adumesny
Copy link
Member

adumesny commented Dec 21, 2019

thanks for looking so deeply and referencing other issues - make our job easier!
hopefully I can take a look and fix it in the lib soon...

see #413

@adumesny
Copy link
Member

real fix in #1107 - sorry it took so long and thank you @ermcgrat

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

3 participants