Skip to content

Instantly share code, notes, and snippets.

@armollica
Last active December 4, 2015 05:12
Show Gist options
  • Save armollica/5a9541beb07565a37d32 to your computer and use it in GitHub Desktop.
Save armollica/5a9541beb07565a37d32 to your computer and use it in GitHub Desktop.
Shape Objects

Creating simple shape objects.

This can simplify drawing to canvas:

ellipse.context(canvas).stroke();

It also lets you encapsulates geometry-related helper functions. For example, the parametric function of an ellipse mapping to Cartesian coordinates:

var point = ellipse.cartesian(theta); // point = {x, y}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Shape Objects</title>
</head>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="shapes.js"></script>
<script>
var width = 960,
height = 500,
t0 = Date.now();
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
var ellipse = shapes.ellipse().context(canvas.node());
var circles = d3.range(0, 2*Math.PI, 2*Math.PI/25)
.map(function(t0) {
return {
t0: t0,
shape: shapes.circle().context(canvas.node())
};
});
d3.timer(function() {
var dt = Date.now() - t0,
tick = dt/3000;
context.clearRect(0, 0, width, height);
ellipse
.update(width/2, height/2, 400*Math.cos(tick), 200*Math.sin(tick))
.stroke();
circles.forEach(function(circle) {
var center = ellipse.cartesian(tick + circle.t0),
radius = 5*Math.sin(tick + circle.t0) + 10;
circle.shape
.update(center.x, center.y, radius)
.fill();
});
});
</script>
</body>
</html>
var shapes = {};
(function() {
function Ellipse(cx, cy, rx, ry) {
this.cx = cx;
this.cy = cy;
this.rx = rx;
this.ry = ry;
this._context = null;
}
Ellipse.prototype.update = function(cx, cy, rx, ry) {
this.cx = cx;
this.cy = cy;
this.rx = rx;
this.ry = ry;
return this;
};
Ellipse.prototype.context = function(canvas) {
if (!arguments.length) return this._context;
this._context = canvas.getContext("2d");
return this;
};
Ellipse.prototype.cartesian = function(theta) {
var x = this.rx * Math.cos(theta) + this.cx,
y = this.ry * Math.sin(theta) + this.cy;
return {x, y}
};
Ellipse.prototype.stroke = function() {
var context = this.context(),
theta = 0,
dt = Math.PI/24,
point = this.cartesian(theta);
context.beginPath();
context.moveTo(point.x, point.y);
for (theta = dt; theta <= 2*Math.PI; theta += dt) {
point = this.cartesian(theta);
context.lineTo(point.x, point.y);
}
context.stroke();
context.closePath();
return this;
};
Ellipse.prototype.fill = function() {
var context = this.context(),
theta = 0,
dt = Math.PI/24,
point = this.cartesian(theta);
context.beginPath();
context.moveTo(point.x, point.y);
for (theta = dt; theta <= 2*Math.PI; theta += dt) {
point = this.cartesian(theta);
context.lineTo(point.x, point.y);
}
context.fill();
context.closePath();
return this;
};
function Circle(cx, cy, r) {
Ellipse.call(this, cx, cy, r, r);
}
Circle.prototype = Object.create(Ellipse.prototype);
Circle.prototype.update = function(cx, cy, r) {
this.cx = cx;
this.cy = cy;
this.rx = r;
this.ry = r;
return this;
};
shapes.ellipse = function(cx, cy, rx, ry) {
var ellipse = new Ellipse(cx, cy, rx, ry);
return ellipse;
};
shapes.circle = function(cx, cy, r) {
var circle = new Circle(cx, cy, r);
return circle;
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment