Showing posts with label ui. Show all posts
Showing posts with label ui. Show all posts

Wednesday, 20 August 2014

Google Drive and User Interfaces

I have explored a few ways of interacting with Google Drive files and folders for a simple document management system. The user-interface needs to present folders and files which represent real world artefacts (eg people , places). Business operations are initiated by the user making a selection on a folder or file name.

The Drive and Google Apps scripting features have developed over time and I have tried using


For me, using the Google Drive SDK  has proven the simplest to build into a responsive user interface and best performing for the user.



The UI Service approach provided an early introduction to interacting with Google Apps script but it is very limited in function and locks the user interface into the script. It carries all the overheads of generating the user interface at run time as well.

HTMLService does provide the familiarity of HTML/CSS/JS development but has limitations and performance impacts caused by CAJA.

Calling a Google Apps Script from the Google Drive user interface suits users who spend there time interacting with Drive directly but selection of action on folder/file becomes a multiclick operation and subsequent user interface has the limitations of HTMLService .

The filepicker provided for Google Drive is functional and has the advantage of being ready to use with good performance. However the pop-up iframe approach may not suit all design styles and customisation is limited. In particular, presenting the file/folder list initially random order slows down the user interaction.

The direct use of the Google Drive SDK has been simplified recently  by improved documentation of the authorisation process. I took the quickstart example and built an html page of links from folder names corresponding to people of interest. It is then simple to incorporate this into a comprehensive user interface for the business user.

Performance and flexibility is the key for this approach. I get a few hundred folder references generate in 3 seconds and can then have a js expert work in there usual toolset to develop responsive bootstrap, jQuery or whatever interface style is required.

Modifed Quickstart example.

