UNPKG

@quartic/bokehjs

Version:

Interactive, novel data visualization

351 lines (350 loc) 15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var extend = function (child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; var annotation_1 = require("./annotation"); var p = require("core/properties"); var text_1 = require("core/util/text"); var bbox_1 = require("core/util/bbox"); var array_1 = require("core/util/array"); var object_1 = require("core/util/object"); var types_1 = require("core/util/types"); exports.LegendView = (function (superClass) { extend(LegendView, superClass); function LegendView() { return LegendView.__super__.constructor.apply(this, arguments); } LegendView.prototype.initialize = function (options) { return LegendView.__super__.initialize.call(this, options); }; LegendView.prototype.bind_bokeh_events = function () { return this.listenTo(this.model, 'change:visible', this.plot_view.request_render); }; LegendView.prototype.compute_legend_bbox = function () { var ctx, glyph_height, glyph_width, h_range, i, label_height, label_standoff, label_width, legend_height, legend_margin, legend_names, legend_padding, legend_spacing, legend_width, len, location, max_label_width, name, panel, ref, ref1, v_range, width, x, y; legend_names = this.model.get_legend_names(); glyph_height = this.model.glyph_height; glyph_width = this.model.glyph_width; label_height = this.model.label_height; label_width = this.model.label_width; this.max_label_height = array_1.max([text_1.get_text_height(this.visuals.label_text.font_value()).height, label_height, glyph_height]); ctx = this.plot_view.canvas_view.ctx; ctx.save(); this.visuals.label_text.set_value(ctx); this.text_widths = {}; for (i = 0, len = legend_names.length; i < len; i++) { name = legend_names[i]; this.text_widths[name] = array_1.max([ctx.measureText(name).width, label_width]); } ctx.restore(); max_label_width = array_1.max(object_1.values(this.text_widths)); legend_margin = this.model.margin; legend_padding = this.model.padding; legend_spacing = this.model.spacing; label_standoff = this.model.label_standoff; if (this.model.orientation === "vertical") { legend_height = legend_names.length * this.max_label_height + (legend_names.length - 1) * legend_spacing + 2 * legend_padding; legend_width = max_label_width + glyph_width + label_standoff + 2 * legend_padding; } else { legend_width = 2 * legend_padding + (legend_names.length - 1) * legend_spacing; ref = this.text_widths; for (name in ref) { width = ref[name]; legend_width += array_1.max([width, label_width]) + glyph_width + label_standoff; } legend_height = this.max_label_height + 2 * legend_padding; } panel = (ref1 = this.model.panel) != null ? ref1 : this.plot_view.frame; h_range = { start: panel.left, end: panel.right }; v_range = { start: panel.bottom, end: panel.top }; location = this.model.location; if (types_1.isString(location)) { switch (location) { case 'top_left': x = h_range.start + legend_margin; y = v_range.end - legend_margin; break; case 'top_center': x = (h_range.end + h_range.start) / 2 - legend_width / 2; y = v_range.end - legend_margin; break; case 'top_right': x = h_range.end - legend_margin - legend_width; y = v_range.end - legend_margin; break; case 'center_right': x = h_range.end - legend_margin - legend_width; y = (v_range.end + v_range.start) / 2 + legend_height / 2; break; case 'bottom_right': x = h_range.end - legend_margin - legend_width; y = v_range.start + legend_margin + legend_height; break; case 'bottom_center': x = (h_range.end + h_range.start) / 2 - legend_width / 2; y = v_range.start + legend_margin + legend_height; break; case 'bottom_left': x = h_range.start + legend_margin; y = v_range.start + legend_margin + legend_height; break; case 'center_left': x = h_range.start + legend_margin; y = (v_range.end + v_range.start) / 2 + legend_height / 2; break; case 'center': x = (h_range.end + h_range.start) / 2 - legend_width / 2; y = (v_range.end + v_range.start) / 2 + legend_height / 2; } } else if (types_1.isArray(location) && location.length === 2) { x = location[0], y = location[1]; x += h_range.start; y += v_range.start + legend_height; } x = this.plot_view.canvas.vx_to_sx(x); y = this.plot_view.canvas.vy_to_sy(y); return { x: x, y: y, width: legend_width, height: legend_height }; }; LegendView.prototype.bbox = function () { var height, ref, width, x, y; ref = this.compute_legend_bbox(), x = ref.x, y = ref.y, width = ref.width, height = ref.height; return new bbox_1.BBox({ x0: x, y0: y, x1: x + width, y1: y + height }); }; LegendView.prototype.on_hit = function (sx, sy) { var bbox, field, glyph_height, glyph_width, h, i, item, j, k, l, label, label_standoff, labels, legend_bbox, legend_spacing, len, len1, len2, len3, r, ref, ref1, ref2, ref3, ref4, vertical, w, x1, x2, xoffset, y1, y2, yoffset; glyph_height = this.model.glyph_height; glyph_width = this.model.glyph_width; legend_spacing = this.model.spacing; label_standoff = this.model.label_standoff; xoffset = yoffset = this.model.padding; legend_bbox = this.compute_legend_bbox(); vertical = this.model.orientation === "vertical"; ref = this.model.items; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; labels = item.get_labels_list_from_label_prop(); field = item.get_field_from_label_prop(); for (j = 0, len1 = labels.length; j < len1; j++) { label = labels[j]; x1 = legend_bbox.x + xoffset; y1 = legend_bbox.y + yoffset; x2 = x1 + glyph_width; y2 = y1 + glyph_height; if (vertical) { ref1 = [legend_bbox.width - 2 * this.model.padding, this.max_label_height], w = ref1[0], h = ref1[1]; } else { ref2 = [this.text_widths[label] + glyph_width + label_standoff, this.max_label_height], w = ref2[0], h = ref2[1]; } bbox = new bbox_1.BBox({ x0: x1, y0: y1, x1: x1 + w, y1: y1 + h }); if (bbox.contains(sx, sy)) { switch (this.model.click_policy) { case "hide": ref3 = item.renderers; for (k = 0, len2 = ref3.length; k < len2; k++) { r = ref3[k]; r.visible = !r.visible; } break; case "mute": ref4 = item.renderers; for (l = 0, len3 = ref4.length; l < len3; l++) { r = ref4[l]; r.muted = !r.muted; } } return true; } if (vertical) { yoffset += this.max_label_height + legend_spacing; } else { xoffset += this.text_widths[label] + glyph_width + label_standoff + legend_spacing; } } } return false; }; LegendView.prototype.render = function () { var bbox, ctx; if (!this.model.visible) { return; } if (this.model.items.length === 0) { return; } ctx = this.plot_view.canvas_view.ctx; bbox = this.compute_legend_bbox(); ctx.save(); this._draw_legend_box(ctx, bbox); this._draw_legend_items(ctx, bbox); return ctx.restore(); }; LegendView.prototype._draw_legend_box = function (ctx, bbox) { ctx.beginPath(); ctx.rect(bbox.x, bbox.y, bbox.width, bbox.height); this.visuals.background_fill.set_value(ctx); ctx.fill(); if (this.visuals.border_line.doit) { this.visuals.border_line.set_value(ctx); return ctx.stroke(); } }; LegendView.prototype._draw_legend_items = function (ctx, bbox) { var active, field, glyph_height, glyph_width, h, i, item, j, k, label, label_standoff, labels, legend_spacing, len, len1, len2, r, ref, ref1, ref2, ref3, vertical, view, w, x1, x2, xoffset, y1, y2, yoffset; glyph_height = this.model.glyph_height; glyph_width = this.model.glyph_width; legend_spacing = this.model.spacing; label_standoff = this.model.label_standoff; xoffset = yoffset = this.model.padding; vertical = this.model.orientation === "vertical"; ref = this.model.items; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; labels = item.get_labels_list_from_label_prop(); field = item.get_field_from_label_prop(); if (labels.length === 0) { continue; } active = (function () { switch (this.model.click_policy) { case "none": return true; case "hide": return array_1.all(item.renderers, function (r) { return r.visible; }); case "mute": return array_1.all(item.renderers, function (r) { return !r.muted; }); } }).call(this); for (j = 0, len1 = labels.length; j < len1; j++) { label = labels[j]; x1 = bbox.x + xoffset; y1 = bbox.y + yoffset; x2 = x1 + glyph_width; y2 = y1 + glyph_height; if (vertical) { yoffset += this.max_label_height + legend_spacing; } else { xoffset += this.text_widths[label] + glyph_width + label_standoff + legend_spacing; } this.visuals.label_text.set_value(ctx); ctx.fillText(label, x2 + label_standoff, y1 + this.max_label_height / 2.0); ref1 = item.renderers; for (k = 0, len2 = ref1.length; k < len2; k++) { r = ref1[k]; view = this.plot_view.renderer_views[r.id]; view.draw_legend(ctx, x1, x2, y1, y2, field, label); } if (!active) { if (vertical) { ref2 = [bbox.width - 2 * this.model.padding, this.max_label_height], w = ref2[0], h = ref2[1]; } else { ref3 = [this.text_widths[label] + glyph_width + label_standoff, this.max_label_height], w = ref3[0], h = ref3[1]; } ctx.beginPath(); ctx.rect(x1, y1, w, h); this.visuals.inactive_fill.set_value(ctx); ctx.fill(); } } } return null; }; LegendView.prototype._get_size = function () { var bbox, side; bbox = this.compute_legend_bbox(); side = this.model.panel.side; if (side === 'above' || side === 'below') { return bbox.height; } if (side === 'left' || side === 'right') { return bbox.width; } }; return LegendView; })(annotation_1.AnnotationView); exports.Legend = (function (superClass) { extend(Legend, superClass); function Legend() { return Legend.__super__.constructor.apply(this, arguments); } Legend.prototype.default_view = exports.LegendView; Legend.prototype.type = 'Legend'; Legend.prototype.cursor = function () { if (this.click_policy === "none") { return null; } else { return "pointer"; } }; Legend.prototype.get_legend_names = function () { var i, item, labels, legend_names, len, ref; legend_names = []; ref = this.items; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; labels = item.get_labels_list_from_label_prop(); legend_names = legend_names.concat(labels); } return legend_names; }; Legend.mixins(['text:label_', 'fill:inactive_', 'line:border_', 'fill:background_']); Legend.define({ orientation: [p.Orientation, 'vertical'], location: [p.Any, 'top_right'], label_standoff: [p.Number, 5], glyph_height: [p.Number, 20], glyph_width: [p.Number, 20], label_height: [p.Number, 20], label_width: [p.Number, 20], margin: [p.Number, 10], padding: [p.Number, 10], spacing: [p.Number, 3], items: [p.Array, []], click_policy: [p.Any, "none"] }); Legend.override({ border_line_color: "#e5e5e5", border_line_alpha: 0.5, border_line_width: 1, background_fill_color: "#ffffff", background_fill_alpha: 0.95, inactive_fill_color: "white", inactive_fill_alpha: 0.9, label_text_font_size: "10pt", label_text_baseline: "middle" }); return Legend; })(annotation_1.Annotation);