The 6 best new features in npm 5

Last night I attended waffle.js and heard a great talk by Laurie Voss, aka seldo, the CTO of npm, about new features in npm@5. Several things have been upgraded and new features have been added in npm@5, so, if you haven’t upgraded yet, you’re missing out.

Here are a few things were upgraded in npm@5:

1 ) npm@5 is fast

npm@5 is much faster than previous versions of npm, and as easy to install as:

npm i npm -g

npm@5 is ten times faster than npm@4.
npm@4 is ten times faster than npm@3.
npm@3 is ten times faster than npm@2.
npm@2 is ten times faster than npm@1.

What does this mean?

10 x 10 x 10 x 10 = 104 = 10,000

It means the current version of npm is 10,000 faster than v1. Yes, I am exaggerating, but just a bit. Believe me, npm@5 is super fast.

2) npm@5 includes package-lock.json by default

Package lock makes npm faster because it doesn’t have to look up all the packages: it knows to use the ones you locked in. In addition, with locked packages, you get the same package versions in production as you do in development. This makes builds more reliable. Gone are the days of trying to figure out a bug only to discover it came from others running different versions of a library.

This does change how updates work. You will no longer automatically get the latest updates. Rather, you now need to explicitly update your packages to semver compatible package versions.

npx npm-check -u

The above snippet will make you go thru each npm update, allowing you to accept or decline breaking changes. npx is introduced in #6 below.

3) npm@5 saves by default

The risk of accidentally deleting a package is gone. You no longer have to use --save. If you install a package it will be there. If you don’t want the package anymore, you can delete it.

If you don’t want to save, you can override the default saving with --no-save.

4) Improved cache

Unbeknownst to many, npm has always had a cache — everything downloaded was stored locally — but not a very good one.

The cache improvements in npm@5 include how corrupt caches are handled: cache --clear has been made obsolete as with npm@5, if the cache is corrupted it will not be used.

5) npm@5 works offline

npm@5 auto detects when you are offline. When offline, npm will install using the local, improved, non-corrupted cache, noted in #4 above. You can force npm to run offline when you are actually online, by using --offline, This is handy for less than optimal connections, like when you’re whining about airplane, Starbucks, or conference wifi, and for those on metered data plans.

6) npx package runner

The new npx package runner will download, install, execute, and clean itself up. The order will be executed either locally or from a cache,  installing any dependencies needed. If a full package specifier is included,  npx will use a freshly-installed, temporary version of the package. If no –package option is specified, npx can guess the name of the binary to invoke depending on the specifier provided.

As an example, if you want to create a React app, simply run:

$ npx create-react-app
$ npm start

This will create a working React app.

The npx package runner is probably the most exciting of the six new features. Laurie’s talk covered the syntax for creating working apps for various libraries.

Future feature: cipm

cipm, the continuous integration package manager currently under development, installs npm dependencies from a package lock. Similar in usage to npm installcipm removes node_modules before beginning the install. It works with npm@5’s lock file.  cipm is useful in continuous integration environments requiring regular, full installs of apps that can cache package data in a central cache.

You can take a look at https://github.com/zkat/cipm. Play with it, but don’t put it into production. Yet.

W3C Performance Specifications

Here are some of the W3C’s web performance specifications:

  • High Resolution Time (Level 3)

    The DOMHighResTimeStamp type, performance.now method, and performance.timeOrigin attributes of the Performance interface resolve Date.now() issues with monotonically increasing time values with sub-millisecond resolution.

    https://w3c.github.io/hr-time

  • Performance Timeline (Level 2)

    Extends definition of the Performance interface, exposes PerformanceEntry in Web Workers and adds support for the PerformanceObserver interface.

    https://w3c.github.io/performance-timeline

  • Resource Timing (Level 3)

    Defines the PerformanceResourceTiming interface providing timing information related to resources in a document.

    https://w3c.github.io/resource-timing https://w3c.github.io/navigation-timing
    Supported in all browser except Safari and Opera Mini, starting with IE10

  • User Timing (Level 2)

    Extends Performance interface with PerformanceMark and PerformanceMeasure.

    https://w3c.github.io/user-timing
    Supported in all browser except Safari and Opera Mini, starting with IE10

  • Beacon API

    Defines a beacon API which can “guarantee” asynchronous and non-blocking delivery of data, while minimizing resource contention with other time-critical operations.

    https://w3c.github.io/beacon
    Not supported in IE, Safari or Opera Mini. Support started with Edge 14
    navigator.sendBeacon() on MDN

  • Preload

    Defines preload for resources which need to be fetched as early as possible, without being immediately processed and executed. Preloaded resources can be specified via declarative markup, the Link HTTP header, or scheduled with JS.

    https://w3c.github.io/preload

  • Cooperative Scheduling of Background Tasks

    Adds the requestIdleCallback method on the Window object, which enables the browser to schedule a callback when it would otherwise be idle, along with the associated cancelIdleCallback and timeRemaining methods.

    https://w3c.github.io/requestidlecallback

