@bokeh/bokehjs
Version:
Interactive, novel data visualization
138 lines • 6.34 kB
JavaScript
import { BaseLineGL } from "./base_line";
import { Float32Buffer, Uint8Buffer } from "./buffer";
export class MultiLineGL extends BaseLineGL {
glyph;
static __name__ = "MultiLineGL";
constructor(regl_wrapper, glyph) {
super(regl_wrapper, glyph);
this.glyph = glyph;
}
draw(indices, main_glyph, transform) {
// Indices refer to whole lines not line segments
if (this.visuals_changed) {
this._set_visuals();
this.visuals_changed = false;
}
const main_gl_glyph = main_glyph.glglyph;
const data_changed_or_mapped = main_gl_glyph.data_changed || main_gl_glyph.data_mapped;
if (data_changed_or_mapped) {
main_gl_glyph._set_data(main_gl_glyph.data_changed);
}
if ((data_changed_or_mapped && main_gl_glyph._is_dashed) || this._is_dashed) {
// length_so_far is a data property as it depends on point positions in canvas coordinates
// but is only needed for dashed lines so it also depends on visual properties.
// Care needed if base glyph is solid but e.g. nonselection glyph is dashed.
main_gl_glyph._set_length();
}
if (data_changed_or_mapped) {
main_gl_glyph.data_changed = false;
main_gl_glyph.data_mapped = false;
}
const { data_size } = this.glyph; // Number of lines
let framebuffer = null;
let tex = null;
if (data_size > 1) {
[framebuffer, tex] = this.regl_wrapper.framebuffer_and_texture;
}
let point_offset = 0;
let prev_index = -1;
for (const index of indices) {
for (let i = prev_index + 1; i < index; i++) {
// Account for offsets of lines not displayed
const npoints = main_glyph.sxs.get(i).length;
point_offset += (npoints + 2) * 2;
}
const npoints = main_glyph.sxs.get(index).length;
const nsegments = npoints - 1; // Points array includes extra points at each end
// Not necessary if just a single line
if (framebuffer != null) {
this.regl_wrapper.clear_framebuffer(framebuffer);
}
this._draw_single(main_gl_glyph, transform, index, point_offset, nsegments, framebuffer);
if (framebuffer != null) {
// Accumulate framebuffer to WebGL canvas
const accumulate_props = {
scissor: this.regl_wrapper.scissor,
viewport: this.regl_wrapper.viewport,
framebuffer_tex: tex,
};
this.regl_wrapper.accumulate()(accumulate_props);
}
point_offset += (npoints + 2) * 2;
prev_index = index;
}
}
_get_visuals() {
return this.glyph.visuals.line;
}
_set_data(data_changed) {
// If data_changed is false the underlying glyph data has not changed but has been mapped to
// different canvas coordinates e.g. via pan or zoom. If data_changed is true the data itself
// has changed, which also implies it has been mapped.
// Set data properties which are points and show flags for data
// (taking into account NaNs but not selected indices)
const line_count = this.glyph.data_size;
const total_point_count = this.glyph.sxs.data.length;
if (this._points == null) {
this._points = new Float32Buffer(this.regl_wrapper);
}
const points_array = this._points.get_sized_array((total_point_count + 2 * line_count) * 2);
let point_offset = 0;
for (let i = 0; i < line_count; i++) {
// Process a single line at a time.
const sx = this.glyph.sxs.get(i);
const sy = this.glyph.sys.get(i);
const npoints = sx.length;
const points = points_array.subarray(point_offset, point_offset + (npoints + 2) * 2);
this._set_points_single(points, sx, sy);
point_offset += (npoints + 2) * 2;
}
this._points.update();
if (data_changed) {
if (this._show == null) {
this._show = new Uint8Buffer(this.regl_wrapper);
}
const show_array = this._show.get_sized_array(total_point_count + line_count);
let point_offset = 0;
let show_offset = 0;
for (let i = 0; i < line_count; i++) {
// Process a single line at a time.
const sx = this.glyph.sxs.get(i);
const npoints = sx.length;
const points = points_array.subarray(point_offset, point_offset + (npoints + 2) * 2);
const show = show_array.subarray(show_offset, show_offset + npoints + 1);
this._set_show_single(show, points);
point_offset += (npoints + 2) * 2;
show_offset += npoints + 1;
}
this._show.update();
}
}
_set_length() {
const line_count = this.glyph.data_size;
const total_point_count = this.glyph.sxs.data.length;
const points_array = this._points.get_array();
const show_array = this._show.get_array();
if (this._length_so_far == null) {
this._length_so_far = new Float32Buffer(this.regl_wrapper);
}
const length_so_far = this._length_so_far.get_sized_array(total_point_count - line_count);
let point_offset = 0;
let show_offset = 0;
let length_offset = 0;
for (let i = 0; i < line_count; i++) {
const sx = this.glyph.sxs.get(i);
const npoints = sx.length;
const nsegments = npoints - 1;
const points = points_array.subarray(point_offset, point_offset + (npoints + 2) * 2);
const show = show_array.subarray(show_offset, show_offset + npoints + 1);
const length = length_so_far.subarray(length_offset, length_offset + nsegments);
this._set_length_single(length, points, show);
point_offset += (npoints + 2) * 2;
show_offset += npoints + 1;
length_offset += nsegments;
}
this._length_so_far.update();
}
}
//# sourceMappingURL=multi_line.js.map