WebGL pie chart - Different results at different Chrome versions

706 views Asked by At

I am trying to develop a pie chart using WebGL. However, I am getting some issues on different Chrome versions. On version 40.0.2214.111, the pie chart looks exactly as I expected with five different parts.

But when I pass to version 43.0.2357.130 the colors on my second and fourth quadrant aren't the same, with the black and brown colors being changed by blue. You can get an example here to test it.

Any ideas why this is happening?

Vertex Shader

attribute vec2 aVertexPosition; 
    varying vec2 vTexCoord; 
    void main(){
        vTexCoord = aVertexPosition;
        gl_Position = vec4(aVertexPosition, 0, 1);
    }

Fragment Shader

precision mediump float;
    varying vec2 vTexCoord; 
    uniform int unumberOfParts;
    void main(){

        vec4 angles = vec4(100.0, 110.0, 70.0, 30.0);
        float prevAngle = radians(0.0);
        float radQuad = radians(90.0);
        float totalAngles = 0.0;

        bool found = false;
        bool hasRest = false;
        float rad = 0.0;
        float AngleToUse = 0.0;
        float rest;

        if (vTexCoord.y < 0.0 && vTexCoord.x < 0.0){ //Checks the coordinates of each quadrant
            for (int i = 0; i<4;i++){
                totalAngles = totalAngles + angles[i];
                if (totalAngles > 90.0){
                    rest = totalAngles - 90.0;
                    AngleToUse = angles[i] - rest;
                    hasRest = true;
                }
                else{
                    AngleToUse = angles[i];
                }
                rad = radians(AngleToUse);
                if ((tan(rad + prevAngle) >= (vTexCoord.y) / (vTexCoord.x)) && (tan(prevAngle) <= (vTexCoord.y) / (vTexCoord.x))){
                    float color = float(i) * 0.3;
                    if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){

                                    gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
                                    found = true;

                    }   
                }
                prevAngle = prevAngle + rad;
                if (totalAngles > 90.0){
                    break;
                }
            }

        }

        if (vTexCoord.y < 0.0 && vTexCoord.x > 0.0){
            for (int i = 0; i<4;i++){
                totalAngles = totalAngles + angles[i];
                if (totalAngles >= 90.0){
                    if (totalAngles - angles[i] < 90.0){
                        AngleToUse = totalAngles - 90.0;
                    }
                    else if (totalAngles > 180.0){
                        rest = totalAngles - 180.0;
                        AngleToUse = angles[i] - rest;
                        hasRest = true;
                    }
                    else{
                        AngleToUse = angles[i];
                    }

                    rad = radians(AngleToUse);
                     if ((tan(radQuad - (rad + prevAngle)) <= (vTexCoord.y) / -(vTexCoord.x)) && (tan(radQuad - (prevAngle)) >= (vTexCoord.y) / -(vTexCoord.x))){
                        float color = float(i) * 0.3;
                        if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
                            //gl_FragColor = vec4(1, 0, 0, 1);

                                        gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
                                        found = true;

                        }   
                     }
                     prevAngle = prevAngle + rad;
                     if (totalAngles > 180.0){
                        break;
                     }

                } 
            }
        }

         else if (vTexCoord.y > 0.0 && vTexCoord.x > 0.0){
            for (int i = 0; i<4;i++){
                totalAngles = totalAngles + angles[i];
                if (totalAngles >= 180.0){
                    if (totalAngles - angles[i] < 180.0){
                        AngleToUse = totalAngles - 180.0;
                    }
                    else if (totalAngles > 270.0){
                        rest = totalAngles - 270.0;
                        AngleToUse = angles[i] - rest;
                        hasRest = true;
                    }
                    else{
                        AngleToUse = angles[i];
                    }

                    rad = radians(AngleToUse);
                    if ((tan(rad + prevAngle) >= (vTexCoord.y) / (vTexCoord.x)) && (tan(prevAngle) <= (vTexCoord.y) / (vTexCoord.x))){
                        float color = float(i) * 0.3;
                        if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
                            //gl_FragColor = vec4(1, 0, 0, 1);

                                        gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
                                        found = true;

                        }   
                    }
                     prevAngle = prevAngle + rad;
                     if (totalAngles > 270.0){
                        break;
                     }

                } 
            }
          }

          else if (vTexCoord.y > 0.0 && vTexCoord.x < 0.0){
            for (int i = 0; i<4;i++){
                totalAngles = totalAngles + angles[i];
                if (totalAngles >= 270.0){
                    if (totalAngles - angles[i] < 270.0){
                        AngleToUse = totalAngles - 270.0;
                    }
                    else{
                        AngleToUse = angles[i];
                    }

                    rad = radians(AngleToUse);
                     if ((tan((rad + prevAngle)) >= -(vTexCoord.x) / (vTexCoord.y)) && (tan((prevAngle)) <= -(vTexCoord.x) / (vTexCoord.y))){
                        float color = float(i) * 0.3;
                        if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
                            //gl_FragColor = vec4(1, 0, 0, 1);

                                        gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
                                        found = true;

                        }   
                     }
                     prevAngle = prevAngle + rad;
                     if (totalAngles > 360.0){
                        break;
                     }

                } 
            }
          }



    if (found == false){
        if ((vTexCoord.x) * (vTexCoord.x) + (vTexCoord.y) * (vTexCoord.y) < 1.0){
            gl_FragColor = vec4(0, 0, 1, 1);
        }
        else{
            gl_FragColor = vec4(1, 1, 1, 0);
        }
    }

    }

WebGL

var c = document.getElementById('c');
var gl = c.getContext('experimental-webgl');

var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer); 
var vertices = [-1, -1 , 1, -1, -1, 1 , 1, 1] 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 

vertexPosBuffer.itemSize = 2; 
vertexPosBuffer.numItems = 4;
vertexPosBuffer.numberOfParts = 2;

vs = document.getElementById('vshader').textContent;
fs = document.getElementById('fshader').textContent;

var program = createProgram(vs,fs);
gl.useProgram(program);
program.vertexPosAttrib = gl.getAttribLocation(program,'aVertexPosition');
program.numberOfParts = gl.getUniformLocation(program,'anumberOfParts');
gl.enableVertexAttribArray(program.vertexPosArray);
gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize , gl.FLOAT, false , 0, 0); 
gl.uniform1i(program.numberOfParts, vertexPosBuffer.numberOfParts);

gl.finish();
gl.drawArrays(gl.TRIANGLE_STRIP, 0 , vertexPosBuffer.numItems); 
1

There are 1 answers

0
WacławJasper On

Have you considered using something like a spritesheet to solve this problem? First create like 100 different pie charts with different levels of fullness on 2D canvas. Then upload the entire sprite sheet to the GPU. On rendering, just render the sprite (a portion of the spritesheet) with desired level of fullness.

The setup would be something like this:

1) generate all the sprites on the 2D canvas

2) upload canvas to GPU with texImage2D

3) for each sprite, pre-calculate the uv values on the texture.

4) at render time, determine the correct uv values to use, then just render with a standard texture with uv fragment shader.

5) enjoy!