CSS effect (shadow, stroke) on SVG with different sizes - php

i have a problem with SVGs (different sizes) and effetcs (strokes, shadows etc.)
The stroke (for example) has not the same size because the icon B is smaller and it is "zoomed" to 500px.
What is the correct way to fix this issue?
must i calculate the effect for every SVG individually? :/
or is there an option to only zoom the SVG and not the effect?
or can i recalculate (with PHP) the SVGs? So that every SVG has the same size?
FIDDLE
http://jsfiddle.net/tqef7qkp/
CSS
stroke: #39A02E;
stroke-width: 5;
Example
A)
<svg xml:space="preserve"
preserveAspectRatio= "xMinYMin meet"
enable-background="new 0 0 500 500"
viewBox="0 0 500 500"
width="500px"
height="500px"
y="0px"
x="0px"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" version="1.1">
B)
<svg xml:space="preserve"
preserveAspectRatio= "xMinYMin meet"
enable-background="new 0 0 50 50"
viewBox="0 0 50 50"
width="500px"
height="500px"
y="0px"
x="0px"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" version="1.1">

You can specify stroke-widths in percentages, not just userSpace units. You can also specify shadow filters the same way (in objectBoundingBox units). This will size your strokes to the size of your svg's vs. the size of your viewboxes.

<style type="text/css" >
<![CDATA[
g { stroke: #39A02E;
stroke-width: 1;
fill:url(#rgrad);}
]]>
</style>
That could fix the stroke problem.
The output:

Related

SVG xlink:href always pulling image from the last record in a Wordpress loop

I'm using an image pulled from a user entry to fill an SVG element - i.e. staff portrait on a team page. Currently the image displayed is always from the last user entry in the (Wordpress) loop.
Here's the relevant part of my template:
foreach ( $allusers as $user ):
$image = get_field('headshot', $user );
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 221 300" style="enable-background:new 0 0 221 300;" xml:space="preserve">
<style type="text/css">
.st4{fill:url(#img-<?php echo $user->ID; ?>);}
</style>
<defs>
<pattern id="img-<?php echo $user->ID; ?>" height="100%" width="100%" patternContentUnits="objectBoundingBox" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid slice">
<image xlink:href="<?php echo $image['url']; ?>" width="1" height="1" preserveAspectRatio="xMidYMid slice" />
</pattern>
</defs>
<circle class="st4" cx="110.5" cy="150.4" r="78.5"/>
</svg>
If I simply do a:
<img src="<?php echo $image['url']; ?>">
This shows the correct image for each entry, so I'm assuming it's to do with the xlink:href part.
How can I get the correct image to show in the SVG element?

How to handle duplicate IDs for inline SVGs?

I am using the same SVG multiple times on a webpage. The SVGs are inserted on the server side with PHP like this:
<?php echo file_get_contents("myimage.svg"); ?>
The SVG contains a gradient, which should have different colors on different instances of the SVG.
An HTML document delivered by the server may look like the following snippet. The same SVG has been inserted twice:
#image1 .stop1 { stop-color: #FDF39C }
#image1 .stop2 { stop-color: #FE8A77 }
#image2 .stop1 { stop-color: #64E8EA }
#image2 .stop2 { stop-color: #A79CFC }
<div id="image1">
<svg width="256" height="256" viewBox="0 0 256 256">
<defs>
<linearGradient id="gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="100%"/>
</linearGradient>
</defs>
<circle fill="url(#gradient1)" cx="128" cy="128" r="100" />
</svg>
</div>
<div id="image2">
<svg width="256" height="256" viewBox="0 0 256 256">
<defs>
<linearGradient id="gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="100%"/>
</linearGradient>
</defs>
<circle fill="url(#gradient1)" cx="128" cy="128" r="100" />
</svg>
</div>
The problem is that both instances of the SVG display the gradient defined in the first SVG. Here is a comparison of the actual vs the intended result:
The reason for this is that the gradients of both inline SVGs have the same ID gradient1, because the same SVG which contains that ID is inserted twice on the server. The circle elements' fill is set to url(#gradient1) in both cases, which the browser simply links to the first occurence of that ID, which is the gradient definition in the first SVG. This behavior is correct, but for my case this is a problem.
The question is: How do I avoid duplicate ids? I worked with SVG injection using SVGInject, and this solved the problem by making the IDs unique. SVGInject simply adds a random string to the end of IDs, for example changing gradient1 to gradient1-h4w7xo82.
However, I do not see a solution when inserting the SVGs with PHP. Can you help?
Convert the svg file into php so you can pass the gradientId parameter into it.
<?php
header('Content-Type: image/svg+xml');
echo '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<defs>
<linearGradient id="' . $gradientId . '">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="100%"/>
</linearGradient>
</defs>
<circle fill="url(#' . $gradientId . ')" cx="128" cy="128" r="100" />
</svg>';
?>
CSS Based Solution
I was having the same problem.
The solution to the above problem is, change the css class, so that different css class is targeting different object.
Change -
CSS Class of 2nd element, I have change it to #image2 .stop1-df, appended additional "df"
Linear Gradient ID - of second element - gradient1-df
Circle fill url - #gradient1-df
#image1 .stop1 { stop-color: #FDF39C }
#image1 .stop2 { stop-color: #FE8A77 }
#image2 .stop1-df { stop-color: #64E8EA }
#image2 .stop2-df { stop-color: #A79CFC }
<div id="image1">
<svg width="256" height="256" viewBox="0 0 256 256">
<defs>
<linearGradient id="gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="100%"/>
</linearGradient>
</defs>
<circle fill="url(#gradient1)" cx="128" cy="128" r="100" />
</svg>
</div>
<div id="image2">
<svg width="256" height="256" viewBox="0 0 256 256">
<defs>
<linearGradient id="gradient1-df">
<stop class="stop1-df" offset="0%"/>
<stop class="stop2-df" offset="100%"/>
</linearGradient>
</defs>
<circle fill="url(#gradient1-df)" cx="128" cy="128" r="100" />
</svg>
</div>
If you use https://jakearchibald.github.io/svgomg/ it will convert all styles to URL-parameters, like this: id="a" and url("a"). If you want multiple SVGs on one page, they interfere with eachother.
I needed to have several SVGs on the same page, so I made a small util for my self. It will replace those a/b/c urls with a parameter you can insert for your self, so you can have 1 SVG with one_a, one_b etc and the second SVG with second_a, second_b etc. It uses regex, obviously:
# replace id="a" with id="test_a"
removeStr = "id=\"#{strChar}\""
regex = new RegExp(removeStr,'g')
strInput = strInput.replace(regex,"id=\"#{strName}_#{strChar}\"")
You can find it here:
https://codepen.io/pwiegers/pen/YzreGGo
It saved me a ton of time; it might save you some :-)

Converting all float in string by whole number PhP

CONTEXT
I have a svg file shaped like following :
<svg width="100px" height="150px">
<g>
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="2125.9858">
</linearGradient>
</g>
</svg>
Note this is an example, in reality my svg is bigger.
GOAL
I would like to input this as a string in php, and find all float, then finally convert those to whole number. The aim of this script is to round all number to reduce the load for rendering in client screen.
EXPECTED OUTPUT
<svg width="100px" height="150px">
<g>
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="2125">
</linearGradient>
</g>
</svg>
QUESTION
Can I use str_replace to do the job ? I thought of something that would be near this command :
$svg = "...";
$svg = str_replace("/[0-9.]/", floor(the_occurence_found), $svg);
Is that possible ? Or am I going right on the wall ?

SVG - positioning won't work

I am new to SVG. I think there are two ways for me to insert SVG icons in my wordpress template.
1.: with "use"
<svg viewBox="0 0 100 100">
<use xlink:href="<?php bloginfo('template_directory'); ?>/icons/download.svg#Layer_1"></use>
</svg>
2.: as PHP file
get_template_part("icons/download")
("get_template_part" in this case refers to a "icon.php" file with the XML code that draws the SVG:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="40px" height="33.999px" viewBox="0 0 40 33.999" style="enable-background:new 0 0 40 33.999;" xml:space="preserve">
<path style="fill-rule:evenodd;clip-rule:evenodd;" d="M39,14h-1v15.999c0,2.209-1.791,4-4,4H6c-2.209,0-4-1.791-4-4V14H1
c-0.552,0-1-0.448-1-1c0-0.552,0.448-1,1-1h1v-0.001h2v18c0,1.104,0.895,2,2,2h28c1.104,0,2-0.896,2-2v-18h2V12h1
c0.552,0,1,0.448,1,1C40,13.552,39.552,14,39,14z M20.708,13.706c-0.001,0.001-0.002,0.002-0.003,0.002l-0.009,0.009l0,0l0,0
c-0.087,0.087-0.189,0.147-0.294,0.196c-0.005,0.002-0.009,0.007-0.014,0.009c-0.369,0.163-0.814,0.098-1.117-0.205l-4.989-4.994
c-0.394-0.394-0.394-1.033,0-1.427c0.394-0.394,1.032-0.394,1.426,0L19,10.591V1c0-0.552,0.448-1,1-1c0.552,0,1,0.448,1,1v9.56
l3.261-3.264c0.393-0.394,1.031-0.394,1.425,0s0.394,1.033,0,1.427L20.708,13.706z"/>
</svg>
The first option doesn't work in IE (even 11!) without javascript.
The second option works in IE9 and above, that's cool! but i am not able to position this SVG. i have put it in a wrapper (".svg-wrapper") and tried to position it with CSS but the SVG appears outside of the wrapper in DOM :-(
Am i doing something wrong here?
echo '<li class="alignmiddle">' . '<div class="svgwrapper">' . get_template_part("icons/download") . '</div>' . $title . '.' . $path_info['extension'] . '<span class="filesize"> (' . $filesize . ')</span>' . '</li>';
Or is there a better solution at all?
I use the following code which allows you to define a fallback for older browsers. This method allows you to apply CSS in the same way you would a normal image. As SVG's are vector based you must assign a width and height.
<img src="<?php bloginfo('template_directory'); ?>/img/example.svg" onerror="this.onerror=null; this.src='<?php bloginfo('template_directory'); ?>/img/example.png'" alt="" />

How to get SVG tag content with PHP

I would like to get SVG tag content with PHP.
test.svg:
<?xml version="1.0" encoding="utf-8"?>
<!-- comment -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="202.5px" height="226.084px" viewBox="0 0 202.5 226.084" enable-background="new 0 0 202.5 226.084" xml:space="preserve">
<g>
<path d="M0,13.628c47.7940,13.628z"/>
<polygon points="108.48,207.874 145.506,196.948 145.506,204.536 108.48,214.854 "/>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
</g>
<g>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
</g>
<anythingElse>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
<anythingElse>
</svg>
php:
$svg = new SimpleXMLElement( file_get_contents( 'test.svg' ) );
$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
$svg->registerXPathNamespace('xlink', 'http://www.w3.org/1999/xlink');
Now, I would like to get the svg tag content as a string.
Desired result (hardcoded example):
$content = '<g>
<path d="M0,13.628c47.7940,13.628z"/>
<polygon points="108.48,207.874 145.506,196.948 145.506,204.536 108.48,214.854 "/>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
</g>
<g>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
</g>
<anythingElse>
<path fill="none" stroke="#000000" d="M114.55,223.959"/>
<anythingElse> ';
//EDIT:
I don't want to look for g tag: '/svg:svg/svg:g'.
As there is no guarantee that inside the svg there will be a g tag. There could be more then one g tag or some other tags.
I want to get everything between the opening and closing svg tags.
You have already seen right (more likely: copy and pasted from an example code that has been given to you in a previous answer w/o understanding it further) that you need to register the XML namespace here for your xpath because there is no prefix for it in the XML:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="202.5px" height="226.084px" viewBox="0 0 202.5 226.084" enable-background="new 0 0 202.5 226.084" xml:space="preserve">
It is just the URI http://www.w3.org/2000/svg, no prefix given. It is the namespace of that <svg> root element.
Therefore you need to register the prefix (the other already prefixed namespace should be already registered automatically):
$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
Which is what you do so far.
To now use your registered prefix in the xpath query, prefix the tagname with it:
/svg:svg/svg:g[1]
Should give you the first <g> element in that SVG-Namespace. Let me know if this still needs further explanation / clarification.
See the online demo.
This is also exactly as the reason outline to your previous question:
Loop through SVG elements with PHP
I think to get onle the g tag you don;t need namespace you could try this:
$result = $svg->xpath('svg/g');
foreach ($result as $gtag) {
echo $gtag . "\n";
}
I can't test it though:)

Categories