A simple scenario - markers chart on a Leaflet map. How to replace the chart with another?
If we do have a Shiny server we’ll write a Shiny app (or .Rmd) and be done with it.
But what if we don’t? How to enjoy a little chart selection without Shiny server’s heavy machinery?
Lets use a Markdown document with some extra JavaScript to do the job!
library(dplyr)
library(echarty)
data1 <- '
lon,lat,time,name,desc,area
-117.213417,32.822426,"2020-02-02","Clairmont","mex.jpg","SD"
-116.837258,33.041465,"2020-03-02","Ramona","👽","SD"
-117.146883,32.731749,"2020-04-02","Zoo","mex.jpg","SD"
-116.792351,32.821695,"2020-04-02","Alpine","👽","SD"
-116.567946,33.067508,"2020-06-02","Julian","👽","SD"
-118.838408,34.202133,"2020-04-02","1000oaks","kim","LA"
-118.435860,34.000473,"2020-06-02","StMonica","https://i.imgur.com/oUTzyvG.png","LA"
-118.045643,34.178955,"2020-06-02","Pasadena","https://i.imgur.com/zTw7b5h.jpg","LA"
-118.845374,34.039848,"2020-07-02","Malibu","https://image.flaticon.com/icons/png/64/129/129138.png","LA"
'
df <- read.csv(text=data1, header=TRUE)
plt <- function(df, name='name?') {
p <- df %>% ec.init(load='leaflet')
p$x$opts$tooltip <- list(ey='')
p$x$opts$name <- name # for one option of the dropdown
p$x$opts$leaflet <- list(zoom=9, roam=TRUE,
center=c(sum(range(df$lon))/2, sum(range(df$lat))/2))
p$x$opts$series <- list(list(
type='scatter', coordinateSystem='leaflet',
# markers as images: works, but not with imgur.com, 'circle' does not work
# symbol = htmlwidgets::JS("function(params) { //console.log(params);
# if (params[4].endsWith('.jpg')) return ('image://'+params[4]);
# if (params[4].endsWith('.png')) return ('image://'+params[4]);
# return('circle');
# }"), symbolSize=44, symbolKeepAspect=TRUE,
symbol = 'pin', symbolSize=44,
itemStyle=list(color= if (name=='LA') 'red' else 'green'),
encode=list(tooltip=list(2,3,5)) ) # Js count 0,1,2..
)
p
}
p1 <- plt(df %>% filter(area=='LA'), 'LA')
p2 <- plt(df %>% filter(area=='SD'), 'SD')
p1$x$o2 <- p2$x$opts # save the second plot data
p1
And here is the JavaScript code
var chopt = {p1:null, p2:null, gpx:null};
function getData() {
try {
// find 1st htmlwidget, easy when there is only one ;-)
const inlineJsonElement = document.querySelector(
`script[type="application/json"][data-for^=htmlwidget-]`
);
const data = JSON.parse(inlineJsonElement.textContent);
return data;
} catch (err) {
console.error(`Couldn't read JSON data from htmlwidget`, err);
}
}
document.addEventListener("DOMContentLoaded", function() {
const pp = getData();
chopt.p1 = pp.x.opts;
chopt.p2 = pp.x.o2;
var pddl = document.querySelector('[id="pddl"]');
var o = document.createElement("option");
o.text = chopt.p1.name; pddl.options.add(o);
o = document.createElement("option");
o.text = chopt.p2.name; pddl.options.add(o);
pddl.addEventListener('change', (event) => {
var wt = document.querySelector("[id^=htmlwidget-]");
// get the ECharts object and replace options
var p = get_e_charts(wt.id);
switch(event.target.value) {
case chopt.p1.name:
p.setOption(chopt.p1, true);
break;
case chopt.p2.name:
p.setOption(chopt.p2, true);
break;
default:
alert('selection not found');
}
});
});
TODO: add a file upload input for .GPX files
Users could view their own data. It all happens in the browser(client), so again no server needed.