-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vue htmlwidget container #11
Comments
Gior Testlibrary(htmltools)
library(htmlwidgets)
library(shiny)
library(vueR)
# remotes::install_github("JohnCoene/gior")
library(gior)
data("country_data")
gi <- country_data %>%
gior() %>%
g_data(from, to, value)
# handle non-standard behaviors by some widgets
get_widget_data <- function(widget) {
as.tags(widget)[[2]]$children[[1]]
}
tl <- tagList(
vueR::html_dependency_vue(minified = FALSE),
htmlDependency(
"htmlwidgets",
packageVersion("htmlwidgets"),
src = system.file("www", package = "htmlwidgets"),
script = "htmlwidgets.js"
),
tags$div(
id = "app",
tag('html-widget', list(
giorOutput('gi'),
`:x` = 'x',
`name` = 'gior' # ideally we find a way to avoid this
))
),
tags$script(HTML(
sprintf("
Vue.component(
'html-widget',
{
props: ['x', 'name'],
template: '<div><slot></slot></div>',
methods: {
// Copied from HTMLWidgets code
// Implement a vague facsimilie of jQuery's data method
elementData: function(el, name, value) {
if (arguments.length == 2) {
return el['htmlwidget_data_' + name];
} else if (arguments.length == 3) {
el['htmlwidget_data_' + name] = value;
return el;
} else {
throw new Error('Wrong number of arguments for elementData: ' +
arguments.length);
}
},
updateWidget: function() {
var component = this;
// use HTMLWidgets.widgets to give us a list of available htmlwidget bindings
var widgets = HTMLWidgets.widgets;
// assume there might be lots, so filter for the one we want
// in this case, we want jsonedit
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
// get our htmlwidget DOM element
var el = this.$el.querySelector('.html-widget');
var instance = this.elementData(el, 'init_result')
widget.renderValue(
el,
this.x,
instance
);
}
},
mounted: function() {
if(typeof(this.x) === 'undefined' || this.x === null) { return }
var component = this;
// use HTMLWidgets.widgets to give us a list of available htmlwiget bindings
var widgets = HTMLWidgets.widgets;
// assume there might be lots, so filter for the one we want
// in this case, we want jsonedit
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
// get our htmlwidget DOM element
var el = this.$el.querySelector('.html-widget');
// get our htmlwidget instance with initialize
var instance = widget.initialize(el);
this.elementData(el, 'init_result', instance);
widget.renderValue(
el,
this.x,
instance
);
},
// updated not working since does not watch deep
// but if the expectation is that data and options are replaced completely
// then updated will trigger
updated: function() {
this.updateWidget()
},
watch: {
x: {
handler: function() {console.log('updating');this.updateWidget()},
deep: true
}
}
}
)
var app = new Vue({
el: '#app',
data: () => (%s)
})
",
get_widget_data(gi)
)
))
)
browsable(tl)
|
Leaflet testnote: example does not update data yet. library(htmltools)
library(htmlwidgets)
library(shiny)
library(vueR)
library(dplyr)
library(leaflet)
get_widget_data <- function(widget) { as.tags(widget)[[2]]$children[[1]] }
# functions from leaflet example
rand_lng <- function(n = 10) rnorm(n, -93.65, .01)
rand_lat <- function(n = 10) rnorm(n, 42.0285, .01)
p <- leaflet() %>%
addTiles() %>%
addCircles(rand_lng(50), rand_lat(50), radius = runif(50, 50, 150))
tl <- tagList(
vueR::html_dependency_vue(minified = FALSE),
htmlDependency("htmlwidgets", packageVersion("htmlwidgets"), src = system.file("www", package = "htmlwidgets"), script = "htmlwidgets.js" ),
p$dependencies,
tags$div(
tags$button("update data", onclick = "updateData()")
),
tags$div(id = "app", tag('html-widget', list(leafletOutput("pl"), `:x` = 'x', `name` = 'leaflet' )) ),
tags$script(HTML(
sprintf("
Vue.component(
'html-widget',
{
props: ['x', 'name'],
template: '<div><slot></slot></div>',
methods: {
elementData: function(el, name, value) {
if (arguments.length == 2) {
return el['htmlwidget_data_' + name];
} else if (arguments.length == 3) {
el['htmlwidget_data_' + name] = value;
return el;
} else {
throw new Error('Wrong number of arguments for elementData: ' +
arguments.length);
}
},
updateWidget: function() {
var component = this;
var widgets = HTMLWidgets.widgets;
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
var el = this.$el.querySelector('.html-widget');
var instance = this.elementData(el, 'init_result')
widget.renderValue(
el,
this.x,
instance
);
}
},
mounted: function() {
var component = this;
var widgets = HTMLWidgets.widgets;
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
var el = this.$el.querySelector('.html-widget');
var instance = widget.initialize(el);
this.elementData(el, 'init_result', instance);
widget.renderValue( el, this.x, instance);
},
updated: function() {
this.updateWidget()
},
watch: {
x: {
handler: function() {console.log('updating');this.updateWidget()},
deep: true
}
}
}
)
var app = new Vue({
el: '#app',
data: () => (%s)
})
function updateData() {
console.log('data', app)
}
",
get_widget_data(p)
)
))
)
browsable(tl) |
@FrissAnalytics nice to see that |
yep! Tried to get the leaflet data in the example above. Turned out it's a pretty complicated object with a highly non-trivial structure, unless you are familiar how the shiny leaflet implementation works. Would be much cleaner to have access to the proxy and to manipulate the widget instance from server.R. |
@FrissAnalytics Here is a little more complicated example with a
|
@FrissAnalytics I probably should have started with a simpler example and then built from there. Here is a Vuetify data table with
|
reactable
has an underappreciatedWidgetContainer
that handleshtmlwidgets
(see lines ). I thinkvueR
should have a similar structure but without thetags
for data and options. Here is a very rough draft example that needs significant improvement, iteration, and testing.The text was updated successfully, but these errors were encountered: