chartx3d
Version:
Data Visualization Chart Library
263 lines (222 loc) • 8.57 kB
JavaScript
import { global } from 'mmvis';
import { GraphObject, _ } from '../graph';
import { Vector3, MeshBasicMaterial, MeshLambertMaterial, FrontSide, DoubleSide, MeshPhongMaterial, Color, Box3 } from 'mmgl/src/index';
//let renderOrder = 100;
class Bar extends GraphObject {
constructor(chart3d, opt) {
super(chart3d);
this.name = 'Bar';
this.type = "bar";
this._type = "bar3d";
this.node = {
shapeType: 'cube', //'cube'立方体 'cylinder'圆柱体 ,'cone'圆锥体
materialType: 'phong', //'lambert' 'phong' 'base' 作色方式
// width: 0,
// _width: 0,
// maxWidth: 50,
// minWidth: 1,
// minHeight: 0,
// radius: 3,
fillStyle: null,
// fillAlpha: 0.95,
// _count: 0, //总共有多少个bar
// xDis: null,
// filter: null
};
this.label = {
enabled: false,
animation: true,
fontColor: null, //如果有设置text.fontColor那么优先使用fontColor
fontSize: 12,
format: null,
lineWidth: 0,
strokeStyle: null,
rotation: 0,
align: "center", //left center right
verticalAlign: "bottom", //top middle bottom
position: "top", //top,topRight,right,rightBottom,bottom,bottomLeft,left,leftTop,center
offsetX: 0,
offsetY: 0
};
//this.sort = null; //TODO:这个设置有问题,暂时所有sort相关的逻辑都注释掉
// this._barsLen = 0;
//this.txtsSp = null;
this.proportion = false;//比例柱状图,比例图首先肯定是个堆叠图
this.allGroupNum = 1;
_.extend(true, this, opt);
// this.materialMap = new Map();
this.init();
}
init() {
this.barsGroup = this._root.app.addGroup({ name: 'bars_gruop' });
}
dataProcess() {
super.dataProcess();
let ceil = this._coordSystem.getCeilSize();
let boxDepth = ceil.z * 0.7;
for (let field in this.drawData) {
let fieldObj = this.drawData[field];
fieldObj.forEach(item => {
item.ceil = ceil;
item.boxWidth = ceil.x / item.hLen * 0.7;
item.boxHeight = item.pos.y;
item.boxDepth = boxDepth > item.boxWidth ? item.boxWidth : boxDepth;
})
}
}
getMaterial(dataOrg) {
let MaterilBar = null;
switch (this.node.materialType) {
case 'phong':
MaterilBar = MeshPhongMaterial;
break;
case 'lambert':
MaterilBar = MeshLambertMaterial
break;
case 'base':
MaterilBar = MeshBasicMaterial
break;
default:
MaterilBar = MeshPhongMaterial;
}
let _color = this._getColor(this.node.fillStyle, dataOrg);
let material = null;
//todo 鼠标移动高亮,需要为每个柱子设置单独的材质,后续考虑有没有其他办法减少材质
// if (!this.materialMap.has(_color)) {
material = new MaterilBar({
color: _color,
transparent: true,
opacity: 1,
depthTest: true,
depthWrite: true,
side: DoubleSide,
// polygonOffset: true,
// polygonOffsetFactor: 1,
// polygonOffsetUnits: 1.5
})
// this.materialMap.set(_color, material);
// } else {
// material = this.materialMap.get(_color);
// }
return material;
}
draw() {
let me = this;
let app = this._root.app;
this.dataProcess();
let scale = 0.9; //每个单元格柱子占用的百分比
for (let field in this.drawData) {
let fieldObj = this.drawData[field];
fieldObj.forEach(item => {
let span = item.ceil.x / (item.hLen * 2) * scale;
let step = item.groupIndex * 2 + 1;
item.fromPos.setX(item.fromPos.x + (span * step - item.ceil.x * 0.5 * scale) - item.boxWidth * 0.5);
if (this.node.shapeType == 'cylinder' || 'cone' == this.node.shapeType) {
item.fromPos.setZ(item.pos.z - item.boxWidth * 0.5);
} else {
item.fromPos.setZ(item.pos.z - item.boxDepth * 0.5);
}
let boxHeight = Math.max((item.boxHeight), 0.01);
let material = me.getMaterial(item);
let obj = null;
let boundbox = new Box3();
let fromPos = item.fromPos.clone();
if (this.node.shapeType == 'cone') {
obj = app.createCone(item.boxWidth, boxHeight, item.boxDepth, material);
boundbox.setFromObject(obj);
fromPos.x += boundbox.getCenter().x;
} else if (this.node.shapeType == 'cylinder') {
obj = app.createCylinder(item.boxWidth, boxHeight, item.boxDepth, material);
boundbox.setFromObject(obj);
fromPos.x += boundbox.getCenter().x;
} else {
obj = app.createBox(item.boxWidth, boxHeight, item.boxDepth, material);
}
obj.name = Bar._bar_prefix + this.node.shapeType + "_" + item.vInd + "_" + item.iNode
obj.userData.info = item;
obj.position.copy(fromPos);
this.group.add(obj);
})
};
this.bindEvent();
}
bindEvent() {
let me = this;
this.__mouseover = function (e) {
//上下文中的this 是bar 对象
this.userData.color = this.material.color.clone();
//高亮
let tempColor = {};
this.material.color.getHSL(tempColor);
this.material.setValues({ color: new Color().setHSL(tempColor.h, tempColor.s, tempColor.l + 0.1) });
me._root.fire({
type: 'tipShow',
event: e.event,
data: this.userData.info
});
me.fire({ type: 'barover', data: this.userData.info });
};
this.__mouseout = function (e) {
this.material.setValues({ color: this.userData.color });
me._root.fire({
type: 'tipHide',
event: e.event,
data: this.userData.info
});
me.fire({ type: 'barout', data: this.userData.info });
};
this.__mousemove = function (e) {
me._root.fire({
type: 'tipMove',
event: e.event,
data: this.userData.info
});
me.fire({ type: 'barmove', data: this.userData.info });
}
this.__click = function (e) {
me.fire({ type: 'barclick', data: this.userData.info });
}
this.group.traverse(obj => {
if (obj.name && obj.name.includes(Bar._bar_prefix)) {
obj.on('mouseover', this.__mouseover);
obj.on('mouseout', this.__mouseout);
obj.on('mousemove', this.__mousemove);
obj.on('click', this.__click);
}
});
}
_getColor(c, dataOrg) {
let field = dataOrg.field.split(',');
var color = this._coordSystem.getColor(field);
//field对应的索引,, 取颜色这里不要用i
if (_.isString(c)) {
color = c
};
if (_.isArray(c)) {
color = _.flatten(c)[_.indexOf(_flattenField, field)];
};
if (_.isFunction(c)) {
color = c.apply(this, [rectData]);
};
return color;
}
dispose() {
//this.materialMap.clear();
this.group.traverse((obj) => {
if (obj.name && obj.name.includes(Bar._bar_prefix)) {
obj.off('click', this.__click);
obj.off('mouseover', this.__mouseover);
obj.off('mouseout', this.__mouseout);
obj.off('mousemove', this.__mousemove);
}
})
super.dispose();
}
resetData() {
this.dispose();
this.draw();
}
}
Bar._bar_prefix = "bar_one_";
global.registerComponent(Bar, 'graphs', 'bar', 3);
export default Bar;