保存/加载可透视表配置

Geo*_*tas 6 r r-markdown htmlwidgets rpivottable

我在几个(rmarkdown)网页上使用rpivottable。

我在这里看到将表配置保存到Cookie或从Cookie恢复表的示例。由于我的Java语言不好,我想问一下是否有可能rmd在表控件的顶部以编程方式在页面中添加两个按钮,从而允许用户保存/加载其首选的表配置(到Cookie或到本地文件(如果可能)。您能否提供示例代码来实现这一目标?

谢谢。

Kat*_*Kat 6

这花了一段时间。我使用本地存储。我这里有很多样式,但没有必要。我使用了 的输出flexdashboard,因为这往往会给我带来最多的 JS 问题。

<style>
body {    /*push content away from far right and left edges*/
  margin-right: 2%;
  margin-left: 2%;
}
.rpivotTable {
  overflow:auto;
  resize: both;
  box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56);
  -moz-box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56);
  -webkit-box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56);
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
  border: 1px solid white;
  padding: 5px;
  margin: 5px 20px 50px 5px;
}
.btn {
  vertical-align: middle;
  -moz-box-shadow: 0px 10px 14px -7px #000000;
  -webkit-box-shadow: 0px 10px 14px -7px #000000;
  box-shadow: 0px 10px 14px -7px #000000;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  border: .5px solid black;
  display: inline-block;
  font-size: 1.3em; 
  padding: .3em 0px;
  width: 18em;
  text-decoration: none; /*no underline!!*/
  cursor: pointer;
}
.btn:active { /*simulate movement*/
  position: relative;
  top: 1px;
}
</style>
Run Code Online (Sandbox Code Playgroud)

我使用了在其他问题中找到的内容。

## R Markdown

<div style="margin-right:5%;">

`r stringi::stri_rand_lipsum(10)`

</div>

```{r cars}

library(rpivotTable)

data(mtcars)
names(mtcars)[10] <- "George.Dontas"

```

Here is the **first** Div.

## Including Plots

Do you want to save or restore the previously saved pivot tables' configuration?

<a id='saveBtn' class='btn' style="background-color:#003b70;color:white;">Save Current Configuration</a>
<a id='restoBtn' class='btn' style="background-color:#b21e29;color:white;">Restore Previous Configuration</a>

```{r pressure, echo=FALSE, fig.show="hold"}
rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px")
```

```{r morePressure, echo=FALSE, fig.show="hold"}
rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px")
```

This should be a different aspect of the report.

```{r evenMorePressure, echo=FALSE, fig.show="hold"}
rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px")
```
Run Code Online (Sandbox Code Playgroud)

这是 JS/JQuery...它有点丑陋,而且是两者(JS/JQuery)的大杂烩。

```{r listenOrElse,results="as-is",engine="js"}

// save current state of the tables to my browser
setTimeout(function(){       //add the events first
  document.querySelector('a#saveBtn').addEventListener('click', savoring);
  document.querySelector('a#restoBtn').addEventListener('click', giveItBack);
  function savoring() {                             // function to save
    el = document.querySelectorAll('.rpivotTable');
    for(i=0; i < el.length; i++){
      elId = el[i].getAttribute("id");
      stringy = $('#' + elId).data("pivotUIOptions"); // collect rows/columns filters
      delete stringy['aggregators'];                 // remove the arbitrary
      delete stringy['renderers'];
      stringy2 = JSON.stringify(stringy);            // make it one key:value
      window.localStorage.setItem('table' + i, stringy2); // store it!
    }
  };
  function giveItBack() {                           // function to regurgitate
    el = document.querySelectorAll('.rpivotTable');
    console.log("working on the giver");
    ods = [...el[0].ownerDocument.scripts];         // make it an array
    for(j=0; j < el.length; j++){
      elId = el[j].getAttribute("id");
      where = ods.filter(function(ods){             // filter scripts for table data
        return ods.dataset['for'] === elId;
      })[0].innerHTML; 
      where2 = JSON.parse(where).x.data;            // WOOO HOO! I figured it out!!
      where3 = HTMLWidgets.dataframeToD3(where2);   // finally sheesh!!
      gimme = window.localStorage.getItem('table' + j); // get storage
      $('#' + elId).pivotUI(where3, JSON.parse(gimme), true, "en"); // put it back!
    }
  }
},100);

```
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述



更新

感谢您指出一些改进的机会,@George Dontas。此更新更改了配置的保存方式。不过,我确信仍然有方法可以改进它。

此更新将文件或网页名称添加为用于存储信息的键值对的一部分。现在,网页/脚本的名称和表编号都需要匹配才能更新表。此外,当配置无法恢复时,这会提醒用户。如果没有保存任何内容并且没有保存文件名和表匹配配置,则会出现此警报。

保存配置的更新

中有一行新代码和一行修改后的代码savoring()

新的:

path = window.location.pathname.split("/").pop().split(".").slice()[0]; //f name
Run Code Online (Sandbox Code Playgroud)

修改的:

window.localStorage.setItem(path + '_table' + i, stringy2); // store it
Run Code Online (Sandbox Code Playgroud)

整个功能发生变化:

  function savoring() {                     // function to save
    el = document.querySelectorAll('.rpivotTable');
    path = window.location.pathname.split("/").pop().split(".").slice()[0];
    for(i=0; i < el.length; i++){
      elId = el[i].getAttribute("id");
      stringy = $('#' + elId).data("pivotUIOptions"); // collect filters
      delete stringy['aggregators'];        // remove the arbitrary
      delete stringy['renderers'];
      stringy2 = JSON.stringify(stringy);   // make it one key:value
      window.localStorage.setItem(path + '_table' + i, stringy2);  // store it
    }
  };
Run Code Online (Sandbox Code Playgroud)

恢复配置的更新

该函数中几乎没有新行。必须收集名称,就像更改一样savoring()。此外,此功能现在还向用户发出警报。

我从基本的系统警报开始,但它不符合我的口味,所以我还开发了一个自定义警报框。我已将两者都包含在这里。

基本警报和更新配置检索

从我最初的答案到发出基本警报的唯一变化是函数中的以下代码行giveItBack()

path = window.location.pathname.split("/").pop().split(".").slice()[0]; //f name
Run Code Online (Sandbox Code Playgroud)

  if(window.localStorage.getItem(path + '_table' + j) === null) {
    jj = j + 1;
    alert("WARNING: There is no saved pivot table configuration for " + path + "'s table " + jj + ".");
    continue; // don't update, go to next table (if more than 1)
  }
Run Code Online (Sandbox Code Playgroud)

这是完整的giveItBack()函数(注意这里有notice(msg)msg,但被注释掉了):

function giveItBack() {               // function to regurgitate
    el = document.querySelectorAll('.rpivotTable');
    console.log("working on the giver");
    ods = [...el[0].ownerDocument.scripts];   // make it an array
    path = window.location.pathname.split("/").pop().split(".").slice()[0]; //name
    for(j=0; j < el.length; j++){
      elId = el[j].getAttribute("id");
      where = ods.filter(function(ods){     // filter scripts data
        return ods.dataset['for'] === elId;
      })[0].innerHTML; 
      where2 = JSON.parse(where).x.data;    // WOOO HOO! I figured it out!!
      where3 = HTMLWidgets.dataframeToD3(where2); // finally formatted
      // is there a saved configuration that matches this file and table?
      if(window.localStorage.getItem(path + '_table' + j) === null) {
        jj = j + 1;
                  //this is for the standard alert box
        alert("WARNING: There is no saved pivot table configuration for " + path + "'s table " + jj + ".");
        //msg = "<b>WARNING</b><br><br>There is no saved pivot table configuration for<br>" + path + "."
        //notice(msg); //this is for the custom alert box
        continue; // go to next loop
      }
      gimme = window.localStorage.getItem(path + '_table' + j); // get storage
      $('#' + elId).pivotUI(where3, JSON.parse(gimme), true, "en"); // put it back!
    }
  };
Run Code Online (Sandbox Code Playgroud)

enter image description here

自定义警报和更新配置检索

如果您选择对警报消息使用更自定义的方法,则还有更多内容(幸运的是,它应该是复制和粘贴)。您将使用giveItBack基本警报更新中的功能,但注释掉或删除alert(...并取消注释msgnotice()

.btn对于我原来的答案中的CSS,更新to .btn, #noted.btn:activeto的样式btn:active, #noted:active

这是自定义警报的剩余 CSS。您可以将此 CSS 添加到其他样式标签或将它们分开。

<style>
#notice-wrapper {
  width: 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1000000;
  background: transparent;
  display: none;
  transition: opacity 1s ease-in;
}
#notice-box {
  -moz-box-shadow: 0px 10px 14px -7px #000000;
  -webkit-box-shadow: 0px 10px 14px -7px #000000;
  box-shadow: 0px 10px 14px -7px #000000;
  border-radius: 4px;
  border: .5px solid black;
  width = 300px;
  background: #003b70;
  color: white;
  min-height: 200px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -100px 0 0 -150px;
}
#notHead {
  text-align: center;
  font-size: 1.3em;
  padding: 4px;
  margin: 2.5em;
  font-family: Verdana, sans-serif;
}
#noted {
  background: #b21e29;
  margin: .5em;
  width: 120px;
  font-family: Verdana, sans-serif;
}
</style>
Run Code Online (Sandbox Code Playgroud)

接下来是自定义警报框的 JS。我将此函数放在setTimeout(function(){withsavoring()和中giveItBack()

  function notice(msg) {
    function cr() {
      if(document.querySelector('#notice-wrapper') === null) {
          wrapper = document.createElement('div');
          wrapper.id = 'notice-wrapper';
          html = "<div id='notice-box'><h2 id='notHead'></h2><div id='noticeBtns'>";
          html += "<button id='noted'>OK</button></div></div>";
          wrapper.innerHTML = html;
          document.body.appendChild(wrapper);
      }
      insta = document.querySelector('#notice-wrapper');
      placer(insta);
      return(insta);
    }
    function placer(insta) {
      wrapper = insta;
      winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientheight;
      wrapper.style.height = winHeight + "px";
    }
    function showy(el) {
      el.style.display = "block";
      el.style.opacity = 1;
    }
    function goAway(el) {
      el.style.opacity = 0;
      setTimeout(function(){
        el.style.display = "none";
      }, 1000);
    }
    function takeAction(msg) {
      insta = cr();
      insta.querySelector('#notHead').innerHTML = msg;
      showy(insta);
      insta.querySelector('#noted').addEventListener('click', function() {
        goAway(insta);
      }, false);
    }
    takeAction(msg);
  }
Run Code Online (Sandbox Code Playgroud)

当然,通过此自定义选项,您有机会按照您认为合适的方式设置其样式。样式控制不是系统警报消息系统的一个选项。

在此输入图像描述

  • 当谈到使用按钮标签与锚标签时,可以得出一个意见。但是,如果按钮是锚点,我更喜欢锚点标签。如果您使用表单按钮,它可能是一个输入标签。对于您的另一个问题 - 现在,如果您要加载不同的脚本或不同的数据表,它会清除任何行和列指定。你的桌子仍然可以工作。但是,它不会告诉您出了什么问题或为什么会发生。你在这里发现了各种各样的漏洞!我有一个更新,即将添加到我的答案中,以解决并修复一些潜在的问题。 (2认同)