Skip to content

Commit 4fb1e49

Browse files
committed
feat: add girafe_class_add/remove/toggle for CSS class manipulation
See #321
1 parent 613d590 commit 4fb1e49

File tree

12 files changed

+294
-2
lines changed

12 files changed

+294
-2
lines changed

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: ggiraph
33
Title: Make 'ggplot2' Graphics Interactive
4-
Version: 0.9.5.003
4+
Version: 0.9.5.004
55
Authors@R: c(
66
person("David", "Gohel", , "david.gohel@ardata.fr", role = c("aut", "cre")),
77
person("Panagiotis", "Skintzos", , "sigmapi@posteo.net", role = "aut"),
@@ -117,6 +117,7 @@ Collate:
117117
'geom_vline_interactive.R'
118118
'ggiraph.R'
119119
'girafe.R'
120+
'girafe_class.R'
120121
'grob_interactive.R'
121122
'guide_bins_interactive.R'
122123
'guide_colourbar_interactive.R'

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ export(ggiraph)
128128
export(ggiraphOutput)
129129
export(girafe)
130130
export(girafeOutput)
131+
export(girafe_class_add)
132+
export(girafe_class_remove)
133+
export(girafe_class_toggle)
131134
export(girafe_css)
132135
export(girafe_css_bicolor)
133136
export(girafe_defaults)

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Feature
44

5+
- New functions `girafe_class_add()`, `girafe_class_remove()` and
6+
`girafe_class_toggle()` allow programmatic manipulation of CSS classes
7+
on girafe SVG elements from Shiny. Elements are targeted by `data_id`,
8+
`key_id` or `theme_id` (#321).
59
- `opts_hover()` and `opts_selection()` gain a new `linked` parameter. When
610
`linked = TRUE`, hover and selection states are shared between geometry
711
elements (`data-id`) and legend/guide elements (`key-id`): hovering or

R/girafe_class.R

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#' @title Add, remove or toggle CSS classes on girafe elements
2+
#'
3+
#' @description
4+
#' These functions allow programmatic manipulation of CSS classes
5+
#' on SVG elements within a girafe output in Shiny applications.
6+
#' Elements are targeted by their `data-id`, `key-id`, or `theme-id`
7+
#' attributes.
8+
#'
9+
#' @param session The Shiny session object.
10+
#' @param id The output id of the girafe element
11+
#' (the `outputId` used in [girafeOutput()]).
12+
#' @param class A non-empty character string of CSS class names to
13+
#' add, remove, or toggle.
14+
#' @param data_id A character vector of `data-id` values identifying
15+
#' the target elements.
16+
#' @param key_id A character vector of `key-id` values identifying
17+
#' the target elements.
18+
#' @param theme_id A character vector of `theme-id` values identifying
19+
#' the target elements.
20+
#'
21+
#' @details
22+
#' At least one of `data_id`, `key_id`, or `theme_id` must be provided.
23+
#'
24+
#' These functions send a custom message to the JavaScript side,
25+
#' which applies the CSS class operation to all matching SVG elements
26+
#' within the girafe root node.
27+
#'
28+
#' @examples
29+
#' \dontrun{
30+
#' # In a Shiny server function:
31+
#' girafe_class_add(session, "plot", "highlighted", data_id = "some_id")
32+
#' girafe_class_remove(session, "plot", "highlighted", data_id = "some_id")
33+
#' girafe_class_toggle(session, "plot", "highlighted", data_id = "some_id")
34+
#' }
35+
#' @name girafe_class
36+
NULL
37+
38+
#' @rdname girafe_class
39+
#' @export
40+
girafe_class_add <- function(session, id, class, data_id = NULL, key_id = NULL, theme_id = NULL) {
41+
girafe_class_action(session, id, class, action = "add", data_id = data_id, key_id = key_id, theme_id = theme_id)
42+
}
43+
44+
#' @rdname girafe_class
45+
#' @export
46+
girafe_class_remove <- function(session, id, class, data_id = NULL, key_id = NULL, theme_id = NULL) {
47+
girafe_class_action(session, id, class, action = "remove", data_id = data_id, key_id = key_id, theme_id = theme_id)
48+
}
49+
50+
#' @rdname girafe_class
51+
#' @export
52+
girafe_class_toggle <- function(session, id, class, data_id = NULL, key_id = NULL, theme_id = NULL) {
53+
girafe_class_action(session, id, class, action = "toggle", data_id = data_id, key_id = key_id, theme_id = theme_id)
54+
}
55+
56+
girafe_class_action <- function(session, id, class, action, data_id = NULL, key_id = NULL, theme_id = NULL) {
57+
if (!is.character(class) || length(class) != 1 || !nzchar(class)) {
58+
stop("`class` must be a non-empty string.", call. = FALSE)
59+
}
60+
if (is.null(data_id) && is.null(key_id) && is.null(theme_id)) {
61+
stop("At least one of `data_id`, `key_id`, or `theme_id` must be provided.", call. = FALSE)
62+
}
63+
64+
message <- list(action = action, cls = class)
65+
if (!is.null(data_id)) message$data_id <- as.character(data_id)
66+
if (!is.null(key_id)) message$key_id <- as.character(key_id)
67+
if (!is.null(theme_id)) message$theme_id <- as.character(theme_id)
68+
69+
session$sendCustomMessage(
70+
type = paste0(id, "_class"),
71+
message = message
72+
)
73+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Title: CSS class manipulation
2+
Author: David Gohel
3+
AuthorUrl: https://www.ardata.fr
4+
License: GPL-3
5+
DisplayMode: Showcase
6+
Tags: girafe-class
7+
Type: Shiny
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This Shiny application demonstrates `girafe_class_add()`, `girafe_class_remove()` and `girafe_class_toggle()`.
2+
3+
Use the text input to type a state name (e.g. "florida"), then click
4+
"Add class", "Remove class" or "Toggle class" to manipulate the
5+
`highlighted` CSS class on the corresponding point.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
library(ggplot2)
2+
library(ggiraph)
3+
4+
crimes <- data.frame(state = tolower(rownames(USArrests)), USArrests)
5+
6+
gg_crime <- ggplot(crimes, aes(x = Murder, y = Assault, colour = UrbanPop)) +
7+
geom_point_interactive(
8+
aes(data_id = state, tooltip = state), size = 3,
9+
hover_nearest = TRUE
10+
) +
11+
scale_colour_gradient(low = "#999999", high = "orange") +
12+
theme_minimal()
13+
14+
shinyServer(function(input, output, session) {
15+
16+
output$plot <- renderGirafe({
17+
girafe(
18+
code = print(gg_crime),
19+
width_svg = 6, height_svg = 5,
20+
options = list(
21+
opts_hover(css = "cursor:pointer;", reactive = TRUE)
22+
)
23+
)
24+
})
25+
26+
output$console <- renderPrint({
27+
input$plot_hovered
28+
})
29+
30+
get_ids <- reactive({
31+
ids <- trimws(unlist(strsplit(input$data_ids, ",")))
32+
ids[nzchar(ids)]
33+
})
34+
35+
observeEvent(input$btn_add, {
36+
ids <- get_ids()
37+
if (length(ids) > 0) {
38+
girafe_class_add(session, "plot", "highlighted", data_id = ids)
39+
}
40+
})
41+
42+
observeEvent(input$btn_remove, {
43+
ids <- get_ids()
44+
if (length(ids) > 0) {
45+
girafe_class_remove(session, "plot", "highlighted", data_id = ids)
46+
}
47+
})
48+
49+
observeEvent(input$btn_toggle, {
50+
ids <- get_ids()
51+
if (length(ids) > 0) {
52+
girafe_class_toggle(session, "plot", "highlighted", data_id = ids)
53+
}
54+
})
55+
})

inst/examples/shiny/css_class/ui.R

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
shinyUI(fluidPage(
2+
tags$h1("girafe CSS class demo"),
3+
4+
tags$style(HTML(
5+
".highlighted { fill: red !important; stroke: black !important; r: 8 !important; }"
6+
)),
7+
8+
fluidRow(
9+
column(
10+
width = 7,
11+
ggiraph::girafeOutput("plot")
12+
),
13+
column(
14+
width = 5,
15+
h4("Class manipulation"),
16+
textInput("data_ids", label = "data-id values (comma separated)",
17+
value = "florida, texas"),
18+
fluidRow(
19+
column(4, actionButton("btn_add", label = "Add class")),
20+
column(4, actionButton("btn_remove", label = "Remove class")),
21+
column(4, actionButton("btn_toggle", label = "Toggle class"))
22+
),
23+
hr(),
24+
h4("Current selection (hover)"),
25+
verbatimTextOutput("console")
26+
)
27+
)
28+
))

inst/htmlwidgets/girafe.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/girafe_class.Rd

Lines changed: 75 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)