@@ -172,12 +172,13 @@ addTiles <- function(
172
172
epsg4326 <- " +proj=longlat +datum=WGS84 +no_defs"
173
173
epsg3857 <- " +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" # nolint
174
174
175
+
175
176
# ' Add a raster image as a layer
176
177
# '
177
- # ' Create an image overlay from a \code{RasterLayer} object. \emph{This is only
178
- # ' suitable for small to medium sized rasters}, as the entire image will be
179
- # ' embedded into the HTML page (or passed over the websocket in a Shiny
180
- # ' context).
178
+ # ' Create an image overlay from a \code{RasterLayer} or a \code{SpatRaster}
179
+ # ' object. \emph{This is only suitable for small to medium sized rasters},
180
+ # ' as the entire image will be embedded into the HTML page (or passed over
181
+ # ' the websocket in a Shiny context).
181
182
# '
182
183
# ' The \code{maxBytes} parameter serves to prevent you from accidentally
183
184
# ' embedding an excessively large amount of data into your htmlwidget. This
@@ -187,18 +188,22 @@ epsg3857 <- "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y
187
188
# ' aware that very large rasters may not only make your map a large download but
188
189
# ' also may cause the browser to become slow or unresponsive.
189
190
# '
190
- # ' By default, the \code{addRasterImage} function will project the RasterLayer
191
- # ' \code{x} to EPSG:3857 using the \code{raster} package's
192
- # ' \code{\link[raster]{projectRaster}} function. This can be a time-consuming
193
- # ' operation for even moderately sized rasters. Upgrading the \code{raster}
194
- # ' package to 2.4 or later will provide a large speedup versus previous
195
- # ' versions. If you are repeatedly adding a particular raster to your Leaflet
191
+ # ' To reduce the size of a SpatRaster, you can use \code{\link[terra]{spatSample}}
192
+ # ' as in \code{x = spatSample(x, 100000, method="regular", as.raster=TRUE)}. With
193
+ # ' a \code{RasterLayer} you can use \code{\link[raster]{sampleRegular}} as in
194
+ # ' \code{sampleRegular(x, 100000, asRaster=TRUE)}.
195
+ # '
196
+ # ' By default, the \code{addRasterImage} function will project the raster data
197
+ # ' \code{x} to the Pseudo-Mercator projection (EPSG:3857). This can be a
198
+ # ' time-consuming operation for even moderately sized rasters; although it is much
199
+ # ' faster for SpatRasters than for RasterLayers.
200
+ # ' If you are repeatedly adding a particular raster to your Leaflet
196
201
# ' maps, you can perform the projection ahead of time using
197
202
# ' \code{projectRasterForLeaflet()}, and call \code{addRasterImage} with
198
203
# ' \code{project = FALSE}.
199
204
# '
200
205
# ' @param map a map widget object
201
- # ' @param x a \code{RasterLayer} object--see \code{\link[raster]{raster}}
206
+ # ' @param x a \code{\link[terra]{SpatRaster}} or a \code{ RasterLayer} object--see \code{\link[raster]{raster}}
202
207
# ' @param colors the color palette (see \code{\link{colorNumeric}}) or function
203
208
# ' to use to color the raster values (hint: if providing a function, set
204
209
# ' \code{na.color} to \code{"#00000000"} to make \code{NA} areas transparent)
@@ -235,7 +240,7 @@ epsg3857 <- "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y
235
240
addRasterImage <- function (
236
241
map ,
237
242
x ,
238
- colors = if (raster :: is.factor(x )) " Set1" else " Spectral" ,
243
+ colors = if (is.factor(x )[ 1 ] ) " Set1" else " Spectral" ,
239
244
opacity = 1 ,
240
245
attribution = NULL ,
241
246
layerId = NULL ,
@@ -245,7 +250,54 @@ addRasterImage <- function(
245
250
maxBytes = 4 * 1024 * 1024 ,
246
251
data = getMapData(map )
247
252
) {
248
- stopifnot(inherits(x , " RasterLayer" ))
253
+ if (inherits(x , " SpatRaster" )) {
254
+ addRasterImage_SpatRaster(
255
+ map = map ,
256
+ x = x ,
257
+ colors = colors ,
258
+ opacity = opacity ,
259
+ attribution = attribution ,
260
+ layerId = layerId ,
261
+ group = group ,
262
+ project = project ,
263
+ method = method ,
264
+ maxBytes = maxBytes ,
265
+ data = data
266
+ )
267
+ } else if (inherits(x , " RasterLayer" )) {
268
+ addRasterImage_RasterLayer(
269
+ map = map ,
270
+ x = x ,
271
+ colors = colors ,
272
+ opacity = opacity ,
273
+ attribution = attribution ,
274
+ layerId = layerId ,
275
+ group = group ,
276
+ project = project ,
277
+ method = method ,
278
+ maxBytes = maxBytes ,
279
+ data = data
280
+ )
281
+ } else {
282
+ stop(" Don't know how to get path data from object of class " , class(x )[[1 ]])
283
+ }
284
+ }
285
+
286
+
287
+ addRasterImage_RasterLayer <- function (
288
+ map ,
289
+ x ,
290
+ colors = if (is.factor(x )[1 ]) " Set1" else " Spectral" ,
291
+ opacity = 1 ,
292
+ attribution = NULL ,
293
+ layerId = NULL ,
294
+ group = NULL ,
295
+ project = TRUE ,
296
+ method = c(" auto" , " bilinear" , " ngb" ),
297
+ maxBytes = 4 * 1024 * 1024 ,
298
+ data = getMapData(map )
299
+ ) {
300
+
249
301
250
302
raster_is_factor <- raster :: is.factor(x )
251
303
method <- match.arg(method )
@@ -260,11 +312,6 @@ addRasterImage <- function(
260
312
if (project ) {
261
313
# if we should project the data
262
314
projected <- projectRasterForLeaflet(x , method )
263
-
264
- # if data is factor data, make the result factors as well.
265
- if (raster_is_factor ) {
266
- projected <- raster :: as.factor(projected )
267
- }
268
315
} else {
269
316
# do not project data
270
317
projected <- x
@@ -311,14 +358,116 @@ addRasterImage <- function(
311
358
)
312
359
}
313
360
361
+ addRasterImage_SpatRaster <- function (
362
+ map ,
363
+ x ,
364
+ colors = if (terra :: is.factor(x )[1 ]) " Set1" else " Spectral" ,
365
+ opacity = 1 ,
366
+ attribution = NULL ,
367
+ layerId = NULL ,
368
+ group = NULL ,
369
+ project = TRUE ,
370
+ method = c(" auto" , " bilinear" , " ngb" ),
371
+ maxBytes = 4 * 1024 * 1024 ,
372
+ data = getMapData(map )
373
+ ) {
374
+
375
+ if (terra :: nlyr(x ) > 1 ) {
376
+ x <- x [[1 ]]
377
+ warning(" using the first layer in 'x'" , call. = FALSE )
378
+ }
379
+
380
+ raster_is_factor <- terra :: is.factor(x )
381
+ method <- match.arg(method )
382
+ if (method == " ngb" ) method = " near"
383
+ if (method == " auto" ) {
384
+ if (raster_is_factor ) {
385
+ method <- " near"
386
+ } else {
387
+ method <- " bilinear"
388
+ }
389
+ }
390
+
391
+ if (project ) {
392
+ # if we should project the data
393
+ projected <- projectRasterForLeaflet(x , method )
394
+ } else {
395
+ # do not project data
396
+ projected <- x
397
+ }
398
+
399
+ bounds <- terra :: ext(
400
+ terra :: project(
401
+ terra :: project(
402
+ terra :: as.points(terra :: ext(x ), crs = terra :: crs(x )),
403
+ epsg3857 ),
404
+ epsg4326 )
405
+ )
406
+
407
+ if (! is.function(colors )) {
408
+ if (method == " near" ) {
409
+ # 'factors'
410
+ colors <- colorFactor(colors , domain = NULL , na.color = " #00000000" , alpha = TRUE )
411
+ } else {
412
+ # 'numeric'
413
+ colors <- colorNumeric(colors , domain = NULL , na.color = " #00000000" , alpha = TRUE )
414
+ }
415
+ }
416
+
417
+ tileData <- terra :: values(projected ) %> % as.vector() %> % colors() %> % col2rgb(alpha = TRUE ) %> % as.raw()
418
+ dim(tileData ) <- c(4 , ncol(projected ), nrow(projected ))
419
+ pngData <- png :: writePNG(tileData )
420
+ if (length(pngData ) > maxBytes ) {
421
+ stop(
422
+ " Raster image too large; " , length(pngData ), " bytes is greater than maximum " ,
423
+ maxBytes , " bytes"
424
+ )
425
+ }
426
+ encoded <- base64enc :: base64encode(pngData )
427
+ uri <- paste0(" data:image/png;base64," , encoded )
428
+
429
+ latlng <- list (
430
+ list (terra :: ymax(bounds ), terra :: xmin(bounds )),
431
+ list (terra :: ymin(bounds ), terra :: xmax(bounds ))
432
+ )
433
+
434
+ invokeMethod(map , data , " addRasterImage" , uri , latlng , opacity , attribution , layerId , group ) %> %
435
+ expandLimits(
436
+ c(terra :: ymin(bounds ), terra :: ymax(bounds )),
437
+ c(terra :: xmin(bounds ), terra :: xmax(bounds ))
438
+ )
439
+ }
440
+
441
+
442
+
314
443
# ' @rdname addRasterImage
315
444
# ' @export
316
445
projectRasterForLeaflet <- function (x , method ) {
317
- raster :: projectRaster(
318
- x ,
319
- raster :: projectExtent(x , crs = sp :: CRS(epsg3857 )),
320
- method = method
321
- )
446
+ if (inherits(x , " SpatRaster" )) {
447
+ if (method == " ngb" ) {
448
+ method = " near"
449
+ }
450
+ terra :: project(
451
+ x ,
452
+ y = epsg3857 ,
453
+ method = method
454
+ )
455
+ } else {
456
+ raster_is_factor <- raster :: is.factor(x );
457
+ projected <- raster :: projectRaster(
458
+ x ,
459
+ raster :: projectExtent(x , crs = sp :: CRS(epsg3857 )),
460
+ method = method
461
+ )
462
+ # if data is factor data, make the result factors as well.
463
+ # only meaningful if ngb was used
464
+ if ((raster_is_factor ) && (method == " ngb" )) {
465
+ raster :: as.factor(projected )
466
+ } else {
467
+ projected
468
+ }
469
+
470
+ }
322
471
}
323
472
324
473
# ' @rdname remove
0 commit comments