js-2dmath
Version:
Fast 2d geometry math: Vector2, Rectangle, Circle, Matrix2x3 (2D transformation), Circle, BoundingBox, Line2, Segment2, Intersections, Distances, Transitions (animation/tween), Random numbers, Noise
412 lines (332 loc) • 10.1 kB
JavaScript
/**
* Utilities for rendering in CanvasElement
*/
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Rectangle} rect
* @param {String} style strokeStyle
*/
function rectangle(context2d, rect, style) {
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.strokeRect(rect[0][0], rect[0][1], rect[1][0] - rect[0][0], rect[1][1] - rect[0][1]);
}
if ("undefined" !== typeof CanvasRenderingContext2D) {
var fillText = CanvasRenderingContext2D.prototype.fillText;
function invertFillText(a, b, c) {
this.save();
//ctx.setTransform(1, 0, 0, 1, 0, 0);
this.transform(1, 0, 0, -1, 0, 0);
fillText.call(this, a, b, -c);
this.restore();
}
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
}
/**
* calling this override fillText so you didn"t see inverted text
* You must not modify the transformation matrix without the proper save/restore.
* @param {CanvasElement} canvas
* @param {CanvasRenderingContext2D} context2d
*/
function invertAxis(canvas, context2d) {
context2d.setTransform(1, 0, 0, -1, 0, canvas.height);
context2d.fillText = invertFillText;
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Number=} coords
* @param {Number=} count
*/
function cartesianAxis(context2d, coords, count) {
context2d.save();
context2d.strokeStyle = "rgba(0,0,0, 0.25)";
//context2d.strokeStyle = "red";
context2d.font = "6pt Consolas";
coords = coords || 320;
count = count || 16;
context2d.beginPath();
context2d.moveTo(-coords, 0);
context2d.lineTo(coords, 0);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(0, -coords);
context2d.lineTo(0, coords);
context2d.stroke();
if (context2d.setLineDash) {
context2d.setLineDash([1, 2]);
} else {
context2d.strokeStyle = "rgba(0,0,0, 0.125)";
}
context2d.beginPath();
context2d.moveTo(-coords, coords * 0.5);
context2d.lineTo(coords, coords * 0.5);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(-coords, -coords * 0.5);
context2d.lineTo(coords, -coords * 0.5);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(coords * 0.5, -coords);
context2d.lineTo(coords * 0.5, coords);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(-coords * 0.5, -coords);
context2d.lineTo(-coords * 0.5, coords);
context2d.stroke();
context2d.setLineDash([]);
context2d.strokeStyle = "rgba(0,0,0, 0.25)";
var i,
inc = coords * 2 / count,
max = count,
x,
y;
context2d.textAlign = "center";
for (i = 0; i <= max; ++i) {
x = -coords + i * inc;
context2d.beginPath();
context2d.moveTo(x, 4);
context2d.lineTo(x, -4);
context2d.stroke();
if (x !== 0) {
context2d.fillText(x, x, -12);
}
}
context2d.fillText("(0,0)", 0, -12);
context2d.textAlign = "left";
for (i = 0; i <= max; ++i) {
y = -coords + i * inc;
context2d.beginPath();
context2d.moveTo(4, y);
context2d.lineTo(-4, y);
context2d.stroke();
if (y !== 0) {
context2d.fillText(y, +12, y - 4);
}
}
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Circle} circle
* @param {String} style strokeStyle/fillStyle
* @param {Boolean=} fill
*/
function circle(context2d, circle, style, fill) {
context2d.save();
if (style !== undefined) {
fill ? context2d.fillStyle = style : context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.arc(circle[0][0], circle[0][1], circle[1], 0, 2 * Math.PI, false);
context2d.stroke();
context2d.beginPath();
context2d.arc(circle[0][0], circle[0][1], 1, 0, 2 * Math.PI, false);
fill ? context2d.fill() : context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Line2} line2
* @param {String} style strokeStyle
* @param {Number=} length
*/
function line2(context2d, line2, style, length) {
context2d.save();
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.beginPath();
var m = line2[1];
length = length || 100;
context2d.moveTo(line2[0][0] - (length * m), line2[0][1] - length);
context2d.lineTo(line2[0][0] + (length * m), line2[0][1] + length);
context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Vec2} vec2
* @param {String} style strokeStyle
* @param {Number=} length
*/
function vec2(context2d, vec2, style, length) {
context2d.save();
length = length || 2;
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.moveTo(vec2[0] + length, vec2[1] + length);
context2d.lineTo(vec2[0] - length, vec2[1] - length);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(vec2[0] - length, vec2[1] + length);
context2d.lineTo(vec2[0] + length, vec2[1] - length);
context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Vec2} origin
* @param {Vec2} vec2
* @param {Number=} length
* @param {String} style strokeStyle
*/
function vec2dir(context2d, origin, vec2, length, style) {
context2d.save();
length = length || 2;
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.moveTo(origin[0], origin[1]);
context2d.lineTo(origin[0] + vec2[0] * length, origin[1] + vec2[1] * length);
context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Vec2} vec2
* @param {Number} angle
* @param {String} style strokeStyle
* @param {Number=} length
*/
function angle(context2d, vec2, angle, style, length) {
context2d.save();
length = length || 10;
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.moveTo(vec2[0] + 2, vec2[1] + 2);
context2d.lineTo(vec2[0] - 2, vec2[1] - 2);
context2d.stroke();
context2d.beginPath();
context2d.moveTo(vec2[0], vec2[1]);
context2d.lineTo(vec2[0] + Math.cos(angle) * length, vec2[1] + Math.sin(angle) * length);
context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Segment2} seg2
* @param {String} style strokeStyle
*/
function segment2(context2d, seg2, style) {
context2d.save();
if (style !== undefined) {
context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.moveTo(seg2[0], seg2[1]);
context2d.lineTo(seg2[2], seg2[3]);
context2d.stroke();
context2d.beginPath();
context2d.arc(seg2[0], seg2[1], 1, 0, 2 * Math.PI, false);
context2d.stroke();
context2d.beginPath();
context2d.arc(seg2[2], seg2[3], 1, 0, 2 * Math.PI, false);
context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Triangle} tri
* @param {String} style strokeStyle/fillStyle
* @param {Boolean=} fill
*/
function triangle(context2d, tri, style, fill) {
context2d.save();
if (style !== undefined) {
fill ? context2d.fillStyle = style : context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.lineTo(tri[1][0], tri[1][1]);
context2d.lineTo(tri[2][0], tri[2][1]);
context2d.lineTo(tri[0][0], tri[0][1]);
context2d.lineTo(tri[1][0], tri[1][1]);
fill ? context2d.fill() : context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {AABB2} aabb2
* @param {String} style strokeStyle/fillStyle
* @param {Boolean=} fill
*/
function aabb2(context2d, aabb2, style, fill) {
context2d.save();
if (style !== undefined) {
fill ? context2d.fillStyle = style : context2d.strokeStyle = style;
}
context2d.strokeRect(aabb2[0], aabb2[1], aabb2[2] - aabb2[0], aabb2[3] - aabb2[1]);
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Polygon} poly
* @param {String} style strokeStyle/fillStyle
* @param {Boolean=} fill
*/
function polygon(context2d, poly, style, fill) {
context2d.save();
if (poly.length < 3) {
fill = false;
}
if (style !== undefined) {
fill ? context2d.fillStyle = style : context2d.strokeStyle = style;
}
context2d.beginPath();
context2d.moveTo(poly[0][0], poly[0][1]);
var i,
max;
for (i = 1, max = poly.length; i < max; ++i) {
context2d.lineTo(poly[i][0], poly[i][1]);
}
context2d.lineTo(poly[0][0], poly[0][1]);
fill ? context2d.fill() : context2d.stroke();
context2d.restore();
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {String} text
* @param {Vec2} vec2 position
* @param {String=} font
*/
function text(context2d, text, vec2, font) {
font = font || "10pt Consolas";
context2d.font = font;
context2d.fillText(text, vec2[0], vec2[1]);
}
/**
* @param {CanvasRenderingContext2D} context2d
* @param {Matrix23} m2d
*/
function applyMatrix23(context2d, m2d) {
context2d.setTransform(m2d[0], m2d[1], m2d[2], m2d[3], m2d[4], m2d[5]);
}
var Draw = {
invertAxis: invertAxis,
cartesianAxis: cartesianAxis,
vec2: vec2,
vec2dir: vec2dir,
rectangle: rectangle,
circle: circle,
line2: line2,
triangle: triangle,
angle: angle,
segment2: segment2,
aabb2: aabb2,
polygon: polygon,
applyMatrix23: applyMatrix23,
text: text
};
module.exports = Draw;