Giter Site home page Giter Site logo

meyfa / php-svg Goto Github PK

View Code? Open in Web Editor NEW
484.0 15.0 86.0 737 KB

Vector graphics (SVG) library for PHP

Home Page: https://packagist.org/packages/meyfa/php-svg

License: MIT License

PHP 100.00%
svg php svg-images vector-graphics parser png library php-svg rasterizing rendering rasterizer

php-svg's Introduction

PHP-SVG

The zero-dependency vector graphics library for PHP applications

CI Maintainability Test Coverage Packagist PHP Version Packagist Downloads

Features

PHP-SVG can help with the following set of tasks:

  • Generating vector graphics programmatically with PHP code. The resulting SVG string can be written to a file or sent as part of the HTTP response.
  • Loading and parsing SVG images into document trees that are easy to modify and append.
  • Converting vector graphics into raster image formats, such as PNG or JPEG (rasterization).

Please note that PHP-SVG is still in its alpha stage and may not be suitable for complex applications, yet. Contributions are very welcome. Find out how to contribute.

Installation

Requirements

PHP-SVG is free of dependencies. All it needs is a PHP installation satisfying the following requirements:

  • PHP version 7.4 or newer. This library is tested against all versions up to (and including) PHP 8.3.
  • If you wish to load SVG files, or strings containing SVG code, you need to have the 'simplexml' PHP extension.
  • If you wish to use the rasterization feature for converting SVGs to raster images (PNGs, JPEGs, ...), you need to have the 'gd' PHP extension.

These extensions are almost always available on typical PHP installations. Still, you might want to make sure that your hosting provider actually has them. If SimpleXML or GD are missing, PHP-SVG can still perform all tasks except those that require the missing extension. For example, programmatically generating SVG images and outputting them as XML will always work, even without any extension.

Composer (recommended)

This package is available on Packagist and can be installed with Composer:

composer require meyfa/php-svg

This adds a dependency to your composer.json file. If you haven't already, setup autoloading for Composer dependencies by adding the following require statement at the top of your PHP scripts:

<?php
require_once __DIR__ . '/vendor/autoload.php';

You may need to adjust the path if your script is located in another folder.

Manual installation

Download the latest release or the current development version of this repository, and extract the source code somewhere in your project. Then you can use our own autoloader to make available the SVG namespace:

<?php
require_once __DIR__ . '/<path_to_php_svg>/autoloader.php';

The rest works exactly the same as with Composer, just without the benefits of a package manager.

Getting started

This section contains a few simple examples to get you started with PHP-SVG.

Creating SVGs programmatically

The following code generates an SVG containing a blue square. It then sets the Content-Type header and sends the SVG as text to the client:

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;
use SVG\Nodes\Shapes\SVGRect;

// image with dimensions 100x100
$image = new SVG(100, 100);
$doc = $image->getDocument();

// blue 40x40 square at the origin
$square = new SVGRect(0, 0, 40, 40);
$square->setStyle('fill', '#0000FF');
$doc->addChild($square);

header('Content-Type: image/svg+xml');
echo $image;

Converting SVGs to strings

The above example uses echo, which implicitly converts the SVG to a string containing its XML representation. This conversion can also be made explicitly:

// This will include the leading <?xml ... ?> tag needed for standalone SVG files:
$xmlString = $image->toXMLString();
file_put_contents('my-image.svg', $xmlString);

// This will omit the <?xml ... ?> tag for outputting directly into HTML:
$xmlString = $image->toXMLString(false);
echo '<div class="svg-container">' . $xmlString . '</div>';

Loading SVGs from strings

In addition to generating images programmatically from scratch, they can be parsed from strings or loaded from files. The following code parses an SVG string, mutates part of the image, and echoes the result to the client:

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

$svg  = '<svg width="100" height="100">';
$svg .= '<rect width="40" height="40" fill="#00F" id="my-rect" />';
$svg .= '</svg>';

$image = SVG::fromString($svg);
$rect = $image->getDocument()->getElementById('my-rect');
$rect->setX(25)->setY(25);

header('Content-Type: image/svg+xml');
echo $image;

Loading SVGs from files

For loading from a file instead of a string, call SVG::fromFile($file). That function supports paths on the local file system, as well as remote URLs. For example:

// load from the local file system:
$image = SVG::fromFile('path/to/file.svg');

// or from the web (worse performance due to HTTP request):
$image = SVG::fromFile('https://upload.wikimedia.org/wikipedia/commons/8/8c/Even-odd_and_non-zero_winding_fill_rules.svg');

Rasterizing

โš ๏ธ This feature in particular is very much work-in-progress. Many things will look wrong and rendering large images may be very slow.

The toRasterImage($width, $height [, $background]) method is used to render an SVG to a raster image. The result is a GD image resource. GD then provides methods for encoding this resource to a number of formats:

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;
use SVG\Nodes\Shapes\SVGCircle;

$image = new SVG(100, 100);
$doc = $image->getDocument();

// circle with radius 20 and green border, center at (50, 50)
$doc->addChild(
    (new SVGCircle(50, 50, 20))
        ->setStyle('fill', 'none')
        ->setStyle('stroke', '#0F0')
        ->setStyle('stroke-width', '2px')
);

// rasterize to a 200x200 image, i.e. the original SVG size scaled by 2.
// the background will be transparent by default.
$rasterImage = $image->toRasterImage(200, 200);

header('Content-Type: image/png');
imagepng($rasterImage);

The raster image will default to preserving any transparency present in the SVG. For cases where an opaque image is desired instead, it is possible to specify a background color. This may be mandatory when outputting to some formats, such as JPEG, that cannot encode alpha channel information. For example:

// white background
$rasterImage = $image->toRasterImage(200, 200, '#FFFFFF');
imagejpeg($rasterImage, 'path/to/output.jpg');

Text rendering (loading fonts)

PHP-SVG implements support for TrueType fonts (.ttf files) using a handcrafted TTF parser. Since PHP doesn't come with any built-in font files, you will need to provide your own. The following example shows how to load a set of font files. PHP-SVG will try to pick the best matching font for a given text element, based on algorithms from the CSS spec.

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

// load a set of fonts from the "fonts" directory relative to the script directory
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Regular.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Bold.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Italic.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-BoldItalic.ttf');

$image = SVG::fromString('
<svg width="220" height="220">
  <rect x="0" y="0" width="100%" height="100%" fill="lightgray"/>
  <g font-size="15">
    <text y="20">hello world</text>
    <text y="100" font-weight="bold">in bold!</text>
    <text y="120" font-style="italic">and italic!</text>
    <text y="140" font-weight="bold" font-style="italic">bold and italic</text>
  </g>
</svg>
');

header('Content-Type: image/png');
imagepng($image->toRasterImage(220, 220));

Note that PHP often behaves unexpectedly when using relative paths, especially with fonts. Hence, it is recommended to use absolute paths, or use the __DIR__ constant to prepend the directory of the current script.

Document model

This section explains a bit more about the object structure and how to query or mutate parts of documents.

SVG root node

An instance of the SVG class represents the image abstractly. It does not store DOM information itself. That is the responsibility of the document root node, which is the object corresponding to the <svg> XML tag. For example:

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

$svg  = '<svg width="100" height="100">';
$svg .= '<rect width="40" height="40" fill="#00F" id="my-rect" />';
$svg .= '</svg>';

$image = SVG::fromString($svg);

// obtain the <svg> node (an instance of \SVG\SVGDocumentFragment):
$doc = $image->getDocument();

Child nodes

Child nodes of any element can be obtained as follows:

// Returns the number of children.
$numberOfChildren = $element->countChildren();

// Returns a child element by its index.
$firstChild = $element->getChild(0);

// Returns an array of matching child elements.
$childrenThatAreRects = $element->getElementsByTagName('rect');

// Returns an array of matching child elements.
$childrenWithClass = $element->getElementsByClassName('my-class-name');

The root node has an additional function for obtaining a unique element by its id attribute:

// Returns an element or null.
$element = $doc->getElementById('my-rect');

Child nodes can be added, removed and replaced:

// Append a child at the end.
$doc->addChild(new \SVG\Nodes\Shapes\SVGLine(0, 0, 10, 10));

// Insert a new child between the children at positions 0 and 1.
$g = new \SVG\Nodes\Structures\SVGGroup();
$doc->addChild($g, 1);

// Remove the second child. (equivalent to $doc->removeChild($g);)
$doc->removeChild(1);

// replace the first child with $g
$doc->setChild(0, $g);

Attributes

Every attribute is accessible via $element->getAttribute($name). Some often-used attributes have additional shortcut methods, but they are only available on the classes for which they are valid, so make sure the node you are accessing is of the correct type to prevent runtime errors. Some examples:

$doc->getWidth();
// equivalent to: $doc->getAttribute('width')

$doc->setWidth('200px');
// equivalent to: $doc->setAttribute('width', '200px');

$rect->setRX('10%');
// equivalent to: $rect->setAttribute('rx', '10%');

Styles

Some presentation attributes are considered style properties by the SVG spec. These will be treated specially by PHP-SVG and made available via getStyle and setStyle instead of getAttribute and setAttribute. Consider the following node:

<circle x="10" y="10" r="5" style="fill: #red" stroke="blue" stroke-width="4" />
  • x, y and r are attributes.
  • fill, stroke and stroke-width are styles.

Debugging

If you aren't getting any output but only a blank page, try temporarily enabling PHP's error reporting to find the cause of the problem.

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// ... rest of the script ...

Make sure you disable this again when you're done, as it may leak sensitive information about your server setup. Additionally, ensure you're not setting the Content-Type header to an image format in this mode, as your browser will try to render the error message as an image, which won't work.

Alternatively, you may attempt to find your server's error log file. Its location depends on how you're running PHP.

Contributing

This project is available to the community for free, and there is still a lot of work to do. Every bit of help is welcome! You can contribute in the following ways:

  • By giving PHP-SVG a star on GitHub to spread the word. The more it's used, the better it will become!
  • By reporting any bugs or missing features you encounter. Please quickly search through the issues tab to see whether someone has already reported the same problem. Maybe you can add something to the discussion?
  • By contributing code. You can take a look at the currently open issues to see what needs to be worked on. If you encounter a bug that you know how to resolve, it should be pretty safe to submit the fix as a pull request directly. For new features, it is recommended to first create an issue for your proposal, to gather feedback and discuss implementation strategies.

Please read:

By contributing material or code to PHP-SVG via a pull request or commit, you confirm that you own the necessary rights to that material or code, and agree to make available that material or code under the terms of the MIT license.

php-svg's People

Contributors

axis80 avatar beatjaeckle avatar bu4ak avatar cedo avatar fankoti avatar kuzmaka avatar lopsided avatar matthiaskuehneellerhold avatar meyfa avatar micgro42 avatar moebrowne avatar niellles avatar norkunas avatar peter279k avatar pkertyxy avatar ptsavdar avatar shyim avatar smnandre avatar tacman avatar thomas-kl1 avatar walidaalhomsi avatar za-ek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

php-svg's Issues

Don't `setStyle()` for initial styles, provide as computed

Using setStyle() in SVGDocumentFragment for initial/default styles gives the wrong impression that the styles might have been declared explicitly, as calling getStyle() with the respective keys returns something. Instead, the class should override getComputedStyle() and provide them there.

is there a way to create manually svg text with php-svg without official method

This project is very useful !
But no integration for text svg in this library is very annoying.

is there a alternate way to integrate text into SVG generate with this library ? perhaps

  • add string manually into svg tag ?
  • inject external file into svg that represent the text ?
  • include external path code into svg path ?

Thank for your partnership.

setAttributeOptional is obsolete

Through 0747a98, the SVGNode::setAttributeOptional method has become obsolete. It is now possible to call the standard setAttribute instead with exactly the same result. setAttributeOptional could then be removed entirely.

This issue serves as a reminder to verify that claim and to update all usages.

Rasterization does not handle gradients, transforms, implicit commands

Code from example:

<?php
require_once __DIR__.'/php-svg/autoloader.php';
use SVG\SVGImage;
$image = SVGImage::fromFile("bodygraph.svg");
$rasterImage = $image->toRasterImage(600, 600);
header('Content-Type: image/png');
imagepng($rasterImage);
?>

Original SVG Image: bodygraph.svg

Rendered PNG Image: rendered image

SVGArcApproximator::approximate() doesn't work properly

I haven't delved too deeply into the maths but the results returned are sometimes incorrect. For example:

$approx = new SVGArcApproximator();
$result = $approx->approximate([10, 10], [20, 10], true, false, 10, 10, 0);

The large arc flag is true but it returns a small arc. I have compared your code with a couple of other implementations. Have a look at this line and line 155. $angleDelta should be adjusted, not $angleStart.
Also vectorAngle() returns a positive number so line 155 is never executed (?)
And is fmod() at line 146 needed ?

Child elements in primitives (e.g. title tag)

The graphical primitives allow for sub elements like "title". The latter usually will be used as tooltip when hovering above the element.

I cannot add a "title" to a SVGCircle, as this is not based on SVGNodeContainer but onSVGNode.

After I changed the inheritance to "SVGNodeContainer", I can successfully add a "title" that renders as expected.

$title = new SVGTitle;
$title->setValue("this is a tooltip title");
$circle->addChild($title);

However SVGTitle too lacks a good

__construct($txt="")
to be rally useful

I' opt for generally inherit the primitives from SVGNodeContainer, as this does no harm.

Unit testing

Intro

As it currently stands, this project has almost no unit tests, despite having the testing framework and CI set up. The time has come to change that.

The following list shall track the things that need to have tests added.

Task List

Base Classes

  • SVG\SVG
    • convertUnit (pt, pc, cm, mm, in, %, px; no unit; different parameter types)
    • convertAngleUnit
    • parseColor (named colors, nonexisting color names; HEX_6, HEX_6, RGB, RGBA, HSL, HSLA (all with overflow))
  • SVG\SVGImage
    • getDocument
    • toRasterImage (return type; width, height)
    • __toString (calls toXMLString)
    • toXMLString
    • fromString (return type)
    • fromFile

Nodes

  • SVG\Nodes\SVGNode
    • constructFromAttributes (constructs child class)
    • getName (returns static::TAG_NAME)
    • getStyle (existent entry; nonexistent entry)
    • setStyle (property is updated; value converted to string)
    • getValue
    • setValue
    • removeStyle (property is unset)
    • getAttribute (existent entry; nonexistent entry)
    • setAttribute (property is updated; value converted to string)
    • removeAttribute (property is unset)
    • getSerializableAttributes (returns $this->attributes)
    • getSerializableStyles (returns $this->styles)
    • getViewBox
  • SVG\Nodes\SVGNodeContainer
    • addChild (duplicate, self; removes from previous; adds, container styles ??)
    • removeChild (instance vs. index; removes, sets $parent; nonexistent child)
    • rasterize (display: none; calls children; ignores visibility)
    • getElementsByTagName
    • getElementsByClassName

Embedded

  • SVG\Nodes\Embedded\SVGImageElement
    • constructor attributes
    • getHref (both versions)
    • setHref (sets xlink:href)
    • attribute getters and setters
    • rasterize (calls render('image', ...); correct options; display, visibility)

Shapes

  • SVG\Nodes\Shapes\SVGCircle
    • constructor attributes
    • attribute getters and setters
    • rasterize (calls render('ellipse', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGEllipse
    • constructor attributes
    • attribute getters and setters
    • rasterize (calls render('ellipse', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGLine
    • constructor attributes
    • attribute getters and setters
    • rasterize (calls render('line', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGPath
    • constructor attributes
    • attribute getters and setters
    • rasterize (calls parser and approximator; calls render('polygon', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGPolygonalShape
    • constructor attributes
    • constructFromAttributes
    • addPoint (array vs. floats)
    • removePoint (removes; out of range behavior)
    • getPoint
    • setPoint
    • getSerializableAttributes (includes points correctly stringified)
  • SVG\Nodes\Shapes\SVGPolygon
    • constructor attributes
    • rasterize (calls render('polygon', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGPolyline
    • constructor attributes
    • rasterize (calls render('polygon', ...); correct options; display, visibility)
  • SVG\Nodes\Shapes\SVGRect
    • constructor attributes
    • attribute getters and setters
    • rasterize (calls render('rect', ...); correct options; display, visibility)

Structures

  • SVG\Nodes\Structures\SVGDefs
    • constructor attributes
    • rasterize (does not render children)
  • SVG\Nodes\Structures\SVGDocumentFragment
    • constructor attributes
    • attribute getters and setters
    • getComputedStyle (initial style if not explicit)
    • getSerializableAttributes (namespaces if root, xmlns: prefix, xlink (once!); width and height if not default)
    • getElementById
  • SVG\Nodes\Structures\SVGStyle
    • setType
    • getType
    • setCss
    • getCss

Rasterization

  • SVG\Rasterization\SVGRasterizer
    • getPathParser
    • getPathApproximator
    • getDocumentWidth, getDocumentHeight (pixel conversion; default value)
    • getWidth, getHeight
    • getScaleX, getScaleY (viewbox vs. no viewbox)
    • getOffsetX, getOffsetY (viewbox vs. no viewbox)
    • getViewBox
    • getImage (returns working image)

Path

  • SVG\Rasterization\Path\SVGArcApproximator
    • approximate
  • SVG\Rasterization\Path\SVGBezierApproximator
    • quadratic
    • cubic
  • SVG\Rasterization\Path\SVGPathApproximator
    • approximate (?)
  • SVG\Rasterization\Path\SVGPathParser
    • should split commands and arguments correctly
    • should support repeated commands
    • should treat repeated MoveTo like implicit LineTo
    • should abort on error
  • SVG\Rasterization\Path\SVGPolygonBuilder
    • constructor
    • build
    • getFirstPoint
    • getLastPoint
    • getPosition
    • addPoint
    • addPointRelative
    • addPoints

Renderers

  • SVG\Rasterization\Renderers\SVGRenderer
    • render (calls prepareRenderParams, renderFill (if needed), renderStroke (if needed); correct color conversion)

Reading

  • SVG\Reading\SVGReader
    • should return an SVGImage or null on error
    • should set all namespaces and attributes (including namespace prefixed ones)
    • should set styles (attributes and style properties)
    • should recurse into child nodes
    • should not fail for unknown nodes

Writing

  • SVG\Writing\SVGWriter
    • should include the XML declaration
    • should write opening and closing tags
    • should write attributes
    • should serialize styles correctly
    • should write child nodes for containers
    • should enclose SVGStyle content in CDATA

Rect outline rendered incorrectly

Rectangle outlines rendered to raster images have the following shortcomings:

  • There are overlaps, resulting in more opaque spots when a color with transparency is used
  • The corners aren't exact (similar to first)
  • Even numbers as stroke widths may result in imprecise line placements (please verify)

Embedded styles ignored

Style element not present in rendered SVG image

<defs
     id="some_id">
    <style
       type="text/css"
       id="some_other_id">
              @import 'http://fonts.fontstorage.com/import/merriweather.css';
              text {font-family: 'Merriweather';}
              .....
    </style>
</defs>

Missing setChild() and addChild() with index

The following methods are proposed for SVGNodeContainer:

  • setChild($index, $newNode) for replacing a node at a given index
  • addChild($newNode, $index) for adding a node at a given index

At the moment, child nodes can only be added at the container's end, and cannot be replaced easily.

path attributtes lost after parsing

Hi,

if i load something like this:

<svg>
   <path d="M04150 05500 A01350 01300 0 1 1 06850 05500"></path>
</svg>

i can't get the 'd' attribute with getAttribute('d'). The attributes array for the path node is allways empty!

ArcTo path command support

The ArcTo path commands 'A' and 'a', essential parts of SVG, are not supported by SVGPathApproximator.

Rect Rotation?

I just discovered this repository and it looks very good.

A question I would have is if it is possible to get the rotation a rect?

How to set fonts for rasterization on existing documents?

when rasterizing svg, all the texts are missing in the png file.
is it implemented at all to rasterize texts ?

sorry, was just missing a font.
You can delete this issue.
works with this, ->setFont(new SVGFont('arial', './arial.ttf'))

SVGArcApproximator::approximate() doesn't work properly

I haven't delved too deeply into the maths but the results returned are sometimes incorrect. For example:

$approx = new SVGArcApproximator();
$result = $approx->approximate([10, 10], [20, 10], true, false, 10, 10, 0);

The large arc flag is true but it returns a small arc. I have compared your code with a couple of other implementations. Have a look at this line and line 155. $angleDelta should be adjusted, not $angleStart.
Also vectorAngle() returns a positive number so line 155 is never executed (?)
And is fmod() at line 146 needed ?

Path data in scientific notation cannot be parsed

Numbers such as -1.7433e4 or 1.91e-2 are not supported by the path parser, leading to missing commands and sometimes PHP errors while rasterizing (You must have at least 3 points in your array in [...]\Rasterization\Renderers\SVGPolygonRenderer.php on line 39).

Ideally, the argument matching RegEx would simply be adapted to support this, the remaining code already supports it (PHP's floatval can deal with scientific notation).

Mark "ext-gd" extension as optional

As the gd extension seems only required to rasterize image, it would be nice to mark it as optional in the composer.json, e.g.:

    "suggest": {
        "ext-gd": "Needed to rasterize images"
    }

Path arguments separated by minus sign are treated as one

In SVG, strings like 36.85-24.33 are defined unambiguously as the two arguments 36.85 and -24.33, but due to the fact that path arguments are not matched but split, PHP-SVG would treat them as 36.85-24.33 and then fail when parsing it as a number. Similarly to #17, this results in missing arguments and/or commands as well as errors when rasterizing.

rgb/rgba and hsl/hsla advanced syntax options

According to MDN [1], there are quite a few more ways to specify colors than are currently covered by the SVG::parseColor method.

The following notations in particular would need to be handled:

  • #RRGGBBAA (hexadecimal notation with alpha component)
  • #RGBA (short hex notation with alpha component)
  • rgb(255, 255, 255, 50%) (note the percentage used for alpha)
  • rgb(255 255 255) (note the missing commas)
  • rgb(255 255 255 / 50%) and rgb(255 255 255 / .5) (note the slash)
  • hsl with different units
  • hsl with alpha given as percentage

Keep in mind that as per #36, everything mentioned above for rgb also applies to rgba, and everything mentioned for hsl also applies to hsla.

[1] https://developer.mozilla.org/en-US/docs/Web/CSS/color_value

SVGNodeContainer methods should be chainable

To make constructing/editing larger node tree parts easier, SVGNodeContainer::addChild() and SVGNodeContainer::removeChild() should return the node container instance they were called on. This would allow for method chaining exactly like the other node methods already offer.

The return values, which are rarely (if ever) used anyway, could rather easily be replaced with some code on the client's side (a simple for loop over all children, checking whether the subject is among them, would suffice).

Rasterizer doesn't render transparencies inside shapes

Tried rasterizing this search icon SVG. Ended up with this:

test

require_once( __DIR__ . '/php-svg-master/autoloader.php' );

use SVG\SVG;

$svg = 'source.svg';
$test = SVG::fromFile( $svg );

$raster_image = $test->toRasterImage( 36, 36 );

imagepng( $raster_image, 'test.png', 9 );
imagejpeg( $raster_image, 'test.jpg', 100 );

Is this a limitation of the GD rendering library?

HTML entity escaping

At the moment, no HTML entity escaping/unescaping is being done for attributes and node contents.

It would arguably be an improvement to have this done behind the scenes by this library instead of the user, with quite positive implications on the effort needed and also on security (think JavaScript injection).

Any way to re-use an embedded font?

I generate an SVG from a template by rendering some text in it. To render the text, I embed a font in the svg. Now I want to use this svg-with-text as a template and add some more text to it, using the font I have already embedded in the svg. Is there a clean way to do it with this library?

text rotate

would it be possible to add rotation of text?

SVG output was fairly easy with something like setAttribute('transform', 'rotate(-45)'), but PNG output is fairly more complicated.

it would need:

  • add rotate parameter to SVGText
  • "magic" calculation of SVG centre of rotation, so that the centre is identical in SVG output and PHP GD output
  • change the 0 parameter of imagettftext angle in TextRenderer.php

any other glitches I've missed?

SVG Image into SVG

Hi there,

Is there a way to load a SVG for placement into a loaded SVG. An image inside an image.

Ideally not using xlink:href. Would very much like the produced SVG self contained.

Thanks.

rgb/rgba and hsl/hsla aliases

According to MDN [1] [2], the rgba keyword should be a mere alias for rgb, as well as the hsla keyword an alias for hsl. They should both accept the same (variable) number of arguments.

As it is currently implemented, the keywords are strict about the number of arguments, and are implemented separately, not as aliases.

[1] https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb()_and_rgba()
[2] https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#hsl()_and_hsla()

The Reader dismissed <linearGradient> label

When I read from an svg file, and show, I find the difference between the original file and the translate version from this lib.
the difference is : not exists now in the read from file of this lib version......

linearGradient support

I would like to generate ร  Rect object SVG and filling this with a linearGradient color like this

https://www.w3schools.com/graphics/svg_grad_linear.asp

Generate this kind of code

<defs> <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" /> <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" /> </linearGradient> </defs> <ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#grad1)" />

I don't understand how can do this with your library.

Can you help me to generate this please ?

SVGReader - Unknown tag are not retrieved

Actually I know it's not a bug, but a feature.

SVG\Reading\SVGReader::$nodeTypes contain the allowed node types. However I'd like to read a SVG and retrieve all properties, even if there not implemented. There's a lot of elements: SVG Elements and it should impossible to implement all (hard work).

Otherwise it seems that the SVGReader class apply all properties as attributes to the parsed node. I understand that declaring specific node types is require in order to render the SVG, but In don't think so to read a SVG.
So, if the SVGReader do not find any concret class for the current parsed node, it should instantiate a new object. In order to instantiate the right node (SVGNode or SVGNodeContainer generic implementations), should we had a full associative array of elements (as key) with boolean (as value) which defined if an element is a container or a final node?

If I'm totally wrong and it's not the purpose of the library, please tell me :)

SVG Support

Please can someone advise what SVG vesions are support and if there are other limitations. I'v been creating SVG's via Illustrator and not all appear to load. Saving to SVG 1.0 seems the most reliable but they don't seem to contain some basic data in the SVG, such as a size that the class can obtain using ->getWidth() etc.

Thanks.

`display` and `visibility` attributes

Support for the display and visibility attributes/styles is missing. This is rather important, since they are able to change the image completely.

imagecreatetruecolor(): Invalid image dimensions

hi
i get magecreatetruecolor(): Invalid image dimensions in
meyfa/php-svg/src/Rasterization/Renderers/SVGRectRenderer.php

the code im using is

$image = SVG::fromFile('file.svg');
$rasterImage = $image->toRasterImage(544,360);

the svg file contain

<svg id="SvgjsSvg2794" width="544" height="360" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" class="apexcharts-svg" xmlns:data="ApexChartsNS" transform="translate(0, 0)" style="background: transparent;"><foreignObject x="0" y="0" width="544" height="360"><div class="apexcharts-legend center position-bottom" xmlns="http://www.w3.org/1999/xhtml" style="right: 0px; position: absolute; left: 0px; top: auto; bottom: 0px;"><div class="apexcharts-legend-series" rel="1" data:collapsed="false" style="margin: 0px 5px;"><span class="apexcharts-legend-marker" rel="1" data:collapsed="false" style="background: rgb(0, 103, 255); color: rgb(0, 103, 255); height: 12px; width: 12px; left: 0px; top: 0px; border-width: 0px; border-color: rgb(255, 255, 255); border-radius: 12px;"></span><span class="apexcharts-legend-text" rel="1" data:collapsed="false" style="color: rgb(55, 61, 63); font-size: 13px; font-family: CircularStd-Book;">Visualizzazioni su Ricerca <span style="font-family: CircularStd-Medium">103735</span></span></div><div class="apexcharts-legend-series" rel="2" data:collapsed="false" style="margin: 0px 5px;"><span class="apexcharts-legend-marker" rel="2" data:collapsed="false" style="background: rgb(0, 221, 233); color: rgb(0, 221, 233); height: 12px; width: 12px; left: 0px; top: 0px; border-width: 0px; border-color: rgb(255, 255, 255); border-radius: 12px;"></span><span class="apexcharts-legend-text" rel="2" data:collapsed="false" style="color: rgb(55, 61, 63); font-size: 13px; font-family: CircularStd-Book;">Visualizzazioni su Map <span style="font-family: CircularStd-Medium">207086</span></span></div></div><style xmlns="http://www.w3.org/1999/xhtml" type="text/css">
    
      .apexcharts-legend {
        display: flex;
        overflow: auto;
        padding: 0 10px;
      }

      .apexcharts-legend.position-bottom, .apexcharts-legend.position-top {
        flex-wrap: wrap
      }
      .apexcharts-legend.position-right, .apexcharts-legend.position-left {
        flex-direction: column;
        bottom: 0;
      }

      .apexcharts-legend.position-bottom.left, .apexcharts-legend.position-top.left, .apexcharts-legend.position-right, .apexcharts-legend.position-left {
        justify-content: flex-start;
      }

      .apexcharts-legend.position-bottom.center, .apexcharts-legend.position-top.center {
        justify-content: center;  
      }

      .apexcharts-legend.position-bottom.right, .apexcharts-legend.position-top.right {
        justify-content: flex-end;
      }

      .apexcharts-legend-series {
        cursor: pointer;
      }

      .apexcharts-legend.position-bottom .apexcharts-legend-series, .apexcharts-legend.position-top .apexcharts-legend-series{
        display: flex;
        align-items: center;
      }

      .apexcharts-legend-text {
        position: relative;
        font-size: 14px;
      }

      .apexcharts-legend-text *, .apexcharts-legend-marker * {
        pointer-events: none;
      }

      .apexcharts-legend-marker {
        position: relative;
        display: inline-block;
        cursor: pointer;
        margin-right: 3px;
      }
      
      .apexcharts-legend.right .apexcharts-legend-series, .apexcharts-legend.left .apexcharts-legend-series{
        display: inline-block;
      }

      .apexcharts-legend-series.no-click {
        cursor: auto;
      }

      .apexcharts-legend .apexcharts-hidden-zero-series, .apexcharts-legend .apexcharts-hidden-null-series {
        display: none !important;
      }

      .inactive-legend {
        opacity: 0.45;
      }</style></foreignObject><g id="SvgjsG2796" class="apexcharts-inner apexcharts-graphical" transform="translate(70.296875, 40)"><defs id="SvgjsDefs2795"><clipPath id="gridRectMasklias78ng"><rect id="SvgjsRect2813" width="468.703125" height="266.584" x="-2.5" y="-2.5" rx="0" ry="0" fill="#ffffff" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0"/></clipPath><clipPath id="gridRectMarkerMasklias78ng"><rect id="SvgjsRect2814" width="481.703125" height="279.584" x="-9" y="-9" rx="0" ry="0" fill="#ffffff" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0"/></clipPath></defs><rect id="SvgjsRect2799" width="1" height="259.966" x="0" y="0" rx="0" ry="0" fill="#b1b9c4" opacity="1" stroke-width="0" stroke-dasharray="0" class="apexcharts-xcrosshairs" filter="none" fill-opacity="0.9"/><g id="SvgjsG2871" class="apexcharts-xaxis" transform="translate(0, 0)"><g id="SvgjsG2872" class="apexcharts-xaxis-texts-g" transform="translate(0, -4)"><text id="SvgjsText2873" font-family="CircularStd-Book" x="0" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2874" style="font-family: CircularStd-Book;">Mar '18</tspan><title>Mar '18</title></text><text id="SvgjsText2875" font-family="CircularStd-Book" x="83.93439354599406" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2876" style="font-family: CircularStd-Book;">May '18</tspan><title>May '18</title></text><text id="SvgjsText2877" font-family="CircularStd-Book" x="167.8687870919881" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2878" style="font-family: CircularStd-Book;">Jul '18</tspan><title>Jul '18</title></text><text id="SvgjsText2879" font-family="CircularStd-Book" x="253.1791543026706" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2880" style="font-family: CircularStd-Book;">Sep '18</tspan><title>Sep '18</title></text><text id="SvgjsText2881" font-family="CircularStd-Book" x="337.11354784866467" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2882" style="font-family: CircularStd-Book;">Nov '18</tspan><title>Nov '18</title></text><text id="SvgjsText2883" font-family="CircularStd-Book" x="421.0479413946587" y="290.584" text-anchor="middle" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-xaxis-label apexcharts-xaxis-label" style="font-family: CircularStd-Book;"><tspan id="SvgjsTspan2884" style="font-family: CircularStd-Book;">2019</tspan><title>2019</title></text></g></g><g id="SvgjsG2896" class="apexcharts-grid"><line id="SvgjsLine2897" x1="0" y1="262.584" x2="0" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2898" x1="83.93439354599406" y1="262.584" x2="83.93439354599406" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2899" x1="167.8687870919881" y1="262.584" x2="167.8687870919881" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2900" x1="253.1791543026706" y1="262.584" x2="253.1791543026706" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2901" x1="337.11354784866467" y1="262.584" x2="337.11354784866467" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2902" x1="421.0479413946587" y1="262.584" x2="421.0479413946587" y2="268.584" stroke="#78909c" stroke-dasharray="0" class="apexcharts-xaxis-tick"/><line id="SvgjsLine2903" x1="0" y1="0" x2="463.703125" y2="0" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2904" x1="0" y1="32.698" x2="463.703125" y2="32.698" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2905" x1="0" y1="65.396" x2="463.703125" y2="65.396" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2906" x1="0" y1="98.094" x2="463.703125" y2="98.094" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2907" x1="0" y1="130.792" x2="463.703125" y2="130.792" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2908" x1="0" y1="163.49" x2="463.703125" y2="163.49" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2909" x1="0" y1="196.18800000000002" x2="463.703125" y2="196.18800000000002" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2910" x1="0" y1="228.88600000000002" x2="463.703125" y2="228.88600000000002" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2911" x1="0" y1="261.584" x2="463.703125" y2="261.584" stroke="#e0e0e0" stroke-dasharray="0" class="apexcharts-gridline"/><line id="SvgjsLine2913" x1="0" y1="261.584" x2="463.703125" y2="261.584" stroke="transparent" stroke-dasharray="0"/><line id="SvgjsLine2912" x1="0" y1="1" x2="0" y2="261.584" stroke="transparent" stroke-dasharray="0"/></g><g id="SvgjsG2816" class="apexcharts-line-series apexcharts-plot-series"><g id="SvgjsG2844" class="apexcharts-series Visualizzazioni-su-Map" data:longestSeries="true" rel="2" data:realIndex="1"><path id="apexcharts-line-1" d="M 0 113.93955987500001C 14.909247979259396 113.93955987500001 27.688603390053167 97.91915512500003 42.597851369312565 97.91915512500003C 57.04557484854105 97.91915512500003 69.4293378307369 68.41301412500002 83.87706130996538 68.41301412500002C 98.80637557183482 68.41301412500002 111.6029306534372 123.29833587500002 126.53224491530663 123.29833587500002C 140.97996839453512 123.29833587500002 153.36373137673098 96.35935912500003 167.81145485595945 96.35935912500003C 182.7407691178289 96.35935912500003 195.53732419943128 131.649743625 210.4666384613007 131.649743625C 225.39595272317013 131.649743625 238.1925078047725 33.75629675000005 253.12182206664195 33.75629675000005C 267.5695455458704 33.75629675000005 279.95330852806626 68.6242365 294.40103200729476 68.6242365C 309.35041255177424 68.6242365 322.1641673041852 34.51994687500002 337.11354784866467 34.51994687500002C 351.56127132789317 34.51994687500002 363.945034310089 83.24732400000005 378.3927577893175 83.24732400000005C 393.3220720511869 83.24732400000005 406.11862713278936 32.83016787500003 421.0479413946588 32.83016787500003C 435.9772556565282 32.83016787500003 448.7738107381306 59.590418 463.703125 59.590418" fill="none" fill-opacity="1" stroke="rgba(0,221,233,0.85)" stroke-opacity="1" stroke-linecap="butt" stroke-width="5" stroke-dasharray="0" class="apexcharts-line" index="1" clip-path="url(#gridRectMasklias78ng)" pathTo="M 0 113.93955987500001C 14.909247979259396 113.93955987500001 27.688603390053167 97.91915512500003 42.597851369312565 97.91915512500003C 57.04557484854105 97.91915512500003 69.4293378307369 68.41301412500002 83.87706130996538 68.41301412500002C 98.80637557183482 68.41301412500002 111.6029306534372 123.29833587500002 126.53224491530663 123.29833587500002C 140.97996839453512 123.29833587500002 153.36373137673098 96.35935912500003 167.81145485595945 96.35935912500003C 182.7407691178289 96.35935912500003 195.53732419943128 131.649743625 210.4666384613007 131.649743625C 225.39595272317013 131.649743625 238.1925078047725 33.75629675000005 253.12182206664195 33.75629675000005C 267.5695455458704 33.75629675000005 279.95330852806626 68.6242365 294.40103200729476 68.6242365C 309.35041255177424 68.6242365 322.1641673041852 34.51994687500002 337.11354784866467 34.51994687500002C 351.56127132789317 34.51994687500002 363.945034310089 83.24732400000005 378.3927577893175 83.24732400000005C 393.3220720511869 83.24732400000005 406.11862713278936 32.83016787500003 421.0479413946588 32.83016787500003C 435.9772556565282 32.83016787500003 448.7738107381306 59.590418 463.703125 59.590418" pathFrom="M -1 359.07125L -1 359.07125L 42.597851369312565 359.07125L 83.87706130996538 359.07125L 126.53224491530663 359.07125L 167.81145485595945 359.07125L 210.4666384613007 359.07125L 253.12182206664195 359.07125L 294.40103200729476 359.07125L 337.11354784866467 359.07125L 378.3927577893175 359.07125L 421.0479413946588 359.07125L 463.703125 359.07125"/><g id="SvgjsG2845" class="apexcharts-series-markers-wrap"><g id="SvgjsG2847" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2848" r="5" cx="0" cy="113.93955987500001" class="apexcharts-marker no-pointer-events wdz5lmb5a" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="0" j="0" index="1" default-marker-size="5"/><circle id="SvgjsCircle2849" r="5" cx="42.597851369312565" cy="97.91915512500003" class="apexcharts-marker no-pointer-events w99g5yb6m" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="1" j="1" index="1" default-marker-size="5"/></g><g id="SvgjsG2850" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2851" r="5" cx="83.87706130996538" cy="68.41301412500002" class="apexcharts-marker no-pointer-events wheeum2drl" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="2" j="2" index="1" default-marker-size="5"/></g><g id="SvgjsG2852" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2853" r="5" cx="126.53224491530663" cy="123.29833587500002" class="apexcharts-marker no-pointer-events w8k49m081" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="3" j="3" index="1" default-marker-size="5"/></g><g id="SvgjsG2854" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2855" r="5" cx="167.81145485595945" cy="96.35935912500003" class="apexcharts-marker no-pointer-events wz9z6uwoq" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="4" j="4" index="1" default-marker-size="5"/></g><g id="SvgjsG2856" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2857" r="5" cx="210.4666384613007" cy="131.649743625" class="apexcharts-marker no-pointer-events wfmtl3kud" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="5" j="5" index="1" default-marker-size="5"/></g><g id="SvgjsG2858" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2859" r="5" cx="253.12182206664195" cy="33.75629675000005" class="apexcharts-marker no-pointer-events wyhb1rvgmi" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="6" j="6" index="1" default-marker-size="5"/></g><g id="SvgjsG2860" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2861" r="5" cx="294.40103200729476" cy="68.6242365" class="apexcharts-marker no-pointer-events whkxa5fb3" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="7" j="7" index="1" default-marker-size="5"/></g><g id="SvgjsG2862" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2863" r="5" cx="337.11354784866467" cy="34.51994687500002" class="apexcharts-marker no-pointer-events whcq842tx" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="8" j="8" index="1" default-marker-size="5"/></g><g id="SvgjsG2864" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2865" r="5" cx="378.3927577893175" cy="83.24732400000005" class="apexcharts-marker no-pointer-events work5h755" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="9" j="9" index="1" default-marker-size="5"/></g><g id="SvgjsG2866" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2867" r="5" cx="421.0479413946588" cy="32.83016787500003" class="apexcharts-marker no-pointer-events w68highnnf" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="10" j="10" index="1" default-marker-size="5"/></g><g id="SvgjsG2868" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2869" r="5" cx="463.703125" cy="59.590418" class="apexcharts-marker no-pointer-events wtg7565v3" stroke="#ffffff" fill="#00dde9" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="11" j="11" index="1" default-marker-size="5"/></g></g><g id="SvgjsG2846" class="apexcharts-datalabels"/></g><g id="SvgjsG2817" class="apexcharts-series Visualizzazioni-su-Ricerca" data:longestSeries="true" rel="1" data:realIndex="0"><path id="apexcharts-line-0" d="M 0 199.41963025C 14.909247979259396 199.41963025 27.688603390053167 210.33820225000002 42.597851369312565 210.33820225000002C 57.04557484854105 210.33820225000002 69.4293378307369 210.971869375 83.87706130996538 210.971869375C 98.80637557183482 210.971869375 111.6029306534372 229.86814800000002 126.53224491530663 229.86814800000002C 140.97996839453512 229.86814800000002 153.36373137673098 231.13548225000002 167.81145485595945 231.13548225000002C 182.7407691178289 231.13548225000002 195.53732419943128 236.838486375 210.4666384613007 236.838486375C 225.39595272317013 236.838486375 238.1925078047725 246.847177375 253.12182206664195 246.847177375C 267.5695455458704 246.847177375 279.95330852806626 234.49879237500002 294.40103200729476 234.49879237500002C 309.35041255177424 234.49879237500002 322.1641673041852 221.939185 337.11354784866467 221.939185C 351.56127132789317 221.939185 363.945034310089 196.21879887500003 378.3927577893175 196.21879887500003C 393.3220720511869 196.21879887500003 406.11862713278936 196.85246600000002 421.0479413946588 196.85246600000002C 435.9772556565282 196.85246600000002 448.7738107381306 208.45344875 463.703125 208.45344875" fill="none" fill-opacity="1" stroke="rgba(0,103,255,0.85)" stroke-opacity="1" stroke-linecap="butt" stroke-width="5" stroke-dasharray="0" class="apexcharts-line" index="0" clip-path="url(#gridRectMasklias78ng)" pathTo="M 0 199.41963025C 14.909247979259396 199.41963025 27.688603390053167 210.33820225000002 42.597851369312565 210.33820225000002C 57.04557484854105 210.33820225000002 69.4293378307369 210.971869375 83.87706130996538 210.971869375C 98.80637557183482 210.971869375 111.6029306534372 229.86814800000002 126.53224491530663 229.86814800000002C 140.97996839453512 229.86814800000002 153.36373137673098 231.13548225000002 167.81145485595945 231.13548225000002C 182.7407691178289 231.13548225000002 195.53732419943128 236.838486375 210.4666384613007 236.838486375C 225.39595272317013 236.838486375 238.1925078047725 246.847177375 253.12182206664195 246.847177375C 267.5695455458704 246.847177375 279.95330852806626 234.49879237500002 294.40103200729476 234.49879237500002C 309.35041255177424 234.49879237500002 322.1641673041852 221.939185 337.11354784866467 221.939185C 351.56127132789317 221.939185 363.945034310089 196.21879887500003 378.3927577893175 196.21879887500003C 393.3220720511869 196.21879887500003 406.11862713278936 196.85246600000002 421.0479413946588 196.85246600000002C 435.9772556565282 196.85246600000002 448.7738107381306 208.45344875 463.703125 208.45344875" pathFrom="M -1 359.07125L -1 359.07125L 42.597851369312565 359.07125L 83.87706130996538 359.07125L 126.53224491530663 359.07125L 167.81145485595945 359.07125L 210.4666384613007 359.07125L 253.12182206664195 359.07125L 294.40103200729476 359.07125L 337.11354784866467 359.07125L 378.3927577893175 359.07125L 421.0479413946588 359.07125L 463.703125 359.07125"/><g id="SvgjsG2818" class="apexcharts-series-markers-wrap"><g id="SvgjsG2820" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2821" r="5" cx="0" cy="199.41963025" class="apexcharts-marker no-pointer-events w3aziisc2" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="0" j="0" index="0" default-marker-size="5"/><circle id="SvgjsCircle2822" r="5" cx="42.597851369312565" cy="210.33820225000002" class="apexcharts-marker no-pointer-events w60e8a5xzh" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="1" j="1" index="0" default-marker-size="5"/></g><g id="SvgjsG2823" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2824" r="5" cx="83.87706130996538" cy="210.971869375" class="apexcharts-marker no-pointer-events wazslh2l1f" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="2" j="2" index="0" default-marker-size="5"/></g><g id="SvgjsG2825" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2826" r="5" cx="126.53224491530663" cy="229.86814800000002" class="apexcharts-marker no-pointer-events wgw0xobuq" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="3" j="3" index="0" default-marker-size="5"/></g><g id="SvgjsG2827" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2828" r="5" cx="167.81145485595945" cy="231.13548225000002" class="apexcharts-marker no-pointer-events we4r6fd3d" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="4" j="4" index="0" default-marker-size="5"/></g><g id="SvgjsG2829" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2830" r="5" cx="210.4666384613007" cy="236.838486375" class="apexcharts-marker no-pointer-events woxbqj6hqi" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="5" j="5" index="0" default-marker-size="5"/></g><g id="SvgjsG2831" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2832" r="5" cx="253.12182206664195" cy="246.847177375" class="apexcharts-marker no-pointer-events wyytrtxjx" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="6" j="6" index="0" default-marker-size="5"/></g><g id="SvgjsG2833" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2834" r="5" cx="294.40103200729476" cy="234.49879237500002" class="apexcharts-marker no-pointer-events wlwv5wn87k" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="7" j="7" index="0" default-marker-size="5"/></g><g id="SvgjsG2835" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2836" r="5" cx="337.11354784866467" cy="221.939185" class="apexcharts-marker no-pointer-events wr8zegybg" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="8" j="8" index="0" default-marker-size="5"/></g><g id="SvgjsG2837" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2838" r="5" cx="378.3927577893175" cy="196.21879887500003" class="apexcharts-marker no-pointer-events wwyet4a94" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="9" j="9" index="0" default-marker-size="5"/></g><g id="SvgjsG2839" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2840" r="5" cx="421.0479413946588" cy="196.85246600000002" class="apexcharts-marker no-pointer-events wwcu3tgxk" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="10" j="10" index="0" default-marker-size="5"/></g><g id="SvgjsG2841" class="apexcharts-series-markers" clip-path="url(#gridRectMarkerMasklias78ng)"><circle id="SvgjsCircle2842" r="5" cx="463.703125" cy="208.45344875" class="apexcharts-marker no-pointer-events whp1hk7ej" stroke="#ffffff" fill="#0067ff" fill-opacity="1" stroke-width="2" stroke-opacity="0.9" rel="11" j="11" index="0" default-marker-size="5"/></g></g><g id="SvgjsG2819" class="apexcharts-datalabels"/></g></g><line id="SvgjsLine2914" x1="0" y1="0" x2="463.703125" y2="0" stroke="#b6b6b6" stroke-dasharray="0" stroke-width="1" class="apexcharts-ycrosshairs"/><line id="SvgjsLine2915" x1="0" y1="0" x2="463.703125" y2="0" stroke-dasharray="0" stroke-width="0" class="apexcharts-ycrosshairs-hidden"/><g id="SvgjsG2916" class="apexcharts-yaxis-annotations"/><g id="SvgjsG2917" class="apexcharts-xaxis-annotations"/><g id="SvgjsG2918" class="apexcharts-point-annotations"/><rect id="SvgjsRect2919" width="0" height="0" x="0" y="0" rx="0" ry="0" fill="#fefefe" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0" class="apexcharts-zoom-rect"/><rect id="SvgjsRect2920" width="0" height="0" x="0" y="0" rx="0" ry="0" fill="#fefefe" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0" class="apexcharts-selection-rect"/></g><g id="SvgjsG2885" class="apexcharts-yaxis" rel="0" transform="translate(25.296875, 0)"><g id="SvgjsG2886" class="apexcharts-yaxis-texts-g"><text id="SvgjsText2887" font-family="CircularStd-Book" x="20" y="41.8" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">22000</text><text id="SvgjsText2888" font-family="CircularStd-Book" x="20" y="74.598" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">20000</text><text id="SvgjsText2889" font-family="CircularStd-Book" x="20" y="107.396" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">18000</text><text id="SvgjsText2890" font-family="CircularStd-Book" x="20" y="140.19400000000002" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">16000</text><text id="SvgjsText2891" font-family="CircularStd-Book" x="20" y="172.99200000000002" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">14000</text><text id="SvgjsText2892" font-family="CircularStd-Book" x="20" y="205.79000000000002" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">12000</text><text id="SvgjsText2893" font-family="CircularStd-Book" x="20" y="238.58800000000002" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">10000</text><text id="SvgjsText2894" font-family="CircularStd-Book" x="20" y="271.386" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">8000</text><text id="SvgjsText2895" font-family="CircularStd-Book" x="20" y="304.184" text-anchor="end" dominate-baseline="central" font-size="12px" fill="#373d3f" class="apexcharts-yaxis-label apexcharts-yaxis-label" style="font-family: CircularStd-Book;">6000</text></g></g></svg>

thx in advance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.