Unable to get true white, true balck in stroke - svg

I'm trying to implement a "marching ants" style animated selection box using svg. The scheme of animating the border's dash pattern seems to work great, except for some reason I can't get true black/true white for the colors.
(Using ff 68.0.2 64-bit, in case that matters)
<svg height="110" width="200">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> <!-- for sample overlay -->
<g fill="none" stroke="#000000" stroke-width="1">
<path id="solid" stroke-dasharray="" d="M5 40 l215 0" />
</g>
<g fill="none" stroke="#ffffff" stroke-width="1">
<path stroke-dasharray="4,8,4,0" d="M5 40 l215 0" />
</g>
<rect x="1" y="1" width="100" height="100" style="fill:rgba(0,0,0,0);stroke-width:1;stroke:rgb(0,0,0)"/>
<rect x="1" y="1" id="ants" width="100" height="100" stroke-dasharray="4,8,4,0" style="fill:rgba(0,0,0,0);stroke-width:1;stroke:#ffffff"/>
Sorry, your browser does not support inline SVG.
</svg>
JsFiddle

After fiddling with this some more I discovered that when increasing the stroke width the colors get closer to desired.
Turns out anti-aliasing is being stupid. If I turn on shape-rendering="crispEdges" then the colors work as expected.
Unfortunately it also leaves the jaggies, which is, of course, why anti-alising exists.
If this is "the solution", I guess I'll settle for it, but if somebody knows how to make anti-aliasing clean up the line edges without dulling the colors so badly, that would be ideal.
UPDATE: I'm going to go ahead and accept this. Once animated, it isn't all that bad.
#keyframes marchingAnts {
0% { stroke-dashoffset: 0 }
100% { stroke-dashoffset: 50 }
}
.ants, .antsBackground {
stroke-width: 1;
fill: none;
shape-rendering: crispEdges;
}
.ants {
stroke: #ffffff;
animation: marchingAnts 2400ms linear infinite;
stroke-dasharray: 5,5,0,0;
}
.antsBackground {
stroke: #000000;
}
Here's a JsFiddle of that with css animation, and for comparison, the 2-pixel width solution from the comments on the OP as well.

Related

SVG circle move(animateMotion) under the path

