Multiple setInterval() using array - arrays

I want to animate all three circles using this one script.
But to achieve this, I need to create 3 variables like 'c1' right?
I got the code to work by duplicating everything:
http://jsfiddle.net/JwkYm/339/
It has to be easier then this. Thanks for your help in advance.
(function () {
// math trick 2*pi*57 = 358, must be less than 360 degree
var circleArr = ['orange-halo','orange-halo2','orange-halo3'];
var myTimerArr = ['myTimer','myTimer2','myTimer3'];
var interval = 30;
var angle = [0,0,0];
var angle_increment = 6;
var c1 = setInterval(function () {
var x = 0;
while(x >= 2)
{
document.getElementById(circleArr[x]).setAttribute("stroke-dasharray", angle[x] + ", 20000");
document.getElementById(myTimerArr[x]).innerHTML = parseInt(angle[x]/360*100) + '%';
if (angle[x] >= 270)
{
c1.clearInterval(c1.timer);
}
angle[x] += angle_increment;
x++;
}
}.bind(this), interval);
#myTimer, #myTimer2, #myTimer3 {
fill: #000099;
font-size: 40px;
font-family: Myriad light;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" style="width:300; height:300; top:0; left:0;">
<circle cx="100" cy="100" r="73" id="blue-halo" fill="none" stroke="#000099" stroke-width="30" />
<circle cx="100" cy="100" r="73" id="orange-halo" fill="none" stroke="#FD6400" stroke-width="31" stroke-dasharray="0,20000" transform="rotate(-90,100,100)" />
<text id="myTimer" text-anchor="middle" x="100" y="110">0%</text>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" style="width:300; height:300; top:0; left:0;">
<circle cx="100" cy="100" r="73" id="blue-halo2" fill="none" stroke="#000099" stroke-width="30" />
<circle cx="100" cy="100" r="73" id="orange-halo2" fill="none" stroke="#FD6400" stroke-width="31" stroke-dasharray="0,20000" transform="rotate(-90,100,100)" />
<text id="myTimer2" text-anchor="middle" x="100" y="110">0%</text>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" style="width:300; height:300; top:0; left:0;">
<circle cx="100" cy="100" r="73" id="blue-halo2" fill="none" stroke="#000099" stroke-width="30" />
<circle cx="100" cy="100" r="73" id="orange-halo2" fill="none" stroke="#FD6400" stroke-width="31" stroke-dasharray="0,20000" transform="rotate(-90,100,100)" />
<text id="myTimer3" text-anchor="middle" x="100" y="110">0%</text>
</svg>
http://jsfiddle.net/JwkYm/341/

Related

How to add images to svg to map each pie in the circle

How can I add an image to the path in my SVG and also rotate the text inside the path and make it closer to the edges of the path?
I am currently using the following code in my React application to create a roulette wheel with multiple sections. Each section is represented by a path that is filled with a specific color. I would like to add an image inside each path and also rotate the text inside the path and make it closer to the edges of the path.
const RouletteWheel = () => {
const items = ["item1", "item2", "item3", "item4"];
const colors = ["blue", "red", "green", "yellow", "brown", "purple"];
const numItems = items.length;
const angle = items.length === 1 ? 0 : 360 / numItems;
return (
<svg viewBox="0 0 100 100" className="svg-wheel">
{items.length > 1 ? (
items.map((item, index) => {
const x1 = 50 + 45 * Math.cos(angle * index * (Math.PI / 180));
const y1 = 50 + 45 * Math.sin(angle * index * (Math.PI / 180));
const x2 = 50 + 45 * Math.cos(angle * (index + 1) * (Math.PI / 180));
const y2 = 50 + 45 * Math.sin(angle * (index + 1) * (Math.PI / 180));
return (
<React.Fragment>
<defs>
<path
id="text-path"
d={`M 50 50 L ${x1} ${y1} A 45 45 0 0 1 ${x2} ${y2} Z`}
/>
</defs>
<path
key={`path-${index}`}
id={`path-${index}`}
d={`M 50 50 L ${x1} ${y1} A 45 45 0 0 1 ${x2} ${y2} Z`}
fill={`${colors[index]}`}
></path>
<text
x={20}
dy={25}
fill="white"
textAnchor="middle"
fontSize={4}
>
<textPath transform={`rotate(100)`} xlinkHref={`#path-${index}`}>{item}</textPath>
</text>
</React.Fragment>
);
})
) : (
<circle key={"circle"} cx="50" cy="50" r="45" fill="url(#pattern1)" />
)}
</svg>
);
};
ReactDOM.render(
RouletteWheel(),
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container"></div>
The following examples in plain SVG. In the first example I just implemented a solid color using the stroke of a circle (#c1).
In the second example I replaced the solid colors with images. Here the circle (#c1) acts as mask for the image. The tricky part is to place the image in the right angle together with the mask. In general all the rotations are calculated from a circle (360) split in 5 items. So 72 degrees each.
In both examples the text is placed along a circle (#c2) using a textpath element and the attribute startOffset. The dominant-baseline of the text is "hanging" -- so the text is place "under" the circle/arc. The placement of the text can be adjusted with the radius of circle (#c2).
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="300">
<defs>
<circle id="c1" r="23" fill="none" stroke-width="46"
stroke-dasharray="72 360" pathLength="360" />
<circle id="c2" r="45" fill="none" pathLength="360" />
</defs>
<g transform="translate(50 50)">
<use href="#c1" stroke="blue" transform="rotate(0)" />
<use href="#c1" stroke="red" transform="rotate(72)" />
<use href="#c1" stroke="green" transform="rotate(144)" />
<use href="#c1" stroke="yellow" transform="rotate(216)" />
<use href="#c1" stroke="brown" transform="rotate(288)" />
<text font-size="6" fill="white" text-anchor="middle"
dominant-baseline="hanging">
<textPath href="#c2" startOffset="36">item 1</textPath>
<textPath href="#c2" startOffset="108">item 2</textPath>
<textPath href="#c2" startOffset="180">item 3</textPath>
<textPath href="#c2" startOffset="252">item 4</textPath>
<textPath href="#c2" startOffset="324">item 5</textPath>
</text>
</g>
</svg>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" width="300">
<defs>
<mask id="m1">
<circle r="23" fill="none" stroke="white" stroke-width="46"
stroke-dasharray="72 360" pathLength="360" />
</mask>
<circle id="c2" r="45" fill="none" pathLength="360" />
</defs>
<g transform="translate(50 50)">
<g mask="url(#m1)">
<image href="https://via.placeholder.com/300/09f/fff.png" width="60"
x="-30" y="-60" transform="rotate(126)" />
</g>
<g mask="url(#m1)" transform="rotate(72)">
<image href="https://via.placeholder.com/300/080/fff.png" width="60"
x="-30" y="-60" transform="rotate(126)" />
</g>
<g mask="url(#m1)" transform="rotate(144)">
<image href="https://via.placeholder.com/300/800/fff.png" width="60"
x="-30" y="-60" transform="rotate(126)" />
</g>
<g mask="url(#m1)" transform="rotate(216)">
<image href="https://via.placeholder.com/300/f0f/fff.png" width="60"
x="-30" y="-60" transform="rotate(126)" />
</g>
<g mask="url(#m1)" transform="rotate(288)">
<image href="https://via.placeholder.com/300/022/fff.png" width="60"
x="-30" y="-60" transform="rotate(126)" />
</g>
<text font-size="6" fill="white" text-anchor="middle"
dominant-baseline="hanging">
<textPath href="#c2" startOffset="36">item 1</textPath>
<textPath href="#c2" startOffset="108">item 2</textPath>
<textPath href="#c2" startOffset="180">item 3</textPath>
<textPath href="#c2" startOffset="252">item 4</textPath>
<textPath href="#c2" startOffset="324">item 5</textPath>
</text>
</g>
</svg>

can't get the SVG to my react component getting an error

I'm trying to add a SVG file but I'm getting an error tat says:
Compiled with problems:X
ERROR
[eslint]
src/svg/banner.jsx
Line 15:2: Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (15:2)
this is the svg:
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle
cx="50"
cy="50"
r="40"
stroke="blue"
fill="lightblue"
/>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="1921.641"
height="170.5"
viewBox="0 0 1921.641 170.5"
>
<defs>
<linearGradient
id="linear-gradient"
x1="-0.038"
y1="-1.902"
x2="1.1"
y2="2.41"
gradientUnits="objectBoundingBox"
>
<stop offset="0" stop-color="#4040be" />
<stop offset="0.36" stop-color="#4e67eb" />
<stop offset="1" stop-color="#31c3ac" />
</linearGradient>
</defs>
<path
id="Path_30"
data-name="Path 30"
d="M0,0H1921.641V170.5H0Z"
opacity="0.8"
fill="url(#linear-gradient)"
/>
</svg>
I'm trying to import it like this:
import { ReactComponent as Logo } from "../svg/banner.svg";
I've also tried to import it like this:
import banner from "../svg/banner.svg";
but it isn't working... any ideas?
using react and chakra UI
create js file export individual SVG data import file inside {} brace and inside importing an SVG file return SVG looks like
//This is my allsvg.js file
export const calender = <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z" />
</svg>
//This is where i will import svg file
import { calender } = require("./Media/AllSvg");
return (<div>{calender}</div>)
If you want set the SVG as a react component, you should return one element. ( You can use react Fragment for that <> /* ...HTML code */ </>)
export default function Svg() {
return (
<>
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle
cx="50"
cy="50"
r="40"
stroke="blue"
fill="lightblue"
/>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="1921.641"
height="170.5"
viewBox="0 0 1921.641 170.5"
>
<defs>
<linearGradient
id="linear-gradient"
x1="-0.038"
y1="-1.902"
x2="1.1"
y2="2.41"
gradientUnits="objectBoundingBox"
>
<stop offset="0" stop-color="#4040be" />
<stop offset="0.36" stop-color="#4e67eb" />
<stop offset="1" stop-color="#31c3ac" />
</linearGradient>
</defs>
<path
id="Path_30"
data-name="Path 30"
d="M0,0H1921.641V170.5H0Z"
opacity="0.8"
fill="url(#linear-gradient)"
/>
</svg>
</>
)
}
JSX elements must be wrapped in an enclosing tag But Your component it's not wrapped . You can use Fragments to group all your svg tags without adding nodes to the DOM try it like this :
<> // shorter syntax you can use for declaring fragments
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle
cx="50"
cy="50"
r="40"
stroke="blue"
fill="lightblue"
/>
</svg>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="1921.641"
height="170.5"
viewBox="0 0 1921.641 170.5"
>
<defs>
<linearGradient
id="linear-gradient"
x1="-0.038"
y1="-1.902"
x2="1.1"
y2="2.41"
gradientUnits="objectBoundingBox"
>
<stop offset="0" stop-color="#4040be" />
<stop offset="0.36" stop-color="#4e67eb" />
<stop offset="1" stop-color="#31c3ac" />
</linearGradient>
</defs>
<path
id="Path_30"
data-name="Path 30"
d="M0,0H1921.641V170.5H0Z"
opacity="0.8"
fill="url(#linear-gradient)"
/>
</svg>
</>

How to style an SVG using React styled components by passing the SVG as prop?

I have this SVG, imported from figma:
import React from 'react';
function CloseIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_5301_20199)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M19.8539 4.85394C20.0491 4.65868 20.0491 4.3421 19.8539 4.14683C19.6586 3.95157 19.342 3.95157 19.1468 4.14683L12.0007 11.2929L4.85372 4.14634C4.65845 3.95108 4.34187 3.95109 4.14661 4.14636C3.95136 4.34162 3.95136 4.65821 4.14663 4.85346L11.2936 12L4.14688 19.1467C3.95162 19.342 3.95162 19.6586 4.14688 19.8538C4.34214 20.0491 4.65873 20.0491 4.85399 19.8538L12.0007 12.7071L19.1467 19.8529C19.342 20.0481 19.6586 20.0481 19.8539 19.8528C20.0491 19.6576 20.0491 19.341 19.8538 19.1457L12.7078 12L19.8539 4.85394Z"
fill="#00A989"
/>
</g>
<defs>
<clipPath id="clip0_5301_20199">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export default CloseIcon;
The SVG is then imported in my component, rendered correctly on the screen as the original style coming from Figma. But when I do style it with styled components, any style is not applied. What is the problem?
import CloseIcon from '../../../Icons/CloseIcon';
import styled from 'styled-components';
<ClosingIcon
aria-label="Close Modal"
onClick={() => setShowModal((prev) => !prev)}
/>
const ClosingIcon = styled(CloseIcon)`
cursor: pointer;
position: absolute;
top: 14px;
right: 32px;
/* width: 32px;
height: 32px; */
padding: 0;
z-index: 10;
`;
you need to pass classname prop to the child component,
function CloseIcon({ className }) {
return (
<svg
className={className} --> like this
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_5301_20199)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.8539 4.85394C20.0491 4.65868 20.0491 4.3421 19.8539 4.14683C19.6586 3.95157 19.342 3.95157 19.1468 4.14683L12.0007 11.2929L4.85372 4.14634C4.65845 3.95108 4.34187 3.95109 4.14661 4.14636C3.95136 4.34162 3.95136 4.65821 4.14663 4.85346L11.2936 12L4.14688 19.1467C3.95162 19.342 3.95162 19.6586 4.14688 19.8538C4.34214 20.0491 4.65873 20.0491 4.85399 19.8538L12.0007 12.7071L19.1467 19.8529C19.342 20.0481 19.6586 20.0481 19.8539 19.8528C20.0491 19.6576 20.0491 19.341 19.8538 19.1457L12.7078 12L19.8539 4.85394Z"
fill="#00A989"
/>
</g>
<defs>
<clipPath id="clip0_5301_20199">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
</svg>
);
}
reference : https://styled-components.com/docs/advanced#existing-css

SVG stroke not showing inside of clipPath

I have the following Codepen, where I'm trying to animate a stroke of a circle around an image.
So far, I've got a circle SVG which is clipping an image, but it doesn't show the stroke inside of clipPath.
How do I get the border to show?
class App extends React.Component {
render() {
return (
<svg width='48' height='48'>
<defs>
<clipPath id='circleView'>
<circle cx='24' cy='24' r='23' fill='none' stroke='red' strokeWidth='2' />
</clipPath>
</defs>
<image width='48' height='48' xlinkHref={'https://source.unsplash.com/random'} clipPath='url(#circleView)' />
</svg>
)
}
}
As Robert said, the child SVG figures in the clip-path line are not displayed.
Therefore, for the animation you need to add another circle outside the clip-path
<circle cx="25" cy="24" r="14" fill="none" stroke="red" strokeWidth="2" />
.container {
width:25%;
height:25%;
}
<div class="container">
<svg viewBox="0 0 48 48" >
<defs>
<clipPath id='circleView'>
<circle cx='24' cy='22' r='16' fill='none' stroke='red' stroke-width='2' />
</clipPath>
</defs>
<image width="100%" height="100%" xlink:href='https://i.stack.imgur.com/O9eO8.jpg'
clip-path='url(#circleView)' />
<circle cx='24' cy='22' r='16' fill='none' stroke='red' strokeWidth='2' />
</svg>
</div>
To animate a circle, use the change in the stroke-dashoffset attribute from maximum to zero. values="(100.48;0)"
Animation starts after click
.container {
width:25%;
height:25%;
}
<div class="container">
<svg id="svg1" viewBox="0 0 48 48">
<defs>
<clipPath id='circleView'>
<circle cx='24' cy='22' r='16' fill='none' stroke='red' stroke-width='2' />
</clipPath>
</defs>
<image width="100%" height="100%" xlink:href='https://i.stack.imgur.com/O9eO8.jpg' clip-path='url(#circleView)' />
<circle transform="rotate(-90 24 22)" cx="24" cy="22" r="16" fill='none' stroke='red' strokeWidth='2'
stroke-dasharray="100.48" stroke-dashoffset="100.48" >
<animate
attributeName="stroke-dashoffset"
dur="1s"
begin="svg1.click"
values="100.48;0"
fill="freeze"/>
</circle>
</svg>
</div>
Variant of animation with CSS
I added transparency animation to the circle animation.
The animation begins when you hover the mouse cursor.
.container {
width:25%;
height:25%;
}
#crc1 {
fill:skyblue;
stroke-width:1;
stroke:red;
stroke-dasharray:100.48;
stroke-dashoffset:100.48;
fill-opacity:0.9;
}
#crc1:hover {
animation: dash 1.5s ease-out forwards;
}
#keyframes dash {
0% { stroke-dashoffset: 100.48; fill-opacity:0.9; }
50% { fill-opacity:0.45;}
100% { stroke-dashoffset: 0; fill-opacity:0; }
}
#img1 {
clip-path: url(#circleView);
}
<div class="container">
<svg id="svg1" viewBox="0 0 48 48">
<defs>
<clipPath id='circleView'>
<circle cx='24' cy='22' r='16'/>
</clipPath>
</defs>
<image width="100%" height="100%" xlink:href='https://i.stack.imgur.com/O9eO8.jpg'
clip-path='url(#circleView)' />
<circle id="crc1" cx="24" cy="22" r="16" />
</svg>
</div>

How to make SVG element clickable?

Angular 1.6
I want to make the following SVG element clickable:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 30.2 34.1"
style="enable-background:new 0 0 30.2 34.1;" xml:space="preserve">
<rect x="19.4" y="0" width="10.8" height="5.4"/>
<rect x="19.4" y="14.3" width="10.8" height="5.4"/>
<rect x="19.4" y="28.7" width="10.8" height="5.4"/>
<rect x="0.2" y="0" width="10.8" height="5.4"/>
<rect x="0.2" y="14.3" width="10.8" height="5.4"/>
<rect x="0.2" y="28.7" width="10.8" height="5.4"/>
</svg>
If not Angular it works by simply enclosing it like this <svg>...</svg>. But the svg graphics simply dissapears if I do the same in Angular.
Also I tried <use> with no success:
<svg ...>
<use xlink:href="" ng-attr-xlink:href="{{$ctrl.menu.channels}}" />
...
</svg>
How to make my svg element clickable attaching a link to it?
Your first approach was OK, you just need a bit of additional CSS:
<a href="#" class="svg">
<svg version="1.1" id="Layer_1">...</svg>
</a>
And in your css:
a.svg:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}

Resources