kottenator / jquery-circle-progress

jQuery Plugin to draw animated circular progress bars
http://kottenator.github.io/jquery-circle-progress/
MIT License
1.1k stars 312 forks source link

progress animation with JQuery File Upload #88

Closed apatikgg closed 8 years ago

apatikgg commented 8 years ago

I'm having issues getting the widget to work with JQuery File Upload.

The progress animation starts only once the file is done uploading (regardless if the file weights 1mo or 100mo) even though JQuery File Upload is set to update the progress value every 1 or 10ms (it works fine with regular progress bars). I've digged into every options (animation speed, disabling the animation...) but so far I haven't been able to solve this.

$('#avatar-progress').circleProgress({
    value: 0,
    size: 156,
    fill: { color: "#60bcff" },
    emptyFill: "#ffffff",
    thickness: 2,
    startAngle: 3.8,
});

JQuery File Upload progress options :

progressInterval: 1,
dataType: 'json',
progress: function (e, data) {
    var progress = parseInt(data.loaded / data.total, 10);
    $('#avatar-progress').circleProgress('value', progress);
}

Any thoughts on this issue ? I'm really looking forward to be able to correctly implement this progress bar. Besides this, great script.

Thanks !

kottenator commented 8 years ago

Please, check this line: parseInt(data.loaded / data.total, 10); - as I understand it returns always either 0 or 1. What you need is data.loaded / data.total without parseInt(...)

apatikgg commented 8 years ago

Thanks for being this quick, and nice catch indeed ! I've tested different things and your suggestion seems to be working provided I disable the animation (or set the speed much lower than the default one).

I'm going to do some more tests and close the ticket if everything is fine. Thanks again !

kottenator commented 8 years ago

You're welcome! ;)

apatikgg commented 8 years ago

After some testing and tuning it works perfectly. :) One final concern that I judged was not worth opening a new ticket (let me know if I should):

For animation/easing purposes I have to redefine the progress bar's speed animation and color depending on the file's size.

For instance a light file would be blue with a speed.animation of 1000ms and a heavy one would be red with a 10ms speed animation so it doesn't get cut everytime the progression is updated while uploading.

I'm doing so like this :

progress: function (e, data) {
    if (data.total <= 10000)  {
        $('#avatar-progress').circleProgress({
            fill: { color: "#0000ff" },
            animation: { duration: 1000}
        });
    } else  {
        $('#avatar-progress').circleProgress({
            fill: { color: "#ff0000" },
            animation: { duration: 10}
        });
    }
}

With the code above, if I load the page and upload a file, the modifications regarding the color/animation will occur as expected, but if I upload a second file, the progress bar will instantly displays 100% as soon as the code above is read a second time even though the value has been set back to 0 before uploading a new file.

Do you have any thoughts on that ?

nb: if need be I will open a new ticket and gather more informations on the issue.

Thanks for your patience

kottenator commented 8 years ago

Yes, I know about this problem. It's the nature of jQuery animation, duration is fixed regardless of value that is animated.

As an option, you could fix the minimal duration, like 50ms or 100ms

apatikgg commented 8 years ago

Oh yeah, the problem isn't actually the animation duration, it's the progress bar instantly popping at 100% when I call

$('#avatar-progress').circleProgress({
        });

several times in a function, even if I don't touch the value option (actually even if I don't set any options at all). Like if calling circleProgress was somehow reinitiating with a default value of 1 (and no animation).

Anyways I feel this is isn't very clear, and since my initial issue is resolved you can set this one as "resolved" :)

I will open a new ticket for this specific problem after gathering more informations so I can present this much better.

Thanks !

kottenator commented 8 years ago

Currently it's implemented in the way described in README. So yes, it re-starts the animation and uses last stored value, which is 1 in your case.

apatikgg commented 8 years ago

Allright, then it seems there must be something messing up the value somewhere in my script. I've been able to reproduce the bug like this :

processfail: function () {
    setTimeout(function () {
        $('#avatar-progress').circleProgress({
            fill: { color: "#ff0000" },
            value: 1,
        });
    }, 1000);
    setTimeout(function () {
        $('#avatar-progress').circleProgress('value', 0);
    }, 3000);
    setTimeout(function () {
        $('#avatar-progress').circleProgress({
            fill: { color: "#0000ff" },
        });
    }, 5000);
},

(NB : processfail triggers if a user tries to upload a file that doesn't meet the requierement) In the exemple above 3 events happen but only 2 should be visible on my page.

  1. After 1 second, the bar goes 0->100 with a red color.
  2. After 3 second it goes back from 100->0 with a red color and at this point the value is stored is indeed 0.
  3. However after 5 second the bar instantly appears at 100 (in blue this time as intended) and goes 100->0.

This is what I have troubles understanding :/ Since the value is already 0 shouldn't the new color option happen "silently" ? (this is actually an exemple of what I'm trying to do in my code, the script above displays a the red 0-100 -> 100-0 animation, then set back the progressbar to its default blue color to prepare for next uploads).

If not how can I put this so the color change actually happens "in the background" without the bar animating etc ?

Thanks again for your time

kottenator commented 8 years ago

Yes, the case is correct, that's how it's implemented right now and maybe it's not the best way :(

The circle remembers that the last animation was started at 100% and finished at 0 so when you redraw it - it replays the last animation.

To make it forget the last animation, you need to override animationStartValue:

// reset the circle
$('#avatar-progress').circleProgress({
  value: 0,
  animationStartValue: 0
});

After it's reset, you can use $('#avatar-progress').circleProgress('value', ...) again, as usual

apatikgg commented 8 years ago

Oh allright ! It now seems to be working in my test page with animationStartValue: 0 so I'm going to assume it's going to be allright for the rest of my code aswell :) Thanks a lot for your help !

I'm closing the ticket, but one last quick question : is there anyway to detect when the animation hits 100% ? (like returning a value or something) I'm implementing a "pulse effect" around the circle when the upload is done that looks very neat with the progress bar, however with small files being uploaded before the animation is completed the pulse effect can trigger too early. If not it's no problem I have several ideas to work my way around it, so no worries :)

Thanks again for your support on this great plugin !

kottenator commented 8 years ago

Sure, there is an event for that - circle-animation-end

apatikgg commented 8 years ago

Hum can I ask how to set it up ?

Like this :

$('#circle').circleProgress.circle-animation-end({
        // code for pulse effect
});

or something more like :

if  ( $('#circle').circleProgress(circle-animation-end)) {
        // code for pulse effect
}

Couldn't find an exemple on the main page and truly have no idea how this works :/

kottenator commented 8 years ago

Probably I need to add this to README:

$('#circle').circleProgress(...);

$('#circle').on('circle-animation-end', function() {
        // code for pulse effect
});

Or via jQuery call chain (you need to add event listener only once!):

$('#circle').circleProgress(...).on('circle-animation-end', function() {
        // code for pulse effect
});
apatikgg commented 8 years ago

Allright I think i get it. What does (...) stand for however ?

Anyways I managed to get it work but as I thought I was finally done, something showed up.

processfail: function () {
    $('#avatar-progress').circleProgress({
                animation: { duration: 500 },
                fill: { color: "#dd3a3a" },
                animationStartValue: 0
            });
    $('#avatar-progress').circleProgress('value', 1);
    $('#avatar-progress').on('circle-animation-end', function() {
        var element = document.getElementById("avatar-progress");
        element.classList.add("avatar-pulse-error");
        setTimeout(function () {
            $('#avatar-progress').circleProgress('value', 0);
            setTimeout(function () {
                var element = document.getElementById("avatar-progress");
                element.removeAttribute("class");
                $('#avatar-progress').circleProgress({
                    animation: { duration: 10 },
                    fill: { color: "#60bcff" },
                    animationStartValue: 0
                });
            }, 500);
        }, 800);
    });
},

As you see I am using the code to run the second half of the script after the 0-100 has ended. It works very fine exept immediatly after this script is done, the part between

$('#avatar-progress').on('circle-animation-end', function() {
        // code for pulse effect
});

gets run again and again in an infinite loop of LSD effect pulse animation. Any idea why the script is doing loops ? It is supposed to run only once after the bar reaches 0->100

Thank you !