Capturing Captions from Youtube Videos

Note: This works for pre-captioned videos, not videos auto-captioned by Youtube.

There are many tutorials on how to download the caption files created by Youtube if you own the video, but I was unable to find a way to download the captions of videos I don’t own. There’s probably an easy way to do it, but since I couldn’t find it, creating a JavaScript function to do it via the console took less effort.

Here’s the code (I did it three ways depending on how you like to code your JS)

Constructor method:

function CaptionCollector () {
  var that = this;
  this.captions = '';
  var nowShowing = '';

  this.collect = function(){
    try {
      var currentCaption = document.getElementsByClassName("captions-text")[0].innerText;
    } catch (e) {
      var currentCaption = null;
    }

    if(currentCaption && nowShowing != currentCaption) {
      nowShowing = currentCaption;
      that.captions += ' ' + nowShowing;
    }

    setTimeout(that.collect, 300);
  }
}

var foo = new CaptionCollector();
foo.collect();

Print the caption with foo.captions. Of course you can use anything instead of “foo”.

Here’s a version using JS object notation:

var captionCollector = {
    captions : '',
    nowShowing: '',

    collect : function(){
      try {
        var currentCaption = document.getElementsByClassName("captions-text")[0].innerText;
      } catch (e) {
        var currentCaption = null;
      }
    if(currentCaption && this.nowShowing != currentCaption) {
        this.nowShowing = currentCaption;
        captionCollector.captions += ' ' + captionCollector.nowShowing;
     }
    setTimeout(captionCollector.collect, 300);
  }
}

captionCollector.collect();

With this version, you print the console with captionCollector.captions

Or you can use the anonymous function method with a single global variable:

(function(){
    ___captions = '';
    var ___nowShowing = '';

    function getCaption() {
        try {
          var currentCaption = document.getElementsByClassName("captions-text")[0].innerText;
        } catch (e) {
          var currentCaption = null;
        }

        if(currentCaption && ___nowShowing != currentCaption) {
          ___nowShowing = currentCaption;
          ___captions += ' ' + ___nowShowing;
        }
        setTimeout(getCaption, 300);
    }

    getCaption();
})();

With this version, you print the console with the global variable ____captions

Because it uses the classname of the caption box Youtube uses for videos, this only works on Youtube. Alter the classname for other video services.

You do have to play the whole video to capture all the captions. With settings, you can play the video at twice the speed.

Clear the console when the video ends. Print the transcript to the console. Select all. Copy. You’re good to go.

Lyrinė Tālrunis: “Telephone” with Lyric Translations

Last week I hacked together a mashup of HP’s IdolOnDemand‘s free Speech Recognition API and Google’s fee-for-service Translation API to create a Lyric Translator. Of course, I had to make the site responsive using VW units for text, and Flexbox for the layout. I also used a datalist to provide an optional list of usable media files. Then, tonight, I wrote a blog post explaining these components.

Enjoy!

The app

Lyrinė Tālrunis, or “Lyric Telephone”, does two things:

  1. It captures the text from an audio file using the free Speech Recognition API from HP IdolOnDemand,
  2. It then translates the captured text into from the original language into French, German, Spanish, Vietnamese, Russian and then back to the original language, enabling you to create new lyrics for — or a more entertaining interpretation of — your favorite songs.

The name is basically Lyrics, as in lyrics from songs, but you can use any media file, and ‘Telephone’ in reference to the game of telephone you learned in pre-K, where when a story gets passed to too many people (or languages) the original text gets morphed into something else.

As deployed, the app provides for two preloaded options of Rudolph the Red-nosed Reindeer and Frosty the Snowman, but you can include a link to any .wav or .mp3 file you find on line.

I’ll be expanding the application to allow for file uploads, and hope to implement uploading directly from your device’s microphone with:

<input type="file" accept="audio/*;capture=microphone">

For right now, simply find a song online, or even a video file, and include the full URL in the input box.

HP’s IdolOnDemand Speech Recognition API

IDOL OnDemand’s Speech Recognition API creates a transcript of the text in an audio or video file. It supports seven languages – including both US an UK English (yes, it will produce “colour” instead of “color” if you ask it to).

You do first need to register with IdolOnDemand to get an API Key. Then it’s a simple AJAX call.

The values you need create the request URL for the speech recognitio API include:

  • The encoded URI to your .wav or other audio of video file.
  • Your API Key
  • The language your file is in (defaults to en-US)

Here is how I created my URL:

  var apikey = YOUR_HP_API_KEY;
      url = document.getElementById('url').value,
      language = document.getElementById('lang').value, 
      query = 'https://api.idolondemand.com/1/api/sync/recognizespeech/v1' + '?';       
  query  += "&url=" + encodeURIComponent(url);
  query  += "&apikey=" + apikey;
  query  += "&language=" + ( language || "en-US");

Where url is the id of the input where the user enters the full path to the media file. The input has 3 default options for you to choose from, but you can enter any text you wish. This is explained in the <datalist> / list attribute section below.

The ‘lang’ is the ID of the <select> drop down that list the langage of the media file.

<select name="lang" id="lang">
  <option value="en-US">English (US)</option>
  <option value="en-GB">English (UK)</option>
  <option value="de-DE">German</option>
  <option value="es-ES">Español</option>
  <option value="fr-FR">Français</option>
  <option value="it-IT">Italiano</option>
</select>

The speech recognition API works for all the above languages and Chinese. Surprisingly, I can actually read and understand all of the languages above (don’t ask).  As I can’t read Chinese and wouldn’t be able to debug it, I didn’t include it in this app.  If you want to include Chinese as an option, please feel free to fork the app repo and add Chinese back in, but please use your own API key.

IDOL OnDemand’s Speech Recognition API uses the language code and the country subcode, so use the long form like “en-US” and not “en”. Don’t know what I am talking about (or have insomnia)? Read up on language tags.

