Skip to content

A library to apply linear partitioning algorithm to a set of photos.

Notifications You must be signed in to change notification settings

Sobesednik/photo-partition

Repository files navigation

photo-partition

A library to apply linear partitioning algorithm to a set of photos.

Usage

partitions(viewports, photoArray, desiredHeight, requestedRows)

  • viewports: an object which maps a viewport width to a container width. For example, in Bootstrap 3, @media queries for .container are setup in the following way:
@media (min-width: 1200px)
.container {
  width: 1170px;
}
@media (min-width: 992px)
.container {
  width: 970px;
}
@media (min-width: 768px)
.container {
  width: 750px;
}

Having the following structure,

<body>
  <div class="container">
    <div class="row">
      <div class="col-xs-12">
        <!-- photos go in here -->
      </div>
    </div>
  </div>
</body>

the col-xs-12 element with 15px padding on left and right will have width of 1140px, 940px and 720px for given min-width values.

Therefore, the viewports argument will be:

{
    1200: 1140,
    992: 940,
    768: 720,
}
  • photoArray: an array of photos as objects. Each object must contain both width and height properties, or aspect property. It can have other values, but they will be removed (todo: inherit properties in the returned object).

  • [desiredHeight]: what required height each image is supposed to take. The value will be used to calculate the total width of all images given their aspect: const summedWidth = lib.getSummedWidth(aspects, desiredHeight)

  • [requestedRows]: if desiredHeight is not given, static number of rows can be specified using this option.

getCSS(partitions, prefix)

  • partitions: an object generated with partitions function.
  • [prefix='s']: a prefix for every class, e.g., s will generate classes s0, s1, etc.

Example

const partitions = require('photo-partition')

const photoList = [
    { url: '/files/cd24b45a-48c3-4f78-a029-7725128e82ef.jpg',
        width: 2448,
        height: 3264,
        aspect: 0.75 },
    { url: '/files/9dc13701-4975-4e45-bbfe-ea6d315b983e.jpg',
        width: 2448,
        height: 3264,
        aspect: 0.75 },
    { url: '/files/91143cde-f06c-4b0b-86e1-9a1dc182fb01.jpg',
        width: 2448,
        height: 3264,
        aspect: 0.75 },
    { url: '/files/6737002f-4fa6-4479-b7eb-bb90271ea359.jpg',
        width: 3264,
        height: 2448,
        aspect: 1.33 },
    { url: '/files/28aac5b5-9a60-445e-b4d6-a51e485745c5.jpg',
        width: 3264,
        height: 2448,
        aspect: 1.33 },
    { url: '/files/d42ee39d-1827-433f-bca0-25c9ddf4abfa.jpg',
        width: 3264,
        height: 2448,
        aspect: 1.33 },
]

const p = partitions.partitions({
    1200: 1140,
    992: 940,
    768: 720,
}, photoList, 250) // partition for bootstrap viewports with desired height of 250
/*
{ '768':
   [ { height: 201, width: 151 },
     { height: 201, width: 151 },
     { height: 201, width: 151 },
     { height: 201, width: 267 },
     { height: 271, width: 360 },
     { height: 271, width: 360 } ],
  '992':
   [ { height: 263, width: 197 },
     { height: 263, width: 197 },
     { height: 263, width: 197 },
     { height: 263, width: 349 },
     { height: 353, width: 469 },
     { height: 353, width: 471 } ],
  '1200':
   [ { height: 183, width: 137 },
     { height: 183, width: 137 },
     { height: 183, width: 137 },
     { height: 183, width: 243 },
     { height: 183, width: 243 },
     { height: 183, width: 243 } ] }
*/

const css = partitions.getCSS(p)
/*
'@media (min-width: 768px) {
    .s0 { width: 151px; height: 201px; }
    .s1 { width: 151px; height: 201px; }
    .s2 { width: 151px; height: 201px; }
    .s3 { width: 267px; height: 201px; }
    .s4 { width: 360px; height: 271px; }
    .s5 { width: 360px; height: 271px; } }
@media (min-width: 992px) {
    .s0 { width: 197px; height: 263px; }
    .s1 { width: 197px; height: 263px; }
    .s2 { width: 197px; height: 263px; }
    .s3 { width: 349px; height: 263px; }
    .s4 { width: 469px; height: 353px; }
    .s5 { width: 471px; height: 353px; } }
@media (min-width: 1200px) {
    .s0 { width: 137px; height: 183px; }
    .s1 { width: 137px; height: 183px; }
    .s2 { width: 137px; height: 183px; }
    .s3 { width: 243px; height: 183px; }
    .s4 { width: 243px; height: 183px; }
    .s5 { width: 243px; height: 183px; } }'
*/

