Category Archives: JavaScript

Setting CSS Background Colors via Javascript – RGB triplet vs Hex

10 Oct 2012

We’ve all had to do it – change the color of text or visible html elements like Div backgrounds or borders, etc. One thing I’ve noticed is that when I request the background color of a Div I get the RGB triplet, not a hexadecimal value. Observe this example:

(Please use a modern browser, I’ve made no effort to make the examples work in old browsers)

<html><head><title></title>
<script language="javascript">
  function getColor(){
    document.getElementById('result').innerHTML = document.getElementById('dd').style.backgroundColor;
  }
</script>
</head>
<body>
<p><a href="javascript:getColor()">Click here to get the color of the box</a></p>
<p>The box color is: <span id="result"></span></p>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="dd"></div>
</body>
</html>

 

Notice that the color obtained is not the hexadecimal value that you saw in the sample source provided above but the RGB equivalent even though its Hexadecimal to begin with.

Next, if I were to attempt to change the color by setting the css background-color value to an RGB value nothing will happen. See this example:

<html><head><title></title>
<script language="javascript">
function setColor(){
  document.getElementById('result').style.backgroundColor = 'rgb(122, 122, 122)';
}
</script>
</head>
<body>
<p><a href="javascript:setColor()">Click here to change the box color with an RGB value: rgb(122, 122, 122);</a></p>
<p>The box color is: <span id="result"></span></p>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="dd"></div>
</body>
</html>

 

As you can see… nothing happens…. so in order to change the background color you must use a hexidecimal value.

If we get a hex value from an element it will be RGB so in order to make it useful elsewhere in our code we would need to convert the RGB back to hexadecimal. Below is a function I wrote that will do that for us.

...
function convertToHex(str){
  var raw = str.match(/(\d+)/g);
  var hexr = parseInt(raw[0]).toString(16);
  var hexg = parseInt(raw[1]).toString(16);
  var hexb = parseInt(raw[2]).toString(16);
      hexr = hexr.value == 1 ? '0' + hexr: hexr;
      hexg = hexg.length == 1 ? '0' + hexg: hexg;
      hexb = hexb.length == 1 ? '0' + hexb: hexb;
  var hex = '#' + hexr + hexg + hexb;
  return hex;
}
...

This function takes an RGB of the following format: rgb(x, x, x) where “x” is any number within the RGB number range. The short description of what is happening would be to say that hexadecimal is base 16, thus the toString(16) which gives us the hex equivalent of each individual RGB value.

The long description would to say that the basic usage of toString() is to convert a number to a string, but we can also pass an argument to the toString() method to tell it what base to convert the number to. A few different bases are available. If we wanted to convert a number to binary we would use toString(2) (pronounced to string base 2), to octal, we would use toString(8) and finally to convert to hexadecimal we use toString(16). Using a base of 10 as in toString(10) is the same as using nothing at all – base 10 is decimal which is what numbers are to begin with.

An interesting thing to note is that hexadecimal is a numbering system from 0 to 9 and then continuing from A to F which totals 16 characters. 15 in hex is “f” which is just one character in length. 16 is two characters – ’10’. So any RGB value lower than 16 in hexadecimal will be a single character in length. Such values need to be left-padded by a zero since a hexadecimal color is always a total of 6 characters (2 characters per R, G, and B). To use our example, 15 = f in hex, we need to left zero pad it to be “0f”. If your RGB value is rgb(15, 15, 15) the proper hexadecimal value would be “0f0f0f” and not “fff” (which is a completely different color, see below). You can see the zero-padding happening in the ternary operators on lines 7, 8, and 9.

The caveat to all of this are the “shortcode” hex values that you see from time to time. Such as “fff” for white which in its full form is “ffffff”, or “ccc” for a light grey which is really “cccccc”. How about this shortened hex: “7de” – that would be “77ddee”. See the pattern? If a browser sees a 3 character hex value then each individual character must represent R, G, and B. In the absence of any other data the rest of the hex values are implied by the existing data, so “7” = “77, “d” = “dd” and “e” = “ee”. It is then necessary to give a browser a full hexadecimal value where necessary to get the actual colors, not implied colors. Left zero-padding where needed achieves this.

