我有JSON数据来生成一些SVG(2D)多边形。我正在寻找一种在三维中在SVG中绘制这些多边形的方法。我发现很多库在画布中绘制3D路径和多边形,但是我需要SVG来访问我的多边形作为DOM对象。 为了更好地理解,我想要这样的东西,但我想要SVG中的输出: JSModeler
答案 0 :(得分:1)
从未创建SVG来制作3D,但您可以通过为多边形面提供多个多边形来模拟3D:
var Polygon = (function() {
function Polygon(lines, fill) {
if (lines === void 0) {
lines = [];
}
if (fill === void 0) {
fill = "rgba(" + (Math.round(Math.random() * 255)) + "," + (Math.round(Math.random() * 255)) + "," + (Math.round(Math.random() * 255)) + ",0.15)";
}
this.lines = lines;
this.fill = fill;
this.svgshape = document.createElementNS('http://www.w3.org/2000/svg', "polygon");
this.svgshape.style.stroke = 'black';
}
Polygon.prototype.render = function(position) {
if (position === void 0) {
position = {
x: 0,
y: 0
};
}
this.svgshape.style.fill = this.fill;
var points = [];
for (var lineIndex = 0; lineIndex < this.lines.length; lineIndex++) {
var line = this.lines[lineIndex];
points.push((line.x + 0.3 * line.z + position.x) + "," + (line.y + 0.3 * line.z + position.y));
}
this.svgshape.setAttribute("points", points.join(" "));
};
return Polygon;
}());
var PolygonSet = (function() {
function PolygonSet(polygons, position) {
if (polygons === void 0) {
polygons = [];
}
if (position === void 0) {
position = {
x: 0,
y: 0
};
}
this.polygons = polygons;
this.position = position;
}
PolygonSet.prototype.render = function(svg) {
if (svg === void 0) {
svg = null;
}
for (var pIndex = 0; pIndex < this.polygons.length; pIndex++) {
var polygon = this.polygons[pIndex];
polygon.render(this.position);
if (svg != null) {
svg.appendChild(polygon.svgshape);
}
}
};
return PolygonSet;
}());
//TEST
var svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
svg.setAttribute("width", "200");
svg.setAttribute("height", "200");
svg.setAttribute("xmlns", 'http://www.w3.org/2000/svg');
var box = new PolygonSet([
//Floor
/* */
new Polygon([{
x: 0,
y: 100,
z: 100
},
{
x: 100,
y: 100,
z: 100
},
{
x: 100,
y: 100,
z: 0
},
{
x: 0,
y: 100,
z: 0
}
]),
//Wall 1 - right
/* */
new Polygon([{
x: 100,
y: 0,
z: 0
},
{
x: 100,
y: 100,
z: 0
},
{
x: 100,
y: 100,
z: 100
},
{
x: 100,
y: 0,
z: 100
},
]),
//Wall 2
/* */
new Polygon([{
x: 0,
y: 0,
z: 0
},
{
x: 100,
y: 0,
z: 0
},
{
x: 100,
y: 100,
z: 0
},
{
x: 0,
y: 100,
z: 0
},
]),
//Wall 3 - left
/* */
new Polygon([{
x: 0,
y: 0,
z: 0
},
{
x: 0,
y: 100,
z: 0
},
{
x: 0,
y: 100,
z: 100
},
{
x: 0,
y: 0,
z: 100
},
]),
//Wall 4
/* */
new Polygon([{
x: 0,
y: 0,
z: 100
},
{
x: 100,
y: 0,
z: 100
},
{
x: 100,
y: 100,
z: 100
},
{
x: 0,
y: 100,
z: 100
},
]),
//Roof
/* */
new Polygon([{
x: 0,
y: 0,
z: 0
},
{
x: 100,
y: 0,
z: 0
},
{
x: 100,
y: 0,
z: 100
},
{
x: 0,
y: 0,
z: 100
}
]),
], {
x: 10,
y: 10
});
box.render(svg);
document.body.appendChild(svg);
setInterval(function() {
var polygon = box.polygons[Math.round((box.polygons.length - 1) * Math.random())];
polygon.fill = "rgba(" + (Math.round(Math.random() * 255)) + "," + (Math.round(Math.random() * 255)) + "," + (Math.round(Math.random() * 255)) + ",0.5)";
box.render();
}, 1000 / 4);
答案 1 :(得分:1)
好的,所以我读了二维形状的3D操作,并发现了{Canuss'动画的this excellent tutorial,我设法制作了SVG版本:
/**
* Point holds data for a "point-in-space" and handles any manipulations of said point, like rotation
*
* @class Point
*/
var Point = (function() {
function Point(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Rotates on all axis
*
* @param {ICoord} angle
* @returns
*
* @memberOf Point
*/
Point.prototype.rotate = function(angle) {
return this
.rotateX(angle.x)
.rotateY(angle.y)
.rotateZ(angle.y);
};
/**
* Rotate on x axis
*
* @param {number} angle
* @returns
*
* @memberOf Point
*/
Point.prototype.rotateX = function(angle) {
var rad, cosa, sina, y, z;
rad = angle * Math.PI / 180;
cosa = Math.cos(rad);
sina = Math.sin(rad);
y = this.y * cosa - this.z * sina;
z = this.y * sina + this.z * cosa;
return new Point(this.x, y, z);
};
/**
* Rotate on y axis
*
* @param {number} angle
* @returns
*
* @memberOf Point
*/
Point.prototype.rotateY = function(angle) {
var rad, cosa, sina, x, z;
rad = angle * Math.PI / 180;
cosa = Math.cos(rad);
sina = Math.sin(rad);
z = this.z * cosa - this.x * sina;
x = this.z * sina + this.x * cosa;
return new Point(x, this.y, z);
};
/**
* Rotate on z axis
*
* @param {number} angle
* @returns
*
* @memberOf Point
*/
Point.prototype.rotateZ = function(angle) {
var rad, cosa, sina, x, y;
rad = angle * Math.PI / 180;
cosa = Math.cos(rad);
sina = Math.sin(rad);
x = this.x * cosa - this.y * sina;
y = this.x * sina + this.y * cosa;
return new Point(x, y, this.z);
};
return Point;
}());
/**
* Face is a collection of point that produces a surface
* A face should have at least 3 points(vertices)
*
*
* @class Face
*/
var Face = (function() {
function Face(name, vertices, color, svgElement) {
if (vertices === void 0) {
vertices = [];
}
if (color === void 0) {
color = "rgba(0,0,255,0.5)";
}
if (svgElement === void 0) {
svgElement = document.createElementNS('http://www.w3.org/2000/svg', "polygon");
}
this.name = name;
this.vertices = vertices;
this.color = color;
this.svgElement = svgElement;
}
/**
* Calculate all vertices positions and rebuild SVG polygon
*
* @param {ICoord} [angle={ x: 0, y: 0, z: 0 }]
* @returns
*
* @memberOf Face
*/
Face.prototype.render = function(angle) {
if (angle === void 0) {
angle = {
x: 0,
y: 0,
z: 0
};
}
this.svgElement.setAttribute("face-name", this.name);
var points = [];
for (var i = 0; i < this.vertices.length; i++) {
var vert = this.vertices[i].rotate(angle);
points.push(vert.x + ',' + vert.y);
}
this.svgElement.setAttribute("stroke", this.color);
this.svgElement.setAttribute("fill", this.color);
this.svgElement.setAttribute("points", points.join(" "));
return this;
};
return Face;
}());
/**
* Polygon is a collection of Faces that make up a shape, like a Box
* Polygon manages 2D translation across the canvas and maintains shape-level data like the current angle
*
* @class Polygon
*/
var Polygon = (function() {
function Polygon(faces, position, angle, svgElement) {
if (faces === void 0) {
faces = [];
}
if (position === void 0) {
position = {
x: 0,
y: 0
};
}
if (angle === void 0) {
angle = {
x: 0,
y: 0,
z: 0
};
}
if (svgElement === void 0) {
svgElement = document.createElementNS('http://www.w3.org/2000/svg', "g");
}
this.faces = faces;
this.position = position;
this.angle = angle;
this.svgElement = svgElement;
}
/**
* Renders all faces and translate across viewport
*
* @param {ICoord} [angle=this.angle]
* @returns
*
* @memberOf Polygon
*/
Polygon.prototype.render = function(angle) {
if (angle === void 0) {
angle = this.angle;
}
this.svgElement.innerHTML = '';
for (var index = 0; index < this.faces.length; index++) {
var face = this.faces[index];
face.render(angle);
this.svgElement.appendChild(face.svgElement);
}
this.svgElement.setAttribute("transform", "translate(" + this.position.x + "," + this.position.y + ")");
return this;
};
return Polygon;
}());
/**
* Box is a utility function that creates a cube Polygon
*
* @param {ICoord} [dimensions={ x: 100, y: 100, z: 100 }]
* @param {ISimpleCoord} [position={ x: 0, y: 0 }]
* @param {ICoord} [angle={ x: 0, y: 0, z: 0 }]
* @returns
*/
function Box(dimensions, position, angle) {
if (dimensions === void 0) {
dimensions = {
x: 100,
y: 100,
z: 100
};
}
if (position === void 0) {
position = {
x: 0,
y: 0
};
}
if (angle === void 0) {
angle = {
x: 0,
y: 0,
z: 0
};
}
return new Polygon([
new Face("Back", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
new Point(-1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
]),
new Face("Left", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
]),
new Face("Right", [
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
]),
new Face("Front", [
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
]),
new Face("Top", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
]),
new Face("Bottom", [
new Point(-1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, 1 * dimensions.y, 1 * dimensions.z),
]),
], position, angle);
}
/**
* Like Box this returns a Polygon shape, this one in a Pyramid shape
*
* @param {ICoord} [dimensions={ x: 100, y: 100, z: 100 }]
* @param {ISimpleCoord} [position={ x: 0, y: 0 }]
* @param {ICoord} [angle={ x: 0, y: 0, z: 0 }]
* @returns
*/
function Pyramid(dimensions, position, angle) {
if (dimensions === void 0) {
dimensions = {
x: 100,
y: 100,
z: 100
};
}
if (position === void 0) {
position = {
x: 0,
y: 0
};
}
if (angle === void 0) {
angle = {
x: 0,
y: 0,
z: 0
};
}
return new Polygon([
new Face("Top", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
]),
new Face("Back", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(0, 1 * dimensions.y, 0),
]),
new Face("Left", [
new Point(-1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(0, 1 * dimensions.y, 0),
]),
new Face("Right", [
new Point(1 * dimensions.x, -1 * dimensions.y, -1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(0, 1 * dimensions.y, 0),
]),
new Face("Front", [
new Point(-1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(1 * dimensions.x, -1 * dimensions.y, 1 * dimensions.z),
new Point(0, 1 * dimensions.y, 0),
]),
], position, angle);
}
/**
* Viewport is the svg-layer where all polygons are drawn
*
* @class Viewport
*/
var Viewport = (function() {
function Viewport(dimensions, polygons, svgElement) {
if (dimensions === void 0) {
dimensions = {
x: 100,
y: 100
};
}
if (polygons === void 0) {
polygons = [];
}
if (svgElement === void 0) {
svgElement = document.createElementNS('http://www.w3.org/2000/svg', "svg");
}
this.dimensions = dimensions;
this.polygons = polygons;
this.svgElement = svgElement;
this.svgElement.setAttribute("width", this.dimensions.x.toString());
this.svgElement.setAttribute("height", this.dimensions.y.toString());
this.svgElement.setAttribute("xmlns", 'http://www.w3.org/2000/svg');
}
return Viewport;
}());
//TEST
var view = new Viewport({
x: 700,
y: 400
});
var box = Box({
x: 100,
y: 100,
z: 100
}, {
x: 200,
y: 200
})
.render();
var pyramid = Pyramid({
x: 100,
y: 100,
z: 100
}, {
x: 500,
y: 200
}, {
x: 180,
y: 0,
z: 0
})
.render();
//append to DOM
document.body.appendChild(view.svgElement);
view.svgElement.appendChild(box.svgElement);
view.svgElement.appendChild(pyramid.svgElement);
//Animate
setInterval(function() {
box.angle.x++;
box.angle.y++;
box.angle.z++;
box.render();
pyramid.angle.x++;
pyramid.angle.y++;
pyramid.angle.z++;
pyramid.render();
}, 1000 / 24);
&#13;
从这里你应该能够自己在3D空间中制作出任何形状。