UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

85 lines 2.99 kB
import { XYGlyph, XYGlyphView } from "./xy_glyph"; import { generic_area_scalar_legend } from "./utils"; import * as hittest from "../../core/hittest"; import * as mixins from "../../core/property_mixins"; import { Selection } from "../selections/selection"; export class PatchView extends XYGlyphView { static __name__ = "PatchView"; _paint(ctx, indices, data) { const { sx, sy } = { ...this, ...data }; let move = true; ctx.beginPath(); for (const i of indices) { const sx_i = sx[i]; const sy_i = sy[i]; if (!isFinite(sx_i + sy_i)) { ctx.closePath(); move = true; } else { if (move) { ctx.moveTo(sx_i, sy_i); move = false; } else { ctx.lineTo(sx_i, sy_i); } } } ctx.closePath(); this.visuals.fill.apply(ctx, "evenodd"); this.visuals.hatch.apply(ctx, "evenodd"); this.visuals.line.apply(ctx); } draw_legend_for_index(ctx, bbox, _index) { generic_area_scalar_legend(this.visuals, ctx, bbox); } _hit_point(geometry) { const result = new Selection(); const { sx, sy } = geometry; // Collect NaN-separated sub-paths const sub_paths_sx = []; const sub_paths_sy = []; const n = this.sx.length; let k = 0; for (let j = 0; j <= n; j++) { if (j == n || isNaN(this.sx[j])) { if (j > k) { // Use subarray to create views (like patches.ts does) sub_paths_sx.push(this.sx.subarray(k, j)); sub_paths_sy.push(this.sy.subarray(k, j)); } k = j + 1; } } if (sub_paths_sx.length == 0) { return result; } // Use "evenodd" fill rule (matches Canvas2D rendering): // A point is inside the filled region if it's contained by an odd number of sub-paths. // This handles both holes (even count = outside) and disjoint polygons (each adds to count). let inside_count = 0; for (let i = 0; i < sub_paths_sx.length; i++) { if (hittest.point_in_poly(sx, sy, sub_paths_sx[i], sub_paths_sy[i])) { inside_count++; } } // Odd count = inside filled region, Even count = inside hole or outside if (inside_count % 2 === 1) { result.add_to_selected_glyphs(this.model); result.view = this; } return result; } } export class Patch extends XYGlyph { static __name__ = "Patch"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = PatchView; this.mixins([mixins.LineScalar, mixins.FillScalar, mixins.HatchScalar]); } } //# sourceMappingURL=patch.js.map