Open cjyetman opened 7 years ago
this would also resolve these issues: #106, #100, and possibly others
@cjyetman I very much like this approach. My main concern would be many networkD3
or other widgets on a page. Here is one solution for custom styling with specificity http://www.buildingwidgets.com/blog/2016/9/7/custom-styling-for-htmlwidgets. onRender
is not always called again on resize
. I cannot remember if this is the case with networkD3
. This solution is also robust to that issue. Let me know if I can help.
thanks @timelyportfolio I knew you'd have something intelligent to say about it
I was hoping to keep the CSS argument to something as simple as a single string, but then we would need something robust/intelligent enough for parsing the CSS and adding the elementId to each rule (no nested CSS rules, boo!). By the way, an ID that starts with a digit, like that created by htmlwidgets:::createWidgetId()
, is not valid CSS and a query for it will fail on some browsers, so I prepended 'hw'. Maybe we could make the css
option a character vector with one rule per element (and a rule with no selector will select the whole widget, or technically the element that contains it)? So the user could pass ...
css <- c("{ background-color: #DAE3F9 !important }",
".nodetext { fill: #000000 }",
".legend text { fill: #FF0000 }")
and the function would do something like this...
# create widget
hw <- htmlwidgets::createWidget(
name = "forceNetwork",
x = list(links = LinksDF, nodes = NodesDF, options = options),
width = width,
height = height,
htmlwidgets::sizingPolicy(padding = 10, browser.fill = TRUE),
package = "networkD3"
)
if (!is.null(css)) {
hw$elementId <- paste0('hw', htmlwidgets:::createWidgetId())
specificcss <- paste(paste0('#', hw$elementId, ' ', css), collapse = '\n')
hw <- htmlwidgets::prependContent(
hw,
htmltools::tags$style(specificcss)
)
}
hw
One major disadvantage to this that I realized is that CSS does not work on elements rendered to canvas, so a reliance on styling/formatting through CSS may not work in the future.
Many of the questions or requests I see about
networkD3
here and on stackoverflow etc. involve some desire to stylize the output beyond the existing parameters available. The more inventive suggestions/answers tend to suggest injecting JavaScript through thelinkDistance
orclickAction
argument, which often works, but is definitely not how it was intended to work, not ideal, and probably liable to muck something up eventually. The alternative, adding more and more parameters to the functions for every imaginable type of stylization, is not ideal either.I propose facilitating a way for the user to pass custom CSS and/or JavaScript when calling the
networkD3
functions. This would allow near limitless stylization without inflating the argument list with a bunch of new parameters.There is a way to do this, suggested by @timelyportfolio on stackoverflow, with the
htmltools
package. That would require movinghtmltools
fromSuggests
toImports
, and it may impact how it shows up in RMarkdown, Shiny, etc.. Otherwise, I'd be happy to hear any suggestions on how to inject custom CSS into a htmlwidget using thehtmlwidgets
package... I think it might be possible by writing a temp CSS file and adding it as a dependency, but it would probably be much more preferable to be able to simply pass it as a character vector.For example, the
forceNetwork
function could accept an argumentcss
and the end of the function could be modified to something like...then a user would be able to do something like this...
If this is implemented, it would make sense to also...
JavaScript injection would be a bit more complicated, but could allow, theoretically, the user to add more interaction than just the
clickAction
, among other things.