Leaflet插件和Leaflet代理

11

我按照这个例子的类比,在闪亮的应用程序中添加了TextPath插件。这很有效:

output$fullscreen_map <- renderLeaflet({
  points <- points_reactive()

  points %>%
    leaflet() %>% 
    addTiles() %>%
    fitBounds(~min(lon), ~min(lat), ~max(lon), ~max(lat)) %>%
    registerPlugin(textPathPlugin) %>%
    onRender("function(el, x, data) {
                data = HTMLWidgets.dataframeToD3(data);
                data = data.map(function(val) { return [val.lat, val.lon]; });
                var layer = L.polyline(data);
                layer.on('mouseover', function () {
                this.setText('  ►  ', {repeat: true, attributes: {fill: 'blue'}});
                });
                layer.on('mouseout', function () {
                this.setText(null);
                });
                layer.addTo(this);
    }", data = points)

})

按照文档的说明,我现在想使用leafletProxy(),这样每当反应式数据源发生更改时,整个地图不会被重新绘制。但遗憾的是,使用以下代码片段:

leafletProxy("fullscreen_map", data = points) %>%
  onRender("function(el, x, data) {
              data = HTMLWidgets.dataframeToD3(data);
              data = data.map(function(val) { return [val.lat, val.lon]; });
              var layer = L.polyline(data);
              layer.on('mouseover', function () {
              this.setText('  ►  ', {repeat: true, attributes: {fill: 'blue'}});
              });
              layer.on('mouseout', function () {
              this.setText(null);
              });
              layer.addTo(this);
  }", data = points)

我认为这不像预期的那样工作。我猜测是因为只有在发生新的渲染时才会调用onRender,而leafletProxy的整个意义就在于不重新渲染?如果我的猜测是正确的,那么是否有其他方法可以实现这一点呢?


3
这是一个有趣的问题... Shiny 具有相当健壮的事件处理功能,所以我认为诀窍在于找到将脚本绑定的正确位置。如果没有 WME ,想要弄清楚这一点可能有点棘手。您是否介意发布一个? - Ian Wesley
1
对我来说,它应该可以工作。如果对JavaScript进行微小的调整,我不会感到惊讶,但需要制作一个MWE,而我现在没有时间。 - Mike Wise
2
@yosukesabai 你能否提供一个最小可重现的示例? - Josh O'Brien
太多内容无法在评论中贴出我的代码,但我没有任何“解决方案”。 所以我只能新建一个问题。 https://dev59.com/NK_la4cB1Zd3GeqPoic2 - yosukesabai
我已经在上面的问题中想出了一个解决方案。我继续测试它是否能够实现我想要的功能(让JavaScript插件在我使用leafletProxy时工作)。 - yosukesabai
显示剩余2条评论
2个回答

1
这可能是以下内容,虽然还有更简洁的方法。
我使用leafletProxy从points_reactive()函数添加折线图层,同时将组设置为reactive。 我监听地图的layeradd事件,如果添加了一个具有reactive组的图层,则添加textPath。
output$fullscreen_map <- renderLeaflet({
  points <- points_reactive()

  points %>%
    leaflet() %>% 
    addTiles() %>%
    fitBounds(~min(lon), ~min(lat), ~max(lon), ~max(lat)) %>%
    registerPlugin(textPathPlugin) %>%
    onRender("function(el, x, data) {
              var mymap = this;

              mymap.on('layeradd',
                function(e) {
                  console.log(e);
                  var layer = e.layer;

                  if (layer.groupname == 'reactive') {
                    layer.on('mouseover', function () {
                      this.setText('  ►  ', {repeat: true, attributes: {fill: 'blue'}});
                    });
                    layer.on('mouseout', function () {
                      this.setText(null);
                    });
                  }
                }
              );

            }", data = points)

  })

  observeEvent(input$clickme,{
               points <- points_reactive()

               leafletProxy('fullscreen_map') %>%
                 addPolylines(lng=points$lon, lat=points$lat, group='reactive')

  }
)
}

0
文档指出: 活动输入和影响renderLeaflet表达式的表达式将导致整个地图从头开始重绘,并重置地图位置和缩放级别。
听起来你需要深入了解Leaflet或触发leafletProxy,确保数据源不会改变,通过使用两个数据源...(也许“代理”在这里是一个错误的名称)。
看看这些插件中是否有一个可以帮助你: https://leafletjs.com/plugins#dynamiccustom-data-loading

我试图理解onRender的工作原理,以及是否可以更新它以响应其他事件。onRender将代码存储在小部件的jsHooks[['render']]中。请参见此处附近的行,以及函数addHook。https://github.com/ramnathv/htmlwidgets/blob/master/R/htmlwidgets.R#L155。然后,在JavaScript代码中处理此存储的代码,有两个位置在`inst/www/htmlwidgets.js`中。我认为可能会从JavaScript代码的某个地方进行另一个`evalAndRun`的调用,但是无法超越这一点... - yosukesabai
这是正确的方向吗?我仍然需要学习整个闪亮系统的工作原理,对于这些交互式工具开发,我是一个完全的新手... - yosukesabai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接