Search code examples
google-apps-scriptsidebaradd-ongoogle-slides

Create grid (n,n) with selected page elements


Using Google application script, I am generating a grid with selected elements. In this example below - I gave input rows 2 and columns 3 to generate the order of the grid. My logic seems to be the production of wrong rows and columns.

Issue : number of rows and columns are wrong.

function grid() {
  var selection = SlidesApp.getActivePresentation().getSelection();
  var pageElements = selection.getPageElementRange().getPageElements();

  //init
  var numRows = 2;
  var horizontalSpace = 5;
  var numColumns = 3;
  var verticalSpace = 10;

  /*get Left, Top, width, height of ist shape.*/
  var shape0Left = pageElements[0].asShape().getLeft(),
    shape0Top = pageElements[0].asShape().getTop(),
    shape0Width = pageElements[0].asShape().getWidth(),
    shape0Height = pageElements[0].asShape().getHeight();

  /*Set the element properties*/
  var elemLeft = shape0Left,
    elemTop = shape0Top,
    elemWidth = 0,
    elemHeight = 0;

  /*Iterate the page selected elements*/
  pageElements.forEach(function(item, index) {
    pageElements[index]
      .asShape()
      .setLeft(elemLeft)
      .setTop(elemTop);

    /*Something wrong with the logic*/
    if ((index + 1) % numRows == 0) {
      /*update the properties of each shape to place in row column order */
      elemTop = shape0Top + pageElements[index].asShape().getHeight() + 10;
      elemLeft = shape0Left;
    } else {
      elemLeft = shape0Left + pageElements[index].asShape().getWidth() + 10;
    }
  });
}

Coming Result Expected output:


Solution

  • With the strategy you are taking, you should update the elemTop and elemLeft variables using the += operator to be sure to include the old value where appropriate.

    Also, you've set these nice verticalSpace and horizontalSpace constants; use them!

    If you need to break out of the element loop early because you only want to manipulate the first 6 elements, you cannot use forEach on the entire array (at least not without a if (index >= 6) return; guard). You can just loop through with a regular for loop and test that i < rumRows * numColumns, or you can get just the first n elements with pageElements.slice(0, n) and use forEach on that array.

    Lastly, the way you have set this up we need to check if we are at the last column or not. To check the current column number (zero indexed), you can use var col = i % numColumns.

    With a for loop:

      /*Iterate the page selected elements*/
      for (var i = 0; i < numRows * numColumns; ++i) {       
        pageElements[i].asShape().setLeft(elemLeft).setTop(elemTop);
        var col = i % numColumns;
        if ((col+1) % numColumns == 0) {         
          elemTop += pageElements[i].asShape().getHeight() + verticalSpace;
          elemLeft = shape0Left;   
        } else {
          elemLeft += pageElements[i].asShape().getWidth() + horizontalSpace;
        }
      }
    

    Using slice and forEach:

      pageElements.slice(0, numRows * numColumns).forEach(function(item, index){
        item.asShape().setLeft(elemLeft).setTop(elemTop);
        var col = index % numColumns;
        if ((col+1) % numColumns == 0) {         
          elemTop += item.asShape().getHeight() + verticalSpace;
          elemLeft = shape0Left;   
        } else {
          elemLeft += item.asShape().getWidth() + horizontalSpace;
        }
      });