Code Monkey home page Code Monkey logo

juicy-tile-list's Introduction

โš ๏ธ This element is DEPRECATED, we lack of resorces to support it any longer. Please write an issue if you are interested in maintaining it.

<juicy-tile-list> Bower Version Build Status

<juicy-tile-list> is masonry-like Custom Element for sortable tiles that packs efficiently without changing HTML structure (changes CSS only).

Features

It gives you:

  • masonry-like, gap-less layout (bin-packing),
  • layout applied in Shadow DOM - so it doesn't mess with your styles,
  • prioritizing items,
  • grouping into virtual, nested containers,
  • alignment in different orientations and directions,
  • dynamically changing size,
  • auto adjusting container sizes,
  • gutter/cell-spacing between tiles,
  • adapting to window size changes.

Demo

Check it live!

Usage

  1. Install the component using Bower:

    $ bower install juicy-tile-list --save
  2. Import Web Components' polyfill, if needed:

    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
  3. Import Custom Element:

    <link rel="import" href="../juicy-tile-list/dist/juicy-tile-list.html">
  4. Start using it!

    <juicy-tile-list></juicy-tile-list>

Options

Attribute Options Default Description
defaultTileSetup Object see below Overwrites default values for Tiles (setup.items[?].?)
gutter Number 0 Overwrites default value of setup.gutter
duration Number 0.5 Duration of repack animation (in seconds).
setup Object Tiles setup
setup.width Number Container width to be used for packing in horizontal direction, if not given innerWidth(this) will be used.
setup.heigh Number Container height to be used for packing in vertical direction, if not given innerWidth(this) will be used.
setup.gutter Number 0 Gutter/cell-spacing size in px
setup.direction String horizontal How to align our package (horizontal layers horizontal, or vertiacal layers: vertical)
setup.rightToLeft Boolean false If set to true, tiles within this container will be arranged from the right to the left.
setup.bottomUp Boolean false If set to true, tiles within this container will be arranged from the bottom to the top.
setup.items Array [] Tiles setup
setup.items[?].priority Number (0-1) 0 Importance of tile, used for sorting elements.
setup.items[?].width Number 1 Tile width
setup.items[?].precalculateWidth Boolean false Set to true to automatically pre-calculate width before every (re-)packing.
setup.items[?].heigh Number 1 Tile height
setup.items[?].precalculateHeight Boolean false Set to true to automatically pre-calculate height before every (re-)packing.
setup.items[?].id String Element/group id by default order in DOM will be used
setup.items[?].content String HTML content for (for virtual containers)
setup.items[?].oversize Number 0 Make container's box & background bleed for this amount of pixels out of packed box. So, render box bigger, but pack with its original size (for virtual containers)
setup.items[?].items Array(Items) Recursive setup (for virtual containers)
setup.items[?].gutter Number 0 Recursive setup (for virtual containers)
setup.items[?].direction String Recursive setup (for virtual containers)
setup.items[?].rightToLeft Boolean Recursive setup (for virtual containers)
setup.items[?].bottomUp Boolean Recursive setup (for virtual containers)
refreshOnMutation Boolean false If set to true, tile-list will be repacked and re-rendered once nodes are added or removed.
refreshOnResize Boolean false If set to true, tile-list will be repacked and re-rendered once window or container gets resized
refreshOnAttached Boolean true If set to true, tile-list will be repacked and re-rendered once (re-)attached to DOM

Properties

Name Options Description
elements Array Array of children which are going to be arranged.
duration Number Duration of repack animation (in seconds).
setup Object Up to date tiles setup. Structure as in attributes.
allItems Object Map of setup nodes. Root container is available under allItems['root'].
items[.].container Object Reference to container item. (non-enumerable property)

Methods

Name Param name Type Default Description
resizeItem Resize any item (real element or virtual container)
               | item       | *Item*             |         | Reference to the setup item
               | width      | *Number*           | `0`     | new width
               | height     | *Number*           | `0`     | new height

