Friday, October 02, 2009

SVG at Google and in Internet Explorer

At Google we're excited about new web technologies like HTML 5, CSS 3, Web Fonts, SVG, faster JavaScript, and more. It's an exciting time to be a web developer, especially with the major advancements made in modern browsers like Firefox, Safari, Opera, and Chrome the last two years. In this blog post I want to share some of the work we've been doing with SVG in particular.

Today kicks off the start of the SVG Open 2009 conference, hosted at Google this year. The SVG Open conference is an annual conference where the SVG community comes together for three-days. Other sponsors of the conference this year include Microsoft and IBM.

What is SVG?

SVG, or Scalable Vector Graphics, is an open web standard that makes it easy to add interactive vector graphics to your web pages. Vector graphics, as opposed to bitmap graphics like JPG, GIF, or PNG files, describe the shapes on your screen with mathematical equations rendered by your computer rather than pixels. This allows vector graphics to stay beautiful and crisp whether displayed on a 40" monitor or a small mobile device.

Just as HTML gives you simple tags such as <form> or <table> to add to your web pages, SVG gives you such graphical tags as <circle> or <rect> for a rectangle that you can drop into your web page. Working with SVG is very similar to working with HTML - you use JavaScript to animate and make things interactive, CSS (Cascading Style Sheets) to add style, etc.

Why Google is Excited About SVG

We're excited about SVG for a host of reasons:

First, SVG is part of the HTML 5 family of technologies. One of the major new features of HTML 5 is the fact that you can now drop SVG tags into normal HTML, directly embedded into your page. We're excited about how this will empower developers. Here, for example, is a small code sample that embeds an SVG circle and rectangle right into an HTML 5 page:
<!DOCTYPE html>
<html>
<body>
<h1>SVG/HTML 5 Example</h1>
<svg>
<circle id="myCircle"
cx="100" cy="75" r="50"
fill="blue"
stroke="firebrick"
stroke-width="3" />
<text x="60" y="155">Hello World</text>
</svg>
</body>
</html>

Produces:


Second, we like that SVG is composed of text and markup, just like HTML. Because it's markup, search engines have a much easier time working with SVG; server-side languages like PHP or Google App Engine can simply emit SVG just like they generate HTML; and users and developers can easily view the source just like a normal web page to learn and move things forward. It's also easy to import and export SVG into tools like the open source Inkscape drawing package or Adobe Illustrator.

Third, the compact size of SVG when combined with HTTP GZip compression can easily make the images on a page roughly an order of magnitude smaller, and when directly embedded into an HTML 5 page can decrease the latency of a page by reducing the number of fetches. Small and fast are definitely two things we like at Google, and we like that SVG helps enable both.

Fourth, SVG integrates with the rest of the web stack, including JavaScript, CSS, and the DOM (Document Object Model). Even better, developers can easily adapt the skills they already know when working with SVG.

Finally, SVG is an open standard that is vendor-neutral. It also has accessibility built in, so when screen readers start to work with SVG your content will be future-proofed with accessibility baked in. We also like that SVG is now natively supported on all modern browsers, including the iPhone.

What Are Some Places We Use SVG?

We use SVG ourselves in a range of products. In Google Docs, for example, you can insert drawings, illustrations, and diagrams using a built in drawing tool:


On all browsers we use SVG to build this user interface; on Internet Explorer we have to revert to an older technology named Vector Markup Language (VML) unfortunately.


Another example is the Google Visualization API, which lets you access multiple sources of structured data that you can display, choosing from a large selection of visualizations. Some of these visualizations (such as this one and this one) use SVG to do their drawing on all browsers except Internet Explorer.

Canvas Or SVG? Oh My!

A natural question is how SVG compares to the Canvas tag. In our opinion both are needed for the web and are suitable for different applications.

The Canvas tag can best be thought of as a scriptable image tag that you build up yourself using JavaScript. This means it is lower-level, requiring you to keep track of all objects you have placed on the canvas. This can be a benefit if you want to do a large degree of non-interactive animation, but can quickly become a burden if you need to build sophisticated user interfaces.

