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 string
101 {
102 std::ostringstream oss;
103 oss << k::space << "transform=" << k::quote << s << k::quote;
104 return oss.str();
105 }
106
107 void
108 add_transform(const string s)
109 {
110 if (!s.empty())
112 }
113};
114
115
116/**
117 Group SVG element.
118
119 Specification reference:
120 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
121
122 Attributes:
123 x, y, width, height, xlink:xref, preserveAspectRatio
124 */
125struct group_element : virtual public element_base
126{
127 static string
128 start_group(const string name)
129 {
130 string ret("<g");
131 if (!name.empty())
132 {
133 ret += " id=";
134 ret += k::quote;
135 ret += name;
136 ret += k::quote;
137 }
138 ret += ">";
139 ret += k::newline;
140 return ret;
141 }
142
143 static string
145 { return string("</g>") + k::newline; }
146
147 /// For groups of elements that have the same name.
148 ///
149 /// Also, although one can nest SVG elements inside another SVG by
150 /// using an 'image_element', the display quality is lacking in
151 /// inkscape. To work around this, insert the contents of the nested
152 /// SVG into a named group element instead.
153 void
156
157 void
158 start_element(string name)
159 { _M_sstream << start_group(name); }
160
161 // For groups of elements with style as specified.
162 void
163 start_element(string name, const style& sty)
164 {
165 _M_sstream << "<g id=" << k::quote << name << k::quote << k::space;
166 add_style(sty);
167 _M_sstream << '>' << k::newline;
168 }
169
170 // For groups of elements with a transform and style if specified.
171 void
172 start_element(string name, const string ts, const style& sty = k::no_style)
173 {
174 _M_sstream << "<g id=" << k::quote << name << k::quote;
175 add_transform(ts);
176
177 // Only add style if it is not the default argument.
178 const color_qi nklr(color::none);
179 const bool stylep = to_string(sty._M_fill_color) != to_string(nklr);
180 if (stylep)
181 add_style(sty);
182 _M_sstream << '>' << k::newline;
183 }
184
185 void
187};
188
189void
192
193
194/**
195 Definitions SVG element. Storage space for elements used later.
196
197 Specification reference:
198 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
199
200 Attributes:
201 id
202 */
203struct defs_element : virtual public element_base
204{
205 static string
207 { return "<defs>"; }
208
209 static string
211 { return "</defs>"; }
212
213 void
215 { _M_sstream << start_defs() << k::newline; }
216
217 void
219};
220
221void
224
225void
232
233
234/**
235 Link SVG element. a
236
237 Specification reference:
238 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a
239
240 Attributes:
241 id
242 */
243struct link_element : virtual public element_base
244{
245 void
247 { _M_sstream << "<a "; }
248
249 void
251
252 void
253 add_data(const string& url)
254 {
255 _M_sstream << "href=" << k::quote << url << k::quote;
257 }
258
259 /// Overload for rel=x form.
260 /// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload
261 /// @param relt attribute that describes the relationship of the
262 /// target object to the link object
263 /// @param ast type of resource.
264 void
265 add_data(const string& url, const string relt, const string ast,
266 const string cors = "anonymous")
267 {
268 _M_sstream << "rel=" << k::quote << relt << k::quote << k::space;
269 _M_sstream << "href=" << k::quote << url << k::quote << k::space;
270 _M_sstream << "as=" << k::quote << ast << k::quote << k::space;
271 _M_sstream << "crossorigin=" << k::quote << cors << k::quote << k::space;
272 _M_sstream << "referrerpolicy=" << k::quote << "no-referrer" << k::quote;
273 _M_sstream << k::space;
275 }
276};
277
278void
280{ _M_sstream << "</a>" << k::newline; }
281
282
283/**
284 Datum consolidating filter use and preferences.
285
286 \verbatim
287 <filter id="gblur10" x="0" y="0">
288 <feGaussianBlur in="SourceGraphic" stdDeviation="10" />
289 <feOffset dx="0" dy="0" />
290 </filter>
291 \endverbatim
292*/
293struct filter_element : virtual public element_base
294{
295 enum class type
296 {
297 feBlend, ///< Blend
298 feImage, ///< Image
299 feOffset, ///< Offset, dx="0", dy="0"
300 feGaussianBlur, ///< Gaussian Blur
303 };
304
305 void
307 { _M_sstream << "<filter>" << k::newline; }
308
309 void
310 start_element(const string id)
311 {
312 _M_sstream << "<filter id=" << k::quote << id << k::quote << ">"
313 << k::newline;
314 }
315
316 // Some filter effects get clipped when appied to an element's area,
317 // so this allows filters to have an element + filter area instead.
318 void
319 start_element(const string id, const area<> blur_area, const point_2t p)
320 {
321 auto [ width, height ] = blur_area;
322 auto [ x, y ] = p;
323 _M_sstream << "<filter id=" << k::quote << id << k::quote << k::space
324 << "x=" << k::quote << x << k::quote << k::space
325 << "y=" << k::quote << y << k::quote << k::space
326 << "width=" << k::quote << width << k::quote << k::space
327 << "height=" << k::quote << height << k::quote
328 << ">"
329 << k::newline;
330 }
331
332 void
334
335 void
336 add_data(const string fltr)
337 { _M_sstream << fltr; }
338
339 // https://drafts.fxtf.org/filter-effects/#elementdef-fegaussianblur
340 // in == SourceGraphic, SourceAlpha, FillPaint, StrokePaint
341 // dev == 1 or 1,1 (0 default if two then x, y direction)
342 string
343 gaussian_blur(string in, string dev)
344 {
345 // <feGaussianBlur in="SourceGraphic" stdDeviation="20" />
346 stream_type stream;
347 stream << "<feGaussianBlur in=";
348 stream << k::quote << in << k::quote << k::space;
349 stream << "stdDeviation=" << k::quote << dev << k::quote << k::space;
350 stream << "/>";
351 return stream.str();
352 }
353
354 string
355 gaussian_blur(string dev)
356 { return gaussian_blur("SourceGraphic", dev); }
357};
358
359void
361{ _M_sstream << "</filter>" << k::newline; }
362
363
364/**
365 Gradient SVG elements.
366
367 Specification reference:
368 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient
369 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
370
371 Note these are always inside a defs block.
372
373 Attributes:
374 id
375 */
376struct gradient_element : virtual public defs_element
377{
378 enum class type
379 {
380 linearGradient, ///< Linear
381 meshgradient, ///< Mesh
382 radialGradient, ///< Radial
383 stop ///< stop, last
384 };
385
386 void
389
390 void
392
393 // off == 10%
394 void
395 stop(const string off, const color& klr, const double opacity = 1.0)
396 {
397 _M_sstream << "<stop offset=" << k::quote << off << k::quote << k::space
398 << "stop-color=" << k::quote << to_string(klr) << k::quote;
399 if (opacity < 1.0)
400 {
401 _M_sstream << k::space
402 << "stop-opacity=" << k::quote << opacity << k::quote;
403 }
404 _M_sstream << " />";
405 _M_sstream << k::newline;
406 }
407
408 // Express two integers as a suitable offset string percentage.
409 const string
410 offset_percentage(const ssize_type numer, const ssize_type denom)
411 {
412 const double ratio = static_cast<double>(numer)/static_cast<double>(denom);
413 const ssize_type perc(round(ratio * 100));
414 return std::to_string(perc) + "%";
415 }
416};
417
418void
421
422
423/// Circular gradients
424/// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient
425struct radial_gradient : virtual public gradient_element
426{
427 void
429 {
431 _M_sstream << "<radialGradient id=" << k::quote << "default" << k::quote;
432 _M_sstream << ">" << k::newline;
433 }
434
435 // Radial gradient centered at (cx, cy) of radius.
436 // Default for radius, cx, cy is "50%"
437 void
438 start_element(const string id, const ssize_type radius = 0,
439 const ssize_type cx = 0, const ssize_type cy = 0)
440 {
442 _M_sstream << "<radialGradient id=" << k::quote << id << k::quote;
443 if (radius > 0)
444 {
445 _M_sstream << k::space << "r=" << k::quote << radius << k::quote;
446 _M_sstream << k::space << "cx=" << k::quote << cx << k::quote;
447 _M_sstream << k::space << "cy=" << k::quote << cy << k::quote;
448 }
449 _M_sstream << ">" << k::newline;
450 }
451
452 // Radial gradient.
453 // End circle (aka 100% stop) at (cx, cy) with radius.
454 // Start circle (aka 0% stop) at (fx, fy) with radius fr.
455 void
456 start_element(const string id, const ssize_type radius,
457 const ssize_type cx, const ssize_type cy, const ssize_type fr,
458 const ssize_type fx, const ssize_type fy)
459 {
461 _M_sstream << "<radialGradient id=" << k::quote << id << k::quote
462 << k::space << "r=" << k::quote << radius << k::quote;
463 _M_sstream << k::space << "cx=" << k::quote << cx << k::quote;
464 _M_sstream << k::space << "cy=" << k::quote << cy << k::quote;
465 if (fr > 0)
466 {
467 _M_sstream << k::space << "fx=" << k::quote << fx << k::quote;
468 _M_sstream << k::space << "fy=" << k::quote << fy << k::quote;
469 _M_sstream << k::space << "fr=" << k::quote << fr << k::quote;
470 }
471 _M_sstream << ">" << k::newline;
472 }
473
474 void
476};
477
478void
480{
481 _M_sstream << "</radialGradient>" << k::newline;
483}
484
485
486/// Linear gradients
487/// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
488struct linear_gradient : virtual public gradient_element
489{
490 void
492 {
494 _M_sstream << "<linearGradient id=" << k::quote << "default" << k::quote;
495 _M_sstream << ">" << k::newline;
496 }
497
498 void
500};
501
502void
504{
505 _M_sstream << "</linearGradient>" << k::newline;
507}
508
509
510/**
511 Marker SVG elements defines a graphic used for drawing
512 arrow[heads, tails, mid] on a poly line or path.
513
514 Specification reference:
515 https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-mid
516
517 Note these are always inside a defs block.
518
519 Attributes:
520 id
521 */
522struct marker_element : virtual public element_base
523{
524 void
526
527 // markerWidth="8" markerHeight="8" refX="4" refY="4">
528 void
529 start_element(const string id, const area<> a, const point_2t p)
530 {
531 auto [ x, y ] = p;
532 auto [ w, h ] = a;
533 _M_sstream << "<marker id=" << k::quote << id << k::quote << k::space
534 << "markerWidth=" << k::quote << w << k::quote << k::space
535 << "markerHeight=" << k::quote << h << k::quote << k::space
536 << "refX=" << k::quote << x << k::quote << k::space
537 << "refY=" << k::quote << y << k::quote << " >"
538 << k::newline;
539 }
540
541 void
543};
544
545void
547{
548 _M_sstream << "</marker>" << k::newline;
549}
550
551
552/**
553 Title SVG element. This is accessible/alt text.
554 This element must be the first element in the svg objectc.
555
556 A title element with no string indicates a decorative element to AT
557 screenreaders.
558
559 Specification reference:
560 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
561*/
562struct title_element : virtual public element_base
563{
564 void
566 { _M_sstream << "<title>" << k::newline; }
567
568 void
569 start_element(const string t)
570 {
572 _M_sstream << t << k::newline;
573 }
574
575 void
577};
578
579void
581{ _M_sstream << "</title>" << k::newline; }
582
583
584/**
585 Description SVG element.
586
587 Specification reference:
588 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
589*/
590struct desc_element : virtual public element_base
591{
592 void
594
595 void
596 start_element(const string dsc)
597 { _M_sstream << "<desc>" << k::newline << dsc << k::newline; }
598
599 void
601};
602
603void
605{ _M_sstream << "</desc>" << k::newline; }
606
607
608/**
609 Text SVG element.
610
611 Specification reference:
612 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text
613
614 Attributes:
615 x, y, dx, dy, text-anchor, rotate, textLength, lengthAdjust
616*/
617struct text_element : virtual public element_base
618{
626
627 /// Either serialize immediately (as below), or create data structure
628 /// that adds data to data_vec and then finish_element serializes.
629 void
630 add_data(const data& d,
631 const string trans = "", const unit utype = svg::unit::point)
632 {
633 const string x("__x");
634 const string y("__y");
635 const string attr("__attr");
636 const string style("__style");
637
638 string strip = R"_delimiter_(x="__x" y="__y" __attr __style)_delimiter_";
639
640 // Add attributes.
641 string_replace(strip, x, std::to_string(d._M_x_origin));
642 string_replace(strip, y, std::to_string(d._M_y_origin));
643 string_replace(strip, attr, d._M_typo.add_attribute(utype));
645 _M_sstream << strip;
646 add_transform(trans);
647 _M_sstream << '>';
648
649 // Add text data.
650 add_raw(d._M_text);
651 }
652
653 void
655 { _M_sstream << "<text "; }
656
657 void
659
660 /// For text list output, use tspan for line breaks. This span
661 /// creates a new horizontal line for every tspan block, starting at
662 /// xpos with spacing dy (1.2em).
663 static string
664 start_tspan_y(uint xpos, string dy)
665 {
666 const string x("__x");
667 const string dys("__dy");
668 string strip = R"_delimiter_(<tspan x="__x" dy="__dy">)_delimiter_";
669 string_replace(strip, x, std::to_string(xpos));
670 string_replace(strip, dys, dy);
671 return strip;
672 }
673
674 static string
676 { return start_tspan_y(xpos, std::to_string(dy)); }
677
678 /// For text list output, use tspan for line breaks. This span
679 /// creates a new vertical line space for every tspan block, starting
680 /// at xpos with horizontal spacing dx ("1.4em").
681 static string
682 start_tspan_x(uint xpos, string dx)
683 {
684 const string x("__x");
685 const string dxs("__dx");
686 string strip = R"_delimiter_(<tspan x="__x" dx="__dx">)_delimiter_";
687 string_replace(strip, x, std::to_string(xpos));
688 string_replace(strip, dxs, dx);
689 return strip;
690 }
691
692 static string
694 { return start_tspan_x(xpos, std::to_string(dx)); }
695
696 static string
698 { return "</tspan>"; }
699};
700
701void
703{ _M_sstream << "</text>" << k::newline; }
704
705
706/// Make text span.
707string
708make_tspan_y_from_string_by_token(string s, uint xpos, const char token = ' ')
709{
710 string start(text_element::start_tspan_y(xpos, "0.5em"));
711 string ret = start;
712 for (uint i = 0; i < s.size(); ++i)
713 {
714 const char c = s[i];
715 if (c != token)
716 ret += c;
717 else
718 {
720 if (i < s.size() - 1)
721 ret += start;
722 }
723 }
725 return ret;
726}
727
728
729/**
730 Rectangle SVG element.
731
732 Specification reference:
733 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect
734
735 Attributes:
736 x, y, width, height, rx, ry
737 */
738struct rect_element : virtual public element_base
739{
747
748 // Verbose opening/closing pair tags for circle_element.
749 // Default assumes the more compact XML "self-closed tag" for circle element.
750 static constexpr const char* pair_open_tag = "<rect>";
751 static constexpr const char* pair_finish_tag = "</rect>";
752
753 /// Either serialize immediately (as below), or create data structure
754 /// that adds data to data_vec and then finish_element serializes.
755 void
756 add_data(const data& d)
757 {
758 const string x("__x");
759 const string y("__y");
760 const string w("__w");
761 const string h("__h");
762
763 string strip = R"_delimiter_(x="__x" y="__y" width="__w" height="__h"
764)_delimiter_";
765
766 string_replace(strip, x, std::to_string(d._M_x_origin));
767 string_replace(strip, y, std::to_string(d._M_y_origin));
768 string_replace(strip, w, std::to_string(d._M_width));
769 string_replace(strip, h, std::to_string(d._M_height));
770 _M_sstream << strip;
771 }
772
773 void
775 { _M_sstream << "<rect "; }
776
777 void
779};
780
781void
784
785
786/**
787 Circle SVG element.
788
789 Specification reference:
790 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle
791
792 Attributes:
793 x, y, width, height, xlink:xref, preserveAspectRatio
794 */
795struct circle_element : virtual public element_base
796{
803
804 // Verbose opening/closing pair tags for circle_element.
805 // Default assumes the more compact XML "self-closed tag" for circle element.
806 static constexpr const char* pair_open_tag = "<circle>";
807 static constexpr const char* pair_finish_tag = "</circle>";
808
809 // Either serialize immediately (as below), or create data structure
810 // that adds data to data_vec and then finish_element serializes.
811 void
812 add_data(const data& d, string trans = "")
813 {
814 const string x("__x");
815 const string y("__y");
816 const string r("__r");
817
818 string strip = R"_delimiter_(cx="__x" cy="__y" r="__r")_delimiter_";
819
820 string_replace(strip, x, std::to_string(d._M_x_origin));
821 string_replace(strip, y, std::to_string(d._M_y_origin));
822 string_replace(strip, r, std::to_string(d._M_radius));
823 _M_sstream << strip;
824 add_transform(trans);
825 }
826
827 void
829 { _M_sstream << "<circle "; }
830
831 void
833
834};
835
836void
839
840
841/**
842 Polygon SVG element.
843
844 Specification reference:
845 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon
846
847 Attributes:
848 points
849 */
850struct polygon_element : virtual public element_base
851{
852 // Verbose opening/closing pair tags for circle_element.
853 // Default assumes the more compact XML "self-closed tag" for circle element.
854 static constexpr const char* pair_open_tag = "<polygon>";
855 static constexpr const char* pair_finish_tag = "</polygon>";
856
857 void
859 { _M_sstream << "<polygon "; }
860
861 void
862 add_data(const vrange& points)
863 {
864 _M_sstream << "points=" << k::quote;
865 _M_sstream << std::setprecision(2);
866 for (const auto& [ x, y ]: points)
867 _M_sstream << x << k::comma << y << k::space;
868 _M_sstream << k::quote << k::newline;
869 }
870
871 void
873};
874
875
876void
879
880
881/**
882 Line SVG element.
883
884 Specification reference:
885 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line
886
887 Attributes:
888 x, y, width, height, xlink:xref, preserveAspectRatio
889*/
890struct line_element : virtual public element_base
891{
899
900 // Either serialize immediately (as below), or create data structure
901 // that adds data to data_vec and then finish_element serializes.
902 void
903 add_data(const data& d, const string dasharray = "")
904 {
905 const string x1("__x1");
906 const string x2("__x2");
907 const string y1("__y1");
908 const string y2("__y2");
909 const string dash("__darray");
910
911 const bool dashp = !dasharray.empty();
912 string stripf = \
913 R"_delimiter_(x1="__x1" y1="__y1" x2="__x2" y2="__y2")_delimiter_";
914 string stript = \
915 R"_delimiter_(x1="__x1" y1="__y1" x2="__x2" y2="__y2" stroke-dasharray="__darray")_delimiter_";
916
917 string strip = dashp ? stript : stripf;
918 string_replace(strip, x1, std::to_string(d._M_x_begin));
919 string_replace(strip, x2, std::to_string(d._M_x_end));
920 string_replace(strip, y1, std::to_string(d._M_y_begin));
921 string_replace(strip, y2, std::to_string(d._M_y_end));
922
923 if (dashp)
924 string_replace(strip, dash, dasharray);
925 _M_sstream << strip;
926 }
927
928 void
930 { _M_sstream << "<line "; }
931
932 void
933 start_element(string name)
934 { _M_sstream << "<line id=" << k::quote << name << k::quote << k::space; }
935
936 void
938};
939
940void
943
944
945/**
946 Polyline SVG element.
947
948 Specification reference:
949 https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline
950
951 Attributes:
952 points, pathLength
953*/
954struct polyline_element : virtual public element_base
955{
956 // vector<point_2t> == vector<tuple<double,double>>
958
960
961 polyline_element(const vrange& points) : polypoints(points) { }
962
963 // Either serialize immediately (as below), or create data structure
964 // that adds data to data_vec and then finish_element serializes.
965 void
966 add_data(const stroke_style& sstyl)
967 {
968 if (!polypoints.empty())
969 {
970 _M_sstream << "points=" << k::quote;
971 for (const point_2t& pt : polypoints)
972 {
973 auto [ x, y ] = pt;
974 _M_sstream << x << k::comma << y << k::space;
975 }
976 _M_sstream << k::quote << k::space;
977
978 if (!sstyl.dasharray.empty())
979 {
980 _M_sstream << "stroke-dasharray=" << k::quote;
981 _M_sstream << sstyl.dasharray << k::quote << k::space;
982 }
983 if (!sstyl.dashoffset.empty())
984 {
985 _M_sstream << "stroke-dashoffset=" << k::quote;
986 _M_sstream << sstyl.dashoffset << k::quote << k::space;
987 }
988 if (!sstyl.linecap.empty())
989 {
990 _M_sstream << "stroke-linecap=" << k::quote;
991 _M_sstream << sstyl.linecap << k::quote << k::space;
992 }
993 if (!sstyl.marker_defs.empty())
994 {
995 // line_style 3
996 string mkr;
997 mkr += k::quote;
998 mkr += "url(#";
999 mkr += sstyl.marker_defs;
1000 mkr += ")";
1001 mkr += k::quote;
1002
1003 _M_sstream << "marker-mid=" << mkr << k::space;
1004 _M_sstream << "marker-end=" << mkr << k::space;
1005 }
1006 }
1007 }
1008
1009 void
1011 { _M_sstream << "<polyline "; }
1012
1013 void
1014 start_element(string name)
1015 { _M_sstream << "<polyline id=" << k::quote << name << k::quote << k::space; }
1016
1017 void
1019};
1020
1021void
1024
1025
1026
1027/**
1028 Path SVG element.
1029
1030 Specification reference:
1031 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
1032
1033 Attributes:
1034 d, pathLength
1035*/
1036struct path_element : virtual public element_base
1037{
1038 struct data
1039 {
1040 string _M_d;
1042 };
1043
1044 // Verbose opening/closing pair tags for path_element.
1045 // Default assumes the more compact XML "self-closed tag" for circle element.
1046 static constexpr const char* pair_open_tag = "<path>";
1047 static constexpr const char* pair_finish_tag = "</path>";
1048
1049 /// Either serialize immediately (as below), or create data structure
1050 /// that adds data to data_vec and then finish_element serializes.
1051 void
1052 add_data(const data& d)
1053 {
1054 const string pathd("__d");
1055 const string len("__l");
1056
1057 string strip = R"_delimiter_(d="__d")_delimiter_";
1058
1059 string_replace(strip, pathd, d._M_d);
1060 string_replace(strip, len, std::to_string(d._M_length));
1061 _M_sstream << strip;
1062 }
1063
1064 void
1066 { _M_sstream << "<path "; }
1067
1068 void
1069 start_element(const string name)
1070 { _M_sstream << "<path id=" << k::quote << name << k::quote << k::space; }
1071
1072 void
1074};
1075
1076void
1082
1083
1084/**
1085 Text on a Path SVG element.
1086
1087 Specification reference:
1088 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath
1089
1090 Attributes:
1091 href, path, method, side, spacing, startOffset, textLength, lengthAdjust
1092*/
1093struct text_path_element : virtual public text_element
1094{
1096 string offset; // "30%"
1097 string side; // "left" || "right" (use convex/concave side of path)
1098
1099 text_path_element(const string name,
1100 const string off = "", const string whichside = "")
1101 : path_name(name), offset(off), side(whichside) { }
1102
1103 virtual void
1104 add_text(string txt)
1105 {
1106 // Start text_path_element...
1107 _M_sstream << "<textPath xlink:href="
1108 << k::quote << '#' << path_name << k::quote;
1109 if (!offset.empty())
1110 _M_sstream << k::space << "startOffset="
1111 << k::quote << offset << k::quote;
1112 if (!side.empty())
1113 _M_sstream << k::space << "side="
1114 << k::quote << side << k::quote;
1115 _M_sstream << '>';
1116
1117 _M_sstream << txt;
1118
1119 // End text_path_element...
1120 _M_sstream << "</textPath>" << k::space;
1121 }
1122};
1123
1124
1125
1126/**
1127 Image SVG element. This can be another SVG file, or can be a raster
1128 image format like PNG or JPEG.
1129
1130 Specification reference:
1131 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
1132
1133 Attributes:
1134 x, y, width, height, xlink:xref, preserveAspectRatio
1135 */
1136struct image_element : virtual public element_base
1137{
1146
1147 void
1148 start_element(const string& id)
1149 {
1150 const string simg = "<image";
1151 _M_sstream << simg << k::space;
1152 if (!id.empty())
1153 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1154 }
1155
1156 void
1159
1160 void
1162
1163 /// Either serialize immediately (as below), or create data structure
1164 /// that adds data to data_vec and then finish_element serializes.
1165 void
1166 add_data(const data& d)
1167 {
1168 const string x("__x");
1169 const string y("__y");
1170 const string w("__w");
1171 const string h("__h");
1172 const string ref("__ref");
1173
1174 string strip = R"_delimiter_(href="__ref" x="__x" y="__y" width="__w" height="__h")_delimiter_";
1175
1176 string_replace(strip, ref, d._M_xref);
1177 string_replace(strip, x, std::to_string(d._M_x_origin));
1178 string_replace(strip, y, std::to_string(d._M_y_origin));
1179 string_replace(strip, w, std::to_string(d._M_width));
1180 string_replace(strip, h, std::to_string(d._M_height));
1181 _M_sstream << strip << k::space;
1182 }
1183
1184 /// Visibility and other HTML/img attributes.
1185 /// @param vattr = visibility attribute, "visible" or "hidden"
1186 /// @param display = display attribute, "none" or "unset" or "initial"
1187 /// @param cors = CORS, "anonymous" or "use-credentials"
1188 /// @param lattr = loading attribute, "lazy" or "eager"
1189 void
1190 add_data(const data& d, const string cors, const string vattr,
1191 const string display = "")
1192 {
1193 add_data(d);
1194
1195 if (!cors.empty())
1196 _M_sstream << "crossorigin=" << k::quote << cors << k::quote << k::space;
1197 if (!vattr.empty())
1198 _M_sstream << "visibility=" << k::quote << vattr << k::quote << k::space;
1199 if (!display.empty())
1200 _M_sstream << "display=" << k::quote << display << k::quote << k::space;
1201 }
1202};
1203
1204
1205void
1208
1209
1210/**
1211 So-called Foreign Objects.
1212
1213 Using to get HTML video elements.
1214
1215 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject
1216 https://stackoverflow.com/questions/40324916/video-tag-embedded-in-svg
1217
1218Translate moves the origin from the top left to the specified
1219coordinates. If you embed an object at 0,0 it will be placed at the
1220new origin. In this case you must embed it at -translation
1221coordinates.
1222
1223Even so, I had to increase the width and height. Why? I don't know. It
1224doesn't seem to be a scale by 2. If someone knows I am curious to
1225know.
1226
1227<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;">
1228 <g>
1229 <g transform="translate(151,104) scale(1,1)">
1230 <rect x="0" y="0" width="300" height="200"></rect>
1231 <foreignObject x="-151" y="-104" width="500" height="400">
1232 <video xmlns="http://www.w3.org/1999/xhtml" width="300" height="200" controls="" style="position: fixed; left: 151px; top: 104px;">
1233 <source src="http://techslides.com/demos/sample-videos/small.mp4" type="video/mp4" />less
1234 </video>
1235 </foreignObject>
1236 </g>
1237 </g>
1238</svg>
1239*/
1240struct foreign_element : virtual public element_base
1241{
1242 void
1244 { _M_sstream << "<g>" << k::newline; }
1245
1246 // av == area of the foreign object and native video frame size
1247 // arect == area of displayed video as embedded inside svg element /aka page
1248 // scale_pair == x/y scaling factor
1249 void
1250 start_element(const point_2t origin, const area<> av, const area<> /*arect*/,
1251 const point_2t scale = std::make_tuple(1.0, 1.0))
1252 {
1253 const auto [ scalex, scaley ] = scale;
1254 const auto [ ox, oy ] = origin;
1255
1256 //const auto [ width, height ] = arect;
1257 //auto xo = width/2;
1258 //auto yo = height/2;
1259
1260 const auto [ vwidth, vheight ] = av;
1261
1262 // Outer group.
1263 group_element go;
1264 go.start_element();
1265 _M_sstream << go.str() << k::newline;
1266
1267 // Inner Group.
1268 group_element gi;
1269 //string tx = transform::translate(xo, yo);
1270 string tscl = transform::scale(scalex, scaley);
1271 gi.start_element(string("video-wrapper"), tscl);
1272 _M_sstream << gi.str() << k::newline;
1273
1274 // Foreign Object
1275 string strip = R"(<foreignObject x="XXX" y="YYY" width="WWW" height="HHH">)";
1276 string_replace(strip, "WWW", std::to_string(vwidth));
1277 string_replace(strip, "HHH", std::to_string(vheight));
1278 string_replace(strip, "XXX", std::to_string(ox));
1279 string_replace(strip, "YYY", std::to_string(oy));
1280 _M_sstream << strip << k::newline;
1281 }
1282
1283 void
1285};
1286
1287void
1289{ _M_sstream << " </foreignObject></g></g>" << k::newline; }
1290
1291
1292/// video HTML object embedded in SVG container.
1293/// NB: HTML elements video/audio/iframe/canvas can be used w/o foreignElement.
1294/// This approach uses HTML wrapped in foreign element.
1295/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1296/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
1297struct video_element : virtual public foreign_element
1298{
1299 void
1300 start_element(const string& id)
1301 {
1302 //const string svideo = "<html:video";
1303 const string svideo = R"(<video xmlns="http://www.w3.org/1999/xhtml" )";
1304 _M_sstream << svideo << k::space;
1305 if (!id.empty())
1306 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1307 }
1308
1309 void
1312
1313 /// Video.
1314 /// a is width and height of video as embedded in page
1315 /// r is the foreign object, with x/y offset and scaled size
1316 ///
1317 /// attr is attribues for video_element
1318 /// autoplay="true" or removed
1319 /// loop="true/false"
1320 /// muted="true/false"
1321 /// controls, controlslist,
1322 /// crossorigin, disablepictureinpicture, disableremoteplayback
1323 ///
1324 void
1325 add_data(const area<> a, const string src, const string mtype = "video/mp4",
1326 const string attr = R"(autoplay="true" loop="true" muted="true")")
1327 {
1328 string strip = R"(width="WWW" height="HHH" )";
1329 string_replace(strip, "WWW", std::to_string(a._M_width));
1330 string_replace(strip, "HHH", std::to_string(a._M_height));
1331 _M_sstream << k::space;
1332 _M_sstream << strip << k::space;
1333 _M_sstream << attr << k::space;
1335
1336 _M_sstream << "<source src=" << k::quote << src << k::quote << k::space;
1337 _M_sstream << "type=" << k::quote << mtype << k::quote;
1339 }
1340
1341 void
1343};
1344
1345void
1347{ _M_sstream << "</video>" << k::newline; }
1348
1349
1350/// iframe HTML object embedded in SVG container.
1351/// NB: HTML elements video/audio/iframe/canvas can be used w/o foreignElement.
1352/// This approach uses HTML wrapped in foreign element.
1353/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1354/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
1355struct iframe_element : virtual public foreign_element
1356{
1357 void
1358 start_element(const string& id)
1359 {
1360 //const string siframe = "<html:iframe";
1361 const string siframe = R"(<iframe xmlns="http://www.w3.org/1999/xhtml" )";
1362 _M_sstream << siframe << k::space;
1363 if (!id.empty())
1364 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1365 }
1366
1367 void
1370
1371 /// iframe.
1372 /// a is width and height of video as embedded in page
1373 /// r is the foreign object, with x/y offset and scaled size
1374 ///
1375 void
1376 add_data(const area<> a, const string src, const string mtype = "image/jpeg",
1377 const string attr = R"(sandbox="allow-scripts allow-same-origin")")
1378 {
1379 string strip = R"(width="WWW" height="HHH" )";
1380 string_replace(strip, "WWW", std::to_string(a._M_width));
1381 string_replace(strip, "HHH", std::to_string(a._M_height));
1382 _M_sstream << k::space;
1383 _M_sstream << strip << k::space;
1384 // _M_sstream << "src=" << k::quote << src << k::quote << k::space;
1385 _M_sstream << attr;
1387
1388 // image/webp or image/jpeg
1389 _M_sstream << "<source src=" << k::quote << src << k::quote << k::space;
1390 _M_sstream << "type=" << k::quote << mtype << k::quote << k::space;
1392 }
1393
1394 void
1396};
1397
1398void
1400{ _M_sstream << "</iframe>" << k::newline; }
1401
1402
1403/// HTML object embedded in SVG container.
1404/// Unlike image_elements, object_elements are not locked down for scripting.
1405/// NB: HTML elements video/audio/object/canvas can be used w/o foreignElement.
1406/// This approach uses HTML wrapped in foreign element.
1407/// https://www.w3.org/TR/SVG2/embedded.html#HTMLElements
1408/// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object
1409struct object_element : virtual public foreign_element
1410{
1411 void
1412 start_element(const string& id)
1413 {
1414 //const string sobject = "<html:object";
1415 const string sobject = R"(<object xmlns="http://www.w3.org/1999/xhtml" )";
1416 _M_sstream << sobject << k::space;
1417 if (!id.empty())
1418 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1419 }
1420
1421 void
1424
1425 /// Add resource to object.
1426 /// @param a is width and height of video as embedded in page
1427 /// @param src is the resource URL
1428 /// @param mtype is the MIME type
1429 /// @param attr is any collection of ad-hoc HTML attributes.
1430 void
1431 add_data(const area<> a, const string src, const string mtype = "image/jpeg",
1432 const string attr = R"(sandbox="allow-scripts allow-same-origin")")
1433 {
1434 string strip = R"(width="WWW" height="HHH" )";
1435 string_replace(strip, "WWW", std::to_string(a._M_width));
1436 string_replace(strip, "HHH", std::to_string(a._M_height));
1437 _M_sstream << k::space;
1438 _M_sstream << strip << k::space;
1439 _M_sstream << "data=" << k::quote << src << k::quote << k::space;
1440 _M_sstream << "type=" << k::quote << mtype << k::quote << k::space;
1441 _M_sstream << attr << k::space;
1443 }
1444
1445 void
1447};
1448
1449void
1451{ _M_sstream << "</object>" << k::newline; }
1452
1453
1454/**
1455 A SVG script element.
1456
1457 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/script
1458*/
1459struct script_element : virtual public element_base
1460{
1461 /// Where is the script element placed? On/within the element
1462 /// itself, or at the document (global)? Neither (none),
1463 /// alongside/same level (parent)?
1464 enum class scope
1465 {
1466 none, ///< Script scope removed
1467 document, ///< Scripts scoped to toplevel document
1468 parent, ///< Scripts scoped to parent
1469 element ///< Scripts scoped to element
1470 };
1471
1472 void
1473 start_element(const string& id)
1474 {
1475 const string shead = R"(<script type="text/javascript" crossorigin="anonymous")";
1476 _M_sstream << shead << k::space;
1477 if (!id.empty())
1478 _M_sstream << "id=" << k::quote << id << k::quote << k::space;
1480 }
1481
1482 void
1485
1486 /// showTooltip(id)
1487 /// hideTooltip(id)
1488 /// event.x vs. event.pageX, event.y vs. event.pageY
1489 static const string&
1491 {
1492 static string js_show_element = R"(
1493 function showTooltip(event, tooltipId) {
1494 const tooltipimg = document.getElementById(tooltipId);
1495 if (tooltipimg) {
1496 const ge = tooltipimg.parentElement;
1497 const svge = ge.parentElement;
1498 const brect = ge.getBoundingClientRect();
1499 const bx = brect.left;
1500 const by = brect.top;
1501
1502 tooltipimg.setAttribute('x', event.x + bx);
1503 tooltipimg.setAttribute('y', event.y + by);
1504
1505 tooltipimg.setAttribute('visibility', 'visible');
1506 } else {
1507 console.error(`Element with ID "${tooltipId}" not found.`);
1509 })";
1510
1511 static string js_show_document = R"(
1512 function showTooltip(event, tooltipId) {
1513 const tooltipimg = document.getElementById(tooltipId);
1514 if (tooltipimg) {
1515 //tooltipimg.onload = function() {
1516 const ge = tooltipimg.parentElement;
1517 const svge = ge.parentElement;
1518 const brect = ge.getBoundingClientRect();
1519 const bx = brect.left;
1520 const by = brect.top;
1521
1522 //const iheight = 150;
1523 const iheight = tooltipimg.offsetHeight; //!isNaN(iheight)
1524 tooltipimg.setAttribute('x', event.pageX - bx);
1525 tooltipimg.setAttribute('y', event.pageY - by - iheight);
1526 tooltipimg.setAttribute('visibility', 'visible');
1527 //tooltipimg.setAttribute('display', 'inline');
1528 } else {
1529 console.error(`Element with ID "${tooltipId}" not found.`);
1530 }
1531 })";
1532
1533 static string js_hide = R"(
1534 function hideTooltip(tooltipId) {
1535 const tooltipimg = document.getElementById(tooltipId);
1536 tooltipimg.setAttribute('visibility', 'hidden');
1537 //tooltipimg.setAttribute('display', 'none');
1538 })";
1539
1540 static string js;
1541 if (context == scope::element)
1542 js = js_show_element + k::newline + js_hide;
1543 if (context == scope::document || context == scope::parent)
1544 js = js_show_document + k::newline + js_hide;
1545
1546 return js;
1547 }
1548
1549 static const string
1550 tooltip_attribute(const string& id)
1551 {
1552 const string toolr("__toolt");
1553 string strip1 = R"_delimiter_(onmouseover="showTooltip(event, '__toolt')" )_delimiter_";
1554 string strip2 = R"_delimiter_(onmouseout="hideTooltip('__toolt')" )_delimiter_";
1555 string_replace(strip1, toolr, id);
1556 string_replace(strip2, toolr, id);
1557 return k::space + strip1 + k::space + strip2;
1558 }
1559
1560 // Script element for js to control visibility of images.
1561 static const script_element
1562 tooltip_script(const scope context)
1563 {
1564 script_element scrpt;
1565 scrpt.start_element("tooltip-js");
1566 scrpt.add_data(script_element::tooltip_javascript(context));
1567 scrpt.finish_element();
1568 return scrpt;
1569 }
1570
1571
1572 /// Add string with script source.
1573 /// @param scriptstr script source
1574 void
1575 add_data(const string scriptstr)
1576 {
1577 _M_sstream << scriptstr;
1578 _M_sstream << k::newline;
1579 }
1580
1581 void
1583};
1584
1585void
1587{ _M_sstream << "</script>" << k::newline; }
1588
1589
1590/**
1591 A SVG object element.
1592
1593 https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
1594 https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image
1595*/
1596struct svg_element : virtual public element_base
1597{
1599
1600 const string _M_name;
1604 const bool _M_lifetime; // scope document scope element
1605
1606 svg_element(const string __title, const area& __cv,
1607 const bool lifetime = true,
1608 const unit u = svg::unit::pixel,
1609 const typography& __typo = k::smono_typo)
1610 : _M_name(__title), _M_area(__cv), _M_unit(u),
1611 _M_typo(__typo), _M_lifetime(lifetime)
1612 {
1613 if (_M_lifetime)
1614 start();
1615 }
1616
1617 svg_element(const string __title, const string desc, const area& __cv,
1618 const bool lifetime = true)
1619 : _M_name(__title), _M_area(__cv), _M_unit(svg::unit::pixel),
1620 _M_typo(svg::k::smono_typo), _M_lifetime(lifetime)
1621 {
1622 if (_M_lifetime)
1623 start(desc);
1624 }
1625
1627 : _M_name(other._M_name), _M_area(other._M_area),
1628 _M_unit(other._M_unit), _M_typo(other._M_typo),
1630 { }
1631
1633 {
1634 if (_M_lifetime)
1635 finish();
1636 }
1637
1638 const point_2t
1640 { return _M_area.center_point(); }
1641
1642 void
1643 start_element();
1644
1645 void
1646 start_element(const point_2t p, const area destarea,
1647 const style& sty = k::no_style);
1648
1649 void
1651
1652 void
1655
1656 void
1657 add_desc(const string desc)
1658 {
1659 desc_element de;
1660 de.start_element(desc);
1661 de.finish_element();
1662 add_element(de);
1663 }
1664
1665 void
1666 add_filters();
1667
1668 void
1669 write();
1670
1671 void
1672 start(const string& desc = "")
1673 {
1674 this->start_element();
1675 this->add_title();
1676 if (!desc.empty())
1677 this->add_desc(desc);
1678 }
1679
1680 void
1681 finish(const bool writep = true)
1682 {
1683 this->finish_element();
1684 if (writep)
1685 this->write();
1686 }
1687};
1688/// @} group elements
1689
1690} // namespace svg
1691
1692#endif
void start_element(const string dsc)
static string start_tspan_x(uint xpos, uint dx)
static constexpr const char * pair_finish_tag
void add_data(const string &url)
void start_element(string name, const string ts, const style &sty=k::no_style)
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...
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 finish_element()
SVG element end boilerplate.
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 start_element(const point_2t origin, const area<> av, const area<>, const point_2t scale=std::make_tuple(1.0, 1.0))
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)
static constexpr const char * pair_open_tag
void start_element()
For groups of elements that have the same name.
void start_element(string name)
static string finish_defs()
static constexpr const char * pair_finish_tag
void add_data(const vrange &points)
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)
static constexpr const char * finish_tag
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)
static string start_group(const string name)
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)
@ feOffset
Offset, dx="0", dy="0".
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)?...
@ none
Script scope removed.
@ element
Scripts scoped to element.
@ parent
Scripts scoped to parent.
@ document
Scripts scoped to toplevel document.
virtual void finish_element()=0
bool empty()
Empty when the output buffer is.
static constexpr const char * pair_open_tag
void add_fill(const string id)
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
string make_transform_attribute(const string s)
Common transforms include rotate(180)
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)
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:60
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:44
double space_type
Base floating point type.
Definition a60-svg.h:63
std::vector< point_2t > vrange
Definition izzi-points.h:61
unsigned int uint
Definition a60-svg.h:58
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space, space_type defaults to double.
Definition izzi-points.h:22
Color quantified as integral RGB components in the range [0,255]. aka like Scalar in OpenCV.
Additional path/line/polyline stroke styles. NB: https://yuanchuan.dev/fun-with-stroke-dasharray.
string dashoffset
Starting offset for line dashes. https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-dashoffset.
string dasharray
Line dash vs. space configuration. Options are single value, like 2, meaning 2 sized dash 2 sized spa...
string linecap
Shape of end of line segments in line dashes. SVG Values are: butt, round, square....
string marker_defs
Marker string pointing to definitions elements. For graph_mode 1, this means the SVG equivalent of CS...
Datum consolidating style preferences.
static string scale(double factor)
const std::string add_attribute(const svg::unit utype=svg::unit::pixel) const