A library for working with phylogenetic and population genetic data.
v0.32.0
svg/document.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2024 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
39 
40 namespace genesis {
41 namespace utils {
42 
43 // =================================================================================================
44 // Svg Document
45 // =================================================================================================
46 
47 // -------------------------------------------------------------
48 // Static Members
49 // -------------------------------------------------------------
50 
51 std::string SvgDocument::indentation_string = " ";
52 
53 // -------------------------------------------------------------
54 // Members
55 // -------------------------------------------------------------
56 
58 {
59  // Get bounding box of all elements and the dimensions of the document.
60  SvgBox bbox;
61  for( auto const& elem : content_ ) {
62  bbox = SvgBox::combine( bbox, elem.bounding_box() );
63  }
64  return bbox;
65 }
66 
70 void SvgDocument::write( std::ostream& out ) const
71 {
72  // Get a box around all elements, and use it to measure doc dimensions and shifting.
73  auto bbox = bounding_box();
74  double doc_width = margin.left + bbox.width() + margin.right;
75  double doc_height = margin.top + bbox.height() + margin.bottom;
76 
77  // SVG header.
78  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
79  out << "<svg";
80  out << svg_attribute( "xmlns", "http://www.w3.org/2000/svg" );
81  out << svg_attribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
82  out << svg_attribute( "width", doc_width );
83  out << svg_attribute( "height", doc_height );
84  out << svg_attribute(
85  "background-color", color_to_hex( background_color, "#", false, true )
86  );
87  // out << svg_attribute(
88  // "style", "background:" + color_to_hex( background_color, "#", false, true )
89  // );
90  if( overflow != Overflow::kNone ) {
91  out << overflow_to_string( overflow );
92  }
93  out << ">\n";
94 
95  // Some metadata.
96  out << svg_comment(
97  "Created with genesis " + genesis_version() + " (" + genesis_url() + ") " +
98  "on " + current_date() + " at " + current_time()
99  ) << "\n";
100  if( Options::get().command_line_string() != "" ) {
101  out << svg_comment( "Program invocation: " + Options::get().command_line_string() ) << "\n";
102  }
103 
104  // Gradients and other definitions. Need to come before the content.
105  if( ! defs.empty() ) {
106  out << SvgDocument::indentation_string << "<defs>\n";
107  for( auto const& def : defs ) {
108  def.write( out, 2 );
109  }
110  out << SvgDocument::indentation_string << "</defs>\n";
111  }
112 
113  // Options to hand over to all elements. Currently not needed, because we do the shifting
114  // for the margin by using a group (see immediately below).
115  auto options = SvgDrawingOptions();
116  // options.offset_x = margin.top;
117  // options.offset_y = margin.top;
118  // options.offset_x = margin.left - bbox.top_left.x;
119  // options.offset_y = margin.top - bbox.top_left.y;
120 
121  // Main group for all elements. We use this to make the handling of the margin
122  // easier.
123  out << SvgDocument::indentation_string << "<g transform=\"translate( ";
124  out << margin.left - bbox.top_left.x << ", " << margin.top - bbox.top_left.y;
125  out << ")\" >\n";
126 
127  // Different approach, use inner svg element instead of group.
128  // Didn't work well with some viewers.
129  // out << SvgDocument::indentation_string << "<svg";
130  // out << svg_attribute( "x", margin.left - bbox.top_left.x );
131  // out << svg_attribute( "y", margin.top - bbox.top_left.y );
132  // out << ">\n";
133 
134  // Print content.
135  for( auto const& elem : content_ ) {
136  elem.write( out, 2, options );
137 
138  // Draw bounding boxes around all elements, for testing purposes.
139  // auto bb = elem.bounding_box();
140  // SvgRect( bb.top_left, bb.size(), SvgStroke(), SvgFill( Color(), 0.0 ) ).write( out, 1 );
141  }
142 
143  // Close main grouping.
144  // out << SvgDocument::indentation_string << "</svg>\n";
145  out << SvgDocument::indentation_string << "</g>\n";
146 
147  // Finish.
148  out << "</svg>\n";
149 }
150 
151 void SvgDocument::write( std::shared_ptr<utils::BaseOutputTarget> target ) const
152 {
153  auto& os = target->ostream();
154  write( os );
155 }
156 
158 {
159  content_.push_back( object );
160  return *this;
161 }
162 
164 {
165  content_.push_back( std::move( object ));
166  return *this;
167 }
168 
170 {
171  return add( object );
172 }
173 
175 {
176  return add( std::move( object ));
177 }
178 
179 std::string SvgDocument::overflow_to_string( SvgDocument::Overflow value )
180 {
181  // switch( value ) {
182  // case Overflow::kNone:
183  // return std::string();
184  // case Overflow::kVisible:
185  // return svg_attribute( "style", "overflow: visible" );
186  // case Overflow::kHidden:
187  // return svg_attribute( "style", "overflow: hidden" );
188  // case Overflow::kScroll:
189  // return svg_attribute( "style", "overflow: scroll" );
190  // case Overflow::kAuto:
191  // return svg_attribute( "style", "overflow: auto" );
192  // case Overflow::kInherit:
193  // return svg_attribute( "style", "overflow: inherit" );
194  // default:
195  // throw std::invalid_argument(
196  // "Invalid Svg attribute Overflow for Svg Document."
197  // );
198  // }
199  switch( value ) {
200  case Overflow::kNone:
201  return std::string();
202  case Overflow::kVisible:
203  return svg_attribute( "overflow", "visible" );
204  case Overflow::kHidden:
205  return svg_attribute( "overflow", "hidden" );
206  case Overflow::kScroll:
207  return svg_attribute( "overflow", "scroll" );
208  case Overflow::kAuto:
209  return svg_attribute( "overflow", "auto" );
210  case Overflow::kInherit:
211  return svg_attribute( "overflow", "inherit" );
212  default:
213  throw std::invalid_argument(
214  "Invalid Svg attribute Overflow for Svg Document."
215  );
216  }
217 }
218 
219 } // namespace utils
220 } // namespace genesis
genesis::genesis_url
std::string genesis_url()
Return the URL of the genesis home page.
Definition: version.hpp:83
genesis::utils::SvgMargin::bottom
double bottom
Definition: utils/formats/svg/helper.hpp:119
helper.hpp
genesis::utils::SvgDocument::Overflow::kInherit
@ kInherit
genesis::utils::SvgBox::combine
static SvgBox combine(SvgBox const &lhs, SvgBox const &rhs)
Definition: utils/formats/svg/helper.hpp:181
genesis::utils::current_date
std::string current_date()
Returns the current date as a string in the format "2014-12-31".
Definition: date_time.cpp:68
genesis::utils::SvgDocument::margin
SvgMargin margin
Definition: svg/document.hpp:122
date_time.hpp
Provides functions for date and time access.
genesis::utils::svg_comment
std::string svg_comment(std::string const &content)
Definition: utils/formats/svg/helper.hpp:223
genesis::utils::SvgMargin::top
double top
Definition: utils/formats/svg/helper.hpp:117
version.hpp
Some stuff that is totally not imporatant, but nice.
genesis::utils::SvgBox
Definition: utils/formats/svg/helper.hpp:127
genesis::utils::current_time
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:88
genesis::utils::SvgDocument::write
void write(std::ostream &out) const
Write the SvgDocument to an output stream.
Definition: svg/document.cpp:70
genesis::utils::SvgDocument::overflow
Overflow overflow
Definition: svg/document.hpp:123
genesis::utils::SvgDocument::indentation_string
static std::string indentation_string
Definition: svg/document.hpp:60
string.hpp
Provides some commonly used string utility functions.
document.hpp
genesis::utils::SvgDocument::operator<<
self_type & operator<<(SvgObject const &object)
Shortcut operator for add(), which allows an even more fluent interface.
Definition: svg/document.cpp:169
genesis::utils::SvgDocument::add
self_type & add(SvgObject const &object)
Add an SvgObject to the document.
Definition: svg/document.cpp:157
genesis::utils::SvgDocument::background_color
Color background_color
Definition: svg/document.hpp:126
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
functions.hpp
Color operators and functions.
genesis::utils::SvgMargin::right
double right
Definition: utils/formats/svg/helper.hpp:118
genesis::utils::svg_attribute
std::string svg_attribute(std::string const &name, T const &value, std::string const &unit="")
Definition: utils/formats/svg/helper.hpp:229
genesis::utils::SvgDocument::Overflow::kAuto
@ kAuto
genesis::utils::SvgDocument
Definition: svg/document.hpp:50
genesis::utils::SvgDocument::defs
std::vector< SvgDefinitions > defs
Definition: svg/document.hpp:125
options.hpp
genesis::utils::SvgDocument::Overflow::kNone
@ kNone
genesis::utils::SvgDocument::bounding_box
SvgBox bounding_box() const
Definition: svg/document.cpp:57
genesis::utils::SvgDocument::Overflow::kVisible
@ kVisible
genesis::genesis_version
std::string genesis_version()
Return the current genesis version.
Definition: version.hpp:63
genesis::utils::Options::get
static Options & get()
Returns a single instance of this class.
Definition: options.hpp:68
genesis::utils::SvgDrawingOptions
Definition: utils/formats/svg/helper.hpp:213
genesis::utils::color_to_hex
std::string color_to_hex(Color const &c, std::string const &prefix, bool uppercase, bool with_alpha)
Return a hex string representation of a Color in the format "#003366[ff]".
Definition: utils/color/functions.cpp:100
genesis::utils::SvgObject
Definition: object.hpp:46
genesis::utils::SvgDocument::Overflow::kScroll
@ kScroll
genesis::utils::SvgDocument::Overflow
Overflow
Definition: svg/document.hpp:62
genesis::utils::SvgMargin::left
double left
Definition: utils/formats/svg/helper.hpp:120
genesis::utils::SvgDocument::Overflow::kHidden
@ kHidden