CSS3 - Animate SVG if visible in viewport (Page Scroll) - javascript

I have been pulling my hair out trying to get this to work. Such a challenge.
The goal is to start the css animation when the object is visible, when it scrolls into view, and not before.
Using Javascript from here.
To make things easy, I have a code pen: https://codepen.io/studiotwofold/pen/dyYJWrV
Any ideas on how to fix this?
HTML:
<div class="icon-container" style="width:100px;">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 44 44" style="enable-background:new 0 0 44 44;" xml:space="preserve">
<defs>
<linearGradient id="icon-gradient" gradientUnits="userSpaceOnUse">
<stop offset="0%" style="stop-color:#E21C79"/>
<stop offset="100%" style="stop-color:#FC4C02"/>
</linearGradient>
</defs>
<g class="stf-icon">
<line x1="26" y1="29" x2="32" y2="29"/>
<path d="M29,25h-3l-0.2-0.5c-0.5-1.6-1.5-3.1-2.7-4.4l0,0c-3.3-3.3-3.2-8.8,0.3-12l0,0c3.2-2.9,8-2.9,11.2,0l0,0
c3.5,3.2,3.6,8.6,0.3,12l0,0c-1.2,1.2-2.2,2.7-2.7,4.4L32,25"/>
<line x1="29" y1="3" x2="29" y2="1"/>
<line x1="19.8" y1="7.3" x2="18.3" y2="6"/>
<line x1="23.9" y1="4.1" x2="23.1" y2="2.3"/>
<line x1="40.4" y1="11.3" x2="42.3" y2="10.7"/>
<line x1="38.1" y1="7" x2="39.6" y2="5.7"/>
<line x1="34" y1="3.8" x2="34.8" y2="2"/>
<path d="M17,13H3c-1.1,0-2,0.9-2,2v22c0,1.1,0.9,2,2,2h18l7,4v-4h7c1.1,0,2-0.9,2-2V24"/>
<line x1="5" y1="21" x2="11" y2="21"/>
<line x1="14" y1="21" x2="18" y2="21"/>
<line x1="5" y1="25" x2="13" y2="25"/>
<line x1="16" y1="25" x2="21" y2="25"/>
<line x1="5" y1="29" x2="8" y2="29"/>
<line x1="11" y1="29" x2="23" y2="29"/>
<line x1="5" y1="33" x2="13" y2="33"/>
<line x1="16" y1="33" x2="21" y2="33"/>
<polyline points="30.2,10 27,16 31,15 28.6,21 "/>
</g>
</svg>
</div>
CSS:
.stf-icon{fill:none;stroke: url(#icon-gradient);stroke-width:1;stroke-linecap:round;stroke-miterlimit:10;}
.animated-icon {
stroke-dasharray: 110;
stroke-dashoffset: 110;
animation: icon-animation 6s linear forwards;
animation-fill-mode: forwards;
}
#keyframes icon-animation {
from {stroke-dashoffset: 110;}
to {stroke-dashoffset: 0;}
}
Jquery:
var $fade = $(".stf-icon"); //Calling the class in HTML
$(window).scroll(function () { //Using the scroll global variable
$fade.each(function () {
fadeMiddle = $(this).offset().top + (0.4 *$(this).height());
windowBottom = $(window).scrollTop() + $(window).height();
if (fadeMiddle < windowBottom) {
$(this).addClass("animated-icon"); //add the animated icon class
}
});
});
/* On Load: Trigger Scroll Once*/
$(window).scroll();
To make things easy, I have a code pen: https://codepen.io/studiotwofold/pen/dyYJWrV
EDIT
Can this be done with straight javascript?
var wrapper = document.querySelector('.icon-container');
window.onscroll = function (event) {
if (wrapper.getBoundingClientRect().top < 0) {
wrapper.className = "icon-container animated-icon";
window.onscroll = null;
}
}

Related

Formula to calculate gauge value to draw path for gauge svg

This is my gauge, but I don't know a formula to render value of this gauge. Somebody can help me with this?
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="145" viewBox="0 0 200 145">
<defs>
<linearGradient id="b" x1="5.165%" y1="76.151%" y2="75.039%">
<stop offset="0%" stop-color="#E9F1FF"/>
<stop offset="100%" stop-color="#DBE7FF"/>
</linearGradient>
<linearGradient id="c" x1="63.192%" x2="36.891%" y1="13.157%" y2="100%">
<stop offset="0%" stop-color="#FF8600"/>
<stop offset="100%" stop-color="#FFC86A"/>
</linearGradient>
<path id="a" d="M100 0c55.228 0 100 44.772 100 100 0 15.954-3.736 31.036-10.382 44.418l-17.912-8.906c5.31-10.7 8.294-22.757 8.294-35.512 0-44.183-35.817-80-80-80s-80 35.817-80 80c0 12.843 3.027 24.98 8.405 35.735l-17.912 8.906C3.778 131.204 0 116.043 0 100 0 44.772 44.772 0 100 0z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<mask id="c" fill="#fff">
<use xlink:href="#a"/>
</mask>
<use fill="url(#b)" xlink:href="#a"/>
<g stroke="#FFF" stroke-width="5" mask="url(#c)" opacity=".3">
<path d="M99.5 97V0M100.252 97.061L110.392.593M100.16 97.06l21.821-94.513M100.885 97.276l31.58-91.715M100.8 97.241l42.523-87.183M101.465 97.6l51.402-82.26M101.399 97.536l61.044-75.383M101.976 98.025l68.589-68.59M102.463 98.6l75.383-61.043M102.4 98.536l82.26-51.403M102.759 99.199l87.183-42.522M102.725 99.115l91.715-31.58M102.94 99.839l94.513-21.82M102.939 99.747l96.468-10.139M103 100.5h97M102.939 101.253l96.469 10.139M102.94 101.16l94.513 21.821M102.724 101.884l91.715 31.58M102.759 101.8l87.183 42.523M102.399 102.465l82.26 51.402M102.464 102.4l75.383 61.044M101.974 102.975l68.59 68.59M101.4 103.464l61.044 75.383M101.464 103.4l51.402 82.26M100.801 103.76l42.522 87.182M100.884 103.724l31.58 91.716M100.161 103.94l21.82 94.513M100.253 103.939l10.139 96.468M99.5 104v97M98.747 103.939l-10.139 96.468M98.839 103.94l-21.82 94.513M98.116 103.724l-31.58 91.716M98.199 103.76l-42.522 87.182M97.536 103.4l-51.402 82.26M97.6 103.464l-61.044 75.383M97.026 102.975l-68.59 68.59M96.536 102.4l-75.383 61.044M96.601 102.465l-82.26 51.402M96.241 101.8L9.058 144.324M96.276 101.884l-91.715 31.58M96.06 101.16L1.548 122.982M96.061 101.253L-.408 111.392M96 100.5H-1M96.061 99.747L-.407 89.608M96.06 99.839L1.548 78.019M96.275 99.115L4.56 67.535M96.241 99.199L9.058 56.677M96.6 98.536L14.34 47.133M96.537 98.6L21.154 37.558M97.024 98.025l-68.589-68.59M97.601 97.536L36.557 22.153M97.535 97.6L46.133 15.34M98.2 97.241L55.676 10.058M98.115 97.276L66.535 5.56M98.84 97.06L77.018 2.548M98.748 97.061L88.608.593"/>
</g>
</g>
<path fill="none" fill-rule="evenodd" stroke="url(#c)" stroke-width="20" d="M72.705 14.214C36.343 25.773 10 59.81 10 100c0 14.45 3.405 28.105 9.457 40.205"/>
</svg>
As #enxaneta pointed out, you should better use strokes.
To display percentage based value segments on your gauge you will foremost need these attributes:
stroke-dasharray: defines the length of segement
stroke-dashoffset: gives you the ability to move your segment
pathlength: changes the computation values ration applied on the stroke-dash attributes
pathlength="100" show 25/100 – useful, if you're working with percentages (e.g. retrieved by some api)
pathlength="100"
stroke-dashoffset="0"
stroke-dasharray="25 100"
pathlength="12" show 3/12 – really handy if you get 'stepped' integer values
pathlength="12"
stroke-dashoffset="0"
stroke-dasharray="3 12"
MDN: pathLength
Here is a rebuild of you gauge using strokes:
svg{
border:1px solid #ccc;
width:33%
}
.gauge-segment{
transition: 0.3s;
}
svg:hover .gauge-segment{
stroke-dashoffset:-33;
stroke-dasharray: 66 100;
}
<p>Hover will change the gauge segment</p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 120">
<defs>
<linearGradient id="gradientBackground" gradientTransform="rotate(30)">
<stop offset="0%" stop-color="#E9F1FF"/>
<stop offset="100%" stop-color="#DBE7FF"/>
</linearGradient>
<linearGradient id="gradientSegment" x1="63.192%" x2="36.891%" y1="13.157%" y2="100%">
<stop offset="0%" stop-color="#FF8600"/>
<stop offset="100%" stop-color="#FFC86A"/>
</linearGradient>
</defs>
<!-- gauge path -->
<symbol id="stroke">
<path pathlength="100" fill="none" stroke-width="10" d="M55.6,103C52,96.1,50,88.3,50,80
c0-27.6,22.4-50,50-50s50,22.4,50,50c0,8.3-2,16.1-5.6,23"/>
</symbol>
<!-- gauge background -->
<g id="gaugeBackground" >
<use id="gaugeBackgroundColor" href="#stroke" stroke="url(#gradientBackground)"></use>
<use id="gaugeBackgroundDash" href="#stroke" stroke="#E9F1FF" stroke-dashoffset="0" stroke-dasharray="1 1" ></use>
</g>
<!-- percentages -->
<g id="gaugeSegments" >
<use id="segment01" class="gauge-segment" href="#stroke" filter="" stroke="url(#gradientSegment)" stroke-dashoffset="0" stroke-dasharray="33 100"></use>
</g>
</svg>

Smooth animate for svg fill

I have an SVG thermometer and I'm trying to animate filling it smoothly for each class.
I did thermometer with toggle classes. I'm trying to animate smoothly up-down, and down-up animation for each class I have.
https://lore1ei.github.io/ -thermometer.
var firstStop = document.getElementById('F1gst1');
percentage = '0%';
firstStop.setAttribute('offset', percentage);
var CountAllCheckboxes = $('.analysis-li').length;
var CountChecked = 0;
$(".analysis-li").click(function() {
$(this).toggleClass("check");
CountChecked = $('.analysis-li.check').length;
percentage = ((CountChecked / CountAllCheckboxes) * 100) + '%';
firstStop.setAttribute('offset', percentage);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<svg class="thermometr" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44.3 333.8">
<linearGradient y2="0%" x2="0%" y1="100%" x1="0%" id="F1g">
<stop stop-color="#00FF00" offset="0%" id="F1gst1"/>
<stop stop-color="#FFFFFF" offset="0%" id="F1gst2"/>
</linearGradient>
<path fill="url(#F1g)" class="st0" d="M30.5 297.5V4.6c0-2.5-2.1-4.6-4.6-4.6-2.5 0-4.6 2.1-4.6 4.6v292.9c-7.9 2-13.8 9.2-13.8 17.8 0 10.2 8.2 18.4 18.4 18.4s18.4-8.2 18.4-18.4c0-8.5-5.9-15.7-13.8-17.8"/>
<path fill="url(#F1g)" class="st0" d="M9 290.2h7.5v.5H9zM9 284.3h7.5v.6H9zM9 278.4h7.5v.5H9zM9 272.5h7.5v.6H9zM0 266.6h16.5v.6H0zM9 260.7h7.5v.5H9zM9 254.8h7.5v.6H9zM9 248.9h7.5v.5H9zM9 243h7.5v.6H9zM0 237.1h16.5v.6H0zM9 231.3h7.5v.5H9zM9 225.4h7.5v.6H9zM9 219.5h7.5v.6H9zM9 213.6h7.5v.6H9zM0 207.7h16.5v.6H0zM9 201.8h7.5v.6H9zM9 195.9h7.5v.6H9zM9 190h7.5v.6H9zM9 184.1h7.5v.5H9zM0 178.2h16.5v.6H0zM9 172.3h7.5v.6H9zM9 166.4h7.5v.5H9zM9 160.5h7.5v.6H9zM9 154.7h7.5v.6H9zM0 148.8h16.5v.6H0zM9 142.9h7.5v.6H9zM9 137h7.5v.5H9zM9 131.1h7.5v.5H9zM9 125.2h7.5v.6H9zM0 119.3h16.5v.5H0zM9 113.4h7.5v.6H9zM9 107.5h7.5v.6H9zM9 101.6h7.5v.5H9zM9 95.7h7.5v.6H9zM0 89.8h16.5v.6H0zM9 83.9h7.5v.6H9zM9 78.1h7.5v.6H9zM9 72.2h7.5v.6H9zM9 66.3h7.5v.6H9zM0 60.4h16.5v.6H0zM9 54.8h7.5v.6H9zM9 48.9h7.5v.6H9zM9 43h7.5v.5H9zM9 37.1h7.5v.6H9zM0 31.2h16.5v.5H0zM9 26h7.5v.6H9zM9 20.1h7.5v.5H9zM9 14.2h7.5v.6H9zM9 8.3h7.5v.6H9zM0 2.4h16.5V3H0z"/>
</svg>
One solution is to animate it using javascript only instead of using css and/or svg-props. For example:
function anim(fromPercentage) {
var topLimit = 25;
fromPercentage += 1;
if(fromPercentage < topLimit) {
$('#F1gst1').attr('offset', fromPercentage + '%');
setTimeout( function() {
anim(fromPercentage);
}, 35);
}
};
/*
* Animates the bar from 10 to 25 percentage.
* Change the topLimit inside the anim-function to the current desired top level.
* Also tweek the timeout to get smoother transition.
*/
anim(10);
#Thomas But i need this for ((CountChecked / CountAllCheckboxes) * 100) + '%'. It will be so many mask and functions.
it's one mask and one function, here a quick snippet:
const scale = Array.from(Array(101), (_,i,a) => 90*(100-i)/100);
document.querySelector("svg #scale").setAttributeNS(null, "d", scale.filter((v,i) => i && i<100 && i%10 === 0).map(v => `M20,${v},25,${v}`).join(""));
setInterval(function(){
let percent = Math.floor(Math.random() * 100);
document.querySelector("div").textContent = percent + "%";
document.querySelector("svg #red").style.setProperty("transform", `translateY(${scale[percent]}px)`)
}, 1000);
svg {
max-width: 100px;
max-height: 200px;
}
svg #red {
transition: transform 300ms;
}
<div></div>
<svg viewbox="0,0,50,100">
<mask id="myMask">
<line x1=25 y1=5 x2=25 y2=80 stroke="white" stroke-width="10" stroke-linecap="round" />
<circle cx=25 cy=90 r=10 fill="white" />
</mask>
<g mask="url(#myMask)">
<rect x=0 y=0 width=50 height=100 fill="#AAA" />
<rect id="red" x=0 y=0 width=50 height=100 fill="red" />
<path id="scale" stroke="#888" stroke-width="0.5" d=""/>
</g>
</svg>
<linearGradient y2="0%" x2="0%" y1="100%" x1="0%" id="F1g">
<stop stop-color="#00FF00" offset="0%" id="F1gst1">
<animate id="g0" attributeName="offset" to="5%" dur="0.5s" begin="indefinite" />
<animate id="g1" attributeName="offset" to="19.285714285714285%" dur="0.5s" begin="indefinite" />
<animate id="g2" attributeName="offset" to="33.57142857142857%" dur="0.5s" begin="indefinite" />
<animate id="g3" attributeName="offset" to="47.857142857142854%" dur="0.5s" begin="indefinite" />
<animate id="g4" attributeName="offset" to="62.14285714285714%" dur="0.5s" begin="indefinite" />
<animate id="g5" attributeName="offset" to="76.42857142857143%" dur="0.5s" begin="indefinite" />
<animate id="g6" attributeName="offset" to="90.71428571428571%" dur="0.5s" begin="indefinite" />
<animate id="g7" attributeName="offset" to="105%" dur="0.5s" begin="indefinite" />
</stop>
<stop stop-color="#FFFFFF" offset="0%" id="F1gst2"/></linearGradient>
<path fill="url(#F1g)" class="st0" d="M30.5 297.5V4.6c0-2.5-2.1-4.6-4.6-4.6-2.5 0-4.6 2.1-4.6 4.6v292.9c-7.9 2-13.8 9.2-13.8 17.8 0 10.2 8.2 18.4 18.4 18.4s18.4-8.2 18.4-18.4c0-8.5-5.9-15.7-13.8-17.8"/><path fill="url(#F1g)" class="st0" d="M9 290.2h7.5v.5H9zM9 284.3h7.5v.6H9zM9 278.4h7.5v.5H9zM9 272.5h7.5v.6H9zM0 266.6h16.5v.6H0zM9 260.7h7.5v.5H9zM9 254.8h7.5v.6H9zM9 248.9h7.5v.5H9zM9 243h7.5v.6H9zM0 237.1h16.5v.6H0zM9 231.3h7.5v.5H9zM9 225.4h7.5v.6H9zM9 219.5h7.5v.6H9zM9 213.6h7.5v.6H9zM0 207.7h16.5v.6H0zM9 201.8h7.5v.6H9zM9 195.9h7.5v.6H9zM9 190h7.5v.6H9zM9 184.1h7.5v.5H9zM0 178.2h16.5v.6H0zM9 172.3h7.5v.6H9zM9 166.4h7.5v.5H9zM9 160.5h7.5v.6H9zM9 154.7h7.5v.6H9zM0 148.8h16.5v.6H0zM9 142.9h7.5v.6H9zM9 137h7.5v.5H9zM9 131.1h7.5v.5H9zM9 125.2h7.5v.6H9zM0 119.3h16.5v.5H0zM9 113.4h7.5v.6H9zM9 107.5h7.5v.6H9zM9 101.6h7.5v.5H9zM9 95.7h7.5v.6H9zM0 89.8h16.5v.6H0zM9 83.9h7.5v.6H9zM9 78.1h7.5v.6H9zM9 72.2h7.5v.6H9zM9 66.3h7.5v.6H9zM0 60.4h16.5v.6H0zM9 54.8h7.5v.6H9zM9 48.9h7.5v.6H9zM9 43h7.5v.5H9zM9 37.1h7.5v.6H9zM0 31.2h16.5v.5H0zM9 26h7.5v.6H9zM9 20.1h7.5v.5H9zM9 14.2h7.5v.6H9zM9 8.3h7.5v.6H9zM0 2.4h16.5V3H0z"/></svg>
This is solution from my friend.
var firstStop = document.getElementById('F1gst1');
percentage = '5%'; firstStop.setAttribute('offset',percentage);
var CountAllCheckboxes = $('.analysis-li').length;
var CountChecked = 0;
$(".analysis-li").click(function(){
$(this).toggleClass("check");
CountChecked = $('.analysis-li.check').length;
percentage = ((CountChecked / CountAllCheckboxes) * 100 + 5)+'%';
$('#g'+CountChecked)[0].beginElement();
setTimeout("firstStop.setAttribute('offset',percentage)", 450);
});

SVG button without CSS doesn't work properly

I'm making a svg button with animated gradient in mouseover event, without CSS.
The button listen to mouseout and mouseover events, without any problem, changing the radialGradient attribute between id="rellenoZoomHover" and id="rellenoZoom", depending on the listener answer.
The button has an tag in it radialGradient declaration tag, that repeats only one time.
The problem is that the script only execute the first time: second time, ignores animate.
Whath I am doing wrong?. Thanks in advance
<?xml version='1.0' encoding='UTF-8'?>
<svg version='1.1' id='project' xmlns:svg='http://www.w3.org/2000/svg'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'
onload='init(evt)'>
<script type='text/ecmascript'>
function init(evt) {
cmdButtonZoomPrevio = document.getElementById('cmdZoomPrevio');
cmdButtonZoomPrevio.addEventListener('mouseover', manejadorDeMouseHoverEnBotones);
cmdButtonZoomPrevio.addEventListener('mouseout', manejadorDeMouseOutEnBotones);
}
<![CDATA[
function manejadorDeMouseHoverEnBotones(evt) {
var pathVolatil = cmdButtonZoomPrevio.childNodes[1];
pathVolatil.setAttribute('fill','url(#rellenoZoomHover)');
}
function manejadorDeMouseOutEnBotones(evt) {
var pathVolatil = cmdButtonZoomPrevio.childNodes[1];
pathVolatil.setAttribute('fill','url(#rellenoZoom)');
}
//El botón cmdZoomPrevio;
var cmdButtonZoomPrevio;
]]>
</script>
<g id="cmdZoomPrevio" class="boton" toggleButton="false" triStateButton="false">
<path id="bordeZoomSE" fill="url(#rellenoZoom)" stroke="#000000" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M64.925,85.116c3.529,0,7.005-0.938,10.042-2.69c9.609-5.554,12.924-17.858,7.354-27.479l34.848-20.112
c16.633,28.863,6.753,65.771-22.063,82.438c-9.188,5.294-19.581,8.093-30.167,8.093L64.925,85.116L64.925,85.116z"/>
<g id="dibujocmdZoomSE">
<rect x="105.766" y="97.561" transform="matrix(0.8707 -0.4918 0.4918 0.8707 -34.1811 65.8925)" fill="#333333" width="4.92" height="0.784"/>
<polygon fill="#663300" points="104.234,87.553 109.439,96.827 109.439,96.897 106.586,98.467 106.518,98.467 101.313,89.191
101.313,89.118 104.165,87.553 "/>
<rect x="101.312" y="86.085" transform="matrix(0.8715 -0.4904 0.4904 0.8715 -29.6865 61.2979)" width="1.641" height="2.429"/>
<polygon fill="#006633" points="98.104,99.394 88.091,93.723 88.091,93.651 98.068,87.73 98.139,87.765 98.139,99.358 "/>
<path fill="none" stroke="#006633" stroke-width="2.15" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3" d="
M98.104,93.543h0.854c3.382,0,6.298-0.593,8.771-1.783c2.373-1.182,3.586-2.61,3.643-4.281c-0.057-1.665-1.262-3.063-3.643-4.203
c-2.474-1.23-5.391-1.854-8.771-1.854c-3.467,0-6.413,0.616-8.835,1.854c-0.139,0.047-0.288,0.117-0.432,0.213"/>
<path fill="#CCFFFF" d="M97.752,86.978c-2.122-0.014-3.947-0.788-5.49-2.313c-1.463-1.474-2.184-3.263-2.174-5.354
c-0.01-2.103,0.714-3.925,2.174-5.457c1.531-1.458,3.348-2.183,5.454-2.179c2.113-0.006,3.911,0.717,5.38,2.179
c1.535,1.527,2.313,3.354,2.314,5.457c-0.006,2.105-0.779,3.892-2.314,5.354C101.635,86.195,99.85,86.966,97.752,86.978z"/>
<path fill="none" stroke="#0000FF" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3" d="
M97.752,86.978c-2.096,0-3.9-0.761-5.42-2.288c-1.475-1.474-2.219-3.229-2.219-5.271c0-2.09,0.744-3.9,2.219-5.421
c1.52-1.479,3.324-2.226,5.42-2.226c2.089,0,3.873,0.738,5.344,2.226c1.522,1.475,2.285,3.271,2.285,5.421
c0,2.048-0.758,3.807-2.285,5.271C101.622,86.217,99.841,86.978,97.752,86.978z"/>
</g>
<defs>
<radialGradient id="rellenoZoomHover" cx="65" cy="65" r="65" gradientUnits="userSpaceOnUse">
<stop offset="0.5" style="stop-color:#FFFFFF">
<animate attributeName="stop-color" values="#FFFFFF;#81BEF7" dur="2s" repeatCount="1"/>
</stop>
<stop offset="1" style="stop-color:#81BEF7"/>
</radialGradient>
<radialGradient id="rellenoZoom" cx="65" cy="65" r="65" gradientUnits="userSpaceOnUse">
<stop offset="0.5" style="stop-color:#FFFFFF" />
<stop offset="1" style="stop-color:#A4A4A4"/>
</radialGradient>
</defs>
</g>
</svg>
The document has a timeline that begins at 0 and stays at 0 unless some animation runs. As an animation runs the timeline advances, in this case to 2 seconds as we have 2 seconds of animation.
The next time we hover the animation timeline is at 2 seconds, so the animation does not trigger again as the animation's start time has passed.
We could either
manually trigger the animation with javascript by calling beginElement(), this would affect just one animation
force the document timeline back to 0 this would affect all animations.
The code below demonstrates both (2. is commented out as we only need one technique)
<?xml version='1.0' encoding='UTF-8'?>
<svg version='1.1' id='project' xmlns:svg='http://www.w3.org/2000/svg'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'
onload='init(evt)'>
<script type='text/ecmascript'>
function init(evt) {
cmdButtonZoomPrevio = document.getElementById('cmdZoomPrevio');
cmdButtonZoomPrevio.addEventListener('mouseover', manejadorDeMouseHoverEnBotones);
cmdButtonZoomPrevio.addEventListener('mouseout', manejadorDeMouseOutEnBotones);
}
<![CDATA[
function manejadorDeMouseHoverEnBotones(evt) {
var pathVolatil = cmdButtonZoomPrevio.childNodes[1];
pathVolatil.setAttribute('fill','url(#rellenoZoomHover)');
document.getElementById('rellenoZoomHoverAnimate').beginElement();
//document.getElementById('project').setCurrentTime(0);
}
function manejadorDeMouseOutEnBotones(evt) {
var pathVolatil = cmdButtonZoomPrevio.childNodes[1];
pathVolatil.setAttribute('fill','url(#rellenoZoom)');
}
//El botón cmdZoomPrevio;
var cmdButtonZoomPrevio;
]]>
</script>
<g id="cmdZoomPrevio" class="boton" toggleButton="false" triStateButton="false">
<path id="bordeZoomSE" fill="url(#rellenoZoom)" stroke="#000000" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M64.925,85.116c3.529,0,7.005-0.938,10.042-2.69c9.609-5.554,12.924-17.858,7.354-27.479l34.848-20.112
c16.633,28.863,6.753,65.771-22.063,82.438c-9.188,5.294-19.581,8.093-30.167,8.093L64.925,85.116L64.925,85.116z"/>
<g id="dibujocmdZoomSE">
<rect x="105.766" y="97.561" transform="matrix(0.8707 -0.4918 0.4918 0.8707 -34.1811 65.8925)" fill="#333333" width="4.92" height="0.784"/>
<polygon fill="#663300" points="104.234,87.553 109.439,96.827 109.439,96.897 106.586,98.467 106.518,98.467 101.313,89.191
101.313,89.118 104.165,87.553 "/>
<rect x="101.312" y="86.085" transform="matrix(0.8715 -0.4904 0.4904 0.8715 -29.6865 61.2979)" width="1.641" height="2.429"/>
<polygon fill="#006633" points="98.104,99.394 88.091,93.723 88.091,93.651 98.068,87.73 98.139,87.765 98.139,99.358 "/>
<path fill="none" stroke="#006633" stroke-width="2.15" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3" d="
M98.104,93.543h0.854c3.382,0,6.298-0.593,8.771-1.783c2.373-1.182,3.586-2.61,3.643-4.281c-0.057-1.665-1.262-3.063-3.643-4.203
c-2.474-1.23-5.391-1.854-8.771-1.854c-3.467,0-6.413,0.616-8.835,1.854c-0.139,0.047-0.288,0.117-0.432,0.213"/>
<path fill="#CCFFFF" d="M97.752,86.978c-2.122-0.014-3.947-0.788-5.49-2.313c-1.463-1.474-2.184-3.263-2.174-5.354
c-0.01-2.103,0.714-3.925,2.174-5.457c1.531-1.458,3.348-2.183,5.454-2.179c2.113-0.006,3.911,0.717,5.38,2.179
c1.535,1.527,2.313,3.354,2.314,5.457c-0.006,2.105-0.779,3.892-2.314,5.354C101.635,86.195,99.85,86.966,97.752,86.978z"/>
<path fill="none" stroke="#0000FF" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="3" d="
M97.752,86.978c-2.096,0-3.9-0.761-5.42-2.288c-1.475-1.474-2.219-3.229-2.219-5.271c0-2.09,0.744-3.9,2.219-5.421
c1.52-1.479,3.324-2.226,5.42-2.226c2.089,0,3.873,0.738,5.344,2.226c1.522,1.475,2.285,3.271,2.285,5.421
c0,2.048-0.758,3.807-2.285,5.271C101.622,86.217,99.841,86.978,97.752,86.978z"/>
</g>
<defs>
<radialGradient id="rellenoZoomHover" cx="65" cy="65" r="65" gradientUnits="userSpaceOnUse">
<stop offset="0.5" style="stop-color:#FFFFFF">
<animate id="rellenoZoomHoverAnimate" attributeName="stop-color" values="#FFFFFF;#81BEF7" dur="2s" repeatCount="1"/>
</stop>
<stop offset="1" style="stop-color:#81BEF7"/>
</radialGradient>
<radialGradient id="rellenoZoom" cx="65" cy="65" r="65" gradientUnits="userSpaceOnUse">
<stop offset="0.5" style="stop-color:#FFFFFF" />
<stop offset="1" style="stop-color:#A4A4A4"/>
</radialGradient>
</defs>
</g>
</svg>

SVG lines draw on scroll with jQuery

How i can create draw animation with css for SVG "line" element. I want to draw the line on scroll, with smooth effect. Some one have any ideas? I try to search this but i cant find this effect with line element.
here is my html and svg:
<div class="box">
<svg width="100%" height="100%">
<line x1="0" y1="0" x2="0" y2="100%" stroke="gray" stroke-width="2" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="gray" stroke-width="2" />
</svg>
</div>
<div class="box2">
<svg width="100%" height="100%">
<line x1="100%" y1="100%" x2="100%" y2="0" stroke="gray" stroke-width="2" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="gray" stroke-width="2" />
</svg>
</div>
<div class="box">
<svg width="100%" height="100%">
<line x1="0" y1="0" x2="0" y2="100%" stroke="gray" stroke-width="2" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="gray" stroke-width="2" />
</svg>
</div>
<div class="box2">
<svg width="100%" height="100%">
<line x1="100%" y1="100%" x2="100%" y2="0" stroke="gray" stroke-width="2" />
<line x1="0" y1="100%" x2="100%" y2="100%" stroke="gray" stroke-width="2" />
</svg>
</div>
and css:
.box{
width: 100%;
height: 300px;
position: relative;
}
.box2{
width: 100%;
height: 300px;
position: relative;
}
Demo
I just know that you can run through a path with an custom javascript, maybe you can use that for a line aswell :)
NEW EDIT FOR SCROLLING FEATURE
// Get a reference to the <path>
var path = document.querySelector('#star-path');
// Get length of path... ~577px in this case
var pathLength = path.getTotalLength();
// Make very long dashes (the length of the path itself)
path.style.strokeDasharray = pathLength + ' ' + pathLength;
// Offset the dashes so the it appears hidden entirely
path.style.strokeDashoffset = pathLength;
// Jake Archibald says so
// https://jakearchibald.com/2013/animated-line-drawing-svg/
path.getBoundingClientRect();
// When the page scrolls...
window.addEventListener("scroll", function(e) {
// What % down is it?
// https://stackoverflow.com/questions/2387136/cross-browser-method-to-determine-vertical-scroll-percentage-in-javascript/2387222#2387222
// Had to try three or four differnet methods here. Kind of a cross-browser nightmare.
var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
// Length to offset the dashes
var drawLength = pathLength * scrollPercentage;
// Draw in reverse
path.style.strokeDashoffset = pathLength - drawLength;
// When complete, remove the dash array, otherwise shape isn't quite sharp
// Accounts for fuzzy math
if (scrollPercentage >= 0.99) {
path.style.strokeDasharray = "none";
} else {
path.style.strokeDasharray = pathLength + ' ' + pathLength;
}
});
body {
/* feel free to change height */
height: 5000px;
}
#star-svg {
position: fixed;
top: 50%;
left: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.6 107.6" id="star-svg">
<path fill="none" stroke="black" stroke-width="2" id="star-path" d="M43.7,65.8L19.9,83.3c-2.9,1.9-5.1,3.2-7.9,3.2c-5.7,0-10.5-5.1-10.5-10.8
c0-4.8,3.8-8.2,7.3-9.8l27.9-12L8.8,41.4c-3.8-1.6-7.3-5.1-7.3-9.8c0-5.7,5.1-10.5,10.8-10.5c2.9,0,4.8,1,7.6,3.2l23.8,17.4
l-3.2-28.2c-1-6.7,3.5-12,9.8-12c6.3,0,10.8,5.1,9.8,11.7L57,41.8l23.8-17.4c2.9-2.2,5.1-3.2,7.9-3.2c5.7,0,10.5,4.8,10.5,10.5
c0,5.1-3.5,8.2-7.3,9.8L63.9,53.8l27.9,12c3.8,1.6,7.3,5.1,7.3,10.1c0,5.7-5.1,10.5-10.8,10.5c-2.5,0-4.8-1.3-7.6-3.2L57,65.8
l3.2,28.2c1,6.7-3.5,12-9.8,12c-6.3,0-10.8-5.1-9.8-11.7L43.7,65.8z"/>
</svg>
Source: https://css-tricks.com/scroll-drawing/
You need to export the svg in a path. and then you can add scroll animation depending on the viewport. Here is the testing server running your instance.demo project

How make svg path fill as progressing animation?

Is there any solution to show the battery frame red:fill as progress filling without covering the rect ?
$(document).ready( function() {
$("#iambutton").click(function () {
console.log("hi");
$(".mysvg").addClass( 'me' );
});
});
.mysvg {
text-align: center;
}
.mysvg svg {
margin: auto;
}
.mysvg svg #loading-frame {
fill: red;
-webkit-transform: translateX(-100%);
-ms-transform: translateX(-100%);
transform: translateX(-100%);
-webkit-transition: all 10s;
transition: all 10s;
}
.mysvg.me svg #loading-frame {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="iambutton">Clik me to see progress</button>
<section class="mysvg">
<svg width="110px" height="88px" viewBox="0 0 110 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mysvg">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#EAEAEA">
<rect id="Brick-4" x="77.5" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-3" x="56" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-2" x="34.5" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-1" x="13" y="10" width="13.5" height="68" rx="3"></rect>
<path id="Rectangle-7" d="M104,30.2724875 C104.164709,30.2576038 104.331485,30.25 104.5,30.25 C107.537566,30.25 110,32.7220822 110,35.7458573 L110,53.1708094 C110,56.2060875 107.531385,58.6666667 104.5,58.6666667 C104.331455,58.6666667 104.164681,58.6590557 104,58.6441617 L104,82.0033234 C104,85.3151964 101.311488,88 97.9970362,88 L6.0029638,88 C2.68761844,88 0,85.3182852 0,82.0033234 L0,5.99667663 C0,2.68480358 2.68851188,0 6.0029638,0 L97.9970362,0 C101.312382,0 104,2.68171476 104,5.99667663 L104,30.2724875 L104,30.2724875 Z M5,10.991014 C5,7.68226832 7.68678744,5 11.0051618,5 L92.9948382,5 C96.3113975,5 99,7.68493655 99,10.991014 L99,77.008986 C99,80.3177317 96.3132126,83 92.9948382,83 L11.0051618,83 C7.68860254,83 5,80.3150634 5,77.008986 L5,10.991014 Z"></path>
<path d="M104,30.2724875 C104.164709,30.2576038 104.331485,30.25 104.5,30.25 C107.537566,30.25 110,32.7220822 110,35.7458573 L110,53.1708094 C110,56.2060875 107.531385,58.6666667 104.5,58.6666667 C104.331455,58.6666667 104.164681,58.6590557 104,58.6441617 L104,82.0033234 C104,85.3151964 101.311488,88 97.9970362,88 L6.0029638,88 C2.68761844,88 0,85.3182852 0,82.0033234 L0,5.99667663 C0,2.68480358 2.68851188,0 6.0029638,0 L97.9970362,0 C101.312382,0 104,2.68171476 104,5.99667663 L104,30.2724875 L104,30.2724875 Z M5,10.991014 C5,7.68226832 7.68678744,5 11.0051618,5 L92.9948382,5 C96.3113975,5 99,7.68493655 99,10.991014 L99,77.008986 C99,80.3177317 96.3132126,83 92.9948382,83 L11.0051618,83 C7.68860254,83 5,80.3150634 5,77.008986 L5,10.991014 Z"
id="loading-frame"></path>
</g>
</g>
</svg>
</section>
It would be a lot easier if you drew the shape with a single path as you could then animate a single gradient to fill it. Alternatively you can extend what I've shown below to have one gradient per element with different start times and durations. I've only done two objects, you could extend the concept to the others if you want. If you want IE support, use fakeSmile.
$(document).ready( function() {
$("#iambutton").click(function () {
$("#a1")[0].beginElement();
$("#a2")[0].beginElement();
$("#a3")[0].beginElementAt(3);
$("#a4")[0].beginElementAt(3);
});
});
.mysvg {
text-align: center;
}
.mysvg svg {
margin: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="iambutton">Clik me to see progress</button>
<section class="mysvg">
<svg width="110px" height="88px" viewBox="0 0 110 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mysvg">
<defs>
<linearGradient id="g1">
<stop offset="0%" stop-color="red">
<animate id="a1" attributeName="offset"
from="0%" to="100%" dur="5s" fill="freeze" begin="indefinite" />
</stop>
<stop offset="0%" stop-color="#EAEAEA">
<animate id="a2" attributeName="offset"
from="0%" to="100%" dur="5s" fill="freeze" begin="indefinite" />
</stop>
</linearGradient>
<linearGradient id="g2">
<stop offset="0%" stop-color="red">
<animate id="a3" attributeName="offset"
from="0%" to="100%" dur="1s" fill="freeze" begin="indefinite" />
</stop>
<stop offset="0%" stop-color="#EAEAEA">
<animate id="a4" attributeName="offset"
from="0%" to="100%" dur="1s" fill="freeze" begin="indefinite" />
</stop>
</linearGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#EAEAEA">
<rect id="Brick-4" fill="url(#g2)" x="77.5" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-3" x="56" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-2" x="34.5" y="10" width="13.5" height="68" rx="3"></rect>
<rect id="Brick-1" x="13" y="10" width="13.5" height="68" rx="3"></rect>
<path id="Rectangle-7" fill="url(#g1)" d="M104,30.2724875 C104.164709,30.2576038 104.331485,30.25 104.5,30.25 C107.537566,30.25 110,32.7220822 110,35.7458573 L110,53.1708094 C110,56.2060875 107.531385,58.6666667 104.5,58.6666667 C104.331455,58.6666667 104.164681,58.6590557 104,58.6441617 L104,82.0033234 C104,85.3151964 101.311488,88 97.9970362,88 L6.0029638,88 C2.68761844,88 0,85.3182852 0,82.0033234 L0,5.99667663 C0,2.68480358 2.68851188,0 6.0029638,0 L97.9970362,0 C101.312382,0 104,2.68171476 104,5.99667663 L104,30.2724875 L104,30.2724875 Z M5,10.991014 C5,7.68226832 7.68678744,5 11.0051618,5 L92.9948382,5 C96.3113975,5 99,7.68493655 99,10.991014 L99,77.008986 C99,80.3177317 96.3132126,83 92.9948382,83 L11.0051618,83 C7.68860254,83 5,80.3150634 5,77.008986 L5,10.991014 Z"></path>
</g>
</g>
</svg>
</section>
Changing your SVG a bit you can make it work.
Instead of using rect to make the battery levels, let them as "holes" in your battery, so you can animate a rect under it and it will look like it's filling the levels.
Something like this:
$(document).ready( function() {
$("#iambutton").click(function () {
console.log("hi");
$(".mysvg").addClass( 'me' );
});
});
.mysvg {
text-align: center;
}
.mysvg svg {
margin: auto;
}
.mysvg svg #loading-frame {
fill: red;
-webkit-transform: translateX(-100%);
-ms-transform: translateX(-100%);
transform: translateX(-100%);
-webkit-transition: all 10s;
transition: all 10s;
}
.mysvg.me svg #loading-frame {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="iambutton">Clik me to see progress</button>
<section class="mysvg">
<svg width="110px" height="88px" viewBox="0 0 110 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mysvg">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#EAEAEA">
<rect id="loading-frame" x="0" y="0" width="110" height="88" fill="red" />
<path d="M0 0 h110 v88 h-110z
M77.5 10 h13.5 v68 h-13.5z
M56 10 h13.5 v68 h-13.5z
M34.5 10 h13.5 v68 h-13.5z
M13 10 h13.5 v68 h-13.5z" fill="black" />
</g>
</g>
</svg>
</section>
Wait a few seconds after the click and you will see the white area being filled by red.
Sorry by the really simple SVG, but it would take more time to redraw the whole battery, you can see more about this way of making "holes" in How to cut a hole in an SVG rectangle
You can make, in a javascript file, a function like this:
$(document).ready( function() {
$("#iambutton").clickenter code here(function () {
console.log("hi");
$(".mysvg").addClass( 'me' );
document.getElementByID('mysvg').fill('red')
});
});

Categories

Resources