UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

130 lines 5.18 kB
import { XYGlyph, XYGlyphView } from "./xy_glyph"; import { inherit } from "./glyph"; import { to_screen } from "../../core/types"; import { LineVector, FillVector, HatchVector } from "../../core/property_mixins"; import * as p from "../../core/properties"; import { Selection } from "../selections/selection"; export class AnnulusView extends XYGlyphView { static __name__ = "AnnulusView"; async load_glglyph() { const { AnnulusGL } = await import("./webgl/annulus"); return AnnulusGL; } _index_data(index) { const { x, y, outer_radius, data_size } = this; for (let i = 0; i < data_size; i++) { const x_i = x[i]; const y_i = y[i]; const r_i = outer_radius.get(i); index.add_rect(x_i - r_i, y_i - r_i, x_i + r_i, y_i + r_i); } } _map_data() { this._define_or_inherit_attr("sinner_radius", () => { if (this.model.properties.inner_radius.units == "data") { if (this.inherited_x && this.inherited_inner_radius) { return inherit; } else { return this.sdist(this.renderer.xscale, this.x, this.inner_radius); } } else { return this.inherited_inner_radius ? inherit : to_screen(this.inner_radius); } }); this._define_or_inherit_attr("souter_radius", () => { if (this.model.properties.outer_radius.units == "data") { if (this.inherited_x && this.inherited_outer_radius) { return inherit; } else { return this.sdist(this.renderer.xscale, this.x, this.outer_radius); } } else { return this.inherited_outer_radius ? inherit : to_screen(this.outer_radius); } }); } _paint(ctx, indices, data) { const { sx, sy, sinner_radius, souter_radius } = { ...this, ...data }; for (const i of indices) { const sx_i = sx[i]; const sy_i = sy[i]; const sinner_radius_i = sinner_radius[i]; const souter_radius_i = souter_radius[i]; if (!isFinite(sx_i + sy_i + sinner_radius_i + souter_radius_i)) { continue; } ctx.beginPath(); ctx.arc(sx_i, sy_i, sinner_radius_i, 0, 2 * Math.PI, true); ctx.moveTo(sx_i + souter_radius_i, sy_i); ctx.arc(sx_i, sy_i, souter_radius_i, 2 * Math.PI, 0, false); this.visuals.fill.apply(ctx, i); this.visuals.hatch.apply(ctx, i); this.visuals.line.apply(ctx, i); } } _hit_point(geometry) { const { sx, sy } = geometry; const x = this.renderer.xscale.invert(sx); const y = this.renderer.yscale.invert(sy); let x0, y0; let x1, y1; if (this.model.properties.outer_radius.units == "data") { x0 = x - this.max_outer_radius; x1 = x + this.max_outer_radius; y0 = y - this.max_outer_radius; y1 = y + this.max_outer_radius; } else { const sx0 = sx - this.max_outer_radius; const sx1 = sx + this.max_outer_radius; [x0, x1] = this.renderer.xscale.r_invert(sx0, sx1); const sy0 = sy - this.max_outer_radius; const sy1 = sy + this.max_outer_radius; [y0, y1] = this.renderer.yscale.r_invert(sy0, sy1); } const indices = []; for (const i of this.index.indices({ x0, x1, y0, y1 })) { const or2 = this.souter_radius[i] ** 2; const ir2 = this.sinner_radius[i] ** 2; const [sx0, sx1] = this.renderer.xscale.r_compute(x, this.x[i]); const [sy0, sy1] = this.renderer.yscale.r_compute(y, this.y[i]); const dist = (sx0 - sx1) ** 2 + (sy0 - sy1) ** 2; if (dist <= or2 && dist >= ir2) { indices.push(i); } } return new Selection({ indices }); } draw_legend_for_index(ctx, { x0, y0, x1, y1 }, index) { const len = index + 1; const sx = new Array(len); sx[index] = (x0 + x1) / 2; const sy = new Array(len); sy[index] = (y0 + y1) / 2; const r = Math.min(Math.abs(x1 - x0), Math.abs(y1 - y0)) * 0.5; const sinner_radius = new Array(len); sinner_radius[index] = r * 0.4; const souter_radius = new Array(len); souter_radius[index] = r * 0.8; this._paint(ctx, [index], { sx, sy, sinner_radius, souter_radius }); } } export class Annulus extends XYGlyph { static __name__ = "Annulus"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = AnnulusView; this.mixins([LineVector, FillVector, HatchVector]); this.define(({}) => ({ inner_radius: [p.DistanceSpec, { field: "inner_radius" }], outer_radius: [p.DistanceSpec, { field: "outer_radius" }], })); } } //# sourceMappingURL=annulus.js.map