Skip to content

Commit

Permalink
add new template: before and after comparison. closes #19
Browse files Browse the repository at this point in the history
  • Loading branch information
shellyscheng committed Jul 4, 2023
1 parent 54dc126 commit 817bc2d
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 1 deletion.
2 changes: 1 addition & 1 deletion _base/lib/pym.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ switch (getParameterByName("mode")) {
// on the NPR homepage." checkbox when pulling the embed code.)
case "hp":
document.body.classList.add("hp");
isHomepage = true;
// isHomepage = true;
break;
// Direct links to the child page (iOS app workaround link)
case "childlink":
Expand Down
79 changes: 79 additions & 0 deletions before_after_comparision/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Before and After Comparison
========================

### About this template

This template offers an animated toggle between two images (a "before" and an "after") — often useful for comparing satellite imagery between two time periods.

Columns in the spreadsheet:

* `key` — A unique one-word descriptor for this pair of before and after images (such as the location the image). This is used as the unique id for each photo embed.
* `headline` - A headline for this pair of before and after images _(optional)_. This is most useful in cases where you are including multiple before/after toggles in the same embed.
* `image1` - The before image filename. We assume that it will live in the `synced/` folder inside the graphic.
* `image1_alt` - Alt text for `image1`
* `label_hed1` — The primary label for the first button. When user clicks the button, `image1` will be displayed. The text for the label is typically "Before."
* `label_dek1` — A secondary label for the first button — typically the date when the `image1` was taken. _(optional)_
* `image2` - The after image filename. We assume that it will live in the `synced/` folder inside the graphic.
* `image2_alt` - Alt text for `image2`
* `label_hed2` — The primary label for the second button. When user clicks the button, `image2` will be displayed. The text for the label is typically "After."
* `label_dek2` — A secondary label for the second button — typically the date when the `image2` was taken. _(optional)_
* `photo_credit` — Photo credit for `image1` and `image2`. _(optional)_

Key files:

* `synced/` — All images should go here. (Note: This does not get committed to the repo. Files are published using a separate syncing process. See further below.)
* `partials/_beforeafter.html` — Template code to display each pair of before and after images
* `index.html` — View all before/after comparisons in this project

-----

### Creating multiple pairs of before and after images

Add rows with corresponding attributes in the `data` spreadsheet with a unique `key` value. Then, depending on your desired way of presenting the images:

#### All pairs appear in the same embed

By default, `index.html` is set up to show all before/after pairs in the spreadsheet, in the order they're listed in the spreadsheet.

#### Each pair gets its own embed

If you want separate embeds for each before/after pair in the spreadsheet:

* Make a copy of `index.html` and rename it according to the `key` for that row
* Change this section of code:

```
<% for (let key of Object.keys(COPY.data)) { %>
<%= await t.include("partials/_beforeafter.html", { COPY: { ...COPY, data: [ COPY.data[key] ]}}) %>
<% } %>
```

to:

```
<%= await t.include("partials/_beforeafter.html", { COPY: { ...COPY, data: [ COPY.data['KEY_FOR_THIS_ROW'] ]}}) %>
```

-----

### Optimizing images

Create a folder locally somewhere on your machine with the original-size images. Inside that folder, create a new folder called `resized`.

Run this ImageMagick script (from our [best practices](https://github.com/nprapps/bestpractices/blob/master/assets.md)) to resize the images:

```
for f in *.jpg; do convert $f -quality 75 -resize 1600x1200\> -strip -sampling-factor 4:2:0 -define jpeg:dct-method=float -interlace Plane resized/$f; done
```

Save the `resized` images in the `synced` folder in this project. Do not keep the original high-res images here.

-----

### Synced files

For this project, images are synced to S3 rather than stored in the repo. Run this to retrieve / sync them:

```
node cli sync $PROJECT_SLUG
```
103 changes: 103 additions & 0 deletions before_after_comparision/graphic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
var pym = require("./lib/pym");
var ANALYTICS = require("./lib/analytics");
require("./lib/webfonts");
var { isMobile } = require("./lib/breakpoints");

var pymChild = null;
var isMobile = isMobile.matches;

/*
* Initialize the graphic.
*/
var onWindowLoaded = function() {
pym.then(function(child) {
pymChild = child;
child.sendHeight();
window.addEventListener("resize", render);
});

initUI();
}

/*
* Render the graphic.
*/
var render = function() {
// Update iframe
if (pymChild) {
pymChild.sendHeight();
}
}

var initUI = function() {
document.querySelectorAll('.graphic').forEach(function(wrapper) {
var toggleTimeout;
var toggleButtons = wrapper.querySelectorAll('.toggle-btn');
var splitId = toggleButtons[0].getAttribute('id').split('-');

toggleButtons.forEach(function(button) {
button.addEventListener('click', function() {
var parentToggleWrap = button.parentElement;
parentToggleWrap.classList.add('clicked');
window.clearTimeout(toggleTimeout);

splitId = button.getAttribute('id').split('-');

// select before image by its unique id
var beforeImage = wrapper.querySelector('#image-' + splitId[1] + '-1');

if (splitId[2] == '1') {
beforeImage.classList.remove('hidden');
} else {
beforeImage.classList.add('hidden');
}

if (!button.classList.contains('active')) {
let activeToggleBtn = parentToggleWrap.querySelector('.toggle-btn.active');
if (activeToggleBtn) {
activeToggleBtn.classList.remove('active');
}
button.classList.add('active');
}
});
});

var autoToggle = function() {
var stepList = [2, 1, 2, 1, 2];
toggleStep(0);

function toggleStep(step_i) {
if (step_i < stepList.length) {
var step = stepList[step_i];

if (!wrapper.querySelector('.image-toggle').classList.contains('clicked')) {
// select before image by its unique id
var beforeImage = wrapper.querySelector('#image-' + splitId[1] + '-1');

if (step == 1) {
beforeImage.classList.remove('hidden');
} else {
beforeImage.classList.add('hidden');
}

let activeToggleBtn = wrapper.querySelector('.toggle-btn.active');
if (activeToggleBtn) {
activeToggleBtn.classList.remove('active');
}

wrapper.querySelector('#toggle-' + splitId[1] + '-' + step).classList.add('active');

toggleTimeout = window.setTimeout(toggleStep, 2000, step_i + 1);
}
}
}
};

autoToggle();
});
};
/*
* Initially load the graphic
* (NB: Use window.load to ensure all images have loaded)
*/
window.onload = onWindowLoaded;
204 changes: 204 additions & 0 deletions before_after_comparision/graphic.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
@import "./lib/base";

body {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}

h1,
h2 {
.mmedia-constrained-centered();
}

.beforeafter + .beforeafter {
margin-top: 33px;
}

.graphic h4 {
.mmedia-constrained-centered();
.lato();
font-size: 18px;
margin-bottom: 11px;
color: #666;
}

.footer,
.footnotes {
.mmedia-constrained();
}

.graphic + .footer {
margin-top: -11px;
}

.top-wrapper {
.clearfix();
text-align: center;

.image-toggle,
.legend {
display: inline-block;
}
}

.image-toggle {
margin-right: 2.5%;
padding-left: 5px;
margin-bottom: 10px;
}

.toggle-btn {
box-sizing: border-box;
display: inline-block;
width: 160px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #ddd;
color: #666;
margin-left: -5px;
opacity: 0.7;
transition: all 200ms ease-in;
.lato();

@media @screen-mobile {
width: 120px;
}

.btn-hed {
text-transform: uppercase;
display: block;
font-size: 13px;
}

.btn-dek {
display: block;
font-size: 11px;
font-style: italic;
font-weight: normal;
color: #aaa;
}

&:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

&:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

&:hover {
color: #999;
opacity: 1;
}

&.active {
background-color: #fff;
border-color: #ddd;
color: #454545;
font-weight: bold;
cursor: pointer;
opacity: 1;
}

@media screen and (max-width: 500px) {
font-size: 1.2em;

img {
display: none;
}
}
}

.img-wrapper {
position: relative;
max-width: 1240px;
margin: 0 auto;
overflow: hidden;

img {
padding: 0;
margin: 0;
max-width: 100%;
display: block;

// @media screen and (max-width: 500px) {
// max-width: 130%;
// margin-left: -15%;
// }

&.image-1 {
position: absolute;
top: 0;
left: 0;
transition: opacity 500ms ease-out;
opacity: 1;

&.hidden {
opacity: 0;
}
}
}
}

.footnotes {
display: none;
}

@media screen and (max-width: 440px) {
.top-wrapper {
text-align: center;
}
}

.hp {
h1, h2, h4 {
display: none;
}

.graphic {
margin-bottom: 10px;
}

.footnotes {
display: block;
margin-bottom: 6px;
}

.footer,
.footnotes {
max-width: none;
margin-left: 0;
margin-right: 0;
}

.image-toggle {
display: flex;
padding: 0;
margin: 0 auto 2px;
justify-content: center;

@media @screen-mobile-above {
max-width: 400px;
}
}

.toggle-btn {
box-sizing: border-box;
display: block;
width: 50%;
border: 1px solid #ccc;
margin-left: 0;

@media @screen-mobile {
width: 50%;
}

&:first-child {
border-right: none;
}
}
}
Loading

0 comments on commit 817bc2d

Please sign in to comment.