Previously, I asked how to obtain the real coordinates (d) of a path when a transformation is applied, finally I decided to investigate the transformation formulas, I have already seen the translation, and now I am seeing the scaling (scale), I managed to do a scaling Basically the formula is:
x’ = x * sx
y’ = y * sy
If I have a path where d attribute (command) of M5, 5 L50, 5 L50, 45 L5, 45 Z, and, If we inspect the path in the DOM, we'll find that it has a width of 135px and a height of 120px:
<svg width="300" height="300" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100" fill="red" />
<path id="element" d="M5, 5 L50, 5 L50, 45 L5, 45 Z" fill="none" stroke="white" />
</svg>
So if I wanted to scale this path using a scale factor of 2, it would be M10, 10 L100, 10 L100, 90 L10, 90, but if we now inspect the path in the DOM, the width is 270px and its height is 240px:
<svg width="300" height="300" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100" height="100" fill="red" />
<path id="element" d="M10, 10 L100, 10 L100, 90 L10, 90 Z" fill="none" stroke="white" />
</svg>
Therefore, the value or scale factor of 2 is equivalent to a width of 135px and a height of 120px, so:
How can I make this scale factor or value equal to 1px?
Is there a conversion formula?
Playing around, I managed to guess that if the scale factor is:
1.1 = 15px -> therefore, the width would be 135px increasing to 150px and the height would be 120px increasing to 135px.
1.01 = 1.5px -> therefore, the width would be 135px increasing to 136.5px and the height would be 120px increasing to 121.5px.
I hope you have understood what I want to do, I hope you can help me.
I think I get what you are saying, but your formulas don't seem to make sense.
1.1 = 15px -> therefore, the width would be 135px increasing to 150px
and the height would be 120px increasing to 135px
That "15px" seems wrong. 1.1 * 135 = 148.5, not 150.
What I think you are asking is how to calculate the scale that would make the width become 150. Is that right?
The scale that will get the width to exactly 150 can be calculated like this:
new_width 150
scale = ----------- = ----- = 1.1111...
old_width 135
So checking that: 135 * 1.1111... = 150.0.
And the new height using this scale would be: 120 * 1.1111... = 133.333...
I am drawing some paths with the same stroke with some significant overlap (dynamically creating and updating a tree). On the overlapping regions, the stroke looks different (darker as well as thicker -see a) as on the non overlapping regions (- see b). The same effect is noticeable with different stroke colors, too.
Here is the code:
path.p2 {
fill: none;
stroke: black;
stroke-width: 1px;
}
<svg height="500" width="400">
<path class="p2" d="M210 10 V 100 H 300 "/>
<path class="p2" d="M210 10 V 120 H 300 "/>
<path class="p2" d="M210 10 V 140 H 300 "/>
<path class="p2" d="M210 10 V 160 H 300 "/>
</svg>
Is there a simple CSS, SVG or javascript fix how to draw these paths (without recalculation of the overlapping regions and creating a new path)?
As I've commented you may add shape-rendering: crispEdges to path.p2
MDN Quote:
crispEdges Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels.
svg {
outline:1px solid;
}
path.p2 {
fill: none;
stroke: black;
stroke-width: 1px;
shape-rendering: crispEdges;
}
<svg height="500" width="400">
<path class="p2" d="M210 10 V 100 H 300 "/>
<path class="p2" d="M210 10 V 120 H 300 "/>
<path class="p2" d="M210 10 V 140 H 300 "/>
<path class="p2" d="M210 10 V 160 H 300 "/>
</svg>
I have an SVG object, a polygon with 3 points. I want to use javascript to rotate the polygon and add text near the point. How can I find the coordinates of the point?
<svg width="165" height="165" style="border: 1px solid black; ">
<path d="M5 0 Q 80 70 160 0" stroke="black" fill="transparent"/>
<path d="M5 165 Q 80 90 160 165" stroke="black" fill="transparent"/>
<polygon points="77.5,20 87.5,20 82.5,75"
style="fill:transparent;stroke:black;stroke-width:1" transform="rotate(90 82.5 20) " />
</svg>
I want to rotate the polygon to somewhere between 0 and -180 degrees from the original 90 position and add a label at the tip so the user knows how far it's been rotated.
To rotate the polygon you can use CSS transform property e.g.
.svg-el {
transform: rotate(90deg);
}
To animate any path or points in the polygon you manipulate it with JS, you can use a library like animejs http://animejs.com/documentation/#motionPath
I am trying to animate a path within an svg.
The path is of a squiggly line to look like a wave. What I am trying to do is have this path translate horizontally on a infinite loop to make it look as though the water is moving.
You can see a similar effect achieved by the outline, only going vertically and this is not within an SVG: https://theoutline.com/
Here is the JsFiddle I have so far with an svg wave/squiggle.
<g class="wave-container">
<path class="wave" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6
c1.6,0,1.6-1.6,3.3-1.6"/>
</g>
https://jsfiddle.net/bje5rxzs/
I am trying to be able to animate this wave horizontally within it's group/container. I know SVG does not support overflow:hidden; within, so how would this be achieved?
Would a mask work? I am open to using a snap.svg if required. I will have other elements within this svg moving, so the squiggle needs to be within the same svg.
Any help much appreciated! Thank you :)
Updated
Like any animation where you are changing the position of something you can use transforms.
The key here is making the squiggly path wider than the svg viewbox, and setting overflow:hidden on svg (which is supported).
Since your illustration is tiny I had to make the svg viewbox tiny as well, only 15px wide, so that the path could overlap the svg container.
<svg version="1.1" x="0px" y="0px" width="15px" height="3.6px" viewBox="0 0 15 3.6">
<path class="white-path animate" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6 c1.6,0,1.6-1.6,3.3-1.6"/>
</svg>
css:
svg {
overflow:hidden;
}
.white-path {
fill:none;
stroke:#FFFFFF;
stroke-width:2;
stroke-linecap:round;
stroke-linejoin:round;
stroke-miterlimit:10;
}
#keyframes squiggle {
from {
transform: translateX(-7px)
}
to {
transform: translateX(0px)
}
}
.animate {
animation: squiggle 1s linear infinite;
}
I used a negative x translation, and through trial and error picked the right distance so the looping was seamless.
Demo:
https://jsfiddle.net/bje5rxzs/6/
you can just nest 2 svg.
var x = -5
setInterval(() => {
wave.setAttribute("transform", `translate(${x},0)`)
if (x >= 0) {
x = -5
} else {
x++
}
}, 100)
<svg viewBox="0 0 300 300" width="200" height="200">
<circle cx="150" cy="150" r="150" fill="red"/>
<svg x="50" y="50" viewBox="1 0 10 3.5" width="100" height="35">
<path id="wave" transform="translate(-5,0)" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6
c1.6,0,1.6-1.6,3.3-1.6" fill="none" stroke="black"/>
</svg>
</svg>
I would like to make an image appear as hexagon.
Therefore I am using svg.
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg"/>
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100"/>
</svg>
Now I want to manipulate the coordinates of this svg depending on position of mouse on screen. So if the mouse-cursor is on right side of screen the first point of hexagon (the upper one) should be at right edge of screen too. Otherwise if the mouse-cursor is on left side of screen the first point of hexagon should be at left edge of screen. The position of this upper point should change dynamically depending on mouse-cursor position.
For testing I tried this one to access the points but it did not work:
<script>
var polygon = document.getElementById("hexagon");
polygon.setAttribute("points", "0,0 100,100 200,200");
</script>
What did I do wrong?
You need to find the center of the svg (I think I have that correct but you might want to verify). Once you have that, you can rotate it to "look at the mouse"
document.addEventListener("mousemove", function(event) {
var follower = document.getElementById("hexagon");
// -----------------------
// calculate the center of the hexagon
// -----------------------
var followerCentroid = (function() {
var followerClientBox = follower.getBoundingClientRect();
return [
(followerClientBox.top + followerClientBox.bottom) / 2,
(followerClientBox.left + followerClientBox.right) / 2
];
})();
// -----------------------
// -----------------------
// rotate to look at mouse
// -----------------------
var lookAngle = Math.atan2(
event.pageX - followerCentroid[1],
-(event.pageY - followerCentroid[0])) * (180 / Math.PI);
follower.style.transform = 'rotate(' + lookAngle + 'deg)';
// -----------------------
});
<div style="padding: 50px;">
<svg id="hexagon">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" width="1" preserveAspectRatio="none" xlink:href="https://pixabay.com/static/uploads/photo/2016/01/14/01/41/image-view-1139204_960_720.jpg" />
</pattern>
</defs>
<polygon fill="url(#pattern1)" points=" 121.25 0 242.5 100 242.5 300 121.25 400 121.25 400 0 300 0 100" />
</svg>
</div>