@bokeh/bokehjs
Version:
Interactive, novel data visualization
177 lines (176 loc) • 18.2 kB
JavaScript
const shader = `
precision mediump float;const float SQRT2=sqrt(2.);const float SQRT3=sqrt(3.);const float PI=3.14159265358979323846;const int butt_cap=0;const int round_cap=1;const int square_cap=2;const int miter_join=0;const int round_join=1;const int bevel_join=2;
const int hatch_dot=1;const int hatch_ring=2;const int hatch_horizontal_line=3;const int hatch_vertical_line=4;const int hatch_cross=5;const int hatch_horizontal_dash=6;const int hatch_vertical_dash=7;const int hatch_spiral=8;const int hatch_right_diagonal_line=9;const int hatch_left_diagonal_line=10;const int hatch_diagonal_cross=11;const int hatch_right_diagonal_dash=12;const int hatch_left_diagonal_dash=13;const int hatch_horizontal_wave=14;const int hatch_vertical_wave=15;const int hatch_criss_cross=16;
uniform float u_antialias;varying vec2 v_coords;varying vec2 v_size;
varying float v_outer_radius;varying float v_inner_radius;varying float v_start_angle;varying float v_end_angle;
varying float v_outer_radius;varying float v_inner_radius;
varying float v_radius;varying float v_start_angle;varying float v_end_angle;
varying float v_radius;
varying float v_n;
varying vec4 v_border_radius;
varying float v_linewidth;varying vec4 v_line_color;varying vec4 v_fill_color;varying float v_line_cap;varying float v_line_join;
varying float v_hatch_pattern;varying float v_hatch_scale;varying float v_hatch_weight;varying vec4 v_hatch_color;varying vec2 v_hatch_coords;
float end_cap_distance(in vec2 p,in vec2 end_point,in vec2 unit_direction,in int line_cap){vec2 offset=p-end_point;if(line_cap==butt_cap)return dot(offset,unit_direction)+0.5*v_linewidth;else if(line_cap==square_cap)return dot(offset,unit_direction);else if(line_cap==round_cap&&dot(offset,unit_direction)>0.)return length(offset);else return-v_linewidth-u_antialias;}
float line_join_distance_no_miter(in vec2 p,in vec2 corner,in vec2 unit_normal,in float offset,in int line_join){float dist_outside=dot((p-corner),unit_normal)-offset;if(line_join==bevel_join&&dist_outside>-0.5*u_antialias)return dist_outside+0.5*v_linewidth;else if(dist_outside>0.)return distance(p,corner);else return-v_linewidth-u_antialias;}
float line_join_distance_incl_miter(in vec2 p,in vec2 corner,in vec2 unit_normal,in float offset,in int line_join,vec2 miter_unit_normal){float dist_outside=dot((p-corner),unit_normal)-offset;if(line_join==miter_join&&dist_outside>0.)return dot((p-corner),miter_unit_normal);else if(line_join==bevel_join&&dist_outside>-0.5*u_antialias)return dist_outside+0.5*v_linewidth;else if(dist_outside>0.)return distance(p,corner);else return-v_linewidth-u_antialias;}
float one_cross(in vec2 p,in int line_cap,in float len){p=abs(p);p=(p.y>p.x)?p.yx:p.xy;float dist=p.y;float end_dist=end_cap_distance(p,vec2(len,0.),vec2(1.,0.),line_cap);return max(dist,end_dist);}
float one_cross_2(in vec2 p,in int line_cap,in vec2 lengths){p=abs(p);bool switch_xy=(p.y>p.x);p=switch_xy?p.yx:p.xy;float len=switch_xy?lengths.y:lengths.x;float dist=p.y;float end_dist=end_cap_distance(p,vec2(len,0.),vec2(1.,0.),line_cap);return max(dist,end_dist);}
float one_y(in vec2 p,in int line_cap,in float len){p=vec2(abs(p.x),-p.y);const float k=6./sqrt(13.);vec2 unit_along=vec2(0.5*k,k/3.);vec2 end_point=vec2(0.5*len*SQRT3,len*SQRT3/3.);float dist=max(abs(dot(p,vec2(-unit_along.y,unit_along.x))),end_cap_distance(p,end_point,unit_along,line_cap));if(p.y<0.){float vert_dist=max(p.x,end_cap_distance(p,vec2(0.,-len),vec2(0.,-1.),line_cap));dist=min(dist,vert_dist);}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){vec2 p_diag=vec2((p.x+p.y)/SQRT2,(p.x-p.y)/SQRT2);float len=0.5*v_size.x;return min(one_cross(p,line_cap,len),one_cross(p_diag,line_cap,len));}
float merge(in float d1,in float d2){return min(d1,d2);}float intersect(in float d1,in float d2){return max(d1,d2);}float subtract(in float d1,in float d2){return max(d1,-d2);}float circle(in vec2 p,in float radius){return length(p)-radius;}float segment_square(in vec2 p,in vec2 q){vec2 v=p-q*clamp(dot(p,q)/dot(q,q),0.,1.);return dot(v,v);}vec2 xy(in float angle){return vec2(cos(angle),sin(angle));}float cross_z(in vec2 v0,in vec2 v1){return v0.x*v1.y-v0.y*v1.x;}float wedge(in vec2 p,in float r,in float start_angle,in float end_angle){vec2 a=r*xy(start_angle);vec2 b=r*xy(end_angle);float d=sqrt(merge(segment_square(p,a),segment_square(p,b)));float s;if(cross_z(a,b)<0.){s=sign(max(cross_z(a,p),cross_z(p,b)));}else{s=-sign(max(cross_z(p,a),cross_z(b,p)));}return s*d;}float annulus(in vec2 p,in float outer_radius,in float inner_radius){float outer=circle(p,outer_radius);float inner=circle(p,inner_radius);return subtract(outer,inner);}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return annulus(p,v_outer_radius,v_inner_radius);}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return intersect(circle(p,v_radius),wedge(p,v_radius,v_start_angle,v_end_angle));}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return intersect(annulus(p,v_outer_radius,v_inner_radius),wedge(p,v_outer_radius,v_start_angle,v_end_angle));}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return length(p)-0.5*v_size.x;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return one_cross(p,line_cap,0.5*v_size.x);}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=abs(p);float dist=p.y;float end_dist=end_cap_distance(p,vec2(0.5*v_size.x,0.),vec2(1.,0.),line_cap);return max(dist,end_dist);}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=abs(p);float r=0.5*v_size.x;const float SQRT13=sqrt(13.);float dist=dot(p,vec2(3.,2.))/SQRT13-2.*r/SQRT13;if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,vec2(0.,r),vec2(0.,1.),v_linewidth/SQRT13,line_join));dist=max(dist,line_join_distance_no_miter(p,vec2(r*2./3.,0.),vec2(1.,0.),v_linewidth*(1.5/SQRT13),line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return v_linewidth+u_antialias;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=abs(p);float rx=v_size.x/2.;float h=v_size.y*(SQRT3/4.);float len_normal=sqrt(h*h+0.25*rx*rx);vec2 unit_normal=vec2(h,0.5*rx)/len_normal;float dist=max(dot(p,unit_normal)-rx*h/len_normal,p.y-h);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,vec2(rx,0.),vec2(1.,0.),0.5*v_linewidth*unit_normal.x,line_join));unit_normal=normalize(unit_normal+vec2(0.,1.));dist=max(dist,line_join_distance_no_miter(p,vec2(0.5*rx,h),unit_normal,0.5*v_linewidth*unit_normal.y,line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){float side_angle=2.*PI/v_n;p.y=-p.y;float angle=mod(atan(p.x,p.y),side_angle);angle=min(angle,side_angle-angle);p=length(p)*vec2(sin(angle),cos(angle));float half_angle=0.5*side_angle;float cos_half_angle=cos(half_angle);vec2 unit_normal=vec2(sin(half_angle),cos_half_angle);vec2 corner=vec2(0.,v_size.y/2.);float dist=dot(p-corner,unit_normal);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,corner,vec2(0.,1.),0.5*v_linewidth*cos_half_angle,line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=abs(p);p=(p.y>p.x)?p.yx:p.xy;float r=0.5*v_size.x;p=p-vec2(r,0.375*r);float dist=max(p.x,p.y);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,vec2(0.,0.),vec2(1./SQRT2,1./SQRT2),v_linewidth/(2.*SQRT2),line_join));dist=min(dist,-line_join_distance_no_miter(p,vec2(-5.*r/8.,0.),vec2(-1./SQRT2,-1./SQRT2),v_linewidth/(2.*SQRT2),line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){vec2 halfsize=v_size/2.;vec2 p2=abs(p)-halfsize;float dist=max(p2.x,p2.y);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p2,vec2(0.,0.),vec2(1./SQRT2,1./SQRT2),v_linewidth/(2.*SQRT2),line_join));}vec4 border_radius=v_border_radius;vec4 xsign=vec4(-1.,1.,1.,-1.);vec4 ysign=vec4(-1.,-1.,1.,1.);for(int i=0;i<4;i++){float radius=border_radius.x;p2=p*vec2(xsign.x,ysign.x);vec2 offset=p2-halfsize+radius;if(min(radius,min(offset.x,offset.y))>0.){dist=max(dist,length(offset)-radius);}border_radius.xyzw=border_radius.yzwx;xsign.xyzw=xsign.yzwx;ysign.xyzw=ysign.yzwx;}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){vec2 p2=abs(p)-v_size/2.;float dist=max(p2.x,p2.y);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p2,vec2(0.,0.),vec2(1./SQRT2,1./SQRT2),v_linewidth/(2.*SQRT2),line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=abs(p);p=(p.y>p.x)?p.yx:p.xy;float r=0.5*v_size.x;float center_x=r*2.44375;float radius=r*1.75626;float dist=radius-distance(p,vec2(center_x,0.));dist=max(dist,line_join_distance_incl_miter(p,vec2(r,r),vec2(1./SQRT2,1./SQRT2),v_linewidth*0.1124297533493792,line_join,vec2(8./sqrt(89.),-5./sqrt(89.))));return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){const float SQRT5=sqrt(5.);const float COS72=0.25*(SQRT5-1.);const float SIN72=sqrt((5.+SQRT5)/8.);float angle=atan(p.x,p.y);angle=mod(angle,0.4*PI)-0.2*PI;p=length(p)*vec2(cos(angle),abs(sin(angle)));float r=0.5*v_size.x;float a=r*sqrt(5.-2.*SQRT5);float dist=dot(p,vec2(COS72,SIN72))-r*COS72;if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,vec2(r,0.),vec2(1.,0.),v_linewidth*(0.5*COS72),line_join));const float COS36=sqrt(0.5+COS72/2.);const float SIN36=sqrt(0.5-COS72/2.);dist=min(dist,-line_join_distance_no_miter(p,vec2(r-a*SIN72,a*COS72),vec2(-COS36,-SIN36),v_linewidth*(0.5*COS36),line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){float r=0.5*v_size.x;float a=r*SQRT3/3.;
p=vec2(abs(p.x),-p.y);
p=vec2(abs(p.x),p.y);
float dist=max(0.5*dot(p,vec2(SQRT3,-1.))-a,p.y-a);if(line_join!=miter_join){dist=max(dist,line_join_distance_no_miter(p,vec2(0.,-(2./SQRT3)*r),vec2(0.,-1.),v_linewidth*0.25,line_join));dist=max(dist,line_join_distance_no_miter(p,vec2(r,a),vec2(SQRT3/2.,0.5),v_linewidth*0.25,line_join));}return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){float angle=atan(p.x,-p.y);angle=mod(angle,PI*2./3.)-PI/3.;p=length(p)*vec2(cos(angle),abs(sin(angle)));const float a=1./SQRT3;const float b=SQRT3/8.;const float c=(a-b)/2.;const float x=(1.-c*c)/(2.*c);const float center_x=x+a;const float radius=x+c;float r=0.5*v_size.x;float dist=r*radius-distance(p,vec2(r*center_x,0.));dist=max(dist,line_join_distance_incl_miter(p,vec2(a*r,r),vec2(0.5,0.5*SQRT3),v_linewidth*0.0881844526878324,line_join,vec2(8.*SQRT3,-5.)/sqrt(217.)));return dist;}
float marker_distance(in vec2 p,in int line_cap,in int line_join){p=vec2((p.x+p.y)/SQRT2,(p.x-p.y)/SQRT2);return one_cross(p,line_cap,0.5*v_size.x);}
float marker_distance(in vec2 p,in int line_cap,in int line_join){return one_y(p,line_cap,0.5*v_size.x);}
float distance_to_fraction(in float dist){return 1.-smoothstep(-0.5*u_antialias,0.5*u_antialias,dist);}float fill_fraction(in float dist){return distance_to_fraction(dist);}float line_fraction(in float dist){return distance_to_fraction(abs(dist)-0.5*v_linewidth);}vec4 fractional_color(in vec4 color,in float fraction){color.a*=fraction;color.rgb*=color.a;return color;}vec4 blend_colors(in vec4 src,in vec4 dest){return(1.-src.a)*dest+src;}
float dot_fraction(in vec2 p){float radius=0.125*v_size.x;float dot_distance=max(length(p)-radius,-0.5*u_antialias);return fill_fraction(dot_distance);}
float wrap(in float x){return fract(x)-0.5;}vec2 wrap(in vec2 xy){return fract(xy)-0.5;}float hatch_fraction(in vec2 coords,in int hatch_pattern){float scale=v_hatch_scale;coords=coords/scale;float halfwidth=0.5*v_hatch_weight/scale;float dist=u_antialias;if(hatch_pattern==hatch_dot){const float dot_radius=0.25;dist=length(wrap(coords))-dot_radius;}else if(hatch_pattern==hatch_ring){const float ring_radius=0.25;dist=abs(length(wrap(coords))-ring_radius)-halfwidth;}else if(hatch_pattern==hatch_horizontal_line){dist=abs(wrap(coords.y))-halfwidth;}else if(hatch_pattern==hatch_vertical_line){dist=abs(wrap(coords.x))-halfwidth;}else if(hatch_pattern==hatch_cross){dist=min(abs(wrap(coords.x)),abs(wrap(coords.y)))-halfwidth;}else if(hatch_pattern==hatch_horizontal_dash){const float halflength=0.25;dist=max(abs(wrap(coords.y)),abs(wrap(coords.x)+0.25)-halflength)-halfwidth;}else if(hatch_pattern==hatch_vertical_dash){const float halflength=0.25;dist=max(abs(wrap(coords.x)),abs(wrap(coords.y)+0.25)-halflength)-halfwidth;}else if(hatch_pattern==hatch_spiral){vec2 wrap2=wrap(coords);float angle=wrap(atan(wrap2.y,wrap2.x)/(2.*PI));const float dr=PI/15.;float radius=length(wrap2);float frac=fract((radius-dr*angle)/dr);dist=dr*(abs(frac-0.5));dist=min(dist,radius)-halfwidth;}else if(hatch_pattern==hatch_right_diagonal_line){dist=abs(wrap(2.*coords.x+coords.y))/sqrt(5.)-halfwidth;}else if(hatch_pattern==hatch_left_diagonal_line){dist=abs(wrap(2.*coords.x-coords.y))/sqrt(5.)-halfwidth;}else if(hatch_pattern==hatch_diagonal_cross){coords=vec2(coords.x+coords.y+0.5,coords.x-coords.y+0.5);dist=min(abs(wrap(coords.x)),abs(wrap(coords.y)))/SQRT2-halfwidth;}else if(hatch_pattern==hatch_right_diagonal_dash){float across=coords.x+coords.y+0.5;dist=abs(wrap(across))/SQRT2;across=floor(across);float along=wrap(0.5*(coords.x-coords.y+across));const float halflength=0.25;along=abs(along)-halflength;dist=max(dist,along)-halfwidth;}else if(hatch_pattern==hatch_left_diagonal_dash){float across=coords.x-coords.y+0.5;dist=abs(wrap(across))/SQRT2;across=floor(across);float along=wrap(0.5*(coords.x+coords.y+across));const float halflength=0.25;along=abs(along)-halflength;dist=max(dist,along)-halfwidth;}else if(hatch_pattern==hatch_horizontal_wave){float wrapx=wrap(coords.x);float wrapy=wrap(coords.y-0.25+abs(wrapx));dist=abs(wrapy)/SQRT2-halfwidth;}else if(hatch_pattern==hatch_vertical_wave){float wrapy=wrap(coords.y);float wrapx=wrap(coords.x-0.25+abs(wrapy));dist=abs(wrapx)/SQRT2-halfwidth;}else if(hatch_pattern==hatch_criss_cross){float plus=min(abs(wrap(coords.x)),abs(wrap(coords.y)));coords=vec2(coords.x+coords.y+0.5,coords.x-coords.y+0.5);float X=min(abs(wrap(coords.x)),abs(wrap(coords.y)))/SQRT2;dist=min(plus,X)-halfwidth;}return distance_to_fraction(dist*scale);}
void main(){int line_cap=int(v_line_cap+0.5);int line_join=int(v_line_join+0.5);
int hatch_pattern=int(v_hatch_pattern+0.5);
float dist=marker_distance(v_coords,line_cap,line_join);
vec4 color=vec4(0.,0.,0.,0.);
float fill_frac=fill_fraction(dist);vec4 color=fractional_color(v_fill_color,fill_frac);
if(hatch_pattern>0&&fill_frac>0.){float hatch_frac=hatch_fraction(v_hatch_coords,hatch_pattern);vec4 hatch_color=fractional_color(v_hatch_color,hatch_frac*fill_frac);color=blend_colors(hatch_color,color);}
float line_frac=line_fraction(dist);
line_frac=max(line_frac,dot_fraction(v_coords));
line_frac=max(line_frac,line_fraction(one_cross(v_coords,line_cap,0.5*v_size.x)));
vec2 lengths=vec2(v_size.x/3.,v_size.x/2.);line_frac=max(line_frac,line_fraction(one_cross_2(v_coords,line_cap,lengths)));
vec2 p=vec2((v_coords.x+v_coords.y)/SQRT2,(v_coords.x-v_coords.y)/SQRT2);line_frac=max(line_frac,line_fraction(one_cross(p,line_cap,APPEND_X_LEN)));
line_frac=max(line_frac,line_fraction(one_y(v_coords,line_cap,0.5*v_size.x)));
if(line_frac>0.){vec4 line_color=fractional_color(v_line_color,line_frac);color=blend_colors(line_color,color);}gl_FragColor=color;}`;
export default shader;