Skip to content

Instantly share code, notes, and snippets.

@gtb104
Last active October 6, 2015 14:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gtb104/3008002 to your computer and use it in GitHub Desktop.
Save gtb104/3008002 to your computer and use it in GitHub Desktop.

d3 Without SVG

This is an example of how to use the d3 framework without Scalable Vector Graphics. The bubbles are CSS styled div elements.

Try it on bl.ocks.org

It is also an example of how to write your JavaScript using CoffeeScript. The following CoffeeScript was compiled into JavaScript, and results in the graphic above.

colors = new d3.scale.category10()

class SimpleBubble
	constructor: (@data, @id, @canvas) ->
		@el = null
		@x = 0
		@y = 0
		@radius = 0
		@boxSize = 0
		@isDragging = false
		@isSelected = false
		@tooltip = null
	
		@init()

	init: ->
		# Elements that make up the bubbles display
		@el = $("<div class='bubble' id='bubble-" + @id + "'></div>")
		@elFill = $("<div class='bubbleFill'></div>")
		@el.append(@elFill)
	
		# Attach mouse interaction to root element
		# Note use of $.proxy to maintain context
		@el.on('mouseover', @showToolTip)
	
		@el.on('mouseout', @hideToolTip)
	
		# Set CSS of Elements
		@radius = @data
		@boxSize = @data * 2
	
		@elFill.css(
			width: @boxSize
			height: @boxSize
			left: -@boxSize / 2
			top: -@boxSize / 2
			"background-color": colors(@data))

	showToolTip: =>
		@tooltip = $("<div class='tooltip'></div>")
		@tooltip.html("<div class='tooltipFill'><p>" + @data + "</p></div>")
		@tooltip.css(
			left: @x + @radius*0.5,
			top: @y + @radius*0.5)
		@canvas.append(@tooltip)

	hideToolTip: =>
		$(".tooltip").remove()	

	move: ->
		@el.css(
			top: this.y,
			left:this.x )

class SimpleVis
	constructor: (canvas, @data) ->
		@width = 800
		@height = 400
		@canvas = $(canvas)
		@force = null
		@bubbles = []
		@centers = [
			{x: 200, y:200}
			{x: 400, y:200}
			{x: 600, y:200}
		]
		@bin = d3.scale.ordinal().range([0,1,2])
	
		@init()

	bubbleCharge: (d) ->
		-Math.pow(d.radius,1) * 8

	makeBubbles: (data, i, canvas) ->
		b = new SimpleBubble(data, i, canvas)
		b.x = b.boxSize + (20 * (i+1))
		b.y = b.boxSize + (10 * (i+1))
		# Store bubble reference
		@bubbles.push b
		@canvas.append b.el

	setBubbleLocation: (bubble, alpha) ->
		center = @centers[this.bin(bubble.id)]
		bubble.y = bubble.y + (center.y - bubble.y) * (0.115) * alpha
		bubble.x = bubble.x + (center.x - bubble.x) * (0.115) * alpha
		[bubble.x,bubble.y]

	updateBubbleLocation: (bubble, alpha) ->
		@setBubbleLocation(bubble, alpha)
		bubble.move()
	
	tickHandler: (event) =>
		@updateBubbleLocation(bubble, event.alpha) for bubble in @bubbles

	init: ->
		# Initialize root visualization element
		@canvas.css(
			width: @width
			height: @height
			"background-color": "#eee"
			position: "relative")
	
		# Create Bubbles
		@makeBubbles(d, i, @canvas) for d, i in @data
	
		# Setup force layout
		@force = d3.layout.force()
			.nodes(@bubbles)
			.gravity(0)
			.charge(@bubbleCharge)
			.friction(0.87)
			.size([@width, @height])
			.on('tick', @tickHandler)
	
		@force.start()

# Create the visualization
$(document).ready () ->
	vis = new SimpleVis("#canvas", [12,33,20,40,60,10,25,44,13,23,14,25,8])

	$("#move").on "click", (e) ->
		vis.bin.range(vis.bin.range().reverse())
		vis.force.resume()
		false

The original code was taken from http://vallandingham.me/d3_without_svg.html

<!DOCTYPE html>
<head>
<title>d3 w/o SVG</title>
<style type="text/css">
.bubble {
display: block;
position: absolute;
}
.bubbleFill {
position: absolute;
display: block;
border: solid 1px white;
-webkit-border-radius: 70px;
-moz-border-radius: 70px;
border-radius: 70px;
}
.tooltip {
position: absolute;
display: block;
}
.tooltipFill {
position: absolute;
display: block;
}
.tooltipFill p {
position: absolute;
display: block;
text-align: center;
background-color: #FEF1B5;
padding: 3px 10px 3px 10px;
}
</style>
</head>
<body>
<div id="canvas"></div>
<a href="#" id="move">Move</a>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
<script type="text/javascript">
(function() {
var SimpleBubble, SimpleVis, colors,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
colors = new d3.scale.category10();
SimpleBubble = (function() {
SimpleBubble.name = 'SimpleBubble';
function SimpleBubble(data, id, canvas) {
this.data = data;
this.id = id;
this.canvas = canvas;
this.hideToolTip = __bind(this.hideToolTip, this);
this.showToolTip = __bind(this.showToolTip, this);
this.el = null;
this.x = 0;
this.y = 0;
this.radius = 0;
this.boxSize = 0;
this.isDragging = false;
this.isSelected = false;
this.tooltip = null;
this.init();
}
SimpleBubble.prototype.init = function() {
this.el = $("<div class='bubble' id='bubble-" + this.id + "'></div>");
this.elFill = $("<div class='bubbleFill'></div>");
this.el.append(this.elFill);
this.el.on('mouseover', this.showToolTip);
this.el.on('mouseout', this.hideToolTip);
this.radius = this.data;
this.boxSize = this.data * 2;
return this.elFill.css({
width: this.boxSize,
height: this.boxSize,
left: -this.boxSize / 2,
top: -this.boxSize / 2,
"background-color": colors(this.data)
});
};
SimpleBubble.prototype.showToolTip = function() {
this.tooltip = $("<div class='tooltip'></div>");
this.tooltip.html("<div class='tooltipFill'><p>" + this.data + "</p></div>");
this.tooltip.css({
left: this.x + this.radius * 0.5,
top: this.y + this.radius * 0.5
});
return this.canvas.append(this.tooltip);
};
SimpleBubble.prototype.hideToolTip = function() {
return $(".tooltip").remove();
};
SimpleBubble.prototype.move = function() {
return this.el.css({
top: this.y,
left: this.x
});
};
return SimpleBubble;
})();
SimpleVis = (function() {
SimpleVis.name = 'SimpleVis';
function SimpleVis(canvas, data) {
this.data = data;
this.tickHandler = __bind(this.tickHandler, this);
this.width = 800;
this.height = 400;
this.canvas = $(canvas);
this.force = null;
this.bubbles = [];
this.centers = [
{
x: 200,
y: 200
}, {
x: 400,
y: 200
}, {
x: 600,
y: 200
}
];
this.bin = d3.scale.ordinal().range([0, 1, 2]);
this.init();
}
SimpleVis.prototype.bubbleCharge = function(d) {
return -Math.pow(d.radius, 1) * 8;
};
SimpleVis.prototype.makeBubbles = function(data, i, canvas) {
var b;
b = new SimpleBubble(data, i, canvas);
b.x = b.boxSize + (20 * (i + 1));
b.y = b.boxSize + (10 * (i + 1));
this.bubbles.push(b);
return this.canvas.append(b.el);
};
SimpleVis.prototype.setBubbleLocation = function(bubble, alpha) {
var center;
center = this.centers[this.bin(bubble.id)];
bubble.y = bubble.y + (center.y - bubble.y) * 0.115 * alpha;
bubble.x = bubble.x + (center.x - bubble.x) * 0.115 * alpha;
return [bubble.x, bubble.y];
};
SimpleVis.prototype.updateBubbleLocation = function(bubble, alpha) {
this.setBubbleLocation(bubble, alpha);
return bubble.move();
};
SimpleVis.prototype.tickHandler = function(event) {
var bubble, _i, _len, _ref, _results;
_ref = this.bubbles;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
bubble = _ref[_i];
_results.push(this.updateBubbleLocation(bubble, event.alpha));
}
return _results;
};
SimpleVis.prototype.init = function() {
var d, i, _i, _len, _ref;
this.canvas.css({
width: this.width,
height: this.height,
"background-color": "#eee",
position: "relative"
});
_ref = this.data;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
d = _ref[i];
this.makeBubbles(d, i, this.canvas);
}
this.force = d3.layout.force().nodes(this.bubbles).gravity(0).charge(this.bubbleCharge).friction(0.87).size([this.width, this.height]).on('tick', this.tickHandler);
return this.force.start();
};
return SimpleVis;
})();
$(document).ready(function() {
var vis;
vis = new SimpleVis("#canvas", [12, 33, 20, 40, 60, 10, 25, 44, 13, 23, 14, 25, 8]);
return $("#move").on("click", function(e) {
vis.bin.range(vis.bin.range().reverse());
vis.force.resume();
return false;
});
});
}).call(this);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment