Your Mouse Is A Magician

Not really, but the simple act of something on the screen following my mouse cursor still fascinates me, but so do many little things in life.

In addition to adding this interactive map, I decided to make the text follow the mouse. And I decided to tell you about it in case you wanted to do it yourself.

interactivemap
First, download JqueryUI and place it in your usual js location. This library gives you all kinds of nice stuff, like moving a <div> around a page that follows your mouse.

Next, reference it in your page, something like this:

<script src="/js/vendor/jquery-ui.min.js"></script>

Here’s my <div> by the way, this is what I’ll be using.

<div id="forworldmapcomment" style="position:absolute;"></div>

In your $(document).ready(function() {}); function add this:

$("#forworldmap").mousemove(function(e){
  $("#forworldmapcomment").position({
	my: "bottom-20",
	of: e,
	collision: "fit"
  });
});

That’s all there is to it, your <div> with id forworldmapcomment will follow the mouse around the screen.

I’ve positioned it 20 pixels above the event (mouse)’s position to avoid most conflicts.

Advertisements

Cool Interactive Map

I added a new interactive map out on NBNW and I think it’s pretty cool. That’s one person!

If you check it out and like it, you can use it too (I’ll give you everything below). Everything is free including the source where I got started (RaphaelJS check it out, very powerful).

Hover your mouse over a country and if available, the average net worth results will appear for all users in that country.

Hover your mouse over a country and if available, the average net worth results will appear for all users in that country.

To play with the map, the only real requirement is that you have a fairly modern browser.  I use HTML5 features that might not work properly in older browsers. Oh, sorry, one more thing, it’s a pretty large map, like 1000 pixels wide, so you might do some scrolling on a small screen.

For you techies, here’s the guts you’ll need (feel free to right-click and View source on my site and take any of that you need). In short, I load my custom database data (just a country name with an average net worth) into a two dimensional Javascript array by parsing the results of an Ajax call. Then when I hover over a country on the map, I pass the country name into my custom array looking for the average net worth.

First, download this from github:

https://raw.github.com/DmitryBaranovskiy/raphael/master/raphael-min.js

Then, download this from Raphael:

http://raphaeljs.com/world/world.js

Ok, so now it’s going to look like I threw up on the page and I sort of did. However, keep following past this main block and the rest will make sense. After that, back into this main block and it too will make sense.