I have to write a code that circles should go under some paths with below SVG
<g>
<g>
<path class="st0" d="M718.54,66.06L294.41,490.19c-48.89,48.89-128.09,48.95-176.91,0.13c-48.82-48.82-48.76-128.02,0.13-176.91
s128.09-48.95,176.91-0.13"/>
</g>
<g>
<path class="st0" d="M294.28,313.55l424.13,424.13c48.89,48.89,128.09,48.95,176.91,0.13c48.82-48.82,48.76-128.02-0.13-176.91
c-48.89-48.89-128.09-48.95-176.91-0.13"/>
</g>
</g>
<circle r="20" fill="blue">
<animateMotion dur="5s" repeatCount="indefinite"
path="M718.54,66.06L294.41,490.19c-48.89,48.89-128.09,48.95-176.91,0.13c-48.82-48.82-48.76-128.02,0.13-176.91
s128.09-48.95,176.91-0.13 M294.28,313.55l424.13,424.13c48.89,48.89,128.09,48.95,176.91,0.13c48.82-48.82,48.76-128.02-0.13-176.91
c-48.89-48.89-128.09-48.95-176.91-0.13" />
https://codepen.io/lzwdct/pen/poRYVXZ
Imagine the paths are like driveway, and the circle passes under the path(like bridge) it should not appear under the bridge.
Is there any way to implement it?
The way SVG mask works is a bit strange. The element it's applied to will only be rendered where the mask is white and where the mask is black (or just not white) it will be hidden. Another strange effect of SVG masks is that if you are animating an element and apply a mask to the element being animated then the mask will move with the element.
To account for the first part is simple, just add a white rect the size of the SVG itself inside the mask and use smaller black shapes to mask. The way to work around the moving mask is to apply the mask not to the element being animated but to a <g> tag that wraps the element(s) being animated.
If you want the circles to go 'under' a section and then 'over' that same section however, then you'll need to do some animating inside the mask as well. In this example I'm using animateTransform inside the mask's rect child (the black part that does the masking) to shrink it after the circles pass 'under' the bridge, you could just as easily use CSS keyframes though.
I suggest strongly that you also cut down the viewbox since your visual elements are so small compared to the available space, in the example I just estimated but the best way is to re-render your graphics in Illustrator and crop the artboard better to your objects.
Also most of the additional markup produced by Illustrator is not needed if the SVG will be inline in HTML. You can lose pretty much everything except the viewBox as shown in my example since those other attributes are mostly only used when the SVG is rendered as an image, hope this helps.
svg {
max-width: 500px;
}
.st0,
.st1 {
fill: none;
stroke: #8ea5ae;
stroke-width: 50;
stroke-miterlimit: 10;
}
.st1 {
stroke-linecap: round
}
.st2 {
fill: none;
stroke: #758992;
stroke-width: 50;
stroke-miterlimit: 10;
}
<svg viewBox="0 0 1015 855">
<mask id="myMask">
<!-- Pixels under white are rendered -->
<rect x="0" y="0" width="1015" height="855" fill="white" />
<!-- Pixels under black are hidden -->
<rect class="moveme" x="315" y="335" height="150" width="150" transform="rotate(45 395 395)">
<animateTransform attributeName="transform"
attributeType="XML"
type="scale"
keyTimes="0; 0.25999; 0.26; 1"
values="1; 1; 0; 0"
dur="5s"
additive="sum"
repeatCount="indefinite"/>
</rect>
</mask>
<path class="st0" d="M718.54,66.06L294.41,490.19c-48.89,48.89-128.09,48.95-176.91,0.13c-48.82-48.82-48.76-128.02,0.13-176.91
s128.09-48.95,176.91-0.13" />
<path class="st1" d="M683.19,30.7L258.92,454.97c-29.29,29.29-76.78,29.29-106.07,0c-29.29-29.29-29.29-76.78,0-106.07
c29.29-29.29,76.78-29.29,106.07,0" />
<path class="st2" d="M753.9,101.42c0,0-424.26,424.26-424.26,424.26c-68.34,68.34-179.15,68.34-247.49,0s-68.34-179.15,0-247.49
s179.15-68.34,247.49,0" />
<path class="st0" d="M294.28,313.55l424.13,424.13c48.89,48.89,128.09,48.95,176.91,0.13c48.82-48.82,48.76-128.02-0.13-176.91 c-48.89-48.89-128.09-48.95-176.91-0.13" />
<path class="st2" d="M329.63,278.19L753.9,702.46c29.29,29.29,76.78,29.29,106.07,0c29.29-29.29,29.29-76.78,0-106.07 s-76.78-29.29-106.07,0" />
<path class="st1" d="M258.92,348.9c0,0,424.26,424.26,424.26,424.26c68.34,68.34,179.15,68.34,247.49,0s68.34-179.15,0-247.49 s-179.15-68.34-247.49,0" />
<!-- Group the circles and apply the mask to the group, not the circles -->
<g mask="url(#myMask)">
<circle r="20" fill="blue">
<animateMotion dur="5s" repeatCount="indefinite" path="M718.54,66.06L294.41,490.19c-48.89,48.89-128.09,48.95-176.91,0.13c-48.82-48.82-48.76-128.02,0.13-176.91
s128.09-48.95,176.91-0.13 M294.28,313.55l424.13,424.13c48.89,48.89,128.09,48.95,176.91,0.13c48.82-48.82,48.76-128.02-0.13-176.91
c-48.89-48.89-128.09-48.95-176.91-0.13" />
</circle>
<circle r="20" fill="blue">
<animateMotion dur="5s" repeatCount="indefinite" path="M753.9,101.42c0,0-424.26,424.26-424.26,424.26c-68.34,68.34-179.15,68.34-247.49,0s-68.34-179.15,0-247.49
s179.15-68.34,247.49,0 M329.63,278.19L753.9,702.46c29.29,29.29,76.78,29.29,106.07,0c29.29-29.29,29.29-76.78,0-106.07
s-76.78-29.29-106.07,0" />
</circle>
<circle r="20" fill="blue">
<animateMotion dur="5s" repeatCount="indefinite" path="M683.19,30.7L258.92,454.97c-29.29,29.29-76.78,29.29-106.07,0c-29.29-29.29-29.29-76.78,0-106.07
c29.29-29.29,76.78-29.29,106.07,0 M258.92,348.9c0,0,424.26,424.26,424.26,424.26c68.34,68.34,179.15,68.34,247.49,0s68.34-179.15,0-247.49
s-179.15-68.34-247.49,0" />
</circle>
</g>
<!-- uncomment the rect below to visualize the animation applied to the mask -->
<!-- <rect x="315" y="335" height="150" width="150" fill="#f00" opacity=".1" transform="rotate(45 395 395)">
<animateTransform attributeName="transform"
attributeType="XML"
type="scale"
keyTimes="0; 0.25999; 0.26; 1"
values="1; 1; 0; 0"
dur="5s"
additive="sum"
repeatCount="indefinite"/>
</rect>-->
</svg>

