Google's Thanos Effect
by mmis1000
HTML
<script src="https://unpkg.com/[email protected]/dist/html2canvas.min.js"></script>
<div id="banner-message">
<p>Hello World</p>
<button type="button" class="js-alt">Change color</button>
</div>
<div id="effect"></div>
<div class="action">
<button type="button" class="js-play">
開始
</button>
<button type="button" class="js-reset">
重置
</button>
<hr style="margin: 20px 0;" />
<div class="line">
<label for="layer-border">
<input type="checkbox" id="layer-border" class="js-border" /> 顯示分層邊框
</label>
</div>
<div class="line">
<label for="layer-count">
分層數
<select id="layer-count" class="js-layer-count">
<option>8</option>
<option>16</option>
<option>32</option>
<option>64</option>
<option>128</option>
<option>256</option>
<option>512</option>
<option>1024</option>
</select>
</label>
</div>
</div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica, sans-serif;
overflow-x: hidden;
}
#banner-message {
background: #fff;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
.action {
margin-top: 1rem;
text-align: center;
color: #fff;
}
.action .line {
margin: 15px 0;
}
#effect {
position: absolute;
text-align: center;
pointer-events: none;
}
#effect canvas {
position: absolute;
left: 0;
top: 0;
transition: transform 1.5s ease-out, opacity 1.5s ease-out;
}
#effect.border canvas {
box-shadow: 0 0 0 1px red;
}
JavaScript
$(() => {
const LAYER_COUNT = 32;
const TRANSITION_DURATION = 1.5;
const TRANSITION_DELAY = 1.35;
let currentLayerCount = LAYER_COUNT;
const $target = $('#banner-message');
const target = $target[0];
const $effect = $('#effect');
const hideTarget = () => {
$target.css({
'transition': `opacity ${TRANSITION_DURATION} ease`,
opacity: 0
});
delay(1e3 * TRANSITION_DURATION).then(() => {
$target.css('visibility', 'hidden');
});
};
const showTarget = () => {
$target.css({
opacity: 1,
visibility: 'visible',
'transition': `opacity 1s ease`
});
};
// bind events
$('.js-play').on('click', function() {
play(currentLayerCount);
});
$('.js-reset').on('click', function() {
var $canvas = $("canvas")
$canvas.css({
transform: `rotate(0deg) translate(0px, 0px) rotate(0deg)`,
opacity: 1
});
setTimeout(function() {
showTarget();
setTimeout(function() {
$canvas.css({
opacity: 0,
'transition': `opacity 1s ease`
})
setTimeout(function() {
$canvas.remove()
}, 1000)
}, 1000)
}, 3000)
});
$('.js-alt').on('click', function($evt) {
$target.toggleClass('alt', $evt.target.checked);
});
$('.js-border').on('change', function($evt) {
$effect.toggleClass('border', $evt.target.checked);
});
$('.js-layer-count').on('change', function($evt) {
currentLayerCount = Number($evt.target.value);
});
$('.js-layer-count').val(currentLayerCount);
function play(layerCount) {
showTarget();
const bRect = target.getBoundingClientRect();
$effect.css({
left: bRect.left,
top: bRect.top,
width: bRect.width,
height: bRect.height
});
html2canvas(target, {
backgroundColor: null,
})
.then(canvas => {
const context = canvas.getContext('2d');
const {
width,
height
} = canvas;
...