reprioritizeItem | | | | Change priority/weight of any item | item | Item | | Reference to the setup item | increase | Boolean | false | true - increases, false decreases priority | end | Boolean | false | true to move to the end of list moveToContainer | | | | Move any item to given container, or wrap it with new one | what | Item | | Reference to the setup item | where | Item | | Reference to the destination container item. | noPacking | Boolean | false | true to prevent re-packing after setup change. createNewContainer| | | | Create new empty virtual container. | name | String | | Name for the container | where | Item | "root"| Reference to the container setup item | rectangle | Rectangle | | Rectangle setup (width, height, priority) | noPacking | Boolean | false | true to prevent re-packing after setup change. deleteContainer | | | | Delete virtual container, move items (if any) to one above. | what | Item | | Reference to the container setup item to delete. | noPacking | Boolean | false | true to prevent re-packing after setup change.

Events

Name Data Description
juicy-tile-list-refresh - Triggered once layout is refreshed

Refresh/repack

<juicy-tile-list> can refresh/repack your tiles interactively. You can set it by attributes: refreshOnMutation, refreshOnResize, refreshOnAttached.

๐Ÿ‘พ ๐Ÿšง Per-item declarative setup (experimental feature)

If you would like to provide more declaratively setup for each element of <juicy-tile-list>, you can do so by adding custom attribute juicy-style on child element, and provide setup in CSS-like syntax:

<juicy-tile-list>
 <div juicy-style="width: 50%; height: 20;">smth</div>
</juicy-tile-list>

instead of setting it via setup:

juicytilelist.setup = {
  // ...    
  items:[
    {
      id: 0,
      priority: 0.2,
      width: "50%",
      height: 20
    }
  ]
}

Properties provided in juicy-style extends defaults, but may be overwritten by explicit setup entry.

The importance of setups, looks as follows:

  1. juicy-tile-list's setup attribute/property,
  2. juicy-tile-list's child juicy-style attribute (extends defaults mentioned below),
  3. juicy-tile-list's defaultTileSetup attribute,
  4. juicy-tile-list's build in default tile setup.

Meaning, that a setup higher on the list overwrites previous values

Tile ids

Every tile gets its id, it's used in ShadowDom (so it won't collide with your markup) to match Light DOM content with positioned tile (and its setup). In HTML ids get created automatically, from order in DOM, so in your setup JSON you simply need to match the index of child node.

๐Ÿšง Custom ids (experimental feature)

If for some reason, consecutive numbers does not fit your needs, you can assign id manually, by setting juicytile attribute:

<juicy-tile-list>
 <div juicytile="myFancyTileId">smth</div>
</juicy-tile-list>
juicytilelist.setup = {
  items:[
    {
      id: "myFancyTileId",
      priority: 0.2
    }
  ]
}

Scoped ids (experimental feature)

You can also add name-space to your id in declarative way.

<juicy-tile-list>
  <juicy-tile-group name="fruits">
    <div>apple</div>
  </juicy-tile-group>
  <juicy-tile-group name="veggies">
    <div>carrot</div>
  </juicy-tile-group>
</juicy-tile-list>
juicytilelist.setup = {
  items:[
    {
      id: "fruits/0",
      priority: 0.2
    },
    {
      id: "veggies/0",
      priority: 0.4
    }
  ]
}

Related components

Development

Naturally stary with npm install and bower install.

Minify

To minify code you can use grunt minify

Release

To minify, bump versions and release it, use grunt release

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -m 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

History

For detailed changelog, check Releases.

License

MIT

juicy-tile-list's People

Contributors

diegohaz avatar tomalec avatar warpech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

juicy-tile-list's Issues

Consider changing "virtual containers" into real "Shadow DOM containers"

As we now have tiles in ShadowDOM, we could mess with DOM there.
We would still keep the grail of not touching user's elements, and polluting the (light) DOM.
But we will simplify the component, on both conceptual and code level.

