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);
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!