<html>
  <head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <script type="text/javascript">
      var CLIENT_ID = '70v406.apps.googleusercontent.com';
      var SCOPES = 'https://www.googleapis.com/auth/drive';

      /**
       * Called when the client library is loaded to start the auth flow.
       */
      function handleClientLoad() {
          console.log('handleClientLoad:'+new Date().getTime())
        window.setTimeout(checkAuth, 1);
      }

      /**
       * Check if the current user has authorized the application.
       */
      function checkAuth() {
                    console.log('CheckAuth:'+new Date().getTime())
        gapi.auth.authorize(
            {'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true},
            handleAuthResult);
      }

      /**
       * Called when authorization server replies.
       *
       * @param {Object} authResult Authorization result.
       
      
      */
      function handleAuthResult(authResult) {
                    console.log('handleAuthResult:'+new Date().getTime())
        var authButton = document.getElementById('authorizeButton');
        authButton.style.display = 'none';

        if (authResult && !authResult.error) {
          // Access token has been successfully retrieved, requests can be sent to the API.
          getItems();
        } else {
          // No access token could be retrieved, show the button to start the authorization flow.
          authButton.style.display = 'block';
          authButton.onclick = function() {
              gapi.auth.authorize(
                  {'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': false},
                  handleAuthResult);
          };
        }
      }

 /*  List folders based on a search
* specify the owning folder and mimetype = folder in the search parameter (q)
* set maxResults  (can do paged calls if actual results exceed 1000) 
 */
      
function getItems() {
    console.log('getItems:'+new Date().getTime())
    var start = new Date();
    var request = gapi.client.request({
      'path': 'drive/v2/files',
      'method': 'GET',
      'params': {
        'q': 'mimeType="application/vnd.google-apps.folder" and "0B90FGJizRd-gX25PTS1CTUF0eHM" in parents  and trashed = false',
       'maxResults': '400'
      }
     });
     request.execute(listItems);
     console.log("elapsed: "+(new Date()-start))
}
/* Sort the result returned from drive api into title order
*   insert html paragraph for each title

*/

function listItems(resp) {
              console.log('listitems:'+new Date().getTime())
    var start = new Date().getTime();
    var result = resp.items.sort(function(a, b){
     var nameA=a.title.toLowerCase(), nameB=b.title.toLowerCase()
     if (nameA < nameB) //sort string ascending
      return -1 
     if (nameA > nameB)
      return 1
     return 0 //default return value (no sorting)
    });

 console.log('items: '+result.length)
    var i = 0;
    var element = document.getElementById("div1");  // insertion point in html
      for (i=0;i<result.length;i++) {
          var para = document.createElement("p"); // create a link element in a para
          var aref = document.createElement("a");
          var node = document.createTextNode(result[i].title);
           aref.setAttribute('href',result[i].alternateLink); // link to driver folder
           aref.appendChild(node);
           para.appendChild(aref);
    
        element.appendChild(para);
      }
    console.log("elapsed: "+(new Date().getTime()-start));
}
    </script>
    <script type="text/javascript" src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
  </head>
  <body>
      <input type="button" id="authorizeButton" style="display: none" value="Authorize" />
  <h1>List</h1>
  <div id='div1'></div>
  </body>
</html>




Tuesday, 10 September 2013

Google Apps Script HtmlService Performance

If you are moving to HtmlService from UiApp, you may encounter some performance issues. First look at the best practices. Hopefully that section will expand over time.
HtmlService introduces Caja to the mix for good or ill and the processing changes quite significantly.
To explore the performance issues around some design decisions, I developed a simple form for an upload to Google Drive. Looking forward to a time when form is as important as function, I chose to style with Twitter Bootstrap and use a bootstrap extension to style the file input component.
Input form image
Simple input form
This means that, as well as the html, there a few .css and .js files to load.
Note that this example has no submit functionality coded, just the display and upload file selection.





I produced an Apps script that simply loaded the form, using bootstrap and jQuery from CDN and additional css and js from Google Drive hosting. Published as a web app here
function doGet() {
  return HtmlService.createHtmlOutputFromFile('bootstrap').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
 To provide a comparison with a hosted web site, I put the same html onto the Google Drive host, using the same .css and .js locations. Available here

The performance difference measured by Chrome at the desktop is quite startling. The Htmlservice script takes around 8seconds to display the form and a further 4seconds to complete loading the javascript files which make the form work. The Google Drive hosted version generally responded fully in 1.4seconds (with occasional outliers around 3.5seconds) which is not bad for a service intended for development rather than high performance service delivery.

A noticable feature of the HtmlService working is that the .js gets are sequential while the hosted version did them all in parallel.

[EDIT The results for the Htmlservice script were so bad that I explored possible workarounds. Putting the css and js files into the project and including them (as described in best practices) did improve the service time to 5-6 seconds. I could not get the jquery.min.js into the project ... the copy crashed in chrome. However, this approach does rather go against the simplicity of including the scripts from a CDN.]

From this, I shall be avoiding Htmlservice wherever possible. I do prefer the separation between presentation and Google Apps function that comes from JSON-P and Javascript.

Your milage may vary of course. I am seeing this in New Zealand at the end of an ADSL link.

Monday, 31 January 2011

SVG coming back, or getting there?



I am a fan of standards as a means of presenting information and having the wide audience seeing the same thing. I was encouraged by Kurt Cagle’s post  that “SVG has made it's way to the web” but I am not sure we are quite there. Of course, SVG has been used to present graphics on the web  for some time but seeing the results has required some  fancy footwork of plugins and careful selection of browser. I think Kurt is being a little premature in his announcement that “every single major browser on the desktop” will render  even specific examples of SVG consistently.
I actually wondered what Kurt was talking about as I viewed his post in the stable Firefox 3.6.10 because the SVG was not rendered at all, but I was sufficiently interested to switch on my laptop with its standard Chrome browser.
Kurt used this artwork http://www.openclipart.org/people/jhnri4/Glass_cup_with_saucer.svg demonstrating one problem with using SVG as a standard graphic ..., I can’t include this image in my Google Doc directly. But a bit of cutting and pasting gets us this.

Kurt provides it scaled to a 240 pixel square in the blog and on my FireFox 4 display it looked like this …

On Chrome however the picture is scaled differently to give you a whole cup.


The SVG word art  example in Kurt's blog was less successful, only appearing in Chrome. The scripting to change the word art did not work in Chrome or Firefox.
All this suggests that we have a way to go with our standards rendering.

[UPDATE : Came back to this later in the day and found that the word art scripting worked in FF4 and Chrome but that the wordart itself only rendered in Chrome]