Skip to content

Commit

Permalink
Image lightbox improvements (#5717)
Browse files Browse the repository at this point in the history
  • Loading branch information
aghassemi committed Oct 27, 2016
1 parent b82f878 commit 70d6d7c
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 17 deletions.
44 changes: 28 additions & 16 deletions extensions/amp-image-lightbox/0.1/amp-image-lightbox.js
Expand Up @@ -48,7 +48,7 @@ const SUPPORTED_ELEMENTS_ = {
};

/** @private @const {!../../../src/curve.CurveDef} */
const ENTER_CURVE_ = bezierCurve(0.4, -0.3, 0.2, 1);
const ENTER_CURVE_ = bezierCurve(0.4, 0, 0.2, 1);

/** @private @const {!../../../src/curve.CurveDef} */
const EXIT_CURVE_ = bezierCurve(0.4, 0, 0.2, 1);
Expand Down Expand Up @@ -913,27 +913,34 @@ class AmpImageLightbox extends AMP.BaseElement {

const rect = layoutRectFromDomRect(this.sourceImage_
./*OK*/getBoundingClientRect());
const imageBox = this.imageViewer_.getImageBox();
const clone = this.sourceImage_.cloneNode(true);
clone.className = '';
st.setStyles(clone, {
position: 'absolute',
top: st.px(rect.top),
left: st.px(rect.left),
width: st.px(rect.width),
height: st.px(rect.height),
transformOrigin: 'top left',
willChange: 'transform',
});
transLayer.appendChild(clone);

this.sourceImage_.classList.add('-amp-ghost');

// Move the image to the location given by the lightbox.
const imageBox = this.imageViewer_.getImageBox();
// Move and resize the image to the location given by the lightbox.
const dx = imageBox.left - rect.left;
const dy = imageBox.top - rect.top;
const scaleX = rect.width != 0 ? imageBox.width / rect.width : 1;
// Duration will be somewhere between 0.2 and 0.8 depending on how far
// the image needs to move.
const motionTime = Math.max(0.2, Math.min(0.8, Math.abs(dy) / 250 * 0.8));
anim.add(0, tr.setStyles(clone, {
transform: tr.translate(tr.numeric(0, dx), tr.numeric(0, dy)),
transform: tr.concat([
tr.translate(tr.numeric(0, dx), tr.numeric(0, dy)),
tr.scale(tr.numeric(1, scaleX)),
]),
}), motionTime, ENTER_CURVE_);

// Fade in the container. This will mostly affect the caption.
Expand Down Expand Up @@ -983,16 +990,16 @@ class AmpImageLightbox extends AMP.BaseElement {

const rect = layoutRectFromDomRect(this.sourceImage_
./*OK*/getBoundingClientRect());
const newLeft = imageBox.left + (imageBox.width - rect.width) / 2;
const newTop = imageBox.top + (imageBox.height - rect.height) / 2;
const clone = image.cloneNode(true);
st.setStyles(clone, {
position: 'absolute',
top: st.px(newTop),
left: st.px(newLeft),
width: st.px(rect.width),
height: st.px(rect.height),
top: st.px(imageBox.top),
left: st.px(imageBox.left),
width: st.px(imageBox.width),
height: st.px(imageBox.height),
transform: '',
transformOrigin: 'top left',
willChange: 'transform',
});
transLayer.appendChild(clone);

Expand All @@ -1001,19 +1008,24 @@ class AmpImageLightbox extends AMP.BaseElement {
opacity: tr.numeric(1, 0),
}), 0.1, EXIT_CURVE_);

// Move the image back to where it is in the article.
const dx = rect.left - newLeft;
const dy = rect.top - newTop;
// Move and resize the image back to where it is in the article.
const dx = rect.left - imageBox.left;
const dy = rect.top - imageBox.top;
const scaleX = imageBox.width != 0 ? rect.width / imageBox.width : 1;
/** @const {!TransitionDef<void>} */
const move = tr.setStyles(clone, {
transform: tr.translate(tr.numeric(0, dx), tr.numeric(0, dy)),
const moveAndScale = tr.setStyles(clone, {
transform: tr.concat([
tr.translate(tr.numeric(0, dx), tr.numeric(0, dy)),
tr.scale(tr.numeric(1, scaleX)),
]),
});

// Duration will be somewhere between 0.2 and 0.8 depending on how far
// the image needs to move. Start the motion later too, but no later
// than 0.2.
const motionTime = Math.max(0.2, Math.min(0.8, Math.abs(dy) / 250 * 0.8));
anim.add(Math.min(0.8 - motionTime, 0.2), (time, complete) => {
move(time);
moveAndScale(time);
if (complete) {
this.sourceImage_.classList.remove('-amp-ghost');
}
Expand Down
22 changes: 22 additions & 0 deletions src/transition.js
Expand Up @@ -38,6 +38,28 @@ export function all(transitions) {
}


/**
* Returns a transition that combines the string result of other string-based
* transitions such as transform and scale using the given opt_delimiter.
* @param {!Array<!TransitionDef<string>>} transitions
* @param {string=} opt_delimiter Defaults to a single whitespace.
* @return {!TransitionDef<string>}
*/
export function concat(transitions, opt_delimiter = ' ') {
return (time, complete) => {
const results = [];
for (let i = 0; i < transitions.length; i++) {
const tr = transitions[i];
const result = tr(time, complete);
if (typeof result == 'string') {
results.push(result);
}
}
return results.join(opt_delimiter);
};
}


/**
* Returns the specified transition with the time curved via specified curve
* function.
Expand Down
49 changes: 49 additions & 0 deletions test/functional/test-transition.js
Expand Up @@ -56,6 +56,55 @@ describe('Transition', () => {
expect(func2.calledWithExactly(1, true)).to.equal(true);
});

describe('concat', () => {
it('should concat two string transitions', () => {
const t1 = tr.translateX(tr.numeric(0, 10));
const t2 = tr.scale(tr.numeric(0, 10));
const concat = tr.concat([t1, t2]);

expect(concat(0, false)).to.equal('translateX(0px) scale(0)');
expect(concat(0.5, false)).to.equal('translateX(5px) scale(5)');
expect(concat(1, true)).to.equal('translateX(10px) scale(10)');
});

it('should handle single transitions', () => {
const t1 = tr.translateX(tr.numeric(0, 10));
const concat = tr.concat([t1]);

expect(concat(0, false)).to.equal('translateX(0px)');
expect(concat(0.5, false)).to.equal('translateX(5px)');
expect(concat(1, true)).to.equal('translateX(10px)');
});

it('should handle empty input', () => {
const concat = tr.concat([]);

expect(concat(0, false)).to.equal('');
expect(concat(0.5, false)).to.equal('');
expect(concat(1, true)).to.equal('');
});

it('should ignore non-string transitions', () => {
const t1 = tr.translateX(tr.numeric(0, 10));
const t2 = tr.spring(2, 10, 12, 0.8);
const concat = tr.concat([t1, t2]);

expect(concat(0, false)).to.equal('translateX(0px)');
expect(concat(0.5, false)).to.equal('translateX(5px)');
expect(concat(1, true)).to.equal('translateX(10px)');
});

it('should support other delimeters', () => {
const t1 = tr.px(tr.numeric(0, 10));
const t2 = tr.px(tr.numeric(0, 20));
const concat = tr.concat([t1, t2], ', ');

expect(concat(0, false)).to.equal('0px, 0px');
expect(concat(0.5, false)).to.equal('5px, 10px');
expect(concat(1, true)).to.equal('10px, 20px');
});
});

it('withCurve', () => {
const func1 = (time, complete) => `${time * 2};${complete}`;
const curve = unusedTime => 0.2;
Expand Down
24 changes: 23 additions & 1 deletion test/manual/amp-image-lightbox.amp.html
Expand Up @@ -48,6 +48,15 @@
color: #aaa;
height: 60px;
}

.row {
display: flex;
flex-direction: row;
}

.row > div {
flex: 1;
}
</style>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<script async src="../../dist/amp.js"></script>
Expand Down Expand Up @@ -87,12 +96,25 @@ <h1>Image Lightbox</h1>
Lorem ipsum dolor sit amet, has nisl nihil convenire et, vim at aeque inermis reprehendunt. Propriae tincidunt id nec, elit nusquam te mea, ius noster platonem in. Mea an idque minim, sit sale deleniti apeirian et. Omnium legendos tractatos cu mea. Vix in stet dolorem accusamus. Iisque rationibus consetetur in cum, quo unum nulla legere ut. Simul numquam saperet no sit.
</p>

<amp-img id="img1"
<div class="row">
<div>
<amp-img id="img1"
srcset="
https://lh4.googleusercontent.com/kDqWeHQ0Zt-UFeHAlc2ydE9AwK7W-kbMXBqyuNvPNy0mNSGAP7FOVB3_1iAOdbQSsbZByErbehvvSKtnTb1L5GoYreijfKwgYwpP1eLCHyl9Am7BSpwRuBABOAO12PtyPBTirdAadnxOmfq9dH_rsLSTaYGmNz1D5QIwXeWd8UeDNUQ3f-cMgvkq4ePqmKoe9t5ySqqLMZs-v3wTi2pd4jV_CurzcMB76k_b4lyD5w77NUowkSaQfscYVQpkDjo6OgG2nBiKJ2TITWVDu2rvt6NuEoOD9xaHgXuv81OnOjXCokxZd5K6TZiAH-Qm1jTKGMANklXiXt6hbwrN3QPA1mq2FardxGNLj1_oqOpXaqfUuj8LvejFRY6zJMGq0r6S_TEtPvbyulIg4PkKPIaVzi5nVdGrAWWoesWh-ORqmxZ4FIhdbd_Igsdh5AcMETBcZz3l5-IX0hmnyUeT5IOPSGw-p3Esgp_abwWB9-kElEiiHPD4QuQ_swsRu0NSFwfRi_QefnJQJ5UATng6iVP3K0g7uumHcwLtFId0vCeHp4A=w1024-h768-no"
width=1024 height=768 layout="responsive"
aria-describedby="img1-desc" role="button" tabindex="0"
on="tap:image-lightbox1"></amp-img>
</div>
<div>
<amp-img id="img2"
srcset="
https://lh4.googleusercontent.com/-okOlNNHeoOc/VbYyrlFYFII/AAAAAAABYdA/La-3j3c-QQI/w2004-h1114-no/PANO_20150726_171347%257E2.jpg 2004w,
https://lh4.googleusercontent.com/-okOlNNHeoOc/VbYyrlFYFII/AAAAAAABYdA/La-3j3c-QQI/w1002-h557-no/PANO_20150726_171347%257E2.jpg 1002w"
width=1024 height=768 layout="responsive"
aria-describedby="img1-desc" role="button" tabindex="0"
on="tap:image-lightbox1"></amp-img>
</div>
</div>

<div id="img1-desc">
Iisque rationibus consetetur in cum, quo unum nulla legere ut. Simul numquam saperet no sit.
Expand Down

0 comments on commit 70d6d7c

Please sign in to comment.