2018/08/28
In the previous article we added a time zone selection on our clock. Now, let's show those cities on a map! In order to do this I'm going to use the popular plot.ly library.
On the HTML side we need a div where the chart will be injected and a button to click:
<button data-bind="click: $root.showPlot">Show cities map</button>
<div id="plot"></div>
Next, we need to include the plot.ly Javascript file. We use the @JavaScriptResource annotation:
@JavaScriptResource("plotly-latest.min.js")
public class Clock {
...
Note that plotly-latest.min.js is a resource added in our Java package.
The HTML button calls showPlot which is a new method in our Clock class:
@Function
static void showPlot(ClockModel model) {
newPlot("plot", createGeoData(new String[]{"London", "Paris", "Tokyo"},
new double[]{51.5074, 48.8566, 35.6895},
new double[]{-0.1278, 2.3522, 139.6917},
new String[]{"top right", "bottom right", "top center"}),
createGeoLayout());
}
Note the @Function annotation. This method calls newPlot, createGeoData (which receives the list of cities and coordinates) and createGeoLayout.
newPlot is quite simple:
@JavaScriptBody(args = {"divName", "data", "layout"}, body = "Plotly.newPlot(divName, data, layout, {displayModeBar: false})")
public static native void newPlot(String divName, Object data, Object layout);
It just calls from Javascript the Plotly.newPlot method with the given arguments. Since this is something executed from the Javascript side, it is a native method and has a @JavaScriptBody.
How interesting to use the native modifier for this!
createGeoData creates the plot.ly configuration object based on the given arguments and it's again native:
@JavaScriptBody(args = {"cities", "lat", "lon", "textPosition"}, body = "return [{\n" +
" type: 'scattergeo',\n" +
" mode: 'markers+text',\n" +
" text: cities,\n" +
" lon: lon,\n" +
" lat: lat,\n" +
" marker: {\n" +
" size: 10,\n" +
" line: {\n" +
" width: 1\n" +
" }\n" +
" },\n" +
" name: 'Clock cities',\n" +
" textposition: textPosition,\n" +
" }]")
public static native Object createGeoData(String[] cities, double[] lat, double [] lon, String[] textPosition);
createGeoLayout is the least interesting as it just creates a static object with the chart properties:
@JavaScriptBody(args = {}, body = "return {\n" +
" autosize: false,\n" +
" height: 220,\n" +
" margin: {\n" +
" l: 0,\n" +
" r: 0,\n" +
" t: 0,\n" +
" b: 0,\n" +
" pad: 0\n" +
" },\n" +
" geo: {\n" +
" scope: 'world',\n" +
" resolution: 50,\n" +
" lonaxis: {\n" +
" 'range': [-10, 160]\n" +
" },\n" +
" lataxis: {\n" +
" 'range': [20, 70]\n" +
" },\n" +
" showland: true,\n" +
" landcolor: '#EAEAAE'\n" +
" }\n" +
" }")
public static native Object createGeoLayout();
That's it! As usual the full project is available at https://github.com/emilianbold/nbwt-clock-demo