Commit 7733808a authored by Paul Asmuth's avatar Paul Asmuth
Browse files

move the legend item drawing code into a new 'legend/item' element

parent 83975b8f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include "elements/plot/points.h"
#include "elements/chart/scatterplot.h"
#include "elements/layout/box.h"
#include "elements/legend/item.h"

#include <iostream>
#include <string.h>
@@ -62,6 +63,7 @@ fviz_t* fviz_init() {
  element_bind(elems, "plot/labels", bind(elements::plot::labels::build, _1, _2, _3));
  element_bind(elems, "plot/lines", bind(elements::plot::lines::build, _1, _2, _3));
  element_bind(elems, "plot/points", bind(elements::plot::points::build, _1, _2, _3));
  element_bind(elems, "legend/item", bind(elements::legend::item::build, _1, _2, _3));
  element_bind(elems, "text", bind(elements::text::build, _1, _2, _3));
  return ctx.release();
}
+206 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "item.h"

#include "data.h"
#include "environment.h"
#include "marker.h"
#include "layout.h"
#include "scale.h"
#include "sexpr.h"
#include "sexpr_conv.h"
#include "sexpr_util.h"
#include "graphics/path.h"
#include "graphics/brush.h"
#include "graphics/text.h"
#include "graphics/layout.h"

using namespace std::placeholders;

namespace fviz::elements::legend::item {

struct LegendItemElem {
  std::string label;
  HAlign label_align;
  Measure label_margin;
  Color label_color;
  FontInfo label_font;
  Measure label_font_size;
  Marker marker;
  HAlign marker_align;
  Measure marker_margin;
  Color marker_color;
  Measure marker_size;
};

ReturnCode draw_label(
    const LegendItemElem& config,
    const LayoutInfo& layout,
    Layer* layer) {
  const auto& bbox = layout.content_box;
  const auto& text = config.label;

  TextStyle style;
  style.font = config.label_font;
  style.color = config.label_color;
  style.font_size = config.label_font_size;

  Point p;
  auto ax = HAlign::CENTER;
  auto ay = VAlign::CENTER;

  switch (config.label_align) {
    case HAlign::LEFT:
      ax = HAlign::LEFT;
      p.x = bbox.x + config.label_margin;
      p.y = bbox.y + bbox.h * 0.5;
      break;
    case HAlign::RIGHT:
      ax = HAlign::RIGHT;
      p.x = bbox.x + bbox.w - config.label_margin;
      p.y = bbox.y + bbox.h * 0.5;
      break;
  }

  if (auto rc = drawTextLabel(text, p, ax, ay, style, layer); !rc) {
    return rc;
  }

  return OK;
}

ReturnCode draw_marker(
    const LegendItemElem& config,
    const LayoutInfo& layout,
    Layer* layer) {
  const auto& bbox = layout.content_box;

  Point p;
  switch (config.marker_align) {
    case HAlign::LEFT:
      p.x = bbox.x + config.marker_margin;
      p.y = bbox.y + bbox.h * 0.5;
      break;
    case HAlign::RIGHT:
      p.x = bbox.x + bbox.w - config.marker_margin;
      p.y = bbox.y + bbox.h * 0.5;
      break;
  }

  const auto& s = config.marker_size;
  const auto& c = config.marker_color;
  if (auto rc = config.marker(p, s, c, layer); !rc) {
    return rc;
  }

  return OK;
}

ReturnCode draw(
    std::shared_ptr<LegendItemElem> config,
    const LayoutInfo& layout,
    Layer* layer) {
  /* convert units */
  convert_unit_typographic(
      layer->dpi,
      layer->font_size,
      &config->label_font_size);

  convert_unit_typographic(
      layer->dpi,
      config->label_font_size,
      &config->label_margin);

  convert_unit_typographic(
      layer->dpi,
      layer->font_size,
      &config->marker_size);

  convert_unit_typographic(
      layer->dpi,
      config->label_font_size,
      &config->marker_margin);

  /* draw label */
  if (auto rc = draw_label(*config, layout, layer); !rc) {
    return rc;
  }

  /* draw marker */
  if (auto rc = draw_marker(*config, layout, layer); !rc) {
    return rc;
  }

  return OK;
}

ReturnCode build(
    const Environment& env,
    const Expr* expr,
    ElementRef* elem) {
  /* inherit defaults */
  auto config = std::make_shared<LegendItemElem>();
  config->label_align = HAlign::LEFT;
  config->label_margin = from_em(2);
  config->label_font = env.font;
  config->label_font_size = env.font_size;
  config->label_color = env.text_color;
  config->marker_align = HAlign::LEFT;
  config->marker_margin = from_em(1);
  config->marker_size = env.font_size;
  config->marker_size.value *= 0.75;
  config->marker_color = env.text_color;

  /* parse exprerties */
  auto config_rc = expr_walk_map(expr_next(expr), {
    {"label", bind(&expr_to_string, _1, &config->label)},
    {
      "label-align",
      expr_to_enum_fn<HAlign>(&config->label_align, {
        {"left", HAlign::LEFT},
        {"right", HAlign::RIGHT},
      })
    },
    {"label-margin", bind(&expr_to_measure, _1, &config->label_margin)},
    {"label-color", bind(&expr_to_color, _1, &config->label_color)},
    {"label-font-size", bind(&expr_to_measure, _1, &config->label_font_size)},
    {"marker-shape", bind(&marker_configure, _1, &config->marker)},
    {
      "marker-align",
      expr_to_enum_fn<HAlign>(&config->marker_align, {
        {"left", HAlign::LEFT},
        {"right", HAlign::RIGHT},
      })
    },
    {"marker-margin", bind(&expr_to_measure, _1, &config->marker_margin)},
    {"marker-color", bind(&expr_to_color, _1, &config->marker_color)},
    {"marker-size", bind(&expr_to_measure, _1, &config->marker_size)},
    {"color", bind(&expr_to_color, _1, &config->marker_color)},
  });

  if (!config_rc) {
    return config_rc;
  }

  if (!config->marker) {
    config->marker = marker_create_disk();
  }

  *elem = std::make_shared<Element>();
  (*elem)->draw = bind(&draw, config, _1, _2);
  return OK;
}

} // namespace fviz::elements::legend::item

