chartx3d
Version:
Data Visualization Chart Library
422 lines (328 loc) • 12.6 kB
JavaScript
import { Events, Vector3, Box3, Matrix4, Vector2, Math as _Math, AmbientLight, DirectionalLight, PointLight, } from "mmgl/src/index";
import { _ } from 'mmvis';
//默认坐标系的中心点与坐标系的原点都为世界坐标的[0,0,0]点
//惯性坐标系
class InertialSystem extends Events {
constructor(root) {
super();
this._root = root;
this.coord = {};
//坐标原点
this.origin = new Vector3(0, 0, 0);
//中心的
this.center = new Vector3(0, 0, 0);
this.boundbox = new Box3();
this.size = new Vector3();
this.baseBoundbox = new Box3();
this.padding = {
left: 0,
top: 0,
right: 0,
bottom: 0,
front: 0,
back: 0
}
this.width = root.width;
this.height = root.height;
this.fieldMap = [];
this.group = root.app.addGroup({ name: 'InertialSystem' });
_.extend(true, this, this.setDefaultOpts(root.opt));
}
setDefaultOpts(opts) {
return opts;
}
init() {
}
addLights() {
//加入灯光
var ambientlight = new AmbientLight(0xffffff, 0.8); // soft white light
this._root.rootStage.add(ambientlight);
let center = this.center.clone();
center = this._getWorldPos(center);
//center.setY(0);
// let dirLights = [];
let intensity = 0.5;
let lightColor = 0xcccccc;
// let position = new Vector3(-1, -1, 1);
// dirLights[0] = new DirectionalLight(lightColor, intensity);
// position.multiplyScalar(10000);
// dirLights[0].position.copy(position);
// dirLights[0].target.position.copy(center);
// // this._root.rootStage.add(dirLights[0]);
// dirLights[1] = new DirectionalLight(lightColor, intensity);
// position = new Vector3(1, -1, 1);
// position.multiplyScalar(10000);
// dirLights[1].position.copy(position);
// dirLights[1].target.position.copy(center);
// this._root.rootStage.add(dirLights[1]);
// dirLights[2] = new DirectionalLight(lightColor, intensity);
// position = new Vector3(-1, -1, -1);
// position.multiplyScalar(10000);
// dirLights[2].position.copy(position);
// dirLights[2].target.position.copy(center);
// this._root.rootStage.add(dirLights[2]);
// dirLights[3] = new DirectionalLight(lightColor, intensity);
// position = new Vector3(1, -1, -1);
// position.multiplyScalar(10000);
// dirLights[3].position.copy(position);
// dirLights[3].target.position.copy(center);
// this._root.rootStage.add(dirLights[3]);
let pointLight = [];
pointLight[0] = new PointLight(lightColor, intensity);
let position = new Vector3(-1, 1, 1);
position.multiplyScalar(10000);
pointLight[0].position.copy(position);
this._root.rootStage.add(pointLight[0]);
pointLight[1] = new PointLight(lightColor, intensity);
position = new Vector3(1, 1, 1);
position.multiplyScalar(10000);
pointLight[1].position.copy(position);
this._root.rootStage.add(pointLight[1]);
pointLight[2] = new PointLight(lightColor, intensity);
position = new Vector3(-1, 1, -1);
position.multiplyScalar(10000);
pointLight[2].position.copy(position);
this._root.rootStage.add(pointLight[2]);
pointLight[3] = new PointLight(lightColor, intensity);
position = new Vector3(1, 1, -1);
position.multiplyScalar(1000);
pointLight[3].position.copy(position);
this._root.rootStage.add(pointLight[3]);
}
updatePosition(center) {
//更新相机姿态
center = center || this.center.clone();
center = this._getWorldPos(center);
let _renderView = this._root.renderView;
let _camera = _renderView._camera;
//相机默认的旋转角度
let dist = _camera.position.distanceTo(center);
let phi = _Math.degToRad(_renderView.controls.alpha); //(90-lat)*(Math.PI/180),
let theta = _Math.degToRad(_renderView.controls.beta); // (lng+180)*(Math.PI/180),
let y = dist * Math.sin(phi);
let temp = dist * Math.cos(phi);
let x = temp * Math.sin(theta);
let z = temp * Math.cos(theta);
//平移实现以中心点为圆心的旋转结果
let newPos = new Vector3(x, y, z);
newPos.add(center);
_camera.position.copy(newPos);
//相机朝向中心点
_camera.lookAt(center);
//orbite target position
this._root.orbitControls.target.copy(center);
}
getEnabledFields(fields) {
if (fields) {
//如果有传参数 fields 进来,那么就把这个指定的 fields 过滤掉 enabled==false的field
//只留下enabled的field 结构
return this.filterEnabledFields(fields);
};
// var fmap = {
// left: [], right:[]
// };
// _.each( this.fieldsMap, function( bamboo, b ){
// if( _.isArray( bamboo ) ){
// //多节竹子,堆叠
// var align;
// var fields = [];
// //设置完fields后,返回这个group属于left还是right的axis
// _.each( bamboo, function( obj, v ){
// if( obj.field && obj.enabled ){
// align = obj.yAxis.align;
// fields.push( obj.field );
// }
// } );
// fields.length && fmap[ align ].push( fields );
// } else {
// //单节棍
// if( bamboo.field && bamboo.enabled ){
// fmap[ bamboo.yAxis.align ].push( bamboo.field );
// }
// };
// } );
// return fmap;
}
filterEnabledFields(fields) {
var me = this;
var arr = [];
if (!_.isArray(fields)) fields = [fields];
_.each(fields, function (f) {
if (!_.isArray(f)) {
if (me.getFieldMap(f).enabled) {
arr.push(f);
}
} else {
//如果这个是个纵向数据,说明就是堆叠配置
var varr = [];
_.each(f, function (v_f) {
if (me.getFieldMap(v_f).enabled) {
varr.push(v_f);
}
});
if (varr.length) {
arr.push(varr)
}
}
});
return arr;
}
getFieldMap(field) {
let searchOpt = null;
let fieldMap = null;
let get = (maps) => {
if (maps) {
let zField = this.isExistZAxisField && this.isExistZAxisField();
if (zField) {
searchOpt = {
key: zField,
value: field
};
} else {
searchOpt = {
key: 'field',
value: field
}
}
_.each(maps, function (map, i) {
if (_.isArray(map)) {
get(map)
} else if (map[searchOpt.key] == searchOpt.value) {
fieldMap = map;
return false;
}
});
}
}
get(this.fieldsMap);
return fieldMap;
}
getColor(field) {
return this.getFieldMap(field) && this.getFieldMap(field).color;
}
getLegendData() {
var me = this;
var data = [];
_.each(_.flatten(me.fieldsMap), function (map, i) {
//因为yAxis上面是可以单独自己配置field的,所以,这部分要过滤出 legend data
var isGraphsField = false;
_.each(me.graphs, function (gopt) {
if (_.indexOf(_.flatten([gopt.field]), map.field) > -1) {
isGraphsField = true;
return false;
}
});
if (isGraphsField) {
data.push({
enabled: map.enabled,
name: map.field,
field: map.field,
ind: map.ind,
color: map.color,
yAxis: map.yAxis
});
}
});
return data;
}
getBoundbox() {
let _boundbox = new Box3();
let _opt = this._root.opt.coord.controls;
//let _frustumSize = this._root.renderView.mode == 'ortho' ? _opt.boxHeight * 0.8 : _opt.boxHeight;
let _height = _opt.boxHeight;
let _width = _opt.boxWidth;
let _depth = _opt.boxDepth;
//斜边
let _hypotenuse = _opt.distance || (new Vector3(_width, 0, _depth)).length();
let _ratio = this._root.renderView.getVisableSize(new Vector3(0, 0, -_hypotenuse)).ratio;
let minX = - _width * 0.5 + this.padding.left * _ratio;
// let minY = - _frustumSize * 0.5 + this.padding.bottom * _ratio;
let minY = - _height * 0.5 + this.padding.bottom * _ratio;
let minZ = this.padding.front - _hypotenuse * 0.5 - _depth;
let maxX = _width * 0.5 - this.padding.right * _ratio;
//let maxY = _frustumSize * 0.5 - this.padding.top * _ratio;
let maxY = _height * 0.5 - this.padding.top * _ratio;
let maxZ = - _hypotenuse * 0.5 + this.padding.back;
_boundbox.min.set(minX, minY, minZ);
_boundbox.max.set(maxX, maxY, maxZ);
this.baseBoundbox = _boundbox
return _boundbox;
}
_getWorldPos(pos) {
let posWorld = pos.clone();
this.group.updateMatrixWorld();
posWorld.applyMatrix4(this.group.matrixWorld);
return posWorld;
}
getSize() {
if (this.boundbox.isEmpty()) {
this.boundbox = this.getBoundbox();
}
this.size = this.boundbox.getSize();
return this.size;
}
dataToPoint(data, dir) {
}
pointToData() {
}
initCoordUI() {
//什么都不做
return null;
}
drawUI() {
// this._root.initComponent();
}
dispose() {
}
resetData() {
}
getAxisDataFrame(fields) {
let dataFrame = this._root.dataFrame;
return dataFrame.getDataOrg(fields, function (val) {
if (val === undefined || val === null || val == "") {
return val;
}
return (isNaN(Number(val)) ? val : Number(val))
})
}
positionToScreen(pos) {
return positionToScreen.call(this, pos);
}
screenToWorld(dx, dy) {
return screenToWorld.call(this, dx, dy);
}
}
let positionToScreen = (function () {
let matrix = new Matrix4();
return function (pos) {
let pCam = this._root.renderView._camera;
const widthHalf = 0.5 * this._root.width;
const heightHalf = 0.5 * this._root.height;
let target = this.group.localToWorld(pos);
target.project(pCam, matrix);
target.x = (target.x * widthHalf) + widthHalf;
target.y = (- (target.y * heightHalf) + heightHalf);
return target;
}
})();
let screenToWorld = (function () {
let matrix = new Matrix4();
//可能有问题,未测试
return function (dx, dy) {
let pCam = this._root.renderView.getCamera();
const widthHalf = this._root.width * 0.5;
const heightHalf = this._root.height * 0.5;
let mouse = new Vector2();
mouse.x = dx / widthHalf - 1;
mouse.y = -dy / heightHalf + 1;
//新建一个三维单位向量 假设z方向就是0.5
//根据照相机,把这个向量转换到视点坐标系
var target = new Vector3(mouse.x, mouse.y, 0.5).unproject(pCam, matrix);
// let target = this.group.localToWorld(pos);
// target.project(pCam, matrix);
// target.x = (target.x * widthHalf) + widthHalf;
// target.y = (- (target.y * heightHalf) + heightHalf);
return target;
}
})();
export { InertialSystem };