Hey there, this site is pretty old now. I've decided to leave it up as I put a lot of work into it and would hate to see it disappear.

Display Tags For 'cameras'

Pictures Taken With My Camera on Flickr

Neal Grosskopf
12/4/2007 12:00:00 AM
A list of pictures taken with the same camera that I have. Interesting to see what other people can do with the same camera you have. Check out your own camera on the site to see what others are doing.

Creating Facebook Styled Photo Tagging With CSS & jQuery

Neal Grosskopf
1/3/2010 5:05:00 PM
View the Facebook-esque Photo Tagging demo

Example vs. Facebook

In this article I'll show you how to create a Facebook-like photo tagging feature. If you're like me you're probably more interested in a live example than digging through this entire article so here is a live demo of the above example.

Importing the jQuery Library

As with all my examples using jQuery, I link to Google's hosted version. If a user already has the file in their browser cache, it cuts down on another HTTP request thus saving your users time.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>

HTML Setup

Below is all the HTML needed for my image tagging example. I dynamically insert much of the other needed HTML via jQuery. Originally I planned to make this a jQuery plugin. This could still easily be accomplished by taking the code within $(document).ready & adding it into a standard plugin code block.

<img src="image.jpg" style="width: 604px; height: 423px;">

CSS Setup

Unlike many of my other articles, there is a lot more code needed to achieve the desired effect. Because of this I probably won't walk you through line-by-line. Instead I'll give a brief description for some of the main elements in the DOM.

#tag-wrapper - This is wrapped around the IMG element and is given a relative position. This allows us to position other elements absolute.

#tag-target - This is a DIV which boxes in the target which a user has clicked on within the photo.

#tag-input - This is a DIV which contains a label, input box & submit/reset buttons. It is attached to the #tag-target DIV.

.hotspot - Finally after a tag has been assigned, a .hotspot DIV is created and positioned over the desired location on the image.

html, body { margin: 0px; padding: 0px; } body { color: #666; font-size: 12px; font-family: Arial, Helvetica, sans-serif; } #tag-wrapper { border: 1px solid #ccc; box-shadow: 0px 0px 10px #bbb; -webkit-box-shadow: 0px 0px 10px #bbb; -moz-box-shadow: 0px 0px 10px #bbb; display: block; padding: 10px; position: relative; } #tag-target, #tag-wrapper img { cursor: crosshair; } #tag-wrapper img { position: absolute; } #tag-target { display: none; border: 4px solid #fff; box-shadow: 0px 0px 20px #000; -webkit-box-shadow: 0px 0px 20px #000; -moz-box-shadow: 0px 0px 20px #000; height: 100px; width: 100px; position: absolute; top: 0px; left: 0px; z-index: 2; } #tag-input { background: #fff; display: none; padding: 5px; position: absolute; top: 0px; left: 0px; width: 137px; z-index: 2; } #tag-input label { display: block; font-weight: bold; } #tag-input input { border: 1px solid #ccc; color: #888; display: block; margin: 5px 0px; outline: 0px; padding: 3px; width: 124px; } .hotspot { border-width: 0px; box-shadow: 0px 0px 0px #000; -webkit-box-shadow: 0px 0px 0px #000; -moz-box-shadow: 0px 0px 0px #000; height: 100px; width: 100px; position: absolute; } .hotspot:hover, .hotspothover { border: 4px solid #fff; box-shadow: 0px 0px 20px #000; -webkit-box-shadow: 0px 0px 20px #000; -moz-box-shadow: 0px 0px 20px #000; z-index: 1; } .hotspot span { display: none; } .hotspot:hover span, .hotspothover span { background: #fff; display: block; font-weight: bold; padding: 3px 0px; text-align: center; } .remove { color: #748950; cursor: pointer; text-decoration: underline; }

Global Javascript Variables

Below are the global Javascript variables used. targetX & targetY plot coordinates for where the user clicks on the image. tagCounter is used to give each of the tags a unique ID

//Placed outside .ready for scoping var targetX, targetY; var tagCounter = 0;

$(document).ready Javascript

In the main code block I've liberally added comments to explain each line of code:

$(document).ready(function(){ //Dynamically wrap image $("img").wrap('<div id="tag-wrapper"></div>'); //Dynamically size wrapper div based on image dimensions $("#tag-wrapper").css({width: $("img").outerWidth(), height: $("img").outerHeight()}); //Append #tag-target content and #tag-input content $("#tag-wrapper").append('<div id="tag-target"></div><div id="tag-input"><label for="tag-name">Person\'s Name:</label><input type="text" id="tag-name"><button type="submit">Submit</button><button type="reset">Cancel</button></div>'); //$("#tag-wrapper").click(function(e){ $("img").click(function(e){ //Determine area within element that mouse was clicked mouseX = e.pageX - $("#tag-wrapper").offset().left; mouseY = e.pageY - $("#tag-wrapper").offset().top; //Get height and width of #tag-target targetWidth = $("#tag-target").outerWidth(); targetHeight = $("#tag-target").outerHeight(); //Determine position for #tag-target targetX = mouseX-targetWidth/2; targetY = mouseY-targetHeight/2; //Determine position for #tag-input inputX = mouseX+targetWidth/2; inputY = mouseY-targetHeight/2; //Animate if second click, else position and fade in for first click if($("#tag-target").css("display")=="block") { $("#tag-target").animate({left: targetX, top: targetY}, 500); $("#tag-input").animate({left: inputX, top: inputY}, 500); } else { $("#tag-target").css({left: targetX, top: targetY}).fadeIn(); $("#tag-input").css({left: inputX, top: inputY}).fadeIn(); } //Give input focus $("#tag-name").focus(); }); //If cancel button is clicked $('button[type="reset"]').click(function(){ closeTagInput(); }); //If enter button is clicked within #tag-input $("#tag-name").keyup(function(e) { if(e.keyCode == 13) submitTag(); }); //If submit button is clicked $('button[type="submit"]').click(function(){ submitTag(); }); }); //$(document).ready


Finally, here is a few functions I use for adding/removing tags:

function submitTag() { tagValue = $("#tag-name").val(); //Adds a new list item below image. Also adds events inline since they are dynamically created after page load $("#tag-wrapper").after('<p id="hotspot-item-' + tagCounter + '">' + tagValue + ' <span class="remove" onclick="removeTag(' + tagCounter + ')" onmouseover="showTag(' + tagCounter + ')" onmouseout="hideTag(' + tagCounter + ')">(Remove)</span></p>'); //Adds a new hotspot to image $("#tag-wrapper").append('<div id="hotspot-' + tagCounter + '" class="hotspot" style="left:' + targetX + 'px; top:' + targetY + 'px;"><span>' + tagValue + '</span></div>'); tagCounter++; closeTagInput(); } function closeTagInput() { $("#tag-target").fadeOut(); $("#tag-input").fadeOut(); $("#tag-name").val(""); } function removeTag(i) { $("#hotspot-item-"+i).fadeOut(); $("#hotspot-"+i).fadeOut(); } function showTag(i) { $("#hotspot-"+i).addClass("hotspothover"); } function hideTag(i) { $("#hotspot-"+i).removeClass("hotspothover"); }

Above & Beyond

I did add a few effects that Facebook does not have. For instance I added fading effects on pretty much everything I could. I often find that adding a fade or slide effect gives applications a more "polished look". I also added an animation if you click a new location for the target tag. Once again, here's a link to the finished product >>


<< Back