@bokeh/bokehjs
Version:
Interactive, novel data visualization
21 lines (20 loc) • 5.44 kB
JavaScript
const shader = `
precision mediump float;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;uniform float u_antialias;
uniform sampler2D u_dash_tex;
varying float v_linewidth;varying vec4 v_line_color;varying float v_line_cap;varying float v_line_join;varying float v_segment_length;varying vec2 v_coords;varying float v_flags;varying float v_cos_turn_angle_start;varying float v_cos_turn_angle_end;
varying float v_length_so_far;varying vec4 v_dash_tex_info;varying float v_dash_scale;varying float v_dash_offset;
float cross_z(in vec2 v0,in vec2 v1){return v0.x*v1.y-v0.y*v1.x;}vec2 right_vector(in vec2 v){return vec2(v.y,-v.x);}float bevel_join_distance(in vec2 coords,in vec2 other_right,in float sign_turn_right){float hw=0.5*v_linewidth;if(other_right.y>=ONE_MINUS_SMALL){return abs(hw-v_coords.x);}else{const vec2 segment_right=vec2(0.,-1.);vec2 corner_right=normalize(other_right+segment_right);vec2 outside_point=(-hw*sign_turn_right)*segment_right;return hw+sign_turn_right*dot(outside_point-coords,corner_right);}}float cap(in int cap_type,in float x,in float y){if(cap_type==butt_cap)return max(0.5*v_linewidth-x,abs(y));else if(cap_type==square_cap)return max(-x,abs(y));else return distance(vec2(min(x,0.),y),vec2(0.,0.));}float distance_to_alpha(in float dist){return 1.-smoothstep(0.5*(v_linewidth-u_antialias),0.5*(v_linewidth+u_antialias),dist);}vec2 turn_angle_to_right_vector(in float cos_turn_angle,in float sign_turn_right){float sin_turn_angle=sign_turn_right*sqrt(1.-cos_turn_angle*cos_turn_angle);return vec2(sin_turn_angle,-cos_turn_angle);}
float dash_distance(in float x){float tex_length=v_dash_tex_info.x;float tex_offset=v_dash_tex_info.y;float tex_dist_min=v_dash_tex_info.z;float tex_dist_max=v_dash_tex_info.w;x+=v_length_so_far-v_dash_scale*tex_offset+v_dash_offset;float dist=texture2D(u_dash_tex,vec2(x/(tex_length*v_dash_scale),0.)).a;dist=tex_dist_min+dist*(tex_dist_max-tex_dist_min);return v_dash_scale*dist;}mat2 rotation_matrix(in vec2 other_right){float sin_angle=other_right.x;float cos_angle=-other_right.y;return mat2(cos_angle,-sin_angle,sin_angle,cos_angle);}
void main(){int join_type=int(v_line_join+0.5);int cap_type=int(v_line_cap+0.5);float halfwidth=0.5*(v_linewidth+u_antialias);float half_antialias=0.5*u_antialias;int flags=int(v_flags+0.5);bool turn_right_end=(flags/32>0);float sign_turn_right_end=turn_right_end?1.:-1.;flags-=32*int(turn_right_end);bool turn_right_start=(flags/16>0);float sign_turn_right_start=turn_right_start?1.:-1.;flags-=16*int(turn_right_start);bool miter_too_large_end=(flags/8>0);flags-=8*int(miter_too_large_end);bool miter_too_large_start=(flags/4>0);flags-=4*int(miter_too_large_start);bool has_end_cap=(flags/2>0);flags-=2*int(has_end_cap);bool has_start_cap=flags>0;vec2 prev_right=turn_angle_to_right_vector(v_cos_turn_angle_start,sign_turn_right_start);vec2 next_right=turn_angle_to_right_vector(v_cos_turn_angle_end,sign_turn_right_end);float dist=v_coords.y;vec2 end_coords=vec2(v_segment_length,0.)-v_coords;if(v_coords.x<=half_antialias){if(has_start_cap)dist=cap(cap_type,v_coords.x,v_coords.y);else if(join_type==round_join){if(v_coords.x<=0.)dist=distance(v_coords,vec2(0.,0.));}else{if(join_type==bevel_join||miter_too_large_start)dist=max(abs(dist),bevel_join_distance(v_coords,prev_right,sign_turn_right_start));float prev_sideways_dist=-sign_turn_right_start*dot(v_coords,prev_right);dist=max(abs(dist),prev_sideways_dist);}}if(end_coords.x<=half_antialias){if(has_end_cap){dist=max(abs(dist),cap(cap_type,end_coords.x,v_coords.y));}else if(join_type==bevel_join||miter_too_large_end){dist=max(abs(dist),bevel_join_distance(end_coords,next_right,sign_turn_right_end));}}float alpha=distance_to_alpha(abs(dist));
if(v_dash_tex_info.x>=0.){dist=dash_distance(v_coords.x);vec2 prev_coords=rotation_matrix(prev_right)*v_coords;float start_dash_distance=dash_distance(0.);if(!has_start_cap&&cap_type==butt_cap){bool outer_solid=start_dash_distance>=0.&&v_coords.x<half_antialias&&prev_coords.x>-half_antialias;if(outer_solid){float half_aa_dist=dash_distance(half_antialias);if(half_aa_dist>0.)dist=half_aa_dist-v_coords.x+half_antialias;else dist=start_dash_distance-v_coords.x;half_aa_dist=dash_distance(-half_antialias);if(half_aa_dist>0.)dist=min(dist,half_aa_dist+prev_coords.x+half_antialias);else dist=min(dist,start_dash_distance+prev_coords.x);}else{if(v_coords.x<half_antialias)dist=min(0.,dash_distance(half_antialias)-half_antialias)+v_coords.x;if(prev_coords.x>-half_antialias&&prev_coords.x<=half_antialias){float prev_dist=min(0.,dash_distance(-half_antialias)-half_antialias)-prev_coords.x;prev_dist=min(prev_dist,0.5*v_linewidth-abs(prev_coords.y));dist=max(dist,prev_dist);}}}if(!has_end_cap&&cap_type==butt_cap&&end_coords.x<half_antialias){float end_dash_distance=dash_distance(v_segment_length);bool increasing=end_dash_distance>=0.&&sign_turn_right_end*v_coords.y<0.;if(!increasing){float half_aa_dist=dash_distance(v_segment_length-half_antialias);dist=min(0.,half_aa_dist-half_antialias)+end_coords.x;}}dist=cap(cap_type,dist,v_coords.y);float dash_alpha=distance_to_alpha(dist);alpha=min(alpha,dash_alpha);}
alpha=v_line_color.a*alpha;gl_FragColor=vec4(v_line_color.rgb*alpha,alpha);}`;
export default shader;