Javascript tutorial
Introduction
With this tutorial, you will learn how to use the Javascript (JS for short) functions of RPGM and control the client-side Javascript part of an app. We will create a project with a leaflet map in an RPGM app. Leaflet is a customizable and interactive map, like Google maps. R will be able to change the map and also get notified if the user clicks somewhere on the map.
Why to use JavaScript
Javascript is a simple programming language which is mainly used on websites, and is also behind the interface of RPGM. Using Javascript will allow you to use the vast Javascript ecosystem, mainly for its custom widgets.
Creating the project
Run RCode and create a new RPGM project.
Adding leaflet
The first step if to download Leaflet. Head into the official website download page, and click on the latest version available, which is 1.9.4 at the time of writing this tutorial. Please note that every Javascript library works differently. For Leaflet, it is shipped as a zip file that should be decompressed.
In the leaflet zip file, take the leaflet.js and leaflet.css files and move them in your project folder. Open the ppro file of your project and find the Custom JS/CSS files section. Add two new lines: leaflet.js and leaflet.css.
Info
Javascript and CSS files will be loaded in the same order as written in the ppro setting. If some Javascript libraries need some dependencies, add the dependencies first.
Leaflet is now added in your project and will be loaded with your app.
Creating the widget
Create a new gui file, name it leaflet.pgui and add it to the Sequencer. Add a new Label widget with Leaflet JS/R example in the value field, as a title.
Then add a new label widget and write in its Value field: <div id="map"></div>
. This will create an HTML div with the id map
, which leaflet will need.
Initializing Leaflet
Currently, Leaflet is added in the app, and an empty HTML div is added to a GUI. Leaflet now needs to be initialized as described in the Leaflet documentation.
Create a new file named main.js: this will be our main Javascript file.
It will be executed only on the client-side of RPGM. Let's create a simple initializeMap
function:
function initializeMap(){
const mapInstance = L.map('map');
mapInstance.setView([51.505, -0.09], 13);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(mapInstance);
}
This function will create a default map zoomed on a London district.
The map
part of the L.map('map')
line is the ID of our HTML div,
which is correctly map
.
But when to call this Javascript function? We have to call it when the user
enter the correct GUI. To detect when the user enter a GUI, we can use
a Javascript RPGM event called didEnterStep
. Add to your Javascript file:
But, how to know in which step or GUI the user just got in? The didEnterStep
event is called with an argument which is the step ID defined in
your project sequence of the current step. Modify the script to check
if the user is correctly in the GUI:
function initializeMap(currentStep){
// Stop if the user is not in the correct GUI
if(currentStep !== 'leaflet'){
return;
}
// Initialize map
const mapInstance = L.map('map');
mapInstance.setView([51.505, -0.09], 13);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(mapInstance);
}
RPGM.on('didEnterStep', initializeMap); // Function called when entered a new step
Above, the value leaflet
refers to the ID of the GUI in the Sequencer
(by default leaflet
on this example since we named
our GUI file leaflet.pgui
).
One last thing, it is a good practice to make sure that some parts of your code are idempotent, meaning that a function can be call multiple times without changing the result beyond the initial application.
In our example, we will move the mapInstance
variable
to the global window
object and initialize it with null
.
The final script is:
window.mapInstance = null;
function initializeMap(){
// Stop if the user is not in the correct GUI
if(RPGM.getCurrentStepId() !== 'leaflet'){
return;
}
// Stop if already initialized
if(window.mapInstance !== null){
return;
}
// Initialize map
window.mapInstance = L.map('map');
window.mapInstance.setView([51.505, -0.09], 13);
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(window.mapInstance);
}
RPGM.on('didEnterStep', initializeMap); // Function called when entered a new step
Finishing the project
Do not forget to add main.js in the Custom JS/CSS files setting of the .ppro.
And check that your .pgui file has leaflet
in the ID field in the Sequencer.
Also, the Leaflet documentation says the HTML div need a defined height, so head to
the CSS tab of .ppro file and add #map {height: 500px;}
:
Export or launch the app and voilĂ !
You can now learn how to communicate between R and Javascript in the next tutorial.