UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

128 lines 3.85 kB
import { SVGRenderingContext2D } from "./svg"; import { BBox } from "./bbox"; import { div, canvas } from "../dom"; export class CanvasLayer { backend; hidpi; static __name__ = "CanvasLayer"; _canvas; get canvas() { return this._canvas; } _ctx; get ctx() { return this._ctx; } _el; get el() { return this._el; } _pixel_ratio = 1; get pixel_ratio() { return this._pixel_ratio; } bbox = new BBox(); constructor(backend, hidpi) { this.backend = backend; this.hidpi = hidpi; switch (backend) { case "webgl": case "canvas": { this._el = this._canvas = canvas({ class: "bk-layer" }); const ctx = this.canvas.getContext("2d"); if (ctx == null) { throw new Error("unable to obtain 2D rendering context"); } this._ctx = ctx; if (hidpi) { this._pixel_ratio = devicePixelRatio; } break; } case "svg": { const ctx = new SVGRenderingContext2D(); this._ctx = ctx; this._canvas = ctx.get_svg(); this._el = div({ class: "bk-layer" }); const shadow_el = this._el.attachShadow({ mode: "open" }); shadow_el.appendChild(this._canvas); break; } } Object.assign(this._ctx, { layer: this, rect_bbox(bbox) { const { x, y, width, height } = bbox; this.rect(x, y, width, height); }, }); } get pixel_ratio_changed() { if (this.hidpi && (this.backend == "canvas" || this.backend == "webgl")) { return this.pixel_ratio != devicePixelRatio; } else { return false; } } resize(width, height) { const size_changed = this.bbox.width != width || this.bbox.height != height; const { pixel_ratio_changed } = this; if (!size_changed && !pixel_ratio_changed) { return; } if (pixel_ratio_changed) { this._pixel_ratio = devicePixelRatio; } this.bbox = new BBox({ left: 0, top: 0, width, height }); const { target } = this; target.width = width * this.pixel_ratio; target.height = height * this.pixel_ratio; } get target() { return this._ctx instanceof SVGRenderingContext2D ? this._ctx : this.canvas; } undo_transform(fn) { const { ctx } = this; const current_transform = ctx.getTransform(); ctx.resetTransform(); try { fn(ctx); } finally { ctx.setTransform(current_transform); } } prepare() { const { ctx, hidpi, pixel_ratio } = this; ctx.save(); if (hidpi) { ctx.scale(pixel_ratio, pixel_ratio); ctx.translate(0.5, 0.5); } this.clear(); return ctx; } clear() { const { x, y, width, height } = this.bbox; this.ctx.clearRect(x, y, width, height); } finish() { this.ctx.restore(); } to_blob() { const { _canvas } = this; if (_canvas instanceof HTMLCanvasElement) { return new Promise((resolve, reject) => { _canvas.toBlob((blob) => blob != null ? resolve(blob) : reject(), "image/png"); }); } else { const ctx = this._ctx; const svg = ctx.get_serialized_svg(true); const blob = new Blob([svg], { type: "image/svg+xml" }); return Promise.resolve(blob); } } } //# sourceMappingURL=canvas.js.map