d3-3d
Version:
D3.js plugin for 3d visualization
413 lines (324 loc) • 12.8 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = {}));
}(this, (function (exports) { 'use strict';
function ccw(polygon) {
var _p = polygon.slice(0), sum = 0;
_p.push(_p[0]);
for (var i = 0; i <= polygon.length - 1; i++) {
var j = i + 1;
var p1 = _p[i].rotated;
var p2 = _p[j].rotated;
sum += (p2.x - p1.x) * (p2.y + p1.y);
}
// if the area is positive
// the curve is counter-clockwise
// because of the flipped y-Axis in the browser
return sum > 0 ? true : false;
}
function centroid(polygon){
var _x = 0, _y = 0, _z = 0, _n = polygon.length;
for (var i = _n - 1; i >= 0; i--) {
_x += polygon[i].rotated.x;
_y += polygon[i].rotated.y;
_z += polygon[i].rotated.z;
}
return {
x: _x / _n,
y: _y / _n,
z: _z / _n,
};
}
function rotateRzRyRx(po, angles){
var rc = angles.rotateCenter;
po.x -= rc[0];
po.y -= rc[1];
po.z -= rc[2];
var rz = rotateZ(po, angles.z);
var ry = rotateY(rz, angles.y);
var rx = rotateX(ry, angles.x);
rx.x += rc[0];
rx.y += rc[1];
rx.z += rc[2];
return rx;
}
function rotateX(p, a){
var sa = Math.sin(a), ca = Math.cos(a);
return {
x: p.x,
y: p.y * ca - p.z * sa,
z: p.y * sa + p.z * ca
};
}
function rotateY(p, a){
var sa = Math.sin(a), ca = Math.cos(a);
return {
x: p.z * sa + p.x * ca,
y: p.y,
z: p.z * ca - p.x * sa
};
}
function rotateZ(p, a){
var sa = Math.sin(a), ca = Math.cos(a);
return {
x: p.x * ca - p.y * sa,
y: p.x * sa + p.y * ca,
z: p.z
};
}
function point(points, options, point, angles){
for (var i = points.length - 1; i >= 0; i--) {
var p = points[i];
p.rotated = rotateRzRyRx({x : point.x(p), y : point.y(p), z : point.z(p)}, angles);
p.centroid = p.rotated;
p.projected = options.project(p.rotated, options);
}
return points;
}
function cube(cubes, options, point$1, angles){
for (var i = cubes.length - 1; i >= 0; i--) {
var cube = cubes[i];
var vertices = point([
cube[0],
cube[1],
cube[2],
cube[3],
cube[4],
cube[5],
cube[6],
cube[7]
], options, point$1, angles);
var v1 = vertices[0];
var v2 = vertices[1];
var v3 = vertices[2];
var v4 = vertices[3];
var v5 = vertices[4];
var v6 = vertices[5];
var v7 = vertices[6];
var v8 = vertices[7];
var front = [v1, v2, v3, v4];
var back = [v8, v7, v6, v5];
var left = [v5, v6, v2, v1];
var right = [v4, v3, v7, v8];
var top = [v5, v1, v4, v8];
var bottom = [v2, v6, v7, v3];
front.centroid = centroid(front);
back.centroid = centroid(back);
left.centroid = centroid(left);
right.centroid = centroid(right);
top.centroid = centroid(top);
bottom.centroid = centroid(bottom);
front.ccw = ccw(front);
back.ccw = ccw(back);
left.ccw = ccw(left);
right.ccw = ccw(right);
top.ccw = ccw(top);
bottom.ccw = ccw(bottom);
front.face = 'front';
back.face = 'back';
left.face = 'left';
right.face = 'right';
top.face = 'top';
bottom.face = 'bottom';
var faces = [front, back, left, right, top, bottom];
cube.faces = faces;
cube.centroid = {x: (left.centroid.x + right.centroid.x)/2, y: (top.centroid.y + bottom.centroid.y)/2, z: (front.centroid.z + back.centroid.z/2)};
}
return cubes;
}
function gridPlane(grid, options, point$1, angles){
var points = point(grid, options, point$1, angles);
var cnt = 0, planes = [];
var numPts = options.row;
var numRow = points.length/numPts;
for (var i = numRow - 1; i > 0; i--) {
for (var j = numPts - 1; j > 0; j--) {
var p1 = j + i * numPts, p4 = p1 - 1, p2 = p4 - numPts + 1, p3 = p2 - 1;
var pl = [points[p1], points[p2], points[p3], points[p4]];
pl.plane = 'plane_' + cnt++;
pl.ccw = ccw(pl);
pl.centroid = centroid(pl);
planes.push(pl);
}
}
return planes;
}
function lineStrip(lineStrip, options, point, angles){
for (var i = lineStrip.length - 1; i >= 0; i--) {
var l = lineStrip[i], m = l.length/2, t = parseInt(m);
for (var j = l.length - 1; j >= 0; j--) {
var p = l[j];
p.rotated = rotateRzRyRx({x : point.x(p), y : point.y(p), z : point.z(p)}, angles);
p.projected = options.project(p.rotated, options);
}
l.centroid = t === m ? centroid([ l[m - 1], l[m] ]) : { x: l[t].rotated.x, y: l[t].rotated.y, z: l[t].rotated.z };
}
return lineStrip;
}
function line(lines, options, point, angles){
for (var i = lines.length - 1; i >= 0; i--) {
var line = lines[i];
var p1 = line[0];
var p2 = line[1];
p1.rotated = rotateRzRyRx({x : point.x(p1), y : point.y(p1), z : point.z(p1)}, angles);
p2.rotated = rotateRzRyRx({x : point.x(p2), y : point.y(p2), z : point.z(p2)}, angles);
p1.projected = options.project(p1.rotated, options);
p2.projected = options.project(p2.rotated, options);
line.centroid = centroid(line);
}
return lines;
}
function plane(planes, options, point, angles){
for (var i = planes.length - 1; i >= 0; i--) {
var plane = planes[i];
var p1 = plane[0];
var p2 = plane[1];
var p3 = plane[2];
var p4 = plane[3];
p1.rotated = rotateRzRyRx({x : point.x(p1), y : point.y(p1), z : point.z(p1)}, angles);
p2.rotated = rotateRzRyRx({x : point.x(p2), y : point.y(p2), z : point.z(p2)}, angles);
p3.rotated = rotateRzRyRx({x : point.x(p3), y : point.y(p3), z : point.z(p3)}, angles);
p4.rotated = rotateRzRyRx({x : point.x(p4), y : point.y(p4), z : point.z(p4)}, angles);
p1.projected = options.project(p1.rotated, options);
p2.projected = options.project(p2.rotated, options);
p3.projected = options.project(p3.rotated, options);
p4.projected = options.project(p4.rotated, options);
plane.ccw = ccw(plane);
plane.centroid = centroid(plane);
}
return planes;
}
function triangle(triangles, options, point, angles){
for (var i = triangles.length - 1; i >= 0; i--) {
var tri = triangles[i];
var p1 = tri[0];
var p2 = tri[1];
var p3 = tri[2];
p1.rotated = rotateRzRyRx({x : point.x(p1), y : point.y(p1), z : point.z(p1)}, angles);
p2.rotated = rotateRzRyRx({x : point.x(p2), y : point.y(p2), z : point.z(p2)}, angles);
p3.rotated = rotateRzRyRx({x : point.x(p3), y : point.y(p3), z : point.z(p3)}, angles);
p1.projected = options.project(p1.rotated, options);
p2.projected = options.project(p2.rotated, options);
p3.projected = options.project(p3.rotated, options);
tri.ccw = ccw(tri);
tri.centroid = centroid(tri);
}
return triangles;
}
function drawLineStrip(lineStrip){
var lastPoint = lineStrip[lineStrip.length - 1];
var path = 'M' + lastPoint.projected.x + ',' + lastPoint.projected.y;
for (var i = lineStrip.length - 2; i >= 0; i--) {
var p = lineStrip[i].projected;
path += 'L' + p.x + ',' + p.y;
}
return path;
}
function drawPlane(d){
return 'M' + d[0].projected.x + ',' + d[0].projected.y + 'L' + d[1].projected.x + ',' + d[1].projected.y + 'L' + d[2].projected.x + ',' + d[2].projected.y + 'L' + d[3].projected.x + ',' + d[3].projected.y + 'Z';
}
function drawTriangle(d){
return 'M' + d[0].projected.x + ',' + d[0].projected.y + 'L' + d[1].projected.x + ',' + d[1].projected.y + 'L' + d[2].projected.x + ',' + d[2].projected.y + 'Z';
}
function orthographic(d, options){
return {
x: options.origin[0] + options.scale * d.x,
y: options.origin[1] + options.scale * d.y
};
}
function x(p) {
return p[0];
}
function y(p) {
return p[1];
}
function z(p) {
return p[2];
}
/**
* @author Stefan Nieke / http://niekes.com/
*/
function _3d() {
var origin = [0, 0],
scale = 1,
projection = orthographic,
angleX = 0,
angleY = 0,
angleZ = 0,
rotateCenter = [0,0,0],
x$1 = x,
y$1 = y,
z$1 = z,
row = undefined,
shape = 'POINT',
processData = {
'CUBE' : cube,
'GRID' : gridPlane,
'LINE' : line,
'LINE_STRIP' : lineStrip,
'PLANE' : plane,
'POINT' : point,
'SURFACE' : gridPlane,
'TRIANGLE' : triangle,
},
draw = {
'CUBE' : drawPlane,
'GRID' : drawPlane,
'LINE_STRIP' : drawLineStrip,
'PLANE' : drawPlane,
'SURFACE' : drawPlane,
'TRIANGLE' : drawTriangle,
};
function _3d(data){
return processData[shape](
data,
{ scale: scale, origin: origin, project: projection, row: row },
{ x: x$1, y: y$1, z: z$1 },
{ x: angleX, y: angleY, z: angleZ, rotateCenter: rotateCenter }
);
}
_3d.origin = function(_){
return arguments.length ? (origin = _, _3d) : origin;
};
_3d.scale = function(_){
return arguments.length ? (scale = _, _3d) : scale;
};
_3d.rotateX = function(_){
return arguments.length ? (angleX = _, _3d) : angleX;
};
_3d.rotateY = function(_){
return arguments.length ? (angleY = _, _3d) : angleY;
};
_3d.rotateZ = function(_){
return arguments.length ? (angleZ = _, _3d) : angleZ;
};
_3d.shape = function(_, r){
return arguments.length ? (shape = _, row = r, _3d) : shape;
};
_3d.rotateCenter = function(_){
return arguments.length ? (rotateCenter = _, _3d) : rotateCenter;
};
_3d.x = function(_){
return arguments.length ? (x$1 = typeof _ === 'function' ? _ : +_, _3d) : x$1;
};
_3d.y = function(_){
return arguments.length ? (y$1 = typeof _ === 'function' ? _ : +_, _3d) : y$1;
};
_3d.z = function(_){
return arguments.length ? (z$1 = typeof _ === 'function' ? _ : +_, _3d) : z$1;
};
_3d.sort = function(a, b){
var _a = a.centroid.z, _b = b.centroid.z;
return _a < _b ? -1 : _a > _b ? 1 : _a >= _b ? 0 : NaN;
};
_3d.draw = function(d){
if(!((shape === 'POINT') || (shape === 'LINE'))){
return draw[shape](d);
}
};
return _3d;
}
exports._3d = _3d;
Object.defineProperty(exports, '__esModule', { value: true });
})));