UNPKG

chartx3d

Version:

Data Visualization Chart Library

554 lines (421 loc) 15.5 kB
import { Math as _Math, Vector2, Vector3, Matrix4, Float32BufferAttribute, BufferGeometry, TrianglesDrawMode, DoubleSide, Texture, Geometry, BoxGeometry, CylinderGeometry, LineGeometry, CircleBufferGeometry, SphereBufferGeometry, DoughnutBufferGeometry, DoughnutGeometry, Shape, ExtrudeBufferGeometry, PlaneGeometry, MeshLambertMaterial, MeshBasicMaterial, MeshPhongMaterial, LineMeshMaterial, LineBasicMaterial, LineDashedMaterial, SpriteMaterial, Group, Mesh, Line, Line2, Sprite, Earcut, LinearFilter, RepeatWrapping, FrontSide } from 'mmgl/src/index'; import { _ } from "mmvis"; import { RenderFont } from './renderFont'; const getBasicMaterial = () => { return new MeshBasicMaterial({ color: 0xffffff * Math.random() }); } //基本图元 const primitive = { //创建一个box createBox(width = 1, height = 1, depth = 1, materials = getBasicMaterial()) { // 初期把一个box 看作一个mesh 后期优化在渲染前做顶点合并 let transMatrix = new Matrix4(); let geometry = new BoxGeometry(1, 1, 1); let mesh = new Mesh(geometry, materials); //box 的中心的在正面下边的中点上,方便对box 高度和深度的变化 geometry.vertices.forEach(vertice => { vertice.addScalar(0.5); //vertice.z *= -1; }); // geometry.faces.forEach(face => { // let a = face.a; // face.a = face.b; // face.b = a; // }) // geometry.normalsNeedUpdate = true; // geometry.computeFaceNormals(); // //更加给定的得数据变换box transMatrix.makeScale(width, height, depth); geometry.vertices.forEach(vertice => { vertice.applyMatrix4(transMatrix); }); return mesh; }, //创建一个圆柱体 createCylinder(width = 1, height = 1, depth = 1, materials = getBasicMaterial()) { // 初期把一个box 看作一个mesh 后期优化在渲染前做顶点合并 let transMatrix = new Matrix4(); //let radius = width * 0.5; let part = 60; let geometry = new CylinderGeometry(1, 1, 1, part); let mesh = new Mesh(geometry, materials); //box 的中心的在正面下边的中点上,方便对box 高度和深度的变化 geometry.vertices.forEach(vertice => { vertice.addScalar(0.5); //vertice.y -= 0.5; //vertice.z *= -1; }); // geometry.faces.forEach(face => { // let a = face.a; // face.a = face.b; // face.b = a; // }) // geometry.normalsNeedUpdate = true; // geometry.computeFaceNormals(); //更加给定的得数据变换box let radius = width * 0.5; transMatrix.makeScale(radius, height, radius); geometry.vertices.forEach(vertice => { vertice.applyMatrix4(transMatrix); }); return mesh; }, createCone(width = 1, height = 1, depth = 1, materials = getBasicMaterial()) { // 初期把一个box 看作一个mesh 后期优化在渲染前做顶点合并 let transMatrix = new Matrix4(); //let radius = width * 0.5; let geometry = new CylinderGeometry(0, 1, 1, 60); let mesh = new Mesh(geometry, materials); //box 的中心的在正面下边的中点上,方便对box 高度和深度的变化 geometry.vertices.forEach(vertice => { vertice.addScalar(0.5); //vertice.y -= 0.5; // vertice.z *= -1; }); // geometry.faces.forEach(face => { // let a = face.a; // face.a = face.b; // face.b = a; // }) // geometry.normalsNeedUpdate = true; // geometry.computeFaceNormals(); //更加给定的得数据变换box let radius = width * 0.5; transMatrix.makeScale(radius, height, radius); geometry.vertices.forEach(vertice => { vertice.applyMatrix4(transMatrix); }); return mesh; }, //创建一个面 createPlane(width = 1, height = 1, materials = undefined, showInfo = { dir: new Vector3() }, group = undefined, faceStyle = {}) { if (!materials) { materials = new MeshLambertMaterial({ color: faceStyle.fillStyle || 0xffffff * Math.random(), side: FrontSide, transparent: true, opacity: faceStyle.alpha || 1, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 0.1, depthTest: true, depthWrite: false }); } let planetGeometry = new PlaneGeometry(width, height); let planeMesh = new Mesh(planetGeometry, materials); if (showInfo.dir.equals(new Vector3(1, 0, 0))) { planeMesh.rotateY(_Math.degToRad(90)); } if (showInfo.dir.equals(new Vector3(-1, 0, 0))) { planeMesh.rotateY(_Math.degToRad(-90)); } if (showInfo.dir.equals(new Vector3(0, 1, 0))) { planeMesh.rotateX(_Math.degToRad(-90)); } if (showInfo.dir.equals(new Vector3(0, -1, 0))) { planeMesh.rotateX(_Math.degToRad(90)); } if (showInfo.dir.equals(new Vector3(0, 0, -1))) { planeMesh.rotateY(_Math.degToRad(180)); } if (showInfo.center) { planeMesh.position.copy(showInfo.center) } if (group) { group.visible = showInfo.visible; group.add(planeMesh); } planeMesh.renderOrder = -100; return planeMesh; }, //绘制普通线条 createCommonLine(points = [], lineStyle) { //let group = this._frameWork.addGroup({ name: 'commonLines' }); let material = new LineBasicMaterial({ color: lineStyle.strokeStyle, // transparent: true, depthTest: true, depthWrite: false }); if (lineStyle.lineType == 'dashed') { material = new LineDashedMaterial({ color: lineStyle.strokeStyle, }) } let geometry = new Geometry(); points.forEach(item => { geometry.vertices.push(item); }) let line = new Line(geometry, material); // line.renderOrder=-110; // group.add(line); return line; }, //绘制线条 createLine(origins, direction, length, lineWidth, lineColor) { let group = new Group(); let lineMeshGeometry = null, line = null; direction.normalize() let matLine = new LineMeshMaterial({ color: lineColor, transparent: true, linewidth: lineWidth, // in pixels resolution: new Vector2(this.width, this.height), dashed: false }); if (!_.isArray(origins)) { origins = [origins]; } let triangleVertices = []; origins.forEach(origin => { triangleVertices = []; triangleVertices.push([0, 0, 0]); let endPoint = new Vector3(); //endPoint.copy([0,0,0]); let delta = new Vector3(); delta.copy(direction); delta.multiplyScalar(length); endPoint.add(delta); triangleVertices.push(endPoint.toArray()); let lineMeshGeometry = new LineGeometry(); lineMeshGeometry.setPositions(_.flatten(triangleVertices)); line = new Line2(lineMeshGeometry, matLine); line.drawMode = TrianglesDrawMode; line.computeLineDistances(); line.scale.set(1, 1, 1); line.position.copy(origin); group.add(line); }) return group; }, //绘制折线 createBrokenLine(points, lineWidth, lineColor) { let matLine = new LineMeshMaterial({ color: lineColor, linewidth: lineWidth, // in pixels resolution: new Vector2(this.width, this.height), dashed: false, depthTest: true, depthWrite: false }); let lineMeshGeometry = new LineGeometry(); let triangleVertices = []; points.forEach(point => { triangleVertices = triangleVertices.concat(point.toArray()); }); lineMeshGeometry.setPositions(triangleVertices); let line = new Line2(lineMeshGeometry, matLine); line.drawMode = TrianglesDrawMode; line.computeLineDistances(); return line; }, //绘制圆形 createCirclePlane(r, faceStyle, materials) { let geometry = new CircleBufferGeometry(r, 32); if (!materials) { materials = new SpriteMaterial({ color: faceStyle.fillStyle || 0xffffff * Math.random(), transparent: true, opacity: faceStyle.alpha || 1, depthTest: true, depthWrite: false }); } let sprite = new Sprite(materials); sprite.geometry = geometry; return sprite; }, //绘制球 createSphere(r, faceStyle, materials) { if (!materials) { materials = new MeshBasicMaterial({ color: faceStyle.fillStyle || 0xffffff * Math.random(), transparent: true, opacity: faceStyle.alpha || 1, // polygonOffset: true, // polygonOffsetFactor: 1, // polygonOffsetUnits: 0.1, depthTest: true, depthWrite: false }); } let geometry = new SphereBufferGeometry(r); let mesh = new Mesh(geometry, materials); return mesh; }, //绘制文字label creatSpriteText(texts, fontStyle) { //相机变化距离,不改变大小 //https://vouzamo.wordpress.com/2016/09/07/threejs-heads-up-display/ //1、透视相机根据距离同时调整自己的缩放 //2、或者在单独的场景使用正交投影渲染 let labels = []; let renderFont = new RenderFont(fontStyle); if (!_.isArray(texts)) { texts = [texts]; } let labelInfos = renderFont.drawTexts(texts); var position = new Float32Array([ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0, ]); let texture = new Texture(); texture.image = renderFont.canvas; texture.wrapS = RepeatWrapping; texture.wrapT = RepeatWrapping; texture.minFilter = LinearFilter; texture.magFilter = LinearFilter; texture.needsUpdate = true; let spriteMatrial = new SpriteMaterial({ color:fontStyle.fillStyle, map: texture, transparent: true, depthWrite: false, }); texts.forEach((text, index) => { let realSize = labelInfos.sizes[text]; //realSize==[width,height] let scale = new Vector3(realSize[0], realSize[1], 1); //scale.multiplyScalar(realSize[1]); //debugger let sprite = new Sprite(spriteMatrial); let geometry = new BufferGeometry(); geometry.setIndex([0, 1, 2, 0, 2, 3]); geometry.addAttribute('position', new Float32BufferAttribute(position, 3, false)) geometry.addAttribute('uv', new Float32BufferAttribute(labelInfos.UVs[text], 2, false)); sprite.geometry = geometry; sprite.scale.copy(scale); sprite.userData = { text: text, size: realSize, maxWidth: labelInfos.maxWidth, maxHeight: labelInfos.maxHeight } //默认不进行裁剪 sprite.frustumCulled = false; labels.push(sprite); }) return labels; }, //绘制多边形 createPolygonPlane(points = [], faceStyle = {}, materials) { if (!materials) { materials = new MeshBasicMaterial({ color: faceStyle.fillStyle || 0xffffff * Math.random(), side: DoubleSide, transparent: true, opacity: faceStyle.alpha || 0.2, // polygonOffset: true, // polygonOffsetFactor: 1, // polygonOffsetUnits: 0.1, depthTest: true, depthWrite: false }); } //earcut(data.vertices, data.holes, data.dimensions); let triangles = Earcut.triangulate(points, null, 3); let geometry = new BufferGeometry(); let positionBuffer = new Float32BufferAttribute(points, 3); geometry.addAttribute('position', positionBuffer); geometry.setIndex(triangles); let mesh = new Mesh(geometry, materials); return mesh; }, createArea(points = [], depth, faceStyle = {}, materials) { if (!materials) { materials = new MeshPhongMaterial({ color: faceStyle.fillStyle || 0xffffff * Math.random(), side: DoubleSide, transparent: true, opacity: faceStyle.alpha || 1.0, // polygonOffset: true, // polygonOffsetFactor: 1, // polygonOffsetUnits: 0.1, depthTest: true, depthWrite: true }); } //earcut(data.vertices, data.holes, data.dimensions); // let triangles = earcut(points, null, 3); // let geometry = new BufferGeometry(); // let positionBuffer = new Float32BufferAttribute(points, 3); // geometry.addAttribute('position', positionBuffer); // geometry.setIndex(triangles); let shape = new Shape(points); let extrudeSettings = { depth: depth || 50, bevelEnabled: true, bevelSegments: 2, steps: 1, bevelSize: 1, bevelThickness: 10 }; let geometry = new ExtrudeBufferGeometry(shape, extrudeSettings) let mesh = new Mesh(geometry, materials); return mesh; }, //饼图的一个扇形角 create3DPie(height, outterRadius, innerRadius = 0, startAngle, endAngle, materials) { let radialSegments = 32; let PI2 = Math.PI * 2; //与2D的饼图角度一直,并沿顺时针绘制 let _startAngle = _Math.degToRad(startAngle - 90); let _endAngle = _Math.degToRad(endAngle - 90); if (!materials) { materials = new MeshBasicMaterial({ color: 0xffffff * Math.random(), side: DoubleSide, transparent: true, opacity: 1, depthTest: true, depthWrite: true }); } let geometry = new DoughnutGeometry(outterRadius, height, innerRadius, radialSegments, (PI2 - _startAngle) % PI2, -(_endAngle - _startAngle)); let mesh = new Mesh(geometry, materials); return mesh; } } export { primitive };