Using jquery-circle-progress with Meteor


#1

I’m working on a small app to control some ESP IoT devices, and I want to use some circle progress bars to make it look more friendly.
The thing is, I’ve been searching for javascript plugins to do this, and the best i found is jquery-circle-progress.
I tried to implement it on my project, but I have no clue about how to implement it, I’m using templates and I don’t know how to include this plugin on the Template iterations.

The plugin is applied on an input element like this:


$(’.myCircle’).circleProgress({
value: 0.75,
fill: {gradient: [[’#0681c4’, .5], [’#4ac5f8’, .5]], gradientAngle: Math.PI / 4}
}).on(‘circle-animation-progress’, function(event, progress, stepValue) {
$(this).find(‘strong’).text(stepValue.toFixed(2).substr(1));
});


I tried using a function at the end of my main.js (the one I use to import everything else) that calls .each element with the “myCircle” class, then applies .circleProgress(…) to each one,
but the circles appear (with the right values and all) for a fraction of a second then dissapear, sometimes they don’t even show up.

This is the repo of the plugin

Am I missing something? maybe there is something like this ready to be implemented on Meteor?

EDIT: when the circles dissapear, the inputs used for this turn into a div again, like it was never touched


#2

You’ll wanna put your initialization code in the onRendered call back of the template that is closest to your input so that the input is in the DOM at the point when it is ran.


#3

im using this now

Template.myTemplate.onRendered = function() {
  $('.myCircle').each(function(){
    var barvalue = ($( this ).val())/100;
    $(this).circleProgress({
     value: barvalue,
     size: 80,
     fill: {
       gradient: ["red", "orange"]
     }
   });
  });

};

this is the element inside the template


< div  class="myCircle"  value="{{value}}"> </div> 

but now it doesn’t show anything, the div is untouched, no errors on the console so far
I guess I’m missing somethign else

EDIT: corrected the class name on the div, typo
EDIT2: formating


#4

Yes, unfortunately the nature of jQuery is to fail silently…

Due to the reactive nature of blaze, there could be the possibility that the element hasn’t been added to the DOM yet. I’d try console.loging the result of the jQuery selector like so and try to figure out if it’s getting a list of nodes.

Template.myTemplate.onRendered = function() {
    console.log($('.myCircle'));
};

Also a note on code formatting…

if you wrap your code in backticks or triple backticks you won’t need the **'s to display the html tags

```
<div></div>
```

#5

Alright, I’m going to try this and see what comes out

Thank you very much, and sorry for the bad formating


#6

You’re very welcome, and no problem. We were all new here once upon a time.


#7

Alright, I tried it and it doesn’t even trigger the onRendered event!
So it never shows up in the console log, but the Template.myTemplate.events is working
I know this beause there’s a button on the template that triggers an event there
so it means the script itself is working, but not the .onRendered (or so I believe)

Template.myTemplate.onRendered = function() {
  console.log("inside the .onRendered function");
  console.log($('.myCircle'));
};

it shows nothing on console, not even the first message

EDIT: typos

UPDATE:

I changed .onRendered by .rendered, and now it shows up, i’m gonna try to apply the function now

jQuery.fn.init(4) [div.myCircle, div.myCircle, div.myCircle, div.myCircle, prevObject: jQuery.fn.init(1)]
0
:
div.myCircle
1
:
div.myCircle
2
:
div.myCircle
3
:
div.myCircle

#8

Sorry, it’s been awhile since I’ve used Blaze so I didn’t catch this earlier… You don’t want to assign a function to the onRendered property, you want to call the onRendered function and pass it a callback like so…

Template.myTemplate.onRendered(function() {
  console.log("inside the .onRendered function");
  console.log($('.myCircle'));
});

#9

Alright, doing that now and reporting it right here

UPDATE: yes, now it shows the console log, and lists all of the elements, now I’ll try with the function

UPDATE 2: now it does the same as before, the circles show up for a fraction of a second (this time without values) then dissapear, if I keep refreshing the page, sometimes the circles stay, and the div holds a canvas

<div class="myCircle" value="20.8"><canvas width="80" height="80"></canvas></div>

But if i refresh it again, they will dissapear
Most of the time the circles dissapear after loading and the div goes back to normal

<div class="myCircle" value="20.8"></div>

UPDATE 3: Sometimes just some of them actually change as circle bars, and they do show values, and update them along with the bar to show the current values


#10

Ok, I managed to “make it work”.
Sometimes (like 50% of the time), the log shows that jquery finds more/less elements than it’s supossed to find (ie: there are 4 items with the class myCircle but it counts 5), and when that happens, the bars won’t display, or just some of them will display properly or broken.
Also noticed that .onRender triggers twice, I should mention that myTemplate is being called more than once:

{{#each myElements}}
                            {{> myTemplate}}
{{/each}}

Maybe this is causing the problem? In my case it should be called twice because thats the number of elements on myElements that I have right now.

It’s definitely not solved, but at least it’s displaying it right half the time.
I’ll keep looking for the source of the issue.


#11

So I don’t think this is being caused by the plugin being called multiple times, as it seems to me that this is how it works to set new values and update… I think though that you code is a little off, so I’m gonna try by best to fix it. Mind you I haven’t actively used jQuery for anything in about 4 years.

Also, check that $(this).val() returns what you expect. I’m not saying it’s wrong because I can’t see the rest of your code, but it looks suspect to me.

Template.myTemplate.onRendered(function () {
    const barvalue = ($(this).val()) / 100;
    this.$('.myCircle').circleProgress({
        value: barvalue,
        size: 80,
        fill: {
            gradient: ["red", "orange"]
        }
    });
});


#12

Yea i’m thinking the same but can’t wrap my mind around the possible issue, i’m very thankful that you are guiding me through this.
I’ll try what you said and double check the barvalue values


#13

Would you be interested to do it via React Component inside your Template? If yes, https://github.com/react-component/progress and you can run this into gadicc:blaze-react-component. If you wanna go that way, I can help you with it.


#14

I would not want to cause paralysis by analysis, but I’d say the best option here would be the simplest one. Spinners like this at the end of the day are usually just a single DOM element such as a DIV with a CSS style attached to it that contains a CSS animation rule. Google will equip you with plenty of CSS animations to copy-paste, so no knowledge of that required. As such, the only thing left for you would be to simply toggle that DIV in Blaze.

Granted, if you want things to be a little more fancy and for example have a spinner on top of an input field, then a little bit of extra work is required (parent element and spinner with position: absolute to place it on top of the field). But perhaps that’s not too important here.


#15

It looks like what I need actually, but I never used react before
Indeed this is my first meteor project, so there’s a lot of things I never used before

how do I apply it to my template?


#16

I’ve been looking for something like this, simple to apply but found nothing that fits what I need sadly, maybe I don’t know what to look for, any guidance is welcome.


#17

Google ‘css spinner jsfiddle’ and you’ll find a bunch of examples. For example this: http://jsfiddle.net/dpren/L7s3mvv4/1/


#18

That’s neat, It’s close to what I need, I think I didn’t explain well what I actually need.
I’m doing a simple dashboard for my small app to control some custom IoT devices.
This is the Template where I’m using the plugin i mentioned:

image

There you can see the cricle bars that I managed to display with the huge help of @copleyjk
That’s pretty much what i need, circle bars that change with the current value, and displaying said value inside the circle. Currently the ones I’m using don’t work 100% of the time, ~50% of the time if I refresh it, it will show broken bars or even some/all of them not displaying at all.

image


#19

Oh, in that case you might be better off trying to implement some existing package. Myself I would still probably go for a pure CSS solution where I’d generate the CSS dynamically in a style attribute (not a class since you’d need it to reflect changing values), but that would require a fair bit of wrangling with CSS. If you feel up for it, give it a shot with the help of this example: https://www.smashingmagazine.com/2015/07/designing-simple-pie-charts-with-css


#20

Thank you, I´m gonna give it a try

EDIT: finally decided to rebuild my app from zero, but I encountered the same prooblem, so instead of leaving it there, i made a script that constantly check for items with the class name and applies the plug in on them.

setInterval(function (){
  var els = document.getElementsByClassName("myCircle"); 
 Array.prototype.forEach.call(els, function(el) {  
    element=$(el); 
    const barvalue = (element.val());
    if(!isNaN(barvalue)){
      element.knob({
          'min':0,
          'max':100,
          'readOnly':true,
          'width': 80,
          'height': 80,
      });
      element.val(barvalue).trigger('change');
    } else {
      element.replaceWith( "<p class='elementDataBig'>"+barvalue+" </p>" );
    }
 });
}, 1000);

It’s not an elegant solution, I don’t even consider it solved, but it’s a good workaround that at least the user doesn’t notice at all. Also decided to change to knob (installed it using npm) as you may notice (which has the same problem so it wasn’t the plugin). Still I wish i could properly find the cause of the problem, but for now this “patches” the problem pretty well.

I leave this here in case it can help anyone that has the same problem.
Thank you all.