elements/legend/item.h

0 → 100644
+25 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once
#include "element.h"

namespace fviz::elements::legend::item {

ReturnCode build(
    const Environment& env,
    const Expr* expr,
    ElementRef* elem);

} // namespace fviz::elements::legend::item
+99 −0
Original line number Diff line number Diff line
name: legend/item
desc: |
  The `legend/item` element is used to draw a legend item.

reference: |
  (legend/item <options>)

option_summary: true

properties:
  - title: "Label Options"
    anchor: label-options
    properties:
      - name: label
        desc: |
          Set the label text.
        desc_code: |
          label <value>
        examples: |
          ;; set the label to 'Hello World'
          label "Hello World"
      - name: label-align
        desc: |
          Set the label alignment.
        desc_code: |
          label-align [left|right]
        examples: |
          ;; set the label alignment to left
          label-align left
      - name: label-margin
        desc: |
          Set the label margin/spacing. See the [measure](#FIXME) page for more details on valid values.
        desc_code: |
          label-margin <measure>
        examples: |
          ;; set the label margin to 2em
          label-margin 2em
      - name: label-font-size
        desc: |
          Set the label font size. See the [measure](#FIXME) page for more details on valid values.
        desc_code: |
          label-font-size <measure>
        examples: |
          ;; set the label font size to 14pt
          label-font-size 14pt
      - name: label-color
        desc: |
          Set the label color. See the [color](#FIXME) page for more details on valid values.
        desc_code: |
          label-color <color>
        examples: |
          ;; set the label color to grey
          label-color #eee

  - title: "Marker Options"
    anchor: marker-options
    properties:
      - name: marker-shape
        desc: |
          Set the marker shape.
        desc_code: |
          marker <marker-shape>
        examples: |
          ;; set the marker shape to hexagon
          marker-shape (hexagon)
      - name: marker-align
        desc: |
          Set the marker alignment.
        desc_code: |
          marker-align [left|right]
        examples: |
          ;; set the marker alignment to left
          marker-align left
      - name: marker-margin
        desc: |
          Set the marker margin/spacing. See the [measure](#FIXME) page for more details on valid values.
        desc_code: |
          marker-margin <measure>
        examples: |
          ;; set the marker margin to 2em
          marker-margin 2em
      - name: marker-size
        desc: |
          Set the marker size. See the [measure](#FIXME) page for more details on valid values.
        desc_code: |
          marker-size <measure>
        examples: |
          ;; set the marker size to 14pt
          marker-size 14pt
      - name: marker-color
        desc: |
          Set the marker color. See the [color](#FIXME) page for more details on valid values.
        desc_code: |
          marker-color <color>
        examples: |
          ;; set the marker color to grey
          marker-color #eee
      - name: color
        alias: marker-color
+7 −0
Original line number Diff line number Diff line
@@ -149,6 +149,13 @@ documentation:
            title: "plot/grid"
            url: "/documentation/elements/plot/grid"
            api_ref: true
      -
        section_title: "Legends"
        pages:
          -
            title: "legend/item"
            url: "/documentation/elements/legend/item"
            api_ref: true

  -
    title: "Community"
Loading