+ Start a Discussion
Marry SteinMarry Stein 

Visualforce: Draw a chart with chart.js libary

Hey guys,

i am not familar with javascript, but i really like how the chart.js libary looks. To get started i want to create some cool Salesforce Dashboards with chart.js. I have already create a visualforce Page to show a simple bar chart. Now, i am looking for a way to get the controller variable to the javascript function : 
http://www.chartjs.org/docs/latest/

This is the javascript Code: 
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["M1", "M2", "M3", "M4", "M5", "M6"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],   
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
</script>
How can i change the label and dataset with controller variables ? My idea is to create a simple list and transform the list to string. Does this work ? 

Thanks for help guys. I cant find any help for chart.js and visualforce...

Greetings,

Marry





 
Best Answer chosen by Marry Stein
Alain CabonAlain Cabon
Hi,

The access fo remote object from the client in javascript was used for button with javascript (not supported in Lightning) and it is also an interesting technique for VFP used for the mobile (android/iOs). 

Best Practices for Using Remote Objects: 
Remote Objects pairs well with JavaScript frameworks such as jQuery and AngularJS, and those can help with the complexity of your application’s user interface. Always consider separating the concerns of your application into multiple layers and keeping them as discrete as possible. This is called “separation of concerns,” and it’s a classic software pattern and best practice.
http://ttps://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_considerations.htm

An Example of Using Remote Objects with jQuery Mobile​
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_example_extended.htm

i know jQuery and it is explained here:for the basics in Salesforce: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_javascript_libraries.htm
 

All Answers

Marry SteinMarry Stein
This is my idea, but i am still struggling. 
public class ChartJSController {
    public String revenue{get;set;}

    	public ChartJSController() {
        	List<AggregateResult> agrList = new List<AggregateResult>();
			agrList =[SELECT SUM(Amount) monthlyRevenue, CALENDAR_MONTH(CloseDate) theMonth
             		FROM Opportunity
                    WHERE CALENDAR_MONTH(CloseDate)<= 6
             		GROUP BY CALENDAR_MONTH(CloseDate)
             		ORDER BY CALENDAR_MONTH(CloseDate)];
            
            String commaSepratedList='';
            for(AggregateResult agr : agrList)
			{
            
 			commaSepratedList += agr + ',' ;
			}
            this.revenue = commaSepratedList;
    	}
}
The Problem is, if i output the variable 'revenue' it looks like this 

AggregateResult:{monthlyRevenue=15000.0, theMonth=1},AggregateResult:{monthlyRevenue=null, theMonth=2},AggregateResult:{monthlyRevenue=3567.0, theMonth=3},

But i need the string like this  

15000.0, 0, 3567, ... 

Any help for that case ? 

Greetins Marry





 
Alain CabonAlain Cabon
Hi,

From the client (even in a Visualforce page), you can read with just javascript code your data without a controller (class) in apex.

function(err, records) of ct.retrieve below is the part where you can get the result of the query.

The specific format of the query filter (clauses) is explained here:  
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_using_retrieve_query_object.htm

The samples:
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_example_simple.htm

https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_using_retrieve_query_object.htm
<apex:remoteObjects jsNamespace="RemoteObjectModel">
    <apex:remoteObjectModel name="Account" fields="Id,Name,CreatedDate"/>
</apex:remoteObjects>

<script>
    var account_created_from_date = new Date('2017-01-01');
    var account_created_to_date = new Date('2018-01-01');
    var clauses = {       
        'where': {
            'CreatedDate': { 'lte': account_created_to_date },
            'and': {
                'CreatedDate': { 'gte': account_created_from_date },
                'Id': { 'ne': '' }
            }
        }   
    };

    var ct = new RemoteObjectModel.Account();
    ct.retrieve(
        clauses,
        function(err, records) { 
            if (err) { 
                console.log(err); 
            } else { 
                console.log(records.length); 
                console.log(records[0]); 
                records.forEach(function(record) { 
                   var accName = record.get("Name");
                   var accCreatedDate = record.get("CreatedDate");                 
                });
            } 
        } 
    );
</script>
Alain CabonAlain Cabon
But for aggregate functions, you still need an apex controller for overriding the default process (must be retested)

Remote Objects and Aggregate Function
https://salesforce.stackexchange.com/questions/36370/remote-objects-and-aggregate-function
 
Alain CabonAlain Cabon