Depending on the file size, your file can take a while to process, so make sure to let your user know something is happening, and make sure to handle errors in case it times out. For better user experience, when the button gets clicked, calling the API, the content of the button changes to a rotating pipe in the hopes of making a quick and easy spinner. (Check out the CSS file if you want to learn the animation, as I am not covering it here). The animation stops and the button returns to the original text when the text extraction of the media file is returned from the Speech API.

 var app = {
     ...
    
     init : function () {
	     // add eventHandler to button
        document.getElementById('doThis').addEventListener('click', function(){
          app.submitToHP();
          app.changeButton();
        });
      },

      // get the words from the original media file
      // the `data` object contains default values & the `apikey`
      submitToHP : function () {
        data.url = document.getElementById(
url').value || data.url;
        var query = data.request_url + '?';
            query += "&url=" + encodeURIComponent(data.url);
            query += "&apikey=" + data.apikey;
            query += "&language=" + document.getElementById('lang').value || "en-US");

        var request = $.ajax(query, function(e) {
                // successfully sent - no actions
              })
            .done(function(e) {
                // response received - handle it
                app.acceptResponse(e.document[0].content);
              })
            .fail(function(e) {
                // error - handle it
                app.acceptResponse('Oops, something went wrong.');
              })
            .always(function(e) {
                // finished - stop button animation
                app.revertButton();
            });
      },
      ... // continues

The reqest returns a JSON object:

{
  "document": [
    {
      "content": "the media speech is here"
    }
  ]
}

So we grab that content with:

e.document[0].content

where e is the response.

The other functions included, but not described include:

  • app.changeButton() — changes button to a spinner
  • app.revertButton() — resets the button to original behavior
  • app.acceptResponse(e.document[0].content) — writes text to the page, and initiates translations, which are done via the Goole Translate API

Google Translate API

I tried finding a good, free, intuitive, easy to use, translation API, but came up empty handed. Sorry Microsoft, you have too many steps, and I couldn’t just “dive right in.” I do, however, have the Yandex translation API on my list of things to look up. It looks like it might be a good free alternative to Google’s fee-for-service translation API.

Time is money, and I was already familiar with the Google Translate API, which is the main reason I chose it. Again, fork me repo to try something different.

The request URL for Google Translate API looks something like this:

var request_URL = "https://www.googleapis.com/language/translate/v2?key=" +  
  YOUR_GOOGLE_API_KEY +
  "&source=" + from +
  "&target=" + to +
  "&q=" + encodeURIComponent(text);

Where you use your own Google API Key, the ‘from’ is the original language, the ‘to’ is the language you want to translate to, and the text you encode with encodeURIComponent(text) is the return value from the Speech Recognition API, what we captured as e.document[0].content above.

As we are translating from the original language to French, German, Spanish, Vietnamese, Russian and then back again to the original language, we are calling the Google API 6 times. The important information is how to create the link for Google’s REST API. You can take a look at the source code to see how I iterate thru the various languages and call the AJAX call for each translation.

CSS3 Values

The page is full responsive. On larger devices, the font is larger. This is done without @media queries. I know. I know. Media queries are all the rage. But they’re not always necessary. CSS3 provides responsive features that enable the creation of responsive content without having to define where your design splits. The browser can do it for you.

In this case, it’s the VW, or viewport width unit, that makes the site naturally responsive. The VW unit is relative to the viewport width: the viewport width is 100vw. If you don’t know all your length units, my 4 year old post needs some updating.

  h1 {
    line-height: 30vh;
    font-size: 8vw;
  }

The above CSS snippet reads “the line height should be 30% of the viewport height. The font size should be 8% of the viewport width”

As the viewport narrows, the font-size will shrink. Yes, it will get illegible if the viewport is too narrow, but no phone is narrow enough to make that illegible. That size is relatively huge, and will even be legible on new watches. And the height shrinks, so does the line height, meaning the h1 will never be taller than 30% of the height of the viewport.

I used VW and VH for the height of the blue header and containers for the translation content: even when empty, the articles will be 40% of the document height.

The content in the button and the input also grow and shrink as the viewport grows or shrinks. vh and vw are very well supported, though vmax, the maximum value of the viewport width and height, and vmin, the lesser of those 2 values, is not fully supported.

CSS Flexible Box Layout Module

CSS Layout is fun! No. Seriously. It is. Just use flexbox.

body {
  display: flex;
  flex-direction: column;
  flex: 1 0 300px;
}
header, article {
  flex: 3;
  min-height: 40vh;
}
footer, main {
  flex: 1; 
  max-height: 10vh;
}
main, article {
  display: flex;
  justify-content: space-around;
  align-items: center;
}
section {
  flex: 1;
}
@media screen and (max-width: 500px) {
  main, article {
    flex-wrap: wrap;
  }
}

Above is just part of the CSS. I’ve posted the CSS relevant to the flexible layout of the document. You’ll note that the layout has four vertical sections: the header, main section with the buttons, the articles where the translations go, and the footer.

The body CSS code block above makes the body a flex container, and the header, main, article and footer all flex items. The flex-direction is column, so they’re one on top of another instead of row, which would put the parts side by side.

The main and article are not only flex items, but they, in turn, are also flex containers. The default flex-direction is row, so the children of the main and the children of the article will be laid out side by side within their parent. We have two flex items within the article (the original text result from the Speech API and the final result processed thru 5 translations.) These will be side by side, and will always be of equal height. They will not wrap by default, but if the width of the screen is 500px wide or less, the row of content can wrap, which means the translation can land below the text capture, and the input can land below the button, which can fall below the language selection.

This project is to show a very simple example of flex layout, and is not meant as a full flexbox tutorial. To learn more about flexbox, I have an open source flexbox tutorial you can play with. There you can see that justify-content: space-around; means that the extra space around the items will be evenly distributed around each item, and all the other flexbox, including several not included in this demonstration.

Datalist element and list attribute

Take a look at the input on the page. You’ll note, in modern browsers, there is a little arrow on the right, which if clicked, shows an autocomplete. This effect is achieved using the HTML5 list attribute along with the <datalist> element and that element’s nested <options>.

<input type="url" list="urls" id="url" placeholder=" URL of .wav file">
    
<datalist id="urls">
  <option value="http://estelle.github.io/audiotranslator/data/frosty.wav">Frosty</option>
  <option value="http://estelle.github.io/audiotranslator/data/rudolph.wav">Rudolph</option>
  <option value="http://estelle.github.io/audiotranslator/data/tet.wav">Test File</option>
</datalist>

In this example, we have an <input> of type url, with a list attribute. The value of the list attribute is the value of the ID of the datalist element. This associates the urls datalist with the input. If a browser doesn’t support datalist, it will simply not show the datalist. Totally progressive enhancement: the form control is still usable in Netscape 4.7

If the browser does support datalist, a drop down menu of the options will show when the input has focus. It will only show the values that are still potentionally valid. If you enter ‘h’, all the values will still show. ANy other character, and the options will no longer be valide options, and they will no longer be displayed. I have a tutorial on web forms, which demonstrates the inclusion of datalist on text, url, email, number, color, range, date and time input types.

Future of the app

Here are some ideas I have for expanding the application. Please fork and do it for me :D

  • File upload option
  • Drag and Drop from desktop to upload file
  • Audio Capture directly from your device
  • Inclusion of original <audio> for your listening pleasure

Web Development Tips

My Twitter account, WebDevTips, has been reactivated. Follow @webDevTips to get (almost) daily Web Development tips in your timeline.


Make Twitter DMs appear as if read in all browsers

Edited July 5, 2015

While the DMs no longer appear unread forever (thanks for the fix, Twitter), the ads are still annoying. Simply drag the Add Killer link to your tool bar and click when necessary.

————————— End Edit —————————

I use Twitter.com to access my tweets. I do so from several different computers and several different browsers on each of those computers. Since Direct Messages read/unread status is stored in local storage, I have to ‘read’ my DMs in every browser on every computer to make them appear read in each of those browsers. I hate that.

What I hate even more is that I have to click on my account drop down, then on direct messages link, then I have to individually open each DM thread to make them appear read, and back out of it before clearing the next.

This was driving me crazy. So, I created a little bookmarklet. I simply added the bookmarklet to each of my browsers. Now, whenever I see that little blue glow I simply click on the little bookmarklet, and the blue glow disappears until I actually get a new DM.

You can get the bookmarklet from my Github

This bookmarklet will mark all of you Twitter direct messages as read simply by deleting the entry in local storage.

The Code:

//Get the URL
var urlistwitter=window.location.href.split('/')[2].split('.'); 

// Check to see if the domain is twitter
if(urlistwitter[urlistwitter.length-2]==='twitter') {

   // remove the local storage item of unread DM references
   window.localStorage.removeItem('dm_threads');
}

// remove the icon that makes them appear unread
document.querySelector('#user-dropdown-toggle .nav-new').classList.remove('nav-new');

Drag this link to your toolbar. When you need to, click it when your Twitter window has focus to remove the localStorage entry and that annoying blue ‘unread’ icon:

Mark DMs as Read

details and summary polyfill

var summaryClick = function(elem){
  if (!('open' in document.createElement('details'))){
    var deetails = elem.parentNode;
    if(deetails.hasAttribute('open')){
     deetails.removeAttribute('open');
    } else {
     deetails.setAttribute('open', 'open')
    }
  }
}

add the summaryClick to your <summary> click event listeners

And then in my CSS I put something similar to:

details:not([open]) {
   height: 2em; 
   overflow: hidden;
}
details[open]  {
   height: auto;
}
summary::before {
   content: "▶ ";
}

Only browsers that understand the JS used will understand the selectors used. So, this isn’t fool proof, but it’s nice, quick and dirty.

Placeholder Attribute Support in ALL browsers

Included along with jQuery, the following code allows you to include the HTML5 placeholder attribute work in older browsers. The idea is to find all the input elements that have a placeholder attribute that the browser is ignoring since it doesn’t understand. Check to see if the input value is empty. If it is empty, include the placeholder value temporarily as the value (preferably making it look like a placeholder). If the user focuses on the input, clear the placeholder value, which is the default behavior in browsers that support the placeholder value. When the user exits the input box, the script checks to see if there is a value. If not, reinstate the value of the placeholder.

The second script is for when the user submits the form: we want to make sure that the form is not alwasy submitting the placeholder value. The main issue with this function is that the user cannot actually enter data that matches the placeholder, so, if you’re going to use this function, make sure that the placeholder value is not one that a user would intentionally submit. For example, use ‘first name’ and ‘last name’ for names, rather than ‘john’ and ‘doe’. Use ‘phone number’ or ‘415.555.1212’ for phone numbers, and other implausible values, etc.

  //make HTML5 placeholders work in non supportive browsers
  $("input[placeholder]").each(function(){
    if($(this).val()==""){
     // $(this).addClass('hasplaceholder');
      $(this).val($(this).attr("placeholder"));
      $(this).focus(function(){
        if($(this).val()==$(this).attr("placeholder")) $(this).val("");
       // $(this).removeClass('hasplaceholder');
      });
      $(this).blur(function(){
        if($(this).val()==""){
	  // $(this).addClass('hasplaceholder');
           $(this).val($(this).attr("placeholder"));
        }
       });
    }
  });

$('form').submit(function(evt){
	$('input[placeholder]').each(function(){
		if($(this).attr("placeholder") == $(this).val()) {$(this).val('');}
	});
});

Here are the lines explained:

Finds and iterates thru each input with a placeholder attribute:
$("input[placeholder]").each(function(){

Checks to see if the value is empty
if($(this).val()==""){

Commented out, you can add this line to add a class to the inputs that currently don’t have a value, so you can stylize them to look like placeholders (in other words, change the color to light grey using CSS):
// $(this).addClass('hasplaceholder');

Find the value of the placeholder attribute and sets it as the value of the value attribute
$(this).val($(this).attr("placeholder"));

Create an onFocus event handler
$(this).focus(function(){

When focused, checks to see if the current value matches the value of the placeholder. If so, it clears the placholder
if($(this).val()==$(this).attr("placeholder")) $(this).val("");

If you included the class to stylize the placeholder look and feel, remove it when the user is focusing on this input
// $(this).removeClass('hasplaceholder');

Close out the onFocus event handler
});

Create an onBlur event handler for when the user exits the input box
$(this).blur(function(){

Check to see if the input box is empty (the user has NOT entered any data)
if($(this).val()==""){

If the value is empty, we’re going to not just put the placeholder in, we should also include a class to be able to stylize it as a placeholder would look:
// $(this).addClass('hasplaceholder');

Put the value of the placeholder in the value — as we did on page load above.
$(this).val($(this).attr("placeholder"));

Close out all the set up stuff
}
});
}
});

We also need to ensure that the element has a legitimate value when the form is sumbitted:

We create an onSubmit event handler:
$('form').submit(function(evt){

We go thru all the inputs that have the placeholder attribute:
$('input[placeholder]').each(function(){

If the current value matches the placeholder value, we clear it before sumbitting:
if($(this).attr("placeholder") == $(this).val()) {$(this).val('');}

We close out the function:
});
});

Note that if the element is ‘required’, the submit function would be different and we would test to see if the browser supports the placeholder attribute before doing any of this, but i am just providing a small snippet to show how easy (and possible) it is to make older browsers support HTML5 form features.

Introduction to GeoLocation

Geolocation allows users to share their physical location with your application if they choose to. Especially useful in social networking, geo tagging, and mapping, but applicable to any type of application, geolocation enables developers to enhance the user experience, making content, social graphs and advertisements more relevant to the location of the user.

The browser will request the permission of the user before accessing geolocation information. Geolocation is an opt in feature: when your web application requests Geolocation information, mobile browsers create an alert, and the desktop browser asks via banner that pops up at the top of the browser window asking permission to access location information. The user can grant permission or deny it, and optionally remember the choice on that site. If permission is granted, the Geolocation information will be accessible to your scripts and any third party scripts included in the page, letting your application determine the location of the user, and maintain location as the user moves around.

Location information is approximate, not exact, being garnered from IP addresses, cell towers, Wi-Fi networks, GPS, or even getting the information through manual data entry by the user.  The geolocation API does not care how the client determines location as long as the data is received in a staddard way. Because determining location can take time, the geolocation API is asynchronous.

To determing browser support for geolocation use:

if(navigator.geolocation) {
   //geolocation is supported
}

The geolocation object provides for the getCurrentPosition() method that asynchronously returns the user’s current location.

if(navigator.geolocation) {
   navigator.geolocation.getCurrentPosition(handle_success, handle_errors);
}

If successful, the callback function will return the current position with the coords property contains the more common latitude and longitude properties as well as the altitude, accuracy, altitudeAccuracy, heading and speed properties. The following script will return the alert the current latitude and longitude, and is available in the chapter files:

if(navigator.geolocation) {
 navigator.geolocation.getCurrentPosition(handle_success,handle_errors); 
 
function handle_success(position){ 
 alert('Latitude: ' + position.coords.latitude + '\n Longitude: ' + position.coords.latitude); 
 }
 
 function handle_errors(err) { 
 switch(err.code) 
    { 
   case err.PERMISSION_DENIED: alert("User refused to share geolocation data"); 
   break; 
 
   case err.POSITION_UNAVAILABLE: alert("Current position is unavailable"); 
   break; 
 
   case err.TIMEOUT: alert("Timed out"); 
   break; 
 
   default: alert("Unknown error"); 
   break; 
  }
 } 

 

}

The draft specification can be found at http://dev.w3.org/geo/api/spec-source.html#geolocation_interface. Geolocation is support in Firefox, Webkit and Opera, but not IE. It is anticipated that it will be supported in IE9.

HTML5: Introduction to <canvas>

Canvas: Tutorial of basic canvas functionality, canvas properties and methods

The HTML5 Canvas specification is a JavaScript API for coding drawings. The canvas API allows the definition of a canvas context object as the <canvas> element on your HTML page inside which we can draw.

We can draw in both 2D and 3D (WebGL) context. 2D is available in all the modern Web browsers, IE9, and via excanvas.js in current versions of IE, and will be more thoroughly introduced below. 3D is still nascent, with only experimental implementations.

2D context provides a simple yet powerful API for performing quick drawing operation, on a 2D bitmap surface. There is no file format, and you can only draw using script. You do not have any DOM nodes for the shapes you draw — you’re drawing pixels, not vectors. OK, not true. You are drawing vectors, but once drawn, only the pixels are remembered.

Your first <canvas>

Being a very basic introduction to canvas, we are only going to cover basic shapes and lines. If you are unfamiliar with JavaScript, the syntax may at first seem a bit confusing. If you are familiar, it should make sense.

Step 1 is adding the <canvas> element to your document. In terms of HTML, the only step involved in adding a canvas to your document is adding the <canvas> element to your document:

<canvas id="flag" width="320" height="220">
You don't support Canvas. If you did, you would see a flag
</canvas>

That is it for the HTML part of it. . We could simply have written <canvas></canvas>. However, you should include an id for ease of JavaScript targeting, but you could also target via placement within the DOM. You can also define the width and height of the canvas, though you can define that in the CSS as well. We’ve also included alternative content for users that don’t support or otherwise can’t see your <canvas> content

With that, we’ve created your blank drawing board, or canvas. Everything else takes place in our JavaScript files. Step 2 is drawing on our canvas. From now on, everything is in javascript. We target the canvas node with getElementById(‘flag’) or getElementsByTagName(‘canvas’)[0], initialize a 2D context and start drawing using 2D context API commands. We can draw the Japanese flag:

<script>
var el= document.getElementById("flag");

if (el && el.getContext) {
var context = el.getContext('2d');
if(context){
context.fillStyle = "#ffffff";
context.strokeStyle = "#CCCCCC";
context.lineWidth = 1;
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = 'rgba(0, 0, 0, 0.4)';
context.strokeRect(10, 10, 300, 200);
context.fillRect(10, 10, 300, 200);
context.shadowColor='rgba(0,0,0,0)';
context.fillStyle = "#d60818";
context.arc(160, 107, 60, 0, Math.PI*2, false);
context.fill();

}
}
</script>

The first line finds your <canvas> element by matching the element’s id attribute. Before creating the 2D context, we check to make sure that the canvas element has been found AND that the browser supports canvas by checking for the existence of the getContext method.

We have to then create a reference to a context using the getContext(contextId) method of the canvas element –‘2d’ and ‘3d’ are the contextId value choices. If context creation is successful, we are finally free to draw in our canvas.

Before drawing a shape, we must define the look and feel of the shape we want to draw by setting properties on the context object. We define the look of the border (stroke and linewidth) properties and the shadow of our first rectangle, which we draw with the strokeRect() method. We pass the same parameters as our SVG example: (10, 10, 300, 200). The four values are the x-offset, the y-offset, width and height respectively. Once the script executes a command, the script forgets about what it has done, and moves onto the next line of code. Unlike our SVG example, the rectangle we’ve drawn on our canvas is not part of the DOM.

When we draw our second rectangle using the fillRect method, which paints rectangles using the previously set fillStyle property, we need to pass the coordinates again as the DOM does not remember our first rectangle, though it can access pixel information.

Both rectangle method calls have the same parameters — 10, 10, 300, 200 — we’ve drawn our fill rectangle directly on top of our dropshadow rectangle. We could have created an object with those coordinates and passed it to both methods, but we can’t tell the canvas to access the first rectangle’s coordinates and copy to the second after the method call

As mentioned above, once you paint onto the canvas, the DOM has no recollection of what you’ve painted. Yes, the JavaScript remembers the values of the properties you’ve set, but the pixels that are places on the canvas are just pixels of color. As we start the process of drawing the disc or sun on our flag, the DOM has no recollection of which pixels were painted with which colors, but it does remember some properties we set, like our shadowColor. As we don’t want a shadow on the red circle, we can set the shadowColor to transparent.

Next we define our circle. We are not actually drawing the circle yet. context . arc(x-offset of center, y-offset of center, radius, startAngle, endAngle, anticlockwise) adds points to an arced path creating a virtual circumference of a circle described by the arguments, starting at the given start angle, in our case 0, which is on the right horizon, and ending at the given end angle, going in the given direction, which in our case is clockwise. Had our endAngle been less than 2Π, our circle would have been flattened: the start and end points connected by a straight line. Π would have created a half circle. We also re-define the fill color, from white to red. We then paint the circle we created using the fill() method that fills the described arc in the fillStyle color.

We haven’t even touched the surface of what <canvas> can do. http://ie.microsoft.com/testdrive/Graphics/CanvasPad/Default.html is a fun page to learn simple shapes, colors, shadows, text, images, transformation, animation and mouse movement with <canvas>.

Canvas functions and properties

Styles

Set the fillStyle

context.fillStyle="color"

Set the strokeStyle

   context.strokeStyle="color"

Line widths

   context.lineWidth=number

Line join styles

   context.lineJoin="bevel || round || miter"

Line end styles

   context.lineCap="butt || round || square"

Rectangles

Draw a rectangle

   context.strokeRect(left, top, width, height)

Fill a rectangle

   context.fillRect(left, top, width, height)

Erase a rectangle

   context.clearRect(left, top, width, height)

paths

Begin a path

   context.beginPath

Complete a path

   context.closePath

Move the pen to a location

   context.moveTo(horizontal, vertical)

Draw a straight line from current point to a new location

   context.lineTo(horizontal, vertical)

Stroke the current path

   context.Stroke()

Fill the current path

   context.fill()

Shadows

Shadow color

   context.shadowColor="color"

Shadow horizontal offset

   context.shadowOffsetX=number

Shadow vertical offset

   context.shadowOffsetY=number

Shadow blur

   context.shadowBlur=number

Canvas versus SVG

HTML5 Canvas and SVG may seem similar, in that they are both web technologies that allow you to create rich graphics inside the browser, but they are fundamentally different. In SVG, you ‘draw’ with XML. For canvas, you draw with JavaScript. Canvas is the painting of pixels onto a canvas, once painted, each pixel is forgotten. SVG, on the other hand, creates DOM nodes, accessible until deleted or until navigation away from the page. They both have their advantages and disadvantages.

SVG is resolution independent, making SVG an excellent choice for user interfaces of all sizes as it allows scaling for all screen resolutions. SVG is an XML file format enabling easy accessibility. SVG can be animated using a declarative syntax, or via JavaScript. Each element becomes part of and is accessible via the SVG DOM API in JavaScript. However, anything that accesses the DOM repeatedly slows the page down.

Canvas is all drawn in pixels. Zooming can lead to pixilation. Canvas is inherently less accsessible: accessibility is limited mainly to including fallback content should canvas not render. Interactivity requires redrawing of each pixel. There are no DOM nodes for anything you draw. There’s no animation API, instead timers are generally used for updating the canvas at quick intervals. Canvas gives you a surface to draw onto with the API of the context you choose. Canvas, however, is very well suited for editing of images, generating raster graphics such as for games or fractals, and operations requiring pixel-level manipulation. Canvas can also be exported to gif or jpeg.