izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg-elements.h
Go to the documentation of this file.
1// svg elements -*- mode: C++ -*-
2
3// Copyright (C) 2014-2025 Benjamin De Kosnik <b.dekosnik@gmail.com>
4
5// This file is part of the alpha60-MiL SVG library. This library is
6// free software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the Free
8// Software Foundation; either version 3, or (at your option) any
9// later version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15
16#ifndef MiL_SVG_ELEMENTS_H
17#define MiL_SVG_ELEMENTS_H 1
18
19
20namespace svg {
21
22/**
23 @defgroup elements SVG Elements
24 @brief All svg components are derived from element_base as per
25 [hierarchy](https://bdekoz.github.io/izzi/html/structsvg_1_1element__base__inherit__graph_org.svg "svg elements")
26
27 @{
28*/
29
30/// Abstract base class for all SVG Elements.
32{
33 using stream_type = std::ostringstream;
34 static constexpr const char* finish_tag = " >";
35 static constexpr string finish_tag_hard = string(finish_tag) + k::newline;
36 static constexpr const char* self_finish_tag = " />";
37
38 // Underlying units for 2D (x,y) mapping (same as area::atype).
39 using atype = space_type; // ... floating point cartesian points
40 //using atype = ssize_type; // ... integer cartesian points
41
42 /// Virtual, only one buffer.
44
45 virtual void
47
48 virtual void
50
51 /// Empty when the output buffer is.
52 bool
53 empty() { return _M_sstream.str().empty(); }
54
55 string
56 str() const { return _M_sstream.str(); }
57
58 void
59 str(const string& s) { return _M_sstream.str(s); }
60
61 // Add sub element e to base object in non-visible defs section
62 void
64
65 // Add sub element e to base object
66 void
68 { _M_sstream << e.str(); }
69
70 void
71 add_fill(const string id)
72 {
73 _M_sstream << k::space;
74 _M_sstream << "fill=" << k::quote;
75 _M_sstream << "url(#" << id << ")" << k::quote;
76 }
77
78 void
79 add_filter(const string id)
80 {
81 _M_sstream << k::space;
82 _M_sstream << "filter=" << k::quote;
83 _M_sstream << "url(#" << id << ")" << k::quote;
84 }
85
86 // Add raw string to group; filter, blend/gradient elements.
87 void
88 add_raw(const string& raw)
89 { _M_sstream << k::space << raw; }
90
91 void
92 add_style(const style& sty)
93 { _M_sstream << to_string(sty); }
94
95 void
96 add_title(const string& t);
97
98 /// Common transforms include rotate(180)
99 void
100 add_transform(const string s)
101 {
102 if (!s.empty())
103 _M_sstream << k::space << "transform=" << k::quote << s << k::quote;
104 }
105};
106
107
108/**
109 Group SVG element.
110
111 Specification reference:
112 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
113
114 Attributes:
115 x, y, width, height, xlink:xref, preserveAspectRatio
116 */
117struct group_element : virtual public element_base
118{
119 static string
120 start_group(const string name = "")
121 {
122 string ret("<g");
123 if (!name.empty())
124 {
125 ret += " id=";
126 ret += k::quote;
127 ret += name;
128 ret += k::quote;
129 }
130 ret += ">";
131 ret += k::newline;
132 return ret;
133 }
134
135 static string
137 { return string("</g>") + k::newline; }
138
139 void
142
143 /// For groups of elements that have the same name.
144 ///
145 /// Also, although one can nest SVG elements inside another SVG by
146 /// using an 'image_element', the display quality is lacking in
147 /// inkscape. To work around this, insert the contents of the nested
148 /// SVG into a named group element instead.
149 void
150 start_element(string name)
151 { _M_sstream << start_group(name); }
152
153 // For groups of elements with style as specified.
154 void
155 start_element(string name, const style& sty)
156 {
157 _M_sstream << "<g id=" << k::quote << name << k::quote << k::space;
158 add_style(sty);
159 _M_sstream << '>' << k::newline;
160 }
161
162 // For groups of elements with transforms and style if specified.
163 void
164 start_element(string name, const transform, const string ts,
165 const style& sty = k::no_style)
166 {
167 _M_sstream << "<g id=" << k::quote << name << k::quote;
168 add_transform(ts);
169
170 // Only add style if it is not the default argument.
171 const color_qi nklr(color::none);
172 const bool stylep = to_string(sty._M_fill_color) != to_string(nklr);
173 if (stylep)
174 add_style(sty);
175 _M_sstream << '>' << k::newline;
176 }
177
178 void
180};
181
182void
185
186
187/**
188 Definitions SVG element. Storage space for elements used later.
189
190 Specification reference:
191 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
192
193 Attributes:
194 id
195 */
196struct defs_element : virtual public element_base
197{
198 static string
200 { return "<defs>"; }
201
202 static string
204 { return "</defs>"; }
205
206 void
208 { _M_sstream << start_defs() << k::newline; }
209
210 void
212};
213
214void
217
218void
225
226
227/**
228 Link SVG element. a
229
230 Specification reference:
231 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a
232
233 Attributes:
234 id
235 */
236struct link_element : virtual public element_base
237{
238 void
240 { _M_sstream << "<a "; }
241
242 void
244
245 void
246 add_data(const string& url)
247 {
248 _M_sstream << "href=" << k::quote << url << k::quote;
250 }
251
252 /// Overload for rel=x form.
253 /// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload
254 /// @param relt attribute that describes the relationship of the
255 /// target object to the link object
256 /// @param ast type of resource.
257 void
258 add_data(const string& url, const string relt, const string ast,
259 const string cors = "anonymous")
260 {
261 _M_sstream << "rel=" << k::quote << relt << k::quote << k::space;
262 _M_sstream << "href=" << k::quote << url << k::quote << k::space;
263 _M_sstream << "as=" << k::quote << ast << k::quote << k::space;
264 _M_sstream << "crossorigin=" << k::quote << cors << k::quote << k::space;
265 _M_sstream << "referrerpolicy=" << k::quote << "no-referrer" << k::quote;
266 _M_sstream << k::space;
268 }
269};
270
271void
273{ _M_sstream << "</a>" << k::newline; }
274
275
276/**
277 Datum consolidating filter use and preferences.
278
279 \verbatim
280 <filter id="gblur10" x="0" y="0">
281 <feGaussianBlur in="SourceGraphic" stdDeviation="10" />
282 <feOffset dx="0" dy="0" />
283 </filter>
284 \endverbatim
285*/
286struct filter_element : virtual public element_base
287{
297
298 void
300 { _M_sstream << "<filter>" << k::newline; }
301
302 void
303 start_element(const string id)
304 {
305 _M_sstream << "<filter id=" << k::quote << id << k::quote << ">"
306 << k::newline;
307 }
308
309 // Some filter effects get clipped when appied to an element's area,
310 // so this allows filters to have an element + filter area instead.
311 void
312 start_element(const string id, const area<> blur_area, const point_2t p)
313 {
314 auto [ width, height ] = blur_area;
315 auto [ x, y ] = p;
316 _M_sstream << "<filter id=" << k::quote << id << k::quote << k::space
317 << "x=" << k::quote << x << k::quote << k::space
318 << "y=" << k::quote << y << k::quote << k::space
319 << "width=" << k::quote << width << k::quote << k::space
320 << "height=" << k::quote << height << k::quote
321 << ">"
322 << k::newline;
323 }
324
325 void
327
328 void
329 add_data(const string fltr)
330 { _M_sstream << fltr; }
331
332 // https://drafts.fxtf.org/filter-effects/#elementdef-fegaussianblur
333 // in == SourceGraphic, SourceAlpha, FillPaint, StrokePaint
334 // dev == 1 or 1,1 (0 default if two then x, y direction)
335 string
336 gaussian_blur(string in, string dev)
337 {
338 // <feGaussianBlur in="SourceGraphic" stdDeviation="20" />
339 stream_type stream;
340 stream << "<feGaussianBlur in=";
341 stream << k::quote << in << k::quote << k::space;
342 stream << "stdDeviation=" << k::quote << dev << k::quote << k::space;
343 stream << "/>";
344 return stream.str();
345 }
346
347 string
348 gaussian_blur(string dev)
349 { return gaussian_blur("SourceGraphic", dev); }
350};
351
352void
354{ _M_sstream << "</filter>" << k::newline; }
355
356
357/**
358 Gradient SVG elements.
359
360 Specification reference:
361 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient
362 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
363
364 Note these are always inside a defs block.
365
366 Attributes:
367 id
368 */
369struct gradient_element : virtual public defs_element
370{
378
379 void
382
383 void
385
386 // off == 10%
387 void
388 stop(const string off, const color& klr, const double opacity = 1.0)
389 {
390 _M_sstream << "<stop offset=" << k::quote << off << k::quote << k::space
391 << "stop-color=" << k::quote << to_string(klr) << k::quote;
392 if (opacity < 1.0)
393 {
394 _M_sstream << k::space
395 << "stop-opacity=" << k::quote << opacity << k::quote;
396 }
397 _M_sstream << " />";
398 _M_sstream << k::newline;
399 }
400
401 // Express two integers as a suitable offset string percentage.
402 const string
403 offset_percentage(const ssize_type numer, const ssize_type denom)
404 {
405 const double ratio = static_cast<double>(numer)/static_cast<double>(denom);
406 const ssize_type perc(round(ratio * 100));
407 return std::to_string(perc) + "%";
408 }
409};
410
411void
414
415
416/// Circular gradients
417/// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient
418struct radial_gradient : virtual public gradient_element
419{
420 void
422 {
424 _M_sstream << "<radialGradient id=" << k::quote << "default" << k::quote;
425 _M_sstream << ">" << k::newline;
426 }
427
428 // Radial gradient centered at (cx, cy) of radius.
429 // Default for radius, cx, cy is "50%"
430 void
431 start_element(const string id, const ssize_type radius = 0,
432 const ssize_type cx = 0, const ssize_type cy = 0)
433 {
435 _M_sstream << "<radialGradient id=" << k::quote << id << k::quote;
436 if (radius > 0)
437 {
438 _M_sstream << k::space << "r=" << k::quote << radius << k::quote;
439 _M_sstream << k::space << "cx=" << k::quote << cx << k::quote;
440 _M_sstream << k::space << "cy=" << k::quote << cy << k::quote;
441 }
442 _M_sstream << ">" << k::newline;
443 }
444
445 // Radial gradient.
446 // End circle (aka 100% stop) at (cx, cy) with radius.
447 // Start circle (aka 0% stop) at (fx, fy) with radius fr.
448 void
449 start_element(const string id, const ssize_type radius,
450 const ssize_type cx, const ssize_type cy, const ssize_type fr,
451 const ssize_type fx, const ssize_type fy)
452 {
454 _M_sstream << "<radialGradient id=" << k::quote << id << k::quote
455 << k::space << "r=" << k::quote << radius << k::quote;
456 _M_sstream << k::space << "cx=" << k::quote << cx << k::quote;
457 _M_sstream << k::space << "cy=" << k::quote << cy << k::quote;
458 if (fr > 0)
459 {
460 _M_sstream << k::space << "fx=" << k::quote << fx << k::quote;
461 _M_sstream << k::space << "fy=" << k::quote << fy << k::quote;
462 _M_sstream << k::space << "fr=" << k::quote << fr << k::quote;
463 }
464 _M_sstream << ">" << k::newline;
465 }
466
467 void
469};
470
471void
473{
474 _M_sstream << "</radialGradient>" << k::newline;
476}
477
478
479/// Linear gradients
480/// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
481struct linear_gradient : virtual public gradient_element
482{
483 void
485 {
487 _M_sstream << "<linearGradient id=" << k::quote << "default" << k::quote;
488 _M_sstream << ">" << k::newline;
489 }
490
491 void
493};
494
495void
497{
498 _M_sstream << "</linearGradient>" << k::newline;
500}
501
502
503/**
504 Marker SVG elements defines a graphic used for drawing
505 arrow[heads, tails, mid] on a poly line or path.
506
507 Specification reference:
508 https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-mid
509
510 Note these are always inside a defs block.
511
512 Attributes:
513 id
514 */
515struct marker_element : virtual public element_base
516{
517 void
519
520 // markerWidth="8" markerHeight="8" refX="4" refY="4">
521 void
522 start_element(const string id, const area<> a, const point_2t p)
523 {
524 auto [ x, y ] = p;
525 auto [ w, h ] = a;
526 _M_sstream << "<marker id=" << k::quote << id << k::quote << k::space
527 << "markerWidth=" << k::quote << w << k::quote << k::space
528 << "markerHeight=" << k::quote << h << k::quote << k::space
529 << "refX=" << k::quote << x << k::quote << k::space
530 << "refY=" << k::quote << y << k::quote << " >"
531 << k::newline;
532 }
533
534 void
536};
537
538void
540{
541 _M_sstream << "</marker>" << k::newline;
542}
543
544
545/**
546 Title SVG element. This is accessible/alt text.
547 This element must be the first element in the svg objectc.
548
549 A title element with no string indicates a decorative element to AT
550 screenreaders.
551
552 Specification reference:
553 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
554*/
555struct title_element : virtual public element_base
556{
557 void
559 { _M_sstream << "<title>" << k::newline; }
560
561 void
562 start_element(const string t)
563 {
565 _M_sstream << t << k::newline;
566 }
567
568 void
570};
571
572void
574{ _M_sstream << "</title>" << k::newline; }
575
576
577/**
578 Description SVG element.
579
580 Specification reference:
581 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
582*/
583struct desc_element : virtual public element_base
584{
585 void
587
588 void
589 start_element(const string dsc)
590 { _M_sstream << "<desc>" << k::newline << dsc << k::newline; }
591
592 void
594};
595
596void
598{ _M_sstream << "</desc>" << k::newline; }
599
600
601/**
602 Text SVG element.
603
604 Specification reference:
605 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text
606
607 Attributes:
608 x, y, dx, dy, text-anchor, rotate, textLength, lengthAdjust
609*/
610struct text_element : virtual public element_base
611{
619
620 // So text_path_element can substitute the text_path part without
621 // duplicating the text formatting and style parts....
622 virtual void
623 add_text(string txt)
624 { _M_sstream << txt; }
625
626 /// Either serialize immediately (as below), or create data structure
627 /// that adds data to data_vec and then finish_element serializes.
628 void
629 add_data(const data& d,
630 const string trans = "", const unit utype = svg::unit::point)
631 {
632 const string x("__x");
633 const string y("__y");
634 const string attr("__attr");
635 const string style("__style");
636
637 string strip = R"_delimiter_(x="__x" y="__y" __attr __style)_delimiter_";
638
639 // Add attributes.
640 string_replace(strip, x, std::to_string(d._M_x_origin));
641 string_replace(strip, y, std::to_string(d._M_y_origin));
642 string_replace(strip, attr, d._M_typo.add_attribute(utype));
644 _M_sstream << strip;
645 add_transform(trans);
646 _M_sstream << '>';
647
648 // Add text data.
649 add_text(d._M_text);
650 }
651
652 void
654 { _M_sstream << "<text "; }
655
656 void
658
659 /// For text list output, use tspan for line breaks. This span
660 /// creates a new horizontal line for every tspan block, starting at
661 /// xpos with spacing dy (1.2em).
662 static string
663 start_tspan_y(uint xpos, string dy)
664 {
665 const string x("__x");
666 const string dys("__dy");
667 string strip = R"_delimiter_(<tspan x="__x" dy="__dy">)_delimiter_";
668 string_replace(strip, x, std::to_string(xpos));
669 string_replace(strip, dys, dy);
670 return strip;
671 }
672
673 static string
675 { return start_tspan_y(xpos, std::to_string(dy)); }
676
677 /// For text list output, use tspan for line breaks. This span
678 /// creates a new vertical line space for every tspan block, starting
679 /// at xpos with horizontal spacing dx ("1.4em").
680 static string
681 start_tspan_x(uint xpos, string dx)
682 {
683 const string x("__x");
684 const string dxs("__dx");
685 string strip = R"_delimiter_(<tspan x="__x" dx="__dx">)_delimiter_";
686 string_replace(strip, x, std::to_string(xpos));
687 string_replace(strip, dxs, dx);
688 return strip;
689 }
690
691 static string
693 { return start_tspan_x(xpos, std::to_string(dx)); }
694
695 static string
697 { return "</tspan>"; }
698};
699
700void
702{ _M_sstream << "</text>" << k::newline; }
703
704
705/// Make text span.
706string
707make_tspan_y_from_string_by_token(string s, uint xpos, const char token = ' ')
708{
709 string start(text_element::start_tspan_y(xpos, "0.5em"));
710 string ret = start;
711 for (uint i = 0; i < s.size(); ++i)
712 {
713 const char c = s[i];
714 if (c != token)
715 ret += c;
716 else
717 {
719 if (i < s.size() - 1)
720 ret += start;
721 }
722 }
724 return ret;
725}
726
727
728/**
729 Rectangle SVG element.
730
731 Specification reference:
732 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect
733
734 Attributes:
735 x, y, width, height, rx, ry
736 */
737struct rect_element : virtual public element_base
738{
746
747 // Verbose opening/closing pair tags for circle_element.
748 // Default assumes the more compact XML "self-closed tag" for circle element.
749 static constexpr const char* pair_open_tag = "<rect>";
750 static constexpr const char* pair_finish_tag = "</rect>";
751
752 /// Either serialize immediately (as below), or create data structure
753 /// that adds data to data_vec and then finish_element serializes.
754 void
755 add_data(const data& d)
756 {
757 const string x("__x");
758 const string y("__y");
759 const string w("__w");
760 const string h("__h");
761
762 string strip = R"_delimiter_(x="__x" y="__y" width="__w" height="__h"
763)_delimiter_";
764
765 string_replace(strip, x, std::to_string(d._M_x_origin));
766 string_replace(strip, y, std::to_string(d._M_y_origin));
767 string_replace(strip, w, std::to_string(d._M_width));
768 string_replace(strip, h, std::to_string(d._M_height));
769 _M_sstream << strip;
770 }
771
772 void
774 { _M_sstream << "<rect "; }
775
776 void
778};
779
780void
783
784
785/**
786 Circle SVG element.
787
788 Specification reference:
789 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle
790
791 Attributes:
792 x, y, width, height, xlink:xref, preserveAspectRatio
793 */
794struct circle_element : virtual public element_base
795{
802
803 // Verbose opening/closing pair tags for circle_element.
804 // Default assumes the more compact XML "self-closed tag" for circle element.
805 static constexpr const char* pair_open_tag = "<circle>";
806 static constexpr const char* pair_finish_tag = "</circle>";
807
808 // Either serialize immediately (as below), or create data structure
809 // that adds data to data_vec and then finish_element serializes.
810 void
811 add_data(const data& d, string trans = "")
812 {
813 const string x("__x");
814 const string y("__y");
815 const string r("__r");
816
817 string strip = R"_delimiter_(cx="__x" cy="__y" r="__r")_delimiter_";
818
819 string_replace(strip, x, std::to_string(d._M_x_origin));
820 string_replace(strip, y, std::to_string(d._M_y_origin));
821 string_replace(strip, r, std::to_string(d._M_radius));
822 _M_sstream << strip;
823 add_transform(trans);
824 }
825
826 void
828 { _M_sstream << "<circle "; }
829
830 void
832
833};
834
835void
838
839
840/**
841 Line SVG element.
842
843 Specification reference:
844 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line
845
846 Attributes:
847 x, y, width, height, xlink:xref, preserveAspectRatio
848*/
849struct line_element : virtual public element_base
850{
858
859 // Either serialize immediately (as below), or create data structure
860 // that adds data to data_vec and then finish_element serializes.
861 void
862 add_data(const data& d, const string dasharray = "")
863 {
864 const string x1("__x1");
865 const string x2("__x2");
866 const string y1("__y1");
867 const string y2("__y2");
868 const string dash("__darray");
869
870 const bool dashp = !dasharray.empty();
871 string stripf = \
872 R"_delimiter_(x1="__x1" y1="__y1" x2="__x2" y2="__y2")_delimiter_";
873 string stript = \
874 R"_delimiter_(x1="__x1" y1="__y1" x2="__x2" y2="__y2" stroke-dasharray="__darray")_delimiter_";
875
876 string strip = dashp ? stript : stripf;
877 string_replace(strip, x1, std::to_string(d._M_x_begin));
878 string_replace(strip, x2, std::to_string(d._M_x_end));
879 string_replace(strip, y1, std::to_string(d._M_y_begin));
880 string_replace(strip, y2, std::to_string(d._M_y_end));
881
882 if (dashp)
883 string_replace(strip, dash, dasharray);
884 _M_sstream << strip;
885 }
886
887 void
889 { _M_sstream << "<line "; }
890
891 void
892 start_element(string name)
893 { _M_sstream << "<line id=" << k::quote << name << k::quote << k::space; }
894
895 void
897};
898
899void
902
903
904/**
905 Polyline SVG element.
906
907 Specification reference:
908 https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline
909
910 Attributes:
911 points, pathLength
912*/
913struct polyline_element : virtual public element_base
914{
915 // vector<point_2t> == vector<tuple<double,double>>
917
919
920 polyline_element(const vrange& points) : polypoints(points) { }
921
922 // Either serialize immediately (as below), or create data structure
923 // that adds data to data_vec and then finish_element serializes.
924 void
925 add_data(const stroke_style& sstyl)
926 {
927 if (!polypoints.empty())
928 {
929 _M_sstream << "points=" << k::quote;
930 for (const point_2t& pt : polypoints)
931 {
932 auto [ x, y ] = pt;
933 _M_sstream << x << k::comma << y << k::space;
934 }
935 _M_sstream << k::quote << k::space;
936
937 if (!sstyl.dasharray.empty())
938 {
939 _M_sstream << "stroke-dasharray=" << k::quote;
940 _M_sstream << sstyl.dasharray << k::quote << k::space;
941 }
942 if (!sstyl.dashoffset.empty())
943 {
944 _M_sstream << "stroke-dashoffset=" << k::quote;
945 _M_sstream << sstyl.dashoffset << k::quote << k::space;
946 }
947 if (!sstyl.linecap.empty())
948 {
949 _M_sstream << "stroke-linecap=" << k::quote;
950 _M_sstream << sstyl.linecap << k::quote << k::space;
951 }
952 if (!sstyl.markerspoints.empty())
953 {
954 string mkr;
955 mkr += k::quote;
956 mkr += "url(#";
957 mkr += sstyl.markerspoints;
958 mkr += ")";
959 mkr += k::quote;
960
961 _M_sstream << "marker-mid=" << mkr << k::space;
962 _M_sstream << "marker-end=" << mkr << k::space;
963 }
964 }
965 }
966
967 void
969 { _M_sstream << "<polyline "; }
970
971 void
972 start_element(string name)
973 { _M_sstream << "<polyline id=" << k::quote << name << k::quote << k::space; }
974
975 void
977};
978
979void
982
983
984
985/**
986 Path SVG element.
987
988 Specification reference:
989 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
990
991 Attributes:
992 d, pathLength
993*/
994struct path_element : virtual public element_base
995{
996 struct data
997 {
998 string _M_d;
1000 };
1001
1002 static constexpr const char* pair_finish_tag = "</path>";
1003
1004 /// Either serialize immediately (as below), or create data structure
1005 /// that adds data to data_vec and then finish_element serializes.
1006 void
1007 add_data(const data& d)
1008 {
1009 const string pathd("__d");
1010 const string len("__l");
1011
1012 string strip = R"_delimiter_(d="__d")_delimiter_";
1013
1014 string_replace(strip, pathd, d._M_d);
1015 string_replace(strip, len, std::to_string(d._M_length));
1016 _M_sstream << strip;
1017 }
1018
1019 void
1021 { _M_sstream << "<path "; }
1022
1023 void
1024 start_element(const string name)
1025 { _M_sstream << "<path id=" << k::quote << name << k::quote << k::space; }
1026
1027 void
1029};
1030
1031void
1037
1038
1039/**
1040 Text on a Path SVG element.
1041
1042 Specification reference:
1043 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath
1044
1045 Attributes:
1046 href, path, method, side, spacing, startOffset, textLength, lengthAdjust
1047*/
1048struct text_path_element : virtual public text_element
1049{
1051 string offset; // "30%"
1052 string side; // "left" || "right" (use convex/concave side of path)
1053
1054 text_path_element(const string name,
1055 const string off = "", const string whichside = "")
1056 : path_name(name), offset(off), side(whichside) { }
1057
1058 virtual void
1059 add_text(string txt)
1060 {
1061 // Start text_path_element...
1062 _M_sstream << "<textPath xlink:href="
1063 << k::quote << '#' << path_name << k::quote;
1064 if (!offset.empty())
1065 _M_sstream << k::space << "startOffset="
1066 << k::quote << offset << k::quote;
1067 if (!side.empty())
1068 _M_sstream << k::space << "side="
1069 << k::quote << side << k::quote;
1070 _M_sstream << '>';
1071
1072 _M_sstream << txt;
1073
1074 // End text_path_element...
1075 _M_sstream << "</textPath>" << k::space;
1076 }
1077};
1078
1079
1080
1081/**
1082 Image SVG element. This can be another SVG file, or can be a raster
1083 image format like PNG or JPEG.
1084
1085 Specification reference:
1086 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
1087
1088 Attributes:
1089 x, y, width, height, xlink:xref, preserveAspectRatio
1090 */
1091struct image_element : virtual public element_base
1092{
1101
1102 void
1103 start_element(const string& id)
1104 {
1105 const string simg = "<image";
1106 _M_sstream << simg << k::space;
1107 if (!id.empty())
1108 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1109 }
1110
1111 void
1114
1115 void
1117
1118 /// Either serialize immediately (as below), or create data structure
1119 /// that adds data to data_vec and then finish_element serializes.
1120 void
1121 add_data(const data& d)
1122 {
1123 const string x("__x");
1124 const string y("__y");
1125 const string w("__w");
1126 const string h("__h");
1127 const string ref("__ref");
1128
1129 string strip = R"_delimiter_(href="__ref" x="__x" y="__y" width="__w" height="__h")_delimiter_";
1130
1131 string_replace(strip, ref, d._M_xref);
1132 string_replace(strip, x, std::to_string(d._M_x_origin));
1133 string_replace(strip, y, std::to_string(d._M_y_origin));
1134 string_replace(strip, w, std::to_string(d._M_width));
1135 string_replace(strip, h, std::to_string(d._M_height));
1136 _M_sstream << strip << k::space;
1137 }
1138
1139 /// Visibility and other HTML/img attributes.
1140 /// @param vattr = visibility attribute, "visible" or "hidden"
1141 /// @param display = display attribute, "none" or "unset" or "initial"
1142 /// @param cors = CORS, "anonymous" or "use-credentials"
1143 /// @param lattr = loading attribute, "lazy" or "eager"
1144 void
1145 add_data(const data& d, const string cors, const string vattr,
1146 const string display = "")
1147 {
1148 add_data(d);
1149
1150 if (!cors.empty())
1151 _M_sstream << "crossorigin=" << k::quote << cors << k::quote << k::space;
1152 if (!vattr.empty())
1153 _M_sstream << "visibility=" << k::quote << vattr << k::quote << k::space;
1154 if (!display.empty())
1155 _M_sstream << "display=" << k::quote << display << k::quote << k::space;
1156 }
1157};
1158
1159
1160void
1163
1164
1165/**
1166 So-called Foreign Objects.
1167
1168 Using to get HTML video elements.
1169
1170 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject
1171 https://stackoverflow.com/questions/40324916/video-tag-embedded-in-svg
1172
1173Translate moves the origin from the top left to the specified
1174coordinates. If you embed an object at 0,0 it will be placed at the
1175new origin. In this case you must embed it at -translation
1176coordinates.
1177
1178Even so, I had to increase the width and height. Why? I don't know. It
1179doesn't seem to be a scale by 2. If someone knows I am curious to
1180know.
1181
1182<svg version="1.1" class="center-block" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="600" style="border: 1px solid black;">
1183 <g>
1184 <g transform="translate(151,104) scale(1,1)">
1185 <rect x="0" y="0" width="300" height="200"></rect>
1186 <foreignObject x="-151" y="-104" width="500" height="400">
1187 <video xmlns="http://www.w3.org/1999/xhtml" width="300" height="200" controls="" style="position: fixed; left: 151px; top: 104px;">
1188 <source src="http://techslides.com/demos/sample-videos/small.mp4" type="video/mp4" />less
1189 </video>
1190 </foreignObject>
1191 </g>
1192 </g>
1193</svg>
1194*/
1195struct foreign_element : virtual public element_base
1196{
1197 void
1199 { _M_sstream << "<g>" << k::newline; }
1200
1201 // av == area of the foreign object and native video frame size
1202 // arect == area of displayed video as embedded inside svg element /aka page
1203 // scale_pair == x/y scaling factor
1204 void
1205 start_element(const point_2t origin, const area<> av, const area<> arect,
1206 const point_2t scale = std::make_tuple(1.0, 1.0))
1207 {
1208 const auto [ scalex, scaley ] = scale;
1209 const auto [ ox, oy ] = origin;
1210
1211 const auto [ width, height ] = arect;
1212 auto xo = width/2;
1213 auto yo = height/2;
1214
1215 const auto [ vwidth, vheight ] = av;
1216
1217 // Outer group.
1218 group_element go;
1219 go.start_element();
1220 _M_sstream << go.str() << k::newline;
1221
1222 // Inner Group.
1223 group_element gi;
1224 const transform txfm;
1225 string tx = transform::translate(xo, yo);
1226 string tscl = transform::scale(scalex, scaley);
1227 gi.start_element(string("video-wrapper"), txfm, tscl);
1228 _M_sstream << gi.str() << k::newline;
1229
1230 // Foreign Object
1231 string strip = R"(<foreignObject x="XXX" y="YYY" width="WWW" height="HHH">)";
1232 string_replace(strip, "WWW", std::to_string(vwidth));
1233 string_replace(strip, "HHH", std::to_string(vheight));
1234 string_replace(strip, "XXX", std::to_string(ox));
1235 string_replace(strip, "YYY", std::to_string(oy));
1236 _M_sstream << strip << k::newline;
1237 }
1238
1239 void
1241};
1242
1243void
1245{ _M_sstream << " </foreignObject></g></g>" << k::newline; }
1246
1247
1248/// video HTML object embedded in SVG container.
1249/// NB: HTML elements video/audio/iframe/canvas can be used w/o foreignElement.
1250/// This approach uses HTML wrapped in foreign element.
1251/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1252/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
1253struct video_element : virtual public foreign_element
1254{
1255 void
1256 start_element(const string& id)
1257 {
1258 //const string svideo = "<html:video";
1259 const string svideo = R"(<video xmlns="http://www.w3.org/1999/xhtml" )";
1260 _M_sstream << svideo << k::space;
1261 if (!id.empty())
1262 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1263 }
1264
1265 void
1268
1269 /// Video.
1270 /// a is width and height of video as embedded in page
1271 /// r is the foreign object, with x/y offset and scaled size
1272 ///
1273 /// attr is attribues for video_element
1274 /// autoplay="true" or removed
1275 /// loop="true/false"
1276 /// muted="true/false"
1277 /// controls, controlslist,
1278 /// crossorigin, disablepictureinpicture, disableremoteplayback
1279 ///
1280 void
1281 add_data(const area<> a, const string src, const string mtype = "video/mp4",
1282 const string attr = R"(autoplay="true" loop="true" muted="true")")
1283 {
1284 string strip = R"(width="WWW" height="HHH" )";
1285 string_replace(strip, "WWW", std::to_string(a._M_width));
1286 string_replace(strip, "HHH", std::to_string(a._M_height));
1287 _M_sstream << k::space;
1288 _M_sstream << strip << k::space;
1289 _M_sstream << attr << k::space;
1291
1292 _M_sstream << "<source src=" << k::quote << src << k::quote << k::space;
1293 _M_sstream << "type=" << k::quote << mtype << k::quote;
1295 }
1296
1297 void
1299};
1300
1301void
1303{ _M_sstream << "</video>" << k::newline; }
1304
1305
1306/// iframe HTML object embedded in SVG container.
1307/// NB: HTML elements video/audio/iframe/canvas can be used w/o foreignElement.
1308/// This approach uses HTML wrapped in foreign element.
1309/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1310/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
1311struct iframe_element : virtual public foreign_element
1312{
1313 void
1314 start_element(const string& id)
1315 {
1316 //const string siframe = "<html:iframe";
1317 const string siframe = R"(<iframe xmlns="http://www.w3.org/1999/xhtml" )";
1318 _M_sstream << siframe << k::space;
1319 if (!id.empty())
1320 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1321 }
1322
1323 void
1326
1327 /// iframe.
1328 /// a is width and height of video as embedded in page
1329 /// r is the foreign object, with x/y offset and scaled size
1330 ///
1331 void
1332 add_data(const area<> a, const string src, const string mtype = "image/jpeg",
1333 const string attr = R"(sandbox="allow-scripts allow-same-origin")")
1334 {
1335 string strip = R"(width="WWW" height="HHH" )";
1336 string_replace(strip, "WWW", std::to_string(a._M_width));
1337 string_replace(strip, "HHH", std::to_string(a._M_height));
1338 _M_sstream << k::space;
1339 _M_sstream << strip << k::space;
1340 // _M_sstream << "src=" << k::quote << src << k::quote << k::space;
1341 _M_sstream << attr;
1343
1344 // image/webp or image/jpeg
1345 _M_sstream << "<source src=" << k::quote << src << k::quote << k::space;
1346 _M_sstream << "type=" << k::quote << mtype << k::quote << k::space;
1348 }
1349
1350 void
1352};
1353
1354void
1356{ _M_sstream << "</iframe>" << k::newline; }
1357
1358
1359/// HTML object embedded in SVG container.
1360/// Unlike image_elements, object_elements are not locked down for scripting.
1361/// NB: HTML elements video/audio/object/canvas can be used w/o foreignElement.
1362/// This approach uses HTML wrapped in foreign element.
1363/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1364/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object
1365struct object_element : virtual public foreign_element
1366{
1367 void
1368 start_element(const string& id)
1369 {
1370 //const string sobject = "<html:object";
1371 const string sobject = R"(<object xmlns="http://www.w3.org/1999/xhtml" )";
1372 _M_sstream << sobject << k::space;
1373 if (!id.empty())
1374 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1375 }
1376
1377 void
1380
1381 /// Add resource to object.
1382 /// @param a is width and height of video as embedded in page
1383 /// @param src is the resource URL
1384 /// @param mtype is the MIME type
1385 /// @param attr is any collection of ad-hoc HTML attributes.
1386 void
1387 add_data(const area<> a, const string src, const string mtype = "image/jpeg",
1388 const string attr = R"(sandbox="allow-scripts allow-same-origin")")
1389 {
1390 string strip = R"(width="WWW" height="HHH" )";
1391 string_replace(strip, "WWW", std::to_string(a._M_width));
1392 string_replace(strip, "HHH", std::to_string(a._M_height));
1393 _M_sstream << k::space;
1394 _M_sstream << strip << k::space;
1395 _M_sstream << "data=" << k::quote << src << k::quote << k::space;
1396 _M_sstream << "type=" << k::quote << mtype << k::quote << k::space;
1397 _M_sstream << attr << k::space;
1399 }
1400
1401 void
1403};
1404
1405void
1407{ _M_sstream << "</object>" << k::newline; }
1408
1409
1410/**
1411 A SVG script element.
1412
1413 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/script
1414*/
1415struct script_element : virtual public element_base
1416{
1417 /// Where is the script element placed? On/within the element
1418 /// itself, or at the document (global)? Neither (none),
1419 /// alongside/same level (parent)?
1420 enum class scope { none, document, parent, element };
1421
1422 void
1423 start_element(const string& id)
1424 {
1425 const string shead = R"(<script type="text/javascript" crossorigin="anonymous")";
1426 _M_sstream << shead << k::space;
1427 if (!id.empty())
1428 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1430 }
1431
1432 void
1435
1436 /// showTooltip(id)
1437 /// hideTooltip(id)
1438 /// event.x vs. event.pageX, event.y vs. event.pageY
1439 static const string&
1441 {
1442 static string js_show_element = R"(
1443 function showTooltip(event, tooltipId) {
1444 const tooltipimg = document.getElementById(tooltipId);
1445 if (tooltipimg) {
1446 const ge = tooltipimg.parentElement;
1447 const svge = ge.parentElement;
1448 const brect = ge.getBoundingClientRect();
1449 const bx = brect.left;
1450 const by = brect.top;
1451
1452 tooltipimg.setAttribute('x', event.x + bx);
1453 tooltipimg.setAttribute('y', event.y + by);
1454
1455 tooltipimg.setAttribute('visibility', 'visible');
1456 } else {
1457 console.error(`Element with ID "${tooltipId}" not found.`);
1458 }
1459 })";
1460
1461 static string js_show_document = R"(
1462 function showTooltip(event, tooltipId) {
1463 const tooltipimg = document.getElementById(tooltipId);
1464 if (tooltipimg) {
1465 //tooltipimg.onload = function() {
1466 const ge = tooltipimg.parentElement;
1467 const svge = ge.parentElement;
1468 const brect = ge.getBoundingClientRect();
1469 const bx = brect.left;
1470 const by = brect.top;
1471
1472 //const iheight = 150;
1473 const iheight = tooltipimg.offsetHeight; //!isNaN(iheight)
1474 tooltipimg.setAttribute('x', event.pageX - bx);
1475 tooltipimg.setAttribute('y', event.pageY - by - iheight);
1476 tooltipimg.setAttribute('visibility', 'visible');
1477 //tooltipimg.setAttribute('display', 'inline');
1478 } else {
1479 console.error(`Element with ID "${tooltipId}" not found.`);
1480 }
1481 })";
1482
1483 static string js_hide = R"(
1484 function hideTooltip(tooltipId) {
1485 const tooltipimg = document.getElementById(tooltipId);
1486 tooltipimg.setAttribute('visibility', 'hidden');
1487 //tooltipimg.setAttribute('display', 'none');
1488 })";
1489
1490 static string js;
1491 if (context == scope::element)
1492 js = js_show_element + k::newline + js_hide;
1493 if (context == scope::document || context == scope::parent)
1494 js = js_show_document + k::newline + js_hide;
1495
1496 return js;
1497 }
1498
1499 static const string
1500 tooltip_attribute(const string& id)
1501 {
1502 const string toolr("__toolt");
1503 string strip1 = R"_delimiter_(onmouseover="showTooltip(event, '__toolt')" )_delimiter_";
1504 string strip2 = R"_delimiter_(onmouseout="hideTooltip('__toolt')" )_delimiter_";
1505 string_replace(strip1, toolr, id);
1506 string_replace(strip2, toolr, id);
1507 return k::space + strip1 + k::space + strip2;
1508 }
1509
1510 // Script element for js to control visibility of images.
1511 static const script_element
1512 tooltip_script(const scope context)
1513 {
1514 script_element scrpt;
1515 scrpt.start_element("tooltip-js");
1517 scrpt.finish_element();
1518 return scrpt;
1519 }
1520
1521
1522 /// Add string with script source.
1523 /// @param scriptstr script source
1524 void
1525 add_data(const string scriptstr)
1526 {
1527 _M_sstream << scriptstr;
1528 _M_sstream << k::newline;
1529 }
1530
1531 void
1533};
1534
1535void
1537{ _M_sstream << "</script>" << k::newline; }
1538
1539
1540/**
1541 A SVG object element.
1542
1543 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
1544 https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image
1545*/
1546struct svg_element : virtual public element_base
1547{
1549
1550 const string _M_name;
1554 const bool _M_lifetime; // scope document scope element
1555
1556 svg_element(const string __title, const area& __cv,
1557 const bool lifetime = true,
1558 const unit u = svg::unit::pixel,
1559 const typography& __typo = k::smono_typo)
1560 : _M_name(__title), _M_area(__cv), _M_unit(u),
1561 _M_typo(__typo), _M_lifetime(lifetime)
1562 {
1563 if (_M_lifetime)
1564 start();
1565 }
1566
1567 svg_element(const string __title, const string desc, const area& __cv,
1568 const bool lifetime = true)
1569 : _M_name(__title), _M_area(__cv), _M_unit(svg::unit::pixel),
1570 _M_typo(svg::k::smono_typo), _M_lifetime(lifetime)
1571 {
1572 if (_M_lifetime)
1573 start(desc);
1574 }
1575
1577 : _M_name(other._M_name), _M_area(other._M_area),
1578 _M_unit(other._M_unit), _M_typo(other._M_typo),
1580 { }
1581
1583 {
1584 if (_M_lifetime)
1585 finish();
1586 }
1587
1588 const point_2t
1590 { return _M_area.center_point(); }
1591
1592 void
1593 start_element();
1594
1595 void
1596 start_element(const point_2t p, const area destarea,
1597 const style& sty = k::no_style);
1598
1599 void
1601
1602 void
1605
1606 void
1607 add_desc(const string desc)
1608 {
1609 desc_element de;
1610 de.start_element(desc);
1611 de.finish_element();
1612 add_element(de);
1613 }
1614
1615 void
1617
1618 void
1619 write();
1620
1621 void
1622 start(const string& desc = "")
1623 {
1624 this->start_element();
1625 this->add_title();
1626 if (!desc.empty())
1627 this->add_desc(desc);
1628 }
1629
1630 void
1631 finish(const bool writep = true)
1632 {
1633 this->finish_element();
1634 if (writep)
1635 this->write();
1636 }
1637};
1638/// @} group elements
1639
1640} // namespace svg
1641
1642#endif
void start_element(const string dsc)
static string start_tspan_x(uint xpos, uint dx)
void start_element(string name, const transform, const string ts, const style &sty=k::no_style)
void add_data(const string &url)
void add_data(const stroke_style &sstyl)
string gaussian_blur(string in, string dev)
static constexpr const char * pair_open_tag
void add_filter(const string id)
void start_element(const string id, const ssize_type radius=0, const ssize_type cx=0, const ssize_type cy=0)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
virtual void add_text(string txt)
stream_type _M_sstream
Virtual, only one buffer.
void start_element(const string &id)
void start_element(const string id, const ssize_type radius, const ssize_type cx, const ssize_type cy, const ssize_type fr, const ssize_type fx, const ssize_type fy)
static const script_element tooltip_script(const scope context)
void add_style(const style &sty)
virtual void add_text(string txt)
void str(const string &s)
void start_element(const string id)
void add_data(const data &d, const string dasharray="")
svg_element(const string __title, const area &__cv, const bool lifetime=true, const unit u=svg::unit::pixel, const typography &__typo=k::smono_typo)
void add_data(const string fltr)
void add_data(const area<> a, const string src, const string mtype="image/jpeg", const string attr=R"(sandbox="allow-scripts allow-same-origin")")
iframe. a is width and height of video as embedded in page r is the foreign object,...
const string offset_percentage(const ssize_type numer, const ssize_type denom)
void start_element(const string id, const area<> blur_area, const point_2t p)
static const string & tooltip_javascript(const scope context)
showTooltip(id) hideTooltip(id) event.x vs. event.pageX, event.y vs. event.pageY
void add_desc(const string desc)
text_path_element(const string name, const string off="", const string whichside="")
void add_data(const area<> a, const string src, const string mtype="image/jpeg", const string attr=R"(sandbox="allow-scripts allow-same-origin")")
Add resource to object.
static string finish_tspan()
void start_element(const string &id)
void add_data(const data &d, string trans="")
void add_transform(const string s)
Common transforms include rotate(180)
void start_element(string name)
static string finish_defs()
static constexpr const char * pair_finish_tag
static string finish_group()
const point_2t center_point()
void add_data(const area<> a, const string src, const string mtype="video/mp4", const string attr=R"(autoplay="true" loop="true" muted="true")")
Video. a is width and height of video as embedded in page r is the foreign object,...
static constexpr const char * self_finish_tag
void add_data(const string scriptstr)
Add string with script source.
void add_title(const string &t)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void start_element(string name, const style &sty)
void start_element()
SVG element beginning boilerplate for outermost (containing) svg_element. Variable: unit,...
void stop(const string off, const color &klr, const double opacity=1.0)
static string start_defs()
string gaussian_blur(string dev)
static const string tooltip_attribute(const string &id)
void start_element(const point_2t p, const area destarea, const style &sty=k::no_style)
static constexpr const char * finish_tag
static string start_group(const string name="")
static string start_tspan_y(uint xpos, string dy)
For text list output, use tspan for line breaks. This span creates a new horizontal line for every ts...
void add_data(const data &d, const string trans="", const unit utype=svg::unit::point)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
static string start_tspan_y(uint xpos, uint dy)
static constexpr const char * pair_finish_tag
virtual void start_element()=0
void start_element(const string &id)
svg_element(const string __title, const string desc, const area &__cv, const bool lifetime=true)
void start_element(string name)
void add_data(const data &d, const string cors, const string vattr, const string display="")
Visibility and other HTML/img attributes.
static string start_tspan_x(uint xpos, string dx)
For text list output, use tspan for line breaks. This span creates a new vertical line space for ever...
std::ostringstream stream_type
static constexpr const char * pair_finish_tag
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void start_element(const string &id)
const typography & _M_typo
void add_raw(const string &raw)
void start_element(const string name)
scope
Where is the script element placed? On/within the element itself, or at the document (global)?...
virtual void finish_element()=0
bool empty()
Empty when the output buffer is.
void add_fill(const string id)
void start_element(const point_2t origin, const area<> av, const area<> arect, const point_2t scale=std::make_tuple(1.0, 1.0))
void start_element(const string id, const area<> a, const point_2t p)
void add_data(const string &url, const string relt, const string ast, const string cors="anonymous")
Overload for rel=x form. https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/p...
void start(const string &desc="")
string str() const
void add_element(const element_base &e)
void start_element(const string t)
svg::area< atype > area
void finish(const bool writep=true)
static constexpr const char * pair_open_tag
void start_element(const string &id)
static constexpr string finish_tag_hard
polyline_element(const vrange &points)
svg_element(const svg_element &other)
void start_element(string name)
For groups of elements that have the same name.
string make_tspan_y_from_string_by_token(string s, uint xpos, const char token=' ')
Make text span.
void store_element(const element_base &e)
Abstract base class for all SVG Elements.
iframe HTML object embedded in SVG container. NB: HTML elements video/audio/iframe/canvas can be used...
Linear gradients https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient.
HTML object embedded in SVG container. Unlike image_elements, object_elements are not locked down for...
Circular gradients https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient.
video HTML object embedded in SVG container. NB: HTML elements video/audio/iframe/canvas can be used ...
color
Color enumerated as types.
unit
Measurement abstraction for absolute (not relative) measurements.
@ pt
Point where 1 pixel x 1/72 dpi x 96 PPI = .26 mm.
int ssize_type
Definition a60-svg.h:59
const string to_string(const unit e)
void string_replace(std::string &target, const std::string &match, const std::string &replace)
Definition a60-svg.h:43
double space_type
Base floating point type.
Definition a60-svg.h:62
std::vector< point_2t > vrange
Definition a60-svg.h:86
unsigned int uint
Definition a60-svg.h:57
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space.
Definition a60-svg.h:65
Color quantified as integral RGB components in the range [0,255]. aka like Scalar in OpenCV.
Additional path/line/polyline stroke styles.
Datum consolidating style preferences.
Datum consolidating transform possibilities. https://developer.mozilla.org/en-US/docs/Web/SVG/Attribu...
static string translate(int x, int y)
static string scale(double factor)
const std::string add_attribute(const svg::unit utype=svg::unit::pixel) const