So I have this svg as the footer and when I check in the developer tools it shows that it is taking up half of the page. I want the svg to only contain in the expected space without taking up extra space in the page since other elements cannot be positioned due to this issue.
<footer className='absolute bottom-0 w-full'>
<svg
className='fill-green'
viewBox='0 0 500 150'
preserveAspectRatio='none'
xmlns='http://www.w3.org/2000/svg'
>
<defs>
<filter id='shadow'>
<feDropShadow
dx='0'
dy='0'
stdDeviation='2'
flood-color='#159F68'
/>
</filter>
<path
id='footer-shadow'
className='stroke-none'
d='M29.86,179.11 C100.86,200.36 200.94,60.48 450.84,180.09 L363.96,855.44 L0.00,190.00 Z'
></path>
</defs>
<g>
<use href='#footer-shadow' filter='url(#shadow)'></use>
<text
className='fill-modern-green text-sm'
x='52%'
y='95%'
dominant-baseline='middle'
text-anchor='middle'
>
All rights reserved.
</text>
</g>
</svg>
</footer>
You can define width and height through the styles attribute for footer and svg. For example:
{/* Height of footer is 30px */}
<footer className='absolute bottom-0 w-full' style={{width: '100%', height: '30px'}}>
{/* SVG Height based on the footer height */}
<svg
style={{width: '100%', height: '100%'}}
className='fill-green'
viewBox='0 0 500 150'
preserveAspectRatio='none'
xmlns='http://www.w3.org/2000/svg'
>
<defs>
<filter id='shadow'>
<feDropShadow
dx='0'
dy='0'
stdDeviation='2'
flood-color='#159F68'
/>
</filter>
<path
id='footer-shadow'
className='stroke-none'
d='M29.86,179.11 C100.86,200.36 200.94,60.48 450.84,180.09 L363.96,855.44 L0.00,190.00 Z'
></path>
</defs>
<g>
<use href='#footer-shadow' filter='url(#shadow)'></use>
<text
className='fill-modern-green text-sm'
x='52%'
y='95%'
dominant-baseline='middle'
text-anchor='middle'
>
All rights reserved.
</text>
</g>
</svg>
</footer>
Related
This is my code in my React app and I find it difficult to make the text appear on the svg, and also want to remove the shadow from the text so that only the shape is having the shadow.
<div className='overflow-hidden'>
<svg
className='fill-green block m-auto'
viewBox='0 0 500 150'
preserveAspectRatio='none'
xmlns='http://www.w3.org/2000/svg'
>
<g filter='url(#shadow)'>
<path
id='footer-shadow'
className='stroke-none'
d='M29.86,179.11 C100.86,200.36 200.94,60.48 450.84,180.09 L363.96,855.44 L0.00,190.00 Z'
></path>
<text
className='fill-modern-green text-sm'
x='50%'
y='100%'
dominant-baseline='middle'
text-anchor='middle'
>
All rights reserved.
</text>
<use xlinkHref='#footer-shadow'></use>
</g>
<filter id='shadow'>
<feDropShadow
dx='0'
dy='0'
stdDeviation='0.8'
flood-color='black'
/>
</filter>
</svg>
</div>
Your stacking order isn't ideal.
The <use> element overlays you text – so swap the order and apply the drop shadow filter to your ` element.
svg{
width:50em;
overflow:visible;
border:1px solid red;
}
<div className='overflow-hidden'>
<svg className='fill-green block m-auto' viewBox='0 0 500 150' preserveAspectRatio='none' xmlns='http://www.w3.org/2000/svg'>
<defs>
<filter id='shadow'>
<feDropShadow dx='0' dy='0' stdDeviation='2' flood-color='black' />
</filter>
<!-- path is only visible if referenced by <use> element -->
<path id='footer-shadow' className='stroke-none' d='M29.86,179.11 C100.86,200.36 200.94,60.48 450.84,180.09 L363.96,855.44 L0.00,190.00 Z'></path>
</defs>
<g >
<use href='#footer-shadow' filter='url(#shadow)'></use>
<!-- The text is now in the foreground -->
<text fill="#fff" className='fill-modern-green text-sm' x='50%' y='100%' dominant-baseline='middle' text-anchor='middle'>
All rights reserved.
</text>
</g>
</svg>
</div>
I also recommend to put your filters inside a <defs> element at the beginning of your svg. Some app frameworks (e.g flutter) struggle with defs placed after the elements these defs (e.g. filters, gradients etc.) are applied to.
So it's just a best practice for better compatibility.
I have the following SVG of dynamically rendered pie chart using react-minimal-pie-chart :-
<svg viewBox="0 0 100 100" width="100%" height="100%"><path d="M 75 50 A 25 25 0 0 1 54.34120444167326 74.6201938253052" fill="none" stroke-width="50" stroke="#8dcd81"><title>Excellent</title></path><path d="M 54.34120444167326 74.6201938253052 A 25 25 0 0 1 26.507684480352285 41.449496416858295" fill="none" stroke-width="50" stroke="#eefa6b"><title>Good</title></path><path d="M 26.507684480352285 41.449496416858295 A 25 25 0 0 1 75 49.99999999999999" fill="none" stroke-width="50" stroke="#FF6382"><title>Weak</title></path><text dominant-baseline="central" x="50" y="50" dx="19.151111077974452" dy="16.06969024216348" text-anchor="middle" style="font-size: 5px;">22 %Excellent</text><text dominant-baseline="central" x="50" y="50" dx="-19.15111107797445" dy="16.069690242163485" text-anchor="middle" style="font-size: 5px;">33 %Good</text><text dominant-baseline="central" x="50" y="50" dx="4.341204441673249" dy="-24.620193825305204" text-anchor="middle" style="font-size: 5px;">44 %Weak</text></svg>
This is my Reactjs code:-
const Element = (props) => {
return (
<text
dominant-baseline="central"
x={props.x}
y={props.y}
dx={props.dx}
dy={props.dy}
text-anchor="middle"
style={{ fontSize: "5px" }}
>
{`${Math.round(props.dataEntry.percentage)} %`}
{props.dataEntry.title}
</text>
);
};
This is codesandbox full Reactjs example:-
https://codesandbox.io/s/throbbing-moon-ejs67?file=/src/App.js
How can i line break between the texts (excellent - good ..) and their percentage .
As Danny says - just stick in a tspan. These settings seem to work ok:
const Element = (props) => {
return (
<text
dominant-baseline="central"
x={props.x}
y={props.y}
dx={props.dx}
dy={props.dy}
text-anchor="middle"
style={{ fontSize: "5px" }}
>
{`${Math.round(props.dataEntry.percentage)} %`}
<tspan dx="-12" dy="5">
{props.dataEntry.title}
</tspan>
</text>
);
};
Here's the code:
<div className="flex flex-wrap -mx-2 mb-8">
{props &&
props.item.map((data, i) => (
<div
key={i}
className="w-full md:w-1/2 lg:w-1/4 px-2 mb-4 flex rounded justify-center items-center p-2 m-1"
>
<h1>abc</h1>
<svg
xmlns="http://www.w3.org/2000/svg"
width="100px"
height="140"
fill={url(`#color-${i}`)}
viewBox="0 0 30 45"
aria-hidden="true"
style={{ transform: `translate(0, -20px)` }}
>
<defs>
<linearGradient id={`color-${i}`} x1="0%" y1="100%" x2="0%" y2="0%">
<stop offset={`${min(7, threshold)}%`} stop-color="rgb(40, 134, 248)" />
<stop offset={`${data.humidity}%`} stop-color="rgb(255, 0, 0)" />
<stop stop-color="rgb(227, 227, 227)" />
</linearGradient>
</defs>
<path stroke="#2886f8" d="M15 6
Q 15 6, 25 18
A 12.8 12.8 0 1 1 5 18
Q 15 6 15 6z" />
</svg>
</div>
))}
</div>
What I'm trying to do here is to fill the linearGradient. but the problem is when I try to do this:
<svg fill={url(#color-${i})}>
it doesn't work. the error is Cannot find name 'url'. the choices to import is the import { url } from 'inspector';.
cause the svg it looks like this.
You should interpolate the string templates correctly.
fill={`url(#color-${i})`}
The url is a reference to another identifier in the SVG, in this case, the linear gradient
and
offset={`${Math.min(7, data.threshold)}%`}
min alone isn't a function, be sure to fully quantify it by calling Math.min
Code
<div className="flex flex-wrap -mx-2 mb-8">
{props.item.map((data, i) => (
<div
key={i}
className="w-full md:w-1/2 lg:w-1/4 px-2 mb-4 flex rounded justify-center items-center p-2 m-1"
>
<h1>abc</h1>
<svg
xmlns="http://www.w3.org/2000/svg"
width="100px"
height="140"
fill={`url(#color-${i})`}
viewBox="0 0 30 45"
aria-hidden="true"
style={{ transform: `translate(0, -20px)` }}
>
<defs>
<linearGradient
id={`color-${i}`}
x1="0%"
y1="100%"
x2="0%"
y2="0%"
>
<stop
offset={`${Math.min(7, data.threshold)}%`}
stop-color="rgb(40, 134, 248)"
/>
<stop
offset={`${data.humidity}%`}
stop-color="rgb(255, 0, 0)"
/>
<stop stop-color="rgb(227, 227, 227)" />
</linearGradient>
</defs>
<path
stroke="#2886f8"
d="M15 6
Q 15 6, 25 18
A 12.8 12.8 0 1 1 5 18
Q 15 6 15 6z"
/>
</svg>
</div>
))}
</div>
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>
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;
}