Skip to content

Instantly share code, notes, and snippets.

@ochafik
Last active December 22, 2016 12:31
Show Gist options
  • Select an option

  • Save ochafik/93bc9ea68f19e654882cbab8eab22f74 to your computer and use it in GitHub Desktop.

Select an option

Save ochafik/93bc9ea68f19e654882cbab8eab22f74 to your computer and use it in GitHub Desktop.
dom abduction
<html>
<head>
<script>
class Container {
constructor(div) {
this.div = div;
this.content = null;
}
setContent(content) {
if (content.parentElement != this.div) {
if (content.parentElement != null) throw new Error('Content already has a parent');
this.div.appendChild(content);
}
this.content = content;
}
ensureSizeOf(e) {
// TODO: import more styles from content.
const p = document.createElement('div');
p.style.width = e.clientWidth + 'px';
p.style.height = e.clientHeight + 'px';
if (this.sizer != null) {
this.sizer.replaceWith(p);
} else {
this.div.appendChild(p);
}
this.sizer = p;
}
removeSizer() {
if (this.sizer == null) {
return;
}
this.div.removeChild(this.sizer);
this.sizer = null;
}
borrowContentOf(container) {
if (container.content == null) throw new Error('Container has no content');
if (this.content == container.content) throw new Error('Already owns the other container\'s content');
if (this.content != null) throw new Error('Container already has content');
if (container.content.parentElement == this.div) throw new Error('Content is already a child');
const content = container.content;
const width = content.clientWidth;
const height = content.clientHeight;
this.ensureSizeOf(content);
setTimeout(() => {
const originRect = content.getBoundingClientRect();
const destinationRect = this.sizer.getBoundingClientRect();
container.ensureSizeOf(content);
container.div.removeChild(content);
container.content = null;
this.removeSizer();
this.setContent(content);
const originScale = originRect.width / width;
const destinationScale = destinationRect.width / width;
content.style.position = 'relative';
content.className += ' animated';
const restoredScale = originScale / destinationScale;
const deltaLeft = (originRect.left - destinationRect.left)
+ (originScale - 1) * width / 2
- (destinationScale - 1) * width / 2
;
const deltaTop = (originRect.top - destinationRect.top)
+ (originScale - 1) * height / 2
- (destinationScale - 1) * height / 2
;
content.style.left = deltaLeft / destinationScale;
content.style.top = deltaTop / destinationScale;
if (originScale != destinationScale) {
content.style.transform = `scale(${restoredScale})`;
}
// if (false)
setTimeout(() => {
content.style.left = 0;
content.style.top = 0;
content.style.transform = null;
}, 100);
});
}
}
var app;
class App {
constructor() {
this.payload = document.getElementById('payload');
this.container1 = new Container(document.getElementById('container1'));
this.container1.setContent(this.payload);
this.container2 = new Container(document.getElementById('container2'));
setTimeout(() => app.abduct(), 1000);
}
abduct() {
app.container2.borrowContentOf(app.container1);
}
release() {
app.container1.borrowContentOf(app.container2);
}
}
</script>
<style>
#app {
position: relative;
height: 100%;
}
.animated {
-webkit-transition: .54s ease-in-out;
-moz-transition: .54s ease-in-out;
-o-transition: .54s ease-in-out;
transition: .54s ease-in-out;
}
#payload {
background-color: blue;
width: 100px;
height: 100px;
}
#container1 {
padding: 10px;
position: absolute;
left: 0;
background-color: #aaffaa; /* green-ish */
transform: scale(0.4);
}
#container2 {
padding: 10px;
right: 0;
bottom: 0;
position: absolute;
background-color: #ffaaaa; /* red-ish */
width: 150px;
height: 150px;
/*transform: scale(2);*/
}
</style>
</head>
<body onload="app = new App()">
<div id="app">
<button onclick="app.abduct()">Abduct</button>
<button onclick="app.release()">Release</button>
<div id="container1">
Container 1
<div id="payload">
</div>
</div>
<div id="container2">
Container 2
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment