Crucial concepts are covered and will not be repeated here. We particularly think about:
+
+Importing Chart.js into a {shiny}
app created with {golem}
+
+Chart.js is a JavaScript library that allows you to create many types of charts (bars, lines, radar, etc.) and customize them as you wish
+It is very well documented
+It is the most popular JavaScript dataviz library on GitHub (over 60,000 โstarsโ at the time of this articleโs publication)
+
+To get an overview of the possibilities offered by Chart.js, visit the official page: https://www.chartjs.org/docs/latest/samples/information.html
+
+Add the dependencies to Chart.js in your {shiny} app
+The following sections assume that you have already created a {shiny}
app with {golem}
.
+If this is not the case and you want to learn more about {golem}
, I invite you to consult the official documentation .
+To add Chart.js to your {shiny}
app, you will need to find a way to incorporate the necessary files for its operation into your application. As we saw in our previous article, two solutions are possible.
+
+Use a โCDNโ (Content Delivery Network) to load the files from a third-party server.
+Download the necessary files and integrate them directly into the application.
+
+We will use the โCDNโ method here.
+Go to the โGetting Startedโ section of Chart.js documentation .
+
+
+
+
+
+
+
+
+
+We retrieve the CDN URL and store this information for later use.
+After creating the skeleton of an application via {golem}
, we will add the Chart.js dependency.
+Letโs open the R/app_ui.R
file of our application and add the link we copied earlier into the body of the golem_add_external_resources()
function.
+ golem_add_external_resources <- function () {
+ add_resource_path (
+ "www" ,
+ app_sys ("app/www" )
+ )
+
+ tags$ head (
+ favicon (),
+ bundle_resources (
+ path = app_sys ("app/www" ),
+ app_title = "chartJS"
+ ),
+ # Add here other external resources
+ # for example, you can add shinyalert::useShinyalert()
+ # Chart.js
+ tags$ script (src = "https://cdn.jsdelivr.net/npm/chart.js" )
+ )
+ }
+
+
+How to know if Chart.js is properly imported ?
+The โGetting Startedโ section previously consulted to retrieve the CDN link indicates that it is necessary to incorporate the HTML <canvas>
tag into our application to display a Chart.js chart. We add this element to the R/app_ui.R
file of our application.
+ app_ui <- function (request) {
+ tagList (
+ # Leave this function for adding external resources
+ golem_add_external_resources (),
+ # Your application UI logic
+ fluidPage (
+ h1 ("golemchartjs" ),
+ tags$ div (
+ tags$ canvas (id= "myChart" )
+ )
+ )
+ )
+ }
+To verify that Chart.js is properly imported into our application, we run our app with golem::run_dev()
, and the rest will take place in the web browser.
+NB: The following screenshots were taken using the Google Chrome browser.
+In the window of our application, right-click and then select โInspectโ. In the new window that opens, choose the โConsoleโ tab and type the command to generate a Chart.js chart, as indicated once again in the โGetting Startedโ section between the HTML script
tags.
+The code to copy and paste into the console is the following:
+ const ctx = document . getElementById ('myChart' );
+
+ new Chart (ctx, {
+ type : 'bar' ,
+ data : {
+ labels : ['Red' , 'Blue' , 'Yellow' , 'Green' , 'Purple' , 'Orange' ],
+ datasets : [{
+ label : '# of Votes' ,
+ data : [12 , 19 , 3 , 5 , 2 , 3 ],
+ borderWidth : 1
+ }]
+ },
+ options : {
+ scales : {
+ y : {
+ beginAtZero : true
+ }
+ }
+ }
+ });
+
+The chart from the demo page appears as expected! ๐
+We can move on! ๐
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step1
+
+
+
+Creating a Bar Chart with Chart.js
+The code used previously allowed us to verify that Chart.js was properly imported into our application. Now, we will see how to create a Chart.js chart from our {shiny}
application. The goal is to produce bar charts for various datasets with customizable options based on user choices.
+Letโs revisit the code executed previously:
+ const ctx = document . getElementById ('myChart' );
+
+ new Chart (ctx, {
+ type : 'bar' ,
+ data : {
+ labels : ['Red' , 'Blue' , 'Yellow' , 'Green' , 'Purple' , 'Orange' ],
+ datasets : [{
+ label : '# of Votes' ,
+ data : [12 , 19 , 3 , 5 , 2 , 3 ],
+ borderWidth : 1
+ }]
+ },
+ options : {
+ scales : {
+ y : {
+ beginAtZero : true
+ }
+ }
+ }
+ });
+We could imagine passing the labels
, label
, data
, and borderWidth
elements as function parameters.
+Letโs go! ๐
+
+Creating a JavaScript code usable from R
+We saw in our previous article that the way to call JavaScript code from R is to use a โJS handlerโ. To do this, go to the dev/02_dev.R
file! We add the following line in the โExternal Resourcesโ section:
+ golem:: add_js_handler ("barchartJS" )
+We fill in the skeleton by indicating โbarchartJSโ as the name of our handler and adding the JavaScript code we saw previously.
+$ (document ). ready (function () {
+ Shiny. addCustomMessageHandler ("barchartJS" , function (arg) {
+ const ctx = document . getElementById ("myChart" );
+
+ new Chart (ctx, {
+ type : "bar" ,
+ data : {
+ labels : ["Red" , "Blue" , "Yellow" , "Green" , "Purple" , "Orange" ],
+ datasets : [
+ {
+ label : "# of Votes" ,
+ data : [12 , 19 , 3 , 5 , 2 , 3 ],
+ borderWidth : 1 ,
+ },
+ ],
+ },
+ options : {
+ scales : {
+ y : {
+ beginAtZero : true ,
+ },
+ },
+ },
+ });
+ });
+ });
+We replace the labels
, label
, data
, and borderWidth
parameters, which are hardcoded here, with the future elements passed as arguments to our handler. The notation to use here will be arg.param_name
to access the values passed by our {shiny}
application. The .
notation is a JavaScript convention for accessing properties of an object. To draw a parallel with R, itโs somewhat like using arg$param_name
.
+At the beginning of our handler, we add a call to the console.log()
function to check the contents of the arg
element from the JS console. This will allow us to verify that the elements passed from R are correctly transmitted to our handler.
+$ ( document ). ready (function () {
+ Shiny. addCustomMessageHandler ('barchartJS' , function (arg) {
+ console . log (arg);
+ const ctx = document . getElementById ('myChart' );
+
+ new Chart (ctx, {
+ type : 'bar' ,
+ data : {
+ labels : arg. labels ,
+ datasets : [{
+ label : arg. label ,
+ data : arg. data ,
+ borderWidth : arg. borderWidth
+ }]
+ },
+ options : {
+ scales : {
+ y : {
+ beginAtZero : true
+ }
+ }
+ }
+ });
+ })
+ });
+We will add elements to the R/app_ui.R
file to generate the parameters to be passed to our handler:
+
+arg.labels
will be a vector of 5 character strings, randomly chosen from the letters of the latin alphabet.
+arg.label
will be a character string, randomly chosen from the letters of the latin alphabet.
+arg.data
will be a vector of 5 integer numbers, randomly chosen between 1 and 100.
+arg.borderWidth
will be an integer, randomly chosen between 1 and 5.
+
+The display of the chart will be triggered by clicking a โShow Barplotโ button.
+Here is the content of our R/app_ui.R
file:
+ app_ui <- function (request) {
+ tagList (
+ # Leave this function for adding external resources
+ golem_add_external_resources (),
+ # Your application UI logic
+ fluidPage (
+ h1 ("golemchartjs" ),
+ actionButton (
+ inputId = "showbarplot" ,
+ label = "Show Barplot"
+ ),
+ tags$ div (
+ tags$ canvas (id = "myChart" )
+ )
+ )
+ )
+ }
+And the content of the R/app_server.R
file :
+ app_server <- function (input, output, session) {
+ observeEvent (input$ showbarplot, {
+ app_labels <- sample (letters, 5 )
+ app_label <- paste0 (sample (letters, 10 ), collapse = "" )
+ app_data <- sample (1 : 100 , 5 )
+ app_borderWidth <- sample (1 : 5 , 1 )
+
+ golem:: invoke_js (
+ "barchartJS" ,
+ list (
+ labels = app_labels,
+ label = app_label,
+ data = app_data,
+ borderWidth = app_borderWidth
+ )
+ )
+ })
+ }
+Here are the key points to remember:
+
+The first parameter in the call to golem::invoke_js()
is the name of the JavaScript handler.
+The following parameters are the elements to be passed as arguments to our handler. They should be passed in a named list where the names correspond to the elements in the arg
object of our handler.
+
+Letโs run our application with golem::run_dev()
and verify that everything works as expected!
+
+Congratulations! ๐
+In addition to the displayed chart, we can see that the JavaScript console in the browser correctly shows the content of the arg
object, including its 4 sub-elements: labels
, label
, data
, and borderWidth
.
+And if you click the button again, what happens?
+
+The chart does not update; it remains stuck on the first chart! ๐ฎ
+The JavaScript console indicates that the arg
object has indeed been updated, but the chart does not refresh. Additionally, an error message appears in the JavaScript console: โError: Canvas is already in use. Chart with ID โ0โ must be destroyed before the canvas with ID โmyChartโ can be reused.โ
+Letโs try to understand whatโs happening: in the R/app_ui.R
file, we added a canvas
element with the ID โmyChartโ (with tags$canvas(id = "myChart")
). This element is used to display the chart. When we click the โShow Barplotโ button, a new chart is generated and displayed in this element. However, the previous chart is not destroyed, and the error message indicates that the โcanvasโ is already in use.
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step2
+
+
+Why isnโt the chart updating?
+To find the answer, we need to refer back to the Chart.js documentation. We can read in the โ.destroy()โ section that in order to reuse the HTML โcanvasโ element for displaying a new chart, it is necessary to destroy the previous chart.
+There is also a command โ.update()โ for updating an existing chart. This method seems more appropriate here, as we are using the same type of chart, with only a few parameters changing. The .update()
method allows updating an existing chart without having to destroy and recreate it, which will be less โbrutalโ visually (with a chart disappearing and then reappearing). However, the .destroy()
method should be kept in mind for cases where we want to radically change the type of chart, for example.
+Updating a chart implies that a chart has already been generated once. Therefore, we need to modify our JavaScript handler to account for this and find a way to detect the existence of a chart on our page. For this, we will refer again to the Chart.js documentation, particularly the getChart
method: https://www.chartjs.org/docs/latest/developers/api.html#static-getchart-key.
+The command to use is in the following form: const chart = Chart.getChart("canvas-id");
. According to the documentation, if the chart exists, the variable chart
will contain the Chart.js object associated with the HTML โcanvasโ element. If the chart does not exist, the variable chart
will be undefined
.
+For this command to work, we need to replace โcanvas-idโ with the ID of our โcanvasโ, which is โmyChartโ here: const chart = Chart.getChart("myChart");
+Letโs restart our application. We indeed find that the chart
object is undefined
as long as the chart has not been created, and it correctly reflects this status afterwards.
+
+We can adapt our code as follows:
+
+If chart
is undefined
, we create a new chart.
+If chart
is not undefined
, we update the existing chart.
+
+We adapt our handler by referring to the documentation for the .update()
method: https://www.chartjs.org/docs/latest/developers/api.html#update-mode
+$ (document ). ready (function () {
+ Shiny. addCustomMessageHandler ("barchartJS" , function (arg) {
+ console . log (arg);
+ const ctx = document . getElementById ("myChart" );
+
+ const chart = Chart. getChart ("myChart" );
+
+ if (chart == undefined ) {
+ console . log ("Creating a new chart" );
+ new Chart (ctx, {
+ type : "bar" ,
+ data : {
+ labels : arg. labels ,
+ datasets : [
+ {
+ label : arg. label ,
+ data : arg. data ,
+ borderWidth : arg. borderWidth ,
+ },
+ ],
+ },
+ options : {
+ scales : {
+ y : {
+ beginAtZero : true ,
+ },
+ },
+ },
+ });
+ } else {
+ console . log ("Updating an existing chart" );
+ chart. data . labels = arg. labels ;
+ chart. data . datasets [0 ]. label = arg. label ;
+ chart. data . datasets [0 ]. data = arg. data ;
+ chart. data . datasets [0 ]. borderWidth = arg. borderWidth ;
+ chart. update ();
+ }
+ });
+ });
+This example is a bit more complex than those seen so far:
+
+Retrieve the Chart.js object associated with the HTML โcanvasโ element using the method Chart.getChart("myChart")
.
+Check if this object is undefined
: if it is, use the code that has been working until now to create a new chart.
+If it is not undefined
, overwrite the configuration elements you want to update and then use the .update()
method. Note the specifics of handling configuration elements: chart.data.labels = arg.labels
for the labels, chart.data.datasets[0].label = arg.label
for the label, etc. Use .
to access object properties, with each .
allowing access to a deeper level of โdepthโ. It is also important to note that array indexing starts at 0 in JavaScript, not at 1 like in R.
+
+After all these efforts, letโs see if everything is back in order ๐!
+
+Phew, everything is OK this time! ๐ฅฒ
+Weโve touched on a more complex case of using a JavaScript library in a {shiny}
application. It is crucial to understand the libraryโs functioning by delving into the depths of its documentation. Moreover, one of the advantages of using a very popular library is that you can often find help on StackOverflow ๐ (here is an example of using the .destroy()
method).
+Feel free to go further in customizing your chart, such as changing the bar colors: https://www.chartjs.org/docs/latest/general/colors.html and https://www.chartjs.org/docs/latest/charts/bar.html.
+The best way to learn is to try reproducing examples from the documentation.
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step3
+
+
+
+Creating a Scatter Plot with Chart.js
+We will attempt to create a scatter plot with Chart.js. To develop our code, we will rely on the Chart.js documentation: https://www.chartjs.org/docs/latest/charts/scatter.html.
+As before, our code will be stored in a JS handler. Therefore, we will add a new handler in the dev/02_dev.R
file:
+ golem:: add_js_handler ("scatterplotJS" )
+The documentation is slightly different from that provided for bar charts. We will need to adapt our handler accordingly. We identify an element config
, which will include the type
, data
, and options
elements we have already seen. There is also a data
element containing datasets
and labels
.
+We will fill in the skeleton of our handler with the JavaScript code from the Chart.js documentation. Initially, we will leave out the โupdateโ part.
+$ (document ). ready (function () {
+ Shiny. addCustomMessageHandler ("scatterplotJS" , function (arg) {
+ const ctx = document . getElementById ("myChart2" );
+
+ const data = {
+ datasets : [
+ {
+ label : "Scatter Dataset" ,
+ data : [
+ {
+ x : - 10 ,
+ y : 0 ,
+ },
+ {
+ x : 0 ,
+ y : 10 ,
+ },
+ {
+ x : 10 ,
+ y : 5 ,
+ },
+ {
+ x : 0.5 ,
+ y : 5.5 ,
+ },
+ ],
+ backgroundColor : "rgb(255, 99, 132)" ,
+ },
+ ],
+ };
+
+ const config = {
+ type : "scatter" ,
+ data : data,
+ options : {
+ scales : {
+ x : {
+ type : "linear" ,
+ position : "bottom" ,
+ },
+ },
+ },
+ };
+ new Chart (ctx, config);
+ });
+ });
+Our JS handler โscatterplotJSโ is ready! We need to add the โdivโ and โcanvasโ to the UI to display the generated chart. We need to modify the HTML ID of our โcanvasโ to avoid any conflict with the bar chart. It will be named โmyChart2โ here.
+Note that there is a slightly different syntax compared to the code used for the bar chart, where the call to โnew Chartโ was made directly with the data
and options
elements. Here, we store these elements in data
and config
variables before passing them to new Chart
.
+Next, we add the following to the R/app_ui.R
file:
+h1 ("Scatterplot" ),
+actionButton (
+ inputId = "showscatterplot" ,
+ label = "Show Scatterplot"
+ ),
+ tags$ div (
+ tags$ canvas (id = "myChart2" )
+ )
+We add the following to the R/app_server.R
file:
+ observeEvent (input$ showscatterplot, {
+ golem:: invoke_js (
+ "scatterplotJS" ,
+ list (
+ )
+ )
+ })
+Our handler does not use any elements passed from R. However, it is necessary to pass an empty list as an argument to ensure the proper functioning of golem::invoke_js()
.
+Letโs run your application with golem::run_dev()
and verify that everything works as expected!
+
+The chart from the documentation works! ๐
+Now, letโs go further by passing our own data as input.
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step4
+
+An example with the iris dataset
+We will use the iris
dataset to generate a scatter plot. We will pass as arguments to our JS handler the data from the Sepal.Length
and Sepal.Width
columns.
+As with the bar chart, we will use elements passed from R through the arg
object in JavaScript.
+We modify the data
object to include a legend title and, most importantly, the data. To observe the elements passed from R, we add a call to console.log()
.
+console . log (arg);
+const data = {
+ datasets : [
+ {
+ label : arg. label ,
+ data : arg. data ,
+ backgroundColor : "rgb(255, 99, 132)" ,
+ },
+ ],
+ };
+As a reminder, in the example from the documentation, the data is passed in the form of an โarray of dictionariesโ. Each dictionary contains the keys x
and y
for the point coordinates.
+ data: [{
+ x : - 10 ,
+ y : 0
+ }, {
+ x : 0 ,
+ y : 10
+ }, {
+ x : 10 ,
+ y : 5
+ }, {
+ x : 0.5 ,
+ y : 5.5
+ }]
+Letโs try to pass the contents of the Sepal.Length
and Sepal.Width
columns via a list. We make the following modification in R/app_server.R
:
+observeEvent (input$ showscatterplot, {
+ golem:: invoke_js (
+ "scatterplotJS" ,
+ list (
+ label = "My scatterplot" ,
+ data = list (
+ x = iris$ Sepal.Length,
+ y = iris$ Sepal.Width
+ )
+ )
+ )
+ })
+We restart our application, and unfortunately, nothing shows up!
+
+Thanks to the console.log()
call in our handler, we can observe the content of the arg
object in the JavaScript console of the browser. We notice that the data passed is not in the correct format. Here, we get an array of two elements, the first containing the values of Sepal.Length
and the second containing the values of Sepal.Width
, which is not the expected format.
+Here, we need to do some work on the R side to transform our data into the expected format.
+If we display a JSON preview of the data we passed as input, indeed the rendering is incorrect.
+
+
jsonlite:: toJSON (
+ list (
+ x = iris$ Sepal.Length,
+ y = iris$ Sepal.Width
+ )
+ )
+
+
+
+
{"x":[5.1,4.9,4.7,4.6,5,5.4,4.6,5,4.4,4.9],"y":[3.5,3,3.2,3.1,3.6,3.9,3.4,3.4,2.9,3.1]}
+
+
+For manipulating lists, the {purrr}
package is a top choice.
+
+
new_data <- purrr:: transpose (
+ list (
+ x = iris$ Sepal.Length,
+ y = iris$ Sepal.Width
+ )
+ )
+ jsonlite:: toJSON (
+ new_data,
+ auto_unbox = TRUE
+ )
+
+
+
+
[{"x":5.1,"y":3.5},{"x":4.9,"y":3},{"x":4.7,"y":3.2},{"x":4.6,"y":3.1},{"x":5,"y":3.6},{"x":5.4,"y":3.9},{"x":4.6,"y":3.4},{"x":5,"y":3.4},{"x":4.4,"y":2.9},{"x":4.9,"y":3.1}]
+
+
+The rendering seems to be more in line with what is expected by Chart.js. Therefore, we will modify our code to pass the data in this manner.
+observeEvent (input$ showscatterplot, {
+ golem:: invoke_js (
+ "scatterplotJS" ,
+ list (
+ label = "My scatterplot" ,
+ data = purrr:: transpose (
+ list (
+ x = iris$ Sepal.Length,
+ y = iris$ Sepal.Width
+ )
+ )
+ )
+ )
+ })
+Letโs observe the result:
+
+This time itโs good! ๐ We can see in the JavaScript console that the data has indeed been passed in the correct format.
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step5
+
+
+
+Going further with the scatter plot
+Additional modifications can be made to enhance the chart:
+
+Here are the resources used to produce the code that we will present shortly:
+
+Title: https://www.chartjs.org/docs/latest/configuration/title.html
+The title should be included in a plugins
object, which in turn is included in the options
object.
+Point Colors: https://www.chartjs.org/docs/latest/charts/line.html#point-styles
+The color of the points will be managed within the datasets
object.
+
+We will offer users the ability to set the chart title, its color, and the color of the points through shiny
inputs (which will be a good way to revisit the โupdateโ-related issues ๐).
+Below is a preview of the chart created here (without functional โupdateโ for now):
+
+The handler code has been completed to account for these new elements:
+$ (document ). ready (function () {
+ Shiny. addCustomMessageHandler ("scatterplotJS" , function (arg) {
+ const ctx = document . getElementById ("myChart2" );
+
+ console . log (arg);
+
+ const data = {
+ datasets : [
+ {
+ label : arg. label ,
+ data : arg. data ,
+ borderColor : arg. pointBorderColor ,
+ backgroundColor : arg. pointBackGroundColor ,
+ },
+ ],
+ };
+
+ const plugins = {
+ title : {
+ display : true ,
+ text : arg. mainTitle ,
+ color : arg. mainTitleColor ,
+ },
+ };
+
+ const config = {
+ type : "scatter" ,
+ data : data,
+ options : {
+ plugins : plugins,
+ scales : {
+ x : {
+ type : "linear" ,
+ position : "bottom" ,
+ title : {
+ display : true ,
+ text : arg. xAxisTitle ,
+ },
+ },
+ y : {
+ title : {
+ display : true ,
+ text : arg. yAxisTitle ,
+ },
+ },
+ },
+ },
+ };
+ new Chart (ctx, config);
+ });
+ });
+In R/app_ui.R
, elements have been added to allow the user to pass the necessary parameters:
+h1 ("Scatterplot" ),
+textInput (
+ inputId = "scatterplot_title" ,
+ label = "Scatterplot Title" ,
+ value = "ChartJS rocks !"
+ ),
+selectInput (
+ inputId = "title_color" ,
+ label = "Title Color" ,
+ choices = c ("brown" , "orange" , "purple" ),
+ selected = "brown"
+ ),
+selectInput (
+ inputId = "points_background_color" ,
+ label = "Points Background Color" ,
+ choices = c ("red" , "blue" , "green" ),
+ selected = "red"
+ ),
+actionButton (
+ inputId = "showscatterplot" ,
+ label = "Show Scatterplot"
+ ),
+ tags$ div (
+ tags$ canvas (id = "myChart2" )
+ )
+Finally, in R/app_server.R
, we add the necessary elements to pass the parameters to our handler:
+observeEvent (input$ showscatterplot, {
+ golem:: invoke_js (
+ "scatterplotJS" ,
+ list (
+ label = "My scatterplot" ,
+ data = purrr:: transpose (
+ list (
+ x = iris$ Sepal.Length,
+ y = iris$ Sepal.Width
+ )
+ ),
+ xAxisTitle = "Sepal Length" ,
+ yAxisTitle = "Sepal Width" ,
+ mainTitle = input$ scatterplot_title,
+ mainTitleColor = input$ title_color,
+ pointBorderColor = "black" ,
+ pointBackGroundColor = input$ points_background_color
+ )
+ )
+ })
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step7
+We still need to include the .update()
method to account for updates to shiny
inputs related to the title and the color of the points.
+We will use the approach from the previous chart to modify our JS handler accordingly.
+$ (document ). ready (function () {
+ Shiny. addCustomMessageHandler ("scatterplotJS" , function (arg) {
+ const ctx = document . getElementById ("myChart2" );
+
+ console . log (arg);
+
+ const chart2 = Chart. getChart ("myChart2" );
+
+ if (chart2 == undefined ) {
+ console . log ("Creating a new chart" );
+
+ const data = {
+ datasets : [
+ {
+ label : arg. label ,
+ data : arg. data ,
+ borderColor : arg. pointBorderColor ,
+ backgroundColor : arg. pointBackGroundColor ,
+ },
+ ],
+ };
+
+ const plugins = {
+ title : {
+ display : true ,
+ text : arg. mainTitle ,
+ color : arg. mainTitleColor ,
+ },
+ };
+
+ const config = {
+ type : "scatter" ,
+ data : data,
+ options : {
+ plugins : plugins,
+ scales : {
+ x : {
+ type : "linear" ,
+ position : "bottom" ,
+ title : {
+ display : true ,
+ text : arg. xAxisTitle ,
+ },
+ },
+ y : {
+ title : {
+ display : true ,
+ text : arg. yAxisTitle ,
+ },
+ },
+ },
+ },
+ };
+ new Chart (ctx, config);
+ } else {
+ console . log ("Updating an existing chart" );
+ chart2. data . datasets [0 ]. backgroundColor = arg. pointBackGroundColor ;
+ chart2. options . plugins . title . text = arg. mainTitle ;
+ chart2. options . plugins . title . color = arg. mainTitleColor ;
+ chart2. update ();
+ }
+ });
+ });
+Letโs observe the result:
+
+Well done! ๐
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step8
+
+
+Modifying the tooltip (advanced level)
+We will look to modify the tooltip that appears when hovering over a point on the chart. In addition to changing its title, we want to display the row number from the dataset corresponding to the hovered point, as well as the corresponding values of Sepal.Length
and Sepal.Width
.
+Here are the resources used:
+
+Tooltip title: https://www.chartjs.org/docs/latest/configuration/tooltip.html#tooltip-callbacks
+Tooltip content: https://www.chartjs.org/docs/latest/configuration/tooltip.html#tooltip-callbacks and https://www.youtube.com/watch?v=anseX1ePfUw
+
+This part will be more complex than the previous ones. But we will manage it! ๐ช
+The plugins
object, used previously to manage the chart title, contains a tooltip
element, which in turn contains a callbacks
element. It is within this element that we can modify the title and content of the tooltip. Most tooltip elements can be configured via a function call that takes a context
element as input. This is a JavaScript object that contains several items related to the hovered point. We will explore the content of this object to extract the information we need later when customizing the tooltip content.
+We modify our JS handler by including a fixed title (we could also have passed it as a parameter):
+const tooltip = {
+ callbacks : {
+ title : function (context) {
+ return "Tooltip title" ;
+ },
+ },
+ };
+
+const plugins = {
+ title : {
+ display : true ,
+ text : arg. mainTitle ,
+ color : arg. mainTitleColor ,
+ },
+ tooltip : tooltip
+ };
+Letโs see if it works:
+
+The application code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step9
+Letโs proceed with customizing the tooltip content!
+In this step, we will modify the label
parameter in the tooltip
object. To refine our code, we will use the debugger
function, which we havenโt used so far! If you are familiar with using browser()
in R, debugger
is its JavaScript equivalent. It allows you to pause the code execution and open the browser console to explore the arguments passed to a function.
+Letโs modify our handler:
+const tooltip = {
+ callbacks : {
+ title : function (context) {
+ return "Tooltip title" ;
+ },
+ label : function (context) {
+ debugger ;
+ }
+ },
+ };
+
+const plugins = {
+ title : {
+ display : true ,
+ text : arg. mainTitle ,
+ color : arg. mainTitleColor ,
+ },
+ tooltip : tooltip,
+ };
+We add a call to the JavaScript debugger
in the label
function of the callbacks
object. We restart our application:
+
+When hovering over a point on the chart, code execution is paused and the browser console opens. We can then explore the content of the context
object passed to the label
function.
+We can identify the information that will be useful:
+
+We can then construct a customized tooltip (remembering to remove the debugger
call ๐):
+const tooltip = {
+ callbacks : {
+ title : function (context) {
+ return "Tooltip title" ;
+ },
+ label : function (context) {
+ lab =
+ "Line number: " +
+ context. dataIndex +
+ " values: " +
+ context. formattedValue ;
+ return lab;
+ },
+ },
+ };
+
+const plugins = {
+ title : {
+ display : true ,
+ text : arg. mainTitle ,
+ color : arg. mainTitleColor ,
+ },
+ tooltip : tooltip,
+ };
+
+Mission accomplished! ๐
+The code for this step is available here: https://github.com/ymansiaux/golemchartjs/tree/step10
+
+
+