Analytics Project SVG Path - javascript

I am not able to figure out how to make path of a circle to go in the middle. I have an example on jsfiddle.
Basically, how do we make this black path go in the middle? This is the path (2nd in svg tag):
[![enter image description here][1]][1]
https://jsfiddle.net/6e1z6xkq/
<div align="center">
<div class="circleDraw">
<svg width="116" height="100">
<g transform="translate(58,58)">
<path d="M-44.430577700900734,37.281681361819274A58,58 0 1,1 44.43057770090073,37.28168136181928L35.23804438347299,29.568230045580812A46,46 0 1,0 -35.238044383472996,29.568230045580805Z" style="fill: rgb(100, 150, 100);">
</path>
<path d="M-90.430577700900734,97.281681361819274A58,58 0 0,1 -96.07604799105425,3.22779870395063L-96.54307254462923,7.939288627271193A46,46 0 0,0 -35.238044383472996,29.568230045580805Z" style="fill: rgb(255, 1, 1);" width="15px" height="20px">
</path>
</svg>
</div>
</div>

You want something like the below (although I would observe that your SVG source is verbose. You can get the same result from a single move and arc drawing command with a green stroke & appropriate stroke width. And there should be no need for a transform - this looks like a drawing tool export.)
<div align="center">
<div class="speedometer--points">
<svg width="116px" height="100px">
<g transform="translate(58,58)">
<path d="M-44.430577700900734,37.281681361819274A58,58 0 1,1 44.43057770090073,37.28168136181928 L35.23804438347299,29.568230045580812 A46,46 0 1,0 -35.238044383472996,29.568230045580805Z" fill="green">
</path>
<path d="M -45 35 l 45 -45" stroke="red" stroke-width="5">
</path>
</g>
</svg>
</div>
</div>