agr.get('monthlyRevenue')
List<AggregateResult> agrList = new List<AggregateResult>();
			agrList =[SELECT SUM(Amount) monthlyRevenue, CALENDAR_MONTH(CloseDate) theMonth
             		FROM Opportunity
                    WHERE CALENDAR_MONTH(CloseDate)<= 6
             		GROUP BY CALENDAR_MONTH(CloseDate)
             		ORDER BY CALENDAR_MONTH(CloseDate)];
            
 String commaSepratedList='';
 for(AggregateResult agr : agrList)
 {
    commaSepratedList += agr.get('monthlyRevenue') + ',' ;
  }

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL_agg_fns.htm
Marry SteinMarry Stein
Hi Alain,
big thanks for your reply ! I will definitely check out your links but i have already found the solution by myself. 

I used 
commaSepratedList = String.valueOf(agr.get('monthlyRevenue')) ;
but i think both options are ok. 
After that, i have remvoed the last comma with:
String s2 = commaSepratedList.removeEnd(',');

Now my String variable looks like it should :

1000.00,200.00,3000.00,4000.00,5000.00,6000.00 

Unfortunately, it doesn work.  For one value it works like a charm.. also when i copy / paste the string in the function it works...  






 
Marry SteinMarry Stein
ok my bad, i just have to use controller variable ^^
instead of 
var datavalues = '{!revenue}';
i just have to use
data: [{!revenue}] 


Ok, now the chart works! But thanks for your effort Alain. I will check out your links tomorrow... How bad is my solution ? :D 
Alain CabonAlain Cabon
Hi,

If that works with your solution and an apex controller, that is sufficient.

 <apex:remoteObjectModel> is more complicated when there are aggregate functions so your solution is also simpler.

 
Marry SteinMarry Stein
thanks ! Could you tell me, whats the exact advantage of an remote object ?  Does it reduce the api calls? 

Are you familar with jquery ? The next step would be to make the chart interactive. :)


Greetings Marry 
Alain CabonAlain Cabon
Hi,

The access fo remote object from the client in javascript was used for button with javascript (not supported in Lightning) and it is also an interesting technique for VFP used for the mobile (android/iOs). 

Best Practices for Using Remote Objects: 
Remote Objects pairs well with JavaScript frameworks such as jQuery and AngularJS, and those can help with the complexity of your application’s user interface. Always consider separating the concerns of your application into multiple layers and keeping them as discrete as possible. This is called “separation of concerns,” and it’s a classic software pattern and best practice.
http://ttps://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_considerations.htm

An Example of Using Remote Objects with jQuery Mobile​
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_remote_objects_example_extended.htm

i know jQuery and it is explained here:for the basics in Salesforce: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_javascript_libraries.htm
 
This was selected as the best answer
Marry SteinMarry Stein
Gracias ! :)
Marry SteinMarry Stein
Hi Alain, 

maybe you can help me again ? :D 
I want to create a real time Dashboard. I have already created a push topic and i am able to render any visualforce component what i want when the push event is "fired".

But i dont like to update the whole apex:chart and moreover i dont like how the charts look. So i am looking for a way to update my chart, when a push event is created.  I have already tried different options, but i can't figure it out..

I created a second methode in my controller to update this variable. The action function is calling this methode. But when i create a completely new Dashboard, the variable {!revenue} is not updated. Strange, if i output the variable with the apex:outputtext component, its updated..  

Maybe there is a simple solution ? :( Thanks for your help Alain 
 
Alain CabonAlain Cabon
Hi Mary,

You have already created a great real time Dashboard with a push topic? You are really good at making this kind of sophisticated development.

Did you use the following technique well explained in this article?
https://developer.salesforce.com/blogs/developer-relations/2013/01/responsive-visualforce-using-streaming-api-and-asynchronous-apex.html
 
Marry SteinMarry Stein
Thanks Alain ! 
At the moment the solution is not really great :D My solution works fine to rerender a number in a PageBlockTable but i want to make it fancy. I want to create a graph which is moving constantly without rerender the whole chart. But thanks for the compliment. I will check out your link !

Yes, i am using cometd to subscribe for the push topi: Did you check out this video ?
https://www.salesforce.com/video/193980/
Its pretty cool ! 
ohio jimohio jim
Accessing your router admin through a 192.168.l.l IP address will allow you to change the settings and configurations that your router software provides. Click Here http://192.168.1.1 or enter 192.168.l.l (https://19216811.run/) into your browser's address bar. If you're getting an error, then 19216811 is not your router's IP address.
hassan raza 31hassan raza 31
seriously amazing and i love this website there are many people urdu sms (https://urdu-sms.com/), Good and many people doing comment i like it what thay saying i m new here