Skip to content
Merged
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
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ importFrom(grDevices,
dev.list,
dev.new,
dev.off,
dev.size,
extendrange,
gray.colors,
hcl,
Expand Down
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ not 'at'`. The free-facet code path listed the eligible types by name, so

### Internals

- Performance improvemnts. (#723 @grantmcdermott)
- Performance improvements. (#723, #724 @grantmcdermott)

## v0.7.0

Expand Down
27 changes: 24 additions & 3 deletions R/legend.R
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,14 @@ tinylegend = function(legend_env) {
legend_env$args[["text.width"]] = NULL
}

# Re-measure legend dimensions (device size may have changed on resize)
legend_env$dims = measure_fake_legend(legend_env)
# Re-measure legend dimensions, but only when the device has actually
# changed. draw_legend() already measured on this device during setup, so on
# the initial draw the result is still current and a measuring pass costs
# about as much as drawing the legend itself. A resize, or a replay onto a
# different device, fails the key comparison and forces the re-measure.
if (is.null(legend_env$dims) || !identical(legend_env$dims_dev, legend_dev_key())) {
legend_env$dims = measure_fake_legend(legend_env)
}

# Calculate and apply soma (outer margin adjustment based on legend size)
# When soma_target is set (multi-legend), use it directly so all legends
Expand Down Expand Up @@ -362,6 +368,17 @@ tinylegend = function(legend_env) {


# Measure legend dimensions using a fake (non-plotted) legend
# Identity of the device a legend measurement belongs to. Size alone is not
# enough: replaying or copying a display list onto a same-sized device with a
# different backend (dev.copy(), dev.print(), an IDE's plot export) yields
# different text metrics, so the device itself has to be part of the key.
# dev.cur() is a named integer, so this captures the backend as well as the
# device number.
legend_dev_key = function() {
list(dev = dev.cur(), size = dev.size())
}


measure_fake_legend = function(legend_env) {
fklgnd.args = modifyList(
legend_env$args,
Expand Down Expand Up @@ -389,6 +406,10 @@ measure_fake_legend = function(legend_env) {
}
}

# Record which device this measurement was taken on, so callers can tell
# whether a cached result is still valid (see tinylegend()).
legend_env$dims_dev = legend_dev_key()

do.call("legend", fklgnd.args)
}

Expand Down Expand Up @@ -929,7 +950,7 @@ build_legend_env = function(
#' with a legend in the margin.
#'
#' @importFrom graphics grconvertX grconvertY rasterImage strheight strwidth xinch
#' @importFrom grDevices as.raster recordGraphics
#' @importFrom grDevices as.raster dev.size recordGraphics
#' @importFrom utils modifyList
#'
#' @examples
Expand Down