So here now is my last example using a color palette toolbar to change the color of a Div element, where I take the background color of the clicked Div element, which is revealed as RGB, convert it back to hexadecimal and apply it to the color box:

<html><head><title></title>
<script language="javascript">
  function convertToHex(str){
    var raw = str.match(/(\d+)/g);
    var hexr = parseInt(raw[0]).toString(16);
    var hexg = parseInt(raw[1]).toString(16);
    var hexb = parseInt(raw[2]).toString(16);
        hexr = hexr.length == 1 ? '0' + hexr: hexr;
        hexg = hexg.length == 1 ? '0' + hexg: hexg;
        hexb = hexb.length == 1 ? '0' + hexb: hexb;
    var hex = '#' + hexr + hexg + hexb;
    return hex;
  }

  window.addEventListener('load',function(){
    document.getElementById('colorWrapper').addEventListener('click',function(e){
      if (e.target.attributes['class'].nodeValue == 'colorSwatch'){
        document.getElementById('box').style.backgroundColor = convertToHex(e.target.style.backgroundColor);
      }
    },false);
  },false);
</script>
<style type="text/css">
  #colorWrapper{
    padding:0px 8px 8px 8px;
    border:1px solid #000;
    width:228px;
    margin: 0px 0px 20px 0px;
  }
  .colorSwatch{
    height:50px;
    width:50px;
    display:inline-block;
  }
</style>
</head>
<body>

<div id="colorWrapper">
  <p>Select a color to change the box's background color.</p>
  <div class="colorSwatch" style="background-color:#5d8eae"></div>
  <div class="colorSwatch" style="background-color:#adae5d"></div>
  <div class="colorSwatch" style="background-color:#78ae5d"></div>
  <div class="colorSwatch" style="background-color:#a05dae"></div>
</div>
<div style="height:100px;width:100px;background-color:#185f8e;border:1px solid #ccc;" id="box"></div>
</body>
</html>

 

An interesting thing to note is that the hexedecimal is not inserted as hexadecimal – its inserted as RGB! Yeah… I don’t know why either… if someone knows, please enlighten me in the comments below….

Using JsDoc With Closures

05 Oct 2012

I’ve just recently switched over to using JsDoc to document my code. JsDoc will take commented JavaScript source-code and create formatted HTML documentation.

The only hurdle in my learning how to use JsDoc was getting it to document my variables/functions locked within closures and the answer turned out to be pretty simple.

To get started with JsDoc you have to first take a moment to get familiar with the JsDoc syntax. After that generating documentation is only a matter of executing JsDoc itself via command line.

Before I go any further here are some links:

Syntax

JsDoc syntax is easy to wrap your head around especially as examples can easily be found. The Wikipedia page for JsDoc is helpful, as is the actual JsDoc Wiki – and if you’ll permit me, this blog post! 😉

Here’s an example of using JsDoc with code written using the closure pattern:

...
/** 
 * module_1()
 * This function encapsulates all variables and methods used within module 1. 
 * @type {Object}
 * @return {} returns nothing
 * @name module_1
 * @namespace Hold all functionality
 */
var module_1 = (function(){
    /** 
    * createNewCustomerGroup()
    * This function handles creating new customer groups
    * @type {Function}
    * @return {} returns nothing
    * @param {String} The new customer group name
    * @see module_1.customerGroup.createCustomerGroup()
    */
    function createNewCustomerGroup(str){
        // code here
    }
})();
...

Of interest here are the @name and @namespace JsDoc tags – without this the object won’t be inspected by JsDoc.

Also note the description at the top of the comment – JsDoc assumes that any lines not starting with the @ symbol will be the description even though they are not preceeded by the @description tag.

Here’s an example of some JsDoc output:

Running JsDoc

JsDoc runs from the command line. Provided you have a compatible version of java installed (see the JsDoc Toolkit home page) its a pretty simple matter to generate your code.

First, as with any command-line applications that I personally use I place the apps themselves at the root of my machine so as to be able to get to them faster – in my case its my E: drive.

Next, take your javascript file and copy it into the JsDoc root – this location will contain jsrun.jar

