UNPKG

@quartic/bokehjs

Version:

Interactive, novel data visualization

451 lines (450 loc) 19 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 side_panel_1 = require("core/layout/side_panel"); var guide_renderer_1 = require("../renderers/guide_renderer"); var renderer_1 = require("../renderers/renderer"); var logging_1 = require("core/logging"); var p = require("core/properties"); var types_1 = require("core/util/types"); exports.AxisView = (function (superClass) { extend(AxisView, superClass); function AxisView() { return AxisView.__super__.constructor.apply(this, arguments); } AxisView.prototype.initialize = function (options) { AxisView.__super__.initialize.call(this, options); this._x_range_name = this.model.x_range_name; return this._y_range_name = this.model.y_range_name; }; AxisView.prototype.render = function () { var ctx; if (this.model.visible === false) { return; } ctx = this.plot_view.canvas_view.ctx; ctx.save(); this._draw_rule(ctx); this._draw_major_ticks(ctx); this._draw_minor_ticks(ctx); this._draw_major_labels(ctx); this._draw_axis_label(ctx); return ctx.restore(); }; AxisView.prototype.bind_bokeh_events = function () { return this.listenTo(this.model, 'change', this.plot_view.request_render); }; AxisView.prototype._get_size = function () { return this._tick_extent() + this._tick_label_extent() + this._axis_label_extent(); }; AxisView.prototype._draw_rule = function (ctx) { var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, sx, sy, x, xoff, y, yoff; if (!this.visuals.axis_line.doit) { return; } ref = coords = this.model.rule_coords, x = ref[0], y = ref[1]; ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1]; ref2 = this.model.normals, nx = ref2[0], ny = ref2[1]; ref3 = this.model.offsets, xoff = ref3[0], yoff = ref3[1]; this.visuals.axis_line.set_value(ctx); ctx.beginPath(); ctx.moveTo(Math.round(sx[0] + nx * xoff), Math.round(sy[0] + ny * yoff)); for (i = k = 1, ref4 = sx.length; 1 <= ref4 ? k < ref4 : k > ref4; i = 1 <= ref4 ? ++k : --k) { ctx.lineTo(Math.round(sx[i] + nx * xoff), Math.round(sy[i] + ny * yoff)); } return ctx.stroke(); }; AxisView.prototype._draw_major_ticks = function (ctx) { var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, results, sx, sy, tin, tout, x, xoff, y, yoff; if (!this.visuals.major_tick_line.doit) { return; } coords = this.model.tick_coords; ref = coords.major, x = ref[0], y = ref[1]; ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1]; ref2 = this.model.normals, nx = ref2[0], ny = ref2[1]; ref3 = this.model.offsets, xoff = ref3[0], yoff = ref3[1]; tin = this.model.major_tick_in; tout = this.model.major_tick_out; this.visuals.major_tick_line.set_value(ctx); results = []; for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) { ctx.beginPath(); ctx.moveTo(Math.round(sx[i] + nx * tout + nx * xoff), Math.round(sy[i] + ny * tout + ny * yoff)); ctx.lineTo(Math.round(sx[i] - nx * tin + nx * xoff), Math.round(sy[i] - ny * tin + ny * yoff)); results.push(ctx.stroke()); } return results; }; AxisView.prototype._draw_minor_ticks = function (ctx) { var coords, i, k, nx, ny, ref, ref1, ref2, ref3, ref4, results, sx, sy, tin, tout, x, xoff, y, yoff; if (!this.visuals.minor_tick_line.doit) { return; } coords = this.model.tick_coords; ref = coords.minor, x = ref[0], y = ref[1]; ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1]; ref2 = this.model.normals, nx = ref2[0], ny = ref2[1]; ref3 = this.model.offsets, xoff = ref3[0], yoff = ref3[1]; tin = this.model.minor_tick_in; tout = this.model.minor_tick_out; this.visuals.minor_tick_line.set_value(ctx); results = []; for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) { ctx.beginPath(); ctx.moveTo(Math.round(sx[i] + nx * tout + nx * xoff), Math.round(sy[i] + ny * tout + ny * yoff)); ctx.lineTo(Math.round(sx[i] - nx * tin + nx * xoff), Math.round(sy[i] - ny * tin + ny * yoff)); results.push(ctx.stroke()); } return results; }; AxisView.prototype._draw_major_labels = function (ctx) { var angle, coords, dim, i, k, labels, nx, ny, orient, ref, ref1, ref2, ref3, ref4, results, side, standoff, sx, sy, x, xoff, y, yoff; coords = this.model.tick_coords; ref = coords.major, x = ref[0], y = ref[1]; ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1]; ref2 = this.model.normals, nx = ref2[0], ny = ref2[1]; ref3 = this.model.offsets, xoff = ref3[0], yoff = ref3[1]; dim = this.model.dimension; side = this.model.panel_side; orient = this.model.major_label_orientation; if (types_1.isString(orient)) { angle = this.model.panel.get_label_angle_heuristic(orient); } else { angle = -orient; } standoff = this._tick_extent() + this.model.major_label_standoff; labels = this.model.formatter.doFormat(coords.major[dim], this.model.loc); this.visuals.major_label_text.set_value(ctx); this.model.panel.apply_label_text_heuristics(ctx, orient); results = []; for (i = k = 0, ref4 = sx.length; 0 <= ref4 ? k < ref4 : k > ref4; i = 0 <= ref4 ? ++k : --k) { if (angle) { ctx.translate(sx[i] + nx * standoff + nx * xoff, sy[i] + ny * standoff + ny * yoff); ctx.rotate(angle); ctx.fillText(labels[i], 0, 0); ctx.rotate(-angle); results.push(ctx.translate(-sx[i] - nx * standoff + nx * xoff, -sy[i] - ny * standoff + ny * yoff)); } else { results.push(ctx.fillText(labels[i], Math.round(sx[i] + nx * standoff + nx * xoff), Math.round(sy[i] + ny * standoff + ny * yoff))); } } return results; }; AxisView.prototype._draw_axis_label = function (ctx) { var angle, label, nx, ny, orient, ref, ref1, ref2, ref3, side, standoff, sx, sy, x, xoff, y, yoff; label = this.model.axis_label; if (label == null) { return; } ref = this.model.rule_coords, x = ref[0], y = ref[1]; ref1 = this.plot_view.map_to_screen(x, y, this._x_range_name, this._y_range_name), sx = ref1[0], sy = ref1[1]; ref2 = this.model.normals, nx = ref2[0], ny = ref2[1]; ref3 = this.model.offsets, xoff = ref3[0], yoff = ref3[1]; side = this.model.panel_side; orient = 'parallel'; angle = this.model.panel.get_label_angle_heuristic(orient); standoff = this._tick_extent() + this._tick_label_extent() + this.model.axis_label_standoff; sx = (sx[0] + sx[sx.length - 1]) / 2; sy = (sy[0] + sy[sy.length - 1]) / 2; this.visuals.axis_label_text.set_value(ctx); this.model.panel.apply_label_text_heuristics(ctx, orient); x = sx + nx * standoff + nx * xoff; y = sy + ny * standoff + ny * yoff; if (isNaN(x) || isNaN(y)) { return; } if (angle) { ctx.translate(x, y); ctx.rotate(angle); ctx.fillText(label, 0, 0); ctx.rotate(-angle); return ctx.translate(-x, -y); } else { return ctx.fillText(label, x, y); } }; AxisView.prototype._tick_extent = function () { return this.model.major_tick_out; }; AxisView.prototype._tick_label_extent = function () { var angle, c, coords, ctx, dim, extent, h, hfactor, hscale, i, k, labels, orient, ref, s, side, val, w, wfactor; extent = 0; ctx = this.plot_view.canvas_view.ctx; dim = this.model.dimension; coords = this.model.tick_coords.major; side = this.model.panel_side; orient = this.model.major_label_orientation; labels = this.model.formatter.doFormat(coords[dim], this.model.loc); this.visuals.major_label_text.set_value(ctx); if (types_1.isString(orient)) { hscale = 1; angle = this.model.panel.get_label_angle_heuristic(orient); } else { hscale = 2; angle = -orient; } angle = Math.abs(angle); c = Math.cos(angle); s = Math.sin(angle); if (side === "above" || side === "below") { wfactor = s; hfactor = c; } else { wfactor = c; hfactor = s; } for (i = k = 0, ref = labels.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { if (labels[i] == null) { continue; } w = ctx.measureText(labels[i]).width * 1.1; h = ctx.measureText(labels[i]).ascent * 0.9; val = w * wfactor + (h / hscale) * hfactor; if (val > extent) { extent = val; } } if (extent > 0) { extent += this.model.major_label_standoff; } return extent; }; AxisView.prototype._axis_label_extent = function () { var angle, axis_label, c, ctx, extent, h, orient, s, side, w; extent = 0; side = this.model.panel_side; axis_label = this.model.axis_label; orient = 'parallel'; ctx = this.plot_view.canvas_view.ctx; this.visuals.axis_label_text.set_value(ctx); angle = Math.abs(this.model.panel.get_label_angle_heuristic(orient)); c = Math.cos(angle); s = Math.sin(angle); if (axis_label) { extent += this.model.axis_label_standoff; this.visuals.axis_label_text.set_value(ctx); w = ctx.measureText(axis_label).width * 1.1; h = ctx.measureText(axis_label).ascent * 0.9; if (side === "above" || side === "below") { extent += w * s + h * c; } else { extent += w * c + h * s; } } return extent; }; return AxisView; })(renderer_1.RendererView); exports.Axis = (function (superClass) { extend(Axis, superClass); function Axis() { return Axis.__super__.constructor.apply(this, arguments); } Axis.prototype.default_view = exports.AxisView; Axis.prototype.type = 'Axis'; Axis.mixins(['line:axis_', 'line:major_tick_', 'line:minor_tick_', 'text:major_label_', 'text:axis_label_']); Axis.define({ bounds: [p.Any, 'auto'], ticker: [p.Instance, null], formatter: [p.Instance, null], x_range_name: [p.String, 'default'], y_range_name: [p.String, 'default'], axis_label: [p.String, ''], axis_label_standoff: [p.Int, 5], major_label_standoff: [p.Int, 5], major_label_orientation: [p.Any, "horizontal"], major_tick_in: [p.Number, 2], major_tick_out: [p.Number, 6], minor_tick_in: [p.Number, 0], minor_tick_out: [p.Number, 4] }); Axis.override({ axis_line_color: 'black', major_tick_line_color: 'black', minor_tick_line_color: 'black', major_label_text_font_size: "8pt", major_label_text_align: "center", major_label_text_baseline: "alphabetic", axis_label_text_font_size: "10pt", axis_label_text_font_style: "italic" }); Axis.internal({ panel_side: [p.Any] }); Axis.prototype.initialize = function (attrs, options) { Axis.__super__.initialize.call(this, attrs, options); this.define_computed_property('computed_bounds', this._computed_bounds, false); this.add_dependencies('computed_bounds', this, ['bounds']); return this.add_dependencies('computed_bounds', this.plot, ['x_range', 'y_range']); }; Axis.getters({ computed_bounds: function () { return this._get_computed('computed_bounds'); }, rule_coords: function () { return this._rule_coords(); }, tick_coords: function () { return this._tick_coords(); }, ranges: function () { return this._ranges(); }, normals: function () { return this.panel._normals; }, dimension: function () { return this.panel._dim; }, offsets: function () { return this._offsets(); }, loc: function () { return this._get_loc(); } }); Axis.prototype.add_panel = function (side) { this.panel = new side_panel_1.SidePanel({ side: side }); this.panel.attach_document(this.document); return this.panel_side = side; }; Axis.prototype._offsets = function () { var frame, ref, side, xoff, yoff; side = this.panel_side; ref = [0, 0], xoff = ref[0], yoff = ref[1]; frame = this.plot.plot_canvas.frame; switch (side) { case "below": yoff = Math.abs(this.panel.top - frame.bottom); break; case "above": yoff = Math.abs(this.panel.bottom - frame.top); break; case "right": xoff = Math.abs(this.panel.left - frame.right); break; case "left": xoff = Math.abs(this.panel.right - frame.left); } return [xoff, yoff]; }; Axis.prototype._ranges = function () { var frame, i, j, ranges; i = this.dimension; j = (i + 1) % 2; frame = this.plot.plot_canvas.frame; ranges = [frame.x_ranges[this.x_range_name], frame.y_ranges[this.y_range_name]]; return [ranges[i], ranges[j]]; }; Axis.prototype._computed_bounds = function () { var cross_range, end, range, range_bounds, ref, ref1, start, user_bounds; ref = this.ranges, range = ref[0], cross_range = ref[1]; user_bounds = (ref1 = this.bounds) != null ? ref1 : 'auto'; range_bounds = [range.min, range.max]; if (user_bounds === 'auto') { return range_bounds; } if (types_1.isArray(user_bounds)) { if (Math.abs(user_bounds[0] - user_bounds[1]) > Math.abs(range_bounds[0] - range_bounds[1])) { start = Math.max(Math.min(user_bounds[0], user_bounds[1]), range_bounds[0]); end = Math.min(Math.max(user_bounds[0], user_bounds[1]), range_bounds[1]); } else { start = Math.min(user_bounds[0], user_bounds[1]); end = Math.max(user_bounds[0], user_bounds[1]); } return [start, end]; } logging_1.logger.error("user bounds '" + user_bounds + "' not understood"); return null; }; Axis.prototype._rule_coords = function () { var coords, cross_range, end, i, j, range, ref, ref1, start, xs, ys; i = this.dimension; j = (i + 1) % 2; ref = this.ranges, range = ref[0], cross_range = ref[1]; ref1 = this.computed_bounds, start = ref1[0], end = ref1[1]; xs = new Array(2); ys = new Array(2); coords = [xs, ys]; coords[i][0] = Math.max(start, range.min); coords[i][1] = Math.min(end, range.max); if (coords[i][0] > coords[i][1]) { coords[i][0] = coords[i][1] = 0 / 0; } coords[j][0] = this.loc; coords[j][1] = this.loc; return coords; }; Axis.prototype._tick_coords = function () { var coords, cross_range, end, i, ii, j, k, l, m, majors, minor_coords, minor_xs, minor_ys, minors, range, range_max, range_min, ref, ref1, ref2, ref3, ref4, ref5, start, ticks, xs, ys; i = this.dimension; j = (i + 1) % 2; ref = this.ranges, range = ref[0], cross_range = ref[1]; ref1 = this.computed_bounds, start = ref1[0], end = ref1[1]; ticks = this.ticker.get_ticks(start, end, range, this.loc, {}); majors = ticks.major; minors = ticks.minor; xs = []; ys = []; coords = [xs, ys]; minor_xs = []; minor_ys = []; minor_coords = [minor_xs, minor_ys]; if (range.type === "FactorRange") { for (ii = k = 0, ref2 = majors.length; 0 <= ref2 ? k < ref2 : k > ref2; ii = 0 <= ref2 ? ++k : --k) { coords[i].push(majors[ii]); coords[j].push(this.loc); } } else { ref3 = [range.min, range.max], range_min = ref3[0], range_max = ref3[1]; for (ii = l = 0, ref4 = majors.length; 0 <= ref4 ? l < ref4 : l > ref4; ii = 0 <= ref4 ? ++l : --l) { if (majors[ii] < range_min || majors[ii] > range_max) { continue; } coords[i].push(majors[ii]); coords[j].push(this.loc); } for (ii = m = 0, ref5 = minors.length; 0 <= ref5 ? m < ref5 : m > ref5; ii = 0 <= ref5 ? ++m : --m) { if (minors[ii] < range_min || minors[ii] > range_max) { continue; } minor_coords[i].push(minors[ii]); minor_coords[j].push(this.loc); } } return { "major": coords, "minor": minor_coords }; }; Axis.prototype._get_loc = function () { var cend, cross_range, cstart, range, ref, side; ref = this.ranges, range = ref[0], cross_range = ref[1]; cstart = cross_range.start; cend = cross_range.end; side = this.panel_side; switch (side) { case 'left': case 'below': return cross_range.start; case 'right': case 'above': return cross_range.end; } }; return Axis; })(guide_renderer_1.GuideRenderer);