简体   繁体   中英

Convert SVG polygon to a 3d polygon in svg not canvas

I have JSON data to generate some SVG (2D) polygons. I'm looking for a way to draw these polygons in SVG with three dimensions. I've found many libraries to draw 3D paths and polygons in canvas but I need SVG to have access to my polygons as a DOM object. For better understanding, I want something like this but I want the output in SVG: JSModeler

SVG中的2D polygin SVG中的3D多边形

SVG was never created to do 3D, but you can emulate 3D by having multiple polygons stand-in for polygon faces:

 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); 

Okay so i read up on 3D manipulation of 2D shapes and found this excellent tutorial for 3D Canvas animations that i managed to make an SVG version of:

 /** * 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); 

From here you should be able to produce most any shape in 3D space yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM