<html>
<head>
<meta charset="UTF-8">
<style>
html {
background-image: url('http://i.imgur.com/EZgaziF.png')
}
canvas {
border: 1px solid black;
background: black;
}
textarea {
color: red;
background: white;
display: none;
width: 100%;
height: 300px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.14.2/math.min.js"></script>
</head>
<body>
<canvas id="graph" width="500" height="500"></canvas>
<textarea id="error"></textarea>
</body>
<script>
// UTILS
var utils = {
setDefaults: function (obj, defaults) {
obj = obj == null ? {} : obj;
for (var prop in defaults) {
var op = obj[prop];
if (op == null) {
obj[prop] = defaults[prop];
}
}
return obj;
}
}
</script>
<script>
// GRAPHING CORE
var c = document.getElementById("graph");
var ctx = c.getContext("2d");
var graphHeight = c.height;
var graphWidth = c.width;
var halfGraphHeight = graphHeight / 2;
var halfGraphWidth = graphWidth / 2;
function getScreenPoint(x, y) {
return { x: halfGraphWidth + x, y: halfGraphHeight - y };
}
function screenPointIsOnScreen(screenPoint) {
var maxX = graphWidth * 10;
var maxY = graphHeight * 10;
return screenPoint.x < maxX && screenPoint.y < maxY;
}
function graph(f, options) {
options = utils.setDefaults(options, {
min: -1 * halfGraphWidth,
max: halfGraphWidth,
interval: 1,
xRotation: 0,
yRotation: 0,
zRotation: 0,
color: "rgb(255,255,255)"
});
ctx.beginPath();
ctx.strokeStyle = options.color;
for (var x = options.min; x <= options.max; x += options.interval) {
var y = f(x);
var rotatedCoordinate = rotateCoordinate([x, y, 0], options.xRotation, options.yRotation, options.zRotation);
var screenPoint = getScreenPoint(rotatedCoordinate.x, rotatedCoordinate.y);
if (screenPointIsOnScreen(screenPoint)) {
if (x === options.min) {
ctx.moveTo(screenPoint.x, screenPoint.y);
}
else {
ctx.lineTo(screenPoint.x, screenPoint.y);
ctx.moveTo(screenPoint.x, screenPoint.y);
}
}
}
ctx.stroke();
ctx.closePath();
}
function plotPoint(x, y, options) {
options = utils.setDefaults(options, {
size: 1,
color: "rgb(255,255,255)"
});
ctx.fillStyle = options.color;
var screenPoint = getScreenPoint(x, y);
ctx.beginPath();
ctx.arc(screenPoint.x, screenPoint.y, options.size, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
function drawLine(point1, point2, options) {
options = utils.setDefaults(options, {
color: "rgb(255,255,255)"
});
var screenPoint1 = getScreenPoint(point1.x, point1.y);
var screenPoint2 = getScreenPoint(point2.x, point2.y);
ctx.strokeStyle = options.color;
ctx.beginPath();
ctx.moveTo(screenPoint1.x, screenPoint1.y);
ctx.lineTo(screenPoint2.x, screenPoint2.y);
ctx.stroke();
ctx.closePath();
}
function clear(x, y, width, height) {
x = x || 0;
y = y || 0;
width = width || c.width;
height = height || c.height;
ctx.clearRect(x, y, width, height);
}
function rotateCoordinate(coordinate, xRotation, yRotation, zRotation) {
var xTransform = math.matrix([
[1, 0, 0],
[0, math.cos(xRotation), -1 * math.sin(xRotation)],
[0, math.sin(xRotation), math.cos(xRotation)]
]);
var yTransform = math.matrix([
[math.cos(yRotation), 0, math.sin(yRotation)],
[0, 1, 0],
[-1 * math.sin(yRotation), 0, math.cos(yRotation)]
]);
var zTransform = math.matrix([
[math.cos(zRotation), -1 * math.sin(zRotation), 0],
[math.sin(zRotation), math.cos(zRotation), 0],
[0, 0, 1]
]);
var basis = math.multiply(math.multiply(xTransform, yTransform), zTransform);
w = math.multiply(basis, coordinate);
return w._data;
}
// var mover = 1; setInterval(function() { mover-=.005; clear(null, 350, null, 150); graph(function(x) { return 50*math.sin(x/25 + mover) - 200; }, {color: "blue", zRotation: math.PI/18}); }, 30);
// graph(function(x) { return 50*math.sin(x/25); }, {color: "blue"});
// plotPoint(180, 180, { size:50, color:'yellow'});
ctx.font = "30px Arial";
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillText(graphHeight + "x" + graphWidth, 10, 50);
</script>
<script>
// PRIMITIVES
function Point(x, y, z) {
var self = this;
self.b = [x, y, z];
self.bp = [x, y, z];
}
function Line(point1, point2) {
var self = this;
self.point1 = point1;
self.point2 = point2;
}
Line.prototype.draw = function () {
var self = this;
var point1 = { x: self.point1.bp[0], y: self.point1.bp[1] };
var point2 = { x: self.point2.bp[0], y: self.point2.bp[1] };
drawLine(point1, point2);
};
function Polygon(points) {
var self = this;
self.points = points;
self.lines = [];
self.xRotation = 0;
self.yRotation = 0;
self.zRotation = 0;
// plot all points
self.points.forEach(function (point) {
plotPoint(point.x, point.y, { color: "red" });
});
// create lines
for (var i = 0; i < self.points.length; i++) {
var point1 = self.points[i];
var point2 = self.points[(i === self.points.length - 1 ? 0 : i + 1)];
self.lines.push(new Line(point1, point2));
}
self.draw();
}
Polygon.prototype.addRotation = function (xRotation, yRotation, zRotation) {
var self = this;
xRotation = xRotation == null ? 0 : xRotation;
yRotation = yRotation == null ? 0 : yRotation;
zRotation = zRotation == null ? 0 : zRotation;
self.xRotation += xRotation;
self.yRotation += yRotation;
self.zRotation += zRotation;
self.xRotation = self.xRotation > math.PI * 2 ? self.xRotation - math.PI * 2 : self.xRotation;
self.yRotation = self.yRotation > math.PI * 2 ? self.yRotation - math.PI * 2 : self.yRotation;
self.zRotation = self.zRotation > math.PI * 2 ? self.zRotation - math.PI * 2 : self.zRotation;
self.points.forEach(function (point) {
point.bp = rotateCoordinate(point.b, self.xRotation, self.yRotation, self.zRotation);
});
self.draw();
};
Polygon.prototype.draw = function () {
var self = this;
self.lines.forEach(function (line) {
line.draw();
});
}
/*var poly1 = new Polygon([
new Point(151, 150, 0),
new Point(-151, 150, 0),
new Point(-150, -150, 0),
new Point(150, -150, 0)
]);*/
var poly1 = new Polygon([
new Point(-50, 50, -50),
new Point(50, 50, -50),
new Point(50, -50, -50),
new Point(-50, -50, -50)
]);
var poly2 = new Polygon([
new Point(50, 50, -50),
new Point(50, 50, 50),
new Point(50, -50, 50),
new Point(50, -50, -50)
]);
var poly3 = new Polygon([
new Point(-50, 50, 50),
new Point(50, 50, 50),
new Point(50, -50, 50),
new Point(-50, -50, 50)
]);
var poly4 = new Polygon([
new Point(-50, 50, -50),
new Point(-50, 50, 50),
new Point(-50, -50, 50),
new Point(-50, -50, -50)
]);
var poly5 = new Polygon([
new Point(-50, 50, -50),
new Point(50, 50, -50),
new Point(50, 50, 50),
new Point(-50, 50, 50)
]);
var poly6 = new Polygon([
new Point(-50, -50, -50),
new Point(50, -50, -50),
new Point(50, -50, 50),
new Point(-50, -50, 50)
]);
clear(125, 125, 250, 250);
var initialRotation = math.PI/3;
poly1.addRotation(initialRotation, initialRotation, initialRotation);
poly2.addRotation(initialRotation, initialRotation, initialRotation);
poly3.addRotation(initialRotation, initialRotation, initialRotation);
poly4.addRotation(initialRotation, initialRotation, initialRotation);
poly5.addRotation(initialRotation, initialRotation, initialRotation);
poly6.addRotation(initialRotation, initialRotation, initialRotation);
(function () {
setInterval(function() {
clear(125, 125, 250, 250);
var x = .001;
var y = .01;
var z = .001;
poly1.addRotation(x, y, z);
poly2.addRotation(x, y, z);
poly3.addRotation(x, y, z);
poly4.addRotation(x, y, z);
poly5.addRotation(x, y, z);
poly6.addRotation(x, y, z);
}, 30);
})();
</script>
<script>
// 3D CUBE
(function () {
var xRotation = math.PI / 4;
var yRotation = math.PI / 4;
var zRotation = math.PI / 4;
var coords = [
[1, 1, 1],
[1, 1, -1],
[-1, 1, 1],
[-1, 1, -1],
[1, -1, 1],
[1, -1, -1],
[-1, -1, 1],
[-1, -1, -1]
];
function rotate(r, amt) {
r += amt;
r = r > 2 * math.PI ? 0 : r;
return r;
}
setInterval(function () {
clear(150, 150, 200, 200);
xRotation = rotate(xRotation, .001);
yRotation = rotate(yRotation, .01);
zRotation = rotate(yRotation, .003);
coords.forEach(function (coord, i) {
coord = coord.map(function (c) { return c * 50; }); // this is not "math". just a quick fix to make it visible
coord = rotateCoordinate(coord, xRotation, yRotation, zRotation);
plotPoint(coord.x, coord.y);
});
}, 30);
})//();
</script>
</html>
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |