1

I want to create a Word file with a text paragraph on the left and an image of a leaflet-map on the right.

So far I can do it, but I would also like to make a border around the whole leaflet image.

The border in my example is only half the size of the image and thus it seems like only the left side has borders.

How can I make the border as big as the image?

library(shiny)
library(officer)
library(leaflet)
library(mapview)

ui <- fluidPage(
  leafletOutput("leafletmap"),
  downloadLink("downloadWord", "Download Word Docx")
)

getLeafletMap <- function() {
  leaflet() %>%
    addTiles() %>% 
    addPopups(-93.65, 42.0285, "Here is the <b>Department of Statistics</b>, ISU")
}

server <- function(input, output, session) {
  output$leafletmap <- renderLeaflet({
    getLeafletMap()
  })

  output$downloadWord <- downloadHandler(
    filename = 'Report.docx',
    content = function(file) {
      ## Map #########################
      map <- getLeafletMap()
      mapshot(x = map, file=paste0(getwd(), "/map.png"),
              remove_controls = c("layersControl"))

      ## Title & Texts #########################
      subtitle <- "Report Map"
      str5 <- "Lorem ipsum dolor sit amet, ligula iaculis mollis lacus consectetur, urna vitae potenti tortor!
      Sit commodo, venenatis leo at et. Ligula ac pulvinar sollicitudin gravida, lobortis lectus ligula et.
      Nisl tristique est erat lectus. Sodales egestas amet ac, ultricies nulla eu, risus blandit."

      ## Styles #########################
      text_style_title <- fp_text(font.size = 20, bold = FALSE, font.family = "Arial", color = "#808080")
      text_style <- fp_text(font.size = 10, bold = FALSE, font.family = "Arial")
      par_style <- fp_par(text.align = "justify")

      ## Make Word Docs #########################
      doc <- read_docx() %>%
        body_add_fpar(fpar(ftext("Report with Map", prop = text_style_title), fp_p = par_style)) %>%
        body_add_par("", style = "Normal") %>% # blank paragraph
        body_end_section_continuous() %>%

        body_add_fpar(fpar(ftext(str5, prop = text_style), fp_p = par_style)) %>%
        body_add_fpar(fpar(external_img(src = paste0(getwd(), "/map.png"), height = 3, width = 4.52),
                           fp_p = fp_par(text.align = "right", padding.top = 6,
                                         border = fp_border(width = 1, color = "red")))) %>%
        body_end_section_columns(widths = c(1.5,2), sep = FALSE, space = 0.2) %>%
        print(doc, target = file)
    }
  )
}

shinyApp(ui, server)
SeGa
  • 9,454
  • 3
  • 31
  • 70
  • Does it work with other images? – Sven Sep 03 '19 at 10:48
  • As far as I can tell, it doesn't. – SeGa Sep 03 '19 at 10:56
  • I've personally had many issues with columns myself. A workaround could be to use a flextable with 2 columns instead. – Sven Sep 03 '19 at 11:20
  • I thought about that too, but how can I only color the right column border then? – SeGa Sep 03 '19 at 11:24
  • You can have control over the borders of flextables: https://davidgohel.github.io/flextable/articles/format.html#borders – Sven Sep 03 '19 at 11:30
  • I know I can control all borders of the flextable, but I just need the borders around the image. But maybe I could put the image in a flextable with 1 column only, but I dont know if I can then have a paragraph of text on the left and the flextable on the right. – SeGa Sep 03 '19 at 11:31
  • Or perhaps it's better to have a flextable in a flextable, if that's possible? Create the outer flextable which has the text in the left column and the 2nd flextable in the right column. This outer flextable has no borders. The 2nd inner flextable has only 1 cell, with borders. – Sven Sep 03 '19 at 11:39
  • If you show me an example in an answer, I'll glady reward you the bounty ;) – SeGa Sep 03 '19 at 11:42

1 Answers1

4

I was able to do it with flextable, vline and hline. One disclaimer, since I wasn't able to use the hline for i=0, there is an empty line in the table for i=0.

library(flextable)
library(officer)

inputFolder <- "test/"
std_border = fp_border(color="orange")

testtable <- data.frame("text" = c("",""), "image" = c("",""))

testft <- flextable(testtable) %>%
  delete_part(part = "header") %>%
  theme_box() %>%
  compose(i = 2, j = 2, value= as_paragraph(as_image(src = paste(inputFolder, "smiley.png", sep = ""), width = 1, height = 1))) %>%
  compose(i = 2, j = 1, value = as_paragraph(as_chunk("Just some random text"))) %>%
  border_remove() %>%
  vline(i=2, j=1, border = std_border) %>%
  vline(i=2, j=2, border = std_border) %>%
  hline(i=1, j=2, border = std_border) %>%
  hline(i=2, j=2, border = std_border)

This gives me the following:

enter image description here

Of course you can format the text, images and borders according your needs.

EDIT:

Of course the officer part is just:

doc <- read_docx() %>%
body_add_flextable(testft)
Sven
  • 1,203
  • 1
  • 5
  • 14
  • Unfortunately, this works for this small example, but it does not work if the columns should have different widths and the image is bigger. And how can I left-align the text? – SeGa Sep 03 '19 at 15:40
  • 1
    Just add the line `align(j=1, align = "left", part="body")` – Sven Sep 03 '19 at 15:57
  • 1
    Not sure why it wouldn't work with different widths and a bigger image? You can create as many columns and rows as you want and give them widths and heights you want. You can also merge cells. So in the end you can position it exactly where you want and just put a border around the cell of the image, with the right i and j values. – Sven Sep 03 '19 at 15:59
  • My final solution is a bit different and doesnt use `hline` or `vline` but `border` instead, but anyway I think you deserve the bounty, since you pointed me in the right direction! :) Thank you again – SeGa Sep 05 '19 at 07:21
  • Ah, I didn't know about `border` yet, thanks for the tip! – Sven Sep 05 '19 at 11:35