jQuery: create image markers with custom data attributes

jQuery: create image markers with custom data attributes

How to create dynamic image markers with jQuery and the HTML5 custom data attributes.

If you use Facebook, Twitter or Flickr, you've probably noticed that a common feature provided by these web sites is the ability to add markers to images. These markers will be expanded to show a full description of an image's detail. Creating such markers is easy. A common problem, however, is related to the metadata storage for each marker. We can use jQuery and the new HTML5 data attributes to overcome this problem.

We'll use a well-formed JSON string which contains an array (called coords) which in turn contains several objects with the following three properties:

  1. top – The vertical offset of each marker.
  2. left – The horizontal offset of each marker.
  3. text – The caption's text of each marker.

This string will be placed within a custom data attribute:


<div id="image-wrapper" data-captions='{"coords": [{"top":180,"left":180,"text":"iMac 1"},{"top":250,"left":300,"text":"iMac 2"}]}'>
    <img src="web-agency-company.jpg" alt=""/>
</div>​

Then we need to define our CSS styles:


#image-wrapper {
    width: 400px;
    height: 400px;
    position: relative;
    margin: 2em auto;
    background: #f6f6f6;
    border: 2px solid #ddd;
}

#image-wrapper img {
    display: block;
    margin: 25px auto;
}

span.marker {
    width: 20px;
    height: 20px;
    background: #f66;
    color: #fff;
    text-align: center;
    position: absolute;
    line-height: 20px;
    cursor: pointer;
}
span.marker:before {
    content: '+';
}

span.caption {
    width: 180px;
    background: #f66;
    color: #fff;
    padding: 4px;
    position: absolute;
    top: 20px;
    left: 0;
    display: none;
}
​

With jQuery we need to use the $.parseJSON() to turn the attribute's value into an actual JavaScript object. Then we can loop through the array of objects to extract the metadata we need:


var Markers = {
    fn: {
        addMarkers: function() {
            var target = $('#image-wrapper');
            var data = target.attr('data-captions');
            var captions = $.parseJSON(data);
            var coords = captions.coords;

            for (var i = 0; i < coords.length; i++) {
                var obj = coords[i];
                var top = obj.top;
                var left = obj.left;
                var text = obj.text;

                $('<span class="marker"/>').css({
                    top: top,
                    left: left
                }).html('<span class="caption">' + text + '</span>').
                appendTo(target);

            }
        },
        showCaptions: function() {
            $('span.marker').live('click', function() {
                var $marker = $(this),
                    $caption = $('span.caption', $marker);
                if ($caption.is(':hidden')) {
                    $caption.slideDown(300);

                } else {
                    $caption.slideUp(300);

                }

            });

        }
    },

    init: function() {
        this.fn.addMarkers();
        this.fn.showCaptions();

    }
};

$(function() {
    Markers.init();

});​

[view-example url="http://jsfiddle.net/gabrieleromanato/GhVkx/"]