const outputList1 = photoList
    .map((photo, index) => ({
        url: photo.url,
        class: `s${index}`,
    }))
/*
[ { url: '/files/cd24b45a-48c3-4f78-a029-7725128e82ef.jpg',
    class: 's0' },
  { url: '/files/9dc13701-4975-4e45-bbfe-ea6d315b983e.jpg',
    class: 's1' },
  { url: '/files/91143cde-f06c-4b0b-86e1-9a1dc182fb01.jpg',
    class: 's2' },
  { url: '/files/6737002f-4fa6-4479-b7eb-bb90271ea359.jpg',
    class: 's3' },
  { url: '/files/28aac5b5-9a60-445e-b4d6-a51e485745c5.jpg',
    class: 's4' },
  { url: '/files/d42ee39d-1827-433f-bca0-25c9ddf4abfa.jpg',
    class: 's5' } ]
*/

await ctx.render('photos', { css, outputList })

nunjucks template:

{% extends "views/layouts/main.html" %}
{% block header %}
  <title>Photos</title>
  <style>
    img.preview {
        width: 100%;
        height: 100%;
    }
    div.preview-div {
        float: left;
        padding: 0.1em;
    }
    {{ css }}
  </style>
{% endblock %}
{% block body %}
  <div>
    {% for photo in outputList %}
      <div class="preview-div {{ photo.class }}"><img class="preview" src="{{ photo.url }}"/></div>
    {% endfor %}
  </div>
{% endblock %}

result html:

<head>
  <style>
  @media (min-width: 768px) { .s0 { width: 151px; height: 201px; } .s1 { width: 151px; height: 201px; } .s2 { width: 151px; height: 201px; } .s3 { width: 267px; height: 201px; } .s4 { width: 360px; height: 271px; } .s5 { width: 360px; height: 271px; } }\n@media (min-width: 992px) { .s0 { width: 197px; height: 263px; } .s1 { width: 197px; height: 263px; } .s2 { width: 197px; height: 263px; } .s3 { width: 349px; height: 263px; } .s4 { width: 469px; height: 353px; } .s5 { width: 471px; height: 353px; } }\n@media (min-width: 1200px) { .s0 { width: 137px; height: 183px; } .s1 { width: 137px; height: 183px; } .s2 { width: 137px; height: 183px; } .s3 { width: 243px; height: 183px; } .s4 { width: 243px; height: 183px; } .s5 { width: 243px; height: 183px; } }
  </style>
</head>

<body>
  <div class="container">
    <div class="row">
      <div class="col-xs-12">
        <div class="preview-div s0"><img class="preview" src="/files/cd24b45a-48c3-4f78-a029-7725128e82ef.jpg"></div>
        <div class="preview-div s1"><img class="preview" src="/files/9dc13701-4975-4e45-bbfe-ea6d315b983e.jpg"></div>
        <div class="preview-div s2"><img class="preview" src="/files/91143cde-f06c-4b0b-86e1-9a1dc182fb01.jpg"></div>
        <div class="preview-div s3"><img class="preview" src="/files/6737002f-4fa6-4479-b7eb-bb90271ea359.jpg"></div>
        <div class="preview-div s4"><img class="preview" src="/files/28aac5b5-9a60-445e-b4d6-a51e485745c5.jpg"></div>
        <div class="preview-div s5"><img class="preview" src="/files/d42ee39d-1827-433f-bca0-25c9ddf4abfa.jpg"></div>
      </div>
    </div>
  <div>
</body>

ES5

The package uses some newer language features. For your convenience, it's been transpiled to be compatible with older environments. You can use the following snippet.

const partitions = require('photo-partition/es5')

Testing

Module is tested with zoroaster: npm test.

About

A library to apply linear partitioning algorithm to a set of photos.

Resources

Stars

Watchers

Forks

Packages

No packages published