/jquery.shapeshift

A dynamic grid system with drag and drop functionality.

Primary LanguageJavaScriptMIT LicenseMIT

Inspired heavily by the jQuery Masonry plugin (http://masonry.desandro.com/), Shapeshift is a plugin which will dynamically arrange a collection of elements into a grid in their parent container. An example of this behavior is what you can find at sites like http://www.pinterest.com.

Shapeshift is intended to be a very bare bones version of these grid systems, however the drag and drop is what sets it apart from the other similar plugins.

Check out a demo here.

Responsive Grid

Resizing the grid to accomodate for more or less space is automatically turned on in Shapeshift, so if your parent container has a 100% grid resizing the window will shapeshift the child objects around to accomodate for the new layout. You can even set CSS3 media queries on your objects and watch as they get shapeshifted around their new size!

Drag and Drop

Position any item within the grid by dragging and dropping them into place. Shapeshift will try to find a logical place for it and display that to you. Coming soon is the ability to drag and drop between multiple containers.

Works on Touch Devices

To have the drag and drop functionality on touch devices you must include the "jquery.ui.touch-punch.min.js" file within the vendor folder. jQuery touch punch extends the jQuery UI Draggable library with touch support, so it must be included before Shapeshift and after the jQuery ui library.

Credits

A big thanks to all of our contributors!

we the media

Shapeshift is maintained by We The Media, inc.

Sites Using Shapeshift

Got a project that you are using shapeshift on? Let us know and we will happily throw a link to your page here!

Getting Started

Dependencies

Shapeshift requires the latest version of jQuery, and the drag and drop functionality requires jQuery UI Draggable/Droppable libraries. It also requires jQuery Touch Punch to work on touch devices.

Setting Up the Parent Container

Objects that get shapeshifted will be absolutely positioned in their parent container. Therefore the parent container must be set to position: relative for the objects to position themselves correctly.

<div class="container" style="position: relative;"></div>

Setting up the Child Elements

The direct children of the parent element are what gets rearranged into the grid system. As mentioned before, each child element will be absolutely positions and obviously must then have a position: absolute attached to them.

note: All child elements must be the same width. Heights can be dynamic, however.

<div class="container" style="position: relative;">
  <div style="position: absolute;">Child Element 1</div>
  <div style="position: absolute;">Child Element 2</div>
  <div style="position: absolute;">Child Element 3</div>
  <div style="position: absolute;">Child Element 4</div>
</div>

The class name and type of elements you can use are completely changable. The only real requirement is the parent must be relative and the children absolute. You can even call shapeshift on multiple elements that have the same class name.

Shapeshift Everything!

Now that we have our setup complete, simply call .shapeshift() on the parent element. It will, by default, select all the children in the parent element to be rearranged.

$('.container').shapeshift();

Shapeshift Options

There are several options that can be passed into the plugin through the objects hash, which also includes turning core features on or off. Here is an example of those options and then descriptions of each attribute.

All of these attributes are the defaults.

$('.container').shapeshift({
  // Features
  centerGrid: true,
  enableAnimation: true,
  enableAutoHeight: true,
  enableDrag: true,
  enableDragAnimation: true,
  enableRearrange: true,
  enableResize: true,

  // Options
  animateSpeed: 150,
  columns: null,
  dragClone: false,
  dragRate: 100,
  dragWhitelist: "*",
  dropCutoff: 0,
  dropWhitelist: "*",
  gutterX: 10,
  gutterY: 10,
  minHeight: 100,
  paddingY: 0,
  paddingX: 0,
  selector: ""
});
Feature Description Type Default Example
centerGrid Center the grid inside the container. This is mainly helpful for when using a responsive container width. Boolean true false
enableAnimation Objects will animate into their new position when shapeshift() is initialized, or when the container is resized. Boolean true false
enableAutoHeight If this is set to true the parent containers height will be automatically be adjusted to compensate for all of the child elements. Boolean true false
enableDrag Enables objects in this container to be drag and dropped. Boolean true false
enableDragAnimation Turn off the object animations of other elements when an element is being dragged. Boolean true false
enableRearrange Setting this to false will disable any rearrangement via drag & drop in the current container. Boolean true false
enableResize The elements will dynamically adjust to the width of their parent container. Boolean true false
Option Description Type Default Example
animateSpeed The speed in milliseconds that the animations will transition using. This currently will also determine how often the drag function gets called, which is the animation speed divided by three (i.e. for the default speed, 100, the drag function will run every 33.3 milliseconds). Integer 150 276
columns Manually specify the number of columns to render. It will automatically detect the maximum amount of columns by default. Integer null (Auto) 5
dragClone If set to true, the item that is dragged will be a clone and therefore will not remove the item from the original container upon drop. This would be analogous to "copy and paste", instead of the default "cut and paste". Boolean false true
dragRate Determines how often the program will detect a position for the currently dragged item to be dropped, in milliseconds. The faster the speed then the more the computer will have to process, but the slower the speed the less responsive it is to items being dragged around. Integer 100 55
dragWhitelist Specify a string which contains the elements that ***can*** be dropped into this container. This defaults to any element being draggable. String "*" ".comment, .post, div, #taco"
dropCutoff Prevents a user from dropping an item X amount from the end of the objects list. For example, if you have 20 items in your container, and you set the dropCutoff to be 3, then you would not be able to drop after the 17th item. Integer 0 3
dropWhitelist Specify a string which contains the elements that ***can*** be dropped into this container. This defaults to any element being droppable.
***If a white list is set, only items listed with it can be draggable.***</td>
<td>String</td>
<td>"*"</td>
<td>".comment, .post, div, #taco"</td>
gutterX Sets the amount of padding horizontally between columns. Integer 10 25
gutterY Sets the amount of padding vertically between objects. Integer 10 25
minHeight Set a minimum height that the container element will be. ***This is only helpful if you have enableAutoHeight turned on.*** Integer 100 550
paddingX Offset the entire grid from the left side of the container element with this attribute. Integer 0 42
paddingY Offset the entire grid from the top of the container element with this attribute. Integer 0 42
selector Shapeshift will by default try to rearrange all of the child elements within the parent element. Setting a selector will target only the children with the class, ID, or element name that the selector describes. String "" ".gallery_image"

Styling the Dragged Element

When an element is picked up it the ".ss-moving" class will be appended to it. Just target it in your own CSS file. For example,

.container .ss-moving {
  opacity: .7;
  transform: rotate(3deg);
}

Detecting Changes

When an item has begun being dragged, it will trigger the "ss-event-dragged" on the container element. You can then write out some code to be fired off when that event occurs. The object that was just selected is also passed back to you. For example,

$containers.on("ss-event-dragged", function(e, selected) {
  var $selected = $(selected);
  console.log("This is the item being dragged:", $selected);
});

Another event that you can watch for is the dropped event. This will also return the selected element, and is useful for getting the final index positions for all the elements in the container. For example,

$containers.on("ss-event-dropped", function(e, selected) {
  var $selected = $(selected)
  console.log("The dropped item is:", $selected)

  // Get the index position of each object
  $objects = $(this).children();
  $objects.each(function(i) {
    console.log("Get the index position:", i)
    console.log("Get the current element:", $(this))
  });
});

For contributors

Feel like you've got an idea on how to optimize the code and want to share it? We are totally open to new changes, however this is one of the first publically available plugins that I am offering and therefore do not have an exact process on pull requests. Feel free to fork the project all you want, but be aware any pull requests that are made may take a while to get implemented (if at all).