Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowing Spinner to keep height on redraw + delaying spinner show (avoid too many or too quick show/hide cycle) #61

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# shinycssloaders 1.0.1 (2021-03-09)
- Add support for making spinner retain previous output size
- Add support to delay display

# shinycssloaders 1.0.0 (2020-07-28)

- Add support for custom images with `image` parameter (#46)
Expand Down
9 changes: 8 additions & 1 deletion R/withSpinner.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#' size of the image is used. Ignored if not using `image`.
#' @param hide.ui By default, while an output is recalculating, the output UI is hidden and the spinner is visible instead.
#' Setting `hide.ui = FALSE` will result in the spinner showing up on top of the previous output UI.
#' @param keep.height By default, the spinner height is determined based on output UI (if defined) or by `proxy.height` field.
#' Setting `keep.height = TRUE` will set the spinner height based on displayed contents when redrawing (first draw will use default proxy height strategy). Ignored if`hide.ui` is set to `FALSE`
#' @param show.delay Milliseconds delay required to show spinner, useful to avoid "blinking" spinner in cases where output redraw is too quick. Defaults to 0.
#' @examples
#' if (interactive()) {
#' library(shiny)
Expand Down Expand Up @@ -46,7 +49,7 @@ withSpinner <- function(
proxy.height = NULL,
id = NULL,
image = NULL, image.width = NULL, image.height = NULL,
hide.ui = TRUE
hide.ui = TRUE, keep.height = FALSE, show.delay = 0
) {
stopifnot(type %in% 0:8)

Expand Down Expand Up @@ -112,8 +115,12 @@ withSpinner <- function(
class = paste(
"shiny-spinner-output-container",
if (hide.ui) "shiny-spinner-hideui" else "",
if (keep.height) "shiny-spinner-keepheight" else "",
if (is.null(image)) "" else "shiny-spinner-custom"
),
`data-showdelay` = paste(
if (is.numeric(show.delay)) show.delay else "0"
),
shiny::div(
class = paste(
"load-container",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ If you don't want to use any of the built-in spinners, you can also provide your

### Specifying the spinner height

The spinner attempts to automatically figure out the height of the output it replaces, and to vertically center itself. For some outputs (such as tables), the height is unknown, so the spinner will assume the output is 400px tall. If your output is expected to be significantly smaller or larger, you can use the `proxy.height` parameter to adjust this.
The spinner attempts to automatically figure out the height of the output it replaces, and to vertically center itself. For some outputs (such as tables), the height is unknown, so the spinner will assume the output is 400px tall. If your output is expected to be significantly smaller or larger, you can use the `proxy.height` parameter to adjust this. For dynamic height outputs, the property `keep.sheight can be set, making the spinner keep the contents size on re-draw (first draw height is determined as usual)

### Showing a spinner on top of the output

Expand Down
38 changes: 32 additions & 6 deletions inst/assets/spinner.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(function() {
var output_states = {};
var timeoutHandles = {};

function escapeSelector(s) {
return s.replace(/([!"#$%&'()*+,-./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
Expand All @@ -8,21 +9,46 @@ function escapeSelector(s) {
function show_spinner(id) {
var selector = "#" + escapeSelector(id);
var parent = $(selector).closest(".shiny-spinner-output-container");
$(selector).siblings(".load-container, .shiny-spinner-placeholder").removeClass('shiny-spinner-hidden');

if (parent.hasClass("shiny-spinner-hideui")) {
$(selector).siblings(".load-container").siblings('.shiny-bound-output, .shiny-output-error').css('visibility', 'hidden');
// if there is a proxy div, hide the previous output
$(selector).siblings(".shiny-spinner-placeholder").siblings('.shiny-bound-output, .shiny-output-error').addClass('shiny-spinner-hidden');

if (parent && parent.length && timeoutHandles[parent] === null) {
var delay = parent.data() && parent.data().showdelay ? parent.data().showdelay : 0;
timeoutHandles[parent] = setTimeout(function(){
timeoutHandles[parent] = null;
var currentHeight = parent.height();

$(selector).siblings(".load-container, .shiny-spinner-placeholder").removeClass('shiny-spinner-hidden');

if (parent.hasClass("shiny-spinner-hideui")) {
$(selector).siblings(".load-container").siblings('.shiny-bound-output, .shiny-output-error')
.css('visibility', 'hidden');

if (parent.hasClass("shiny-spinner-keepheight") && currentHeight) parent.css("height", currentHeight + "px");

// if there is a proxy div, hide the previous output
$(selector).siblings(".shiny-spinner-placeholder").siblings('.shiny-bound-output, .shiny-output-error').addClass('shiny-spinner-hidden');
}

}, delay);

}
}

function hide_spinner(id) {
var selector = "#" + escapeSelector(id);
var parent = $(selector).closest(".shiny-spinner-output-container");

if (parent && parent.length && timeoutHandles[parent] !== null) {
clearTimeout(timeoutHandles[parent]);
timeoutHandles[parent] = null;
}

$(selector).siblings(".load-container, .shiny-spinner-placeholder").addClass('shiny-spinner-hidden');
if (parent.hasClass("shiny-spinner-hideui")) {

$(selector).siblings(".load-container").siblings('.shiny-bound-output').css('visibility', 'visible');

if (parent.hasClass("shiny-spinner-keepheight")) parent.css("height", "");

// if there is a proxy div, show the previous output in case it was hidden
$(selector).siblings(".shiny-spinner-placeholder").siblings('.shiny-bound-output').removeClass('shiny-spinner-hidden');
}
Expand Down
6 changes: 6 additions & 0 deletions man/withSpinner.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.