How to add animation in the clippath of svg - svg

I'm learning how to use svg clippath. And I know how to use the static clippath.
<svg width="500" height="150">
<clipPath id="circle">
<circle cx=50 cy=50 r=50></circle>
</clipPath>
<circle cx=50 cy=50 r=50></circle>
<rect x="0" y="0" width="30" height="15"
style="stroke: #ff0000; fill: none;" clip-path='url(#circle)'>
</rect>
</svg>
there I can get a clip rect.
code Image
but when I try to add an animation, the rect could out of the clippath.
<svg width="500" height="150">
<clipPath id="circle">
<circle cx=50 cy=50 r=50></circle>
</clipPath>
<circle cx=50 cy=50 r=50></circle>
<rect x="0" y="0" width="30" height="15"
style="stroke: #ff0000; fill: none;" clip-path='url(#circle)'>
<animateMotion
path="M10,50 q60,50 100,0 q60,-50 100,0"
begin="0s" dur="10s" repeatCount="indefinite"
rotate="auto"
></animateMotion>
</rect>
</svg>
The rect is out of clippath
what I need is when the rect is out of clippath, it could not be seen any more. The clippath is not allow to move.
So how to get the rectangle in motion to remain in the clippath?

You put the clipped rect in a group and you apply the animation to the group like so:
<svg viewBox="0 0 400 300">
<clipPath id="circle">
<circle cx=50 cy=50 r=50>
</circle>
</clipPath>
<g>
<circle cx=50 cy=50 r=50></circle>
<rect x="0" y="0" width="30" height="15"
style="stroke: #ff0000; fill: none;" clip-path='url(#circle)'>
</rect>
<animateMotion
path="M10,50 q60,50 100,0 q60,-50 100,0"
begin="0s" dur="10s" repeatCount="indefinite"
rotate="auto"
></animateMotion>
</g>
</svg>
UPDATE
The OP is commenting that his question has now been revised.
My question is how to not show the rectangle when it moves outside the clippath?
In this case you put the animated rect in a group and you clip the group like so:
<svg viewBox="0 0 500 150">
<clipPath id="circle">
<circle cx=50 cy=50 r=50></circle>
</clipPath>
<g clip-path='url(#circle)'>
<circle cx=50 cy=50 r=50></circle>
<rect x="0" y="0" width="30" height="15"
style="stroke: #ff0000; fill: none;" >
<animateMotion
path="M10,50 q60,50 100,0 q60,-50 100,0"
begin="0s" dur="10s" repeatCount="indefinite"
rotate="auto"
></animateMotion>
</rect>
</g>
</svg>

Related

How to mask a portion of a stroked path in SVG?

I'm looking to mask a portion of a straight line in SVG and can really only figure out how to do it one way, but would rather do another because the line lengths will be dynamically generated and the mask portion won't.
Let me explain.
Assume I have a line that is <path d="M0,0 L0,100" stroke="blue" stroke-width="20"/>, I would like to mask with transparency the first 10 pixels, meaning just the d="M0,0 L0,10" portion.
I can do this, which produces the results I'd like:
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="90" x="0" y="10" fill="white"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
But the issue is that I can't seem to do the opposite with the rect in the mask, wherein I simply define the it as <rect width="20" height="10" x="0" y="0" fill="white"/> (notice only height and y are different).
Am I missing something on how do define a 10x20 rectangle and have it's mask simply hide a portion of a stroked path, or is this impossible?
If I understood the question correctly, then you need to have a mask in the form of a rectangle of fixed size 10Х20, which will be applied to the line with variable length.
In this case, you can try on a combined mask, one part of which will be opaque fill = "black" and the second part will be transparent fill = "white" and show the rest of the line.
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="100" x="0" y="0" fill="white"/>
<rect width="20" height="10" x="0" y="0" fill="black"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
An example of animating the line masking process with a rectangle 10 x 20px
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="100" x="0" y="0" fill="white"/>
<rect width="20" height="10" x="0" y="0" fill="black">
<animate attributeName="y" dur="2s" values="-10;0" fill="freeze" />
</rect>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>
Works for me ... am I misunderstanding what you're trying to do?
<svg width="100" height="100">
<rect stroke="black" stroke-width="2" width="100" height="100" fill="yellow"/>
<svg x="10" y="0" width="200" height="200" >
<defs>
<rect x="0" y="0" width="20" height="10" stroke="none"/>
<mask id="chopmask" maskUnits="userSpaceOnUse">
<rect width="20" height="10" x="0" y="0" fill="white"/>
</mask>
</defs>
<path d="M0,0 L0,100" mask="url(#chopmask)" stroke="blue" stroke-width="20"/>
</svg>
</svg>

Alter coordinates system by flipping X axis (start at top right corner)

I'm looking for a simple way to make the coordinate system in a given svg element start from the top right corner, instead of the top left. This means the X axis is flipped, thus increasing the x attribute of an element renders it further to the left, and increasing the y attribute renders it further to the bottom as usual.
I've played around with scale and viewBox, however:
scale almost solves the problem, but it doesn't really work for my use case because it also flips the text I've got rendered
viewBox doesn't seem work with height="100%" and width="100%". For my use case I don't think I can hard code the height and width of the SVG because I need it to be usable across many different resolutions and screen sizes.
This question says it solves the same problem for the Y axis with a matrix transformation. I looked around and tried to calculate the equivalent for the X axis, but with no success.
Here is an example of what I'm trying to achieve:
<svg style="border: 1px black solid;" height="100%" width="100%">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="0" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="72" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="124" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="166" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="70" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="122" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="164" y="28"></rect>
</g>
</svg>
As you can see I'd like this stacked bar to be rendered from the right, with the red bar being the furthest to the left (so essentially the stacked bar would be flipped)
Also I'm doing this in Elm, so I can't access the DOM to check widths, heights or coordinates of elements (I'm calculating everything in a functional way).
If anyone could help me achieve this I'd be greatly thankful.
The way I would think about this is drawing your bars from x="0" to the left, and then setting the viewBox with a negative x value and a width that lets it end at x="0".
For the text elements, add a negative sign to the x value. For the rects, set the x value as x -> -x - width.
Define a viewBox such that the lowest x value is still inside, or whatever is appropriate.
<svg style="border: 1px black solid;" height="100%" width="100%" viewBox="-500 0 500 100">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="-70" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="-122" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="-164" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="-216" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="-72" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-124" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-166" y="28"></rect>
</g>
</svg>
This will scale the text and the bars; if you need to avoid that, there is a trick. You can surround the content with two <svg> elements and use the inner one to move everything 100% to the right. overflow="visible" (or style="overflow:visible") makes sure the content is visible although it is formally outside the viewport of the inner <svg>.
<svg style="border: 1px black solid;" height="100%" width="100%">
<svg x="100%" overflow="visible">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="-70" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-35" y="29">7</text>
</g>
<g>
<rect fill="orange" width="50" height="12" x="-122" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-97" y="29">5</text>
</g>
<g>
<rect fill="orange" width="40" height="12" x="-164" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-144" y="29">4</text>
</g>
<g>
<rect fill="red" width="50" height="12" x="-216" y="30"></rect>
<text fill="black" font-size="10px" text-anchor="middle" x="-191" y="29">5</text>
</g>
<rect fill="#52575E" width="2" height="16" x="-72" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-124" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="-166" y="28"></rect>
</g>
</svg>
</svg>
As you said, scale "almost works". You can use scale again to unflip the text. Use nested transforms to get the flipping style working correctly with horizontal text placement. If you want to switch back to the unflipped version just change the -1 in the scale to a 1 (or get rid of the transform in the flipping style).
<head>
<style TYPE="text/css">
<!--
.flipped {
transform: scale(-1,1);
}
-->
</style>
</head>
<svg class=flipped style="border: 1px black solid;" height="100%" width="100%">
<g>
<g>
<rect fill="#F0BC40" width="70" height="12" x="0" y="30"></rect>
<g transform="translate(35,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >7</text>
</g>
</g>
</g>
<g>
<rect fill="orange" width="50" height="12" x="72" y="30"></rect>
<g transform="translate(97,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >5</text>
</g>
</g>
</g>
<g>
<rect fill="orange" width="40" height="12" x="124" y="30"></rect>
<g transform="translate(144,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >4</text>
</g>
</g>
</g>
<g>
<rect fill="red" width="50" height="12" x="166" y="30"></rect>
<g transform="translate(191,29)">
<g class=flipped >
<text fill="black" font-size="10px" text-anchor="middle" >5</text>
</g>
</g>
</g>
<rect fill="#52575E" width="2" height="16" x="70" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="122" y="28"></rect>
<rect fill="#52575E" width="2" height="16" x="164" y="28"></rect>
</g>
</svg>

How can i scale a shape without scaling its pattern?

I have an svg shape which uses a pattern. I want the pattern to NOT scale when i scale the shape.
Here's a fiddle with a minimal example, the bigger circle should show the pattern like the smaller one:
http://jsfiddle.net/cTMrQ/6/
<svg style="position: absolute" width="100%" height="100%" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">
<defs>
<pattern id="checkerPattern" patternUnits="userSpaceOnUse" x="0" y="0" width="4" height="4">
<image x="0" y="0" xlink:href="http://inwonderland.at/new/lines.png" width="4" height="4" />
</pattern>
<circle fill="url(#checkerPattern)" id="c" cx="50" cy="50" r="50" />
</defs>
<use x="100" y="100" xlink:href="#c" />
<use x="200" y="100" xlink:href="#c" transform="scale(2)" />
</svg>
In the end the shape will be a complex path and the image in the pattern will be a scan of a piece of paper, so just drawing a bigger circle instead of scaling it won't work.
Update
To clarify what i want, here are two images:
this is what it looks like, no matter what i try, when i scale the shape:
http://inwonderland.at/new/ihave.png
this is what i want:
http://inwonderland.at/new/iwant.png
i want the background image (bitmap image) to always have its natural size.
You can't get what you want using a pattern, the transform always happens after the fill, and you can't just move the pattern fill into a wrapper either. My suggestion is to use a filter and apply the filter on a wrapper - like so:
<svg style="position: absolute" width="100%" height="100%" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">
<defs>
<circle fill="url(#checkerPattern)" id="c1" cx="50" cy="50" r="50" />
<filter id="linepattern" x="0%" y="0%" height="100%" width="100%">
<feImage xlink:href="http://inwonderland.at/new/lines.png" result="pattern" width="4" height="4"/>
<feTile/>
<feComposite operator="in" in2="SourceGraphic"/>
</filter>
</defs>
<use filter="url(#linepattern)" x="100" y="100" xlink:href="#c1" />
<use filter="url(#linepattern)" x="200" y="100" xlink:href="#c1" transform="scale(2)" />
<g filter="url(#linepattern)">
<use x="50" y="100" xlink:href="#c1" transform="scale(2)" />
</g>
</svg>
Using viewport
1:1 no zoom
<svg width="800" height="400" viewBox="0 0 800 400">
2:1 zoom double size
<svg width="800" height="400" viewBox="0 0 400 200">
The following elements can use the viewBox attribute
<svg>
<symbol>
<image>
<marker>
<pattern>
<view>
viewbox is fully animatable; and you can zoom into any center point.
<animate attributeName="viewBox" begin="1s" dur="1s"
values="0 0 600 400; 250 180 300 200" fill="freeze" />
Transform a parent tag
Yes an SVG can be a child element but more commonly shapes made with multible tags are placed inside a group tag.
Transform scale can be used with tags which are parents IE the group tag.
<g transform="scale(1.5)">
/* draw your shape inside the g tag */
<use x="100" y="100" xlink:href="#c" />
<use x="200" y="100" xlink:href="#c" />
</g>
So using your above example scale the shape in a parent tag.
Update
To scale image but not patterns in other words move patterns, or icons, on background image that scales.
<g transform="scale(2)">
/* draw your shape inside the g tag */
<use x="100" y="100" xlink:href="#c" transform="scale(.5)" />
<use x="200" y="100" xlink:href="#c" transform="scale(.5)"/>
</g>
Update full svg
I had to move things around a bit, One full size, (lets call it a map), with an overlay of 1 half size map in the upper left corner. setting the full screen to render between 0 and max of 600. Setting a viewport the same but with the width set to 300 scales it down. I do need to double the radius for this example of scaling.
<svg viewBox="0 0 600 600" style="position: absolute" width="100%" height="100%" version="1.1" baseProfile="full"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">
<defs>
<pattern id="checkerPattern" patternUnits="userSpaceOnUse" x="0" y="0" width="4" height="4">
<image x="0" y="0" xlink:href="http://inwonderland.at/new/lines.png" width="4" height="4" />
</pattern>
<circle fill="url(#checkerPattern)" id="c" cx="50" cy="50" r="50" />
<circle fill="url(#checkerPattern)" id="c2" cx="50" cy="50" r="100" />
</defs>
<use x="100" y="100" xlink:href="#c" transform="scale(.5)"/>
<use x="200" y="100" xlink:href="#c" transform="scale(1)"/>
<rect width="600" height="600" style="fill: none; stroke: black;" />
<svg viewBox="0 0 600 600" width="300" height="300" x="300">
<use x="100" y="100" xlink:href="#c2" transform="scale(.5)"/>
<use x="200" y="100" xlink:href="#c2" transform="scale(1)"/>
<rect width="600" height="600" style="fill: none; stroke: black;" />
</svg>
</svg>
This example is scaled using the same circle pattern. The radius does not need to be changed here because the location is not in the tag being scaled. I'm making use of svg tags here but other tags can be used.
<svg viewBox="0 0 600 600" style="position: absolute" width="100%" height="100%" version="1.1" baseProfile="full"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events">
<defs>
<pattern id="checkerPattern" patternUnits="userSpaceOnUse" x="0" y="0" width="4" height="4">
<image x="0" y="0" xlink:href="http://inwonderland.at/new/lines.png" width="4" height="4" />
</pattern>
<circle fill="url(#checkerPattern)" id="c" r="50" cx="50" cy="50" />
</defs>
<svg x="100" y="100"><use xlink:href="#c" transform="scale(.5)"/></svg>
<svg x="200" y="100"><use xlink:href="#c" transform="scale(1)"/></svg>
<rect width="600" height="600" style="fill: none; stroke: black;" />
<svg viewBox="0 0 600 600" width="300" height="300" x="300">
<svg x="100" y="100"><use xlink:href="#c" transform="scale(1)"/></svg>
<svg x="200" y="100"><use xlink:href="#c" transform="scale(2)"/></svg>
<rect width="600" height="600" style="fill: none; stroke: black;" />
</svg>
</svg>

How to Exclude Area inside of clippath in Svg

I want to hide anything that outside a rectangle. (this i have achieved with clipping successfully). but another condition is that, 'also hide anything that comes inside the black big circle'. Now how i can achieve that?
in below example, 'yellow circle' must be eliminated'.
see below images for detail
Original:-
Desired:-
Below is my Svg code:-
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
</clipPath>
</svg>
Erik Dahlström is right, your clip can include the entire rectangle and the cutout for the circle. This way, anything you associate with #clip1 as the clip-path will not be visible inside your circle area. Here is what it looks like for your example:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
<g>
<rect x="50" y="50" width="200" height="200" stroke="1" fill="red"/>
<circle cx="180" cy="150" r="30" stroke="blue" />
</g>
<g clip-path = "url(#clip1)">
<circle cx="180" cy="150" r="10" stroke="blue" fill="yellow" />
</g>
<clipPath id = "clip1">
<path d="M 50,50 l200 0 l0 200 l-200 0z M150,150 a30,30 1 0,0 60,0z M210,150 a30,30 1 0,0 -60,0z"/>
</clipPath>

reference element in a animate element and the element and animate element are in a defs to be reflected in use element

I am researching svg animation and was wonder if it possible to use the href attribute in the animate element which the target of the href and the animate element it self are in a defs... here is a code working example:
<svg viewBox="0 0 400 100">
<defs>
<rect id="anim-rect"
x="-25" y="-25"
width="50" height="50"
fill="#29e" >
<animate
attributeName="fill"
values="#29e; #4e4; #f40; #29e"
dur="6s"
repeatCount="indefinite" />
</rect>
</defs>
<use xlink:href="#anim-rect" transform="translate(100 50)"/>
<use xlink:href="#anim-rect" transform="translate(200 50)"/>
<use xlink:href="#anim-rect" transform="translate(300 50)"/>
</svg>
And here what I want to do:
<svg viewBox="0 0 400 100">
<defs>
<rect id="anim-rect"
x="-25" y="-25"
width="50" height="50"
fill="#29e" >
</rect>
<animate xlink:href="#anim-rect"
attributeName="fill"
values="#29e; #4e4; #f40; #29e"
dur="6s"
repeatCount="indefinite" />
</defs>
<use xlink:href="#anim-rect" transform="translate(100 50)"/>
<use xlink:href="#anim-rect" transform="translate(200 50)"/>
<use xlink:href="#anim-rect" transform="translate(300 50)"/>
</svg>
Any help would be appreciated.

Resources