This awesome website uses hovers over a circle area to split the circle into four other circles and then four more and four more – each time reducing the size of the circle and the colour of the circles and making sure none of the circles meet.
"use strict"
/*
* Made with love by Vadim Ogievetsky for Annie Albagli (Valentine's Day 2011)
* Powered by Mike Bostock's D3
*
* For me on GitHub: https://github.com/vogievetsky/KoalasToTheMax
* License: MIT [ http://koalastothemax.com/LICENSE ]
*
* If you are reading this then I have an easter egg for you:
* You can use your own custom image as the source, simply type in:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?http://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Flag_of_the_United_Kingdom.svg/200px-Flag_of_the_United_Kingdom.svg.png
*
* also if you want to use a custom image and want people to guess what it is
* (without seeing the url) then you can type the url in base64 encoding like so:
* http://koalastothemax.com?
* e.g.
* http://koalastothemax.com?YXN0bGV5LmpwZw==
* (try to guess the image above)
*/
var koala = {
version: '1.8.2'
};
(function() {
function array2d(w, h) {
var a = [];
return function(x, y, v) {
if (x < 0 || y < 0) return void 0;
if (arguments.length === 3) {
// set
return a[w * x + y] = v;
} else if (arguments.length === 2) {
// get
return a[w * x + y];
} else {
throw new TypeError("Bad number of arguments");
}
}
}
// Find the color average of 4 colors in the RGB colorspace
function avgColor(x, y, z, w) {
return [
(x[0] + y[0] + z[0] + w[0]) / 4,
(x[1] + y[1] + z[1] + w[1]) / 4,
(x[2] + y[2] + z[2] + w[2]) / 4
];
}
koala.supportsCanvas = function() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
koala.supportsSVG = function() {
return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', "svg").createSVGRect;
};
function Circle(vis, xi, yi, size, color, children, layer, onSplit) {
this.vis = vis;
this.x = size * (xi + 0.5);
this.y = size * (yi + 0.5);
this.size = size;
this.color = color;
this.rgb = d3.rgb(color[0], color[1], color[2]);
this.children = children;
this.layer = layer;
this.onSplit = onSplit;
}
Circle.prototype.isSplitable = function() {
return this.node && this.children
}
Circle.prototype.split = function() {
if (!this.isSplitable()) return;
d3.select(this.node).remove();
delete this.node;
Circle.addToVis(this.vis, this.children);
this.onSplit(this);
}
Circle.prototype.checkIntersection = function(startPoint, endPoint) {
var edx = this.x - endPoint[0],
edy = this.y - endPoint[1],
sdx = this.x - startPoint[0],
sdy = this.y - startPoint[1],
r2 = this.size / 2;
r2 = r2 * r2; // Radius squared
// End point is inside the circle and start point is outside
return edx * edx + edy * edy <= r2 && sdx * sdx + sdy * sdy > r2;
}
Circle.addToVis = function(vis, circles, init) {
var circle = vis.selectAll('.nope').data(circles)
.enter().append('circle');
if (init) {
// Setup the initial state of the initial circle
circle = circle
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; })
.attr('r', 4)
.attr('fill', '#ffffff')
.transition()
.duration(1000);
} else {
// Setup the initial state of the opened circles
circle = circle
.attr('cx', function(d) { return d.parent.x; })
.attr('cy', function(d) { return d.parent.y; })
.attr('r', function(d) { return d.parent.size / 2; })
.attr('fill', function(d) { return String(d.parent.rgb); })
.attr('fill-opacity', 0.68)
.transition()
.duration(300);
}
// Transition the to the respective final state
circle
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; })
.attr('r', function(d) { return d.size / 2; })
.attr('fill', function(d) { return String(d.rgb); })
.attr('fill-opacity', 1)
.each('end', function(d) { d.node = this; });
}
// Main code
var vis,
maxSize = 512,
minSize = 4,
dim = maxSize / minSize;
koala.loadImage = function(imageData) {
// Create a canvas for image data resizing and extraction
var canvas = document.createElement('canvas').getContext('2d');
// Draw the image into the corner, resizing it to dim x dim
canvas.drawImage(imageData, 0, 0, dim, dim);
// Extract the pixel data from the same area of canvas
// Note: This call will throw a security exception if imageData
// was loaded from a different domain than the script.
return canvas.getImageData(0, 0, dim, dim).data;
};
koala.makeCircles = function(selector, colorData, onEvent) {
onEvent = onEvent || function() {};
var splitableByLayer = [],
splitableTotal = 0,
nextPercent = 0;
function onSplit(circle) {
// manage events
var layer = circle.layer;
splitableByLayer[layer]--;
if (splitableByLayer[layer] === 0) {
onEvent('LayerClear', layer);
}
var percent = 1 - d3.sum(splitableByLayer) / splitableTotal;
if (percent >= nextPercent) {
onEvent('PercentClear', Math.round(nextPercent * 100));
nextPercent += 0.05;
}
}
// Make sure that the SVG exists and is empty
if (!vis) {
// Create the SVG ellement
vis = d3.select(selector)
.append("svg")
.attr("width", maxSize)
.attr("height", maxSize);
} else {
vis.selectAll('circle')
.remove();
}
// Got the data now build the tree
var finestLayer = array2d(dim, dim);
var size = minSize;
// Start off by populating the base (leaf) layer
var xi, yi, t = 0, color;
for (yi = 0; yi < dim; yi++) {
for (xi = 0; xi < dim; xi++) {
color = [colorData[t], colorData[t+1], colorData[t+2]];
finestLayer(xi, yi, new Circle(vis, xi, yi, size, color));
t += 4;
}
}
// Build up successive nodes by grouping
var layer, prevLayer = finestLayer;
var c1, c2, c3, c4, currentLayer = 0;
while (size < maxSize) {
dim /= 2;
size = size * 2;
layer = array2d(dim, dim);
for (yi = 0; yi < dim; yi++) {
for (xi = 0; xi < dim; xi++) {
c1 = prevLayer(2 * xi , 2 * yi );
c2 = prevLayer(2 * xi + 1, 2 * yi );
c3 = prevLayer(2 * xi , 2 * yi + 1);
c4 = prevLayer(2 * xi + 1, 2 * yi + 1);
color = avgColor(c1.color, c2.color, c3.color, c4.color);
c1.parent = c2.parent = c3.parent = c4.parent = layer(xi, yi,
new Circle(vis, xi, yi, size, color, [c1, c2, c3, c4], currentLayer, onSplit)
);
}
}
splitableByLayer.push(dim * dim);
splitableTotal += dim * dim;
currentLayer++;
prevLayer = layer;
}
// Create the initial circle
Circle.addToVis(vis, [layer(0, 0)], true);
// Interaction helper functions
function splitableCircleAt(pos) {
var xi = Math.floor(pos[0] / minSize),
yi = Math.floor(pos[1] / minSize),
circle = finestLayer(xi, yi);
if (!circle) return null;
while (circle && !circle.isSplitable()) circle = circle.parent;
return circle || null;
}
function intervalLength(startPoint, endPoint) {
var dx = endPoint[0] - startPoint[0],
dy = endPoint[1] - startPoint[1];
return Math.sqrt(dx * dx + dy * dy);
}
function breakInterval(startPoint, endPoint, maxLength) {
var breaks = [],
length = intervalLength(startPoint, endPoint),
numSplits = Math.max(Math.ceil(length / maxLength), 1),
dx = (endPoint[0] - startPoint[0]) / numSplits,
dy = (endPoint[1] - startPoint[1]) / numSplits,
startX = startPoint[0],
startY = startPoint[1];
for (var i = 0; i <= numSplits; i++) {
breaks.push([startX + dx * i, startY + dy * i]);
}
return breaks;
}
function findAndSplit(startPoint, endPoint) {
var breaks = breakInterval(startPoint, endPoint, 4);
var circleToSplit = []
for (var i = 0; i < breaks.length - 1; i++) {
var sp = breaks[i],
ep = breaks[i+1];
var circle = splitableCircleAt(ep);
if (circle && circle.isSplitable() && circle.checkIntersection(sp, ep)) {
circle.split();
}
}
}
// Handle mouse events
var prevMousePosition = null;
function onMouseMove() {
var mousePosition = d3.mouse(vis.node());
// Do nothing if the mouse point is not valid
if (isNaN(mousePosition[0])) {
prevMousePosition = null;
return;
}
if (prevMousePosition) {
findAndSplit(prevMousePosition, mousePosition);
}
prevMousePosition = mousePosition;
d3.event.preventDefault();
}
// Handle touch events
var prevTouchPositions = {};
function onTouchMove() {
var touchPositions = d3.touches(vis.node());
for (var touchIndex = 0; touchIndex < touchPositions.length; touchIndex++) {
var touchPosition = touchPositions[touchIndex];
var prevTouchPosition = prevTouchPositions[touchPosition.identifier]
if (prevTouchPosition) {
findAndSplit(prevTouchPosition, touchPosition);
}
prevTouchPositions[touchPosition.identifier] = touchPosition;
}
d3.event.preventDefault();
}
function onTouchEnd() {
var touches = d3.event.changedTouches;
for (var touchIndex = 0; touchIndex < touches.length; touchIndex++) {
var touch = touches.item(touchIndex);
prevTouchPositions[touch.identifier] = null;
}
d3.event.preventDefault();
}
// Initialize interaction
d3.select(document.body)
.on('mousemove.koala', onMouseMove)
.on('touchmove.koala', onTouchMove)
.on('touchend.koala', onTouchEnd)
.on('touchcancel.koala', onTouchEnd);
};
})();
With Bonfire Night approaching in the UK, Col Morley and Igor Krestov of Blue Claw decided to put their CSS skills to work creating this fire safety infographic aimed at school-age children.
When viewed in a suitable browser, some elements of the infographic will animate. Rather than aiming at supersmooth, in-your-face visual effects, the flickering of the flames and the sparkling of the sparklers is simple, subtle – and, we think, all the more effective for it.
Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.
Inspired by Firefox’s homepage Olympic flame over the summer of 2012, the infographic was created using layered graphics and CSS3 to aid in the process of transition of scale, movement and speed, explains Morley. “The bonfire is made up of several layered ‘fire’ shapes then playing around with key frames enabled stretching, opacity and by adding a warm glow renders a realistic flame effect.
“The spark that appears throughout the page was created using a similar technique. Three images were used to pulsate at different rates of scale, similar effect to how we animated the ‘fearful cat’. The movement of the eyes on the hot dog was produced by mouse tracking code adding further interest to those who spotted that.
“The styling of the traditional blackboard theme gives the piece the right level and tone for the audience and enabled us to experiment with textures and fonts.”
If you’re a user of our design applications such as Photoshop and Illustrator, you know how you can create very cool effects with blend modes. An Amazon search returns many books and a Google search on ‘photoshop blending tutorial’ returns more than 200,000 results. This points to a very widely known and used feature.
To be able to blend to images together like Photoshop does, we will need to use the HTML5 canvas feature. The images are loaded dynamically using Javascript.
The easy way to blend two images together can be summarized into
// Might be an 'offscreen' canvas
var over = someCanvas.getContext('2d');
var under = anotherCanvas.getContext('2d');
over.blendOnto( under, 'screen', {destX:30,destY:15} );
[Question] I have two form pages and a next button to move from page 1 to page 2. When the next button is clicked, I wanted to validate all the required fields before moving to the second page. How do you make the page transition stop, when validation fail on page 1?
I ran into a problem when trying to validate a few radio button groups on a page before the page transition happened in JQuery Mobile.
I did not want the page to change before I managed to check if the user had managed to select an option from the screen.
I am using JQuery Mobile Events to trap the page change and cancel it if there is something wrong with the page I am trying to move from.
Because there were more than one radio button group on the page, I got the names of all the groups and then looped through them. If I found one unchecked, I would stop the transition with e.preventDefault().
I hope this helps someone.
<script type="text/javascript">
$(document).bind('pagebeforechange', function (e, data) {
var to = data.toPage,
from = data.options.fromPage;
if (typeof to ==='string') {
var u = $.mobile.path.parseUrl(to);
to = u.hash ||'#'+ u.pathname.substring(1);
if (from) from ='#'+ from.attr('id');
var blnchecked;
blnchecked =true;
//find all radio groups on a pagevar radio_groups = {}
$(from +" input[type=radio]").each(function () {
radio_groups[this.name] =true;
})
for (group in radio_groups) {
if_checked =!!$(from +" input[name="+ group +"]:checked").length;
// alert(group + (if_checked ? ' has checked radios' : ' does not have checked radios'));if (!if_checked) {
blnchecked =false;
}
}
if (blnchecked==false) {
alert('Please select an option!');
e.preventDefault();
// remove active class on button// otherwise button would remain highlighted
$.mobile.activePage
.find('.ui-btn-active')
.removeClass('ui-btn-active');
}
}
});
</script>
Internet Explorer does not have access to window.location.origin, which is a bummer because it is a pretty handy variable to have, but we can make it work with a fairly straight forward check because we access .origin;
Wherever you go, there you are. And sometimes knowing where you are makes all the difference (especially to a web app). In this chapter we’re going to show you how to create web pages that are location aware—sometimes you’ll be able to pinpoint your users down to the corner they’re standing on, and sometimes you’ll only be able to determine the area of town they’re in (but you’ll still know the town!). Heck, sometimes you won’t be able to determine anything about their location, which could be for technical reasons, or just because they don’t want you being so nosy. Go figure.
In any case, in this chapter we’re going to explore a JavaScript API: Geolocation. Grab the best location-aware device you have (even if it’s your desktop PC), and let’s get started.
Knowing where your users are can add a lot to a web experience: you can give them directions, make suggestions about where they might go, you can know it’s raining and suggest indoor activities, you can let your users know who else in their area might be interested in some activity. There’s really no end to the ways you can use location information.
With HTML5 (and the Geolocation JavaScript-based API) you can easily access location information in your pages. That’s said, there are a few things to know about location before we get started. Let’s check it out…
Q: I heard Geolocation isn’t a real API?
A: Geolocation is not considered a first-class member of the existing HTML5 standard, but that said, it is a standard of the W3C, widely supported and pretty much everyone includes Geolocation in the list of important HTML5 APIs. And it most certainly is a real JavaScript API!
Q: Is the Geolocation API the same as the Google Maps API?
A: No. They are completely different APIs. The Geolocation API is solely focused on getting you information about your position on
the Earth. The Google Maps API is a JavaScript library offered by Google that gives you access to all their Google Maps functionality.
So, if you need to display your users location in a map, Google’s API gives you a convenient way to implement that functionality.
Q: Isn’t it a privacy concern to have my device reveal my location?
A: The Geolocation specification specifies that any browser must have the express permission of the user to make use of their location. So, if your code makes use of the Geolocation API, the first thing the browser will do is make sure it is okay with the user to share her location.
Q: How well supported is Geolocation?
A: Very well supported; in fact, it’s available in almost every modern browser including desktop and mobile. You’ll want to be sure you’re using the latest version of your browser; if you are, then you’re probably good to go.
The Lat and Long of it… To know where you are, you need a coordinate system, and you need one on the Earth’s surface. Luckily we have such a thing, and it uses latitude and longitude together as a coordinate system. Latitude specifies a north/sourth point on the Earth, and longitude, an east/west point. Latitude is measured from the equator, and longitude is measured from Greenwich, England. The job of the geolocation API is to give us the coordinates of where we are at any time, using these coordinates.
You’ve probably seen latitude and longitude specfied in both degrees / minutes / seconds, such as (47˚38’34’’, 122˚32’32’’), and in decimal values, such as (47.64, -122.54). With the Geolocation API we always use decimal values. If you need to convert degrees/ minutes/seconds to decimal, you can use this function:
You don’t have to have the newest smartphone to be location aware. Even desktop browsers are joining the game. You might ask, how would a desktop browser determine its location if it doesn’t have GPS or any other fancy location technologies?
Well, all browsers (in devices and on your desktop) are using a few different ways to determine where you are, some more accurate than others. Let’s take a look:
GPS
Global Positioning System, supported by many newer mobile devices, provides extremely accurate location information based on satellites. Location data may include altitude, speed and heading information. To use it, though, your device has to be able to see the sky, and it can take a long time to get a location. GPS can also be hard on your batteries.
IP Address
Location information based on your IP address uses an external database to map the IP address to a physical location. The advantage of this approach is that it can work anywhere; however, often IP addresses are resolved to locations such as your ISP’s local office. Think of this method as being reliable to the city or sometimes neighborhood level.
Cell Phone
Cell phone triangulation figures out your location based on your distance from one or more cell phone towers (obviously the more towers, the more accurate your location will be). This method can be fairly accurate and works indoors (unlike GPS); it also can be much quicker than GPS. Then again, if you’re in the middle of nowhere with only one cell tower, your accuracy is going to suffer.
WiFi
WiFi positioning uses one or more WiFi access points to triangulate your location. This method can be very accurate, works indoors and is fast. Obviously it requires you are somewhat stationary (perhaps drinking a venti iced tea at a coffee house).
The browser implementation is going to determine how location is determined. But the good news is the browser can use any of these means to determine your location. In fact, a smart browser might first use cell phone triangulation, if it is available, to give you a rough idea of location, and then later give you a more accurate location with WiFi or GPS.
We’ll see that you don’t need to worry about how the location is being determined, and we’ll focus more on the accuracy of your location instead. Based on the accuracy, you can determine how useful the location is going to be for you.
The code:
window.onload = getMyLocation;
function getMyLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayLocation);
} else {
alert(“Oops, no geolocation support”);
}
}
function displayLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var div = document.getElementById(“location”);
div.innerHTML = “You are at Latitude: ” + latitude + “, Longitude: ” + longitude;
}
What we just did…
Let’s walk through the code in a little more detail:
if (navigator.geolocation) {
…
} else {
alert(“Oops, no geolocation support”);
}
The first thing you need to know if you’re going to write geolocation code is “does this browser support it?” To do that we make use of the fact that browsers have a geolocation property in their navigation object only if geolocation is supported. So we can test to see if the geolocation property exists, and if so make use of it; otherwise, we’ll let the user know.
If your browser supports the Geolocation API, you’ll find a geolocation property in the navigator object.
We can use a simple test to see if geolocation is there (if it’s not then navigator.geolocation evaluates to null and the condition will fail).
Now, if there is a navigator.geolocation property, we’re going to make some more use of it. In fact, the navigator.geolocation property is an object that contains the entire geolocation API. The main method the API supports is getCurrentPosition, which does the work of getting the browser’s location. Let’s take a closer look at this method, which has three parameters, the second two of which are optional:
The successHandler is a function that is called if the browser is able to successfully determine your location.
These two parameters are optional, which is why we didn’t need them before.
The errorHandler is another function, that is called if something goes wrong and the browser can’t determine your location.
The options parameter allows you to customize the way geolocation works.
Remember, APIs are just objects with properties and methods!