TrailMesh.js 3.9 KB
import * as echarts from 'echarts/lib/echarts';
import graphicGL from '../../util/graphicGL';

import TrailGeometry from './TrailGeometry';
import { getItemVisualColor, getItemVisualOpacity } from '../../util/visual';

import trailGLSL from './shader/trail.glsl.js';

graphicGL.Shader.import(trailGLSL);

export default graphicGL.Mesh.extend(function () {

    var material = new graphicGL.Material({
        shader: new graphicGL.Shader({
            vertex: graphicGL.Shader.source('ecgl.trail.vertex'),
            fragment: graphicGL.Shader.source('ecgl.trail.fragment')
        }),
        transparent: true,
        depthMask: false
    });

    // texture saving the keypoints.
    var pointsTexture = new graphicGL.Texture2D({
        type: graphicGL.Texture.FLOAT,
        minFilter: graphicGL.Texture.NEAREST,
        magFilter: graphicGL.Texture.NEAREST,
        width: 1024
    });

    return {
        geometry: new TrailGeometry({
            dynamic: true
        }),
        material: material,
        culling: false,
        $ignorePicking: true,

        _pointsTexture: pointsTexture
    };
}, {

    setData: function (data, api) {
        var seriesModel = data.hostModel;
        var geometry = this.geometry;

        var effectModel = seriesModel.getModel('effect');
        var size = effectModel.get('trailWidth') * api.getDevicePixelRatio();
        var trailLength = effectModel.get('trailLength');

        geometry.trailLength = trailLength;
        this.material.set('trailLength', trailLength);

        geometry.reset();

        var vertexCount = 0;
        var triangleCount = 0;
        data.each(function (idx) {
            var pts = data.getItemLayout(idx);
            vertexCount += geometry.getCurveVertexCount(pts[0], pts[1], pts[2], pts[3]);
            triangleCount += geometry.getCurveTriangleCount(pts[0], pts[1], pts[2], pts[3]);
        });
        geometry.setVertexCount(vertexCount);
        geometry.setTriangleCount(triangleCount);

        var colorArr = [];
        var textureWidth = this._pointsTexture.width;
        var textureHeight = Math.ceil(data.count() / (textureWidth / 4));
        var pointsTexture = this._pointsTexture;
        pointsTexture.height = textureHeight;

        if (!(pointsTexture.pixels && pointsTexture.pixels.length === textureWidth * textureHeight * 4)) {
            pointsTexture.pixels = new Float32Array(textureWidth * textureHeight * 4);
        }
        var pixels = pointsTexture.pixels;

        var effectColor = effectModel.get('trailColor');
        var effectOpacity = effectModel.get('trailOpacity');
        var hasEffectColor = effectColor != null;
        var hasEffectOpacity = effectOpacity != null;

        data.each(function (idx) {
            var pts = data.getItemLayout(idx);
            var opacity = hasEffectOpacity ? effectOpacity : getItemVisualOpacity(data, idx);
            var color = getItemVisualColor(data, idx);

            if (opacity == null) {
                opacity = 1;
            }
            colorArr = graphicGL.parseColor(hasEffectColor ? effectColor : color, colorArr);
            colorArr[3] *= opacity;

            var u = idx * 4 % textureWidth / (textureWidth - 1);
            var v = Math.floor(idx * 4 / textureWidth) / (textureHeight - 1) || 0;

            for (var k = 0; k < 4; k++) {
                pixels[(idx * 4 + k) * 4] = pts[k][0];
                pixels[(idx * 4 + k) * 4 + 1] = pts[k][1];
                pixels[(idx * 4 + k) * 4 + 2] = pts[k][2];
            }

            geometry.addCurveTrail(
                pts[0], pts[1], pts[2], pts[3], [u, v], size, colorArr
            );
        });

        this.material.set('pointsTexture', pointsTexture);

        pointsTexture.dirty();

        geometry.dirty();
    },

    setScale: function (scale) {
        this.geometry.scale = scale;
    },

    setAnimationPercent: function (percent) {
        this.material.set('percent', percent);
    }
});