Commit f9925813 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

update axis drawing code to immediate mode rendering

parent db421b32
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -13,15 +13,28 @@

namespace signaltk {

enum class TextHAlign {
  LEFT, CENTER, RIGHT
};

enum class TextVAlign {
  TOP, CENTER, BOTTOM
};

struct TextStyle {
  TextStyle();
  TextHAlign halign;
  TextVAlign valign;
  double font_size;
};

void drawText(
    Layer* layer,
    const std::string& text,
    const TextStyle& text_style,
    double x,
    double y,
    const std::string& halign,
    const std::string& valign,
    const std::string& class_name,
    double rotate = 0.0f);
    Layer* layer);


} // namespace signaltk
+45 −273
Original line number Diff line number Diff line
@@ -59,300 +59,72 @@ bool AxisDefinition::hasTitle() const {
  return title_.length() > 0;
}

/*
void renderAxes(Layer* target, Viewport* viewport) {
  std::tuple<int, int, int, int> padding = viewport->padding();
  std::vector<std::pair<int, AxisDefinition*>> top;
  std::vector<std::pair<int, AxisDefinition*>> right;
  std::vector<std::pair<int, AxisDefinition*>> bottom;
  std::vector<std::pair<int, AxisDefinition*>> left;

  for (const auto& axis : axes_) {
    switch (axis->getPosition()) {

      case AxisDefinition::TOP: {
        top.emplace_back(std::get<0>(padding), axis.get());
        std::get<0>(padding) += kAxisPadding;
        std::get<0>(padding) += axis->hasLabels() ? kAxisLabelHeight : 0;
        std::get<0>(padding) += axis->hasTitle() ? kAxisTitleLength : 0;
        break;
void renderAxisVertical(
    const AxisDefinition& axis_config,
    double x,
    double y0,
    double y1,
    Layer* target) {
  /* draw axis line */ 
  {
    StrokeStyle style;
    strokeLine(target, x, y0, x, y1, style);
  }

      case AxisDefinition::RIGHT: {
        right.emplace_back(std::get<1>(padding), axis.get());
        std::get<1>(padding) += kAxisPadding;
        std::get<1>(padding) += axis->hasLabels() ? kAxisLabelWidth : 0;
        std::get<1>(padding) += axis->hasTitle() ? kAxisTitleLength : 0;
  double label_placement = 0;
  switch (axis_config.label_placement) {
    case AxisDefinition::LABELS_RIGHT:
      label_placement = 1;
      break;
      }

      case AxisDefinition::BOTTOM: {
        bottom.emplace_back(std::get<2>(padding), axis.get());
        std::get<2>(padding) += kAxisPadding;
        std::get<2>(padding) += axis->hasLabels() ? kAxisLabelHeight : 0;
        std::get<2>(padding) += axis->hasTitle() ? kAxisTitleLength : 0;
    case AxisDefinition::LABELS_LEFT:
      label_placement = -1;
      break;
      }

      case AxisDefinition::LEFT: {
        left.emplace_back(std::get<3>(padding), axis.get());
        std::get<3>(padding) += kAxisPadding;
        std::get<3>(padding) += axis->hasLabels() ? kAxisLabelWidth : 0;
        std::get<3>(padding) += axis->hasTitle() ? kAxisTitleLength : 0;
    default:
      break;
  }

    }
  }

  if (std::get<0>(padding) < kAxisLabelHeight * 0.5f) {
    std::get<0>(padding) += kAxisLabelHeight * 0.5f;
  }

  if (std::get<1>(padding) < kAxisLabelWidth * 0.5f) {
    std::get<1>(padding) += kAxisLabelWidth * 0.5f;
  }

  if (std::get<2>(padding) < kAxisLabelHeight * 0.5f) {
    std::get<2>(padding) += kAxisLabelHeight * 0.5f;
  }

  if (std::get<3>(padding) < kAxisLabelWidth * 0.5f) {
    std::get<3>(padding) += kAxisLabelWidth * 0.5f;
  }

  viewport->setPadding(padding);

  for (const auto& placement : top) {
    renderTopAxis(target, viewport, placement.second, placement.first);
  }

  for (const auto& placement : right) {
    renderRightAxis(target, viewport, placement.second, placement.first);
  }

  for (const auto& placement : bottom) {
    renderBottomAxis(target, viewport, placement.second, placement.first);
  }

  for (const auto& placement : left) {
    renderLeftAxis(target, viewport, placement.second, placement.first);
  }
}

*/

void renderTopAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int top) {
  StrokeStyle style;

  int padding_left = viewport->paddingLeft();
  int inner_width = viewport->innerWidth();

  top += kAxisPadding;

  /* draw title */
  if (axis->hasTitle()) {
    drawText(target,
        axis->getTitle(),
        padding_left + inner_width* 0.5f,
        top,
        "middle",
        "text-before-edge",
        "title");

    top += kAxisTitleLength;
  }

  /* draw labels */
  if (axis->hasLabels()) {
    top += kAxisLabelHeight; // FIXPAUL: calculate label width?

    for (const auto& label : axis->getLabels()) {
      auto tick_x = padding_left + inner_width * label.first;

      drawText(target,
          label.second,
          tick_x,
          top - kAxisLabelHeight * 0.5f,
          "middle",
          "central",
          "label");
    }
  }

  /* draw ticks */
  for (const auto& tick : axis->getTicks()) {
    auto tick_x = padding_left + inner_width * tick;

    strokeLine(target,
        tick_x,
        top,
        tick_x,
        top + kTickLength,
        style);
  }

  /* draw stroke */
  strokeLine(target,
      padding_left,
      top,
      padding_left + inner_width,
      top,
      style);

}


void renderRightAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int right) {
  StrokeStyle style;

  int padding_top = viewport->paddingTop();
  int inner_height = viewport->innerHeight();

  right += kAxisPadding;

  /* draw title */
  if (axis->hasTitle()) {
    right += kAxisTitleLength;
    drawText(target,
        axis->getTitle(),
        viewport->width_ - right,
        padding_top + inner_height * 0.5f,
        "middle",
        "text-before-edge",
        "title",
        270);
  }

  /* draw labels */
  if (axis->hasLabels()) {
    right += kAxisLabelWidth; // FIXPAUL: calculate label width?

    for (const auto& label : axis->getLabels()) {
      auto tick_y = padding_top + inner_height * (1.0 - label.first);

      drawText(target,
          label.second,
          viewport->width_ - right + (kTickLength * 2),
          tick_y,
          "start",
          "middle",
          "label");
    }
  }

  /* draw ticks */
  for (const auto& tick : axis->getTicks()) {
    auto tick_y = padding_top + inner_height * (1.0 - tick);

    strokeLine(target,
        viewport->width_ - right,
        tick_y,
        viewport->width_ - right - kTickLength,
        tick_y,
        style);
  }

  /* draw stroke */
  strokeLine(target,
      viewport->width_ - right,
      padding_top,
      viewport->width_ - right,
      padding_top + inner_height,
      style);

}

void renderBottomAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int bottom) {
  for (const auto& tick : axis_config.getTicks()) {
    auto y = y0 + (y1 - y0) * tick;
    StrokeStyle style;

  int padding_left = viewport->paddingLeft();
  int inner_width = viewport->innerWidth();

  bottom += kAxisPadding;

  /* draw title */
  if (axis->hasTitle()) {
    drawText(target,
        axis->getTitle(),
        padding_left + inner_width* 0.5f,
        viewport->height_ - bottom,
        "middle",
        "no-change",
        "title");

    bottom += kAxisTitleLength;
    strokeLine(target, x, y, x + kTickLength * label_placement, y, style);
  }

  /* draw labels */
  if (axis->hasLabels()) {
    bottom += kAxisLabelHeight; // FIXPAUL: calculate label width?

    for (const auto& label : axis->getLabels()) {
      auto tick_x = padding_left + inner_width * label.first;

      drawText(target,
          label.second,
          tick_x,
          viewport->height_ - bottom + kAxisLabelHeight * 0.5f,
          "middle",
          "central",
          "label");
    }
  }

  /* draw ticks */
  for (const auto& tick : axis->getTicks()) {
    auto tick_x = padding_left + inner_width * tick;
  for (const auto& label : axis_config.getLabels()) {
    auto [ tick, label_text ] = label;
    auto y = y0 + (y1 - y0) * tick;

    strokeLine(target,
        tick_x,
        viewport->height_ - bottom,
        tick_x,
        viewport->height_ - bottom - kTickLength,
        style);
    TextStyle style;
    style.halign = TextHAlign::LEFT;
    style.valign = TextVAlign::TOP;
    drawText(
        label_text,
        style,
        x,
        y,
        target);
  }

  /* draw stroke */
  strokeLine(target,
      padding_left,
      viewport->height_ - bottom,
      padding_left + inner_width,
      viewport->height_ - bottom,
      style);

}

void renderAxisVertical(
void renderAxisHorizontal(
    const AxisDefinition& axis_config,
    double x,
    double y0,
    double y1,
    double y,
    double x0,
    double x1,
    Layer* target) {
  /* draw axis line */ 
  {
    StrokeStyle style;
    strokeLine(target, x, y0, x, y1, style);
    strokeLine(target, x0, y, x1, y, style);
  }

  double label_placement = 0;
  switch (axis_config.label_placement) {
    case AxisDefinition::LABELS_RIGHT:
    case AxisDefinition::LABELS_BOTTOM:
      label_placement = 1;
      break;
    case AxisDefinition::LABELS_LEFT:
    case AxisDefinition::LABELS_TOP:
      label_placement = -1;
      break;
    default:
@@ -361,9 +133,9 @@ void renderAxisVertical(

  /* draw ticks */
  for (const auto& tick : axis_config.getTicks()) {
    auto y = y0 + (y1 - y0) * tick;
    auto x = x0 + (x1 - x0) * tick;
    StrokeStyle style;
    strokeLine(target, x, y, x + kTickLength * label_placement, y, style);
    strokeLine(target, x, y, x, y + kTickLength * label_placement, style);
  }
}

+8 −54
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ struct AxisDefinitions {
};

/**
 * Render the axes
 * Render a vertical axis
 */
void renderAxisVertical(
    const AxisDefinition& axis_config,
@@ -142,60 +142,14 @@ void renderAxisVertical(
    Layer* target);

/**
 * Render a top axis
 *
 * @param target the render target
 * @param axis the axis definition
 * @param padding the padding state
 * @param top the top padding for this axis
 */
void renderTopAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int top);

/**
 * Render a right axis
 *
 * @param target the render target
 * @param axis the axis definition
 * @param padding the padding state
 * @param right the right padding for this axis
 */
void renderRightAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int right);

/**
 * Render a bottom axis
 *
 * @param target the render target
 * @param axis the axis definition
 * @param padding the padding state
 * @param bottom the bottom padding for this axis
 * Render a horizontal axis
 */
void renderBottomAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int bottom);

/**
 * Render a left axis
 *
 * @param target the render target
 * @param axis the axis definition
 * @param padding the padding state
 * @param left the left padding for this axis
 */
void renderLeftAxis(
    Layer* target,
    Viewport* viewport,
    AxisDefinition* axis,
    int left);
void renderAxisHorizontal(
    const AxisDefinition& axis_config,
    double y,
    double x0,
    double x1,
    Layer* target);

} // namespace chart
} // namespace signaltk
+52 −17
Original line number Diff line number Diff line
@@ -13,51 +13,86 @@ using namespace signaltk;
using namespace signaltk::chart;

int main(int argc, char** argv) {
  Layer target(1000, 600);
  Layer target(1200, 800);
  target.clear(Colour{1, 1, 1, 1});

  double padding = 20;
  double padding = 80;

  // draw left axis
  {
    AxisDefinition axis;
    axis.label_placement = AxisDefinition::LABELS_RIGHT;
    axis.label_placement = AxisDefinition::LABELS_LEFT;
    axis.addTick(0.0);
    axis.addTick(0.2);
    axis.addTick(0.4);
    axis.addTick(0.6);
    axis.addTick(0.8);
    axis.addTick(1.0);
    axis.addLabel(0.0, "asd");
    axis.addLabel(0.2, "blah");
    axis.addLabel(0.4, "xxx");
    axis.addLabel(0.6, "d");
    axis.addLabel(0.8, "e");
    axis.addLabel(1.0, "f");
    renderAxisVertical(axis, padding, padding, target.height - padding, &target);
  }

  // draw right axis
  {
    AxisDefinition axis;
    axis.label_placement = AxisDefinition::LABELS_LEFT;
    axis.label_placement = AxisDefinition::LABELS_RIGHT;
    axis.addTick(0.0);
    axis.addTick(0.2);
    axis.addTick(0.4);
    axis.addTick(0.6);
    axis.addTick(0.8);
    axis.addTick(1.0);
    axis.addLabel(0.0, "a");
    axis.addLabel(0.2, "b");
    axis.addLabel(0.4, "c");
    axis.addLabel(0.6, "d");
    axis.addLabel(0.8, "e");
    axis.addLabel(1.0, "f");
    renderAxisVertical(axis, target.width - padding, padding, target.height - padding, &target);
  }

  //axis_left->setTitle("my axis");
  //axis_left->addTick(0.0);
  //axis_left->addTick(0.2);
  //axis_left->addTick(0.4);
  //axis_left->addTick(0.6);
  //axis_left->addTick(0.8);
  //axis_left->addTick(1.0);
  //axis_left->addLabel(0.0, "0");
  //axis_left->addLabel(0.2, "1");
  //axis_left->addLabel(0.4, "2");
  //axis_left->addLabel(0.6, "3");
  //axis_left->addLabel(0.8, "4");
  //axis_left->addLabel(1.0, "5");
  // draw top axis
  {
    AxisDefinition axis;
    axis.label_placement = AxisDefinition::LABELS_TOP;
    axis.addTick(0.0);
    axis.addTick(0.2);
    axis.addTick(0.4);
    axis.addTick(0.6);
    axis.addTick(0.8);
    axis.addTick(1.0);
    axis.addLabel(0.0, "a");
    axis.addLabel(0.2, "b");
    axis.addLabel(0.4, "c");
    axis.addLabel(0.6, "d");
    axis.addLabel(0.8, "e");
    axis.addLabel(1.0, "f");
    renderAxisHorizontal(axis, padding, padding, target.width - padding, &target);
  }

  // draw bottom axis
  {
    AxisDefinition axis;
    axis.label_placement = AxisDefinition::LABELS_BOTTOM;
    axis.addTick(0.0);
    axis.addTick(0.2);
    axis.addTick(0.4);
    axis.addTick(0.6);
    axis.addTick(0.8);
    axis.addTick(1.0);
    axis.addLabel(0.0, "a");
    axis.addLabel(0.2, "b");
    axis.addLabel(0.4, "c");
    axis.addLabel(0.6, "d");
    axis.addLabel(0.8, "e");
    axis.addLabel(1.0, "f");
    renderAxisHorizontal(axis, target.height - padding, padding, target.width - padding, &target);
  }

  target.writePNG(std::string(argv[0]) + ".png");
}