Comments (6)
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.
from vuer.
Gior Test
library(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)
from vuer.
Leaflet test
note: 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)
from vuer.
@FrissAnalytics nice to see that leaflet
works. In a shiny
context I'd like to see if we can take advantage of the proxy
methods provided by leaflet
.
from vuer.
@FrissAnalytics Here is a little more complicated example with a plotly
htmlwidget in Vuetify table cells. It is a mess but does prove that it can be done.
# plotly htmlwidgets in Vuetify table cells
library(htmltools)
library(vueR)
library(plotly)
library(dplyr)
iris_tbl <- iris %>%
group_by(Species) %>%
summarize(
plot_data = get_widget_data(
plot_ly(x = ~Sepal.Width, y = ~Sepal.Length, data = cur_data())
)
)
get_widget_data <- function(widget) { htmltools::as.tags(widget)[[2]]$children[[1]] }
tl <- tagList(
plot_ly()$dependencies,
htmlwidgets:::getDependency("plotly"),
vueR::html_dependency_vue(minified = FALSE),
tags$head(
tags$link(href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css", rel="stylesheet"),
tags$script(src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js")
),
tags$div(
id = "app",
tag(
"v-data-table",
list(
`:headers` = "headers",
`:items` = "tbl_data",
tag(
"template",
list(
`v-slot:item.plot_data` = "{ item }",
tag(
"html-widget",
list(
style = "width: 100%;",
`:x` = "JSON.parse(item.plot_data).x",
`name` = "plotly",
tags$div(class="html-widget plotly", style="width:100%; height:400px;", `:id`="'cell-' + item.Species")
)
)
)
)
)
)
),
tags$script(HTML(
"
Vue.component(
'html-widget',
{
props: ['x', 'name'],
template: '<div class=\"html-widget\"><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() {
// see comments in mounted which is nearly identical except in update we do not initialize or attach
// initial data to the element. we could clean this up and make one function.
var component = this
// use HTMLWidgets.widgets to give us a list of available htmlwidget bindings
var widgets = window.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')
if(typeof(instance) === 'undefined') {
// get our htmlwidget instance with initialize
instance = widget.initialize(el);
this.elementData(el, 'init_result', instance);
widget.renderValue(
el,
this.x,
instance
)
}
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
}
}
}
)
"
)),
tags$script(HTML(
sprintf(
'
const app = new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
headers: %s,
tbl_data: %s
}),
});
',
jsonlite::toJSON(lapply(colnames(iris_tbl), function(x){list(text=x,value=x)}), auto_unbox=TRUE),
jsonlite::toJSON(iris_tbl, auto_unbox = TRUE)
)
))
)
browsable(tl)
from vuer.
@FrissAnalytics I probably should have started with a simpler example and then built from there. Here is a Vuetify data table with iris
data.
# plotly htmlwidgets in Vuetify table cells
library(htmltools)
library(vueR)
tl <- tagList(
vueR::html_dependency_vue(minified = FALSE),
tags$head(
tags$link(href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css", rel="stylesheet"),
tags$link( href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900", rel="stylesheet"),
tags$link(href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css", rel="stylesheet"),
tags$script(src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js")
),
tags$div(
id = "app",
ref = "app",
tag(
"v-app",
list(
tag(
"v-main",
list(
tag(
"v-data-table",
list(
`:headers` = "headers",
`:items` = "tbl_data"
)
)
)
)
)
)
),
tags$script(HTML(
sprintf(
'
const app = new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
headers: %s,
tbl_data: %s
}),
});
',
jsonlite::toJSON(lapply(colnames(iris), function(x){list(text=toupper(x),value=x)}), auto_unbox=TRUE),
jsonlite::toJSON(iris, auto_unbox = TRUE)
)
))
)
browsable(tl)
from vuer.
Related Issues (10)
- Error: path for html_dependency not provided HOT 6
- vue 3 HOT 7
- link vue to crosstalk? HOT 2
- How to link vueR with leaflet? HOT 7
- vuejs clipboard integration
- vue3 reactive input values HOT 6
- Shiny and vuex
- vue Shiny input helper / template HOT 1
- Change installation instructions and other URLs to new Github Org HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vuer.