Javascript: get contour of polygon / remove inside lines - javascript

I've a polygon and I want to get the contour of it, it looks like this:
<polygon fill="transparent" points=" -60.48565220947266,46.13742103271485, 56.557547790527344,46.13742103271485, 56.557547790527344,-5.06897780456543, -60.48565220947266,-5.06897780456543, 37.050350115966786,-9.94577780456543, -85.80719033203123,-9.94577780456543, -85.80719033203123,46.13742103271485, 56.34799779052733,46.13742103271485, 56.34799779052733,19.315022195434572, 37.050350115966786,19.315022195434572, -74.9509506591797,-5.06897780456543, -74.9509506591797,46.13742103271485, 56.347997790527344,46.13742103271485, 56.347997790527344,19.315022195434572, 37.0503501159668,19.315022195434572, 37.0503501159668,-9.94577780456543, -30.333590332031253,-9.94577780456543, -30.333590332031253,-5.06897780456543, 37.0503501159668,-5.06897780456543" style="stroke: black; stroke-width: 1px;" stroke-dasharray="5, 5" id="#contour"></polygon>
<svg>
<g transform="translate(100,100)">
<polygon fill="transparent" points=" -60.48565220947266,46.13742103271485, 56.557547790527344,46.13742103271485, 56.557547790527344,-5.06897780456543, -60.48565220947266,-5.06897780456543, 37.050350115966786,-9.94577780456543, -85.80719033203123,-9.94577780456543, -85.80719033203123,46.13742103271485, 56.34799779052733,46.13742103271485, 56.34799779052733,19.315022195434572, 37.050350115966786,19.315022195434572, -74.9509506591797,-5.06897780456543, -74.9509506591797,46.13742103271485, 56.347997790527344,46.13742103271485, 56.347997790527344,19.315022195434572, 37.0503501159668,19.315022195434572, 37.0503501159668,-9.94577780456543, -30.333590332031253,-9.94577780456543, -30.333590332031253,-5.06897780456543, 37.0503501159668,-5.06897780456543" style="stroke: black; stroke-width: 1px;" stroke-dasharray="5, 5" id="#contour"></polygon>
</g>
</svg>
I want to remove everything that is inside of the polygon and keep only the border, my math skills are low and I'm having trouble making it to work.
How can I achive this?

Related

SVG in HTML: How to use a multicolored SVG as a mask

