I have several number counters and want them to start animating when the user scroll downs to them. Right now, I achieved this by writing a function for each one of them but I'm sure that's an inefficient way of doing this.
I have a working example here:
https://codepen.io/adogandesign/pen/PWqVov
HTML:
<div id="states" class="animated">
<div class="anim_num">
<svg>
<pattern>...</pattern>
<text id="count_num1"></text>
</svg>
</div>
</div>
<div id="concerts" class="animated">
<div class="anim_num">
<svg>
<pattern>...</pattern>
<text id="count_num2"></text>
</svg>
</div>
</div>
Javascript:
$(window).scroll(startCounter1);
function startCounter1() {
if ($(window).scrollTop() > $("#states").offset().top - $(window).height() + 0) {
$(window).off("scroll", startCounter1);
$("#count_num1").each(function () {
var $this = $(this);
jQuery({ Counter: 0 }).animate({ Counter: $this.text() }, {
duration: 4000,
easing: 'swing',
step: function (now) {
$this.text(now.toFixed(0));
}
});
});
}
}
$(window).scroll(startCounter2);
function startCounter2() {
if ($(window).scrollTop() > $("#concerts").offset().top - $(window).height() + 0) {
$(window).off("scroll", startCounter2);
$("#count_num2").each(function () {
var $this = $(this);
jQuery({ Counter: 0 }).animate({ Counter: $this.text() }, {
duration: 4000,
easing: 'swing',
step: function (now) {
$this.text(now.toFixed(0));
}
});
});
}
}
My question is how can I combine that javascript code into one function?
The general algorithm you can use for refactoring of this sort is:
Identify the parts that are different.
Replace those parts with variable names.
Create a function wrapper, replacing those variables with function parameters.
Replace the code with calls to that function.
So in this case, the first variance is "#states" vs "#concerts"; let's call that section. The second is #count_num1 vs #count_num2, which we can call counter. Now we can do this:
function createScrollCounter(section, counter) {
$(window).scroll(scrollCounter);
function scrollCounter() {
if ($(window).scrollTop() > $(section).offset().top - $(window).height() + 0) {
$(window).off("scroll", scrollCounter);
$(counter).each(function () {
var $this = $(this);
jQuery({ Counter: 0 }).animate({ Counter: $this.text() }, {
duration: 4000,
easing: 'swing',
step: function (now) {
$this.text(now.toFixed(0));
}
});
});
}
}
}
createScrollCounter('#states', '#count_num1');
createScrollCounter('#concerts', '#count_num2');
Use an each to loop over a common class instead of focusing on individual ID's and handle each instance inside that loop
Something like:
$('.animated').each(function() { // #states & #concerts
// current instance of the animated class
var $this = $(this),
// find associated text element,
// will be #count_num1 or #count_num2 depending on $this instance
$textEl = $this.find('text');
// check instance offset
if ($(window).scrollTop() > $this.offset().top - $(window).height() + 0) {
jQuery({
Counter: 0
}).animate({
Counter: $textEl.text()
}, {
duration: 4000,
easing: 'swing',
step: function(now) {
$textEl.text(now.toFixed(0));
}
});
}
});
Note that you probably want to check if the animation is already taking place before initializing it again for every pixel move of scroll
Simply give each text tag same class like "animation" and remove id (count_num1, count_num2) from there and at $("#count_num1") use $(".animation") I had check this method in your codepen link and it work perfectly.
$(window).scroll(startCounter1);
function startCounter1() {
if ($(window).scrollTop() > $("#states").offset().top - $(window).height() + 0) {
$(window).off("scroll", startCounter1);
$(".animation").each(function () {
var $this = $(this);
jQuery({ Counter: 0 }).animate({ Counter: $this.text() },
{
duration: 4000,
easing: 'swing',
step: function (now) {
$this.text(now.toFixed(0));
}
});
});
}
}
body{
width: 100%;
overflow-x: hidden;
font-family: Open Sans, sans-serif;
}
.scrolldown {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 50px;
}
.animated_percentage {
max-width: 100%;
margin: 0 auto;
position: relative;
}
.anim_num {
display: block;
position: relative;
max-height: 100vh;
padding: 5% 0;
font-size: 350px;
font-weight: 900;
}
#states .anim_num {
padding-left: 20%;
}
#concerts .anim_num {
padding-right: 30%;
}
#fans .anim_num {
padding-left: 15%;
}
svg {
max-width: 100%;
max-height: 100%;
}
#count_num1{
fill: url(#img1);
}
#count_num2{
fill: url(#img2);
}
#count_num3{
fill: url(#img3);
}
.exp {
position: absolute;
top: 50%;
font-size: 48px;
font-weight: 700;
color: #aabbae;
}
#states .exp {
left: 10%;
}
#concerts .exp {
right: 20%;
}
#fans .exp {
left: 5%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="scrolldown">
Scroll down to see the animation
</div>
<div id="states" class="animated_percentage">
<div class="anim_num">
<svg viewBox="0 0 960 540">
<pattern id="img1" patternUnits="userSpaceOnUse" width="100%" height="100%" x="-10%" y="-25%">
<image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://adogandesign.com/wp-content/uploads/2017/01/AdobeStock_69678727.jpg" width="960" height="540"></image>
</pattern>
<text text-anchor="middle" x="50%" y="50%" class="animation" id="count_num1">46</text>
</svg>
</div><!--#anim_num-->
<div class="exp">
States travelled
</div>
</div>
<div id="concerts" class="animated_percentage">
<div class="anim_num">
<svg viewBox="0 0 960 540">
<pattern id="img2" patternUnits="userSpaceOnUse" width="100%" height="100%" x="0" y="-20%">
<image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://adogandesign.com/wp-content/uploads/2017/01/AdobeStock_63664078.jpg" width="960" height="540"></image>
</pattern>
<text text-anchor="middle" x="50%" y="50%" class="animation" id="count_num2">97</text>
</svg>
</div><!--#anim_num-->
<div class="exp">
Concerts Given
</div>
</div>
<div id="fans" class="animated_percentage">
<div class="anim_num">
<svg viewBox="0 0 960 540">
<pattern id="img3" patternUnits="userSpaceOnUse" width="100%" height="100%" x="0" y="-22%">
<image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://adogandesign.com/wp-content/uploads/2017/01/AdobeStock_93833225.jpg" width="960" height="540"></image>
</pattern>
<text text-anchor="middle" x="50%" y="50%" class="animation" id="count_num3">436</text>
</svg>
</div><!--#anim_num-->
<div class="exp">
Fans Gone Wild
</div>
</div>
Related
I’m trying to fluidify a circle progress bar in a timer. The progress bar represents the progression in the duration of the timer. I made an svg <circle> circle element for the progress bar. Every 10th of second, I change the css attribute stroke-dashoffset of the circle. This works fine but if we choose less than 5 minutes for the time, the movements of the progress bar are not fluid. What can I do to make that fluid ?
class Timer {
constructor(circle, text) {
this.circle = circle
this.text = text
this.text.innerHTML
}
async start(hours, minutes, seconds) {
this.circle.style["stroke-dasharray"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
this.circle.style["stroke-dashoffset"] = parseInt(Math.PI * this.circle.getBoundingClientRect().width)
await this.countdown()
this.circle.classList = "progress"
var remaining, interval, duration, end;
duration = parseInt(hours) * 3600000 + parseInt(minutes) * 60000 + (parseInt(seconds) + 1) * 1000
end = Date.now() + duration
interval = setInterval(async () => {
remaining = end - Date.now()
this.circle.style["stroke-dashoffset"] = remaining * parseInt(Math.PI * this.circle.getBoundingClientRect().width) / duration;
if (remaining < 0) {
this.circle.style["stroke-dashoffset"] = 0
clearInterval(interval)
window.location.href = "./"
return true
} else {
this.text.innerHTML = `${("0" + parseInt(remaining / 3600000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 / 60000)).slice(-2)}:${("0" + parseInt(remaining % 3600000 % 60000 / 1000)).slice(-2)}`
}
}, 100)
}
countdown() {
var duration;
duration = 2
this.text.innerHTML = 3
return new Promise(resolve => {
setInterval(async () => {
if (duration <= 0) {
resolve(true)
} else {
this.text.innerHTML = duration
duration -= 1
}
}, 1000)
})
}
}
const timer = new Timer(document.getElementById("progress"), document.getElementById("text"))
const params = new URLSearchParams(window.location.search)
timer.start(0, 0, 10)
:root {
--pi: 3.141592653589793
}
circle.progress {
display: block;
position: absolute;
fill: none;
stroke: url(#circle.progress.color);
stroke-width: 4.5vmin;
stroke-linecap: round;
transform-origin: center;
transform: rotate(-90deg);
}
circle.progress.animation {
animation: circle 3s linear forwards;
}
.progress-container {
left: 50vw;
top: 50vh;
width: 90vmin;
height: 90vmin;
margin-top: -45vmin;
margin-left: -45vmin;
position: absolute;
padding: none;
}
.outer {
margin: none;
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 6px 6px 10px -1px rgba(0, 0, 0, 0.15), -6px -6px 10px -1px rgba(255, 255, 255, 0.7);
padding: 2.5%;
}
.inner {
margin: 2.5%;
width: 95%;
height: 95%;
border-radius: 50%;
box-shadow: inset 4px 4px 6px -1px rgba(0, 0, 0, 0.15), inset -4px -4px 6px -1px rgba(255, 255, 255, 0.7);
}
svg {
display: block;
position: absolute;
left: 50vw;
top: 50vh;
width: 90.5vmin;
height: 90.5vmin;
margin-top: -45.25vmin;
margin-left: -45.25vmin;
}
svg text {
font-size: 10vmin;
font-family: 'Roboto', sans-serif;
}
#keyframes circle {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: calc(45.5vmin * var(--pi) * 2);
}
}
<link href="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/css/materialize.min.css" rel="stylesheet"/>
<div class="progress-container">
<div class="outer center-align">
<div class="inner"></div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="center" version="1.1">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
</defs>
<circle id="progress" class="progress animation" cy="45.25vmin" cx="45.25vmin" r="42.75vmin" />
<text id="text" text-anchor="middle" x="50%" y="50%">Temps restant</text>
</svg>
<script src="https://cdn.jsdelivr.net/npm/#materializecss/materialize#1.2.1/dist/js/materialize.min.js"></script>
The code here runs the timer for 10 seconds. Normally, you would have to choose the time in another page. To have the time input, go to that page (the page is in french).
I'm not able to explain the issue, so here I have an alternative solution. The function setInterval has issues with the timing (maybe that is actually you issue...). You cannot expect it to be precise. Instead of controlling the progress using setInterval you can use a keyframe animation with the Web Animations API. This is a better alternative to the JavaScript animation where you update an attribute/style, and easier to work with then SVG SMIL animations.
So, I rely on the animation doing its job and then update the time displayed by asking for the currenttime on the animation object.
const progress = document.getElementById('progress');
const text = document.getElementById('text');
document.forms.form01.addEventListener('click', e => {
if(e.target.value){
var progressKeyframes = new KeyframeEffect(
progress,
[
{ strokeDasharray: '0 100' },
{ strokeDasharray: '100 100' }
],
{ duration: parseInt(e.target.value), fill: 'forwards' }
);
var a1 = new Animation(progressKeyframes, document.timeline);
a1.play();
let timer = setInterval(function(){
if(a1.playState == 'running'){
text.textContent = Math.floor(a1.currentTime/1000);
}else if(a1.playState == 'finished'){
text.textContent = Math.round(e.target.value/1000);
clearInterval(timer);
}
}, 100);
}
});
<form name="form01">
<input type="button" value="2000" />
<input type="button" value="5000" />
<input type="button" value="10000" />
</form>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="300">
<defs>
<linearGradient id="circle.progress.color">
<stop offset="0%" stop-color="BlueViolet" />
<stop offset="100%" stop-color="MediumVioletRed" />
</linearGradient>
<filter id="shadow">
<feDropShadow dx=".4" dy=".4" stdDeviation="1" flood-color="gray"/>
</filter>
</defs>
<circle r="40" stroke="white" stroke-width="8" fill="none" transform="translate(50 50)" filter="url(#shadow)"/>
<circle id="progress" r="40" stroke="url(#circle.progress.color)" stroke-width="8" fill="none" pathLength="100" stroke-dasharray="0 100" transform="translate(50 50) rotate(-90)" stroke-linecap="round"/>
<text id="text" dominant-baseline="middle" text-anchor="middle" x="50" y="50">0</text>
</svg>
Hellol,I have a code for a custom cursor, and the cursor, which is a ball/circle, was supposed to grow/scale when hovering over a link, if you see the code below, this function is there, but it is not working, does anyone know what's wrong? Thank you in advance. Note, I am unable to create a snippet here. The code is from codepen: https://codepen.io/clementGir/pen/RQqvQx
<div class="cursor">
<div class="cursor__ball cursor__ball--big ">
<svg height="30" width="30">
<circle cx="15" cy="15" r="12" stroke-width="0"></circle>
</svg>
</div>
<div class="cursor__ball cursor__ball--small">
<svg height="10" width="10">
<circle cx="5" cy="5" r="4" stroke-width="0"></circle>
</svg>
</div>
</div>
<style>
body .cursor {
pointer-events: none;
}
body .cursor__ball {
position: fixed;
top: 0;
left: 0;
mix-blend-mode: difference;
z-index: 1000;
}
body .cursor__ball circle {
fill: #f7f8fa;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<script>
const $bigBall = document.querySelector('.cursor__ball--big');
const $smallBall = document.querySelector('.cursor__ball--small');
const $hoverables = document.querySelectorAll('a');
// Listeners
document.body.addEventListener('mousemove', onMouseMove);
for (let i = 0; i < $hoverables.length; i++) {
if (window.CP.shouldStopExecution(0)) break;
$hoverables[i].addEventListener('mouseenter', onMouseHover);
$hoverables[i].addEventListener('mouseleave', onMouseHoverOut);
}
// Move the cursor
window.CP.exitedLoop(0); function onMouseMove(e) {
TweenMax.to($bigBall, .4, {
x: e.clientX - 15,
y: e.clientY - 15
});
TweenMax.to($smallBall, .1, {
x: e.clientX - 5,
y: e.clientY - 7
});
}
// Hover an element
function onMouseHover() {
TweenMax.to($bigBall, .3, {
scale: 4
});
}
function onMouseHoverOut() {
TweenMax.to($bigBall, .3, {
scale: 1
});
}
</script>```
Growing cursor on hovering a link.
The codepen you are trying to copy links to external scripts and has been adapted to work inside codepen.
What I did to get the pen to work here (I think you only needed step 4):
For CSS & JS clicked down arrow top right, view compiled
Copy over all code
Settings>JS>External Scripts>Copy link into Stack Overflow snippet's external scripts
Removed 'window.CP' code junk which I assume is something to do with codepen and getting the window object of their sub-document
const $bigBall = document.querySelector('.cursor__ball--big');
const $smallBall = document.querySelector('.cursor__ball--small');
const $hoverables = document.querySelectorAll('.hoverable');
// Listeners
document.body.addEventListener('mousemove', onMouseMove);
for (let i = 0; i < $hoverables.length; i++) {
$hoverables[i].addEventListener('mouseenter', onMouseHover);
$hoverables[i].addEventListener('mouseleave', onMouseHoverOut);
}
// Move the cursor
function onMouseMove(e) {
TweenMax.to($bigBall, .4, {
x: e.pageX - 15,
y: e.pageY - 15 });
TweenMax.to($smallBall, .1, {
x: e.pageX - 5,
y: e.pageY - 7 });
}
// Hover an element
function onMouseHover() {
TweenMax.to($bigBall, .3, {
scale: 4 });
}
function onMouseHoverOut() {
TweenMax.to($bigBall, .3, {
scale: 1 });
}
body {
height: 100vh;
background: #010101;
cursor: none;
margin: 0;
display: flex;
font-family: monospace;
}
body h1,
body p,
body a {
color: #fff;
}
body a {
border-bottom: 2px solid #fff;
padding: 10px 0;
margin-top: 25px;
}
body .cursor {
pointer-events: none;
}
body .cursor__ball {
position: fixed;
top: 0;
left: 0;
mix-blend-mode: difference;
z-index: 1000;
}
body .cursor__ball circle {
fill: #f7f8fa;
}
body .left,
body .right {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
body .right {
background: #fff;
}
body .right a {
border-bottom: 2px solid #000;
}
body .right h1,
body .right p,
body .right a {
color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div class="cursor">
<div class="cursor__ball cursor__ball--big ">
<svg height="30" width="30">
<circle cx="15" cy="15" r="12" stroke-width="0"></circle>
</svg>
</div>
<div class="cursor__ball cursor__ball--small">
<svg height="10" width="10">
<circle cx="5" cy="5" r="4" stroke-width="0"></circle>
</svg>
</div>
</div>
<div class="left">
<h1>Hello</h1>
<p>Check out this link:</p>
<a class="hoverable">Hover meh</a>
</div>
<div class="right">
<h1>Hello</h1>
<p>Check out this link:</p>
<a class="hoverable">Hover meh</a>
</div>
I have a chevron SVG at the bottom of my page that I want to hide once the user scrolls down. I can't figure out why my JS isn't working and the chevron is never hidden:
NOTE: the console.log statements do run and the css stylesheet does work.
chevron = document.getElementById("down-accelerate-path");
window.addEventListener("scroll", e => {
const y = window.scrollY;
if (y >= 1) {
console.log(y + " " + chevron)
chevron.className = ""
chevron.hidden = true;
} else {
chevron.className = "hide"
chevron.hidden = false;
}
});
body {
height: 300vh;
}
.hide {
display: none;
}
#down-accelerate {
position: fixed;
top: 88%;
transform: translateX(-50%);
}
<span class="center">
<svg height=88 width=88 viewBox="0 0 444.819 444.819" xmlns="http://www.w3.org/2000/svg" id = "down-accelerate">
<path id="down-accelerate-path" style="" fill="white" stroke="none"
d="M434.252,114.203l-21.409-21.416c-7.419-7.04-16.084-10.561-25.975-10.561c-10.095,0-18.657,3.521-25.7,10.561
L222.41,231.549L83.653,92.791c-7.042-7.04-15.606-10.561-25.697-10.561c-9.896,0-18.559,3.521-25.979,10.561l-21.128,21.416
C3.615,121.436,0,130.099,0,140.188c0,10.277,3.619,18.842,10.848,25.693l185.864,185.865c6.855,7.23,15.416,10.848,25.697,10.848
c10.088,0,18.75-3.617,25.977-10.848l185.865-185.865c7.043-7.044,10.567-15.608,10.567-25.693
C444.819,130.287,441.295,121.629,434.252,114.203z"/>
</svg>
</span>
Your code appears to be working. But I couldn't see the chevron. So I made it black and changed its position for testing. I also cleaned up the code a bit.
chevron = document.getElementById("chevron");
window.addEventListener("scroll", e => {
const y = window.scrollY;
if (y >= 1) {
chevron.className = 'hide'
} else {
chevron.className = ''
}
});
body {
height: 300vh;
}
.hide {
display: none;
}
#down-accelerate {
position: fixed;
right: 50%;
}
<span class="center" id="chevron">
<svg height=88 width=88 viewBox="0 0 444.819 444.819" xmlns="http://www.w3.org/2000/svg" id = "down-accelerate">
<path id="down-accelerate-path" style="" fill="black" stroke="none"
d="M434.252,114.203l-21.409-21.416c-7.419-7.04-16.084-10.561-25.975-10.561c-10.095,0-18.657,3.521-25.7,10.561
L222.41,231.549L83.653,92.791c-7.042-7.04-15.606-10.561-25.697-10.561c-9.896,0-18.559,3.521-25.979,10.561l-21.128,21.416
C3.615,121.436,0,130.099,0,140.188c0,10.277,3.619,18.842,10.848,25.693l185.864,185.865c6.855,7.23,15.416,10.848,25.697,10.848
c10.088,0,18.75-3.617,25.977-10.848l185.865-185.865c7.043-7.044,10.567-15.608,10.567-25.693
C444.819,130.287,441.295,121.629,434.252,114.203z"/>
</svg>
</span>
I have a full screen SVG image/mask reveal; it works great on desktop but it doesn't scale/fit on mobile devices. So im guessing the best solution would be to dynamically build the SVG and SVG container depending on screen width and have a mobile & desktop build. So i'm looking for advice and the best solution and if someone could point me in the right direction or know of an example I can look at.
// DRAW SVG MASK /////////////////////////////
var svg = document.querySelector("#svg__bg");
var tl = new gsap.timeline({ onUpdate: onUpdate });
var pt = svg.createSVGPoint();
var ratio = 0.5625;
tl.to("#masker", {duration: 2, attr: {r: 2400}, ease: "power2.in" });
tl.reversed(true);
function mouseHandler() {
tl.reversed(!tl.reversed());
}
function getPoint(evt) {
pt.x = evt.clientX;
pt.y = evt.clientY;
return pt.matrixTransform(svg.getScreenCTM().inverse());
}
function mouseMove(evt) {
var newPoint = getPoint(evt);
gsap.set("#dot", { cx: newPoint.x, cy: newPoint.y });
gsap.to("#ring, #masker", {duration: 0.88, attr: { cx: newPoint.x, cy: newPoint.y }, ease: "power2.out" });
}
function onUpdate() {
var prog = (tl.progress() * 100);
}
function newSize() {
var w = window.innerWidth;
var h = window.innerHeight;
if (w > h * (16 / 9)) {
gsap.set("#svg__bg", { attr: { width: w, height: w * ratio } });
} else {
gsap.set("#svg__bg", {
attr: {
width: h / ratio,
height: h
}
});
}
var data = svg.getBoundingClientRect();
gsap.set("#svg__bg", {
x: w / 2 - data.width / 2
});
gsap.set("#svg__bg", {
y: h / 2 - data.height / 2
});
}
window.addEventListener("mousedown", mouseHandler);
window.addEventListener("mouseup", mouseHandler);
window.addEventListener("mousemove", mouseMove);
newSize();
window.addEventListener("resize", newSize);
#import url('https://fonts.googleapis.com/css?family=Montserrat:700&display=swap');
body {
min-height: 100vh;
background-color: #1F242D;
cursor: none;
overflow: hidden;
font-family: 'Montserrat', sans-serif;
}
.intro-svg {
position: relative;
padding: 0;
margin: 0;
width: 100%;
min-height: 100vh;
height: calc(var(--vh, 1vh) * 100);
overflow: hidden;
z-index: 1;
}
.svg__container {
height: 100%;
width: 100%;
position: relative;
overflow: hidden;
}
.svg__image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: none;
}
.text-svg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: none;
z-index:2;
}
.impact-text {
font-size: 7em;
line-height: 1.2;
text-transform: uppercase;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js"></script>
<div class="intro-svg">
<div class="svg__container">
<svg id="svg__bg" class="svg__image" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="1600" height="900" viewBox="0 0 1600 900">
<defs>
<radialGradient id="mask-gradient">
<stop offset="80%" stop-color="#fff"/><stop offset="100%" stop-color="#000" />
</radialGradient>
<mask id="the-mask">
<circle id="masker" r="250" fill="url(#mask-gradient)" cx="800" cy="450">
</circle>
</mask>
<mask id="mask-text" width="100" height="100" x="0" y="0">
<text id="masker" class="impact-text row-1" fill="none" stroke="#fff" stroke-width="3" x="10.1%" y="42%">A</text>
<text id="masker" class="impact-text row-2" fill="white" x="10%" y="55%">Digital</text>
<text id="masker" class="impact-text row-3" fill="white" x="10%" y="68%">Designer</text>
</mask>
</defs>
<image id="lines" xlink:href="https://i.imgur.com/1TQRj56.jpg" x="0" y="0" width="1600" height="900" />
<g id="mask-reveal" mask="url(#the-mask)">
<image id="regular" xlink:href="https://i.imgur.com/7VtEKv3.jpg" x="0" y="0" width="1600" height="900" />
</g>
<g mask="url(#mask-text)">
<image id="text-before" xlink:href="https://i.imgur.com/7VtEKv3.jpg" x="0" y="0" width="1600" height="900" />
</g>
<circle id="ring" r="20" fill="none" stroke="#D74A53" stroke-width="2" cx="800" cy="450" />
<circle id="dot" r="4" fill="#D74A53" cx="800" cy="450"/>
</svg>
</div>
</div>
just add
#svg__bg {
width: 100%;
height:auto;
}
andchange them with media query
don't forget to change
<svg id="svg__bg" class="svg__image" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1600 900">
without width="1600" height="900"
I'm trying to make a small animation (using Velocity.js) that alternates between two looping states when an svg is clicked. The first state is horizontally from scaleX(1) to scaleX(2.5) back to scaleX(1) at scaleY(1), the second is vertically scaleY(1) to scaleY(8) back to scaleY(1) at scaleX(2.5). When the svg is clicked the animation starts in it's horizontal state, clicked again, the state that was just active (horizontal) should stop, and the alternative state should start (vertical), every click changes to the alternate state. Ideally the state change is seamless in the sense that svg should scale to the correct scale on the axis that is not animating whilst the new active state is animating.
This is a gif of what i'm trying to achieve, the blue dot symbolises a click:
My current outcome is embedded, the problem i'm having is that only one state change occurs so I need to stop the previous animation. The other problem is that in the transition, the scaling does not happen at the same time, i.e the new active state's animation does not happen at the same time as scaling of the axis that is not animating in the new state. Any pointers in the right direction would be greatly appreciated.
// LINKs TO VELOCITY
// https://rawgit.com/julianshapiro/velocity/master/velocity.min.js
// https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.0/velocity.min.js
var Rightscale = {
chooser: 0,
svg: $('#right').find('svg'),
init: function() {
this.bindEvents();
},
bindEvents: function() {
Rightscale.svg.on("click", function() {
console.log(Rightscale.chooser)
if(Rightscale.chooser === 0) {
Rightscale.chooser = 1;
Rightscale.horizontal();
} else {
Rightscale.chooser = 0;
Rightscale.vertical();
}
})
},
horizontal: function() {
Rightscale.svg.velocity({
scaleX: 2.5,
scaleY: 1
}, {
duration: 3000,
loop: true,
easing: "linear"
})
},
vertical: function() {
Rightscale.svg.velocity({
scaleY: 8,
scaleX: 2.5
}, {
duration: 3000,
loop: true,
easing: "linear"
})
},
}
$(document).ready(function() {
Rightscale.init();
});
#right {
width: 100vw;
height: 100vh;
background-color: blue;
display: flex;
justify-content: center;
align-items: center;
}
.scale {
width: 40%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.0/velocity.min.js"></script>
<script src="https://rawgit.com/julianshapiro/velocity/master/velocity.min.js"></script>
<div id="right">
<div class="scale">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 392 132" style="enable-background:new 0 0 392 132;" xml:space="preserve">
<g>
<path d="M76.1,26.4v100.7H44.5V26.2H20.2V3.6h80v22.8H76.1z"/>
<path d="M113,127.1V3.6h69.5v22.6H145v27.3h32.4v22.6h-32.2v28.2h38.4v22.8H113z"/>
<path d="M235.6,129.3c-26.7,0-40.7-11.9-40.7-34.6c0-4.5,0.2-6.6,1.1-11.5h26.4l-0.2,2.6c-0.2,2.3-0.2,4.5-0.2,6.6
c0,10.7,4.7,16.4,13.7,16.4c8.1,0,12.8-5.1,12.8-13.7c0-7.5-3.6-13-9.8-15.6l-12.4-4.9C204.5,65.9,197,56.3,197,37.7
C197,13.4,210.9,1,238.6,1c24.5,0,36.7,10,36.7,29.9c0,4.3-0.4,6.4-1.3,11.9h-26.5c0.6-4.5,0.8-6.2,0.8-8.8
c0-8.5-3.6-12.8-10.2-12.8c-6.4,0-10.9,4.9-10.9,11.9c0,7.2,3.6,10.9,14.7,15.4l15.8,6.2c15.8,6.4,23.7,18.1,23.7,35.4
C281.3,115.4,265.1,129.3,235.6,129.3z"/>
<path d="M345.5,26.4v100.7h-31.6V26.2h-24.3V3.6h80v22.8H345.5z"/>
</g>
</svg>
</div>
</div>
I'm not sure if this is the desired effect you wanted. But I added a line in your click handler that stops current animations.
// LINKs TO VELOCITY
// https://rawgit.com/julianshapiro/velocity/master/velocity.min.js
// https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.0/velocity.min.js
var Rightscale = {
chooser: 0,
svg: $('#right').find('svg'),
init: function() {
this.bindEvents();
},
bindEvents: function() {
Rightscale.svg.on("click", function() {
Rightscale.svg.velocity("stop", true);
console.log(Rightscale.chooser)
if(Rightscale.chooser === 0) {
Rightscale.chooser = 1;
Rightscale.horizontal();
} else {
Rightscale.chooser = 0;
Rightscale.vertical();
}
})
},
horizontal: function() {
Rightscale.svg.velocity({
scaleX: 2.5,
scaleY: 1
}, {
duration: 3000,
loop: true,
easing: "linear"
})
},
vertical: function() {
Rightscale.svg.velocity({
scaleY: 8,
scaleX: 2.5
}, {
duration: 3000,
loop: true,
easing: "linear"
})
},
}
$(document).ready(function() {
Rightscale.init();
});
#right {
width: 100vw;
height: 100vh;
background-color: blue;
display: flex;
justify-content: center;
align-items: center;
}
.scale {
width: 40%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.0/velocity.min.js"></script>
<script src="https://rawgit.com/julianshapiro/velocity/master/velocity.min.js"></script>
<div id="right">
<div class="scale">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 392 132" style="enable-background:new 0 0 392 132;" xml:space="preserve">
<g>
<path d="M76.1,26.4v100.7H44.5V26.2H20.2V3.6h80v22.8H76.1z"/>
<path d="M113,127.1V3.6h69.5v22.6H145v27.3h32.4v22.6h-32.2v28.2h38.4v22.8H113z"/>
<path d="M235.6,129.3c-26.7,0-40.7-11.9-40.7-34.6c0-4.5,0.2-6.6,1.1-11.5h26.4l-0.2,2.6c-0.2,2.3-0.2,4.5-0.2,6.6
c0,10.7,4.7,16.4,13.7,16.4c8.1,0,12.8-5.1,12.8-13.7c0-7.5-3.6-13-9.8-15.6l-12.4-4.9C204.5,65.9,197,56.3,197,37.7
C197,13.4,210.9,1,238.6,1c24.5,0,36.7,10,36.7,29.9c0,4.3-0.4,6.4-1.3,11.9h-26.5c0.6-4.5,0.8-6.2,0.8-8.8
c0-8.5-3.6-12.8-10.2-12.8c-6.4,0-10.9,4.9-10.9,11.9c0,7.2,3.6,10.9,14.7,15.4l15.8,6.2c15.8,6.4,23.7,18.1,23.7,35.4
C281.3,115.4,265.1,129.3,235.6,129.3z"/>
<path d="M345.5,26.4v100.7h-31.6V26.2h-24.3V3.6h80v22.8H345.5z"/>
</g>
</svg>
</div>
</div>