SVG Use -- Unable to repostion polygon after rotation

I am trying to create a 16 point star inside a circle using SVG and pure CSS -- no JS!
My strategy is to create 16 equilateral triangles (via Defs and Use, to keep it DRY), rotating each Use iteration by 22.5 degrees.
My problem is that when I apply the rotate() transform to the second triangle, SVG changes the center point of the triangle -- which CSS3 does not (it rotates around a fixed axis).
I have tried adding x and y parameters, adding a class and doing a translate() transform, doing that inline... nothing works -- I just cant figure out how to move the triangle back into position (with a rotation) inside the circle (centered at 150, 150 I reckon).
Any help would be appreciated. Here is the SVG line of code that I am having trouble with.
<use xlink:href="#triangle" style="transform: rotate(22.5deg);" />
You can see it in action here.
<style > .toile {
display: flex;
flex-direction: column;
max-width: 400px;
max-height: 800px;
justify-content: center;
align-items: center;
/* centers outer containing element (the circle) horizontally & vertically */
border: 5px #009000;
/* green */
border-style: groove;
background-color: #f9e4b7;
margin: 0 auto;
/* centers surface on a page */
}
<div class="toile">
<svg>
<defs>
<pattern id="grid" width="15" height="15" patternUnits="userSpaceOnUse">
<rect fill="white" x="0" y="0" width="14" height="14"/>
<rect fill="#009000" x="14" y="0" width="1" height="14"/>
<rect fill="#009000" x="0" y="14" width="14" height="5"/>
</pattern>
<g id="triangle">
<svg>
<polygon points="150,18 200,100 100,100"
style="stroke:#009000;stroke-width:1; fill:#afeeee; opacity:.7" />
</svg>
</g>
</defs>
<rect fill="url(#grid)" x="0" y="0" width="100%" height="100%" />
<svg viewBox="0 100 400 400" stroke="#009000" stroke-width=".5" width="300" height="300" class="cercle">
<circle cx="50%" cy="50%" r="75" fill="transparent" /> </svg>
<svg viewBox="0 100 400 400" stroke="#ce2029" stroke-width=".5" width="300" height="300">
<circle cx="50%" cy="50%" r="2" fill="#ce2029" /> </svg>
<use xlink:href="#triangle" />
<use xlink:href="#triangle" style="transform: rotate(22.5deg);" />
</svg>
</div>
Thank you for any solution to this problem; I just can't figure it out! Please no JS solutions!
UPDATE:
I've changed the 16-point gon to a 15 point one, as for some reason a series of 22.5 degree rotations create an unbalanced hexadecagon. I got rid of the red circle center point, and the background grid, and added SVG animation. Here is the (final) working example.
Sorry about the CodePen but I am trying to figure out how to make snippets work for an entire HTML/CSS/SVG program.
This is one way of doing it:
First I simplified your code. Unless you have a good reason to do it like this, it's always better to keep things simple.
I calculated the points tor the triangle around the center of the svg canvas:
<polygon id="triangle" points="200,125 264.95,237.5 135.05,237.5"
I rotate the triangle using svg transforms: transform="rotate(22.5,200,200)"
The first value is the rotation in degs and next you have the x and y of the rotation center.
As it comes out with SVG transforms you don't have IE issues. Please read this article about Transforms on SVG Elements
.toile {
display: flex;
flex-direction: column;
max-width: 400px;
max-height: 800px;
justify-content: center;
align-items: center;
/* centers outer containing element (the circle) horizontally & vertically */
border: 5px #009000;
/* green */
border-style: groove;
background-color: #f9e4b7;
margin: 0 auto;
/* centers surface on a page */
}
<div class="toile">
<svg viewBox="0 0 400 400" stroke="#009000" stroke-width=".5" width="300" height="300" >
<defs>
<pattern id="grid" width="15" height="15" patternUnits="userSpaceOnUse">
<rect fill="white" x="0" y="0" width="14" height="14"/>
<rect fill="#009000" x="14" y="0" width="1" height="14"/>
<rect fill="#009000" x="0" y="14" width="14" height="5"/>
</pattern>
<polygon id="triangle" points="200,125 264.95,237.5 135.05,237.5"
style="stroke:#009000;stroke-width:1; fill:#afeeee; opacity:.7" />
</defs>
<rect fill="url(#grid)" x="0" y="0" width="100%" height="100%" />
<circle class="cercle" cx="50%" cy="50%" r="75" fill="transparent" />
<circle cx="50%" cy="50%" r="2" fill="#ce2029" />
<use xlink:href="#triangle" />
<use xlink:href="#triangle" transform="rotate(22.5,200,200)" />
</svg>
</div>
UPDATE
To calculate the points for the triangle you may use javascript. In the case of a regular polygon like a triangle all 3 vertices are on a circumscribed circle at a 2*Math.PI/3 angle one from each other. I'm starting with an offset of -Math.PI/2 (-90 degs) for the first vertex.
// the center of the SVG canvas calculated from the values of the viewBox attribute. Alternatively you can choose a different point
let c = {x:200,y:200}
let radius = 75;
let points = [];
for(let a = -Math.PI/2; a < 3*Math.PI/2; a+= 2*Math.PI/3){
let x = c.x + radius*Math.cos(a);
let y = c.y + radius*Math.sin(a);
points.push(x);
points.push(y);
}
tri.setAttributeNS(null, "points", points.join());
svg{border:1px solid;height:90vh}
<svg viewBox="0 0 400 400">
<polygon id="tri" />
</svg>

How to animate an SVG circle around an ellipse

This may be a duplicate of a similar question asked by Ruby several years ago, but following the suggestions posted has not resulted in a solution for me. Of course it could be me that is the problem.
I am trying to generate cycloid curves (circles rotating around other curves) BUT I would like to create the curve of a circle rotating around an ellipse - not a circle.
I can animate a circle to follow an elliptical path.
I can animate a circle to rotate about its center.
I need to do both animations simultaneously, but my object follows a path somewhere else in my viewbox.
html, body, svg {
width: 100%;
height: 100%;
}
<svg viewBox="0 0 700 700">
<path id="OUT" d="M200,250
a220,110 0 1,0 600,0
a220,110 0 1,0 -600,0"
style="fill:none;stroke:#ccc; stroke-width:2" />
<g id="CC">
<circle r=40 cx=200 cy=250 fill="none" stroke="black" stroke- width="2"/>
<g id="C1">
<circle r=5 cx=200 cy=250 fill="green"/>
</g>
<circle cx="240" cy="250" r="3" fill="blue" />
</g>
<animateTransForm
xlink:href="#CC"
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 200 250" to="360 200 250" begin="1s" dur="10s"
additive="sum" />
<animateTransform
xlink:href="#CC"
attributeName="transform"
attributeType="XML"
type="rotate"
mpath xlink:href="#OUT"
from="0 300 250" to="360 300 250"
begin="1s" dur="10s" fill="freeze"
additive="sum"/>
</svg>
Hopefully this will give someone an idea of my effort, and trigger a solution. Many thanks.
www.softouch.on.ca
you just need to use animateMotion to apply line animation on any
shape just set so animation can know in which line it has to walk
because of transform translate issue i manually set transform
translate, it will work without setting transform translate in
circle
i used css key frame animation to rotate small circle and both
animation not working at a time so i added one layer(as <g> tag)
inside main <g> tag
html, body, svg {
width: 100%;
height: 100%;
}
<svg width="500" height="500" viewBox="0 0 1000 1000" >
<def>
<style>
#-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(359deg);
}
}
#extrag{
transform-origin: left;
animation: rotation 5s infinite linear;
transform-origin: 201px 250px;
}
</style>
</def>
<path id="OUT" d="M200,250
a220,110 0 1,0 600,0
a220,110 0 1,0 -600,0"
style="fill:none;stroke:#ccc; stroke-width:2" />
<g id="CC" transform="translate(-190,-245)">
<g id="extrag">
<circle r=40 cx=200 cy=250 fill="none" stroke="black" stroke-width="2"/>
<g id="C1" >
<circle r=5 cx=200 cy=250 fill="green"/>
</g>
<circle cx="240" cy="250" r="3" fill="blue">
</circle>
</g>
<animateMotion
xlink:href="#CC"
attributeName="motion"
attributeType="XML"
additive="sum"
dur="6s"
repeatCount="indefinite">
<mpath xlink:href="#OUT"/>
</animateMotion>
</g>
</svg>