I know how to use SVG masks to completely "cut out" the mask in another shape, if the mask is monochrome.
How can I use a multicolored SVG definition X as the mask so that the outer shape of X defines the "hole" to be cut out?
Here are three images that illustrate what I am trying to achieve:
svg #1 to be used as mask
svg #2 on which the outer shape of #1 should be used as a cut-out
result
Creating a white-filled version of the shape as #enxaneta proposed is not applicable to my problem, as I have many "complicated" external SVG definitions, and I don't want to change every single one of them.
Is there another, simpler way to achieve what I want?
You need to define your paths with no fill. Then you use your paths for the mask and fill them with white. To draw the image you fill those paths with the colors of your choice.
svg{border:1px solid; width:49vw}
svg:nth-child(2){background:red;}
mask use{fill:white;}
<svg viewBox="0 0 100 50">
<defs>
<polygon id="a" points="30,5 70,20 75,40 20,20" />
<circle id="b" cx="50" cy="25" r="15" />
<circle id="c" cx="60" cy="35" r="10" />
<mask id="m">
<use xlink:href="#a"/>
<use xlink:href="#b"/>
<use xlink:href="#c"/>
</mask>
</defs>
<g id="complexShape">
<use xlink:href="#a" fill="lightblue" />
<use xlink:href="#b" fill="gold"/>
<use xlink:href="#c" fill="red"/>
</g>
</svg>
<svg viewBox="0 0 100 50">
<rect width="100" height="50" style="mask: url(#m)" />
</svg>
The colour of a mask determines the final opacity of the masked object at that point. The R, G, B, and A components of the mask colour are combined in a formula to determine a luminance value that is used to set the final transparency that the mask will be a that point. So, for example, if the mask is red, the final masked result will be semi transparent.
There is no way to make a coloured object be a solid (not translucent) mask. Only full white will do that.
Update
Assuming you have an external SVG image that looks like the following:
<svg viewBox="0 0 100 50">
<polygon id="a" points="30,5 70,20 75,40 20,20" fill="lightblue"/>
<circle id="b" cx="50" cy="25" r="15" fill="gold"/>
<circle id="c" cx="60" cy="35" r="10" fill="red" stroke="blue" stroke-width="4"/>
</svg>
You can turn this into a "mask" version by adding three lines to the start of your SVG.
<svg viewBox="0 0 100 50">
<filter id="blacken"><feFlood flood-color="black"/><feComposite operator="in" in2="SourceGraphic"/></filter>
<style>svg :not(#maskbg) { filter: url(#blacken); }</style>
<rect id="maskbg" x="-100%" y="-100%" width="300%" height="300%" fill="white"/>
<polygon id="a" points="30,5 70,20 75,40 20,20" fill="lightblue"/>
<circle id="b" cx="50" cy="25" r="15" fill="gold"/>
<circle id="c" cx="60" cy="35" r="10" fill="red" stroke="blue" stroke-width="4"/>
</svg>
This is something that could easily be scripted. This method should work for almost all SVGs.
Once you have all the mask variants built, you can apply them using mask-image.
https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image

Hover events for a dashed line in an SVG

An SVG with a line (or path) which uses stroke-dasharray only seems to trigger CSS and JS hover events when the user hovers over the solid parts of the dashed line: https://codepen.io/anon/pen/YeXoZy
Is there a simple way to make both the JS and CSS events trigger when the solid or invisible parts of the line are hovered?
My current plan is to draw a second, invisible line following the same path and use it to detect mouse events. https://codepen.io/anon/pen/BYNgRR This seems heavy handed and I'm hoping there's a cleaner way I'm missing.
I'm not sure how to do it without the second "detector" line, but a less heavy handed way is at least possible without the JS.
Switch the order of the lines, then you can use the hover selector as usual for the dashed line, then use + in a selector for the detector line to change the properties of the line immediately following it:
https://codepen.io/RyanGoree/pen/LQVKBV
This can be solved somewhat by using a rect instead of line and using SVG transforms with patterns.
An example can be seen at this CodePen.
It essentially bubbles down to:
<svg height="210" width="500">
<defs>
<pattern id="pattern1"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="green" stroke-width="12px" y2="10"/>
</pattern>
<pattern id="pattern2"
width="10" height="10"
patternUnits="userSpaceOnUse"
patternTransform="rotate(0 60 60)">
<line stroke="red" stroke-width="12px" y2="10" stroke="transparent"/>
</pattern>
</defs>
<g transform="rotate(45 60 60)">
<rect x="0" y="0" width="500" height="5"/>
</g>
</svg>
And the following CSS:
rect {
fill: url(#pattern1)
}
rect:hover {
fill: url(#pattern2)
}
This is an old topic I know. But found the answer on Css hover sometimes doesn't work on svg paths
If you want to trigger the event only on stroke/visible, use pointer-events: stroke; or pointer-events: visible; (only the stroke) and pointer-events: all; (on both)
Here is a code example:
<body>
<div id="donut-score" class="svg-item" style="display: block;">
<svg width="100%" height="100%" viewBox="0 0 40 40" class="donut">
<circle class="donut-hole" cx="20" cy="20" r="15.91549430918954" fill="#fff"></circle>
<circle class="donut-ring" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5"></circle>
<circle id="donut-score-part-1" class="donut-segment donut-segment-1" onmousemove="this.style.stroke ='orange';" onmouseout="this.style.stroke = '#ff8197';" cx="20" cy="20" r="15.91549430918954" fill="transparent" stroke-width="3.5" stroke-dasharray="20 80" stroke-dashoffset="25"></circle>
<g class="donut-text-item donut-text-item">
<text y="50%" transform="translate(0, 2)">
<tspan id="donut-score-text" x="50%" text-anchor="middle" class="donut-text">Score </tspan>
<tspan id="donut-score-aantal" x="50%" Y="65%" text-anchor="middle" class="donut-text">0 </tspan>
</text>
</g>
</svg>
</div>
</body>
ccs:
.donut-segment {
stroke: #ff8197;
}
.svg-item {
width:200px;
font-size: 16px;
margin: 0 auto;
}
.donut-text {
font-size: 0.35em;
line-height: 1;
transform: translateY(0.5em);
font-weight: bold;
}
If you add pointer-events: stroke; to the class .donut-segment then it only works on the stroke. If you use non or pointer-events: all it works on both. I tested it in codepen.

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>

Analytics Project SVG Path

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.

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