With your file in place you’ll need to start up your machine’s command prompt and navigate to where your javascript file has just been copied to. The image below shows the location on my computer:

The next part is constructing the command to send to jsrun.jar – to make this easy on yourself just do what I do – write it once and keep it in a text file for quick editing/copying. In this example the command line looks like this:

java -jar jsrun.jar app\run.js -a -t=templates\jsdoc module1.js -a -p -v

Where “module1.js” is the script that I want to generate documentation of. Notice the switches at the end of the string, they are:

  • -a include all functions
  • -p include private/underscored functions
  • -v verbose feedback, this will print out within the command prompt

So, lets execute the above command line… I’ll just copy it, then right click on the Windows command prompt and paste, and then hit “return” to get things rolling. Here’s the result and feedback courtesy of the verbose switch:

The generated documentation will be in the “out” folder which exists in the JsDoc root. That’s all there is to it, go forth and document!

Using the Google Maps API to Get Locations from Zip Codes

14 Sep 2012

Google offers many API’s, among them is the Maps API. In this example we’ll show all the code necessary to hit Google with a zip code to get the location in the form of City, State and Country.

As of June 22, 2016 you **must** apply for a Google Maps API key. All sites that use the service prior to June 22 will be grandfathered into the Google Maps service for keyless usage (Read this post from the Google Geo Developers Blog). Any new applications must include an API key so that Google can enforce rate limiting. If you see this error message: “MissingKeyMapError” – you are trying to use the Google Maps Service without a key – the fix is simply to acquire and start using an API key.

First thing to do is to reference Google’s Map API:

...
<script language="javascript" src="https://maps.google.com/maps/api/js?sensor=false&key=YOUR-API-KEY"></script>
...

Next is a little form used to enter your zip code:

...
<form>
zip: \<input type="text" name="zip" value="46032"> <a href="#" onclick="getLocation()">Get Address</a>
</form>
...

You can see that I have a link which fires a function called “getLocation()” – below you’ll find that function and the related code:

...
function getLocation(){
  getAddressInfoByZip(document.forms[0].zip.value);
}

function response(obj){
  console.log(obj);
}
function getAddressInfoByZip(zip){
  if(zip.length >= 5 && typeof google != 'undefined'){
    var addr = {};
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({ 'address': zip }, function(results, status){
      if (status == google.maps.GeocoderStatus.OK){
        if (results.length >= 1) {
	  for (var ii = 0; ii < results[0].address_components.length; ii++){
	    var street_number = route = street = city = state = zipcode = country = formatted_address = '';
	    var types = results[0].address_components[ii].types.join(",");
	    if (types == "street_number"){
	      addr.street_number = results[0].address_components[ii].long_name;
	    }
	    if (types == "route" || types == "point_of_interest,establishment"){
	      addr.route = results[0].address_components[ii].long_name;
	    }
	    if (types == "sublocality,political" || types == "locality,political" || types == "neighborhood,political" || types == "administrative_area_level_3,political"){
	      addr.city = (city == '' || types == "locality,political") ? results[0].address_components[ii].long_name : city;
	    }
	    if (types == "administrative_area_level_1,political"){
	      addr.state = results[0].address_components[ii].short_name;
	    }
	    if (types == "postal_code" || types == "postal_code_prefix,postal_code"){
	      addr.zipcode = results[0].address_components[ii].long_name;
	    }
	    if (types == "country,political"){
	      addr.country = results[0].address_components[ii].long_name;
	    }
	  }
	  addr.success = true;
	  for (name in addr){
	      console.log('### google maps api ### ' + name + ': ' + addr[name] );
	  }
	  response(addr);
        } else {
          response({success:false});
        }
      } else {
        response({success:false});
      }
    });
  } else {
    response({success:false});
  }
}
...

Thats it - open up the console in Chrome and notice the output as you enter different zip codes.

Playing Audio in Android/iOS Web Apps

11 Sep 2012

If you’re familiar with the state of HTML5 in Android land you know that many CSS3 features are not supported, among them is the AUDIO tag. There is a library out called SoundManager2 that claims to offer a “reliable cross-platform audio” solution but after trying it on mobile platforms I think it falls short of that promise.