How to set the common background In SVG?

How to set the common background for all svg?
<svg>
<g id="dsfdf">
-----------
</g>
<g id="dsfgfdgdf">
-----------
</g>
</svg>
How to set the common background for G tags. Please any one help
By specifying the fill in the svg element itself, you can always specify another color in the containing elements, like the red circle on the first position in the sample.
<svg fill="green" id="svg1" xmlns="http://www.w3.org/2000/svg" style="width: 3.5in; height: 1in">
<circle id="circle1" r="30" cx="100" cy="34" style="fill: red; stroke: blue; stroke-width: 2"/>
<circle id="circle2" r="30" cx="200" cy="34"/>
<circle id="circle3" r="30" cx="300" cy="34"/>
</svg>

Box shadow animation on SVG element

Is there any option to animate CSS box-shadow effect on SVG element?
I have this markup:
<g id="g-svg_el_obj921" style="top: 300px; left: 550px;">
<circle r="95.12" fill="rgb(50, 149, 196)" class="some_class" id="svg_el_obj921" priority="4" position="300_550" cx="550" cy="300"></circle>
</g>
and this animation setup:
circle {
cursor: pointer;
-webkit-animation: shadow_fly 310ms infinite ease-in-out;
#-webkit-keyframes shadow_fly {
0% {-webkit-svg-shadow: 0 0 7px #53BE12;}
50% {-webkit-svg-shadow: 0 0 30px #53BE12;}
99% {-webkit-svg-shadow: 0 0 7px #53BE12;}
}
&:hover {
}
}
Thx for help.
Yes filters can be animated:
Here is how to create shadow/inset/blur filters on svg
<svg id="obj921">
<filter id="imagenconturbulencias" x="0" y="0" width="100%" height="100%">
<feTurbulence result="cloud" baseFrequency=".01" seed="1" stitchTiles="nostitch" type="fractalNoise" numOctaves="2">
<animate attributeName="baseFrequency" calcMode="paced" begin="0s" dur="12s" values=".01;.13;.01;" repeatCount="indefinite"/>
</feTurbulence>
<feComposite operator="in" in="cloud" in2="SourceGraphic"/></filter>
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<svg>
<use filter="url(#imagenconturbulencias)" xlink:href="#obj921"></use>
</svg>
run this snippet!
animate/> tag goes inside filter/> description tag /look closely
The circle in < use > tag is the animated one, you have to hide the original sprite as smart as you can. That is common task in using sprites - advantage for this approach is, you can reference {use} this sprite in many places over your page, but it's vector values are loaded once (that saves space)
There is not, at least with css-animation, it's only possible for html elements, not svg elements.

Resources