299 lines
9.0 KiB
JavaScript
299 lines
9.0 KiB
JavaScript
|
|
import * as echarts from 'echarts/lib/echarts';
|
||
|
|
import graphicGL from '../../util/graphicGL';
|
||
|
|
import retrieve from '../../util/retrieve';
|
||
|
|
import format from '../../util/format';
|
||
|
|
import BarsGeometry from '../../util/geometry/Bars3DGeometry';
|
||
|
|
import LabelsBuilder from '../../component/common/LabelsBuilder';
|
||
|
|
import glmatrix from 'claygl/src/dep/glmatrix';
|
||
|
|
import { getItemVisualColor, getItemVisualOpacity } from '../../util/visual';
|
||
|
|
var vec3 = glmatrix.vec3;
|
||
|
|
export default echarts.ChartView.extend({
|
||
|
|
type: 'bar3D',
|
||
|
|
__ecgl__: true,
|
||
|
|
init: function (ecModel, api) {
|
||
|
|
this.groupGL = new graphicGL.Node();
|
||
|
|
this._api = api;
|
||
|
|
this._labelsBuilder = new LabelsBuilder(256, 256, api);
|
||
|
|
var self = this;
|
||
|
|
|
||
|
|
this._labelsBuilder.getLabelPosition = function (dataIndex, position, distance) {
|
||
|
|
if (self._data) {
|
||
|
|
var layout = self._data.getItemLayout(dataIndex);
|
||
|
|
|
||
|
|
var start = layout[0];
|
||
|
|
var dir = layout[1];
|
||
|
|
var height = layout[2][1];
|
||
|
|
return vec3.scaleAndAdd([], start, dir, distance + height);
|
||
|
|
} else {
|
||
|
|
return [0, 0];
|
||
|
|
}
|
||
|
|
}; // Give a large render order.
|
||
|
|
|
||
|
|
|
||
|
|
this._labelsBuilder.getMesh().renderOrder = 100;
|
||
|
|
},
|
||
|
|
render: function (seriesModel, ecModel, api) {
|
||
|
|
// Swap barMesh
|
||
|
|
var tmp = this._prevBarMesh;
|
||
|
|
this._prevBarMesh = this._barMesh;
|
||
|
|
this._barMesh = tmp;
|
||
|
|
|
||
|
|
if (!this._barMesh) {
|
||
|
|
this._barMesh = new graphicGL.Mesh({
|
||
|
|
geometry: new BarsGeometry(),
|
||
|
|
shadowDepthMaterial: new graphicGL.Material({
|
||
|
|
shader: new graphicGL.Shader(graphicGL.Shader.source('ecgl.sm.depth.vertex'), graphicGL.Shader.source('ecgl.sm.depth.fragment'))
|
||
|
|
}),
|
||
|
|
// Only cartesian3D enable culling
|
||
|
|
// FIXME Performance
|
||
|
|
culling: seriesModel.coordinateSystem.type === 'cartesian3D',
|
||
|
|
// Render after axes
|
||
|
|
renderOrder: 10,
|
||
|
|
// Render normal in normal pass
|
||
|
|
renderNormal: true
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
this.groupGL.remove(this._prevBarMesh);
|
||
|
|
this.groupGL.add(this._barMesh);
|
||
|
|
this.groupGL.add(this._labelsBuilder.getMesh());
|
||
|
|
var coordSys = seriesModel.coordinateSystem;
|
||
|
|
|
||
|
|
this._doRender(seriesModel, api);
|
||
|
|
|
||
|
|
if (coordSys && coordSys.viewGL) {
|
||
|
|
coordSys.viewGL.add(this.groupGL);
|
||
|
|
var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
|
||
|
|
|
||
|
|
this._barMesh.material[methodName]('fragment', 'SRGB_DECODE');
|
||
|
|
}
|
||
|
|
|
||
|
|
this._data = seriesModel.getData();
|
||
|
|
|
||
|
|
this._labelsBuilder.updateData(this._data);
|
||
|
|
|
||
|
|
this._labelsBuilder.updateLabels();
|
||
|
|
|
||
|
|
this._updateAnimation(seriesModel);
|
||
|
|
},
|
||
|
|
_updateAnimation: function (seriesModel) {
|
||
|
|
graphicGL.updateVertexAnimation([['prevPosition', 'position'], ['prevNormal', 'normal']], this._prevBarMesh, this._barMesh, seriesModel);
|
||
|
|
},
|
||
|
|
_doRender: function (seriesModel, api) {
|
||
|
|
var data = seriesModel.getData();
|
||
|
|
var shading = seriesModel.get('shading');
|
||
|
|
var enableNormal = shading !== 'color';
|
||
|
|
var self = this;
|
||
|
|
var barMesh = this._barMesh;
|
||
|
|
var shadingPrefix = 'ecgl.' + shading;
|
||
|
|
|
||
|
|
if (!barMesh.material || barMesh.material.shader.name !== shadingPrefix) {
|
||
|
|
barMesh.material = graphicGL.createMaterial(shadingPrefix, ['VERTEX_COLOR']);
|
||
|
|
}
|
||
|
|
|
||
|
|
graphicGL.setMaterialFromModel(shading, barMesh.material, seriesModel, api);
|
||
|
|
barMesh.geometry.enableNormal = enableNormal;
|
||
|
|
barMesh.geometry.resetOffset(); // Bevel settings
|
||
|
|
|
||
|
|
var bevelSize = seriesModel.get('bevelSize');
|
||
|
|
var bevelSegments = seriesModel.get('bevelSmoothness');
|
||
|
|
barMesh.geometry.bevelSegments = bevelSegments;
|
||
|
|
barMesh.geometry.bevelSize = bevelSize;
|
||
|
|
var colorArr = [];
|
||
|
|
var vertexColors = new Float32Array(data.count() * 4);
|
||
|
|
var colorOffset = 0;
|
||
|
|
var barCount = 0;
|
||
|
|
var hasTransparent = false;
|
||
|
|
data.each(function (idx) {
|
||
|
|
if (!data.hasValue(idx)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var color = getItemVisualColor(data, idx);
|
||
|
|
var opacity = getItemVisualOpacity(data, idx);
|
||
|
|
|
||
|
|
if (opacity == null) {
|
||
|
|
opacity = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
graphicGL.parseColor(color, colorArr);
|
||
|
|
colorArr[3] *= opacity;
|
||
|
|
vertexColors[colorOffset++] = colorArr[0];
|
||
|
|
vertexColors[colorOffset++] = colorArr[1];
|
||
|
|
vertexColors[colorOffset++] = colorArr[2];
|
||
|
|
vertexColors[colorOffset++] = colorArr[3];
|
||
|
|
|
||
|
|
if (colorArr[3] > 0) {
|
||
|
|
barCount++;
|
||
|
|
|
||
|
|
if (colorArr[3] < 0.99) {
|
||
|
|
hasTransparent = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
barMesh.geometry.setBarCount(barCount);
|
||
|
|
var orient = data.getLayout('orient'); // Map of dataIndex and barIndex.
|
||
|
|
|
||
|
|
var barIndexOfData = this._barIndexOfData = new Int32Array(data.count());
|
||
|
|
var barCount = 0;
|
||
|
|
data.each(function (idx) {
|
||
|
|
if (!data.hasValue(idx)) {
|
||
|
|
barIndexOfData[idx] = -1;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var layout = data.getItemLayout(idx);
|
||
|
|
var start = layout[0];
|
||
|
|
var dir = layout[1];
|
||
|
|
var size = layout[2];
|
||
|
|
var idx4 = idx * 4;
|
||
|
|
colorArr[0] = vertexColors[idx4++];
|
||
|
|
colorArr[1] = vertexColors[idx4++];
|
||
|
|
colorArr[2] = vertexColors[idx4++];
|
||
|
|
colorArr[3] = vertexColors[idx4++];
|
||
|
|
|
||
|
|
if (colorArr[3] > 0) {
|
||
|
|
self._barMesh.geometry.addBar(start, dir, orient, size, colorArr, idx);
|
||
|
|
|
||
|
|
barIndexOfData[idx] = barCount++;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
barMesh.geometry.dirty();
|
||
|
|
barMesh.geometry.updateBoundingBox();
|
||
|
|
var material = barMesh.material;
|
||
|
|
material.transparent = hasTransparent;
|
||
|
|
material.depthMask = !hasTransparent;
|
||
|
|
barMesh.geometry.sortTriangles = hasTransparent;
|
||
|
|
|
||
|
|
this._initHandler(seriesModel, api);
|
||
|
|
},
|
||
|
|
_initHandler: function (seriesModel, api) {
|
||
|
|
var data = seriesModel.getData();
|
||
|
|
var barMesh = this._barMesh;
|
||
|
|
var isCartesian3D = seriesModel.coordinateSystem.type === 'cartesian3D';
|
||
|
|
barMesh.seriesIndex = seriesModel.seriesIndex;
|
||
|
|
var lastDataIndex = -1;
|
||
|
|
barMesh.off('mousemove');
|
||
|
|
barMesh.off('mouseout');
|
||
|
|
barMesh.on('mousemove', function (e) {
|
||
|
|
var dataIndex = barMesh.geometry.getDataIndexOfVertex(e.triangle[0]);
|
||
|
|
|
||
|
|
if (dataIndex !== lastDataIndex) {
|
||
|
|
this._downplay(lastDataIndex);
|
||
|
|
|
||
|
|
this._highlight(dataIndex);
|
||
|
|
|
||
|
|
this._labelsBuilder.updateLabels([dataIndex]);
|
||
|
|
|
||
|
|
if (isCartesian3D) {
|
||
|
|
api.dispatchAction({
|
||
|
|
type: 'grid3DShowAxisPointer',
|
||
|
|
value: [data.get('x', dataIndex), data.get('y', dataIndex), data.get('z', dataIndex, true)]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
lastDataIndex = dataIndex;
|
||
|
|
barMesh.dataIndex = dataIndex;
|
||
|
|
}, this);
|
||
|
|
barMesh.on('mouseout', function (e) {
|
||
|
|
this._downplay(lastDataIndex);
|
||
|
|
|
||
|
|
this._labelsBuilder.updateLabels();
|
||
|
|
|
||
|
|
lastDataIndex = -1;
|
||
|
|
barMesh.dataIndex = -1;
|
||
|
|
|
||
|
|
if (isCartesian3D) {
|
||
|
|
api.dispatchAction({
|
||
|
|
type: 'grid3DHideAxisPointer'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}, this);
|
||
|
|
},
|
||
|
|
_highlight: function (dataIndex) {
|
||
|
|
var data = this._data;
|
||
|
|
|
||
|
|
if (!data) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var barIndex = this._barIndexOfData[dataIndex];
|
||
|
|
|
||
|
|
if (barIndex < 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var itemModel = data.getItemModel(dataIndex);
|
||
|
|
var emphasisItemStyleModel = itemModel.getModel('emphasis.itemStyle');
|
||
|
|
var emphasisColor = emphasisItemStyleModel.get('color');
|
||
|
|
var emphasisOpacity = emphasisItemStyleModel.get('opacity');
|
||
|
|
|
||
|
|
if (emphasisColor == null) {
|
||
|
|
var color = getItemVisualColor(data, dataIndex);
|
||
|
|
emphasisColor = echarts.color.lift(color, -0.4);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (emphasisOpacity == null) {
|
||
|
|
emphasisOpacity = getItemVisualOpacity(data, dataIndex);
|
||
|
|
}
|
||
|
|
|
||
|
|
var colorArr = graphicGL.parseColor(emphasisColor);
|
||
|
|
colorArr[3] *= emphasisOpacity;
|
||
|
|
|
||
|
|
this._barMesh.geometry.setColor(barIndex, colorArr);
|
||
|
|
|
||
|
|
this._api.getZr().refresh();
|
||
|
|
},
|
||
|
|
_downplay: function (dataIndex) {
|
||
|
|
var data = this._data;
|
||
|
|
|
||
|
|
if (!data) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var barIndex = this._barIndexOfData[dataIndex];
|
||
|
|
|
||
|
|
if (barIndex < 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var color = getItemVisualColor(data, dataIndex);
|
||
|
|
var opacity = getItemVisualOpacity(data, dataIndex);
|
||
|
|
var colorArr = graphicGL.parseColor(color);
|
||
|
|
colorArr[3] *= opacity;
|
||
|
|
|
||
|
|
this._barMesh.geometry.setColor(barIndex, colorArr);
|
||
|
|
|
||
|
|
this._api.getZr().refresh();
|
||
|
|
},
|
||
|
|
highlight: function (seriesModel, ecModel, api, payload) {
|
||
|
|
this._toggleStatus('highlight', seriesModel, ecModel, api, payload);
|
||
|
|
},
|
||
|
|
downplay: function (seriesModel, ecModel, api, payload) {
|
||
|
|
this._toggleStatus('downplay', seriesModel, ecModel, api, payload);
|
||
|
|
},
|
||
|
|
_toggleStatus: function (status, seriesModel, ecModel, api, payload) {
|
||
|
|
var data = seriesModel.getData();
|
||
|
|
var dataIndex = retrieve.queryDataIndex(data, payload);
|
||
|
|
var self = this;
|
||
|
|
|
||
|
|
if (dataIndex != null) {
|
||
|
|
echarts.util.each(format.normalizeToArray(dataIndex), function (dataIdx) {
|
||
|
|
status === 'highlight' ? this._highlight(dataIdx) : this._downplay(dataIdx);
|
||
|
|
}, this);
|
||
|
|
} else {
|
||
|
|
data.each(function (dataIdx) {
|
||
|
|
status === 'highlight' ? self._highlight(dataIdx) : self._downplay(dataIdx);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
},
|
||
|
|
remove: function () {
|
||
|
|
this.groupGL.removeAll();
|
||
|
|
},
|
||
|
|
dispose: function () {
|
||
|
|
this._labelsBuilder.dispose();
|
||
|
|
|
||
|
|
this.groupGL.removeAll();
|
||
|
|
}
|
||
|
|
});
|