Positioning and animating a line within the svg
It was easiest to go into Illustrator to create a stroke path that matched your arc.
From there it is just a matter of animating the svg with the following css. For any point along the path you can set the stroke-dashoffset from 285 to 515 (for this example.
.speed{
stroke-dasharray: 260px;
stroke-dashoffset: 285;
}
To Animate The stroke with CSS
You can apply a transition of the stroke-dataoffset to the complete path (css-tricks has a good article on this), like so:
svg:hover .speed{
stroke-dashoffset: 515;
transition: 1s ease;
}
Positioning a circle in the middle of your svg
I apologize I misread the question initially. You will want to add a <circle></circle> svg tag with cx, cy, and r attributes. cx and cy are the positioning attributes and r is the radius. In this case cx and cy are set to zero and I've arbitrarily set the radius.
You can read more about basic svg shapes at MDN
Moving the red path to the middle
You can add transform: translate(x,y) to the appropriate path. 'x' and 'y' represent the x and y coordinates of the path. You can also add other attributes like rotate() and skew(). MDN has good explanations of this as well.
Also I noticed in your fiddle that you hadn't closed the <g> tag.
.speed {
stroke-dasharray: 260px;
stroke-dashoffset: 285;
transition: 1s ease;
}
svg:hover .speed {
stroke-dashoffset: 515;
transition: 1s ease;
}
<div align="center">
Hover over the first svg!
<div class="circleClass">
<svg width="116" height="100">
<g transform="translate(58,58)">
<path d="M-44.430577700900734, 37.281681361819274A58, 58 0 1,1 44.43057770090073,37.28168136181928L35.23804438347299,29.568230045580812A46,46 0 1,0 -35.238044383472996,29.568230045580805Z" style="fill: rgb(100, 150, 100);"/>
<path class="speed" d="M40.1,33.5l3.4-4.9c12.6-19,11.4-44.3-3.6-62.1C29.9-45.3,15.4-52,0-52c-12.2,0-24.1,4.3-33.4,12.2
c-20.4,17.1-24.4,46.8-10,68.5c0,0,2.3,4,3.3,5.1" stroke="red" fill="transparent" stroke-width="12"/>
</g>
</svg>
</div>
</div>
<div align="center">
<div class="circleClass">
<svg width="116" height="100">
<g transform="translate(58,58)">
<path d="M-44.430577700900734,37.281681361819274A58,58 0 1,1 44.43057770090073,37.28168136181928L35.23804438347299,29.568230045580812A46,46 0 1,0 -35.238044383472996,29.568230045580805Z" style="fill: rgb(100, 150, 100);">
</path>
<polygon points="2,2.50 0,-2.5 -40,30" style="fill:red;" />
</g>
</svg>
</div>
</div>
<div align="center">
<svg width="116" height="100">
<g transform="translate(58,58)">
<path d="M-44.430577700900734,37.281681361819274A58,58 0 1,1 44.43057770090073,37.28168136181928L35.23804438347299,29.568230045580812A46,46 0 1,0 -35.238044383472996,29.568230045580805Z" style="fill: rgb(100, 150, 100);">
</path>
<circle cx="0" cy="0" r="25"/>
</g>
</svg>
</div>

Your task is complicated a little due to the fact that your green arc is not a simple little path arc that goes from left to right (or vice versa). It is actually a closed shape that defines the outside of the green shape. So it goes from left to right around the outer radius, then a little straight bit to the inner radius, and another arc back to the start.
It is possible to fill a green shape like that, in a meter like way, using a mask or a clipping path. However it is much simpler to just convert your green meter shape to a simple path that goes from left to right in one direction, and has a thick width.
If we do that, your SVG becomes, something like:
<div align="center">
<div class="circleDraw">
<svg width="116" height="100">
<g transform="translate(58,58)">
<! the green path converted to a simple one directional stroke -->
<path d="M -39.8,33.4 A 52,52, 0, 1, 1, 39.8, 33.4"
style="fill: none; stroke-width: 12; stroke: rgb(100, 150, 100);">
</path>
</g>
</svg>
</div>
</div>
Now that we've done that, we can use a really easy method to produce your black meter line.
What we do is make an exact duplicate of the green line (except black this time of course). Then we apply a dash array to the line that makes it on for 50% of the length and off for 50% of the length.
The length of our arc is 236 units. So we set the dash array to:
stroke-dasharray: 118 118
<div align="center">
<div class="circleDraw">
<svg width="116" height="100">
<g transform="translate(58,58)" style="fill: none; stroke-width: 12;">
<! the green path -->
<path d="M -39.8,33.4 A 52,52, 0, 1, 1, 39.8, 33.4"
style="stroke: rgb(100, 150, 100);">
</path>
<!-- the black path -->
<path d="M -39.8,33.4 A 52,52, 0, 1, 1, 39.8, 33.4"
style="stroke: black; stroke-dasharray: 118 118;">
</path>
</g>
</svg>
</div>
</div>
If you need to change the meter to read something other than 50%, then you need to adjust the value of the stroke-dasharray. Just make sure the two values add up to (at least) 236.
This other question shows how to update the meter with Javascript if that's what you ultimately want to do.

Related

I want to make it appear as if text is always the same distance away from circle

My problem is that when i am rotating this svg i counter rotate the text to keep it horizontal. however this makes it look like it is further from the circle when the degree is for example 0 or 180 when its high above or below. but when its 90 its right next to it. i believe this is actually correct since the center of the text is the same distance away. is there a way to fix this?
<svg
height="200"
viewBox="0 0 100 100"
fill="none"
transform="rotate(45, -16, -16)"
>
<circle
cx="30"
cy="30"
r="5"
fill="#FFFFFF"
stroke="#3D3D3D"
stroke-width="1.5"
/>
<g transform="rotate(90, 20, 20)">
<path
d="M15.6528 7.06945L15.4939 7.36025L15.602 7.67352L17.8504 14.1941L2.3372 6.25279L18.9596 1.01652L15.6528 7.06945Z"
fill="white"
stroke="#3D3D3D"
stroke-width="1.5"
/>
</g>
<text
x="30"
y="70"
text-anchor="middle"
font-size="14px"
fill="#3D3D3D"
pointer-events="none"
font-weight={500}
transform="rotate(-45, 30, 70)"
>
some text here
</text>
</svg>
Remember to set your transform-origin, because they help solv this: if you want the text at a fixed distance, put it in a <g> with the circle's center as transform-origin, and a rotation transform, and then give the text element a rotation by the same angle in the opposite direction so that it stays upright.

Click only through holes in svg mask

I have svg mask which determines holes in rectangular. Behind svg mask I have some clickable elements and I would like to pass events to them, but only through holes. I've experimented with pointer-events values, but I can only make either whole mask to pass events or whole mask to capture them. For one hole it can be simply done using clip-path, just determining outer part of the hole, but several holes make things more difficult. Is there any possibility to avoid using clip-path? I also tried pointer-events: visiblePainted and pointer-events: painted, but had no success.
.background {
width: 400px;
height: 400px;
background: red;
cursor: pointer;
}
.svg {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
<button class="background">
</button>
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg" class="svg">
<defs>
<mask id="mask">
<rect
x="0"
y="0"
width="400"
height="400"
fill="white"
/>
<rect
x="20"
y="20"
width="40"
height="40"
fill="black"
/>
<rect
x="290"
y="290"
width="40"
height="40"
fill="black"
/>
</mask>
</defs>
<rect
x="0"
y="0"
width="400"
height="400"
fill="black"
opacity="0.5"
mask="url(#mask)"
pointer-events="auto"
/>
</svg>
There are several aspects to this problem. First, you are right the behavior of masks and clip-paths is different in relation to hit-testing.
A clip path is a geometric boundary, and a given point is clearly either inside or outside that boundary; thus, pointer events must be captured normally over the rendered areas of a clipped element, but must not be captured over the clipped areas... By contrast, a mask is not a binary transition, but a pixel operation, and different behavior for fully transparent and almost-but-not-fully-transparent may be confusingly arbitrary; as a consequence, for elements with a mask applied, pointer events must still be captured even in areas where the mask goes to zero opacity.
Second, a clip-path is a geometric shape, but just like all paths, it might contain holes. Instead of three <rect>s, you can use one <path> with three subpaths, as long as the clip-rule makes sure the subpaths inside get cut out of the surrounding shape.
Third, if the pointer-events property is applied to an <svg> element in a HTML context, its behavior becomes...strange. Any other value than pointer-events: none on the <svg> element lead to the whole bounding box receiving events - a behavior proposed for HTML elements, but currently not part of any spec.
The solution here is to set pointer-events: none on the <svg> element, and then to reverse that with pointer-events: painted on the child <rect> element.
button, svg {
position:absolute;
width:400px;
height:400px
}
button {
background: #0000ff;
cursor: pointer;
}
button:hover {
background: #008800;
}
svg {
pointer-events: none;
}
.over {
fill: #000;
clip-path: url(#clip);
pointer-events: painted;
}
<button></button>
<svg xmlns="http://www.w3.org/2000/svg" height="400" width="400">
<defs>
<clipPath id="clip" clip-rule="evenodd">
<path d="M 20 20 h 360 v 360 h -360 z
M 40 40 v 40 h 40 v -40 z
M 200 290 v 40 h 40 v -40 z" />
</clipPath>
</defs>
<rect y="0" x="0" height="400" width="400" class="over" />
</svg>
Clip masks are useful for cropping parts out of complicated objects, but if you're just working with blocks of solid colour then maybe it would be just as easy to create shapes that already have holes in them.
I've added an example below. Does this help?
<svg width="400" heoght="200" viewBox="0 0 400 200">
<text x="100" y="100" text-anchor="middle"
alignment-baseline="middle" onclick="alert('Hello!')"
style="cursor:pointer">Click me</text>
<text x="300" y="100" text-anchor="middle"
alignment-baseline="middle" onclick="alert('Hello?')"
style="cursor:pointer">Not me</text>
<path d="M20 20 180 20 180 180 20 180ZM60 60 60 140 140
140 140 60Z" fill="#3a6" fill-opacity="0.7"
fill-rule="nonzero"/>
<path d="M220 20 380 20 380 180 220 180Z" fill="#f20"
fill-opacity="0.7"/>
</svg>

Finding point of svg polygon

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

how to draw svg path animation

i have 3 glowing blub and 2 dotted line joining them.i have to pass a light glow(like every dash is glowing one by one) through the lines from one to other blub in a repeating manner.So far i am able to achieve this.
https://jsfiddle.net/hsfxS/3856/..
<div class="mr-glow-1">
<svg width="401" height="332" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line stroke-dasharray="10, 5" x1="0" y1="1" x2="600" y2="600" style="stroke-width: 2px; stroke: rgb(0, 0, 0);"></line>
</svg>
</div>
The dotted line actually comes from a background image. i just have to pass a pink light glow through the dotted lines showing that transition is happening from one to other.How do i achieve this?I am working in angular 4 but can do the animation by pure javascript.
You can use <animate> elements to animate a change of X and Y position
https://codepen.io/danjiro/post/how-to-make-svg-loop-animation
<animate attributeName="cx" from="50" to="250"
dur="5s" repeatCount="indefinite" />
So you can make a glowing circle and animate its changing x and y position with the animate element
There are a number of ways to do what you want. It all depends on how you want the effect to look and how fancy you want to get.
For instance, here is one way. It animates stroke-dashoffset to moves a small dash along a second line so that it appears to follow the first line.
<svg width="401" height="332" version="1.1" xmlns="http://www.w3.org/2000/svg">
<line stroke-dasharray="10, 5" x1="0" y1="1" x2="600" y2="600" style="stroke-width: 2px; stroke: rgb(0, 0, 0);"/>
<line stroke-dasharray="14, 1000" x1="0" y1="1" x2="600" y2="600" style="stroke-width: 8px; stroke: rgba(192, 64, 64, 0.5);">
<animate attributeName="stroke-dashoffset" from="0" to="-848" dur="1s" repeatCount="indefinite" />
</line>
</svg>

Looking to combine CSS fill color and SVG pattern on an SVG element

I'd like to use the awesomeness of CSS to style SVG elements in combination of 2 things: fill color and texture. My textures are created using SVG patterns that have a stroke but no fill. But even though the pattern has no fill it still won't allow a CSS fill color to be visible through the strokes.
http://jsfiddle.net/9MTB6/
A segment from the fiddle:
.texture_diagonal{
fill: url(#texture_diagonal);
}
.cell_default{
fill: #cccccc;
}
.cell_selected{
stroke-width: 2px;
stroke: #FF0000;
}
<pattern id="texture_diagonal" x="0" y="0" width="25%" height="25%" patternUnits="objectBoundingBox">
<path d="M 0 0 l 32 32" style="stroke: black; fill: none;"/>
</pattern>
<rect x="98" y="115"
width="32" height="32"
class="texture_diagonal cell_default cell_selected"
/>
In the fiddle example, I show how I'd like to combine CSS classes so that the third row of rectangles can have both a 'texture' pattern and a fill color. It would be too tedious to define an SVG pattern for each combination (ex: 4 textures X 3 fill colors x 2 selected/unselected = 24 patterns needed!). So my question:
Can I make the pattern behave like a transparent PNG? (so the empty white portion of the pattern allows the fill color to show beneath)?
------- EDIT:
My last idea before I resort to Peter's solution:
<defs>
<pattern id="texture_diagonal" x="0" y="0" width="25%" height="25%" patternUnits="objectBoundingBox">
<path d="M 8 0 l 0 32" style="stroke: black; fill: none;"/>
<path class="myfill" d="M 0 0 l 0 32 l 32 0 l 0 -32 l -32 0"/>
</pattern>
</defs>
<rect x="20" y="20" width="32" height="32"
class="texture_diagonal cell_connected"/>
<rect x="59" y="20" width="32" height="32"
class="texture_diagonal cell_default"/>
Is there any way to use CSS combination of selectors to target the 'myfill' path when it's in different contexts (cell_connected versus cell_default)?
You can't do quite what you want because when you set the fill to the texture you overwrite the original fill. The only way I can see around this is to write two rects on top of each other and only texture the top one.
For example:
<rect x="20" y="115" width="32" height="32"
style="stroke: black;"
class="cell_default" />
<rect x="20" y="115" width="32" height="32"
style="stroke: black;"
class="texture_vertical" />
It's not ideal, but it works.

Categories