The price is that we may hit the performance as we would perform DOM moves.

However, I think it's worth to measure the impact, as we wouldn't probably do much around the DOM - we will construct the separated tree on load(or setup change), then just distribute child nodes as we do anyways.

Consider separation of smoke test and unit tests

We can divide our automated test to

  • unit test group - for very atomic tests for individual functionalities, and
  • smoke test group - which will contain common use cases, or use cases that were reported as bugs

Make configuration `item.id` (`item.index`) optional.

Make configuration easier and shorter:

{
    items:[
        {
            priority:0.9,
            height: 50,
            width: 50
        },
        {
            priority:0.8,
            height: 100,
            width:50
        }
    ]
}

should be enough, as we could use indexOf element in items array if not given explicitly.

However it should work only for root level, and naturally will require index, if you want to mix virtual containers between real items.

Make workaround for lack of `Element#onresize` event nicer.

Currently workaround just finds parent <juicy-tiles> element and listen to its change.
However, current <juicy-tiles> ma get resided by any other element or event.

Consider writing cross-browser Element#onresize support, or even make it separated Web Component..

Polymer 1.0?

Now polymer 1.0 is out, it would be nice to have a compatible version of this..

Separate to different responsibility layers to improve performance

In order to improve performance, we will separate <juicy-tile-list> to layers as bellow, so most common case will use raw CSS configuration and get reduced to almost just browser rendering.

  • <juicy-css-tile-list css=".."> will just decorate child nodes in ShadowDOM, and apply given CSS. Given as text or file path.

  • <juicy-tile-list>/<juicy-tile-list-json-to-css-manager json="{}" css="{{}}"> will take readable json configuration and process it to the CSS code which will be used by layer above.

  • <juicy-tile-list> or just suggested use case code, that will use CSS if given, or call <juicy-tile-list-json-to-css-manager> , or <juicy-tile-editor> if needed:

    <template>
    <template if="{{relayout || !css}}">
      <link rel="import" href="juicy-tile-list-json-to-css-manager.html"/>
      <juicy-tile-list-json-to-css-manager css="{{css}}" json="{{json}}"></juicy-tile-list-json-to-css-manager>
    </template>
    <juicy-tile-list css="{{css}}">
      <content><!-- content of "polyjuice-merger" HTML --></content>
    </juicy-tile-list>
    </template>

So it will work smoothly with view-model like:

{
    Html: "/path/to/merged.html?..",
    app1: {..},
    app2: {..},
    setup: {
        css: "/path to virtual.css",
        relayout: true/false, // set when something get changed in merged HTML, or just set empty css property
        json: {..}
    }
}

Naming suggestions welcome ;)

Plural word in name is confusing

Jocke pointed out that element name should always be singular to avoid confusion.

