I am trying to add an image into the center of a SVG circle.
I tried with patterns
<pattern id="image_birds" x="0" y="0" patternUnits="userSpaceOnUse" height="100" width="100">
<image x="0" y="0" xlink:href="birds.png" height="50" width="50"></image>
</pattern>
But it does not center the image. I am working with Javascript.
Clipping should do what you are looking for: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Clipping_and_masking
Something like:
<clipPath id="cut-off-bottom">
<circle cx="100" cy="100" r="50" />
</clipPath>
<image x="25" y="25" xlink:href="http://placehold.it/150.png" height="150" width="150" clip-path="url(#cut-off-bottom)" ></image>
You can see the result of this example here: http://jsbin.com/EKUTUco/1/edit?html,output
Up to you to center the images in javascript according to their sizes, via x and y attributes.
Ok I found the answer. What I did is adding a filter to my svg:
<filter id = "i1" x = "0%" y = "0%" width = "100%" height = "100%">
<feImage xlink:href = "birds.png"/>
</filter>
and in the circle add attribute:
circle.setAttribute('filter','url(#i1)');
Related
This code below places textBox1 at a y-position of 200, but getBoundingClientRect returns a value of 190.
Why?
https://codepen.io/anon/pen/REKayR?editors=1011
<svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0%" y="0%" width="100%" height="100%" fill="beige" />
<svg id="textBox1" x="0%" y="200" width="100%" height="25%">
<rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
<text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
</svg>
</svg>
var textBox = $("#textBox1");
var textBBox = textBox[0].getBoundingClientRect();
console.log("The y-pos is: " + textBBox.y);
.getBoundingClientRect() is part of the generic Element interface, and computes the rectangle in relation to the screen viewport. SVG offer some more specific methods:
SVGGraphicsElement.getBBox() computes the bounding box in the local coordinate system the element is drawn in.
SVGGraphicsElement.getCTM() computes the transformation matrix getween the local coordinate system and the nearest SVG viewport (a <svg> element, for example).
SVGGraphicsElement.getScreenCTM() computes the transformation matrix getween the local coordinate system and the screen viewport.
In addition, the DOMMatrix interface has an .inverse() method, so you can easily compute positions in the opposite direction. (For example, if you transform a mouse event screenx/screenY position with the result of element.getScreenCTM().inverse(), you'll get the mouse position in relation to that element.)
The one thing a bit awkward is that you have to construct a SVGPoint object, which can only be achieved by the SVGSVGElement.createSVGPoint() method on an <svg> element, to have something to apply your matrix to.
As for your question, consider the different return values for the three doordinate systems for the rect inside the inner <svg>:
var textBox = document.querySelector('#textBox1 rect');
var svg = document.querySelector('#rootBox');
var point = svg.createSVGPoint();
var local = textBox.getBBox();
point.x = local.x, point.y = local.y;
console.log("local: ", local.x, local.y);
var nearest = textBox.getCTM();
var point2 = point.matrixTransform(nearest);
console.log("nearest viewport: ", point2.x, point2.y);
var screen = textBox.getScreenCTM();
var point3 = point.matrixTransform(screen);
console.log("screen viewport: ", point3.x, point3.y);
<svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0%" y="0%" width="100%" height="100%" fill="beige" />
<svg id="textBox1" x="0%" y="200" width="100%" height="25%">
<rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
<text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
</svg>
</svg>
getBoundingClientRect takes things like scroll position into account. Any margin or padding on the HTML body would also factor in, but adding to the result rather than subtracting.
If you make sure you aren't scrolled down, and the margins do not factor in, you will get 200:
function log() {
var textBox = $("#textBox1");
var textBBox = textBox[0].getBoundingClientRect();
console.log("The y-pos is: " + textBBox.y);
}
log();
setInterval(log, 1000);
html,
body {
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg id="rootBox" width="500" height="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0%" y="0%" width="100%" height="100%" fill="beige" />
<svg id="textBox1" x="0%" y="200" width="100%" height="25%">
<rect class="background" x="0%" y="0%" width="100%" height="100%" fill="gray" fill-opacity="0.5" />
<text class="textGroup" x="0" y="0"><tspan x="50%" dy="-0.25em" text-anchor="middle">tspan line 0</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 1</tspan><tspan x="50%" dy="1.5em" text-anchor="middle">tspan line 2</tspan></text>
</svg>
</svg>
Couldn't find it anywhere else to I might ask here :
I have svg rectangle which inside has other rectangles.
What I want to achieve is to center each of these rectangles in the centre of it's parent and in relation to each other.
If I drag rectangle 1 down I want the other one to move up to keep both of them centered - and same thing happening if I drag the other element down (should push upper one up).
Problem here is that I might have different width/heights and there would be 2 or more elements. Is there any mathematical equationfor that? Or a name that I can look for?
I would put the 3 rects inside a group and use the group as in the following example
svg{
border:1px solid;
width: 30vh;
}
<svg viewBox="0 0 100 280">
<defs>
<g id="rects">
<rect width="80" height="80" />
<rect width="60" height="25" x="10" y="10" />
<rect width="60" height="25" x="10" y="45" />
</g>
</defs>
<use xlink:href="#rects" x="10" y="10" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="100" stroke="black" fill="none" />
<use xlink:href="#rects" x="10" y="190" stroke="black" fill="none" />
</svg>
Is it possible to shade in a corner of a shape using only gradients?
Below is an image of what I am trying to do, but had to use a circle and a path.
I know using a path is probably a better method, but I am curious if it can be accomplished with gradients.
Thank you.
Path is not the only method. Sometimes a 5 year old can outsmart me with basic shapes:-
<svg class="sheet" xmlns="http://www.w3.org/2000/svg"
xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">
<pattern id="my_pattern" patternUnits="userSpaceOnUse"
width="200" height="200" viewbox="0 0 200 200">
<rect x="0" y="0" fill="#33ff33" width="200" height="200" />
<rect x="50" y="0" fill="red" width="50" height="50" />
</pattern>
<circle cx="50" cy="50" r="40" style="stroke:black; stroke-width: 2;
fill: URL(#my_pattern)"/>
</svg>
Not with a single gradient. No.
I am new on stackoverflow.
I face a problem in svg code. I want to draw a container with a background image but when I set an image it breaks into 4 parts and gives a white space in mid of container.
This is my SVG code:
<svg id="do-as-cards" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0,0,320,340" preserveAspectRatio="xMidYMin">
<defs>
<pattern id="imgDo" preserveAspectRatio="true" patternUnits="userSpaceOnUse" y="0" x="0" width="240" height="120" >
<image xlink:href="http://s22.postimg.org/ekd89tb8x/image.png" x="0" y="0" width="407px" height="220px" />
</pattern>
<pattern id="imgAs" preserveAspectRatio="true" patternUnits="userSpaceOnUse" y="0" x="0" width="240" height="120" >
<image xlink:href="http://s22.postimg.org/72zfguwc1/image.png" x="0" y="0" width="407px" height="220px" />
</pattern>
</defs>
<g transform="translate(160,86)">
<g id="doCard" class="animatedCard" transform="matrix(1 0 0 1 0 0)" onclick="spin()">
<path class="cardOutline" d="m -150,-60 c 0,-10 10,-20 20,-20 l260,0 c 10,0 20,10 20,20 l 0,120 c 0,10 -10,20 -20,20 l -260,0 c -10,0 -20,-10 -20,-20 l 0,-120 z" />
<foreignObject id="do" class="cardFace" x="-120" y="-60" width="240" height="120"></foreignObject>
</g>
</g>
<g transform="translate(160,253)">
<g id="asCard" class="animatedCard" transform="matrix(1 0 0 1 0 0)" onclick="spin()">
<path class="cardOutline" id="as_path" d="m -150,-60 c 0,-10 10,-20 20,-20 l260,0 c 10,0 20,10 20,20 l 0,120 c 0,10 -10,20 -20,20 l -260,0 c -10,0 -20,-10 -20,-20 l 0,-120 z"/>
<foreignObject id="as" class="cardFace" x="-120" y="-60" width="240" height="120"></foreignObject>
</g>
</g>
</svg>
You can see this code in running stage by using this url
I have already tried the following:
How to set a SVG rect element's background image?
Fill SVG path element with a background-image
Using a <pattern> may not be the best way to do what you want. It can be done though.
If you are using a pattern, stick to the default patternUnits (objectBoundingBox), and set width and height to 1. Then set the width and height of your image to the max width or height of the region you are trying to fill. In the case of your example shapes, that appears to be 300. Then adjust the x and y of the <image> so it is centred in your shape.
<pattern id="imgDo" y="0" x="0" width="1" height="1" >
<image xlink:href="http://s22.postimg.org/ekd89tb8x/image.png" x="0" y="-75" width="300" height="300" />
</pattern>
Demo: http://jsfiddle.net/TRLa7/1/
Personally, I would use a <clipPath> for this situation. Use your path shape as the clipPath for the image. You will need to add an additional copy of the <path> to apply your stroke effects etc. You can define your card(s) in the <defs> section and then use a <use> to instantiate each card.
Demo: http://jsfiddle.net/TRLa7/2/
After several tries, and code changes, I am unable to make rectangle inside SVG to change his position - don't even ask for animating. Obviously using jQuery SVG plugin plus animation extension.
The problem: A SVGs wrapped inside three <div>, an inside y have a rectangle that need to be at y:0 after the document loads. And this is the code:
var rect = jQuery('div.post-image').children('svg').svg().svg('get');
jQuery(rect).each(function(){
jQuery(this).change('.b1', {y:0});
});
Well, nothing happens with the rectangle, it keeps the original coordinate. Chrome console doesn't says anything either.
Added: the HTML in question
<a href="#" class="post-image" title="title">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="250" height="140" viewBox="0,0,250,140" overflow="hidden">
<switch>
<g>
<defs>
<filter id="innershadow">
<feOffset dx="0" dy="0"></feOffset>
<feGaussianBlur stdDeviation="7" result="offset-blur"></feGaussianBlur>
<feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"></feComposite>
<feFlood flood-color="#000" flood-opacity="0.3" result="color"></feFlood>
<feComposite operator="in" in="color" in2="inverse" result="shadow"></feComposite>
<feComposite operator="over" in="shadow" in2="SourceGraphic"></feComposite>
</filter>
<pattern xmlns="http://www.w3.org/2000/svg" id="image-771" patternUnits="userSpaceOnUse" width="250" height="202">
<image href="example-310x250.jpg" xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="250" height="202"></image>
</pattern>
<clipPath id="clip">
<polygon points="0,0 235,0 250,70 235,140 0,140 15,70"></polygon>
</clipPath>
</defs>
<polygon points="0,0 235,0 250,70 235,140 0,140 15,70" style="fill: url(#image-771); filter:url(#innershadow);"></polygon>
<rect class="b1" width="100%" height="100%" style="fill:rgb(0,92,148); opacity: 0.9;" clip-path="url(#clip)" x="0" y="98"></rect>
<rect class="b2" width="60" height="25" style="fill:rgb(0,92,148); opacity: 0.9;" clip-path="url(#clip)" x="190" y="0"></rect>
<rect class="b3" width="100" height="25" style="fill:rgb(0,0,0); opacity: 0.75;" clip-path="url(#clip)" x="0" y="0"></rect>
</g>
<foreignObject width="250" height="140">
<img width="250" height="125" src="example-fallback.jpg" alt="example" title="title"> </foreignObject>
</switch>
</svg>
</a>
I'm willing to use <canvas> for this, but I don't know what are the outcomes.
Found out what wast the problem:
var rect = jQuery('a.post-image').children('svg').find('.b2, .b3');
jQuery(rect).each(function(){
jQuery(this).attr('y','-25');
});
Done, and without a plugin. Okey, not the best way (find instead of most direct selector), but it will cut it.