SVG, meanwhile, is higher-level, doing the bookkeeping necessary to keep track of where everything is, making things like mouse interaction much easier. If you don't need this interaction, however, the overhead imposed by SVG can get in the way of certain applications. Because SVG is markup, importing and exporting is much easier, including SEO and accessibility.

We believe that Canvas versus SVG is a false dichotomy. A great example of both technologies working together is the Firefox Download Tracker. This page shows real time updates across the world whenever a copy of Firefox is downloaded. SVG is used to draw the map of the world; this is an appropriate use, since we don't want thousands of lines of JavaScript for this but rather markup from a tool like Inkscape. Red circles are drawn on top of the SVG using the Canvas tag as copies are downloaded; this is perfect for Canvas as the circles are non-interactive and might number in the thousands if copies are being downloaded rapidly.

SVG In Internet Explorer and in Wikipedia

Now that you know a bit more about SVG, why we like it, and some of the places we use it, let me tell you a bit about some of the work we've been doing to support SVG lately.

In addition to hosting this years conference, we are also helping to address the fact that SVG can't be used on Internet Explorer. It's hard for developers to use new web technologies if they can't deploy them on IE. In response to this, we've been working with others in the open source community on a drop-in JavaScript library named SVG Web that brings SVG to Internet Explorer.

SVG Web cleverly uses existing facilities on Internet Explorer 6, 7, and 8 to instantly enable SVG support without the user having to download any new software or plugins. Using SVG Web plus native SVG support you can now target close to 100% of the existing installed web base, today. Before SVG Web you could only target about ~30% of web browsers with SVG.

Once dropped in SVG Web gives you partial support for SVG 1.1, SVG Animation (SMIL), Fonts, Video and Audio, DOM and style scripting through JavaScript, and more in about a 60K library. Your SVG content can be embedded directly into normal HTML 5 or through the OBJECT tag. If native SVG support is already present in the browser then that is used. No downloads or plugins are necessary other than Flash which is used for the actual rendering, so it's very easy to use and incorporate into an existing web site. Here's a quick one minute introduction to SVG Web:



SVG Web is currently in alpha and is a developer release. It's also important to note that it is a collaboration with many others in the open source community outside Google, including Rick Masters at F5 Networks and James Hight at Zavoo Labs. Google is just one participant in this open source project. Finally, a JavaScript library will never be as fast as native support; this doesn't take Internet Explorer off the hook for needing to implement SVG, but it does help developers in the here and now deploy their SVG today to get the wheel turning.

In addition to helping enable SVG on Internet Explorer, we've been working with Wikipedia. Wikipedia has an impressively large collection of SVG files that are under Creative Commons licenses. Every one of these files is available in the Wikimedia Commons; for example here is the Linux penguin Tux as SVG. We've been working with Wikipedia to enable interactive zooming and panning of these SVG files, similar to Google Maps; even better, this functionality works in Internet Explorer thanks to the SVG Web library on the sixth largest site on the web.

Today at the SVG Open show we are demoing a prototype of the Wikipedia SVG Zoom and Pan tool; deployment to the wider base of Wikipedia users will happen after the conference and an appropriate QA period. Here's a screencast showing the tool in action:



We hope you are as excited as we are about SVG and other new web technologies in the pipeline!

Monday, September 28, 2009

Chris Anderson: CouchDB: Relaxing Offline JavaScript

Last week I hosted Chris Anderson for a Google tech talk on CouchDB as part of the Web Exponents speaker series. Chris is an Apache CouchDB committer. He is co-author of the forthcoming O'Reilly book CouchDB: The Definitive Guide and a director of couch.io.

Making web applications work offline is a hot topic. Google Gears blazed the trail, and Web Storage is part of HTML5. CouchDB is a NoSQL alternative that makes it easy for web apps to run offline. This is important because even as bandwidth grows, latency is still an issue for a significant number of users, and outages or zero-bars can and do happen. CouchDB makes this a non-issue by running your application close to the user, on their device or in their browser. Chris calls this "ground computing" - a refreshing counterpoint to the oft-used "cloud computing" label. Hear more from Chris in his video and slides.



Check out other videos in the Web Exponents speaker series:

Thursday, September 24, 2009

Google Sites: Now with an API!

Today, we launched a new Google Data API for Google Sites. The API supports most of the functionality found in Google Sites, which includes the ability to:
  • Retrieve, create, modify, and delete pages and content.
  • Upload/download attachments.
  • Review the revision history across a site.
  • Display recent user activity.
To get started, see the full documentation, Java Developer's Guide, or dive into our code samples. We're also open-sourcing an import/export tool that uploads or creates a local back-up of an entire Google Site.

Visit us in our new developer forum if you have questions!

Wednesday, September 23, 2009

Gmail for Mobile HTML5 Series: CSS Transforms and Floaty Bars

On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of what we've learned in a brief series of follow-up blog posts. This week, I'll talk about different ways to animate the floaty bar.

Even from the earliest brainstorming days for our new version of Gmail for iPhone and Android-powered devices, we knew we wanted to try something novel with menu actions: a context-sensitive, always-accessible UI element that follows conveniently as a user scrolls. Thus, the "floaty bar" was born! It took us a surprisingly long time, experimenting with different techniques and interactions, to converge on the design you see today. Let's look under the covers to see how the animation is achieved. You may be surprised to find that the logic is actually quite simple!


Screenshots of the floaty bar in action

In CSS:
.CSS_FLOATY_BAR {
...
top: -50px; /* start off the screen, so it slides in nicely */
-webkit-transition: top 0.2s ease-out;
...
}
In JavaScript:
// Constructor for the floaty bar
gmail.FloatyBar = function() {
this.menuDiv = document.createElement('div');
this.menuDiv.className = CSS_FLOATY_BAR;
...
};

// Called when it's time for the floaty bar to move
gmail.FloatyBar.prototype.setTop = function() {
this.menuDiv.style.top = window.scrollY + 'px';
};

// Called when the floaty bar menu is dismissed
gmail.FloatyBar.prototype.hideOffScreen = function() {
this.menuDiv.style.top = '-50px';
};

gmail.floatyBar = new gmail.FloatyBar();

// Listen for scroll events on the top level window
window.onscroll = function() {
...
gmail.floatyBar.setTop();
...
};
The essence here is that when the viewport scrolls, the floaty bar 'top' is set to the new viewport offset. The -webkit-transition rule specifies the animation parameters. (The 'top' property is to be animated, over 0.2s, using the ease-out timing function.) This is the animation behavior we had at launch, and it works just fine on Android and mobile Safari browsers.

However, there's actually a better way to achieve the same effect, and the improvement is particularly evident on mobile Safari. The trick is to use "CSS transforms". CSS transforms is a mechanism for applying different types of affine transformations to page elements, specified via CSS. We're going to use a simple one which is translateY. Here's the same logic, updated to use CSS transforms.

In CSS:
.CSS_FLOATY_BAR {
...
top: -50px; /* start off the screen, so it slides in nicely */
-webkit-transition: -webkit-transform 0.2s ease-out;
...
}
In JavaScript:
// Called when it's time for the floaty bar to move
gmail.FloatyBar.prototype.setTop = function() {
var translate = window.scrollY - (-50);
this.menuDiv.style['-webkit-transform'] = 'translateY(' + translate + 'px)';
};

// Called when the floaty bar menu is dismissed
gmail.FloatyBar.prototype.hideOffScreen = function() {
this.menuDiv.style['-webkit-transform'] = 'translateY(0px)';
};
Upon every scroll event, the floaty bar is translated vertically to the new viewport offset (modulo the offscreen offset which is important to the floaty bar's initial appearance). And, why exactly is this such an improvement? Even though the logic is equivalent, iPhone OS's implementation of CSS transforms is "performance enhanced", whilst our first iteration (animating the 'top' property) is performed by the OS in software. That's why the experience was unfortunately somewhat chunky at times, depending on the speed of the iPhone hardware.

You'll see smoother looking floaty bars coming very soon to an iPhone near you. This is just the first in a series of improvements we're planning for the mobile Gmail floaty bar. Watch for them in our iterative webapp, rolling out over the next couple of weeks and months!



Previous posts from Gmail for Mobile HTML5 Series:
HTML5 and Webkit pave the way for mobile web applications
Using AppCache to launch offline - Part 1
Using AppCache to launch offline - Part 2
Using AppCache to launch offline - Part 3
A Common API for Web Storage
Suggestions for better performance
Cache pattern for offline HTML5 web application
Using timers effectively
Autogrowing Textareas
Reducing Startup Latency

Announcing the Google Sidewiki API

Alongside the exciting release of Google Sidewiki today, we're also happy to announce the availability of the first version of the Google Sidewiki Data API. Google Sidewiki is a new feature of Google Toolbar (for Firefox and Internet Explorer) that lets everyone contribute helpful information next to any webpage. Our post over on the Google Blog goes into more detail and also has a video that shows Sidewiki in action. To start using it yourself, go to google.com/sidewiki and install Google Toolbar with Sidewiki.

On the developer side, we're releasing a Google Sidewiki Data API today that lets you work freely with the content that's created in Google Sidewiki. You can use it to retrieve all entries written about a particular webpage as well as all entries written by a given Sidewiki author.

So after you've played with Sidewiki in the browser, give it a whirl in your console too -- we have client libraries, documentation and code samples ready to go for you. We'll be excited to see what gadgets, projects and extensions you'll think of. A translation gadget that displays and translates Sidewiki entries on the fly? A Google App Engine-powered browser of all Sidewiki entries? Your own browser extension or Greasemonkey script?

The Google Sidewiki API is available in Google Code Labs and is read-only at the moment. We've set up a developer-oriented discussion group and issue tracker where you can discuss your experiences with the API and where we'd love to hear about your feedback and projects. Keep us posted!

Tuesday, September 22, 2009

Video Introduction to HTML 5

Are you interested in HTML 5 and what's coming down the pipeline but haven't had time to read any articles yet? We've put together an educational Introduction to HTML 5 video that goes over many of the major aspects of this new standard, including:
  • Web vector graphics with the Canvas tag and Scalable Vector Graphics (SVG)
  • The Geolocation API
  • HTML 5 Video
  • The HTML 5 Database and Application Cache
  • Web workers
In the video we also crack open the HTML 5 YouTube Video prototype to show you some of the new HTML 5 tags, such as nav, article, etc. It's chock full of demos and sample source code.



Introducing Google Chrome Frame

Today, we're releasing an early version of Google Chrome Frame, an open source plug-in that brings HTML5 and other open web technologies to Internet Explorer.

We're building Google Chrome Frame to help web developers deliver faster, richer applications like Google Wave. Recent JavaScript performance improvements and the emergence of HTML5 have enabled web applications to do things that could previously only be done by desktop software. One challenge developers face in using these new technologies is that they are not yet supported by Internet Explorer. Developers can't afford to ignore IE -- most people use some version of IE -- so they end up spending lots of time implementing work-arounds or limiting the functionality of their apps.

With Google Chrome Frame, developers can now take advantage of the latest open web technologies, even in Internet Explorer. From a faster Javascript engine,  to support for current web technologies like HTML5's offline capabilities and <canvas>, to modern CSS/Layout handling, Google Chrome Frame enables these features within IE with no additional coding or testing for different browser versions.

To start using Google Chrome Frame, all developers need to do is to add a single tag:

<meta http-equiv="X-UA-Compatible" content="chrome=1">

When Google Chrome Frame detects this tag it switches automatically to using Google Chrome's speedy WebKit-based rendering engine. It's that easy. For users, installing Google Chrome Frame will allow them to seamlessly enjoy modern web apps at blazing speeds, through the familiar interface of the version of IE that they are currently using.

We believe that Google Chrome Frame makes life easier for web developers as well as users. While this is still an early version intended for developers, our team invites you to try out this for your site. You can start by reading our documentation. Please share your feedback in our discussion group and file any bugs you find through the Chromium issue tracker.



(Cross-posted on the Chromium Blog)

Tuesday, September 15, 2009

Registration Opens for fall 2009 Google Developer Days

We are excited to open registration for our second round of Google Developer Day events this year:
Both events will offer opportunities to learn the latest about our APIs and developer tools, including Android, Google Chrome, Google Wave, App Engine, AJAX APIs and more. There will also be time for developers to socialize - whether at "office hours" or the "after hours".  You'll be able to chat about your latest project or discuss that brain-busting question with fellow developers and Google engineers.

Similar to our Google I/O event in the US, the Developer Days will host a developer sandbox area, highlighting partners who have used Google developer products to build their own unique applications.  You can also take the opportunity to share a project or coding experience during our lightning talks. We look forward to seeing what developers bring to the table this year!

Space is limited so register soon!

Monday, September 14, 2009

Legacy gadget API deprecation

If you're a gadget developer, you've probably used the gadgets.* API, a re-namespaced and improved version of the original legacy, or _IG_*, gadgets API. The gadgets.* API has gained wide acceptance, both on Google and non-Google gadget containers, and is the standard API for gadget development.

However, there remains a number of gadgets using the legacy API, primarily gadgets developed for iGoogle, and the time to upgrade those gadgets is now. As of today, the legacy gadgets API is officially deprecated. For a period of one year, gadgets using the legacy API will continue to be supported, and function. After that, the legacy API will be turned off for the majority of Google containers (such as iGoogle, orkut, Gmail, and Calendar).

For more specifics on how the deprecation affects iGoogle developers, and details on coming resources to help in the API transition, check out this post on the iGoogle developer blog.

Thursday, September 03, 2009

Gmail for Mobile HTML5 Series: Reducing Startup Latency

On April 7th, Google launched a new version of Gmail for mobile for iPhone and Android-powered devices. We shared the behind-the-scenes story through this blog and decided to share more of what we've learned in a brief series of follow-up blog posts. This week, I'll talk about how modularization can be used to greatly reduce the startup latency of a web app.

To a user, the startup latency of an HTML 5 based application is critical. It is their first impression of the application's performance. If it's really slow, they might not even bother to wait for the app to load before navigating away. Even if your application is blazing fast after it loads, the user may never get the chance to experience it.

There are several aspects of an HTML 5 based application that contribute to startup latency:
  1. Network time to fetch the application (JavaScript + HTML)
  2. JavaScript parse time
  3. Code execution time to fetch the data and render the home page of your application
The third issue is up to you! The first two issues, however, are directly correlated with the size of the application. This is a tricky problem since as your application matures, it will have more features and the code size will get bigger. So, what to do? Modularize your application! Split up your code into independent, standalone modules. Consider splitting each view/screen of your application and implement each new feature as its own module. This is only half the story. Now that you have your code modularized, you need to decide which subset of these modules are critical to load your application's home page. All the non-core modules should be downloaded and parsed at a later time. With a consistent code size for your startup code, you can maintain a consistent startup time. Now, let's go into some nitty gritty details of how we built an application with lazy-loaded modules.

How to Split Your Code into Modules

Splitting an application into individual modules might not be as simple as you think. Code that serves a common purpose/functionality should be grouped together and form a module (comparable to a library). As mentioned earlier, we selected which modules are critical to the home page of the app and which modules can be lazy-loaded at a later time. Let's use a Weather application as an example:

High Level Functionality:
  • A "Weather in my Favourite Cities" home page
  • Click on a city to view the cities entire week forecast
  • Weather data comes from an external web service
Possible Module Separation:
  • Weather data model
  • Weather web service API
  • Common UI widgets (buttons, toolbars, navigation, etc)
  • Favourite Cities page
  • City Weather Forecast page
Now let's say your users want a "breaking news" feature. No problem: just put the page, the news data API and the data model into a new module.

One thing to keep in mind is the dependency order of your modules. For modules that have many downstream dependencies, it might make sense to include them as part of the core modules.

How to Lazy Load the Modules

Option 1: Script as DOM

This method uses JavaScript to insert SCRIPT tags into the HEAD's DOM.
<script type="text/JavaScript">
  function loadFile(url) {
    var script = document.createElement('SCRIPT');
    script.src = url;
    document.getElementsByTagName('HEAD')[0].appendChild(script);
  }
</script>
Option 2: XmlHttpRequest (XHR)

This method sets up XmlHttpRequests to retrieve the JavaScript . The returned string should be evaluated in the XHR callbacks (using the eval(string) method). This method is a little more complicated but it gives you more control over error handling.
<script type="text/JavaScript">
  function loadFile(url) {
     function callback() {
      if (req.readyState == 4) { // 4 = Loaded
        if (req.status == 200) {
          eval(req.responseText);
        } else {
          // Error
        }
      }
    };
    var req = new XMLHttpRequest();
    req.onreadystatechange = callback;
    req.open("GET", url, true);
    req.send("");
  }
</script>
The next question is, when to lazy load the modules? One strategy is to lazy load the modules in the background once the home page has been loaded. This approach has some drawbacks. First, JavaScript execution in the browser is single threaded. So while you are loading the modules in the background, the rest of your app becomes non-responsive to user actions while the modules load. Second, it's very difficult to decide when, and in what order, to load the modules. What if a user tries to access a feature/page you have yet to lazy load in the background? A better strategy is to associate the loading of a module with a user's action. Typically, user actions are associated with an invocation of an asynchronous function (for example, an onclick handler). This is the perfect time for you to lazy load the module since the code will have to be fetched over the network. If mobile networks are slow, you can adopt a strategy where you prefetch the code of the modules in advance and keep them stored in the javascript heap. Only then parse and load the corresponding module on user action. One word of caution is that you should make sure your prefetching strategy doesn't impact the user's experience - for example, don't prefetch all the modules while you are fetching user data. Remember, dividing up the latency has far better for users than bunching it all together during startup.

For an HTML 5 application that takes advantage of the application cache to reduce startup latency and to serve the application offline, there are a few caveats one should be aware of. Mobile networks have decent bandwidth, but poor round trip latency, so listing each module as a separate resource in the manifest incurs quite a bit of extra startup latency when the application cache is empty. Also, if one of the module resources fails to be downloaded by the application cache (e.g. disconnected from network), additional error handling code needs to be written to handle such a case. Finally, applications today have no control when the application cache decides to download the resources in the manifest (such a feature is not defined in the current specification of the draft standard). Typically, resources are downloaded once the main page is loaded, but that's not an ideal time since that's when the application requests user data.

To work-around these caveats, we found a trick that allows you to bundle all of your modules into a single resource without having to parse any of the JavaScript. Of course, with this strategy, there is greater latency with the initial download of the single resource (since it has all your JavaScript modules), but once the resource is stored in the browser's application cache, this issue becomes much less of a factor.

To combine all modules into a single resource, we wrote each module into a separate script tag and hid the code inside a comment block (/* */). When the resource first loads, none of the code is parsed since it is commented out. To load a module, find the DOM element for the corresponding script tag, strip out the comment block, and eval() the code. If the web app supports XHTML, this trick is even more elegant as the modules can be hidden inside a CDATA tag instead of a script tag. An added bonus is the ability to lazy load your modules synchronously since there's no longer a need to fetch the modules asynchronously over the network.

On an iPhone 2.2 device, 200k of JavaScript held within a block comment adds 240ms during page load, whereas 200k of JavaScript that is parsed during page load added 2600 ms. That's more than a 10x reduction in startup latency by eliminating 200k of unneeded JavaScript during page load! Take a look at the code sample below to see how this is done.
<html>
...
<script id="lazy">
// Make sure you strip out (or replace) comment blocks in your JavaScript first.
/*
JavaScript of lazy module
*/
</script>

<script>
  function lazyLoad() {
    var lazyElement = document.getElementById('lazy');
    var lazyElementBody = lazyElement.innerHTML;
    var jsCode = stripOutCommentBlock(lazyElementBody);
    eval(jsCode);
  }
</script>

<div onclick=lazyLoad()> Lazy Load </div>
</html>
In the future, we hope that the HTML5 standard will allow more control over when the application cache should download resources in the manifest, since using comments to pass along code is not elegant but worked nicely for us. In addition, the snippets of code are not meant to be a reference implementation and one should consider many additional optimizations such as stripping white space and compiling the JavaScript to make its parsing and execution faster. To learn more about web performance, get tips and tricks to improve the speed of your web applications and to download tools, please visit http://code.google.com/speed.

Previous posts from Gmail for Mobile HTML5 Series

HTML5 and Webkit pave the way for mobile web applications
Using AppCache to launch offline - Part 1
Using AppCache to launch offline - Part 2
Using AppCache to launch offline - Part 3
A Common API for Web Storage
Suggestions for better performance
Cache pattern for offline HTML5 web application