Sankey Network(在 R blogdown 中)无法在 Firefox 上正确呈现

Sankey Network (within R blogdown) won't render properly on Firefox

我的 blogdown 站点(包括绘图、markdown 等)通常在 Chrome 和 Firefox 上都能正常显示。顺便说一下,它们通常在 IE 上也能正常工作,尽管我不太关心那个浏览器。为了完整性,我将把它包括在讨论中。

当我使用 networkD3 R 包在 blogdown 中包含一个 Sankey Network 时,在 Chrome 和 IE 中呈现 'properly',但在 Firefox 中不呈现。 Firefox 人为地缩小了 Sankey Network 的大小,见下文:

这是我正在使用的代码。在将 Sankey Networks 与 blogdown 一起使用时,我可以做些什么来让 Sankey Network 在 Firefox 上正确呈现?

我确实把 {r, fig.width=x, fig.height=y} 搞得一团糟。增加 xy 会增加整体图像的大小,同时将整体图像保持在相同的 'small' blogdown 框中,从而有效地减小 Sankey Network 的大小甚至比上面显示的还要远。减小 xy 只会减小图像大小,也会使 Sankey Network 比上面显示的更小。我想我需要解决渲染问题(在 Firefox 中存在,在 Chrome 中不存在)。

---
title: "Data Analysis"
date: "2019-01-01T18:00:00-09:00"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(blogdown)
library(networkD3)
```

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

```{r sankey, echo=FALSE, error=FALSE, message=FALSE, warning=FALSE}
source <- c("A", "A", "B", "C", "D", "D", "E", "E")
target <- c("D", "E", "E", "D", "H", "I", "I", "H")
values <- c(1, 22, 5, 5, 5, 10, 10, 10)
nodes <- data.frame(name = unique(c(source, target)))
links <- data.frame(source = match(source, nodes$name) - 1,
                    target = match(target, nodes$name) - 1,
                    value = values)
sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
              Target = "target", Value = "value", NodeID = "name", 
              units = "unitX", fontSize = 12, nodeWidth = 20)
```

[编辑] 我已经更新了我的代码,如下所示, 但是,它仍然呈现 'small',没有明显的变化:(

---
title: "Data Analysis"
date: "2019-01-01T18:00:00-09:00"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(blogdown)
library(networkD3)
```

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

```{r sankey, echo=FALSE, error=FALSE, message=FALSE, warning=FALSE}
source <- c("A", "A", "B", "C", "D", "D", "E", "E")
target <- c("D", "E", "E", "D", "H", "I", "I", "H")
values <- c(1, 22, 5, 5, 5, 10, 10, 10)
nodes <- data.frame(name = unique(c(source, target)))
links <- data.frame(source = match(source, nodes$name) - 1,
                    target = match(target, nodes$name) - 1,
                    value = values)

sn <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source", 
                    Target = "target", Value = "value", NodeID = "name", 
                    units = "unitX", fontSize = 12, nodeWidth = 20)

htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')

# also tried this to no avail
# htmlwidgets::onRender(sn, 'document.getElementById().getElementsByTagName("svg")[0].setAttribute()')            
```

根据 Github issue 中的讨论,似乎解决方案是在 htmlwidgets::onRender 命令中设置桑基图的正确索引号。

所以如果桑基图是页面上的第一个 SVG,命令应该是:

htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[0].setAttribute("viewBox", "")')

如果桑基图是页面上的第二个 SVG,命令应该是:

htmlwidgets::onRender(sn, 'document.getElementsByTagName("svg")[1].setAttribute("viewBox", "")')

等等


更新 2020.04.02

我目前首选的方法是使用 htmlwidgets::onRender 专门针对传递的 htmlwidget 包含的 SVG,就像这样...

onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')

然后可以根据需要专门针对您页面上的尽可能多的 htmlwidgets 执行此操作,例如...

onRender(sn, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')

onRender(sn2, 'function(el) { el.querySelector("svg").removeAttribute("viewBox") }')

的基础上,这里有一个 hack 对我有用,可以让多个 Sankey 图在 Firefox 中正确呈现。

将此代码放入您的 Rmd:

htmlwidgets::onStaticRenderComplete('$.each( document.getElementsByTagName("svg"), function( index, value ){value.setAttribute("viewBox", null);});')

渲染完所有sankeys后,它将遍历并将svg对象的所有viewBox属性设置为null,以便所有sankeys填充它们的边界框。