Closed TrantorM closed 1 month ago
Very good question, and I would classify this as advanced usage. vuejs
does not know how to automatically update htmlwidgets
, since they are not components
. We will need to watch selected
and explicitly provide instructions to update the map. I think this gets close, but let me know if not.
library(htmltools)
library(leaflet) # I installed leaflet 1.0 with devtools::install_github("timelyportfolio/leaflet@v1.0")
library(leaflet.extras)
library(vueR)
topojson <- readr::read_file('https://rawgit.com/TrantorM/leaflet-choropleth/gh-pages/examples/basic_topo/crimes_by_district.topojson')
map <- leaflet() %>%
setView(-75.14, 40, zoom = 11) %>%
addProviderTiles("CartoDB.Positron") %>%
addGeoJSONChoropleth(
topojson,
valueProperty = "{{selected}}",
group = "choro"
)
ui <- tagList(
tags$div(
id="app",
tags$select("v-model" = "selected",
tags$option("disabled value"="","Select one"),
tags$option("incidents"),
tags$option("dist_num")
),
tags$span(
"Selected: {{selected}}"
),
tags$div(map)
),
tags$script(
"
var app = new Vue({
el: '#app',
data: {
selected: 'incidents'
},
watch: {
selected: function() {
// uncomment debugger below if you want to step through
//debugger;
// only expect one
// if we expect multiple leaflet then we will need
// to be more specific
var instance = HTMLWidgets.find('.leaflet');
// get the map
// could easily combine with above
var map = instance.getMap();
// we set group name to choro above
// so that we can easily clear
map.layerManager.clearGroup('choro');
// now we will use the prior method to redraw
var el = document.querySelector('.leaflet');
// get the original method
var addgeo = JSON.parse(document.querySelector(\"script[data-for='\" + el.id + \"']\").innerText).x.calls[1];
addgeo.args[7].valueProperty = this.selected;
LeafletWidget.methods.addGeoJSONChoropleth.apply(map,addgeo.args);
}
}
});
"
),
html_dependency_vue(offline=FALSE)
)
browsable(ui)
live example; I did have to change to update the valueProperty
. could have possibly used Vue.nextTick
also
https://bl.ocks.org/timelyportfolio/1a7d43b14a23665857ad5ef421d9ac41
After all said and done, not sure if it is worth or not unless you plan to use other vuejs
components.
Glad it worked. I will try to post some alternative solutions over the next couple of days. Do you plan to integrate in a bigger application or in a bigger Shiny context? Most of the performance gain is not coming from vuejs
here, and if a minimal application, we could just stick with vanilla JS.
The idea is to build an atlas with a collection of distribution maps in topic of prehistory (mainly point geometries), that one can compare with each other (like in a simple GIS viewer but in the browser). The project is in the very beginning, I just want to check, what's possible in R.
In the atlas I would like to include also the results from the genetics regarding the prehistoric migration and the distribution of modern YDNA-haplogroups (quite a lot of polygon geometries with several properties).
In this example I try to visualise the Ratio of two different haplogroups. The initial representation is correct, but when I select an other property and go back to the initial haplogroup R1b
, the calculated results are wrong. Any Idea, how to fix that?
I try to avoid a solution with Shiny.
I would be interested in alternative solutions.
Is it possible to assign a function to the addgeo.args[7].valueProperty
expression in order to compute the valueProperty
based on the selected property? Something like addgeo.args[7].valueProperty = function(feature) {return feature.properties.{{selected}} / feature.properties.area_sqmi}
. I can't get it running.
library(htmltools)
library(leaflet) # I installed leaflet 1.0 with devtools::install_github("timelyportfolio/leaflet@v1.0")
library(leaflet.extras)
library(vueR)
topojson <- readr::read_file('https://rawgit.com/TrantorM/leaflet-choropleth/gh-pages/examples/basic_topo/crimes_by_district.topojson')
map <- leaflet() %>%
setView(-75.14, 40, zoom = 11) %>%
addProviderTiles("CartoDB.Positron") %>%
addGeoJSONChoropleth(
topojson,
valueProperty = JS(paste0("function(feature) {return feature.properties.{{selected}} / feature.properties.area_sqmi}")),
group = "choro"
)
ui <- tagList(tags$div(id="app",
tags$select("v-model" = "selected",
tags$option("disabled value"="","Select one"),
tags$option("incidents"),
tags$option("area_sqmi"),
tags$option("dist_num")),
tags$span("Selected: {{selected}}"),
tags$div(map)
),
tags$script(
"
var app = new Vue({
el: '#app',
data: {
selected: 'incidents'
},
watch: {
selected: function() {
// uncomment debugger below if you want to step through debugger;
// only expect one; if we expect multiple leaflet then we will need to be more specific
var instance = HTMLWidgets.find('.leaflet');
// get the map; could easily combine with above
var map = instance.getMap();
// we set group name to choro above, so that we can easily clear
map.layerManager.clearGroup('choro');
// now we will use the prior method to redraw
var el = document.querySelector('.leaflet');
// get the original method
var addgeo = JSON.parse(document.querySelector(\"script[data-for='\" + el.id + \"']\").innerText).x.calls[1];
addgeo.args[7].valueProperty = 'function(feature) {return feature.properties.{{selected}} / feature.properties.area_sqmi}';
LeafletWidget.methods.addGeoJSONChoropleth.apply(map,addgeo.args);
}
}
});
"
),
html_dependency_vue(offline=FALSE,minified=FALSE))
browsable(ui)
Thanks for this great package. How can one link a reactive vueR variable to select topojson properties in leaflet? I tried the following example. The preselection
incidents
is working, but leaflet doesn't rerendering when I select an other property. Any Idea, how to fix that?