SoundManager 2’s approach is to use HTML5 where possible with Flash as a fallback mechanism. Makes sense for desktop OS’s, not so much for mobile. iOS, even with its own quirks (no inline playing, no autoplay, etc) has functional HTML5 audio/video so that’s not much of an issue. Android is very different in that the HTML5 AUDIO tag is not implemented. Flash exists on Android but that has its own issues, among them: we are forced to assume that the Flash Player exists on the Android device in the first place which isn’t always the case. Add to that the fact that many users have to install the Flash Player manually on their devices as there is an absence of any auto-install capability. The final nail in that coffin is Adobe’s abandonment of the Android Flash Player altogether meaning no one can install it.

SoundManager 2 can no longer claim to be useful for mobile when its completely unusable on Android. Maybe when a version of Android with HTML5 Audio support takes the lion’s share of the Android ecosystem SoundManager 2 may again have use within the mobile space.

In any event, as mentioned, the lack of HTML5 AUDIO tag support continues to make supporting sound in Android Web Apps a challenge. The solution I’ve come up with (not that its a novel one) is to use the HTML5 VIDEO tag instead. VIDEO has support at least back to Android 2.2. Most events are supported though some don’t do quite behave in the manner that you would like for them to which makes the creation of a custom audio player somewhat of a challenge. In the end you may just have to bail on some lofty ideas/features that you may have for your own custom player but at least you can still get some sound working reliably.

It has been said that you can in fact feed the VIDEO tag an MP3. However, what happens within Android differs across its varied flavors. In Android 2.2 what will happen is that Android will not play the audio in-page but instead launch the native media player – and what you have is a black screen, devoid of controls albeit with your MP3 playing. In Android 4 you can get MP3 audio to work inline.

Due to the different behaviors and presentations between Android versions I’ve personally switched to using video files(mp4) to deliver sound. The result is that in Android 2.2 the native media player will display the video content – an image keyframed every second – which satisfies some mystery requirement that allows the on-screen controls to appear. This is much better than a black screen. On Android 4 we don’t care about the visual aspect of the video because my implementation avoids it entirely.

The concept is to use single VIDEO tag that is placed off-screen, use Javascript to change its src and control the sound via the relevant HTML5 media events.

It is important to note that some VIDEO tag attributes are necessary for this to work as without them you’ll be greeted by silence. Below is the HTML to use:

...
<video id="videoEl" autobuffer height="10" width="10" controls style="position:absolute;top:0px;left:-99px;">
  <source src="something.mp4">
</video>
...

The autobuffer is there because it can’t hurt. The one thing that is necessary is the presence of the video controls (yes, even though you won’t see them). Otherwise this is all pretty simple – you can see that the VIDEO tag is placed off screen.

I won’t post my complete setup as thats a bit of code, however, here’s a great start; first some HTML to be styled however you like:

...
<ul id="songs" class="music_list">
  <li src="vid/song_1.mp4">This is song number one</li>
  <li src="vid/song_2.mp4">This is the second song</li>
  <li src="vid/song_3.mmp4">Number three</li>
  <li src="vid/song_4.mp4">The last song</li>
  <li qwe="noSound">Just a list item, no video/sound to play here</li>
</ul>
...

In this case I’ve elected to keep the URL to the video in the LI tag. Here’s my JavaScript that utilizes the above, populates the VIDEO src, and controls the VIDEO (our sound):

