UNPKG

vue-ripple-directive

Version:
149 lines (124 loc) 6.26 kB
var Ripple = { bind: function(el, binding){ // Default values. var props = { event: 'mousedown', transition: 600 }; setProps(Object.keys(binding.modifiers),props); el.addEventListener(props.event, function(event) { rippler(event, el, binding.value); }); var bg = binding.value || Ripple.color || 'rgba(0, 0, 0, 0.35)'; var zIndex = Ripple.zIndex || '9999'; function rippler(event, el) { var target = el; // Get border to avoid offsetting on ripple container position var targetBorder = parseInt((getComputedStyle(target).borderWidth).replace('px', '')); // Get necessary variables var rect = target.getBoundingClientRect(), left = rect.left, top = rect.top, width = target.offsetWidth, height = target.offsetHeight, dx = event.clientX - left, dy = event.clientY - top, maxX = Math.max(dx, width - dx), maxY = Math.max(dy, height - dy), style = window.getComputedStyle(target), radius = Math.sqrt((maxX * maxX) + (maxY * maxY)), border = (targetBorder > 0 ) ? targetBorder : 0; // Create the ripple and its container var ripple = document.createElement("div"), rippleContainer = document.createElement("div"); rippleContainer.className = 'ripple-container'; ripple.className = 'ripple'; //Styles for ripple ripple.style.marginTop= '0px'; ripple.style.marginLeft= '0px'; ripple.style.width= '1px'; ripple.style.height= '1px'; ripple.style.transition= 'all ' + props.transition + 'ms cubic-bezier(0.4, 0, 0.2, 1)'; ripple.style.borderRadius= '50%'; ripple.style.pointerEvents= 'none'; ripple.style.position= 'relative'; ripple.style.zIndex= zIndex; ripple.style.backgroundColor = bg; //Styles for rippleContainer rippleContainer.style.position= 'absolute'; rippleContainer.style.left = 0 - border + 'px'; rippleContainer.style.top = 0 - border + 'px'; rippleContainer.style.height = '0'; rippleContainer.style.width = '0'; rippleContainer.style.pointerEvents = 'none'; rippleContainer.style.overflow = 'hidden'; // Store target position to change it after var storedTargetPosition = ((target.style.position).length > 0) ? target.style.position : getComputedStyle(target).position; // Change target position to relative to guarantee ripples correct positioning if (storedTargetPosition !== 'relative') { target.style.position = 'relative'; } rippleContainer.appendChild(ripple); target.appendChild(rippleContainer); ripple.style.marginLeft = dx + "px"; ripple.style.marginTop = dy + "px"; // No need to set positioning because ripple should be child of target and to it's relative position. // rippleContainer.style.left = left + (((window.pageXOffset || document.scrollLeft) - (document.clientLeft || 0)) || 0) + "px"; // rippleContainer.style.top = top + (((window.pageYOffset || document.scrollTop) - (document.clientTop || 0)) || 0) + "px"; rippleContainer.style.width = width + "px"; rippleContainer.style.height = height + "px"; rippleContainer.style.borderTopLeftRadius = style.borderTopLeftRadius; rippleContainer.style.borderTopRightRadius = style.borderTopRightRadius; rippleContainer.style.borderBottomLeftRadius = style.borderBottomLeftRadius; rippleContainer.style.borderBottomRightRadius = style.borderBottomRightRadius; rippleContainer.style.direction = 'ltr'; setTimeout(function() { ripple.style.width = radius * 2 + "px"; ripple.style.height = radius * 2 + "px"; ripple.style.marginLeft = dx - radius + "px"; ripple.style.marginTop = dy - radius + "px"; }, 0); function clearRipple() { setTimeout(function() { ripple.style.backgroundColor = "rgba(0, 0, 0, 0)"; }, 250); // Timeout set to get a smooth removal of the ripple setTimeout(function() { rippleContainer.parentNode.removeChild(rippleContainer); }, 850); el.removeEventListener('mouseup', clearRipple, false); // After removing event set position to target to it's original one // Timeout it's needed to avoid jerky effect of ripple jumping out parent target setTimeout(function () { var clearPosition = true; for(var i = 0; i < target.childNodes.length; i++) { if(target.childNodes[i].className === 'ripple-container') { clearPosition = false; } } if(clearPosition) { if(storedTargetPosition !== 'static') { target.style.position = storedTargetPosition; } else { target.style.position = ''; } } }, props.transition + 250) } if(event.type === 'mousedown') { el.addEventListener('mouseup', clearRipple, false); } else { clearRipple(); } } } }; function setProps(modifiers,props) { modifiers.forEach(function(item) { if(isNaN(Number(item))) props.event = item; else props.transition = item; }); } export default Ripple;