Skip to content

Commit

Permalink
Merge pull request #83 from trafficonese/newlogo
Browse files Browse the repository at this point in the history
Newlogo
Also addresses r-tmap/tmap#461 by supporting local images now
  • Loading branch information
tim-salabim authored Jun 1, 2024
2 parents 1582ab9 + 4f58726 commit 9c7ae45
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 166 deletions.
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ Suggests:
lwgeom,
mapdeck,
plainview,
stars
stars,
tools
Encoding: UTF-8
LazyData: false
RoxygenNote: 7.3.1
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@ export(addTileFolder)
export(clip2sfc)
export(colorOptions)
export(garnishMap)
export(hideLogo)
export(paintRules)
export(removeHomeButton)
export(removeLogo)
export(removeMouseCoordinates)
export(showLogo)
export(updateLayersControl)
export(updateLogo)
importFrom(base64enc,base64encode)
importFrom(grDevices,col2rgb)
importFrom(grDevices,colors)
importFrom(grDevices,rgb)
importFrom(leaflet,addRasterImage)
importFrom(leaflet,colorNumeric)
importFrom(leaflet,expandLimits)
importFrom(leaflet,filterNULL)
importFrom(leaflet,getMapData)
importFrom(leaflet,gridOptions)
importFrom(leaflet,invokeMethod)
Expand Down
9 changes: 9 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ leafem 0.2.3.9003 (2024-06-01)

features and improvements

* Added `removeLogo()`, `updateLogo`, `hideLogo()` and `showLogo()` functions to manipulate logo's on the map.
These functions utilize the new `layerId` argument in `addLogo()`. (#50, #49)

bug fixes

* `addLogo()` was rewritten to correctly handle remote and local images across
R, Shiny, and Markdown contexts. It gained the arguments `layerId` and `class`.
Local images are encoded using `base64enc::dataURI` and logos are added to the map
using `layerId`. The `src` argument has been deprecated; the function now
automatically determines if an image is local or remote using `file.exists()`. #43, #42, #16

documentation etc

miscellaneous
Expand Down
266 changes: 107 additions & 159 deletions R/logo.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
logodeps <- function() {
list(
htmltools::htmlDependency(
"logodeps",
version = "1.0.0",
system.file("htmlwidgets/lib/", package = "leafem"),
script = "logo.js",
)
)
}


### addLogo ##################################################################
##############################################################################
#' add a local or remote image (png, jpg, gif, bmp, ...) to a leaflet map
Expand All @@ -9,15 +21,17 @@
#' @param map a mapview or leaflet object.
#' @param img the image to be added to the map.
#' @param alpha opacity of the added image.
#' @param src character specifying the source location ("local" for images from
#' the disk, "remote" for web image sources).
#' @param src DEPRECATED. The function now automatically determines if `img` is
#' a local or remote image using `file.exists(img)`.
#' @param url an optional URL to be opened when clicking on the image
#' (e.g. company's homepage).
#' @param position one of "topleft", "topright", "bottomleft", "bottomright".
#' @param offset.x the offset in x direction from the chosen position (in pixels).
#' @param offset.y the offset in y direction from the chosen position (in pixels).
#' @param width width of the rendered image in pixels.
#' @param height height of the rendered image in pixels.
#' @param layerId an id for the logo div.
#' @param class optional class
#'
#' @examples
#' library(leaflet)
Expand Down Expand Up @@ -50,6 +64,7 @@
#' @export addLogo
#' @name addLogo
#' @rdname addLogo
#' @importFrom leaflet filterNULL
#' @aliases addLogo

## courtesy of
Expand All @@ -59,177 +74,110 @@
addLogo <- function(map,
img,
alpha = 1,
src = c("remote", "local"),
url,
src = NULL,
url = NULL,
position = c("topleft", "topright",
"bottomleft", "bottomright"),
offset.x = 50,
offset.y = 13,
width = 60,
height = 60) {
# check for duplication?
# not sure of a good way to do this
height = 60,
class = NULL,
layerId = NULL) {

if (inherits(map, "mapview")) map <- mapview2leaflet(map)
stopifnot(inherits(map, c("leaflet", "leaflet_proxy")))

if (!missing(url)) url <- paste0('"', url, '"')

position <- position[1]
src <- src[1]


div_topleft <- paste0("newDiv.css({
'position': 'absolute',
'top': '", offset.y, "px',
'left': '", offset.x, "px',
'background-color': 'transparent',
'border': '0px solid black',
'width': '", width, "px',
'height': '", height, "px',
});")

div_topright <- paste0("newDiv.css({
'position': 'absolute',
'top': '", offset.y, "px',
'right': '", offset.x, "px',
'background-color': 'transparent',
'border': '0px solid black',
'width': '", width, "px',
'height': '", height, "px',
});")

div_bottomleft <- paste0("newDiv.css({
'position': 'absolute',
'bottom': '", offset.y, "px',
'left': '", offset.x, "px',
'background-color': 'transparent',
'border': '0px solid black',
'width': '", width, "px',
'height': '", height, "px',
});")

div_bottomright <- paste0("newDiv.css({
'position': 'absolute',
'bottom': '", offset.y, "px',
'right': '", offset.x, "px',
'background-color': 'transparent',
'border': '0px solid black',
'width': '", width, "px',
'height': '", height, "px',
});")

div <- switch(position,
topleft = div_topleft,
topright = div_topright,
bottomleft = div_bottomleft,
bottomright = div_bottomright)

div_funk <- paste0("function(el, x, data) {
// we need a new div element because we have to handle
// the mouseover output seperately
// debugger;
function addElement () {
// generate new div Element
var newDiv = $(document.createElement('div'));
// append at end of leaflet htmlwidget container
$(el).append(newDiv);
//provide ID and style
newDiv.addClass('logo');\n",
div,
"return newDiv;
}")

div_add <- paste0("// check for already existing logo class to not duplicate
var logo = $(el).find('.logo');
if(!logo.length) {
logo = addElement();")

# if (missing(url)) {
# div_html <- paste0("logo.html('<img src=", img,
# ", width=", width, "height=", height, "></a>');
# var map = HTMLWidgets.find('#' + el.id).getMap();
# };
# }")
# } else {
# div_html <- paste0("logo.html('<a href=", url, "><img src=", img,
# ", width=", width, "height=", height, "></a>');
# var map = HTMLWidgets.find('#' + el.id).getMap();
# };
# }")
# }

div_html <- switch(src,
remote = remoteImage(img, alpha, url, width, height),
local = localImage(img, alpha, url, width, height))

render_stuff <- paste0(div_funk, div_add, div_html)

map <- htmlwidgets::onRender(map, render_stuff)

return(map)
if (!is.null(src)) {
warning("'src' parameter is deprecated in 'addLogo' and will be ignored.\n",
"The function now automatically determines if 'img' is a local or remote image using 'file.exists(img)'.")
}
position <- match.arg(position)
map$dependencies <- c(map$dependencies, logodeps())

img <- base64local(img)

options <- filterNULL(list(
alpha = alpha,
url = url,
position = position,
offsetX = offset.x,
offsetY = offset.y,
width = width,
height = height,
class = class
))

## Make sure layerId is set and unique
if (is.null(layerId)) {
layerId <- as.character(as.numeric(Sys.time()))
}

leaflet::invokeMethod(
map,
NULL,
"addLogo",
img,
layerId,
options)
}

#' updateLogo
#' @inheritParams addLogo
#' @rdname addLogo
#' @export
updateLogo <- function(map, img, layerId) {
img <- base64local(img)
leaflet::invokeMethod(
map,
NULL,
"updateLogo",
img,
layerId)
}

#' removeLogo
#' @inheritParams addLogo
#' @rdname addLogo
#' @export
removeLogo <- function(map, layerId) {
leaflet::invokeMethod(
map,
NULL,
"removeLogo",
layerId)
}

### local image
localImage <- function(img, alpha, url, width, height) {
nm <- basename(img)
drs <- file.path(tempdir(), "graphs")
if (!dir.exists(drs)) dir.create(drs)
fls <- file.path(drs, nm)
invisible(file.copy(img, file.path(drs, nm)))
rel_path <- paste0('"', file.path("..", basename(drs), basename(img)), '"')

style <- paste0(', style="opacity:',
alpha,
';filter:alpha(opacity=',
alpha * 100, ');"')

if (missing(url)) {
div_html <- paste0("logo.html('<img src=", rel_path,
", width=", width, ", height=", height, style,
", ></a>');
var map = HTMLWidgets.find('#' + el.id).getMap();
};
}")
} else {
div_html <- paste0("logo.html('<a href=", url, "><img src=", rel_path,
", width=", width, ", height=", height, style,
"></a>');
var map = HTMLWidgets.find('#' + el.id).getMap();
};
}")
}
#' hideLogo
#' @inheritParams addLogo
#' @rdname addLogo
#' @export
hideLogo <- function(map, layerId) {
leaflet::invokeMethod(
map,
NULL,
"hideLogo",
layerId)
}

return(div_html)
#' showLogo
#' @inheritParams addLogo
#' @rdname addLogo
#' @export
showLogo <- function(map, layerId) {
leaflet::invokeMethod(
map,
NULL,
"showLogo",
layerId)
}

### remote image
remoteImage <- function(img, alpha, url, width, height) {

img <- paste0('"', img, '"')

style <- paste0(', style="opacity:',
alpha,
';filter:alpha(opacity=',
alpha * 100, ');"')

if (missing(url)) {
div_html <- paste0("logo.html('<img src=", img,
", width=", width, ", height=", height, style,
"></a>');
var map = HTMLWidgets.find('#' + el.id).getMap();
};
}")
} else {
div_html <- paste0("logo.html('<a href=", url, "><img src=", img,
", width=", width, ", height=", height, style,
"></a>');
var map = HTMLWidgets.find('#' + el.id).getMap();
};
}")
base64local <- function(img) {
if (file.exists(img)) {
fileext <- tools::file_ext(img)
if (fileext == "svg") fileext <- paste0(fileext, "+xml")
img <- base64enc::dataURI(file = img, mime = paste0("image/", fileext))
}

return(div_html)
img
}

##############################################################################
Loading

0 comments on commit 9c7ae45

Please sign in to comment.