...
var videoPlayer = (function(){
  var _isPlaying = false;
  var _elTarget;
  var _video;
  function _resetAllVideoStyles(){
    var lists = document.getElementsByTagName('ul');
    for (var i=0;i<lists.length;i++){
      if (lists[i].getAttribute('class').indexOf('music_list') != -1){
        var desc = lists[i].childNodes;
        for (var j=0;j<desc.length;j++){
          if (desc[j].nodeType == 1){
            desc[j].setAttribute('class','');
          }
        }
      }
    }
  }
  function _ifOldAndroid(){
    return navigator.userAgent.indexOf('Android 2.3.3') != -1 ? true : false;
  }
  function _loadVideo(t,str){
    t.setAttribute('class','mp_selected');
    _video.src = str;
    _elTarget = t;
    _video.load();
    setTimeout(function(){
      _video.play();
      _isPlaying = true;
    },1000); // NECESSARY timeout, play too soon and nothing will happen
  }
  function _stopVideo(){
    _video.pause();
    _isPlaying = false;
    _resetAllVideoStyles();
  }
  function init(v_id){;
    var el = _video = document.getElementById(v_id);
    el.addEventListener('error',function(){
      console.log('Cannot load the file');
    });
    el.addEventListener('pause', function(){
      console.log('paused/stopped');
    });
    el.addEventListener('loadstart', function(){
      console.log('starting to lo
    });
    el.addEventListener('play', function(){
      console.log('playing');
    });
    el.addEventListener('durationc
      console.log('duration changed');
    });
    el.addEventListener('progress', function(){
      console.log('progress: file is being downloaded');
    });
  }
  function dispatcher(t,str){
    if (t == _elTarget){
      _elTarget = null;
      _stopVideo();
    } else if (_isPlaying){
      _stopVideo();
      setTimeout(function(){
        _loadVideo(t,str);
      },100);
    } else {
      _loadVideo(t,str);
    }
  }
	
  return{
    init:init,
    dispatcher:dispatcher
  }
})();
window.addEventListener('load',function(){
  var list = document.getElementsByTagName('li');
  for (var i=0;i < list.length;i++){
    if (list[i].getAttribute('qwe') !== 'noSound'){
      list[i].addEventListener('click',function(e){
        videoPlayer.dispatcher(e.target,e.target.attributes[0].nodeValue);
      },false);
    }
  }
},false);
...

As you can see events are bound to all qualifying LI tags – the qualifier being that the parent UL must have a class called “music_list” assigned to it.

Thats a decent start for you – all the events are setup – you will quickly see that they don’t really fire when you expect them to. For example, the onplay event seems to start as the video is buffering, not when the video actually starts to play. ondurationchange may fire more than once – etc…. so as i mentioned before making a slick UI will be a bit of a chore. One thing that should be useful, though granted maybe not a cureall is the video.paused property. At least you will know when the video is playing or not, but as I already noted the video is considered playing when what I believe based on observation is buffering and not actual playing.

As far as iOS the video does not play inline, rather, the native video player will come up full screen. This happens because contrary to every other mobile browser Apple has decided in its totalitarian wisdom to buck the standard and suspend the mobile app in favor of its built-in media player. That’s a rather ironic tactic IMO as they profess to be on the side of HTML 5 & standardization but as usual they change the game per their whim and there’s nothing that can be done about it. Apple gives no explanation for this so it is what it is.

So that’s about – doing the above gets you something that works on both major mobile OS’s – Android with its caveats, and iOS with its mobile media player hijacking the

Scrolling in LungoJS HTML5 Framework

12 Jul 2012

I’ve been looking at other frameworks lately, among them LungoJS. After fiddling with the framework I had difficulties creating scrolling views. The docs say that getting a scrolling area is as simple as adding a “scrollable” class to a div – not quite, there are some other requirements.

To get scrolling articles you must have the following structure – notice the DIV that wraps the content:

...
<article id="something" class="scrollable">
   <div> <!-- This DIV is important!! -->
      Your content in here
   </div>
</article>
...

If you attempt to create a scrollable div inside an article tag you **must** also set a height for that div, like so:

...
<article id="something">
   <div id="myDiv" class="scrollable" style="height:300px;">
      <div> <!-- This DIV is important!! -->
         Your content in here
      </div>
   </div>
</article>
...

Notice the ID in the scrollable divs – ID is **required**, you will see as much in the console if you forget this.

Note the DIV that is the immediate child of the scrollable div – that is also required. No need to style it or add an ID. Your content must be wrapped by a DIV – P’s, Lists and header elements also work. Spans do not.

If the scrolling area is not an article tag then you **must** include the height for the scrolling div, which is illustrated in the second example above.

I noticed a lot of confusion in the forums and was confused myself – IMO the docs should be amended with the above.