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 with four coloured blocks that I want to clip by a rotated ellipse. It works as expected in Chrome and Safari, but Firefox (63.0.3 on Mac) ignores the transformation of the ellipse.
Here is a CodePen that illustrates the issue.
SVG
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 500 500">
<defs>
<clipPath id="myClip">
<ellipse id = "ellipse" cx="250" cy="250" rx="200" ry="100" />
</clipPath>
</defs>
<g class="clip-this">
<rect class="color-1" x="0" y="0" width="250" height="250" />
<rect class="color-2" x="250" y="0" width="250" height="250" />
<rect class="color-3" x="0" y="250" width="250" height="250" />
<rect class="color-4" x="250" y="250" width="250" height="250" />
</g>
</svg>
CSS
#ellipse{
transform:rotate(-30deg);
transform-origin:center;
}
.color-1,.color-4{
fill:#ababab;
}
.color-2,.color-3{
fill:#3a3a3a;
}
svg {
max-width: 400px;
}
.clip-this{
clip-path: url(#myClip);
}
This is a known bug. As a workaround, you can use the SVG transform attribute instead of the CSS property. Note that for full browser compatibility the transform function must not have units for the numbers, and the center of rotation is noted in userspace coordinates.
.color-1,.color-4{
fill:#ababab;
}
.color-2,.color-3{
fill:#3a3a3a;
}
svg {
max-width: 400px;
}
.clip-this{
clip-path: url(#myClip);
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 500 500">
<defs>
<clipPath id="myClip">
<ellipse id = "ellipse" cx="250" cy="250" rx="200" ry="100" transform="rotate(-30, 250, 250)" />
</clipPath>
</defs>
<g class="clip-this">
<rect class="color-1" x="0" y="0" width="250" height="250" />
<rect class="color-2" x="250" y="0" width="250" height="250" />
<rect class="color-3" x="0" y="250" width="250" height="250" />
<rect class="color-4" x="250" y="250" width="250" height="250" />
</g>
</svg>
Why, in this SVG, can I change the stroke-width on hover, but not the stroke-color?
The problem is clearly presented in the snippet below.
The stroke-width:5; is seeing applied to all elements in the <g id="HOVERME_LEGEND_ABC">, while the stroke:blue; is seemingly just not applied to any.
MWE SNIPPET
#LEGEND_ABC{
cursor:pointer;
}
#LEFTTICKBOX_ABC{
stroke:black;
}
#COLOUREDBOX_ABC{
fill:yellow;
stroke:black;
}
#HOVERME_LEGEND_ABC:hover{
fill:#0000EE;
stroke-width:5;
stroke:blue;
}
<svg id="SVG"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="500"
height="70"
viewBox="-15 -45 500 70">
<g id="LEGEND_ABC">
<g id="HOVERME_LEGEND_ABC">
<rect id="LEFTTICKBOX_ABC"
x="0"
y="0"
width="15"
height="15">
</rect>
<use id="COLOUREDBOX_ABC"
x="30"
y="-5"
xlink:href="#LEGENDBOX">
</use>
<text id="TEXT_ABC"
x="65"
y="12.5">
Color me (why are the rectangles not being stroked blue?)
</text>
</g>
</g>
<defs id="DEFINITIONS">
<rect id="RECTANGLE_YELLOW"
width="42.5"
height="95">
</rect>
<rect id="LEGENDBOX"
x="0"
y="0"
width="25"
height="25">
</rect>
</defs>
</svg>
What I would like, is the whole contents of <g id="HOVERME_LEGEND_ABC"> being stroked blue on hovering over the group, regardless of what stroke-colors the individual objects have before hovering over the group.
Be more spesific... #HOVERME_LEGEND_ABC:hover #COLOUREDBOX_ABC
#LEGEND_ABC{
cursor:pointer;
}
#LEFTTICKBOX_ABC{
stroke:black;
}
#COLOUREDBOX_ABC{
fill:yellow;
stroke:black;
}
#HOVERME_LEGEND_ABC:hover{
fill:#0000EE;
stroke-width:5;
stroke:blue;
}
#HOVERME_LEGEND_ABC:hover #COLOUREDBOX_ABC{
fill:#0000EE;
stroke-width:5;
stroke:blue;
}
#HOVERME_LEGEND_ABC:hover #LEFTTICKBOX_ABC{
fill:#0000EE;
stroke-width:5;
stroke:blue;
}
<svg id="SVG"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="500"
height="70"
viewBox="-15 -45 500 70">
<g id="LEGEND_ABC">
<g id="HOVERME_LEGEND_ABC">
<rect id="LEFTTICKBOX_ABC"
x="0"
y="0"
width="15"
height="15">
</rect>
<use id="COLOUREDBOX_ABC"
x="30"
y="-5"
xlink:href="#LEGENDBOX">
</use>
<text id="TEXT_ABC"
x="65"
y="12.5">
Color me (why are the rectangles not being stroked blue?)
</text>
</g>
</g>
<defs id="DEFINITIONS">
<rect id="RECTANGLE_YELLOW"
width="42.5"
height="95">
</rect>
<rect id="LEGENDBOX"
x="0"
y="0"
width="25"
height="25">
</rect>
</defs>
</svg>
How can I make the black background of the div visible?
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>
<div style="background:black;color:white;margin-top:-50px;">
<h1>Hello Plunker!</h1>
</div>
http://plnkr.co/edit/rHlE2AdfkR81zVjE3oez?p=preview
Thanks.
Give relative position to black div.
Link.