Any idea why the rotation does not seem to take place in the clip path coordinates? 0.5 0.5 should denote the center of the shape, i.e. where the two squares meet.
svg {
background: green;
}
<svg width="100" height="100" viewBox="0 0 100 100">
<clipPath id="rel" clipPathUnits="objectBoundingBox" transform="rotate(20 0.5 0.5)">
<rect width="0.5" height="0.5"/>
<rect x="0.5" y="0.5" width="0.5" height="0.5"/>
</clipPath>
<rect width="100" height="100" x="0" y="0" clip-path="url(#rel)" fill="red"/>
</svg>
I expected to see something like this:
svg {
background: green;
}
<svg width="100" height="100" viewBox="0 0 100 100">
<clipPath id="abs" transform="rotate(20 50 50)">
<rect width="50" height="50"/>
<rect x="50" y="50" width="50" height="50"/>
</clipPath>
<rect width="100" height="100" x="0" y="0" clip-path="url(#abs)" fill="red"/>
</svg>
I have some tile symbols that I would like to place on a grid. This is what I'm trying to achieve:
Use tile coordinates to position the symbols (e.g. 4,2 instead of 85,43)
Use pixel coordinates (not tile coordinates) for defining the vertices of symbols
Rotate symbols around their center without specifying absolute coordinates.
I have solutions to the first two (there might be better solutions though) but not the third. I can rotate the tile at 4,2 by a quarter turn with this:
<!-- 10/21 = 0.47619047619 -->
<use x="4" y="2" href="#rooftop-0" class="theme-0" transform="rotate(90 4.476 2.476)" />
I really don't like having to specify the tile coordinates twice. Ideally, I would like to write something like this instead:
<use x="4" y="2" href="#rooftop-0" class="theme-0 rotate-1" />
Defining .rotate-1 in the stylesheet doesn't seem to have any effect on the rotation. transform-origin="50% 50%" seems to be setting the origin to 50% of the viewport or something. Maybe defining the symbol with coordinates from -10 to 10 instead of 0 to 20 would help? Should I define the viewBox of the symbols?
Another solution would be manually changing the coordinates of the vertices in the symbol to create the other 3 orientations. I'd rather not!
Anyway, this is what I have so far:
<?xml version="1.0" standalone="no"?>
<!-- 21*10+1 = 211 -->
<svg width="211" height="211" version="2.0" xmlns="http://www.w3.org/2000/svg">
<style>
.grid-line {
fill: #DDD;
}
.grass-fill {
fill: #8C8;
}
.tile {
/* 1/21 = 0.04761904761 */
transform: scale(0.04761904761, 0.04761904761);
}
.theme-0 {
--roof-color-0: #F44;
--roof-color-1: #F66;
--roof-color-2: #F88;
--roof-color-3: #FAA;
}
.theme-1 {
--roof-color-0: #44F;
--roof-color-1: #66F;
--roof-color-2: #88F;
--roof-color-3: #AAF;
}
</style>
<defs>
<pattern id="grid" width="21" height="21" patternUnits="userSpaceOnUse">
<rect class="grid-line" x="0" y="0" width="1" height="21" />
<rect class="grid-line" x="0" y="0" width="21" height="1" />
</pattern>
<symbol id="rooftop-0">
<g class="tile">
<rect class="grass-fill" width="20" height="20" />
<polygon style="fill: var(--roof-color-0)" points="3,2 17,2 18,8 2,8" />
<polygon style="fill: var(--roof-color-1)" points="2,8 18,8 17,14 3,14" />
<polygon style="fill: var(--roof-color-2)" points="8,8 11,14 11,18 8,18" />
<polygon style="fill: var(--roof-color-3)" points="8,8 8,18 5,18 5,14" />
</g>
</symbol>
<symbol id="rooftop-1">
<g class="tile">
<rect class="grass-fill" width="20" height="20" />
<polygon style="fill: var(--roof-color-0)" points="2,11 18,11 17,17 3,17" />
<polygon style="fill: var(--roof-color-1)" points="3,5 17,5 18,11 2,11" />
<polygon style="fill: var(--roof-color-2)" points="10,11 10,3 13,3 13,5" />
<polygon style="fill: var(--roof-color-3)" points="10,11 7,5 7,3 10,3" />
</g>
</symbol>
</defs>
<g>
<rect fill="#999" width="100%" height="100%" />
<rect fill="url(#grid)" width="100%" height="100%" />
</g>
<g transform="translate(1, 1) scale(21, 21)">
<use x="3" y="2" href="#rooftop-0" class="theme-1" />
<!-- 10/21 = 0.47619047619 -->
<use x="4" y="2" href="#rooftop-0" class="theme-0" transform="rotate(90 4.476 2.476)" />
<use x="5" y="2" href="#rooftop-1" class="theme-1" />
</g>
</svg>
Here's a screenshot:
Is there a clean way of doing what I'm trying to do? Rotating a symbol around its center seems like something one would do all the time.
Instead of setting your <use> attributes using xand y coordinates, you can set them using transform="translate(x, y), this way, the origin parameters of the rotate() method will stay the same (0.5, 0.5):
<svg viewBox="0 0 211 211">
<style>
.grid-line {
fill: #DDD;
}
.grass-fill {
fill: #8C8;
}
.theme-0 {
--roof-color-0: #F44;
--roof-color-1: #F66;
--roof-color-2: #F88;
--roof-color-3: #FAA;
}
.theme-1 {
--roof-color-0: #44F;
--roof-color-1: #66F;
--roof-color-2: #88F;
--roof-color-3: #AAF;
}
</style>
<defs>
<pattern id="grid" x="-0.5" y="-0.5" width="20" height="20" patternUnits="userSpaceOnUse">
<rect class="grid-line" x="0" y="0" width="1" height="20" />
<rect class="grid-line" x="0" y="0" width="20" height="1" />
</pattern>
<symbol id="rooftop-0" viewBox="0 0 20 20">
<g class="tile" transform="translate(0.5, 0.5) scale(0.95)">
<rect class="grass-fill" width="20" height="20" />
<polygon style="fill: var(--roof-color-0)" points="3,2 17,2 18,8 2,8" />
<polygon style="fill: var(--roof-color-1)" points="2,8 18,8 17,14 3,14" />
<polygon style="fill: var(--roof-color-2)" points="8,8 11,14 11,18 8,18" />
<polygon style="fill: var(--roof-color-3)" points="8,8 8,18 5,18 5,14" />
</g>
</symbol>
<symbol id="rooftop-1" viewBox="0 0 20 20">
<g class="tile"transform="translate(0.5, 0.5) scale(0.95)">
<rect class="grass-fill" width="20" height="20" />
<polygon style="fill: var(--roof-color-0)" points="2,11 18,11 17,17 3,17" />
<polygon style="fill: var(--roof-color-1)" points="3,5 17,5 18,11 2,11" />
<polygon style="fill: var(--roof-color-2)" points="10,11 10,3 13,3 13,5" />
<polygon style="fill: var(--roof-color-3)" points="10,11 7,5 7,3 10,3" />
</g>
</symbol>
</defs>
<g>
<rect fill="#999" width="100%" height="100%" />
<rect fill="url(#grid)" width="100%" height="100%" />
</g>
<g transform="scale(20, 20)">
<use xlink:href="#rooftop-0" class="theme-1" width="1" height="1" transform="translate(4, 2) rotate(0,0.5,0.5)"/>
<use xlink:href="#rooftop-1" class="theme-0" width="1" height="1" transform="translate(5, 2) rotate(90,0.5,0.5)"/>
<use xlink:href="#rooftop-0" class="theme-1" width="1" height="1" transform="translate(6, 2) rotate(180,0.5,0.5)"/>
</g>
</svg>
I hope this is what you were asking: The symbol has now a wiewBox attribute: viewBox="0 0 20 20" This means that the symbol has a width of 20 units and a height of 20 units. Now you can use the symbol like this:
<use xlink:href="#rooftop-0" width="20" height="20" x="63" y="21" />
As you can see I can give the symbol a width and a height in this case width="20" height="20" but you can give it any size you need. Also you can use the x and y attributes to reposition the used symbol.
Now you can also rotate the use element around it's center by using transform="rotate(90,73,31)" This is rotating the element 90degs around the point {x:73,y:31}
<svg viewBox="0 0 211 211">
<style>
.grid-line {
fill: #DDD;
}
.grass-fill {
fill: #8C8;
}
.theme-0 {
--roof-color-0: #F44;
--roof-color-1: #F66;
--roof-color-2: #F88;
--roof-color-3: #FAA;
}
.theme-1 {
--roof-color-0: #44F;
--roof-color-1: #66F;
--roof-color-2: #88F;
--roof-color-3: #AAF;
}
</style>
<defs>
<pattern id="grid" width="21" height="21" patternUnits="userSpaceOnUse">
<rect class="grid-line" x="0" y="0" width="1" height="21" />
<rect class="grid-line" x="0" y="0" width="21" height="1" />
</pattern>
<symbol id="rooftop-0" viewBox="0 0 20 20">
<g class="tile">
<rect class="grass-fill" width="20" height="20" />
<polygon style="fill: var(--roof-color-0)" points="3,2 17,2 18,8 2,8" />
<polygon style="fill: var(--roof-color-1)" points="2,8 18,8 17,14 3,14" />
<polygon style="fill: var(--roof-color-2)" points="8,8 11,14 11,18 8,18" />
<polygon style="fill: var(--roof-color-3)" points="8,8 8,18 5,18 5,14" />
</g>
</symbol>
</defs>
<g>
<rect fill="#999" width="100%" height="100%" />
<rect fill="url(#grid)" width="100%" height="100%" />
</g>
<g transform="translate(1, 1)">
<use x="42" y="21" xlink:href="#rooftop-0" class="theme-1" width="20" height="20" />
<use x="63" y="21" xlink:href="#rooftop-0" class="theme-0" width="20" height="20" transform="rotate(90,73,31)" />
</g>
</svg>
So I've created a page with some colorful SVG images in it, and I want them to be grayed at hormal state, and shows color while hovered.
svg {
width: 200px;
margin: 50px;
}
svg * {
transition: fill 1s;
}
svg:not(:hover) * {
fill: gray !important;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 1">
<rect x="0" y="0" width="1" height="1" style="fill: red" />
<rect x="1" y="0" width="1" height="1" style="fill: green" />
<rect x="2" y="0" width="1" height="1" style="fill: blue" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 1">
<g>
<rect x="0" y="0" width="1" height="1" style="fill: red" />
<rect x="1" y="0" width="1" height="1" style="fill: green" />
<rect x="2" y="0" width="1" height="1" style="fill: blue" />
</g>
</svg>
As one can see, SVGs have different colored elements, also some elements are grouped. This is pretty simplified example, but the real images are much more complex, with massive transform-s so I can't easily remove grouping.
Both images work perfect and changes colors while hovered, but the first image does it instantly while the the second has 1 second delay before animation starts.
Searching for the solution I've found that if an elemend is wrapped with a single <g> tag it has the animation delay, but if there no <g> or two of them, no delay occurs.
Firefox animates both images with no animation delay.
By the moment I ungrouped elements by hands, but obviously it's not a good solution, so the question is how it can be solved without changing files at all ?
A pretty sneaky bug, but easily solved: just restrict the child selector to non-g elements:
svg {
width: 200px;
margin: 50px;
}
svg :not(g) {
transition: fill 1s;
}
svg:not(:hover) * {
fill: gray !important;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 1">
<rect x="0" y="0" width="1" height="1" style="fill: red" />
<rect x="1" y="0" width="1" height="1" style="fill: green" />
<rect x="2" y="0" width="1" height="1" style="fill: blue" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3 1">
<g>
<rect x="0" y="0" width="1" height="1" style="fill: red" />
<rect x="1" y="0" width="1" height="1" style="fill: green" />
<rect x="2" y="0" width="1" height="1" style="fill: blue" />
</g>
</svg>
I have an svg rect chart like:
<div style="width:300px;height:300px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%;height:100%" viewBox="0 0 300 300">
<g>
<rect width="14.55" height="40%" x="0" y="0" fill="black"></rect>
<rect width="14.55" height="20%" x="50" y="0" fill="green"></rect>
<rect width="14.55" height="80%" x="100" y="0" fill="red"></rect>
<rect width="14.55" height="90%" x="150" y="0" fill="yellow"></rect>
<rect width="14.55" height="10%" x="200" y="0" fill="pink"></rect>
<rect width="14.55" height="60%" x="250" y="0" fill="orange"></rect>
</g>
</svg>
</div>
What I want to do is to display it upside down.
The code and a given solution, are coming from http://jsfiddle.net/rhvP8/5/
Although, I want to keep each bar in the same X place. So, rotation approach is not that useful in this case.
Any help is welcome.
Rotation of the x-axis only seems be be what you require.
svg {
border: 1px solid green;
transform: rotateX(180deg);
}
<div style="width:300px;height:300px;">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%;height:100%" viewBox="0 0 300 300">
<g>
<rect width="14.55" height="40%" x="0" y="0" fill="black"></rect>
<rect width="14.55" height="20%" x="50" y="0" fill="green"></rect>
<rect width="14.55" height="80%" x="100" y="0" fill="red"></rect>
<rect width="14.55" height="90%" x="150" y="0" fill="yellow"></rect>
<rect width="14.55" height="10%" x="200" y="0" fill="pink"></rect>
<rect width="14.55" height="60%" x="250" y="0" fill="orange"></rect>
</g>
</svg>
</div>
I'm trying to make an SVG image where I use one group of shapes as a mask for another.
Basically I want a group of transparent shapes that overlay a bigger shape and clip it, so you can see the page background through them (because they're transparent) but not the bigger shape's fill or stroke.
I tried applying a mask to the big shape that has a tag pointing to the #overlays group but it doesn't seem to work. Pointing the to an individual overlay DOES work but I don't want to put in a for every overlay.
Codepen: http://codepen.io/nathancox/pen/YPgZPR?editors=110
The top shape is the SVG, the bottom one is an image of what I'm trying to get it to do.
Here's the SVG:
<svg>
<defs>
<mask id="clip-behind" >
<rect id="bg" x="0" y="0" width="100%" height="100%" fill="white"/>
<use xlink:href="#overlays" fill='black' fill-opacity='1' />
</mask>
</defs>
<rect
mask="url(#clip-behind)"
width="260" height="270" x="50" y="50"
fill='none' stroke-opacity='1' stroke='black' stroke-width='4'
/>
<g id="overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red'>
<rect id='overlay1' width="80" height="80" x="280" y="150" />
<rect id='overlay2' width="50" height="50" x="140" y="300" />
</g>
</svg>
Anybody know what I'm doing wrong, or if there's a better approach?
You won't be able to do it this way, <mask> uses alpha-channel to determine the opacity of masking ( black is clipped and white left ).
So in order to avoid semi-transparence of red mask, and because you can't change the already set fill property of elements contained in a <g> copied with <use>, you will have to link for an in <defs> <g>, without attribute, in the <mask> and in the document, and set their respective attributes then :
Really transparent :
body {
background-color: #fff;
background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
background-size: 100% 1.2em;
}
svg {
width: 400px;
height: 400px;
}
<div id='container'>
<svg>
<defs>
<g id="overlays">
<rect id='overlay1' width="80" height="80" x="280" y="150" />
<rect id='overlay2' width="50" height="50" x="140" y="300" />
</g>
<mask id="clip-behind">
<rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
<use xlink:href="#overlays"/>
</mask>
</defs>
<rect mask="url(#clip-behind)" width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />
<use xlink:href="#overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red' />
</svg>
<img src='https://dl.dropboxusercontent.com/u/587097/desired.png' />
</div>
Semi-transparent :
body {
background-color: #fff;
background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
background-size: 100% 1.2em;
}
svg {
width: 400px;
height: 400px;
}
<div id='container'>
<svg>
<defs>
<mask id="clip-behind">
<rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
<!-- changed the fill-opacity to make it more obvious -->
<g id="overlays" fill='red' fill-opacity='0.8' stroke-opacity='1' stroke='red'>
<rect id='overlay1' width="80" height="80" x="280" y="150" />
<rect id='overlay2' width="50" height="50" x="140" y="300" />
</g>
</mask>
</defs>
<rect mask="url(#clip-behind)" width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />
</svg>
</div>
<use xlink:href="#overlays" fill="black" fill-opacity="1"> displayed in normal view :
(still red semi-transparent)
body {
background-color: #fff;
background-image: linear-gradient(#eee 0.1em, transparent 0.1em);
background-size: 100% 1.2em;
}
svg {
width: 400px;
height: 400px;
}
<div id='container'>
<svg>
<defs>
<g id="overlays" fill='red' fill-opacity='0.25' stroke-opacity='1' stroke='red'>
<rect id='overlay1' width="80" height="80" x="280" y="150" />
<rect id='overlay2' width="50" height="50" x="140" y="300" />
</g>
</defs>
<rect width="260" height="270" x="50" y="50" fill='none' stroke-opacity='1' stroke='black' stroke-width='4' />
<use xlink:href="#overlays" fill="black" fill-opacity="1" />
</svg>
</div>