How to prevent random particles to appear where unnecessary scrollbars are triggered?
The background element can't be fixed-sized.
I think the solution could be to only show particles on the visible part of the viewport and to leave a margin of a few pixels, but I don't know how to do it.
// https://github.com/maxspeicher/jquery-sparkle
(function($, window, document) {
const defaults = {
fill: "#fff",
stroke: "#000",
size: 20,
delay: 0,
duration: 1500,
pause: 1000
};
const optionsKeys = ["fill", "stroke", "size", "delay", "duration", "pause"];
const optionsStrToObj = function(optionsStr) {
const optionsArr = !!optionsStr ? optionsStr.split(" ") : [];
var optionsObj = {};
for (var i=0; i<optionsArr.length; ++i) {
optionsObj[optionsKeys[i]] = optionsArr[i];
}
return optionsObj;
};
$.fn.sparkle = function(options) {
$.destroySparkle = $.destroySparkle || {};
const $this = this;
const id = this.data("sparkle-id") || (new Date()).getTime() + Math.random();
if (options === "destroy" && this.find("svg").length > 0) {
$.destroySparkle[id] = true;
this.data("sparkle-id", null);
}
var settings;
if (options instanceof Array) {
for (var i=0; i<options.length; ++i) {
$this.sparkle(optionsStrToObj(options[i]));
}
return;
} else if (options instanceof Object) {
settings = $.extend({}, defaults, options);
} else {
settings = defaults;
}
const cssAnimationAttr = "my-sparkle " + settings.duration + "ms infinite linear";
const $star = $('<svg class="my-sparkle" version="1.1" viewBox="0.0 0.0 50.0 50.0" fill="none" stroke="none" stroke-linecap="square" stroke-miterlimit="10" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="p.0"><path d="m0 0l50.0 0l0 50.0l-50.0 0l0 -50.0z" clip-rule="nonzero"></path></clipPath><g clip-path="url(#p.0)"><path fill="' + settings.stroke + '" fill-opacity="0.0" d="m0 0l50.0 0l0 50.0l-50.0 0z" fill-rule="nonzero"></path><path fill="' + settings.fill + '" d="m0.62204725 25.0l20.068499 -4.323374l4.309454 -20.13332l4.309454 20.13332l20.068499 4.323374l-20.068499 4.323374l-4.309454 20.133318l-4.309454 -20.133318z" fill-rule="nonzero"></path><path stroke="' + settings.stroke + '" stroke-width="1.0" stroke-linejoin="round" stroke-linecap="butt" d="m0.62204725 25.0l20.068499 -4.323374l4.309454 -20.13332l4.309454 20.13332l20.068499 4.323374l-20.068499 4.323374l-4.309454 20.133318l-4.309454 -20.133318z" fill-rule="nonzero"></path></g></svg>').css({
position: "absolute",
width: settings.size,
height: settings.size,
zIndex: 9999
});
const w = this.width();
const h = this.height();
const getCoordinates = function() {
return {
left: Math.random() * w,
top: Math.random() * h
};
};
const placeStar = function(init) {
const coords = getCoordinates();
if (init) {
$this.append($star);
}
$star.css({
"-moz-animation": cssAnimationAttr,
"-webkit-animation": cssAnimationAttr,
animation: cssAnimationAttr,
display: "block",
left: coords.left,
top: coords.top
});
window.setTimeout(function() {
$star.css({
"-moz-animation": null,
"-webkit-animation": null,
animation: null,
display: "none"
});
if (!$.destroySparkle[id]) {
window.setTimeout(function() {
placeStar(false);
}, settings.pause);
} else {
$star.remove();
}
}, settings.duration);
};
if (this.css("position") === "static") {
this.css("position", "relative");
}
if (!$.destroySparkle[id] && options !== "destroy") {
window.setTimeout(function() {
placeStar(true);
}, settings.delay);
this.data("sparkle-id", id);
}
return this;
};
$("#bg").sparkle({
size: 25,
}).sparkle({
delay: 1000,
pause: 750,
size: 25
}).sparkle({
delay: 1500,
pause: 750,
size: 25
}).sparkle({
delay: 2000,
pause: 750,
size: 25
}).sparkle({
delay: 2500,
pause: 750,
size: 25
}).sparkle({
delay: 3000,
pause: 750,
size: 25
});
})(Zepto, window, document);
#-moz-keyframes my-sparkle {
0% {
opacity: 0;
-moz-transform: rotate(0deg) scale(0);
}
50% {
opacity: 1;
-moz-transform: rotate(360deg) scale(1);
}
100% {
opacity: 0;
-moz-transform: rotate(720deg) scale(0);
}
}
#-webkit-keyframes my-sparkle {
0% {
opacity: 0;
-webkit-transform: rotate(0deg) scale(0);
}
50% {
opacity: 1;
-webkit-transform: rotate(360deg) scale(1);
}
100% {
opacity: 0;
-webkit-transform: rotate(720deg) scale(0);
}
}
#keyframes my-sparkle {
0% {
opacity: 0;
transform: rotate(0deg) scale(0);
}
50% {
opacity: 1;
transform: rotate(360deg) scale(1);
}
100% {
opacity: 0;
transform: rotate(720deg) scale(0);
}
}
body {
background-color: #1d1f20;
margin: 0;
padding: 20px;
}
#bg {
color: #666;
display: inline-block;
font-family: Verdana;
font-size: 200%;
font-weight: bold;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
<html id="bg" style="width: 100%;
height: 100%;">
<head>
<meta charset="UTF-8">
<title>Sparkles</title>
</head>
<body>
<div>Sparkle, sparkle!</div>
</body>
</html>
https://codepen.io/tigre/pen/xRbZPZ
You are using it wrong. Dont directly use sparcle plugin on html tag instead add element to starting of body tag and style it
<body>
<div id="bg"></div>
<div>Sparkle, sparkle!</div>
</body>
where bg is your sparkle element you are pointing to.
and Style bg element as following
#bg {
position:fixed;
display:block;
width:100%;
height:100%;
top:0;
left:0;
background: #1d1f20;
overflow:hidden;
z-index:-1;
}
Here is updated Codepen link : https://codepen.io/anon/pen/LbELWa
Related
I use an open-source plugin in github, here is the link:
https://github.com/yxfanxiao/jQuery-plugin-progressbar
Please see the codes below:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Progress Bar</title>
<link rel="stylesheet" href="jQuery-plugin-progressbar.css">
<script src="jquery-1.11.3.js"></script>
<script src="jQuery-plugin-progressbar.js"></script>
</head>
<body>
<div class="progress-bar position"></div>
<div class="progress-bar position" data-percent="60" data-duration="1000" data-color="#ccc,yellow"></div>
<div class="progress-bar position" data-percent="20" data-color="#a456b1,#12b321"></div>
<input type="submit" value="加载">
<script>
$(".progress-bar").loading();
$('input').on('click', function () {
$(".progress-bar").loading();
});
</script>
</body>
</html>
JS:
;
(function ($) {
$.fn.loading = function () {
var DEFAULTS = {
backgroundColor: '#b3cef6',
progressColor: '#4b86db',
percent: 75,
duration: 2000
};
$(this).each(function () {
var $target = $(this);
var opts = {
backgroundColor: $target.data('color') ? $target.data('color').split(',')[0] : DEFAULTS.backgroundColor,
progressColor: $target.data('color') ? $target.data('color').split(',')[1] : DEFAULTS.progressColor,
percent: $target.data('percent') ? $target.data('percent') : DEFAULTS.percent,
duration: $target.data('duration') ? $target.data('duration') : DEFAULTS.duration
};
// console.log(opts);
$target.append('<div class="background"></div><div class="rotate"></div><div class="left"></div><div class="right"></div><div class=""><span>' + opts.percent + '%</span></div>');
$target.find('.background').css('background-color', opts.backgroundColor);
$target.find('.left').css('background-color', opts.backgroundColor);
$target.find('.rotate').css('background-color', opts.progressColor);
$target.find('.right').css('background-color', opts.progressColor);
var $rotate = $target.find('.rotate');
setTimeout(function () {
$rotate.css({
'transition': 'transform ' + opts.duration + 'ms linear',
'transform': 'rotate(' + opts.percent * 3.6 + 'deg)'
});
},1);
if (opts.percent > 50) {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.right').css({
animation: animationRight,
opacity: 1
});
$target.find('.left').css({
animation: animationLeft,
opacity: 0
});
}
});
}
})(jQuery);
CSS:
.position {
float: left;
margin: 100px 50px;
}
.progress-bar {
position: relative;
height: 100px;
width: 100px;
}
.progress-bar div {
position: absolute;
height: 100px;
width: 100px;
border-radius: 50%;
}
.progress-bar div span {
position: absolute;
font-family: Arial;
font-size: 25px;
line-height: 75px;
height: 75px;
width: 75px;
left: 12.5px;
top: 12.5px;
text-align: center;
border-radius: 50%;
background-color: white;
}
.progress-bar .background {
background-color: #b3cef6;
}
.progress-bar .rotate {
clip: rect(0 50px 100px 0);
background-color: #4b86db;
}
.progress-bar .left {
clip: rect(0 50px 100px 0);
opacity: 1;
background-color: #b3cef6;
}
.progress-bar .right {
clip: rect(0 50px 100px 0);
transform: rotate(180deg);
opacity: 0;
background-color: #4b86db;
}
#keyframes toggle {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
Note that you can download a zip-file from the link provided including those codes. As to be seen, originally the pie charts are rotating clockwise. All I need is to make them rotate counterclockwise. That was looking easy but I could not manage to do it for hours unfortunately. Any help or advise would be so appreciated! Thanks!!
Edit: Please note that the starting point (origin) of the animation should not be changed, should start from the top (north).
You should start by multiplying your rotate value by its minus value; -3.6 instead of 3.6. You'd also have to update the CSS accordingly as otherwise it will start animating from bottom contrary to original version where it starts from top.
You can trick it via swapping left and right components, but that will affect the progress values less than 50%, thus you should add an else statement to handle that as well.
Hence final JS file becomes like below;
JS:
;
(function ($) {
$.fn.loading = function () {
var DEFAULTS = {
backgroundColor: '#f00',
progressColor: '#adadad',
percent: 75,
duration: 2000
};
$(this).each(function () {
var $target = $(this);
var opts = {
backgroundColor: $target.data('color') ? $target.data('color').split(',')[0] : DEFAULTS.backgroundColor,
progressColor: $target.data('color') ? $target.data('color').split(',')[1] : DEFAULTS.progressColor,
percent: $target.data('percent') ? $target.data('percent') : DEFAULTS.percent,
duration: $target.data('duration') ? $target.data('duration') : DEFAULTS.duration
};
$target.append('<div class="background"></div><div class="rotate"></div>'+
'<div class="left"></div>'+
'<div class="right"></div><div class=""><span>' +
+ opts.percent + '%</span></div>');
$target.find('.background').css('background-color', opts.backgroundColor);
$target.find('.left').css('background-color', opts.backgroundColor);
$target.find('.rotate').css('background-color', opts.progressColor);
$target.find('.right').css('background-color', opts.progressColor);
var $rotate = $target.find('.rotate');
setTimeout(function () {
$rotate.css({
'transition': 'transform ' + opts.duration + 'ms linear',
'transform': 'rotateZ(' + -opts.percent * 3.6 + 'deg)'
});
},1);
if (opts.percent > 50) {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.left').css({
animation: animationRight,
opacity: 1
});
$target.find('.right').css({
animation: animationLeft,
opacity: 0
});
}
else {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.left').css({
animation: animationRight,
opacity: 0
});
$target.find('.right').css({
animation: animationLeft,
opacity: 1
});
}
});
}
})(jQuery);
i am using a popup that perfectly suits my needs! what i want to do is add another instance of the same popup but its not working,basically i have two different popup i want to show depending on the scenario like one for register and one for login. the first instance named somedialog works fine but the instance somedialog2 doesn't work here's my code
<a data-dialog="somedialog" class="trigger icon icon-register">Register</a>
<a data-dialog="somedialog2" class="trigger icon icon-login">Login</a>
<div id="somedialog" class="dialog dialog--close">
<div class="dialog__overlay"></div>
<div class="dialog__content">
<div class="morph-shape">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 560 280" preserveAspectRatio="none">
<rect x="3" y="3" fill="none" width="556" height="276"></rect>
</svg>
</div>
<div class="dialog-inner">
<h2><strong>Wait!</strong>, Are you a teacher or a student?</h2>
<div>
<button style="display: none" class="action" data-dialog-close="a">Close</button>
<button class="action" onclick="window.location.href='<?=base_url()?>Home/student_register'">I'm A Student</button>
<button class="action" onclick="window.location.href='<?=base_url()?>Home/teacher_register'">I'm A Teacher</button>
</div>
</div>
</div>
</div>
<div id="somedialog2" class="dialog dialog--close">
<h1>here</h1>
<div class="dialog__overlay"></div>
<div class="dialog__content">
<div class="morph-shape">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 560 280" preserveAspectRatio="none">
<rect x="3" y="3" fill="none" width="556" height="276"></rect>
</svg>
</div>
<div class="dialog-inner">
<h2><strong>Wait!</strong>, Are you a teacher or a student?</h2>
<div>
<button style="display: none" class="action" data-dialog-close="a">Close</button>
<button class="action" onclick="window.location.href='<?=base_url()?>Student'">I'm A Student</button>
<button class="action" onclick="window.location.href='<?=base_url()?>Teacher'">I'm A Teacher</button>
</div>
</div>
</div>
</div>
js
( function( window ) {
'use strict';
var support = { animations : Modernizr.cssanimations },
animEndEventNames = { 'WebkitAnimation' : 'webkitAnimationEnd', 'OAnimation' : 'oAnimationEnd', 'msAnimation' : 'MSAnimationEnd', 'animation' : 'animationend' },
animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ],
onEndAnimation = function( el, callback ) {
var onEndCallbackFn = function( ev ) {
if( support.animations ) {
if( ev.target != this ) return;
this.removeEventListener( animEndEventName, onEndCallbackFn );
}
if( callback && typeof callback === 'function' ) { callback.call(); }
};
if( support.animations ) {
el.addEventListener( animEndEventName, onEndCallbackFn );
}
else {
onEndCallbackFn();
}
};
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function DialogFx( el, options ) {
this.el = el;
this.options = extend( {}, this.options );
extend( this.options, options );
this.ctrlClose = this.el.querySelector( '[data-dialog-close]' );
this.isOpen = false;
this._initEvents();
}
DialogFx.prototype.options = {
// callbacks
onOpenDialog : function() { return false; },
onCloseDialog : function() { return false; }
}
DialogFx.prototype._initEvents = function() {
var self = this;
// close action
this.ctrlClose.addEventListener( 'click', this.toggle.bind(this) );
// esc key closes dialog
document.addEventListener( 'keydown', function( ev ) {
var keyCode = ev.keyCode || ev.which;
if( keyCode === 27 && self.isOpen ) {
self.toggle();
}
} );
this.el.querySelector( '.dialog__overlay' ).addEventListener( 'click', this.toggle.bind(this) );
}
DialogFx.prototype.toggle = function() {
var self = this;
if( this.isOpen ) {
classie.remove( this.el, 'dialog--open' );
classie.add( self.el, 'dialog--close' );
onEndAnimation( this.el.querySelector( '.dialog__content' ), function() {
classie.remove( self.el, 'dialog--close' );
} );
// callback on close
this.options.onCloseDialog( this );
}
else {
classie.add( this.el, 'dialog--open' );
// callback on open
this.options.onOpenDialog( this );
}
this.isOpen = !this.isOpen;
};
// add to global namespace
window.DialogFx = DialogFx;
})( window );
(function() {
var dlgtrigger = document.querySelector( '[data-dialog]' );
console.log(dlgtrigger);
var dlgtrigger = document.querySelector( '[data-dialog]' ),
somedialog = document.getElementById( dlgtrigger.getAttribute( 'data-dialog' ) ),
dlg = new DialogFx( somedialog );
dlgtrigger.addEventListener( 'click', dlg.toggle.bind(dlg) );
})();
(function() {
var dlgtrigger = document.querySelector( '[data-dialog]' );
console.log(dlgtrigger);
var dlgtrigger = '<a class="trigger icon icon-register" data-dialog="somedialog">',
somedialog = "somedialog2",
dlg = new DialogFx( somedialog );
dlgtrigger.addEventListener( 'click', dlg.toggle.bind(dlg) );
})();
Codepen
This should do it,, the problem that you had was that your code only targeted one element id,, I only expanded it to account for all elements that have [data-dialog] property..
/**
* dialog box v0.1
* Ashwin Saxena
*/
;
(function(window) {
'use strict';
var support = {
animations: Modernizr.cssanimations
},
animEndEventNames = {
'WebkitAnimation': 'webkitAnimationEnd',
'OAnimation': 'oAnimationEnd',
'msAnimation': 'MSAnimationEnd',
'animation': 'animationend'
},
animEndEventName = animEndEventNames[Modernizr.prefixed('animation')],
onEndAnimation = function(el, callback) {
var onEndCallbackFn = function(ev) {
if (support.animations) {
if (ev.target != this) return;
this.removeEventListener(animEndEventName, onEndCallbackFn);
}
if (callback && typeof callback === 'function') {
callback.call();
}
};
if (support.animations) {
el.addEventListener(animEndEventName, onEndCallbackFn);
} else {
onEndCallbackFn();
}
};
function extend(a, b) {
for (var key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
return a;
}
function DialogFx(el, options) {
this.el = el;
this.options = extend({}, this.options);
extend(this.options, options);
this.ctrlClose = this.el.querySelector('[data-dialog-close]');
this.isOpen = false;
this._initEvents();
}
DialogFx.prototype.options = {
// callbacks
onOpenDialog: function() {
return false;
},
onCloseDialog: function() {
return false;
}
}
DialogFx.prototype._initEvents = function() {
var self = this;
// close action
this.ctrlClose.addEventListener('click', this.toggle.bind(this));
// esc key closes dialog
document.addEventListener('keydown', function(ev) {
var keyCode = ev.keyCode || ev.which;
if (keyCode === 27 && self.isOpen) {
self.toggle();
}
});
this.el.querySelector('.dialog__overlay').addEventListener('click', this.toggle.bind(this));
}
DialogFx.prototype.toggle = function() {
var self = this;
if (this.isOpen) {
classie.remove(this.el, 'dialog--open');
classie.add(self.el, 'dialog--close');
onEndAnimation(this.el.querySelector('.dialog__content'), function() {
classie.remove(self.el, 'dialog--close');
});
// callback on close
this.options.onCloseDialog(this);
} else {
classie.add(this.el, 'dialog--open');
// callback on open
this.options.onOpenDialog(this);
}
this.isOpen = !this.isOpen;
};
// add to global namespace
window.DialogFx = DialogFx;
})(window);
/* call */
(function() {
var dlgs = document.querySelectorAll('[data-dialog]');
for( var i = 0; i < dlgs.length; i++){
var dlgID = document.getElementById(dlgs[i].getAttribute('data-dialog'));
var dlg = new DialogFx( dlgID );
dlgs[i].addEventListener('click', dlg.toggle.bind(dlg));
}
})();
button {
padding: 1em 2em;
outline: none;
font-weight: 600;
border: none;
color: #fff;
background: #c94e50;
}
.dialog,
.dialog__overlay {
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.dialog {
position: fixed;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
pointer-events: none;
}
.dialog__overlay {
position: absolute;
z-index: 1;
background: rgba(55, 58, 71, 0.9);
opacity: 0;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
-webkit-backface-visibility: hidden;
}
.dialog--open .dialog__overlay {
opacity: 1;
pointer-events: auto;
}
.dialog__content {
width: 50%;
max-width: 560px;
min-width: 290px;
background: #fff;
padding: 4em;
text-align: center;
position: relative;
z-index: 5;
opacity: 0;
}
.dialog--open .dialog__content {
pointer-events: auto;
}
/* Content */
.dialog h2 {
margin: 0;
font-weight: 400;
font-size: 2em;
padding: 0 0 2em;
margin: 0;
}
.dialog--open .dialog__overlay {
-webkit-transition-duration: 0.8s;
transition-duration: 0.8s;
}
.dialog--close .dialog__overlay {
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
}
.dialog__content {
padding: 0;
background: transparent;
}
.dialog.dialog--open .dialog__content {
opacity: 1;
}
.morph-shape {
position: absolute;
width: calc(100% + 4px);
height: calc(100% + 4px);
top: -2px;
left: -2px;
z-index: -1;
}
.morph-shape svg rect {
stroke: #fff;
stroke-width: 2px;
stroke-dasharray: 1680;
}
.dialog--open .morph-shape svg rect {
-webkit-animation: anim-dash 0.6s forwards;
animation: anim-dash 0.6s forwards;
}
.dialog-inner {
opacity: 0;
background: #fff;
}
.dialog--open .dialog-inner {
padding: 4em;
opacity: 1;
-webkit-transition: opacity 0.85s 0.35s;
transition: opacity 0.85s 0.35s;
}
.dialog.dialog--open h2 {
-webkit-animation: anim-elem-1 0.7s ease-out both;
animation: anim-elem-1 0.7s ease-out both;
}
.dialog.dialog--open button {
-webkit-animation: anim-elem-2 0.7s ease-out both;
animation: anim-elem-2 0.7s ease-out both;
}
#keyframes anim-dash {
0% {
stroke-dashoffset: 1680;
}
100% {
stroke-dashoffset: 0;
}
}
#-webkit-keyframes anim-dash {
0% {
stroke-dashoffset: 1680;
}
100% {
stroke-dashoffset: 0;
}
}
/* Inner elements animations */
#-webkit-keyframes anim-elem-1 {
0% {
opacity: 0;
-webkit-transform: translate3d(-150px, 0, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
}
}
#keyframes anim-elem-1 {
0% {
opacity: 0;
-webkit-transform: translate3d(-150px, 0, 0);
transform: translate3d(-150px, 0, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
#-webkit-keyframes anim-elem-2 {
0% {
opacity: 0;
-webkit-transform: translate3d(150px, 0, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
}
}
#keyframes anim-elem-2 {
0% {
opacity: 0;
-webkit-transform: translate3d(150px, 0, 0);
transform: translate3d(150px, 0, 0);
}
100% {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://tympanus.net/Development/DialogEffects/js/classie.js"></script>
<script src="https://tympanus.net/Development/DialogEffects/js/modernizr.custom.js"></script>
<div class="button-wrap">
<button data-dialog="somedialog" class="trigger">Open Dialog 1</button>
</div>
<div class="button-wrap">
<button data-dialog="somedialog1" class="trigger">Open Dialog 2</button>
</div>
<div id="somedialog" class="dialog dialog--close">
<div class="dialog__overlay"></div>
<div class="dialog__content">
<div class="morph-shape">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 560 280" preserveAspectRatio="none">
<rect x="3" y="3" fill="none" width="556" height="276"></rect>
</svg>
</div>
<div class="dialog-inner">
<h2><strong>Howdy</strong>, I'm a dialog box 1</h2>
<div><button class="action" data-dialog-close="a">Close</button></div>
</div>
</div>
</div>
<div id="somedialog1" class="dialog dialog--close">
<div class="dialog__overlay"></div>
<div class="dialog__content">
<div class="morph-shape">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 560 280" preserveAspectRatio="none">
<rect x="3" y="3" fill="none" width="556" height="276"></rect>
</svg>
</div>
<div class="dialog-inner">
<h2><strong>Howdy</strong>, I'm a dialog box 2</h2>
<div><button class="action" data-dialog-close="a">Close</button></div>
</div>
</div>
</div>
I'm trying to create something like this :
https://tympanus.net/Development/FullscreenLayoutPageTransitions/
But the problem I face is that my divs are dynamic - could be any number that comes from a xhr service call. I'm trying to stack up divs but on click, they don't grow from their position to occupy the whole screen but grow from top left like this:
https://codepen.io/anon/pen/vJPNOq.
How can I achieve the same effect as in the first link for a dynamic list whose count can be unknown?
<div>
<h1>Your dashboard</h1>
<span class="close">X</span>
<section class="parent">
<section>room1</section>
<section>room2</section>
<section>room3</section>
<section>room4</section>
<section>room5</section>
<sectoin>room6</sectoin>
</section>
</div>
section section{
width:150px;
height:150px;
background-color:green;
margin:10px;
padding:30px;
transition:all .5s linear;
}
.parent{
position:relative;
height:100%;
width:100%;
background-color:red;
}
.expanded{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:999;
background-color:red;
}
.close{
position:absolute;
top:100;
right:0;
z-index:1000;
cursor:pointer;
}
$('.parent section').click(function(){
$(this).addClass('expanded');
})
$('.close').click(function(){
$('.parent section').each(function(){
$(this).removeClass('expanded');
})
})
Here's a demo that shows how you can do this dynamically, it has a few issues if you spam click it but if you disable the click handler until it finishes the animation, they won't matter. Alternatively you could cache the bounding values (you might want to anyway simply to avoid some of the reflows), but the specifics can change a lot depending on the website you're using this effect on.
Also I didn't implement the shrinking effect but I think it's probably fairly obvious how to do it based on the grow effect.
const numberOfTiles = 9;
const totalColumns = 3;
const totalRows = Math.ceil(numberOfTiles / totalColumns);
const container = document.createElement('div');
Object.assign(container.style, {
width: '80vw',
height: '80vh',
background: 'rgb(60, 61, 60)',
transform: 'translate(10vw, 10vh)',
lineHeight: 1 / totalRows * 100 + '%'
});
const tiles = [];
for (let row = 0; row < totalRows; ++row) {
for (let col = 0; col < totalColumns; ++col) {
if (tiles.length < numberOfTiles) {
const tileContainer = document.createElement('div');
Object.assign(tileContainer.style, {
position: 'relative',
width: 1 / totalColumns * 100 + '%',
height: 1 / totalRows * 100 + '%',
display: 'inline-block'
});
let randomColor = Math.ceil((Math.random() * Math.pow(255, 3))).toString(16);
while (randomColor.length < 6) {
randomColor = '0' + randomColor;
}
randomColor = '#' + randomColor;
const tile = document.createElement('div');
tile.classList.add('tile');
Object.assign(tile.style, {
width: '100%',
height: '100%',
background: randomColor,
willChange: 'transform, left, top'
});
tile.addEventListener('click', (evt) => {
if (tile.classList.toggle('fullscreen')) {
let clientRect = tile.getClientRects();
Object.assign(tile.style, {
position: 'absolute',
width: clientRect.width + 'px',
height: clientRect.height + 'px',
left: clientRect.left + 'px',
top: clientRect.top + 'px',
transition: '1s width, 1s height, 1s transform, 1s left, 1s top',
zIndex: 100
});
setTimeout(() => {
let clientRect = tile.getBoundingClientRect();
Object.assign(tile.style, {
left: 0,
top: 0,
width: '100vw',
height: '100vh',
transform: `translate(${-clientRect.left}px, ${-clientRect.top}px)`
});
}, 0);
} else {
Object.assign(tile.style, {
width: '100%',
height: '100%',
left: 0,
top: 0,
transform: '',
zIndex: 1
});
setTimeout(() => {
Object.assign(tile.style, {
zIndex: 0
});
}, 1000);
}
});
tiles.push(tile);
tileContainer.appendChild(tile);
container.appendChild(tileContainer);
}
}
}
document.body.appendChild(container);
* {
margin: 0;
padding: 0;
}
So I have a simple CSS animation (a circle that grows, and then shrinks back down). I am able to successfully use Javascript to detect the start and end of the animation, but can't figure out how to detect the individual keyframes of that animation.
So my question is: how can I detect when the 50% keyframe has been reached in my animation?
Demo: http://codepen.io/tymichaels/pen/Mprrxw
HTML
<div class="center">
<svg class="center circle-animation" xmlns="https://www.w3.org/TR/SVG/">
<g>
<circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
<text x="35" y="75" font-size="18" class="output">circle</text>
</g>
</svg>
</div>
CSS
svg { width:150px;}
text {color:#000; font-family: sans-serif; font-weight: bold;}
.center{
margin-top:100px;
text-align:center;
padding-bottom:50px;
}
.circle-animation{
animation-delay:2s;
animation-duration: 4s;
animation-name: circle-animation;
animation-direction: normal;
animation-timing-function: linear;
}
#-webkit-keyframes circle-animation {
0% {transform: scale( 1 );}
50% {transform: scale( 2.25 );}
100% {transform: scale( 1 );}
}
JS
window.onload = function() {
var elm = document.querySelector('.circle-animation');
var op = document.querySelector('.output');
elm.addEventListener('animationend', function(e) {
op.innerHTML = 'ended';
});
elm.addEventListener('animationstart', function(e) {
op.innerHTML = 'started';
});
}
You can dispatch a custom event on animationstart with setInterval and clear the interval on animationend.
window.onload = function() {
var elm = document.querySelector('.circle-animation');
var op = document.querySelector('.output');
var eventOnAnimate = new Event('onanimate');
var time = 0;
elm.addEventListener('animationend', function(e) {
op.innerHTML = 'ended';
clearInterval(elm.interval);
time = 0;
});
elm.addEventListener('animationstart', function(e) {
op.innerHTML = 'started';
time = 0;
elm.interval = setInterval(function(){
eventOnAnimate.data = {sampleData: ++time};
elm.dispatchEvent(eventOnAnimate);
});
});
elm.addEventListener('onanimate', function(e) {
op.innerHTML = e.data.sampleData + 'ms';
});
}
svg { width:150px;}
text {color:#000; font-family: sans-serif; font-weight: bold;}
.center{
margin-top:30px;
text-align:center;
padding-bottom:50px;
}
.circle-animation{
animation-delay:2s;
animation-duration: 4s;
animation-name: circle-animation;
animation-direction: normal;
animation-timing-function: linear;
}
#-webkit-keyframes circle-animation {
0% {transform: scale( 1 );}
50% {transform: scale( 2.25 );}
100% {transform: scale( 1 );}
}
<div class="center">
<svg class="center circle-animation" xmlns="https://www.w3.org/TR/SVG/">
<g>
<circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
<text x="35" y="75" font-size="18" class="output">circle</text>
</g>
</svg>
</div>
There is no native event support for listening keyframe-by-keyframe, but you can create a workaround with setTimeout and window.getComputedStyle (to get the animation-duration property).
Below is an onKeyframes utility which can be used to listen for an arbitrary number of keyframe events using a more intuitive percentage-based syntax:
onKeyframes(elm, {
0: function() {
op.textContent = 'started'
},
50: function() {
op.textContent = 'midpoint'
},
100: function() {
op.textContent = 'ended'
}
})
Demo Snippet:
function onKeyframes(element, handlers) {
var from = handlers[0] || handlers.from
var to = handlers[100] || handlers.to
delete handlers.from
delete handlers[0]
delete handlers.to
delete handlers[100]
handlers = Object.keys(handlers).map(function(k) {
return [k, this[k]]
}, handlers)
element.addEventListener('animationstart', function() {
from && from.apply(this, arguments)
if (handlers.length) {
var match = /(\d+)(m?)s/.exec(window.getComputedStyle(element).animationDuration)
var duration = (match[2] ? 1 : 1e3) * match[1]
handlers.forEach(function(pair) {
setTimeout(pair[1], pair[0] / 100 * duration)
})
}
})
to && element.addEventListener('animationend', to)
}
window.onload = function() {
var elm = document.querySelector('.circle-animation')
var op = document.querySelector('.output')
onKeyframes(elm, {
0: function() {
op.textContent = 'started'
},
50: function() {
op.textContent = 'midpoint'
},
100: function() {
op.textContent = 'ended'
}
})
}
svg {
width: 150px;
}
text {
color: #000;
font-family: sans-serif;
font-weight: bold;
}
.center {
margin-top: 100px;
text-align: center;
padding-bottom: 50px;
}
.circle-animation {
animation-delay: 2s;
animation-duration: 4s;
animation-name: circle-animation;
animation-direction: normal;
animation-timing-function: linear;
}
#-webkit-keyframes circle-animation {
0% {
transform: scale( 1);
}
50% {
transform: scale( 2.25);
}
100% {
transform: scale( 1);
}
}
<div class="center">
<svg class="center circle-animation" xmlns="https://www.w3.org/TR/SVG/">
<g>
<circle cx="65" cy="70" r=60 fill="#96CCFF" stroke-width="3" stroke="#8181F7"></circle>
<text x="35" y="75" font-size="18" class="output">circle</text>
</g>
</svg>
</div>
I have 2 button (the unsmile and smile).
1. When i click to unsmile the img "flies" to left side.
2. When i click to smile the img is "flies" to right side.
But i need to do the following:
When i click on the img and drag it to the left, the img + description should "fly" to the left side and show a js alert - "You don't like this".
When i click on the img and drag it to right, the img + description should "fly" to the right side and show an alert - "You like this".
When i click on the img and drag it under the img, the img + description should "fly" down and show an alert - "You add this to favorite".
This should be done in javascript/html5/css.
It will be compiled using intelXDK to android platform.
HTML
<div id="food"></div>
<div id="control">
<div class="button no">
</div>
<div class="button yes">
</div>
</div>
</div>
JS Code
$('a[href*=#]').click(function(){
return false;
});
var animationEndEvent = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
var Food = {
wrap: $('#food'),
selectFood: [
{
name: 'Hamburger',
locaction: 'Poland, Warsaw, FoocCap',
img: "images/photo/1.jpg"
},
{
name: 'Chiness something',
locaction: 'Poland, Warsaw, FoocKnajp',
img: "images/photo/2.jpg"
},
{
name: 'Nuggets',
locaction: 'Japan, Tokyo, Yorazowa',
img: "images/photo/3.jpg"
},
{
name: 'Burger',
locaction: 'Japan, Nagasaki, Nogoiau',
img: "images/photo/4.jpg"
},
{
name: 'Chicken pice',
locaction: 'Russia, Moskow, Karmino',
img: "images/photo/5.jpg"
}
],
add: function(){
var random = this.selectFood[Math.floor(Math.random() * this.selectFood.length)];
this.wrap.append("<div class='foodChoose'><img alt='" + random.name + "' src='" + random.img + "' /><span><strong>" + random.name + "</strong>, " + random.locaction + "</span></div>");
}
}
var App = {
yesButton: $('.button.yes .trigger'),
noButton: $('.button.no .trigger'),
blocked: false,
like: function(liked){
var animate = liked ? 'animateYes' : 'animateNo';
var self = this;
if (!this.blocked) {
this.blocked = true;
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent, function() {
$(this).remove();
Food.add();
self.blocked = false;
});
}
}
};
App.yesButton.on('mousedown', function() {
App.like(true);
});
App.noButton.on('mousedown', function() {
App.like(false);
});
$(document).ready(function() {
Food.add();
});
CSS
#keyframes yes {
0% {
transform: scale(1) rotateZ(0deg);
left: 0;
}
30% {
transform: scale(1.05) rotateZ(0deg);
left: 0;
}
100% {
transform: rotateZ(45deg);
left: 400px;
}
}
.animateYes {
animation-fill-mode: both;
animation: yes 0.6s linear;
}
#keyframes no {
0% {
transform: rotateZ(360deg);
right: 0;
}
30% {
transform: scale(1.05) rotateZ(360deg);
right: 0;
}
100% {
transform: rotateZ(315deg);
right: 400px;
}
}
.animateNo {
animation-fill-mode: both;
animation: no 0.6s linear;
}
#control {
position: relative;
margin: 0 auto;
width: 250px;
top: -55%;
}
#control .button {
width: 65px;
height: 65px;
background: #fff;
position: absolute;
top: 5px;
border-radius: 50%;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
}
#control .button .trigger:active {
transform: translateY(-50%) scale(0.75);
transition: all .05s linear;
}
#control .button .trigger:before {
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
font-family: 'FontAwesome';
}
#control .no {
left: 38px;
}
#control .no .trigger:before {
content: "\2639";
font-size: 40px;
color: #c33;
}
#control .yes {
right: 38px;
}
#control .yes .trigger:before {
content: "\263A";
font-size: 40px;
color: #3b7;
}
Current working version can be found here.
It's beed a while since I worked with jquery- let me know if it's a bad way to handle it so I can update/delete it?
You have already implemented an animationEnd handler
var App = {
yesButton: $('.button.yes .trigger'),
noButton: $('.button.no .trigger'),
blocked: false,
like: function(liked){
var animate = liked ? 'animateYes' : 'animateNo';
var self = this;
if (!this.blocked) {
this.blocked = true;
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent, function() {
$(this).remove();
Food.add();
self.blocked = false;
});
}
}
};
just pass the required arguments to your handler, e.g.
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent,
function(e) {
function(liked) {
$(this).remove();
alert(liked);
Food.add();
self.blocked = false;
}.bind(e.target, liked);
}
);
I'm passing the jquery custom event target here which should be identical to $('.foodChoose').eq(0)
^^ this means you will not need the original event and can remove the outer function like:
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent,
function(liked) {
$(this).remove();
alert(liked);
Food.add();
self.blocked = false;
}.bind($('.foodChoose').eq(0), liked);
);
added a fiddle including the code: https://jsfiddle.net/jLugv92t/1/ - slightly modified to bind to App. Thiy way we get rid of
var self = this;