selectorClass

Default: false

This string is used to find the elements that filter/sort the boxes.

To learn more, go to Filter.

<button class="selector" data-filter="">all</button>
<button class="selector" data-filter="letter-r">Has the letter "R"</button>
<button class="selector" data-filter="letter-l">Has the letter "L"</button>
<button class="selector" data-filter="letter-n">Has the letter "N"</button>

<div id="container">
  <div class="box letter-r" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box letter-r letter-n" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box letter-l" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box letter-r letter-n" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box letter-l" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box letter-r letter-l" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container", ".box", {
  selectorClass: "selector"
});

selectorEventListener

Default: "click"

This is the event that binds filter/sort functionality to the input with the selectorClass.

<div class="selector-12" style="background-color: white" data-filter="">all</div>
<div class="selector-12" style="background-color: red" data-filter="red">Red</div>
<div class="selector-12" style="background-color: yellow" data-filter="yellow">Yellow</div>
<div class="selector-12" style="background-color: blue" data-filter="blue">Blue</div>

<div id="container-12">
  <div class="box red" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box red yellow" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box yellow" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box blue yellow" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box blue" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box blue red" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container", ".box", {
  selectorClass: "selector",
  selectorEventListener: "mouseenter"
});
all
Red
Yellow
Blue

initialRender

Default:

{
  filter: "",
  sort: "",
  order: ""
}

This option controls how the boxes are filtered, sorted, and ordered on the initial render. Add a value to filter or sort on equal to one of the selectors' data-filter or data-sort values. Order is ascending by default. If you want you want to descending order, set the order value to "desc" or "descending".

<button class="selector" data-filter="">all</button>
<button class="selector" data-filter="letter-r">Has the letter "R"</button>
<button class="selector" data-filter="letter-l">Has the letter "L"</button>
<button class="selector" data-filter="letter-n">Has the letter "N"</button>

<div id="container">
  <div class="box letter-r" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box letter-r letter-n" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box letter-l" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box letter-r letter-n" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box letter-l" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box letter-r letter-l" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container", ".box", {
  selectorClass: "selector",
  defaultCategory: "letter-r"
});

filter and sortData

Default: []

Note: Gonna wait for example before I build up another example.

<button class="selector" data-filter="">all</button>
<button class="selector" data-filter="letter-r">Has the letter "R"</button>
<button class="selector" data-filter="letter-l">Has the letter "L"</button>
<button class="selector" data-filter="letter-n">Has the letter "N"</button>

<div id="container">
  <div class="box letter-r" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box letter-r letter-n" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box letter-l" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box letter-r letter-n" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box letter-l" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box letter-r letter-l" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container", ".box", {
  selectorClass: "selector",
  defaultCategory: "letter-r"
});

resize

Default: true

Adds a event listener to the window listening for resize. When the window resizes it calls tessarray.renderOnResize(), which checks if the width of the container has changed before calling tessarray.render().

If you make the container width static through css or the flickr option containerWidth, or you want to handle all of the resizing yourself, set this to false to prevent renderOnResize from firing unneccessarily.

<div id="container">
  <div class="box" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container", ".box", {
  resize: false
});

Transitions

By default the transition options are objects. If you want to change the attributes of a transition, you have to define all of the attributes of the object

var tessarray = new Tessarray("#container", ".box", {
  containerTransition: {
    duration: 500,
    timingFunction: "cubic-bezier(0.320, 1.385, 0.730, -0.470)",
    duration: 0
  }
});

If you don't want that transition at all, you set the value to false.

tessarray = new Tessarray("#container", ".box", {
  containerTransition: false
});

If you want to write your own transition, write it as a string and pass it to the option as such:

tessarray = new Tessarray("#container", "box", {
  boxTransition: "transform 500ms ease-in 0ms, height 500ms ease-in 0ms, width 500ms ease-in 0ms, opacity 400ms ease-out 0ms"
});

It's important to note that the code above only adds an opacity transition to the boxTransition, as the default boxTransition has identical transitions on transform, height, and width.

If you want to write your own transitions in CSS, set both boxTransition and boxTransformOutTransition to false.

Note: should I mention that this is not recommended? Tessarray's load gets a little ugly because everything transforms in.

containerTransition

Default:

{ duration: 375, timingFunction: "ease-in", delay: 0 }

The default value evaluates to: transition: opacity 350ms ease-in 0ms

Options for the container's opacity transition. It is used to fade in the container once tessarray knows the dimensions of the boxes on initial render.

<div id="container">
  <div class="box">
    <img class="image" src="https://source.unsplash.com/category/nature/720x1080"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/category/nature/900x900"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/category/people/1600x900"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/category/nature/800x600"/>
  </div>
</div>
<p>This text is below the Tessarray object. This should slide down</p>
#container {
  height: 0px;
  overflow: hidden;
}
.image {
  height: 100%;
  width: 100%;
}
var tessarray = new Tessarray("#container", ".box", {
  containerTransition: "height 500ms ease-in, opacity 350ms ease-in"
});

This text is below the Tessarray object. This should slide down

boxTransition

Default:

{ duration: 375, timingFunction: "ease-in", delay: 0 }

The default value evaluates to transition: transform 500ms ease-in 0ms, height 500ms ease-in 0ms, width 500ms ease-in 0ms;.

This controls most of the boxes' transitions on transform, height, and width. This option does not control how the boxes are transformed when they are scaled out (such as when they are filtered). This transition is set on every box every time render is called except for the initial render, when it set immediately after.

This example uses a slower, smoother transition, and slows the boxTransformOutTransition to match.

Note: Css is not up to date, and the button needs to be fixed once Tessarray is more synchronous.

<button class="selector" data-filter="">all</button>
<button class="selector" data-filter="letter-r">Has the letter "R"</button>
<button class="selector" data-filter="letter-l">Has the letter "L"</button>
<button class="selector" data-filter="letter-n">Has the letter "N"</button>

<div id="container">
  <div class="box letter-r" style="background-color: red;" data-aspect-ratio="1.333"></div>
  <div class="box letter-r letter-n" style="background-color: orange;" data-aspect-ratio="1"></div>
  <div class="box letter-l" style="background-color: yellow;" data-aspect-ratio="1.6"></div>
  <div class="box letter-r letter-n" style="background-color: green;" data-aspect-ratio="1.33"></div>
  <div class="box letter-l" style="background-color: blue;" data-aspect-ratio=".75"></div>
  <div class="box letter-r letter-l" style="background-color: purple;" data-aspect-ratio="1.333"></div>
</div>
var tessarray = new Tessarray("#container",".box", {
  selectorClass: "selector",
  boxTransition: {
    duration: 700,
    timingFunction: "cubic-bezier(0.215, 0.61, 0.355, 1)",
    delay: 0
  },
  boxTransformOutTransition: {
    duration: 350,
    timingFunction: "linear",
    delay: 0
  }
});

boxTransformOutTransition

Default:

{
  duration: 250,
  timingFunction: "ease-in",
  delay: 0
}

This controls the boxes' transitions when they disappear from the layout layout. Every time render is called, every box is assigned the boxTransition transition. Every box that is not going to be rendered in the next filteration then has that transition overwritten by boxTransformOutTransition before the box nodes are scaled down to nothing.

This transition happens independently of boxTransition because the transitions out felt sluggish when they took the same pace.

<button class="selector" data-filter="">All</button>
<button class="selector" data-filter="nature">Nature</button>
<button class="selector" data-filter="people">People</button>
<div id="container">
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/720x1080"/>
  </div>
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/900x900"/>
  </div>
  <div class="box people">
    <img class="image" src="https://source.unsplash.com/category/people/1600x900"/>
  </div>
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/800x600"/>
  </div>
</div>
.image {
  height: 100%;
  width: 100%
}
var tessarray = new Tessarray("#container", ".box", {
  selectorClass: "selector",
  boxTransformOutTransition: {
    duration: 0,
    timingFunction: "ease-in",
    delay: 0
  }
});

Class Hooks

containerLoadedClass

Default: "container-is-loaded"

This class is added to the container once the container knows the aspect ratios for every box.

<div id="container">
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/720x1080"/>
  </div>
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/900x900"/>
  </div>
  <div class="box people">
    <img class="image" src="https://source.unsplash.com/category/people/1600x900"/>
  </div>
  <div class="box nature">
    <img class="image" src="https://source.unsplash.com/category/nature/800x600"/>
  </div>
</div>
#container {
  left: 200%;
}
#container.container-is-loaded {
  left: 0%;
}
.image {
  height: 100%;
  width: 100%
}
var tessarray = new Tessarray("#container", ".box", {
  containerTransition: "opacity 600ms ease-in 0ms, left 600ms cubic-bezier(0.215, 0.61, 0.355, 1) 0ms"
});

boxLoadedClass

Default: "box-is-loaded"

This class is added to each box once the image within the box has completely loaded. If Tessarray cannot find an image in the box, this class will be added as soon as Tessarray reads the aspect ratio.

<div id="container">
  <div class="box nature" data-width="720" data-height="1080">
    <img class="image" src="https://source.unsplash.com/category/nature/720x1080"/>
  </div>
  <div class="box nature" data-width="900" data-height="900">
    <img class="image" src="https://source.unsplash.com/category/nature/900x900"/>
  </div>
  <div class="box people" data-width="1600" data-height="900">
    <img class="image" src="https://source.unsplash.com/category/people/1600x900"/>
  </div>
  <div class="box nature" data-width="800" data-height="600">
    <img class="image" src="https://source.unsplash.com/category/nature/800x600"/>
  </div>
</div>
.image {
  height: 100%;
  width: 100%;
  opacity: 0;
  transition: opacity 350ms ease-in 0ms;
}
.box-is-loaded .image {
  opacity: 1;
}
.box {
  background-color: grey;
}
var tessarray = new Tessarray("#container", ".box", {
  boxLoadedClass: "box-is-loaded"
});

Callbacks

onContainerLoad

Default: false

Callback that is triggered once the container knows all of its own properties as well as the aspect ratios for every box.

<div id="container">
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/buildings"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/food"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/nature"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/people"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/technology"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/objects"/>
    <div class="aspect-ratio-container">
      <p class="aspect-ratio"></p>
    </div>
  </div>
</div>
.image {
  height: 100%;
  width: 100%
}
.aspect-ratio-container {
  position: absolute;
  width: 100%;
  bottom: 0;
  text-align: center;
}
.aspect-ratio {
  color: white;
  font-size: 1.5em;
  margin: 0;
}
var tessarray = new Tessarray("#container", ".box", {
  onContainerLoad: function(tessarray) {
    for (var i = 0; i < tessarray.boxObjects.length; i++) {
      var aspectRatioParagraph = tessarray.boxObjects[i].boxNode.querySelector(".aspect-ratio");
      var aspectRatio = tessarray.boxObjects[i].aspectRatio;
      aspectRatioParagraph.innerHTML = Number((aspectRatio).toFixed(2)).toString() + ":1";
    }
  }
});

onBoxLoad

Default: false

Parameter: box object

This callback is called for each box once the image within the box has completely loaded. If Tessarray cannot find an image in the box, this class will be added as soon as Tessarray reads the aspect ratio.

Note: I'll change CSS in the code snippets after loadbar is changed

<div id="loader">
  <progress id="bar" value="0" max="6" ng-model="prog">
  </progress>
</div>
<div id="container">
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/buildings"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/food"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/nature"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/people"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/technology"/>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/objects"/>
  </div>
</div>
.image {
  height: 100%;
  width: 100%;
}
#loader {
  width: 100%;
  text-align: center
}
#loader progress {
  margin: 200px auto;
  display: inline-block;
  width: 60%;
  border-radius: 10px;
}
#loader progress::-webkit-progress-bar {
  height: 13px;
  border: 1px solid #170F2F;
  border-radius: 10px;
  background-color: #170F2F;
}
#loader progress::-webkit-progress-value {
  height: 12px;
  background-color: #FF4E47;
  border: 1px solid #170F2F;
  border-radius: 10px;
}
var progressComplete = function() {
  var progressContainer = document.getElementById("loader");
  var container = document.getElementById("container");
  progressContainer.style.opacity = 0;
  progressContainer.style.display = "none";
  container.style.opacity = 1;
};
var tessarray = new Tessarray("#container", ".box", {
  onContainerLoad: function(tessarray) {
    tessarray.container.style.opacity = "0";
  },
  onBoxLoad: function(box) {
    var progressBar = document.getElementById("bar");
    progressBar.value += 1;
    if (progressBar.value === 6) {
      setTimeout(progressComplete, 200);
    }
  }
});

onRender

Default: false

Parameters: tessarray object, initialRender (boolean)

Callback is called every time render is called. True is passed to initialRender if it is the first render, else false is passed.

Note: I might want a render button that renders new unsplash images. I really think I want a slider for rowHeightTolerance.

<p><code>tessarray.options.flickr.targetRowHeight = 300</code></p>
<p><code>tessarray.options.flickr.targetRowHeightTolerance = <span id="current-tolerance">0.25</span></code></p>
<input type="range" id="range-tolerance" value="25" min="0" max="100">
<div id="container">
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/buildings"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/food"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/nature"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/people"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/technology"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
  <div class="box">
    <img class="image" src="https://source.unsplash.com/random/objects"/>
    <div class="aspect-ratio-container">
      <p class="original-aspect-ratio aspect-ratio"></p>
      <p class="current-aspect-ratio aspect-ratio"></p>
    </div>
  </div>
</div>
#range-tolerance {
  width: 100%;
}
.image {
  height: 100%;
  width: 100%;
}
.aspect-ratio-container {
  position: absolute;
  width: 100%;
  bottom: 0;
  text-align: center;
}
.aspect-ratio {
  color: white;
  font-size: 1.5em;
  margin: 0;
}
var tessarray = new Tessarray("#container", ".box", {
  onContainerLoad: function(tessarray) {
    for (var i = 0; i < tessarray.boxObjects.length; i++) {
      var originalAspectRatioParagraph = tessarray.boxObjects[i].boxNode.querySelector('.original-aspect-ratio');
      var originalAspectRatio = tessarray.boxObjects[i].aspectRatio;
      originalAspectRatioParagraph.innerHTML = "Original: " + Number((originalAspectRatio).toFixed(2)).toString() + ":1";
    }
  },
  onRender: function(tessarray) {
    for (var i = 0; i < tessarray.boxObjects.length; i++) {
      var currentAspectRatioParapraph = tessarray.boxObjects[i].boxNode.querySelector('.current-aspect-ratio');
      var currentAspectRatio = tessarray.layoutGeometry.boxes[i].width / tessarray.layoutGeometry.boxes[i].height;
      currentAspectRatioParapraph.innerHTML = "Current: " + Number((currentAspectRatio).toFixed(2)).toString() + ":1";
    }
  },
  flickr: {targetRowHeight: 300}
});

var changeRowHeightTolerance = function() {
  var rowHeightTolerance = parseFloat(document.getElementById('range-tolerance').value) / 100;
  document.getElementById("current-tolerance").innerHTML = rowHeightTolerance;
  tessarray.options.flickr.targetRowHeightTolerance = rowHeightTolerance;
  tessarray.render();
};

document.getElementById('range-tolerance').addEventListener('input', tessarray.debounce(changeRowHeightTolerance, 100));

targetRowHeight = 300

targetRowHeightTolerance = 0.25

flickr options

Default: {}

These are the options that Flickr's Justified Layout provides to manipulate the layout. This default evaluates to this:

var tessarray = new Tessarray("#container", ".box", {
  flickr: {
    containerWidth: 1060,
    containerPadding: 10,
    boxSpacing: 10,
    targetRowHeight: 320,
    targetRowHeightTolerance: 0.25,
    maxNumRows: Number.POSITIVE_INFINITY,
    forceAspectRatio: false, 
    showWidows: true,
    fullWidthBreakoutRowCadence: false
  }
});

The complete documentation for Flickr's Justified Layout can be found here.