A toolkit for working with phylogenetic data.
v0.19.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
svg/document.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 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 <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
38 
39 namespace genesis {
40 namespace utils {
41 
42 // =================================================================================================
43 // Svg Document
44 // =================================================================================================
45 
46 // -------------------------------------------------------------
47 // Static Members
48 // -------------------------------------------------------------
49 
50 std::string SvgDocument::indentation_string = " ";
51 
52 // -------------------------------------------------------------
53 // Members
54 // -------------------------------------------------------------
55 
57 {
58  // Get bounding box of all elements and the dimensions of the document.
59  SvgBox bbox;
60  for( auto const& elem : content_ ) {
61  bbox = SvgBox::combine( bbox, elem.bounding_box() );
62  }
63  return bbox;
64 }
65 
69 void SvgDocument::write( std::ostream& out ) const
70 {
71  // Get a box around all elements, and use it to measure doc dimensions and shifting.
72  auto bbox = bounding_box();
73  double doc_width = margin.left + bbox.width() + margin.right;
74  double doc_height = margin.top + bbox.height() + margin.bottom;
75 
76  // SVG header.
77  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
78  out << "<svg";
79  out << svg_attribute( "xmlns", "http://www.w3.org/2000/svg" );
80  out << svg_attribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
81  out << svg_attribute( "width", doc_width );
82  out << svg_attribute( "height", doc_height );
83  if( overflow != Overflow::kNone ) {
84  out << overflow_to_string( overflow );
85  }
86  out << ">\n";
87 
88  // Some metadata.
89  out << svg_comment(
90  "Created with genesis " + genesis_version() + " (" + genesis_url() + ") " +
91  "on " + current_date() + " at " + current_time()
92  ) << "\n";
93  if( Options::get().command_line_string() != "" ) {
94  out << svg_comment( "Program invocation: " + Options::get().command_line_string() ) << "\n";
95  }
96 
97  // Gradients and other definitions. Need to come before the content.
98  if( ! defs.empty() ) {
99  out << SvgDocument::indentation_string << "<defs>\n";
100  for( auto const& def : defs ) {
101  def.write( out, 2 );
102  }
103  out << SvgDocument::indentation_string << "</defs>\n";
104  }
105 
106  // Options to hand over to all elements. Currently not needed, because we do the shifting
107  // for the margin by using a group (see immediately below).
108  auto options = SvgDrawingOptions();
109  // options.offset_x = margin.top;
110  // options.offset_y = margin.top;
111  // options.offset_x = margin.left - bbox.top_left.x;
112  // options.offset_y = margin.top - bbox.top_left.y;
113 
114  // Main group for all elements. We use this to make the handling of the margin
115  // easier.
116  out << SvgDocument::indentation_string << "<g transform=\"translate( ";
117  out << margin.left - bbox.top_left.x << ", " << margin.top - bbox.top_left.y;
118  out << ")\" >\n";
119 
120  // Different approach, use inner svg element instead of group.
121  // Didn't work well with some viewers.
122  // out << SvgDocument::indentation_string << "<svg";
123  // out << svg_attribute( "x", margin.left - bbox.top_left.x );
124  // out << svg_attribute( "y", margin.top - bbox.top_left.y );
125  // out << ">\n";
126 
127  // Print content.
128  for( auto const& elem : content_ ) {
129  elem.write( out, 2, options );
130 
131  // Draw bounding boxes around all elements, for testing purposes.
132  // auto bb = elem.bounding_box();
133  // SvgRect( bb.top_left, bb.size(), SvgStroke(), SvgFill( Color(), 0.0 ) ).write( out, 1 );
134  }
135 
136  // Close main grouping.
137  // out << SvgDocument::indentation_string << "</svg>\n";
138  out << SvgDocument::indentation_string << "</g>\n";
139 
140  // Finish.
141  out << "</svg>\n";
142 }
143 
145 {
146  content_.push_back( object );
147  return *this;
148 }
149 
151 {
152  content_.push_back( std::move( object ));
153  return *this;
154 }
155 
157 {
158  return add( object );
159 }
160 
162 {
163  return add( std::move( object ));
164 }
165 
166 std::string SvgDocument::overflow_to_string( SvgDocument::Overflow value )
167 {
168  // switch( value ) {
169  // case Overflow::kNone:
170  // return std::string();
171  // case Overflow::kVisible:
172  // return svg_attribute( "style", "overflow: visible" );
173  // case Overflow::kHidden:
174  // return svg_attribute( "style", "overflow: hidden" );
175  // case Overflow::kScroll:
176  // return svg_attribute( "style", "overflow: scroll" );
177  // case Overflow::kAuto:
178  // return svg_attribute( "style", "overflow: auto" );
179  // case Overflow::kInherit:
180  // return svg_attribute( "style", "overflow: inherit" );
181  // default:
182  // throw std::invalid_argument(
183  // "Invalid Svg attribute Overflow for Svg Document."
184  // );
185  // }
186  switch( value ) {
187  case Overflow::kNone:
188  return std::string();
189  case Overflow::kVisible:
190  return svg_attribute( "overflow", "visible" );
191  case Overflow::kHidden:
192  return svg_attribute( "overflow", "hidden" );
193  case Overflow::kScroll:
194  return svg_attribute( "overflow", "scroll" );
195  case Overflow::kAuto:
196  return svg_attribute( "overflow", "auto" );
197  case Overflow::kInherit:
198  return svg_attribute( "overflow", "inherit" );
199  default:
200  throw std::invalid_argument(
201  "Invalid Svg attribute Overflow for Svg Document."
202  );
203  }
204 }
205 
206 } // namespace utils
207 } // namespace genesis
static SvgBox combine(SvgBox const &lhs, SvgBox const &rhs)
std::string current_date()
Returns the current date as a string in the format "2014-12-31".
Definition: date_time.cpp:39
std::string genesis_url()
Return the URL of the genesis home page.
Definition: version.hpp:82
std::vector< SvgDefinitions > defs
std::string svg_attribute(std::string const &name, T const &value, std::string const &unit="")
std::string svg_comment(std::string const &content)
self_type & add(SvgObject const &object)
Add an SvgObject to the document.
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:51
void write(std::ostream &out) const
Write the SvgDocument to an output stream.
Provides some commonly used string utility functions.
SvgBox bounding_box() const
Provides functions for date and time access.
self_type & operator<<(SvgObject const &object)
Shortcut operator for add(), which allows an even more fluent interface.
static std::string indentation_string
static Options & get()
Returns a single instance of this class.
Definition: options.hpp:59
Some stuff that is totally not imporatant, but nice.
std::string genesis_version()
Return the current genesis version.
Definition: version.hpp:62