text: var _a;
  import { GuideRenderer, GuideRendererView } from "../renderers/guide_renderer";
  import { Ticker } from "../tickers/ticker";
  import { TickFormatter } from "../formatters/tick_formatter";
  import { LabelingPolicy, AllLabels } from "../policies/labeling";
  import * as mixins from "../../core/property_mixins";
  import { TickLabelOrientation } from "../../core/enums";
  import { Indices } from "../../core/types";
  import { SideLayout } from "../../core/layout/side_panel";
  import { sum } from "../../core/util/array";
  import { entries } from "../../core/util/object";
  import { isNumber } from "../../core/util/types";
  import { GraphicsBoxes, TextBox } from "../../core/graphics";
  import { FactorRange } from "../ranges/factor_range";
  import { BaseText } from "../text/base_text";
  import { build_view } from "../../core/build_views";
  import { unreachable } from "../../core/util/assert";
  import { isString } from "../../core/util/types";
  import { parse_delimited_string } from "../text/utils";
  const { abs } = Math;
  export class AxisView extends GuideRendererView {
      constructor() {
          super(...arguments);
          /*private*/ this._axis_label_view = null;
          /*private*/ this._major_label_views = new Map();
      }
      async lazy_initialize() {
          await super.lazy_initialize();
          await this._init_axis_label();
          await this._init_major_labels();
      }
      async _init_axis_label() {
          const { axis_label } = this.model;
          if (axis_label != null) {
              const _axis_label = isString(axis_label) ? parse_delimited_string(axis_label) : axis_label;
              this._axis_label_view = await build_view(_axis_label, { parent: this });
          }
          else
              this._axis_label_view = null;
      }
      async _init_major_labels() {
          const { major_label_overrides } = this.model;
          for (const [label, label_text] of entries(major_label_overrides)) {
              const _label_text = isString(label_text) ? parse_delimited_string(label_text) : label_text;
              this._major_label_views.set(label, await build_view(_label_text, { parent: this }));
          }
      }
      update_layout() {
          this.layout = new SideLayout(this.panel, () => this.get_size(), true);
          this.layout.on_resize(() => this._coordinates = undefined);
      }
      get_size() {
          const { visible, fixed_location } = this.model;
          if (visible && fixed_location == null && this.is_renderable) {
              const { extents } = this;
              const height = Math.round(extents.tick + extents.tick_label + extents.axis_label);
              return { width: 0, height };
          }
          else
              return { width: 0, height: 0 };
      }
      get is_renderable() {
          const [range, cross_range] = this.ranges;
          return range.is_valid && cross_range.is_valid;
      }
      _render() {
          if (!this.is_renderable)
              return;
          const { tick_coords, extents } = this;
          const ctx = this.layer.ctx;
          ctx.save();
          this._draw_rule(ctx, extents);
          this._draw_major_ticks(ctx, extents, tick_coords);
          this._draw_minor_ticks(ctx, extents, tick_coords);
          this._draw_major_labels(ctx, extents, tick_coords);
          this._draw_axis_label(ctx, extents, tick_coords);
          this._paint?.(ctx, extents, tick_coords);
          ctx.restore();
      }
      connect_signals() {
          super.connect_signals();
          const { axis_label, major_label_overrides } = this.model.properties;
          this.on_change(axis_label, async () => {
              this._axis_label_view?.remove();
              await this._init_axis_label();
          });
          this.on_change(major_label_overrides, async () => {
              for (const label_view of this._major_label_views.values()) {
                  label_view.remove();
              }
              await this._init_major_labels();
          });
          this.connect(this.model.change, () => this.plot_view.request_layout());
      }
      get needs_clip() {
          return this.model.fixed_location != null;
      }
      // drawing sub functions -----------------------------------------------------
      _draw_rule(ctx, _extents) {
          if (!this.visuals.axis_line.doit)
              return;
          const [xs, ys] = this.rule_coords;
          const [sxs, sys] = this.coordinates.map_to_screen(xs, ys);
          const [nx, ny] = this.normals;
          const [xoff, yoff] = this.offsets;
          this.visuals.axis_line.set_value(ctx);
          ctx.beginPath();
          for (let i = 0; i < sxs.length; i++) {
              const sx = Math.round(sxs[i] + nx * xoff);
              const sy = Math.round(sys[i] + ny * yoff);
              ctx.lineTo(sx, sy);
          }
          ctx.stroke();
      }
      _draw_major_ticks(ctx, _extents, tick_coords) {
          const tin = this.model.major_tick_in;
          const tout = this.model.major_tick_out;
          const visuals = this.visuals.major_tick_line;
          this._draw_ticks(ctx, tick_coords.major, tin, tout, visuals);
      }
      _draw_minor_ticks(ctx, _extents, tick_coords) {
          const tin = this.model.minor_tick_in;
          const tout = this.model.minor_tick_out;
          const visuals = this.visuals.minor_tick_line;
          this._draw_ticks(ctx, tick_coords.minor, tin, tout, visuals);
      }
      _draw_major_labels(ctx, extents, tick_coords) {
          const coords = tick_coords.major;
          const labels = this.compute_labels(coords[this.dimension]);
          const orient = this.model.major_label_orientation;
          const standoff = extents.tick + this.model.major_label_standoff;
          const visuals = this.visuals.major_label_text;
          this._draw_oriented_labels(ctx, labels, coords, orient, this.panel.side, standoff, visuals);
      }
      _axis_label_extent() {
          if (this._axis_label_view == null)
              return 0;
          const axis_label_graphics = this._axis_label_view.graphics();
          const padding = 3;
          axis_label_graphics.visuals = this.visuals.axis_label_text.values();
          axis_label_graphics.angle = this.panel.get_label_angle_heuristic("parallel");
          if (isNumber(this.plot_view.base_font_size))
              axis_label_graphics.base_font_size = this.plot_view.base_font_size;
          const size = axis_label_graphics.size();
          const extent = this.dimension == 0 ? size.height : size.width;
          const standoff = this.model.axis_label_standoff;
          return extent > 0 ? standoff + extent + padding : 0;
      }
      _draw_axis_label(ctx, extents, _tick_coords) {
          if (this._axis_label_view == null || this.model.fixed_location != null)
              return;
          const [sx, sy] = (() => {
              const { bbox } = this.layout;
              switch (this.panel.side) {
                  case "above":
                      return [bbox.hcenter, bbox.bottom];
                  case "below":
                      return [bbox.hcenter, bbox.top];
                  case "left":
                      return [bbox.right, bbox.vcenter];
                  case "right":
                      return [bbox.left, bbox.vcenter];
              }
          })();
          const [nx, ny] = this.normals;
          const standoff = extents.tick + extents.tick_label + this.model.axis_label_standoff;
          const { vertical_align, align } = this.panel.get_label_text_heuristics("parallel");
          const position = {
              sx: sx + nx * standoff,
              sy: sy + ny * standoff,
              x_anchor: align,
              y_anchor: vertical_align,
          };
          const axis_label_graphics = this._axis_label_view.graphics();
          axis_label_graphics.visuals = this.visuals.axis_label_text.values();
          axis_label_graphics.angle = this.panel.get_label_angle_heuristic("parallel");
          if (this.plot_view.base_font_size != null)
              axis_label_graphics.base_font_size = this.plot_view.base_font_size;
          axis_label_graphics.position = position;
          axis_label_graphics.align = align;
          axis_label_graphics.paint(ctx);
      }
      _draw_ticks(ctx, coords, tin, tout, visuals) {
          if (!visuals.doit)
              return;
          const [x, y] = coords;
          const [sxs, sys] = this.coordinates.map_to_screen(x, y);
          const [nx, ny] = this.normals;
          const [xoff, yoff] = this.offsets;
          const [nxin, nyin] = [nx * (xoff - tin), ny * (yoff - tin)];
          const [nxout, nyout] = [nx * (xoff + tout), ny * (yoff + tout)];
          visuals.set_value(ctx);
          ctx.beginPath();
          for (let i = 0; i < sxs.length; i++) {
              const sx0 = Math.round(sxs[i] + nxout);
              const sy0 = Math.round(sys[i] + nyout);
              const sx1 = Math.round(sxs[i] + nxin);
              const sy1 = Math.round(sys[i] + nyin);
              ctx.moveTo(sx0, sy0);
              ctx.lineTo(sx1, sy1);
          }
          ctx.stroke();
      }
      _draw_oriented_labels(ctx, labels, coords, orient, _side, standoff, visuals) {
          if (!visuals.doit || labels.length == 0)
              return;
          const [dxs, dys] = coords;
          const [sxs, sys] = this.coordinates.map_to_screen(dxs, dys);
          const [xoff, yoff] = this.offsets;
          const [nx, ny] = this.normals;
          const nxd = nx * (xoff + standoff);
          const nyd = ny * (yoff + standoff);
          const { vertical_align, align } = this.panel.get_label_text_heuristics(orient);
          const angle = this.panel.get_label_angle_heuristic(orient);
          labels.visuals = visuals.values();
          labels.angle = angle;
          labels.base_font_size = this.plot_view.base_font_size;
          for (let i = 0; i < labels.length; i++) {
              const label = labels.items[i];
              label.position = {
                  sx: sxs[i] + nxd,
                  sy: sys[i] + nyd,
                  x_anchor: align,
                  y_anchor: vertical_align,
              };
              if (label instanceof TextBox)
                  label.align = align;
          }
          const n = labels.length;
          const indices = Indices.all_set(n);
          const { items } = labels;
          const bboxes = items.map((l) => l.bbox());
          const dist = (() => {
              const [range] = this.ranges;
              if (!range.is_reversed)
                  return this.dimension == 0 ? (i, j) => bboxes[j].left - bboxes[i].right
                      : (i, j) => bboxes[i].top - bboxes[j].bottom;
              else
                  return this.dimension == 0 ? (i, j) => bboxes[i].left - bboxes[j].right
                      : (i, j) => bboxes[j].top - bboxes[i].bottom;
          })();
          const { major_label_policy } = this.model;
          const selected = major_label_policy.filter(indices, bboxes, dist);
          const ids = [...selected.ones()];
          if (ids.length != 0) {
              const cbox = this.parent.canvas_view.bbox;
              const correct_x = (k) => {
                  const bbox = bboxes[k];
                  if (bbox.left < 0) {
                      const offset = -bbox.left;
                      const { position } = items[k];
                      items[k].position = { ...position, sx: position.sx + offset };
                  }
                  else if (bbox.right > cbox.width) {
                      const offset = bbox.right - cbox.width;
                      const { position } = items[k];
                      items[k].position = { ...position, sx: position.sx - offset };
                  }
              };
              const correct_y = (k) => {
                  const bbox = bboxes[k];
                  if (bbox.top < 0) {
                      const offset = -bbox.top;
                      const { position } = items[k];
                      items[k].position = { ...position, sy: position.sy + offset };
                  }
                  else if (bbox.bottom > cbox.height) {
                      const offset = bbox.bottom - cbox.height;
                      const { position } = items[k];
                      items[k].position = { ...position, sy: position.sy - offset };
                  }
              };
              const i = ids[0];
              const j = ids[ids.length - 1];
              if (this.dimension == 0) {
                  correct_x(i);
                  correct_x(j);
              }
              else {
                  correct_y(i);
                  correct_y(j);
              }
          }
          for (const i of selected) {
              const label = items[i];
              label.paint(ctx);
          }
      }
      // extents sub functions -----------------------------------------------------
      /*protected*/ _tick_extent() {
          return this.model.major_tick_out;
      }
      _tick_label_extents() {
          const coords = this.tick_coords.major;
          const labels = this.compute_labels(coords[this.dimension]);
          const orient = this.model.major_label_orientation;
          const standoff = this.model.major_label_standoff;
          const visuals = this.visuals.major_label_text;
          return [this._oriented_labels_extent(labels, orient, standoff, visuals)];
      }
      get extents() {
          const tick_labels = this._tick_label_extents();
          return {
              tick: this._tick_extent(),
              tick_labels,
              tick_label: sum(tick_labels),
              axis_label: this._axis_label_extent(),
          };
      }
      _oriented_labels_extent(labels, orient, standoff, visuals) {
          if (labels.length == 0 || !visuals.doit)
              return 0;
          const angle = this.panel.get_label_angle_heuristic(orient);
          labels.visuals = visuals.values();
          labels.angle = angle;
          labels.base_font_size = this.plot_view.base_font_size;
          const size = labels.max_size();
          const extent = this.dimension == 0 ? size.height : size.width;
          const padding = 3;
          return extent > 0 ? standoff + extent + padding : 0;
      }
      // {{{ TODO: state
      get normals() {
          return this.panel.normals;
      }
      get dimension() {
          return this.panel.dimension;
      }
      compute_labels(ticks) {
          const labels = this.model.formatter.format_graphics(ticks, this);
          const { _major_label_views } = this;
          const visited = new Set();
          for (let i = 0; i < ticks.length; i++) {
              const override = _major_label_views.get(ticks[i].toString());
              if (override != null) {
                  visited.add(override);
                  labels[i] = override.graphics();
              }
          }
          // XXX: make sure unused overrides don't prevent document idle
          for (const label_view of this._major_label_views.values()) {
              if (!visited.has(label_view)) {
                  label_view._has_finished = true;
              }
          }
          return new GraphicsBoxes(labels);
      }
      get offsets() {
          // If we have a fixed_position then we should respect that exactly and
          // not apply any offsets (https://github.com/bokeh/bokeh/issues/8552)
          if (this.model.fixed_location != null)
              return [0, 0];
          const { frame } = this.plot_view;
          let [xoff, yoff] = [0, 0];
          switch (this.panel.side) {
              case "below":
                  yoff = abs(this.layout.bbox.top - frame.bbox.bottom);
                  break;
              case "above":
                  yoff = abs(this.layout.bbox.bottom - frame.bbox.top);
                  break;
              case "right":
                  xoff = abs(this.layout.bbox.left - frame.bbox.right);
                  break;
              case "left":
                  xoff = abs(this.layout.bbox.right - frame.bbox.left);
                  break;
          }
          return [xoff, yoff];
      }
      get ranges() {
          const i = this.dimension;
          const j = (i + 1) % 2;
          const { ranges } = this.coordinates;
          return [ranges[i], ranges[j]];
      }
      get computed_bounds() {
          const [range] = this.ranges;
          const user_bounds = this.model.bounds;
          const range_bounds = [range.min, range.max];
          if (user_bounds == "auto")
              return [range.min, range.max];
          else {
              let start;
              let end;
              const [user_start, user_end] = user_bounds;
              const [range_start, range_end] = range_bounds;
              const { min, max } = Math;
              if (abs(user_start - user_end) > abs(range_start - range_end)) {
                  start = max(min(user_start, user_end), range_start);
                  end = min(max(user_start, user_end), range_end);
              }
              else {
                  start = min(user_start, user_end);
                  end = max(user_start, user_end);
              }
              return [start, end];
          }
      }
      get rule_coords() {
          const i = this.dimension;
          const j = (i + 1) % 2;
          const [range] = this.ranges;
          const [start, end] = this.computed_bounds;
          const xs = new Array(2);
          const ys = new Array(2);
          const 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] = NaN;
          coords[j][0] = this.loc;
          coords[j][1] = this.loc;
          return coords;
      }
      get tick_coords() {
          const i = this.dimension;
          const j = (i + 1) % 2;
          const [range] = this.ranges;
          const [start, end] = this.computed_bounds;
          const ticks = this.model.ticker.get_ticks(start, end, range, this.loc);
          const majors = ticks.major;
          const minors = ticks.minor;
          const xs = [];
          const ys = [];
          const coords = [xs, ys];
          const minor_xs = [];
          const minor_ys = [];
          const minor_coords = [minor_xs, minor_ys];
          const [range_min, range_max] = [range.min, range.max];
          for (let ii = 0; ii < majors.length; ii++) {
              if (majors[ii] < range_min || majors[ii] > range_max)
                  continue;
              coords[i].push(majors[ii]);
              coords[j].push(this.loc);
          }
          for (let ii = 0; ii < minors.length; ii++) {
              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,
          };
      }
      get loc() {
          const { fixed_location } = this.model;
          if (fixed_location != null) {
              if (isNumber(fixed_location))
                  return fixed_location;
              const [, cross_range] = this.ranges;
              if (cross_range instanceof FactorRange)
                  return cross_range.synthetic(fixed_location);
              unreachable();
          }
          const [, cross_range] = this.ranges;
          switch (this.panel.side) {
              case "left":
              case "below":
                  return cross_range.start;
              case "right":
              case "above":
                  return cross_range.end;
          }
      }
      // }}}
      serializable_state() {
          return {
              ...super.serializable_state(),
              bbox: this.layout.bbox.box,
          };
      }
      remove() {
          this._axis_label_view?.remove();
          for (const label_view of this._major_label_views.values()) {
              label_view.remove();
          }
          super.remove();
      }
      has_finished() {
          if (!super.has_finished())
              return false;
          if (this._axis_label_view != null) {
              if (!this._axis_label_view.has_finished())
                  return false;
          }
          for (const label_view of this._major_label_views.values()) {
              if (!label_view.has_finished())
                  return false;
          }
          return true;
      }
  }
  AxisView.__name__ = "AxisView";
  export class Axis extends GuideRenderer {
      constructor(attrs) {
          super(attrs);
      }
  }
  _a = Axis;
  Axis.__name__ = "Axis";
  (() => {
      _a.prototype.default_view = AxisView;
      _a.mixins([
          ["axis_", mixins.Line],
          ["major_tick_", mixins.Line],
          ["minor_tick_", mixins.Line],
          ["major_label_", mixins.Text],
          ["axis_label_", mixins.Text],
      ]);
      _a.define(({ Any, Int, Number, String, Ref, Dict, Tuple, Or, Nullable, Auto }) => ({
          bounds: [Or(Tuple(Number, Number), Auto), "auto"],
          ticker: [Ref(Ticker)],
          formatter: [Ref(TickFormatter)],
          axis_label: [Nullable(Or(String, Ref(BaseText))), null],
          axis_label_standoff: [Int, 5],
          major_label_standoff: [Int, 5],
          major_label_orientation: [Or(TickLabelOrientation, Number), "horizontal"],
          major_label_overrides: [Dict(Or(String, Ref(BaseText))), {}],
          major_label_policy: [Ref(LabelingPolicy), () => new AllLabels()],
          major_tick_in: [Number, 2],
          major_tick_out: [Number, 6],
          minor_tick_in: [Number, 0],
          minor_tick_out: [Number, 4],
          fixed_location: [Nullable(Or(Number, Any)), null],
      }));
      _a.override({
          axis_line_color: "black",
          major_tick_line_color: "black",
          minor_tick_line_color: "black",
          major_label_text_font_size: "11px",
          major_label_text_align: "center",
          major_label_text_baseline: "alphabetic",
          axis_label_text_font_size: "13px",
          axis_label_text_font_style: "italic",
      });
  })();
  //# sourceMappingURL=axis.js.map