Skip to content

Instantly share code, notes, and snippets.

@ForsakenHarmony
Created January 10, 2018 19:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ForsakenHarmony/f0827bad62cf737050ce85cc6ae24490 to your computer and use it in GitHub Desktop.
Save ForsakenHarmony/f0827bad62cf737050ce85cc6ae24490 to your computer and use it in GitHub Desktop.
Image viewer popup in preact
.background {
will-change: opacity;
transition: opacity 250ms;
visibility: hidden;
opacity: 0;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 100;
}
.background.active {
visibility: visible;
opacity: 1;
background: rgba(1, 1, 1, 0.9);
}
.img {
will-change: transform, top, left;
transition: all 250ms;
position: relative;
top: 50%;
left: 50%;
padding: 40px;
transform: translate(-50%, -50%) scale(.01, .01);
z-index: 101;
}
.img.active {
transform: translate(-50%, -50%);
max-height: 100vh;
}
import { Component } from 'preact';
import Viewer from './imageviewer'
export default class Image extends Component {
render({ url, caption }) {
return (
<div class="column is-one-third">
<div class="card">
<div class="card-image">
<Viewer url={url}/>
</div>
<div class="content">{caption}</div>
</div>
</div>
);
}
}
import { Component } from 'preact';
import cls from 'obj-str';
import styles from './image.css'
export default class Viewer extends Component {
state = {
active: false,
imageStyle: {},
};
image = null;
toggleOpen = () => {
if (this.state.active) {
this.setState({ active: false })
} else {
this.setState({ active: true })
}
};
setupStyle = () => {
const imageStyle = {};
const docRect = document.body.getBoundingClientRect();
const docWidth = docRect.width;
const docHeight = docRect.height;
const imageRect = this.image.getBoundingClientRect();
const width = imageRect.width;
const height = imageRect.height;
const x = imageRect.left;
const y = imageRect.top;
const origWidth = this.image.naturalWidth;
const origHeight = this.image.naturalHeight;
const docRatio = docWidth / docHeight;
const imgRatio = (origWidth + 80) / (origHeight + 80);
const scale = docRatio > imgRatio
? height / docHeight
: width / docWidth;
imageStyle.transform = `translate(-50%, -50%) scale(${scale})`;
imageStyle.top = y + height / 2;
imageStyle.left = x + width / 2;
this.setState({imageStyle})
};
imageRef = (e) => {
this.image = e;
};
render({ url }, { active, imageStyle }) {
return (
<div onClick={this.toggleOpen} style={{cursor: 'pointer'}}>
<img
src={url}
ref={this.imageRef}
onMouseEnter={this.setupStyle}
/>
<div className={cls({ [styles.background]: true, [styles.active]: active })}>
<img
src={url}
className={cls({ [styles.img]: true, [styles.active]: active })}
style={!active && imageStyle}
/>
</div>
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment