CSS transform scale function moving SVG item position automatically - svg

I am working on a navigation bar in a circle format split in 5.All the elements are SVGs.
It really look like a pie chart.While hovering one part, i would like to scale the svg element to the exterior. As i am trying to use scale with this, the element just translate itself further and do the scale effect.I'm not sure but i think it is a problem of overlapping css element? Anyway if someone could help me with this how to tell the part to stay at the same place and then scale bigger, or do i need to manually re-translate the element at the correct place?
Thanks, here is a represatation:
#group-part-1>text {
visibility: hidden;
}
#group-part-1:hover text {
visibility: visible;
}
#group-part-2>text {
visibility: hidden;
}
#group-part-2:hover text {
visibility: visible;
}
#group-part-3>text {
visibility: hidden;
}
#group-part-3:hover text {
visibility: visible;
}
#group-part-4>text {
visibility: hidden;
}
#group-part-4:hover text {
visibility: visible;
}
#group-part-5>text {
visibility: hidden;
}
#group-part-5:hover text {
visibility: visible;
}
#part-1:hover {
fill: red;
transform: scale(1.2);
}
#part-2:hover {
fill: green;
transform: scale(1.2);
}
#part-3:hover {
fill: purple;
}
#part-4:hover {
fill: orange;
}
#part-5:hover {
fill: blue;
}
<svg width="210" height="297" viewBox="0 0 210 297" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="example">
<g id="group-part-5">
<path id="part-5"
d="M156.393 107.998C159.608 118.055 159.557 128.873 156.247 138.899C152.936 148.926 146.536 157.647 137.964 163.813L108.768 123.223L156.393 107.998Z"
fill="black" stroke="black" stroke-width="0.0132292" />
<text x="160" y="150" fill="black">Project</text>
</g>
<g id="group-part-4">
<path id="part-4"
d="M137.963 163.813C129.391 169.979 119.087 173.272 108.529 173.222C97.9698 173.171 87.6979 169.78 79.1853 163.532L108.768 123.223L137.963 163.813Z"
fill="#1A1A1A" stroke="black" stroke-width="0.0132292" />
<text x="90" y="200" fill="black">About</text>
</g>
<g id="group-part-3">
<path id="part-3"
d="M79.2054 163.547C70.6897 157.304 64.3689 148.526 61.1491 138.469C57.9293 128.413 57.9756 117.596 61.2815 107.568L108.768 123.223L79.2054 163.547Z"
fill="#333333" stroke="black" stroke-width="0.0132292" />
<text x="10" y="150" fill="black">Contact</text>
</g>
<g id="group-part-2">
<path id="part-2"
d="M61.2928 107.534C64.606 97.508 71.008 88.7885 79.5814 82.625C88.1547 76.4615 98.4593 73.1703 109.018 73.2231L108.768 123.223L61.2928 107.534Z"
fill="#4D4D4D" stroke="black" stroke-width="0.0132292" />
<text x="25" y="75" fill="black">Home</text>
</g>
<g id="group-part-1">
<path id="part-1"
d="M108.941 73.2228C119.5 73.2594 129.776 76.6378 138.297 82.8738C146.818 89.1097 153.146 97.8831 156.374 107.937L108.768 123.223L108.941 73.2228Z"
fill="#666666" stroke="black" stroke-width="0.0132292" />
<text x="150" y="75" fill="black">Work</text>
</g>
</svg>
thanks

This is the way I would do it:
the svg element is centered around the point {x:0,y:0}: viewBox="-105 -105 210 210"
I calculate the points for the arc in base of the angle of the wedge and the radius of the circle
In this example I'm rotating the text too so I'm putting both the wedge and the text in the same group (#group_part5) and I'm transforming the group on mouse over: transform: translate(10px, 0) scale(1.2);
I'm wrapping everything in a different group (#example) and I'm rotating this group to the needed position.
//the angle for the circle wedge
let angle = 2*Math.PI/5;
//the radius of the circle wedge
let r = 60;
//calculate the points for the arc
let p1 = {x:r*Math.cos(-angle/2),
y:r*Math.sin(-angle/2)};
let p2 = {x:r*Math.cos(angle/2),
y:r*Math.sin(angle/2)};
//build the d attribute
let d = `M0,0L${p1.x},${p1.y}A${r},${r} 0 0 1 ${p2.x},${p2.y} z`;
//set the d attribute of the path
part5.setAttribute("d",d);
svg {
border: solid;
}
#example {
transform: rotate(36deg);
}
#group_part5:hover {
fill: red;
transform: translate(10px, 0) scale(1.2);
}
#group_part5:hover text {
fill: black;
}
<svg width="210" viewBox="-105 -105 210 210">
<g id="example">
<g id="group_part5">
<path id="part5" d="" />
<text fill="none" x="30">Project</text>
</g>
</g>
</svg>
Observation: If you don't want to use javascript you can take the d attribute for the path from the inspector.
UPDATE
The OP is commenting
The only thing is that the 'origin' top-left corner is moving, i want it to stay at the same place as well as the borders, the border only need to be longer and the circle exterior border further
If I understand you correctly in the previous demo please replace transform: translate(10px, 0) scale(1.2); with transform: scale(1.2);
If this is what you need there is a simpler way to do this: instead or scaling the wedge you can add a wide stroke - the same color as the fill - like in the following demo:
Please take a look:
svg {
border: solid;
}
#example {
transform: rotate(36deg);
}
#group_part5:hover {
fill: red;
/*transform: translate(10px, 0) scale(1.2);*/
}
#group_part5:hover path:nth-of-type(2){stroke:red;}
#group_part5:hover text {
fill: black;
}
<svg width="210" viewBox="-105 -105 210 210">
<g id="example">
<g id="group_part5">
<path id="part5" d="M0,0L48.54101966249685,-35.26711513754839A60,60 0 0 1 48.54101966249685,35.26711513754839 z"></path>
<path d="M48.54101966249685,-35.26711513754839A60,60 0 0 1 48.54101966249685,35.26711513754839" fill="none" stroke-width="10"></path>
<text fill="none" x="30">Project</text>
</g>
</g>
</svg>

Related

Reusing SVG elements while inserting different text?

I want to display balls with 1,2,3,4 inside. Can I use <use>? or I must duplicate the stone <g>?
#stone text {
fill: grey;
dominant-baseline: middle;
text-anchor: middle;
font-size: 0.33pt;
}
#pane {
background-color: yellow;
width: 100%;
height: 100%;
}
.stone-white {
fill: #F2F4F4;
}
.stone-black {
fill: #273746;
}
<svg id="pane" viewBox="0 0 22 22" preserveAspectRatio="none">
<defs>
<g id="stone">
<circle cx="0" cy="0" r="0.45" />
<text>333</text>
</g>
</defs>
<use href="#stone" class="stone-white" x="1" y="1"/>
<use href="#stone" class="stone-white" x="2" y="2"/>
<use href="#stone" class="stone-black" x="3" y="2"/>
<use href="#stone" class="stone-black" x="2" y="4"/>
</svg>

SVG - inherit multiple colors/animations

What I try to do:
Using a <use> element to copy an icon, and color the icon in two different colors when a specific class is added to the <use> element.
The Icon:
<symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
id="red5" x="0px" y="0px" viewBox="0 0 48.1 50.8">
<style type="text/css">
.st0{
fill:#D73647;
stroke:#000000;
stroke-miterlimit:10;
}
/* use.active .color-a{
fill: green;
}
use.active .color-b{
fill: blue;
}*/ // Not working...
</style>
<g>
<path class="st0 color-a" d="M2.3,20.2L11.8,20.2C11.8,20.2 12.5,10.9 22.3,11.2C22.3,11.2 28.5,11.1 32.3,16L26.3,22.4L47.5,22.4L47.5,2.7L40.4,9C40.4,9 36.1,0.4 23.6,0.5C23.6,0.5 4.8,-0.2 2.3,20.2z">
</path>
<path class="st0 color-b" d="M45.8,30.6L36.3,30.6C36.3,30.6 35.6,39.9 25.8,39.6C25.8,39.6 19.6,39.7 15.8,34.8L21.8,28.4L0.5,28.4L0.5,48.1L7.7,41.7C7.7,41.7 12,50.3 24.5,50.2C24.5,50.3 43.3,51 45.8,30.6z">
</path>
</g>
</symbol>
The Use Element:
<use id="svg_16"
xlink:href="#red5" transform="matrix(0.6730555893894703,0,0,0.7071457914654147,-239.09557391490307,-165.87702520953462) "
y="269.9999919533732"
x="473.99998587369964"
class="default-state"
fill="black"></use>
When the class of the <use> is changed from "default-state" to "active", I want the colors of the arrows to change (each to its own color).
What I've tried so far:
I understood that for the paths to change their color from the <use> element I have to change their CSS class to this:
.st0{
fill: inherit; // <- changed
stroke: #000000;
stroke-miterlimit: 10;
}
and the color classes to this:
use.active {
fill: green;
}
but then when I set the class of <use> to "active" they both get the same color...
I would like to do the same thing for animations.
What am I missing? How do I achive this?
This is how I would do it: I would create one symbol and I would reuse twice the same path: once as it is and once rotated 180 degs. For the "default" state please remove the active class of the g element.
.st0{
stroke-miterlimit:10;
}
.active .color-a{
fill: green;
}
.active .color-b{
fill: blue;
}
svg{width:90vh;border:1px solid}
<svg viewBox="0 0 140 150" >
<symbol id="a" viewBox="0 0 48.1 50.8">
<path class="st0 color-a" id="k" d="M2.3,20.2L11.8,20.2C11.8,20.2 12.5,10.9 22.3,11.2C22.3,11.2 28.5,11.1 32.3,16L26.3,22.4L47.5,22.4L47.5,2.7L40.4,9C40.4,9 36.1,0.4 23.6,0.5C23.6,0.5 4.8,-0.2 2.3,20.2z">
</path>
</symbol>
<g class="active" id="svg_16" >
<use class="color-a"
xlink:href="#a">
</use>
<use class="color-b" transform="rotate(180 70 75)"
xlink:href="#a"> </use>
</g>
</svg>

SVG - Center text for each path/shape

I'm able to center text for each path/shape explicitly, but I don't want to do the math for each one. I've tried this the code below but it just puts the two texts on top of one another, which would make sense if it's referring to the one <svg> and not each <g> or <path>.
<svg viewBox="0 0 91.742 214.2" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#000" stroke-width="1">
<g>
<text class="room-text" x="50%" y="50%">145</text>
<path class="room" d="m 0.134593,0.134751 2.2679,133.799999 86.179,0.75595 -5.2917,-133.049999 z"/>
</g>
<g>
<text class="room-text" x="50%" y="50%">146</text>
<path class="room" d="m 2.402593,133.94175 0.75595,80.131 88.446,-0.75594 -3.0238,-78.619 z"/>
</g>
</svg>
I've also tried anchor-text and baseline-alignment but an explicit x and y value are still needed.
Yeah. I ended up just doing it through JavaScript.
document.addEventListener("DOMContentLoaded", function(event) {
var svg = document.getElementById("svg");
/***** Get the room box and text box *****/
for (i = 1; i < svg.childNodes[1].childNodes.length; i += 2) {
var room = svg.childNodes[1].childNodes[i].childNodes[3]; // path element
var textbox = svg.childNodes[1].childNodes[i].childNodes[1]; // text element
var new_x = document.createAttribute("x"); // make a new attribute to add to the textbox
new_x.value = room.getBBox().width / 2 + room.getBBox().x - textbox.getBBox().width / 2; // calculate the textbox's new x position
textbox.setAttributeNode(new_x) // assign the textbox the new x value
}
});
body {
box-sizing: border-box;
}
.main {
width: 100%;
}
svg {
display: block;
margin: 0 auto;
width: 400px;
height: 400px;
}
.room {
fill: rgba(220, 220, 220, .4);
}
.room:hover {
fill: rgba(0, 255, 255, 0.4);
}
.room-text {
fill: black;
font-size: 14px;
font-family: "Helvetica";
}
<div id="svg">
<svg viewBox="0 0 181.01 255.02" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#000" stroke-width="1">
<g id="r145">
<text class="room-text" y="40">145</text>
<path class="room" d="m0.13374 1.6456 0.75595 68.792 135.32-2.2679-4.5357-68.036z"/>
</g>
<g>
<text class="room-text" y="130">146</text>
<path class="room" d="m0.88969 70.437 29.482 103.57 150.43-3.7798-44.601-102.05z"/>
</g>
<g>
<text class="room-text" y="220">147</text>
<path class="room" d="m30.372 174 42.333 79.375 96.762 1.5119 11.339-84.667z"/>
</g>
</svg>
</div>

SVG moves out of position when screen size changes or doesn't scale

I've created an SVG and put the width as a percentage because I want it to resize to fit different screen widths, but when I resize the screen, the svg moves up and down and doesn't move left/right to stay in the centre. If I use pixels instead of percentages, it doesn't resize with the screen.
Preview didn't work on here so here's the codepen link
.
HTML
<svg height="100%" width="100%" id="main">
<circle class="graph line line-1" cx="50%" cy="50%" r="25%" stroke-width="5%" stroke="#f1c40f" fill="none" />
<circle class="graph line line-2" cx="50%" cy="50%" r="20%" stroke-width="5%" stroke="#e67e22" fill="none" />
<circle class="graph line line-3" cx="50%" cy="50%" r="15%" stroke-width="5%" stroke="#00c0df" fill="none" />
</svg>
CSS
#main {
padding: 100px 0;
margin-top: 100px;
height: 200px;
background-color: pink;
}
.graph {
transform: rotate(270deg);
}
.graph.line {
transform-origin: center;
stroke-dasharray: 160%;
animation: graph 1.5s ease-in-out infinite alternate;
}
#keyframes graph {
from {
stroke-dashoffset: 160%;
}
to {
stroke-dashoffset: 90%;
}
}
That's what viewBox is for. With a viewBox, you establish a local coordinate system, which scales with your image. In your svg you simply use your local coordinates, and the image scales to any size...
#main {
position:absolute;
top:0px;left:0px;
right:0px;bottom:0px;
background:pink
}
.graph {
transform: rotate(270deg);
}
.graph.line {
transform-origin: center;
stroke-dasharray: 160%;
animation: graph 1.5s ease-in-out infinite alternate;
}
#keyframes graph {
from {
stroke-dashoffset: 160%;
}
to {
stroke-dashoffset: 90%;
}
}
<svg viewBox="0 0 100 100" id="main">
<circle class="graph line line-1" cx="50" cy="50" r="25" stroke-width="5" stroke="#f1c40f" fill="none" />
<circle class="graph line line-2" cx="50" cy="50" r="20" stroke-width="5" stroke="#e67e22" fill="none" />
<circle class="graph line line-3" cx="50" cy="50" r="15" stroke-width="5" stroke="#00c0df" fill="none" />
</svg>

How to set different colors in different parts of stroke in html SVG

How can I achieve something like this using SVG?
You would need two different circle elements, one for the underlying gray color and the other for the blue stroke, then apply a stroke-dasharray and stroke-dashoffset to the blue stroke.
.track,
.filled {
stroke-width: 10;
fill: none;
}
.track {
stroke: #eee;
}
.filled {
stroke: blue;
stroke-dashoffset: 110;
stroke-dasharray: 440;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 190 190">
<circle class="track" cx="80" cy="80" r="70" />
<circle class="filled" cx="80" cy="80" r="70" />
</svg>

Resources