<script src="/js/vendor/raphael-min.js"></script>
<script src="/js/vendor/world.js"></script>
<script>
Raphael("forworldmap", 1000, 400, function () {
var r = this;
r.rect(0, 0, 1000, 400, 10).attr({
    stroke: "none",
    fill: "0-#9bb7cb-#adc8da"
});
var over = function () {
    this.c = this.c || this.attr("fill");
    this.stop().animate({fill: "#bacabd"}, 500);
},
    out = function () {
	this.stop().animate({fill: this.c}, 500);
    };
r.setStart();
var hue = Math.random();
var myCountryArray = new Array();
for (var country in worldmap.shapes) {
    // var c = Raphael.hsb(Math.random(), .5, .75);
    // var c = Raphael.hsb(.11, .5, Math.random() * .25 - .25 + .75);
     var myRPath = r.path(worldmap.shapes[country]).attr({stroke: "#ccc6ae", fill: "#f0efeb", "stroke-opacity": 0.25});
     myCountryArray[myRPath.id] = worldmap.names[country];
     myRPath.hover(function() {
	showNetWorthTooltip(myCountryArray[this.id]);
     });
}
var world = r.setFinish();
world.hover(over, out);
// world.animate({fill: "#666", stroke: "#666"}, 2000);
world.getXY = function (lat, lon) {
    return {
	cx: lon * 2.6938 + 465.4,
	cy: lat * -2.6938 + 227.066
    };
};
world.getLatLon = function (x, y) {
    return {
	lat: (y - 227.066) / -2.6938,
	lon: (x - 465.4) / 2.6938
    };
};
var latlonrg = /(\d+(?:\.\d+)?)[\xb0\s]?\s*(?:(\d+(?:\.\d+)?)['\u2019\u2032\s])?\s*(?:(\d+(?:\.\d+)?)["\u201d\u2033\s])?\s*([SNEW])?/i;
world.parseLatLon = function (latlon) {
    var m = String(latlon).split(latlonrg),
	lat = m && +m[1] + (m[2] || 0) / 60 + (m[3] || 0) / 3600;
    if (m[4].toUpperCase() == "S") {
	lat = -lat;
    }
    var lon = m && +m[6] + (m[7] || 0) / 60 + (m[8] || 0) / 3600;
    if (m[9].toUpperCase() == "W") {
	lon = -lon;
    }
    return this.getXY(lat, lon);
};

try {
    navigator.geolocation && navigator.geolocation.getCurrentPosition(function (pos) {
	r.circle().attr({fill: "none", stroke: "#f00", r: 5}).attr(world.getXY(pos.coords.latitude, pos.coords.longitude));
    });
} catch (e) {}
var frm = document.getElementById("latlon-form"),
    dot = r.circle().attr({fill: "r#FE7727:50-#F57124:100", stroke: "#fff", "stroke-width": 2, r: 0}),
    // dot2 = r.circle().attr({stroke: "#000", r: 0}),
    ll = document.getElementById("latlon"),
    cities = document.getElementById("cities");
});
</script>

In that code above, it’s all right off Raphael. I only changed a few lines to create a new array for myself and call my own Javascript function on a mouse hover event.

var myRPath = r.path(worldmap.shapes[country]).attr({stroke: "#ccc6ae", fill: "#f0efeb", "stroke-opacity": 0.25});
myCountryArray[myRPath.id] = worldmap.names[country];
myRPath.hover(function() {
    showNetWorthTooltip(myCountryArray[this.id]);
});

And of course, here’s my custom code

//this var will hold all country data from initial ajax call
var mycountryarray = new Array();

$(document).ready(function(){
doLoadCountriesData();
});
function doLoadCountriesData()
{
	var sessionKey = "countriesInSession";
	//if browser supports session storage, try to use it
	if (sessionStorage) {
		var sessionValue = sessionStorage.getItem(sessionKey);
		if (sessionValue) {
			mycountryarray = $.parseJSON(sessionValue);
			return true; // We just avoided one ajax request
		}
	}
	//browser doesn't support session storage or the session var is empty, go get posts
	$.ajax({
		url: 'GetCountryAvgNetWorth.php',
		type: 'GET',
		cache: 'false',
		success: function(jsonresponse) {
			//if sessionStorage supported, save response in session
			if (sessionStorage) {
				mycountryarray = $.parseJSON(jsonresponse);
				sessionStorage.setItem(sessionKey, jsonresponse);
			}
		},
		error: function(xhr) {
			// handle errors
		},
	});
	return true;
}
function showNetWorthTooltip(country) {
	if (!(mycountryarray)) {
		doLoadCountriesData();
	}
	if (mycountryarray[country]) {
		$("#forworldmapcomment").html("Average net worth for " + country + " is $" + ReplaceNumberWithCommas(mycountryarray[country]));
	} else {
		$("#forworldmapcomment").html("Average net worth for " + country + " is unavailable");
	}
}
function ReplaceNumberWithCommas(yourNumber) {
	//Seperates the components of the number
	var n= yourNumber.toString().split(".");
	//Comma-fies the first part
	n[0] = n[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
	//Combines the two sections
	return n.join(".");
}

HTML5 Facelift

This past weekend, I thought I developed a new allergy.  It’s not pollen, I already have that allergy.  I thought had I developed an allergy to Internet Explorer.

Here’s what I did to SitterSat.com over the weekend.  I overhauled it in an effort to make it HTML5 compliant.  I want to do a bunch of cool graphic stuff like add a million stars to the page.  Well, no not really, although that is really cool.  Great use of Three.js.  No, instead I bootstrapped it.  Github to the rescue!

The reason I thought I had a new allergy to IE is because when something didn’t work in IE I used to be able to find all kinds of work-arounds to get everything to work fine in that browser.  Things that worked well in Chrome without workarounds.  But it called for all this nasty little code I had to maintain.  This time however, I just grew tired of it.  I’d rather not have all that nasty little code.  So for now I put a disclaimer at the footer of the page for IE users saying something like “This site works fine in IE, but looks better in Firefox and best in Chrome or Safari.”  Fortunately, for us, only 7% of our user base visits us with IE.  Oh yes and I figure very little to none of that 7% is using IE 10 with Windows 8 which actually seems to work fine from my own testing.

So here’s where I think we’ll end up!  Everything should work just fine in these cases:

Safari (41% of user base) – will work just fine

Chrome (46% of user base) – will work just fine

Firefox (4% of user base) – will work just fine in >v17

Opera (0% of user base) – will work just fine in >v12

IE (7% of user base) – will work just fine in >v10

A couple of pain points

Placeholder text

This is a small thing, but placeholder text doesn’t seem to work in IE (< v10).  That’s the nice little text you get inside a textbox to aid you in remembering what the input in that box is supposed to be provided.  The placeholder text eliminates unnecessary labels elsewhere and frees up valuable real estate, plus it just looks nice and cool.

CSS3

Gradients, transitions and animations aren’t doing so well in IE  (< v10).  We’ll just have to look at a non-moving red box.  To accomodate, I’ve added in some text above the box, “Fetching…” which in hindsight is valuable anyhow.  You wouldn’t know what that progress bar is for if I didn’t say so I’m glad that’s in there.

For an example of what I’m talking about, go to SitterSat.com and look at the page while the latest 2 blog posts load on the right hand side.  If you look very quickly (because it may load really fast), you should see something like this bar below (but animating, like an old barber’s pole).  That is, unless you’re using an older version of IE (< v10):

loadingblogstriper

I put this progress bar in to let you know some fetching was taking place.  I changed the way I’m loading those latest 2 blog posts.  Previously, I was loading the posts synchronously which was a real drag, literally, the page wouldn’t fully load until that processing was complete.  Yuck.  Now, I’m asynchronously loading from another domain (sittersatblog.com) using a jquery ajax call.  Partial Yippee.  In Chrome, looks great, very nice, in IE (< v10), not so good, just a red bar.  I will look into caching it, there’s no need to go get that so often.  That’ll be Full Yippee.  Why we have a separate domain for the blog is another discussion entirely.

Now onto the good stuff

So now that’s out of the way.  Let’s move onto what I love about this effort.  It’s certainly not banging away at a keyboard all weekend.  I should mention that all weekend is a bit of an exaggeration, I started Saturday morning and finished up Sunday evening around 9p.m..  And that incorporates the fact that I tinker and tinker and tinker and tinker with the smaller details until I’m happy with it.  That slows me down quite a bit.  During that time, we got a Christmas tree, put up decorations, played with the kids and intervened on a few seemingly pointless kid arguments.  My point is that this mini project was secondary and can be done here and there without too much fuss.  Of course, as I type this I can’t help but reflect on that fact that I have an ever patient wife.

What I love about the bootstrapping process was the clean transition to HTML5 compliancy.  Plus, I got some insight into the geniuses that created all this stuff.  How generous for them to have created it all for public consumption!

Here’s the path I took to get there:

1. Go out and git yourself a good zipball of fun, from github or another source.  I actually ended up using a custom download from Initializr that includes Modernizr.  Inside it will look something like this, as you’ll notice very straightforward:

Bootstrap zipball

– css

– img (glyphicons halflings – they’ve worked out a special arrangement with github so you get these for free)

– js

2. Update your files to HTML5 compliancy (<!DOCTYPE html> and stuff like that).  You can do all this manually, but you can also start with some of Bootstrap’s barebones HTML5 compliant templates and just plug in the dynamic stuff.  I didn’t use a template, but I did take some elements out of the templates, some for use, some for study, like the hero template, navbar (loved the collapsing menu), narrow marketing container and nice large carousel jumbotron.

That’s it.  Oh yes, I love the doctype declaration by the way.  The pre-HTML5 way has always annoyed me.  You’ll probably like the other small changes like meta, stylesheet and javascript declaration changes for the same reason.

Oprah’s Scott’s favorite thing

Best of all, my most favorite thing?  Without question, the responsive 12 grid layout available with bootstrap.  I love it.  It’s not for everyone, but nothing is.  For me, it provides flexibility with ease of use and most of all speed.  I can quit messing around with the basic layout so much, everything is right there in div and CSS, everything I need to move fast.  And it works great for tablets and smartphones.

Previously, I had a couple of inserts of some nasty code, something where I look at the user’s useragent to determine if they are using something other than a desktop browser.  If they were, I changed the look and feel.  While it worked, I never really liked the way it look on smartphones and tablets.  Not only was the formatting slightly askew, I had removed some things from the view.  All this time I had previously spent on making it look good while botching up the code.  It wasn’t that bad, I make it sound worse that it was, but still I just didn’t like it that much.  I wanted something responsive, something where the stylesheets would more appropriately determine where things land and how they look on the page for various screen sizes.  And I wanted my code to be cleaner!  That’s as it should be after all.  It is more so now than ever and I’m happy.

So now that the basic HTML5 implementation is in place, I can focus on replacing some more of my other homegrown code with standard goodies from bootstrap and jquery.  All while trying to implement new and relevant HTML5 specific features.  I just need to think about what those features would be!