Maybe we should rename juicy-tiles to juicy-tile (Jocke's suggestion) or juicy-tile-list.

Ideas go!

Separate tiles, sortable-tiles, recursive tiles, and editor to standalone Web Components

Just to make it more reusable by others, and give conceptual separation.

Auto-arranging tiles could be quite commonly used, but full stack of features we need in PJ is probably quite specific.

So we could divide what we have to:

Juicy-tile-list does not work with text nodes; what to do about it

It happened to me more than once that I was trying to render such template in juicy-tile-list:

<template>
   Hello World
</template>

As an app developer I would totally expect this to work. It doesn't work with juicy-tile-list, because only element nodes are rendered. Text nodes are ignored.

This works as expected:

<template>
   <div>Hello World</div>
</template>

I propose to either:

  1. wrap text nodes in Shadow DOM (hard)
  2. show console.error for any non-empty text node in juicy-tile-list root (easy)

refreshOnResize is broken by first breakpoint

Implementation of first breakpoint uses width/height of given setup. But usually, when refreshonresize attribute is on, someone may expect size to adjust to the new values, instead of keeping the first one.

We may once again consider use of precalculateWidth/-Height for root containers.

"Export" packed elements as CSS grid

Instead of using position: absolute; we could try render packed items using CSS grid layout.

We could either hardcode it within juicy-tiles, or make separate component, that renders layout according to same JSON config.

Wrap tiles in Shadow DOM

In some kind of <juicy-tile> or just <div>.
It should

  • simplify code and concept,
  • make our component way less intrusive,
  • we will not modify CSS of content nodes,
  • 3rd party tiles may use padding/margins etc. freely.

Move DOM related operations to juicy-tiles.html

DOM related operations should be moved from Package.js to juicy-tiles.html (perhaps inside refresh() method). It may be required to create one or two callbacks to be passed to Package.packItems() that will prepare layout of elements and apply the styles.

Documentation on dynamically adding elements?

I have a mixture of images and probably sized DIV elements that I'd like to dynamically create. But when I try to appendChild(element) to the juicy-tile-list, I don't see any results.

Is there a different way to add elements? Looking for some documentation on this.

Cache original tile size

As we still didn't find a way to Wrap tiles in Shadow DOM (#22), and we overwrite child element's style, it could be nice to cache/expose original dimensions somewhere.
It should help with:

  • applying "auto" height according to initial styles,
  • reverting styles back,
  • at least notice users(devs) what's going on

@warpech ideas from discussion started at https://github.com/Polyjuice/Launcher/issues/79#issuecomment-48712000 :

I propose to store the original inline style as a data attribute (https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes, https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.dataset)

Animations and tests

We may toggle css transition animations using attribute/class/custom style as one one hand, they looks nice, but they complicate automated tests, and juicy-tile-grid extension

Re-implement height auto

Height auto should be reimplemented. We discussed that a way to achieve it is to remove height from being passed to Packer.js.

Instead, we should just pass one dimension constraint, which will be width for horizontal direction or height for vertical direction.

The other dimension becomes unconstrained. This means Packer.js will create slots with infinite maximum size and report that size back to Package.js upon finish.

Then, Package.js can decide whether that size exceeds the assumed dimensions for the container and show it (if height="auto") or clip it out.

This goes in line with suggestions in this ticket: https://github.com/Polyjuice/Launcher/issues/44

Move load & save functionality out of juicy-tile-list

As discussed today on a call with Tomek:

Loading/saving of the setup should not be the responsibility of <juicy-tile-list>.

Proposed solution - move load & save methods out from <juicy-tile-list> to <juicy-tile-editor>.

Support right-to-left and other orientations

Currently we do support following directions of packing

  • "rightDown" - find place on right, if none go down /
    horizontal layers left-to-right
  • "downRight" - find place bellow, if none go right /
    horizontal layers left-to-right

It would be nice to support at least left-to-right direction: for RTL languages, though layouts, for compatibility with bootstrap/flexbox/flexgrid demos (Juicy/juicy-tile-grid#13) ;)
Bottom up seems awkward, but why don't we support it as well.

Sometimes gap is calculated incorrectly

See tile 3 here:
gap_bug_html
Configuration:

{
  "gap": 25,
  "items": [
    {
      "name": "name",
      "background":"rgba(150,150,150,0.15)",
      "priority": 0.9,
      "gap": 0,
      "heightAuto": true,
      "width": 320,
      "items":[
            {
              "index": 0,
              "priority": 0.9,
              "height": 50,
              "width": 160
            },
            {
              "index": 1,
              "priority": 0.8,
              "height": 140,
              "width": 160
            }
      ]
    },
    {
      "index": 4,
      "priority": 0.79,
      "height": 115,
      "width": 160
    },
    {
      "index": 5,
      "priority": 0.61,
      "height": 25,
      "width": 160
    },
    {
      "index": 2,
      "priority": 0.7,
      "height": 140,
      "width": 160
    },
    {
      "index": 3,
      "priority": 0.6,
      "height": 50,
      "width": 160
    }
  ],
  "name": "root",
  "width": 539.703125,
  "heightAuto": true
}

Replace bin-packing with word-wrapping

I discussed this with @Starcounter-Jack on the phone today.

It seems that a lot of times we are fighting with bin-packing algorithm, which fills the gaps with contents with lower priority, if elements with higher priority are already placed.

For example, consider such layout:

<span juicy-style="width  50px; priority 1.00"></span>
<div  juicy-style="width 400px; priority 0.75"></div>
<span juicy-style="width  50px; priority 0.50"></span>
<div  juicy-style="width 400px; priority 0.25"></div>

When the container is 400px wide, bin-packing renders it like below (disregarding the arbitrary priority):

SPAN SPAN
DIV
DIV

Whereas word-wrapping would render it like this:

SPAN
DIV
SPAN
DIV

I would like to discuss creating word-wrapping mode in packery and turn it ON by default.

Bin-packing is a nice feature in general (when you are building Pinterest), but not so efficient when you are building a business form.

Also, with word-wrapping, line break feature (#47) makes much more sense.

Relative dimension in group does not work

In

 {width: 200,
    items: [{
      id: "group",
      items:[
        {
          id: 0,
          priority: 0.9,
          height: 50,
          width: 100
        },{
          id: 1,
          priority: 0.7,
          height: 50,
          width: "50%"
        }
      ],
      priority: 0.9,
      height: 50,
      width: 200
    }]
}

Second item is not packed after first.

Change priority range

Today @Starcounter-Jack suggested changing the priority range to 1-100 (and direction to ascending).
The goal is to avoid 0.00000000000001 hacks in case of tiles provided by different vendors.

With priorities still used as (real) Numbers, but advertised as in natural range, with somehow described steps, we would not block it technically, but we hope that naturally people will use numbers like 1,2,3. So instead of thin tailed exponential distribution, we will get something more log-normal.

Add line break feature

On today's (2016-02-04) meeting @Starcounter-Jack came with the idea of "line break" feature, that will make sure that the element will be packed in the "new row". The way to achieve that would be to mark entire space before the highest x and y of items packed before, as not available.

Here is a picture that visualize the "line break" set for tile 4:
20160204_170803 linebreak in packery

I would suggest to rephrase it a little bit:

As the button uses return/line break icon, we will call the property "line break", and attach it the the last element (3) before marking space as not available.
("line" applies for vertical and horizontal breaking, "new row" could be confusing, as there are grid/table "rows" between 3 and 4, so someone could think, we went too far; "line break" in other environments is used at the end of a line, not at the beginning).

Then (to adhere to the implementation specifics), after "line break" element we will simply use current \max_{packed} y (\max_{packed} x, for column axis), to remove from free slots set all rectangles that starts at smaller y (x).

With such definition, we could apply it to any axis (rows/cols), in any direction (vert./horiz.) and orientation (RTL/..).

Plus, you closes your line, so event without specifying new line, you will be sure that no other new element (with lower priority) could break into 'your' free space.

Naturally, we do not have to expose all directions to the editor/end user.

Make tests pass in Edge

It seems that everything works, but for some reason tests fail on Win 10 Edge.

I bet it's similar issues to the ones I have fixed for Firefox and IE recently: Web Components shims make every thing asynchronous.

I tried to test it on virtual machine, but there most of them pass, so maybe it's a matter of increasing the timeout.

@miyconst, if you will have some spare time could you take a look at it?

When resizing container quickly, size "auto" for real elements fails.

Calculating desired dimension reads scrollSize of the element in its previous position, so its content may wrapp. We could move it to (0,0) before, but still we will read dimensions before transition is finished, so when the element is still on its previous position, but it is "cut" by windows size.

It could be fixed by disabling transition while calculating size, but this would result with no transition at all when window is being resided smoothly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.