@bokeh/bokehjs
Version:
Interactive, novel data visualization
145 lines • 5.55 kB
JavaScript
import { RadialGlyph, RadialGlyphView } from "./radial_glyph";
import * as hittest from "../../core/hittest";
import { minmax2 } from "../../core/util/arrayable";
import { Selection } from "../selections/selection";
export class CircleView extends RadialGlyphView {
static __name__ = "CircleView";
async load_glglyph() {
const { CircleGL } = await import("./webgl/circle");
return CircleGL;
}
_paint(ctx, indices, data) {
const { sx, sy, sradius } = { ...this, ...data };
for (const i of indices) {
const sx_i = sx[i];
const sy_i = sy[i];
const sradius_i = sradius[i];
if (!isFinite(sx_i + sy_i + sradius_i)) {
continue;
}
ctx.beginPath();
ctx.arc(sx_i, sy_i, sradius_i, 0, 2 * Math.PI, 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);
const { hit_dilation } = this.model;
const [x0, x1, y0, y1] = (() => {
if (this.model.properties.radius.units == "data") {
const dr = this.max_radius * hit_dilation;
const x0 = x - dr;
const x1 = x + dr;
const y0 = y - dr;
const y1 = y + dr;
return [x0, x1, y0, y1];
}
else {
const ds = this.max_radius * hit_dilation;
const sx0 = sx - ds;
const sx1 = sx + ds;
const sy0 = sy - ds;
const sy1 = sy + ds;
const [x0, x1] = this.renderer.xscale.r_invert(sx0, sx1);
const [y0, y1] = this.renderer.yscale.r_invert(sy0, sy1);
return [x0, x1, y0, y1];
}
})();
const candidates = this.index.indices({ x0, x1, y0, y1 });
const indices = [];
if (this.model.properties.radius.units == "data") {
for (const i of candidates) {
const r2 = (this.sradius[i] * hit_dilation) ** 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 <= r2) {
indices.push(i);
}
}
}
else {
for (const i of candidates) {
const r2 = (this.sradius[i] * hit_dilation) ** 2;
const dist = (this.sx[i] - sx) ** 2 + (this.sy[i] - sy) ** 2;
if (dist <= r2) {
indices.push(i);
}
}
}
return new Selection({ indices });
}
_hit_span(geometry) {
const { sx, sy } = geometry;
const bounds = this.bounds();
const [x0, x1, y0, y1] = (() => {
const dr = this.max_radius;
if (geometry.direction == "h") {
// use circle bounds instead of current pointer y coordinates
const sx0 = sx - dr;
const sx1 = sx + dr;
const [x0, x1] = this.renderer.xscale.r_invert(sx0, sx1);
const { y0, y1 } = bounds;
return [x0, x1, y0, y1];
}
else {
// use circle bounds instead of current pointer x coordinates
const sy0 = sy - dr;
const sy1 = sy + dr;
const { x0, x1 } = bounds;
const [y0, y1] = this.renderer.yscale.r_invert(sy0, sy1);
return [x0, x1, y0, y1];
}
})();
const indices = [...this.index.indices({ x0, x1, y0, y1 })];
return new Selection({ indices });
}
_hit_rect(geometry) {
const { sx0, sx1, sy0, sy1 } = geometry;
const [x0, x1] = this.renderer.xscale.r_invert(sx0, sx1);
const [y0, y1] = this.renderer.yscale.r_invert(sy0, sy1);
const candidates = this.index.indices({ x0, x1, y0, y1 });
const indices = [];
for (const i of candidates) {
const sx_i = this.sx[i];
const sy_i = this.sy[i];
if (sx0 <= sx_i && sx_i <= sx1 && sy0 <= sy_i && sy_i <= sy1) {
indices.push(i);
}
}
return new Selection({ indices });
}
_hit_poly(geometry) {
const { sx: sxs, sy: sys } = geometry;
const candidates = (() => {
const [sx0, sx1, sy0, sy1] = minmax2(sxs, sys);
const [x0, x1] = this.renderer.xscale.r_invert(sx0, sx1);
const [y0, y1] = this.renderer.yscale.r_invert(sy0, sy1);
return this.index.indices({ x0, x1, y0, y1 });
})();
const indices = [];
for (const i of candidates) {
if (hittest.point_in_poly(this.sx[i], this.sy[i], sxs, sys)) {
indices.push(i);
}
}
return new Selection({ indices });
}
}
export class Circle extends RadialGlyph {
static __name__ = "Circle";
constructor(attrs) {
super(attrs);
}
static {
this.prototype.default_view = CircleView;
this.define(({ Float }) => ({
hit_dilation: [Float, 1.0],
}));
}
}
//# sourceMappingURL=circle.js.map