Skip to content

Instantly share code, notes, and snippets.

@chitreshkakwani
Created August 12, 2012 05:09
Show Gist options
  • Save chitreshkakwani/3329877 to your computer and use it in GitHub Desktop.
Save chitreshkakwani/3329877 to your computer and use it in GitHub Desktop.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="indexui.css" />
</head>
<body onLoad="init()">
<header class="large">
<div class="inner-wrap">
<a class="brand">
<b><h1>Ad Cloud</h1>
</b></td>
</a>
<p style="float:right">Set your preferences here. Not logged in? <a href="/login.html">Login here</a></p>
</div>
</header>
<div id="landing-container" class="prelaunch_users">
<div class="glow">
<canvas class="glow" id="canvas1" width="1550" height="800" style=" style="border: 0px solid black;">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
</div>
<script src="tags.js"></script>
</body>
/* CSS Document */
body{margin:0;}
/*body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:normal 14px;line-height:20px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;font-weight:normal 14px;line-height:20px;background-color:#f4f4f4;color:#666666;}*/
body{font-family:Georgia, "Times New Roman", Times, serif; font:Georgia; font-size:14px; font-weight:normal 14px; line-height:20px; font-family:Georgia, "Times New Roman", Times, serif; font-size:16px; font-weight:normal 14px;line-height:20px; background-color:#f4f4f4;color:#666666;}
header.large .brand{margin-top:3.375px;margin-left:0;}
header.large{background:white;display:block;position:relative;height:67.5px;border-bottom-color:rgba(0, 0, 0, 0.1);box-shadow:0 1px 30px rgba(219, 219, 219, 0.5);}
.inner-wrap{max-width:1080px;margin:0px auto 0px;}
.prelaunch_users .glow{padding-top:27px;border-color:rgba(0, 0, 0, 0.05);}
.glow{border-bottom:1px solid rgba(0, 0, 0, 0.1);background-image:-webkit-radial-gradient(50% 8%, ellipse closest-side, rgba(255, 255, 255, 0.25) 20%, rgba(219, 219, 219, 0.1) 100%),url('bgnoise.gif');}
header .existing{float:right;margin-top:13.5px;}header .existing a{font-weight:bold;}
.brand h1{
color:#333;
padding-left:18px;
padding-top:20px;
font-weight:400;
background:url('logo1.jpg') no-repeat 3px 3px;
background-size:20px;/*font:400 26px 'Bree',Helvetica,Arial,sans-serif;*/
margin:4px 10px 0 0;
letter-spacing:-1px;
position:absolute;
width: 149px;
height: 38px;
font-size: 40px;
}
.landing h1{font-family:'bree',sans-serif;font-weight:500;text-shadow:rgba(0, 0, 0, 0.1) 0px 1px 1px;width:100%;font-size:48px;text-align:center;margin:23.625px 0 0;color:#333;}
// Open Hack day 2012 !
/* AJAX methods */
var xmlhttp;
function loadXMLDoc(url, callback) {
xmlhttp = null;
if (window.XMLHttpRequest) {// code for all new browsers
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {// code for IE5 and IE6
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp != null) {
xmlhttp.onreadystatechange = callback;
xmlhttp.open("GET", url, true);
xmlhttp.send(null);
} else {
alert("Your browser does not support XMLHTTP.");
}
}
/*******************************************************************/
// Constructor for Tag objects to hold data for all drawn objects.
// For now they will just be defined as rectangles.
function Tag(x, y, fill, txt) {
// This is a very simple and unsafe constructor. All we're doing is checking if the values exist.
// "x || 0" just means "if there is a value for x, use that. Otherwise use 0."
// But we aren't checking anything else! We could put "Lalala" for the value of x
this.x = x || 0;
this.y = y || 0;
this.w = 10;
this.h = 30;
this.fill = fill || '#AAAAAA';
this.text = txt || 'default';
}
// Draws this Tag to a given context
Tag.prototype.draw = function(ctx) {
ctx.font = "30px Georgia";
ctx.fillStyle = '#000000';
ctx.fillText(this.text, this.x, this.y + this.h);
this.w = ctx.measureText(this.text).width;
console.log(this.x);
}
// Determine if a point is inside the Tag's bounds
Tag.prototype.contains = function(mx, my) {
// All we have to do is make sure the Mouse X,Y fall in the area between
// the Tag's X and (X + Height) and its Y and (Y + Height)
return (this.x <= mx) && (this.x + this.w >= mx) && (this.y <= my)
&& (this.y + this.h >= my);
}
function TagCloud(x, y, rad, col) {
this.x = x;
this.y = y;
this.radius = rad;
this.fill = col;
}
TagCloud.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
//draw a circle
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
TagCloud.prototype.contains = function(mx, my) {
// Since tag cloud is a circle, we need to check if the distance of given
// point from the center of the tag cloud is less than or equal to the radius
dx = this.x - mx;
dy = this.y - my;
return dx * dx + dy * dy <= this.radius * this.radius;
}
function CloudButton(x, y, w, h, txt, col) {
this.x = x;
this.y = y;
this.h = h;
this.w = w;
this.text = txt;
this.fill = col;
}
CloudButton.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.fillStyle = "#FFFFFF";
ctx.font = "30px Georgia";
ctx.fillText(this.text, this.x, this.y + this.h);
}
//Determine if a point is inside the Tag's bounds
CloudButton.prototype.contains = function(mx, my) {
// All we have to do is make sure the Mouse X,Y fall in the area between
// the Tag's X and (X + Height) and its Y and (Y + Height)
return (this.x <= mx) && (this.x + this.w >= mx) && (this.y <= my)
&& (this.y + this.h >= my);
}
CanvasState.prototype.fadeOut = function(e){
var alpha = 1.0; // full opacity
var canvas = this.canvas;
var context = this.ctx;
interval = setInterval(function () {
//canvas.width = canvas.width; // Clears the canvas
context.fillStyle = "rgba(255, 0, 0, " + alpha + ")";
context.font = "italic 20pt Arial";
context.fillText("added", 50, 50);
alpha = alpha - 0.05; // decrease opacity (fade out)
if (alpha < 0) {
//this.canvas.width = this.canvas.width; // Clears the canvas
clearInterval(interval);
}
}, 50);
}
function CanvasState(canvas) {
// **** First some setup! ****
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
// This complicates things a little but but fixes mouse co-ordinate problems
// when there's a border or padding. See getMouse for more detail
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(
canvas, null)['paddingLeft'], 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(
canvas, null)['paddingTop'], 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(
canvas, null)['borderLeftWidth'], 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(
canvas, null)['borderTopWidth'], 10) || 0;
}
// Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page
// They will mess up mouse coordinates and this fixes that
var html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
// **** Keep track of state! ****
this.valid = false; // when set to false, the canvas will redraw everything
this.Tags = []; // Collection of tags in main cloud
this.myTags = []; // Collection of tags in my cloud
this.cloudButtons = [];
/* Ads cloud */
this.adsCloudX = 500;
this.adsCloudY = 400;
this.adsCloudRadius = 250;
console.log("Cloud center x: " + this.adsCloudX);
console.log("Cloud radius: " + this.adsCloudRadius);
this.adsCloud = new TagCloud(this.adsCloudX, this.adsCloudY,
this.adsCloudRadius, '#99CCFF');
/* My ads cloud */
this.myCloudX = 1000;
this.myCloudY = 400;
this.myCloudRadius = 200;
this.myCloud = new TagCloud(this.myCloudX, this.myCloudY,
this.myCloudRadius, '#E9CCFC');
this.dragging = false; // Keep track of when we are dragging
// the current selected object. In the future we could turn this into an array for multiple selection
this.selection = null;
this.dragoffx = 0; // See mousedown and mousemove events for explanation
this.dragoffy = 0;
// **** Then events! ****
// This is an example of a closure!
// Right here "this" means the CanvasState. But we are making events on the Canvas itself,
// and when the events are fired on the canvas the variable "this" is going to mean the canvas!
// Since we still want to use this particular CanvasState in the events we have to save a reference to it.
// This is our reference!
var myState = this;
//fixes a problem where double clicking causes text to get selected on the canvas
canvas.addEventListener('selectstart', function(e) {
e.preventDefault();
return false;
}, false);
// Up, down, and move are for dragging
canvas.addEventListener('mousedown', function(e) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var Tags = myState.Tags;
var l = Tags.length;
for ( var i = l - 1; i >= 0; i--) {
if (Tags[i].contains(mx, my)) {
var mySel = Tags[i];
// Keep track of where in the object we clicked
// so we can move it smoothly (see mousemove)
myState.dragoffx = mx - mySel.x;
myState.dragoffy = my - mySel.y;
myState.dragging = true;
myState.selection = mySel;
myState.valid = false;
return;
}
}
// havent returned means we have failed to select anything.
// If there was an object selected, we deselect it
if (myState.selection) {
myState.selection = null;
myState.valid = false; // Need to clear the old selection border
}
}, true);
canvas.addEventListener('mousemove', function(e) {
if (myState.dragging) {
var mouse = myState.getMouse(e);
// We don't want to drag the object by its top-left corner, we want to drag it
// from where we clicked. Thats why we saved the offset and use it here
myState.selection.x = mouse.x - myState.dragoffx;
myState.selection.y = mouse.y - myState.dragoffy;
myState.valid = false; // Something's dragging so we must redraw
}
}, true);
canvas.addEventListener('mouseup', function(e) {
if (myState.dragging) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var cloud = myState.myCloud;
if (cloud.contains(mx, my))
{
console.log(myState.selection.text + " dropped in my cloud");
loadXMLDoc('http://localhost:3000/tag?=' + myState.selection.text, null);
}
} else {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var len = myState.cloudButtons.length;
for ( var i = len - 1; i >= 0; i--) {
if (myState.cloudButtons[i].contains(mx, my)) {
console.log(myState.cloudButtons[i].text + " clicked.");
loadCloudTags(myState.cloudButtons[i].text);
}
}
}
myState.dragging = false;
}, true);
// double click for making new Tags
canvas.addEventListener('dblclick', function(e) {
//var mouse = myState.getMouse(e);
//myState.addTag(new Tag(mouse.x - 10, mouse.y - 10, 20, 20,
// 'rgba(0,255,0,.6)'));
}, true);
// **** Options! ****
this.selectionColor = '#CC0000';
this.selectionWidth = 2;
this.interval = 30;
setInterval(function() {
myState.draw();
}, myState.interval);
}
CanvasState.prototype.addTag = function(tag) {
var tagX = Math.floor((Math.random() * (this.adsCloudRadius - 100)) + 1);
if (Math.floor((Math.random() * 10) + 1) > 5)
tagX = this.adsCloudX + tagX; // Subtracted constant to prevent text from getting out of the cloud
else
tagX = this.adsCloudX - tagX;
var tagY = Math.floor((Math.random() * (this.adsCloudRadius - 100)) + 1);
if (Math.floor((Math.random() * 10) + 1) > 5)
tagY = this.adsCloudY + tagY;
else
tagY = this.adsCloudY - tagY;
console.log(tagX);
this.Tags.push(new Tag(tagX, tagY, 'rgba(127, 255, 212, .5)', tag));
this.valid = false;
}
CanvasState.prototype.addMyTag = function(tag) {
var tagX = Math.floor((Math.random() * (this.myCloudRadius - 50)) + 1);
if (Math.floor((Math.random() * 10) + 1) > 5)
tagX = this.myCloudX + tagX; // Subtracted constant to prevent text from getting out of the cloud
else
tagX = this.myCloudX - tagX;
var tagY = Math.floor((Math.random() * (this.myCloudRadius - 50)) + 1);
if (Math.floor((Math.random() * 10) + 1) > 5)
tagY = this.myCloudY + tagY;
else
tagY = this.myCloudY - tagY;
console.log(tagX);
console.log(tagY);
console.log("adding my tag: " + tag);
this.myTags.push(new Tag(tagX, tagY, 'rgba(127, 255, 212, .5)', tag));
this.valid = false;
}
CanvasState.prototype.addCloud = function(cloud) {
var count = this.cloudButtons.length;
this.cloudButtons.push(new CloudButton(10, count * 60 + 100, 200, 50,
cloud, "#FF6600"));
this.valid = false;
}
CanvasState.prototype.clearMainCloud = function() {
this.Tags = [];
}
CanvasState.prototype.clearMyCloud = function() {
this.myTags = [];
}
CanvasState.prototype.clear = function() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
// While draw is called as often as the INTERVAL variable demands,
// It only ever does something if the canvas gets invalidated by our code
CanvasState.prototype.draw = function() {
// if our state is invalid, redraw and validate!
if (!this.valid) {
var ctx = this.ctx;
var Tags = this.Tags;
this.clear();
for ( var i = 0; i < this.cloudButtons.length; i++) {
var button = this.cloudButtons[i];
button.draw(ctx);
}
/* Draw the tag clouds */
this.adsCloud.draw(ctx);
this.myCloud.draw(ctx);
// ** Add stuff you want drawn in the background all the time here **
// draw my Tags
var len = this.myTags.length;
for ( var i = 0; i < len; i++) {
var Tag = this.myTags[i];
// We can skip the drawing of elements that have moved off the screen:
if (Tag.x > this.width || Tag.y > this.height || Tag.x + Tag.w < 0
|| Tag.y + Tag.h < 0)
continue;
this.myTags[i].draw(ctx);
}
// draw all Tags
var l = Tags.length;
for ( var i = 0; i < l; i++) {
var Tag = Tags[i];
// We can skip the drawing of elements that have moved off the screen:
if (Tag.x > this.width || Tag.y > this.height || Tag.x + Tag.w < 0
|| Tag.y + Tag.h < 0)
continue;
Tags[i].draw(ctx);
}
// draw selection
// right now this is just a stroke along the edge of the selected Tag
if (this.selection != null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
var mySel = this.selection;
ctx.strokeRect(mySel.x, mySel.y, mySel.w, mySel.h);
}
// ** Add stuff you want drawn on top all the time here **
this.valid = true;
}
}
// Creates an object with x and y defined, set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky, we have to worry about padding and borders
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {
x : mx,
y : my
};
}
// If you dont want to use <body onLoad='init()'>
// You could uncomment this init() reference and place the script reference inside the body tag
//init();
var cloudsObj;
var canvasState;
function displayClouds() {
if (xmlhttp.readyState == 4) {// 4 = "loaded"
if (xmlhttp.status == 200) {// 200 = OK
var json_clouds = xmlhttp.responseText;
console.log(json_clouds);
cloudsObj = JSON.parse(json_clouds);
console.log(cloudsObj);
for (var i = 0; i < cloudsObj.length; i++) {
console.log(cloudsObj[i].cloud.name);
canvasState.addCloud(cloudsObj[i].cloud.name);
}
} else {
alert("Problem retrieving data");
}
}
}
function displayTags() {
if (xmlhttp.readyState == 4) {// 4 = "loaded"
if (xmlhttp.status == 200) {// 200 = OK
var json_cloudTags = xmlhttp.responseText;
var cloudTags = JSON.parse(json_cloudTags);
for (var i = 0; i < cloudTags.length; i++) {
console.log("Tag: " + cloudTags[i].tag.name);
canvasState.addTag(cloudTags[i].tag.name);
}
} else {
alert("Problem retrieving data");
}
}
}
function displayMyTags()
{
if (xmlhttp.readyState == 4) {// 4 = "loaded"
if (xmlhttp.status == 200) {// 200 = OK
var json_cloudTags = xmlhttp.responseText;
var cloudTags = JSON.parse(json_cloudTags);
for (var i = 0; i < cloudTags.length; i++) {
console.log("Tag: " + cloudTags[i].tag.name);
canvasState.addMyTag(cloudTags[i].tag.name);
}
} else {
alert("Problem retrieving data");
}
}
}
function loadMyTags()
{
canvasState.clearMyCloud();
// Fetch cloud tags
//loadXMLDoc('http://localhost/mytags', displayMyTags);
var json_myTags = '[{"tag":{"name":"Bangalore","id":1,"updated_at":"2012-08-11T18:16:04Z","description":"","cloud_id":1,"created_at":"2012-08-11T12:54:59Z"}},{"tag":{"name":"Hyderabad","id":4,"updated_at":"2012-08-11T19:50:24Z","description":"blah","cloud_id":1,"created_at":"2012-08-11T19:50:24Z"}}]';
var myTags = JSON.parse(json_myTags);
for (var i = 0; i < myTags.length; i++) {
console.log("Tag: " + myTags[i].tag.name);
canvasState.addMyTag(myTags[i].tag.name);
}
}
function loadCloudTags(cloud) {
canvasState.clearMainCloud();
// Fetch cloud tags
// Fetch tags for a cloud
loadXMLDoc('http://localhost/' + cloud +'/tags', displayTags);
/*var json_cloudTags = '[{"tag":{"name":"Bangalore","id":1,"updated_at":"2012-08-11T18:16:04Z","description":"","cloud_id":1,"created_at":"2012-08-11T12:54:59Z"}},{"tag":{"name":"Hyderabad","id":4,"updated_at":"2012-08-11T19:50:24Z","description":"blah","cloud_id":1,"created_at":"2012-08-11T19:50:24Z"}}]';
var cloudTags = JSON.parse(json_cloudTags);
for (var i = 0; i < cloudTags.length; i++) {
console.log("Tag: " + cloudTags[i].tag.name);
canvasState.addTag(cloudTags[i].tag.name);
}*/
}
function init() {
canvasState = new CanvasState(document.getElementById('canvas1'));
loadXMLDoc('http://localhost/clouds', displayClouds);
/*
json_clouds = '[{"cloud":{"name":"Locations","id":1,"updated_at":"2012-08-11T16:46:43Z","created_at":"2012-08-11T16:46:43Z"}},{"cloud":{"name":"Categories","id":2,"updated_at":"2012-08-11T16:46:57Z","created_at":"2012-08-11T16:46:57Z"}},{"cloud":{"name":"Deals","id":3,"updated_at":"2012-08-11T16:57:17Z","created_at":"2012-08-11T16:57:17Z"}},{"cloud":{"name":"Professions","id":4,"updated_at":"2012-08-11T16:57:27Z","created_at":"2012-08-11T16:57:27Z"}},{"cloud":{"name":"Hobbies","id":5,"updated_at":"2012-08-11T16:57:34Z","created_at":"2012-08-11T16:57:34Z"}}]';
cloudsObj = JSON.parse(json_clouds);
for (var i = 0; i < cloudsObj.length; i++) {
console.log(cloudsObj[i].cloud.name);
canvasState.addCloud(cloudsObj[i].cloud.name);
}*/
loadMyTags();
}
// Now go make something amazing!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment