I am trying to add a fade out effect (that happens after half a second after it has been drawn) to an arch in HTML Canvas.
I am able to draw a circle.
This is my code to draw the arch.
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.arc(Xcoord, Ycoord, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.lineWidth = "4";
ctx.strokeStyle = "#000000";
ctx.stroke();
ctx.closePath();
Is there a way I can extend this to add a fade out effect that starts 0.5 seconds after it has been drawn.
My solution is based on pure JavaScript.
Set an interval.
Set opacity if none.
Reduce opacity until 0.
Clear interval after opacity reaches 0.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0,0,200,100);
setTimeout(function(){
var fadeTarget = document.getElementById("myCanvas");
var fadeEffect = setInterval(function () {
if (!fadeTarget.style.opacity) {
fadeTarget.style.opacity = 1;
}
if (fadeTarget.style.opacity > 0) {
fadeTarget.style.opacity -= 0.02;
} else {
clearInterval(fadeEffect);
}
}, 20);
},0.5);
<canvas id="myCanvas" width="200" height="100"
style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
A great canvas 2d resource is MDN's CanvasRenderingContext2D
This is the second question on the same topic I have answered recently. The following answer on how to fade content on the canvas will explain how to render animated (fading) content.
Timing
The example below using the time passed to the mainLoop function by requestAnimationFrame creates the various time related animated FX. Time is stored in globalTime and used as needed
The animation timing is in the bottom function drawContent and uses the variables animateStart (how long before starting) and animateLen (how long the animation is)
Then from that a value from 0-1 (in animPos) is passed to the function donut.draw and used to animate. donut.draw also uses the globalTime to change the icing color.
var globalTime; // set in mainLoop
var startTime; // undefined means it is reset
var animateStart = 2500; // in ms time till animation starts 2.5 seconds
var animateLen = 10000; // in ms length of animation 10 seconds
function drawContent() {
var animPos = 0; // default anim pos
// check if animation need reset. If so set start time
if (startTime === undefined) { startTime = globalTime + animateStart }
// use the dif between global and start times to get the animation pos
const t = globalTime - startTime;
if (t >= 0 && t < animateLen) {
animPos = t / (animateLen / 2);
animPos = animPos > 1 ? 1- (animPos - 1) : animPos;
} else if(t >= animateLen) { startTime = undefined } // resets animation
donut.draw(Math.easeInOut(animPos));
}
Fading
The fading is performed on the sprinkles using globalAlpha. and there is also some fading on the shadow cast on the donut by the icing. (using globalAlpha and globalCompositeOperation = "source-atop" )
The highlight line on the icing is also faded by using the CSS color format rgba(255,255,255, 0.7) where the last value is the alpha amount (from 0 - 1).
Why the over the top demo?
I am not a fan of SVG and as Vivek Raju's SVG example is so pretty it may sway people away from the better canvas 2D or WebGL solutions, which can be far more dynamic and interesting.
So the example below recreates the same content using pure JS and the CanvasRenderingContext2D API.
Demo
Math.TAU = Math.PI * 2; // set up 2 PI
Math.PI90 = Math.PI / 2; // 90 deg
Math.easeInOut = (v, p = 2) => v < 0 ? 0 : v > 1 ? 1 : v ** p / (v ** p + (1 - v) ** p)
Math.rand = (val) => Math.random() * val;
Math.randI = (val) => Math.random() * val | 0;
requestAnimationFrame(mainLoop);
CanvasRenderingContext2D.prototype.setStyle = function(style) {
for(const [key, value] of Object.entries(style)) { this[key] = value }
}
const ctx = canvas.getContext("2d");
const W = canvas.width = innerWidth; // size canvas to page
const H = canvas.height = innerHeight * 1.5;
const sprinkle = (x, y, col, size, ang) => ({x,y,col,size,ang});
const donut = {
styles: {
main: { // the icing
lineWidth: 3,
strokeStyle: "#000",
fillStyle: "#FCC",
},
inner: { // the donut
lineWidth: 2,
strokeStyle: "#000",
fillStyle: "#DB8",
},
highlight: {
lineWidth: 2,
strokeStyle: "rgba(255,255,255,0.8)",
},
sprinkle: {
lineWidth: 2,
strokeStyle: "#000",
}
},
x: W * (1/2),
y: H * (1/3) - H * (1/16) ,
r: Math.min(W * (1 / 2.5), H * (1 / 4)),
highlightOffset: 4,
drips:11, // best that this value is odd and >= 3
sprinkleCount: 7,
resetDrips: 0,
init() {
var i = 0;
this.dripLens = [];
this.sprinkles = [];
while (i < this.drips) {
this.dripLens.push(Math.rand(1) + ((i + 1) % 2));
i++;
}
i = 0;
const dr = this.r / this.drips;
const innerR = this.r * (1/3);
while (i < this.sprinkleCount) {
const a = (i / (this.sprinkleCount - 1)) * (Math.PI + 1) + Math.PI - 0.5;
const dist = Math.rand(this.r - innerR) * 0.4;
const col = "#" + Math.randI(0xFFF).toString(16).padStart(3,"0").replace(/[0-9]/g,"A");
const ang = Math.rand(Math.TAU);
const x = Math.cos(a) * (dist + innerR * 1.75) + this.x;
const y = Math.sin(a) * (dist + innerR * 1.75) + this.y;
this.sprinkles.push(sprinkle(x,y,col, dr*0.85, ang));
i++;
}
},
draw(dripScale) {
const y = this.y + this.r * (1/1.5);
const dr = this.r / this.drips;
const dripLen = this.r * (1/2.3) * dripScale;
const innerR = this.r * (1/3);
const ho = this.highlightOffset;
const lw = this.styles.main.lineWidth;
var x = this.x + this.r - dr, xx = x - dr * 2;
var i = 0;
ctx.setStyle(this.styles.inner);
ctx.beginPath();
ctx.arc(this.x, this.y, this.r - lw, 0, Math.TAU);
ctx.arc(this.x, this.y, innerR + lw, 0, Math.TAU);
ctx.fill("evenodd");
ctx.stroke();
ctx.setStyle(this.styles.main);
const lum = Math.sin(globalTime / (250 * 90)) * 20 + 50;
ctx.fillStyle = "hsl("+(globalTime / 250) % 360 +",100%,"+lum+"%)"
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, Math.PI, Math.TAU);
while (i < this.drips) {
const dy = this.dripLens[i++] * dripLen;
if (i % 2) {
ctx.arc(x, y + dy, dr, 0, Math.PI);
} else {
ctx.arc(x, y + dy, dr,0, -Math.PI, true);
}
x -= dr * 2;
}
ctx.closePath();
ctx.moveTo(this.x + innerR, this.y);
ctx.arc(this.x, this.y, innerR, 0, Math.TAU);
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 0.25;
ctx.lineWidth = this.styles.main.lineWidth * 3;
ctx.stroke();
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "source-over";
ctx.lineWidth = this.styles.main.lineWidth;
ctx.fill("evenodd");
ctx.stroke();
ctx.setStyle(this.styles.highlight);
ctx.beginPath();
ctx.arc(this.x, this.y, innerR + ho, 0, Math.PI90);
i = 0;
while (i < this.drips - 1) {
const dy1 = this.dripLens[i++] * dripLen;
const dy2 = this.dripLens[i++] * dripLen;
ctx.moveTo(xx + dr + ho, y + dy1);
ctx.arc(xx, y + dy2, dr + ho, 0, -Math.PI90, true);
xx -= dr * 4;
}
const dy1 = this.dripLens[i] * dripLen;
ctx.moveTo(xx + dr + ho, y + dy1);
ctx.arc(this.x, this.y, this.r - ho, Math.PI , Math.PI + Math.PI90);
ctx.stroke();
i = 4;
ctx.setStyle(this.styles.sprinkle);
for (const spr of this.sprinkles) {
const dy = ((spr.y - (this.y - this.r)) / this.r) * 5 * dripScale;
ctx.globalAlpha = Math.sin(globalTime / ((1 + i) * 200)) * 0.4 + 0.6;
ctx.setTransform(1,0,0,1, spr.x, spr.y + dy);
ctx.rotate(spr.ang + dy * 0.2 * (i++ % 2 ? -1 : 1));
ctx.fillStyle = spr.col;
ctx.beginPath();
ctx.arc(0, -spr.size, spr.size / 2, Math.PI, Math.TAU);
ctx.arc(0, spr.size, spr.size / 2, 0, Math.PI);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
ctx.globalAlpha = 1;
ctx.setTransform(1, 0, 0, 1, 0, 0);
if (this.resetDrips === 0 && dripScale < 0.01) {
this.resetDrips = 1;
i = 0;
while (i < this.dripLens.length) {
this.dripLens[i] = Math.rand(1) + 0.1 + ((i + 1) % 2);
i++;
}
} else if (this.resetDrips === 1 && dripScale > 0.9) {
this.resetDrips = 0;
}
}
};
donut.init();
var globalTime;
var startTime;
var animateStart = 2500; // 2.5 seconds
var animateLen = 10000; // 10 seconds
function mainLoop(time) {
globalTime = time;
ctx.globalAlpha = 1;
ctx.clearRect(0, 0, W, H);
drawContent();
requestAnimationFrame(mainLoop);
}
function drawContent() {
var animPos = 0;
if (startTime === undefined) { startTime = globalTime + animateStart }
const t = globalTime - startTime;
if (t >= 0 && t < animateLen) {
animPos = t / (animateLen / 2);
animPos = animPos > 1 ? 1- (animPos - 1) : animPos;
} else if(t >= animateLen) { startTime = undefined } // resets animation
donut.draw(Math.easeInOut(animPos));
}
body {
padding: 0px;
}
canvas {
position: absolute;
top: 0px;
left: 0px;
}
<canvas id="canvas"></canvas>
Hover to the SVG file:
body {
text-align: center;
}
#donut-icing {
fill: #FA9CB6;
transition: fill 3s ease-out;
}
#donut:hover {
cursor: pointer;
}
#donut:hover #donut-icing {
fill: #4a8af4;
}
<html>
<head>
<title>SVG Donut Animated on Hover with CSS / Sass</title>
</head>
<body>
<svg id="donut" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="204" height="203" viewBox="0 0 204 203">
<defs>
<linearGradient id="donut-a" x1="50%" x2="50%" y1="59.542%" y2="98.874%">
<stop offset="0%" stop-color="#F8F5EA"/>
<stop offset="100%" stop-color="#E1D6B6"/>
</linearGradient>
<path id="donut-icing" fill="#FA9CB6" d="M200,100 C200,44.771525 155.228475,0 100,0 C44.771525,0 0,44.771525 0,100 M0,100 L0,156.203125 C0,159.048145 2.12004279,161.359375 4.63917526,161.359375 C7.35102845,161.359375 9.47049623,159.052855 9.27835052,156.203125 L9.27835052,148.46875 C9.4934916,145.61902 11.6018043,143.3125 14.4329897,143.3125 C16.8052584,143.3125 18.9141431,145.62373 19.0721649,148.46875 L19.0721649,156.203125 L19.0721649,168.0625 C18.9141431,170.90752 21.0230278,173.21875 23.7113402,173.21875 C26.2264819,173.21875 28.3347946,170.91223 28.3505155,168.0625 L28.3505155,161.359375 L28.3505155,154.140625 C28.3347946,151.291053 30.4431073,148.984375 32.9896907,148.984375 C35.6465615,148.984375 37.7554461,151.295764 37.628866,154.140625 L37.628866,193.84375 C37.7554461,196.68877 39.8643308,199 42.2680412,199 C45.067785,199 47.1760977,196.69348 47.4226804,193.84375 L47.4226804,131.453125 C47.1760977,128.603395 49.2844103,126.296875 52.0618557,126.296875 C54.4878645,126.296875 56.5967492,128.608105 56.7010309,131.453125 L56.7010309,176.3125 C56.5967492,179.15752 58.7056338,181.46875 61.3402062,181.46875 C63.909088,181.46875 66.0174007,179.16223 65.9793814,176.3125 L65.9793814,141.765625 C66.0174007,138.916053 68.1257134,136.609375 70.6185567,136.609375 C73.3291675,136.609375 75.4380522,138.920764 75.257732,141.765625 L75.257732,160.84375 C75.4380522,163.688611 77.5469369,166 79.8969072,166 C82.750391,166 84.8587037,163.693322 85.0515464,160.84375 L85.0515464,153.625 C84.8587037,150.775428 86.9670164,148.46875 89.6907216,148.46875 C92.1704706,148.46875 94.2793552,150.780139 94.3298969,153.625 L94.8453608,187.140625 C94.8027248,189.985486 97.14593,192.296875 100,192.296875 C102.927546,192.296875 105.270115,189.990197 105.154639,187.140625 L104.639175,149.5 C104.746746,145.61902 106.855058,143.3125 109.278351,143.3125 C112.058513,143.3125 114.167397,145.62373 113.917526,148.46875 L113.917526,168.0625 C114.167397,170.90752 116.276282,173.21875 119.072165,173.21875 C121.479736,173.21875 123.588049,170.91223 123.71134,168.0625 L123.71134,161.359375 L123.71134,154.140625 C123.588049,151.291053 125.696362,148.984375 128.350515,148.984375 C130.899816,148.984375 133.0087,151.295764 132.989691,154.140625 L132.989691,193.84375 C133.0087,196.68877 135.117585,199 137.628866,199 C140.321039,199 142.429352,196.69348 142.268041,193.84375 L142.268041,138.671875 L142.268041,131.453125 C142.429352,128.603395 144.537665,126.296875 146.907216,126.296875 C149.741119,126.296875 151.850003,128.608105 152.061856,131.453125 L152.061856,139.1875 L152.061856,171.15625 C151.850003,174.00127 153.958888,176.3125 156.701031,176.3125 C159.162342,176.3125 161.270655,174.00598 161.340206,171.15625 L161.340206,144.859375 L161.340206,141.765625 C161.270655,138.916053 163.378968,136.609375 165.979381,136.609375 C168.582422,136.609375 170.691306,138.920764 170.618557,141.765625 L170.618557,144.859375 L170.618557,176.3125 C170.629257,179.157361 172.738142,181.46875 175.257732,181.46875 C177.941596,181.46875 180.049909,179.162072 179.896907,176.3125 L179.896907,153.625 C180.111958,150.775428 182.220271,148.46875 185.051546,148.46875 C187.423725,148.46875 189.532609,150.780139 189.690722,153.625 L189.690722,163.421875 C189.532609,166.266736 191.875815,168.578125 194.845361,168.578125 C197.65743,168.578125 200,166.271447 200,163.421875 L200,100"/>
</defs>
<g fill="none" fill-rule="evenodd" transform="translate(2 2)">
<circle cx="100" cy="100" r="100" fill="url(#donut-a)"/>
<path stroke="#302434" stroke-linecap="square" stroke-width="2" d="M180,160 C180.163288,159.782085 185.314605,152.363686 187,149 L180,160 Z M48,185 C63.1555058,194.519493 80.9387639,200 99.9750338,200 C111.534055,200 122.652906,197.969392 133,194.15209"/>
<mask id="donut-c" fill="#fff">
<use xlink:href="#donut-icing"/>
</mask>
<use fill="#FA9CB6" xlink:href="#donut-icing"/>
<path d="M200,100 C200,44.771525 155.228475,0 100,0 C44.771525,0 0,44.771525 0,100 M0,100 L0,156.203125 C0,159.048145 2.12004279,161.359375 4.63917526,161.359375 C7.35102845,161.359375 9.47049623,159.052855 9.27835052,156.203125 L9.27835052,148.46875 C9.4934916,145.61902 11.6018043,143.3125 14.4329897,143.3125 C16.8052584,143.3125 18.9141431,145.62373 19.0721649,148.46875 L19.0721649,156.203125 L19.0721649,168.0625 C18.9141431,170.90752 21.0230278,173.21875 23.7113402,173.21875 C26.2264819,173.21875 28.3347946,170.91223 28.3505155,168.0625 L28.3505155,161.359375 L28.3505155,154.140625 C28.3347946,151.291053 30.4431073,148.984375 32.9896907,148.984375 C35.6465615,148.984375 37.7554461,151.295764 37.628866,154.140625 L37.628866,193.84375 C37.7554461,196.68877 39.8643308,199 42.2680412,199 C45.067785,199 47.1760977,196.69348 47.4226804,193.84375 L47.4226804,131.453125 C47.1760977,128.603395 49.2844103,126.296875 52.0618557,126.296875 C54.4878645,126.296875 56.5967492,128.608105 56.7010309,131.453125 L56.7010309,176.3125 C56.5967492,179.15752 58.7056338,181.46875 61.3402062,181.46875 C63.909088,181.46875 66.0174007,179.16223 65.9793814,176.3125 L65.9793814,141.765625 C66.0174007,138.916053 68.1257134,136.609375 70.6185567,136.609375 C73.3291675,136.609375 75.4380522,138.920764 75.257732,141.765625 L75.257732,160.84375 C75.4380522,163.688611 77.5469369,166 79.8969072,166 C82.750391,166 84.8587037,163.693322 85.0515464,160.84375 L85.0515464,153.625 C84.8587037,150.775428 86.9670164,148.46875 89.6907216,148.46875 C92.1704706,148.46875 94.2793552,150.780139 94.3298969,153.625 L94.8453608,187.140625 C94.8027248,189.985486 97.14593,192.296875 100,192.296875 C102.927546,192.296875 105.270115,189.990197 105.154639,187.140625 L104.639175,149.5 C104.746746,145.61902 106.855058,143.3125 109.278351,143.3125 C112.058513,143.3125 114.167397,145.62373 113.917526,148.46875 L113.917526,168.0625 C114.167397,170.90752 116.276282,173.21875 119.072165,173.21875 C121.479736,173.21875 123.588049,170.91223 123.71134,168.0625 L123.71134,161.359375 L123.71134,154.140625 C123.588049,151.291053 125.696362,148.984375 128.350515,148.984375 C130.899816,148.984375 133.0087,151.295764 132.989691,154.140625 L132.989691,193.84375 C133.0087,196.68877 135.117585,199 137.628866,199 C140.321039,199 142.429352,196.69348 142.268041,193.84375 L142.268041,138.671875 L142.268041,131.453125 C142.429352,128.603395 144.537665,126.296875 146.907216,126.296875 C149.741119,126.296875 151.850003,128.608105 152.061856,131.453125 L152.061856,139.1875 L152.061856,171.15625 C151.850003,174.00127 153.958888,176.3125 156.701031,176.3125 C159.162342,176.3125 161.270655,174.00598 161.340206,171.15625 L161.340206,144.859375 L161.340206,141.765625 C161.270655,138.916053 163.378968,136.609375 165.979381,136.609375 C168.582422,136.609375 170.691306,138.920764 170.618557,141.765625 L170.618557,144.859375 L170.618557,176.3125 C170.629257,179.157361 172.738142,181.46875 175.257732,181.46875 C177.941596,181.46875 180.049909,179.162072 179.896907,176.3125 L179.896907,153.625 C180.111958,150.775428 182.220271,148.46875 185.051546,148.46875 C187.423725,148.46875 189.532609,150.780139 189.690722,153.625 L189.690722,163.421875 C189.532609,166.266736 191.875815,168.578125 194.845361,168.578125 C197.65743,168.578125 200,166.271447 200,163.421875 L200,100" mask="url(#donut-c)"/>
<path stroke="#302434" stroke-linecap="square" stroke-width="3" d="M200 100C200 44.771525 155.228475 0 100 0 44.771525 0 0 44.771525 0 100M0 100L0 156.203125C0 159.048145 2.12004279 161.359375 4.63917526 161.359375 7.35102845 161.359375 9.47049623 159.052855 9.27835052 156.203125L9.27835052 148.46875C9.4934916 145.61902 11.6018043 143.3125 14.4329897 143.3125 16.8052584 143.3125 18.9141431 145.62373 19.0721649 148.46875L19.0721649 156.203125 19.0721649 168.0625C18.9141431 170.90752 21.0230278 173.21875 23.7113402 173.21875 26.2264819 173.21875 28.3347946 170.91223 28.3505155 168.0625L28.3505155 161.359375 28.3505155 154.140625C28.3347946 151.291053 30.4431073 148.984375 32.9896907 148.984375 35.6465615 148.984375 37.7554461 151.295764 37.628866 154.140625L37.628866 193.84375C37.7554461 196.68877 39.8643308 199 42.2680412 199 45.067785 199 47.1760977 196.69348 47.4226804 193.84375L47.4226804 131.453125C47.1760977 128.603395 49.2844103 126.296875 52.0618557 126.296875 54.4878645 126.296875 56.5967492 128.608105 56.7010309 131.453125L56.7010309 176.3125C56.5967492 179.15752 58.7056338 181.46875 61.3402062 181.46875 63.909088 181.46875 66.0174007 179.16223 65.9793814 176.3125L65.9793814 141.765625C66.0174007 138.916053 68.1257134 136.609375 70.6185567 136.609375 73.3291675 136.609375 75.4380522 138.920764 75.257732 141.765625L75.257732 160.84375C75.4380522 163.688611 77.5469369 166 79.8969072 166 82.750391 166 84.8587037 163.693322 85.0515464 160.84375L85.0515464 153.625C84.8587037 150.775428 86.9670164 148.46875 89.6907216 148.46875 92.1704706 148.46875 94.2793552 150.780139 94.3298969 153.625L94.8453608 187.140625C94.8027248 189.985486 97.14593 192.296875 100 192.296875 102.927546 192.296875 105.270115 189.990197 105.154639 187.140625L104.639175 149.5C104.746746 145.61902 106.855058 143.3125 109.278351 143.3125 112.058513 143.3125 114.167397 145.62373 113.917526 148.46875L113.917526 168.0625C114.167397 170.90752 116.276282 173.21875 119.072165 173.21875 121.479736 173.21875 123.588049 170.91223 123.71134 168.0625L123.71134 161.359375 123.71134 154.140625C123.588049 151.291053 125.696362 148.984375 128.350515 148.984375 130.899816 148.984375 133.0087 151.295764 132.989691 154.140625L132.989691 193.84375C133.0087 196.68877 135.117585 199 137.628866 199 140.321039 199 142.429352 196.69348 142.268041 193.84375L142.268041 138.671875 142.268041 131.453125C142.429352 128.603395 144.537665 126.296875 146.907216 126.296875 149.741119 126.296875 151.850003 128.608105 152.061856 131.453125L152.061856 139.1875 152.061856 171.15625C151.850003 174.00127 153.958888 176.3125 156.701031 176.3125 159.162342 176.3125 161.270655 174.00598 161.340206 171.15625L161.340206 144.859375 161.340206 141.765625C161.270655 138.916053 163.378968 136.609375 165.979381 136.609375 168.582422 136.609375 170.691306 138.920764 170.618557 141.765625L170.618557 144.859375 170.618557 176.3125C170.629257 179.157361 172.738142 181.46875 175.257732 181.46875 177.941596 181.46875 180.049909 179.162072 179.896907 176.3125L179.896907 153.625C180.111958 150.775428 182.220271 148.46875 185.051546 148.46875 187.423725 148.46875 189.532609 150.780139 189.690722 153.625L189.690722 163.421875C189.532609 166.266736 191.875815 168.578125 194.845361 168.578125 197.65743 168.578125 200 166.271447 200 163.421875L200 100"/>
<circle cx="100.5" cy="100.5" r="26.5" fill="#FFF" stroke="#302434" stroke-linecap="square" stroke-width="3"/>
<path stroke="#FFF" stroke-linecap="round" stroke-width="2" d="M103,132 L103,132 C119.016258,132 132,119.016258 132,103" opacity=".7"/>
<path fill="#F7DA71" stroke="#302434" stroke-width="2.062" d="M168.854871,80.8314322 L168.854871,81.1126307 C168.854871,82.6700566 170.123055,83.9411037 171.680144,83.9411037 L183.967742,83.9411037 C185.519686,83.9411037 186.793015,82.6697696 186.793015,81.1126307 L186.793015,80.8314322 C186.793015,79.2740064 185.52483,78.0029593 183.967742,78.0029593 L171.680144,78.0029593 C170.1282,78.0029593 168.854871,79.2742934 168.854871,80.8314322 Z" transform="rotate(-134 177.824 80.972)"/>
<path fill="#FFAD38" stroke="#302434" stroke-width="2.062" d="M170.784479,122.710815 L170.784479,122.992013 C170.784479,124.549439 172.052663,125.820486 173.609752,125.820486 L185.89735,125.820486 C187.449294,125.820486 188.722623,124.549152 188.722623,122.992013 L188.722623,122.710815 C188.722623,121.153389 187.454438,119.882342 185.89735,119.882342 L173.609752,119.882342 C172.057808,119.882342 170.784479,121.153676 170.784479,122.710815 Z" transform="rotate(25 179.754 122.851)"/>
<path fill="#9FC1EA" stroke="#302434" stroke-width="2.062" d="M137.779864,103.591935 L137.779864,103.873134 C137.779864,105.430559 139.048049,106.701607 140.605137,106.701607 L152.892735,106.701607 C154.444679,106.701607 155.718008,105.430272 155.718008,103.873134 L155.718008,103.591935 C155.718008,102.034509 154.449824,100.763462 152.892735,100.763462 L140.605137,100.763462 C139.053193,100.763462 137.779864,102.034796 137.779864,103.591935 Z" transform="rotate(-73 146.749 103.733)"/>
<path fill="#FFAD38" stroke="#302434" stroke-width="2.062" d="M69.2022598,19.4388294 L69.2022598,19.7200279 C69.2022598,21.2774537 70.4704445,22.5485008 72.0275331,22.5485008 L84.3151307,22.5485008 C85.8670745,22.5485008 87.1404041,21.2771667 87.1404041,19.7200279 L87.1404041,19.4388294 C87.1404041,17.8814035 85.8722194,16.6103564 84.3151307,16.6103564 L72.0275331,16.6103564 C70.4755893,16.6103564 69.2022598,17.8816905 69.2022598,19.4388294 Z" transform="rotate(-41 78.171 19.58)"/>
<path fill="#F45467" stroke="#302434" stroke-width="2.062" d="M63.4327156,63.1481419 L63.4327156,63.4293404 C63.4327156,64.9867663 64.7009003,66.2578133 66.2579889,66.2578133 L78.5455866,66.2578133 C80.0975304,66.2578133 81.3708599,64.9864793 81.3708599,63.4293404 L81.3708599,63.1481419 C81.3708599,61.5907161 80.1026752,60.319669 78.5455866,60.319669 L66.2579889,60.319669 C64.7060452,60.319669 63.4327156,61.5910031 63.4327156,63.1481419 Z" transform="rotate(-51 72.402 63.289)"/>
<path fill="#9FC1EA" stroke="#302434" stroke-width="2.062" d="M93.4950295,44.5196548 L93.4950295,44.8008533 C93.4950295,46.3582791 94.7632142,47.6293262 96.3203028,47.6293262 L108.6079,47.6293262 C110.159844,47.6293262 111.433174,46.3579921 111.433174,44.8008533 L111.433174,44.5196548 C111.433174,42.9622289 110.164989,41.6911819 108.6079,41.6911819 L96.3203028,41.6911819 C94.768359,41.6911819 93.4950295,42.962516 93.4950295,44.5196548 Z" transform="rotate(-120 102.464 44.66)"/>
<path fill="#F45467" stroke="#302434" stroke-width="2.062" d="M116.763462,17.6083368 L116.763462,17.8895353 C116.763462,19.4469612 118.031647,20.7180082 119.588736,20.7180082 L131.876333,20.7180082 C133.428277,20.7180082 134.701607,19.4466741 134.701607,17.8895353 L134.701607,17.6083368 C134.701607,16.050911 133.433422,14.7798639 131.876333,14.7798639 L119.588736,14.7798639 C118.036792,14.7798639 116.763462,16.051198 116.763462,17.6083368 Z" transform="rotate(-163 125.733 17.749)"/>
<path fill="#9FC1EA" stroke="#302434" stroke-width="2.062" d="M31.4950295,42.5196548 L31.4950295,42.8008533 C31.4950295,44.3582791 32.7632142,45.6293262 34.3203028,45.6293262 L46.6079004,45.6293262 C48.1598442,45.6293262 49.4331738,44.3579921 49.4331738,42.8008533 L49.4331738,42.5196548 C49.4331738,40.9622289 48.1649891,39.6911819 46.6079004,39.6911819 L34.3203028,39.6911819 C32.768359,39.6911819 31.4950295,40.962516 31.4950295,42.5196548 Z" transform="rotate(-120 40.464 42.66)"/>
<path fill="#9FC1EA" stroke="#302434" stroke-width="2.062" d="M7.00295932,122.683344 L7.00295932,122.964542 C7.00295932,124.521968 8.27114404,125.793015 9.82823266,125.793015 L22.1158303,125.793015 C23.6677741,125.793015 24.9411037,124.521681 24.9411037,122.964542 L24.9411037,122.683344 C24.9411037,121.125918 23.6729189,119.854871 22.1158303,119.854871 L9.82823266,119.854871 C8.27628888,119.854871 7.00295932,121.126205 7.00295932,122.683344 Z" transform="rotate(44 15.972 122.824)"/>
<path fill="#9FC1EA" stroke="#302434" stroke-width="2.062" d="M143.573598,38.5351135 L143.573598,38.816312 C143.573598,40.3737379 144.841783,41.644785 146.398871,41.644785 L158.686469,41.644785 C160.238413,41.644785 161.511742,40.3734509 161.511742,38.816312 L161.511742,38.5351135 C161.511742,36.9776877 160.243558,35.7066406 158.686469,35.7066406 L146.398871,35.7066406 C144.846928,35.7066406 143.573598,36.9779747 143.573598,38.5351135 Z" transform="rotate(10 152.543 38.676)"/>
<path fill="#FFAD38" stroke="#302434" stroke-width="2.062" d="M13.7798639,78.5919351 L13.7798639,78.8731336 C13.7798639,80.4305595 15.0480486,81.7016065 16.6051372,81.7016065 L28.8927349,81.7016065 C30.4446787,81.7016065 31.7180082,80.4302725 31.7180082,78.8731336 L31.7180082,78.5919351 C31.7180082,77.0345093 30.4498235,75.7634622 28.8927349,75.7634622 L16.6051372,75.7634622 C15.0531935,75.7634622 13.7798639,77.0347963 13.7798639,78.5919351 Z" transform="rotate(-73 22.749 78.733)"/>
<path fill="#FFAD38" stroke="#302434" stroke-width="2.062" d="M133.763462,61.6083368 L133.763462,61.8895353 C133.763462,63.4469612 135.031647,64.7180082 136.588736,64.7180082 L148.876333,64.7180082 C150.428277,64.7180082 151.701607,63.4466741 151.701607,61.8895353 L151.701607,61.6083368 C151.701607,60.050911 150.433422,58.7798639 148.876333,58.7798639 L136.588736,58.7798639 C135.036792,58.7798639 133.763462,60.051198 133.763462,61.6083368 Z" transform="rotate(-17 142.733 61.749)"/>
<path fill="#F7DA71" stroke="#302434" stroke-width="2.062" d="M40.1448483,100.300712 L40.1448483,100.58191 C40.1448483,102.139336 41.4130331,103.410383 42.9701217,103.410383 L55.2577193,103.410383 C56.8096631,103.410383 58.0829927,102.139049 58.0829927,100.58191 L58.0829927,100.300712 C58.0829927,98.7432859 56.8148079,97.4722388 55.2577193,97.4722388 L42.9701217,97.4722388 C41.4181779,97.4722388 40.1448483,98.7435729 40.1448483,100.300712 Z" transform="rotate(54 49.114 100.441)"/>
<path stroke="#302434" stroke-linecap="square" stroke-width="2" d="M143 190C153.043627 185.195415 162.158445 178.746675 170 171M28.7212226 170.713933C31.3439197 173.284559 34.1076215 175.717271 37 178M11.5217511 145.997463C13.5503966 149.823796 15.8170146 153.505818 18.3020045 157.024023"/>
<path stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 140C20.5567785 140 22.8296876 142.321236 23 145.178571L23 152.946429 23 169M37 146C39.5567785 146 41.8296876 148.311968 42 151.157895L42 158.894737 42 195M56 123C58.5567785 123 60.8296876 125.305227 61 128.142857L61 135.857143 61 177M151 122C153.556779 122 155.829688 124.311968 156 127.157895L156 134.894737 156 171M74 133C76.5567785 133 78.8296876 135.3242 79 138.185185L79 145.962963 79 161M94 145C96.5567785 145 98.8296876 147.3242 99 150.185185L99 157.962963 99 187M113 139C115.556779 139 117.829688 141.280512 118 144.087719L118 151.719298 118 168M132 145C134.556779 145 136.829688 147.311968 137 150.157895L137 157.894737 137 194M170 133C172.301101 133 174.346719 135.293314 174.5 138.116279L174.5 145.790698 175 177M189 144C191.556779 144 193.829688 146.301766 194 149.135135L194 156.837838 194 163" opacity=".7"/>
</g>
</svg>
</body>
</html>
I have the following SVG:
<svg>
<g>
<path id="k9ffd8001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="#a0a700"></path>
<path id="kb8000001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="url(#k9ffb0001)"></path>
</g>
</svg>
I want to get a CSS-like border-top-right-radius and border-top-bottom-radius effect.
How can I achieve that rounded corner effect?
Here is how you can create a rounded rectangle with SVG Path:
<path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" />
Explanation
m100,100: move to point(100,100)
h200: draw a 200px horizontal line from where we are
a20,20 0 0 1 20,20: draw an arc with 20px X radius, 20px Y radius, clockwise, to a point with 20px difference in X and Y axis
v200: draw a 200px vertical line from where we are
a20,20 0 0 1 -20,20: draw an arc with 20px X and Y radius, clockwise, to a point with -20px difference in X and 20px difference in Y axis
h-200: draw a -200px horizontal line from where we are
a20,20 0 0 1 -20,-20: draw an arc with 20px X and Y radius, clockwise, to a point with -20px difference in X and -20px difference in Y axis
v-200: draw a -200px vertical line from where we are
a20,20 0 0 1 20,-20: draw an arc with 20px X and Y radius, clockwise, to a point with 20px difference in X and -20px difference in Y axis
z: close the path
<svg width="440" height="440">
<path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" fill="none" stroke="black" stroke-width="3" />
</svg>
Not sure why nobody posted an actual SVG answer. Here is an SVG rectangle with rounded corners (radius 3) on the top:
<path d="M0,0 L0,27 A3,3 0 0,0 3,30 L7,30 A3,3 0 0,0 10,27 L10,0 Z" />
This is a Move To (M), Line To (L), Arc To (A), Line To (L), Arc To (A), Line To (L), Close Path (Z).
The comma-delimited numbers are absolute coordinates. The arcs are defined with additional parameters specifying the radius and type of arc. This could also be accomplished with relative coordinates (use lower-case letters for L and A).
The complete reference for those commands is on the W3C SVG Paths page, and additional reference material on SVG paths can be found in this article.
As referenced in my answer to Applying rounded corners to paths/polygons, I have written a routine in javascript for generically rounding corners of SVG paths, with examples, here: http://plnkr.co/edit/kGnGGyoOCKil02k04snu.
It will work independently from any stroke effects you may have. To use, include the rounding.js file from the Plnkr and call the function like so:
roundPathCorners(pathString, radius, useFractionalRadius)
The result will be the rounded path.
The results look like this:
You have explicitly set your stroke-linejoin to round but your stroke-width to 0, so of course you're not going to see rounded corners if you have no stroke to round.
Here's a modified example with rounded corners made through strokes:
http://jsfiddle.net/8uxqK/1/
<path d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z"
stroke-width="5"
stroke-linejoin="round"
stroke="#808600"
fill="#a0a700" />
Otherwise—if you need an actual rounded shape fill and not just a rounded fatty stroke—you must do what #Jlange says and make an actual rounded shape.
I'd also consider using a plain old <rect> which provides the rx and ry attributes
MDN SVG docs <- note the second drawn rect element
I've happened upon this problem today myself and managed to solve it by writing a small JavaScript function.
From what I can tell, there is no easy way to give a path element in an SVG rounded corners except if you only need the borders to be rounded, in which case the (CSS) attributes stroke, stroke-width and most importantly stroke-linejoin="round" are perfectly sufficient.
However, in my case I used a path object to create custom shapes with n corners that are filled out with a certain color and don't have visible borders, much like this:
I managed to write a quick function that takes an array of coordinates for an SVG path and returns the finished path string to put in the d attribute of the path html element. The resulting shape will then look something like this:
Here is the function:
/**
* Creates a coordinate path for the Path SVG element with rounded corners
* #param pathCoords - An array of coordinates in the form [{x: Number, y: Number}, ...]
*/
function createRoundedPathString(pathCoords) {
const path = [];
const curveRadius = 3;
// Reset indexes, so there are no gaps
pathCoords = pathCoords.slice();
for (let i = 0; i < pathCoords.length; i++) {
// 1. Get current coord and the next two (startpoint, cornerpoint, endpoint) to calculate rounded curve
const c2Index = ((i + 1) > pathCoords.length - 1) ? (i + 1) % pathCoords.length : i + 1;
const c3Index = ((i + 2) > pathCoords.length - 1) ? (i + 2) % pathCoords.length : i + 2;
const c1 = pathCoords[i];
const c2 = pathCoords[c2Index];
const c3 = pathCoords[c3Index];
// 2. For each 3 coords, enter two new path commands: Line to start of curve, bezier curve around corner.
// Calculate curvePoint c1 -> c2
const c1c2Distance = Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
const c1c2DistanceRatio = (c1c2Distance - curveRadius) / c1c2Distance;
const c1c2CurvePoint = [
((1 - c1c2DistanceRatio) * c1.x + c1c2DistanceRatio * c2.x).toFixed(1),
((1 - c1c2DistanceRatio) * c1.y + c1c2DistanceRatio * c2.y).toFixed(1)
];
// Calculate curvePoint c2 -> c3
const c2c3Distance = Math.sqrt(Math.pow(c2.x - c3.x, 2) + Math.pow(c2.y - c3.y, 2));
const c2c3DistanceRatio = curveRadius / c2c3Distance;
const c2c3CurvePoint = [
((1 - c2c3DistanceRatio) * c2.x + c2c3DistanceRatio * c3.x).toFixed(1),
((1 - c2c3DistanceRatio) * c2.y + c2c3DistanceRatio * c3.y).toFixed(1)
];
// If at last coord of polygon, also save that as starting point
if (i === pathCoords.length - 1) {
path.unshift('M' + c2c3CurvePoint.join(','));
}
// Line to start of curve (L endcoord)
path.push('L' + c1c2CurvePoint.join(','));
// Bezier line around curve (Q controlcoord endcoord)
path.push('Q' + c2.x + ',' + c2.y + ',' + c2c3CurvePoint.join(','));
}
// Logically connect path to starting point again (shouldn't be necessary as path ends there anyway, but seems cleaner)
path.push('Z');
return path.join(' ');
}
You can determine the rounding strength by setting the curveRadius variable at the top. The default is 3 for a 100x100 (viewport) coordinate system, but depending on the size of your SVG, you may need to adjust this.
For my case I need to radius begin and end of path:
With stroke-linecap: round; I change it to what I want:
This question is the first result for Googling "svg rounded corners path". Phrogz suggestion to use stroke has some limitations (namely, that I cannot use stroke for other purposes, and that the dimensions have to be corrected for the stroke width).
Jlange suggestion to use a curve is better, but not very concrete. I ended up using quadratic Bézier curves for drawing rounded corners. Consider this picture of a corner marked with a blue dot and two red points on adjacent edges:
The two lines could be made with the L command. To turn this sharp corner into a rounded corner, start drawing a curve from the left red point (use M x,y to move to that point). Now a quadratic Bézier curve has just a single control point which you must set on the blue point. Set the end of the curve at the right red point. As the tangent at the two red points are in the direction of the previous lines, you will see a fluent transition, "rounded corners".
Now to continue the shape after the rounded corner, a straight line in a Bézier curve can be achieved by setting the control point between on the line between the two corners.
To help me with determining the path, I wrote this Python script that accepts edges and a radius. Vector math makes this actually very easy. The resulting image from the output:
#!/usr/bin/env python
# Given some vectors and a border-radius, output a SVG path with rounded
# corners.
#
# Copyright (C) Peter Wu <peter#lekensteyn.nl>
from math import sqrt
class Vector(object):
def __init__(self, x, y):
self.x = x
self.y = y
def sub(self, vec):
return Vector(self.x - vec.x, self.y - vec.y)
def add(self, vec):
return Vector(self.x + vec.x, self.y + vec.y)
def scale(self, n):
return Vector(self.x * n, self.y * n)
def length(self):
return sqrt(self.x**2 + self.y**2)
def normal(self):
length = self.length()
return Vector(self.x / length, self.y / length)
def __str__(self):
x = round(self.x, 2)
y = round(self.y, 2)
return '{},{}'.format(x, y)
# A line from vec_from to vec_to
def line(vec_from, vec_to):
half_vec = vec_from.add(vec_to.sub(vec_from).scale(.5))
return '{} {}'.format(half_vec, vec_to)
# Adds 'n' units to vec_from pointing in direction vec_to
def vecDir(vec_from, vec_to, n):
return vec_from.add(vec_to.sub(vec_from).normal().scale(n))
# Draws a line, but skips 'r' units from the begin and end
def lineR(vec_from, vec_to, r):
vec = vec_to.sub(vec_from).normal().scale(r)
return line(vec_from.add(vec), vec_to.sub(vec))
# An edge in vec_from, to vec_to with radius r
def edge(vec_from, vec_to, r):
v = vecDir(vec_from, vec_to, r)
return '{} {}'.format(vec_from, v)
# Hard-coded border-radius and vectors
r = 5
a = Vector( 0, 60)
b = Vector(100, 0)
c = Vector(100, 200)
d = Vector( 0, 200 - 60)
path = []
# Start below top-left edge
path.append('M {} Q'.format(a.add(Vector(0, r))))
# top-left edge...
path.append(edge(a, b, r))
path.append(lineR(a, b, r))
path.append(edge(b, c, r))
path.append(lineR(b, c, r))
path.append(edge(c, d, r))
path.append(lineR(c, d, r))
path.append(edge(d, a, r))
path.append(lineR(d, a, r))
# Show results that can be pushed into a <path d="..." />
for part in path:
print(part)
Here are some paths for tabs:
https://codepen.io/mochime/pen/VxxzMW
<!-- left tab -->
<div>
<svg width="60" height="60">
<path d="M10,10
a10 10 0 0 1 10 -10
h 50
v 47
h -50
a10 10 0 0 1 -10 -10
z"
fill="#ff3600"></path>
</svg>
</div>
<!-- right tab -->
<div>
<svg width="60" height="60">
<path d="M10 0
h 40
a10 10 0 0 1 10 10
v 27
a10 10 0 0 1 -10 10
h -40
z"
fill="#ff3600"></path>
</svg>
</div>
<!-- tab tab :) -->
<div>
<svg width="60" height="60">
<path d="M10,40
v -30
a10 10 0 0 1 10 -10
h 30
a10 10 0 0 1 10 10
v 30
z"
fill="#ff3600"></path>
</svg>
</div>
The other answers explained the mechanics. I especially liked hossein-maktoobian's answer.
The paths in the pen do the brunt of the work, the values can be modified to suite whatever desired dimensions.
This basically does the same as Mvins answer, but is a more compressed down and simplified version. It works by going back the distance of the radius of the lines adjacent to the corner and connecting both ends with a bezier curve whose control point is at the original corner point.
function createRoundedPath(coords, radius, close) {
let path = ""
const length = coords.length + (close ? 1 : -1)
for (let i = 0; i < length; i++) {
const a = coords[i % coords.length]
const b = coords[(i + 1) % coords.length]
const t = Math.min(radius / Math.hypot(b.x - a.x, b.y - a.y), 0.5)
if (i > 0) path += `Q${a.x},${a.y} ${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`
if (!close && i == 0) path += `M${a.x},${a.y}`
else if (i == 0) path += `M${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`
if (!close && i == length - 1) path += `L${b.x},${b.y}`
else if (i < length - 1) path += `L${a.x * t + b.x * (1 - t)},${a.y * t + b.y * (1 - t)}`
}
if (close) path += "Z"
return path
}
Here’s a piece of react code to generate rectangles with different corner radiuses:
const Rect = ({width, height, tl, tr, br, bl}) => {
const top = width - tl - tr;
const right = height - tr - br;
const bottom = width - br - bl;
const left = height - bl - tl;
const d = `
M${tl},0
h${top}
a${tr},${tr} 0 0 1 ${tr},${tr}
v${right}
a${br},${br} 0 0 1 -${br},${br}
h-${bottom}
a${bl},${bl} 0 0 1 -${bl},-${bl}
v-${left}
a${tl},${tl} 0 0 1 ${tl},-${tl}
z
`;
return (
<svg width={width} height={height}>
<path d={d} fill="black" />
</svg>
);
};
ReactDOM.render(
<Rect width={200} height={100} tl={20} tr={0} br={20} bl={60} />,
document.querySelector('#app'),
);
https://jsfiddle.net/v1Ljpxh7/
Just to simplify implementing answer of #hmak.me, here's a commented piece of React code to generate rounded rectangles.
const Rect = ({width, height, round, strokeWidth}) => {
// overhang over given width and height that we get due to stroke width
const s = strokeWidth / 2;
// how many pixels do we need to cut from vertical and horizontal parts
// due to rounded corners and stroke width
const over = 2 * round + strokeWidth;
// lengths of straight lines
const w = width - over;
const h = height - over;
// beware that extra spaces will not be minified
// they are added for clarity
const d = `
M${round + s},${s}
h${w}
a${round},${round} 0 0 1 ${round},${round}
v${h}
a${round},${round} 0 0 1 -${round},${round}
h-${w}
a${round},${round} 0 0 1 -${round},-${round}
v-${h}
a${round},${round} 0 0 1 ${round},-${round}
z
`;
return (
<svg width={width} height={height}>
<path d={d} fill="none" stroke="black" strokeWidth={strokeWidth} />
</svg>
);
};
ReactDOM.render(
<Rect width={64} height={32} strokeWidth={2} round={4} />,
document.querySelector('#app'),
);
Jsfiddle link.
I wrote this little typescript function so I can dynamically create the path for a complex rounded rectangle that function similar to a div with border-radius.
export function roundedRectPath(
x: number,
y: number,
width: number,
height: number,
bevel: [number, number, number, number] = [3, 3, 3, 3]
): string {
return "M" + x + "," + y
+ `m 0 ${bevel[0]}`
+ `q 0 -${bevel[0]} ${bevel[0]} -${bevel[0]}`
+ `l ${width - bevel[0] - bevel[1]} 0`
+ `q ${bevel[1]} 0 ${bevel[1]} ${bevel[1]}`
+ `l 0 ${height - bevel[1] - bevel[2]}`
+ `q 0 ${bevel[2]} -${bevel[2]} ${bevel[2]}`
+ `l -${width - bevel[2] - bevel[3]} 0`
+ `q -${bevel[3]} 0 -${bevel[3]} -${bevel[3]}`
+ `z`;
}
I found a solution but it is a bit hacky so it may not always work. I found that if you have an arc (A or a) with really small values it forces it to create a curve in one spot thus forming a rounded comer...
<svg viewBox="0 0 1 0.6" stroke="black" fill="grey" style="stroke-width:0.05px;">
<path d="M0.7 0.2 L0.1 0.1 A0.0001 0.0001 0 0 0 0.099 0.101 L0.5 0.5Z"></path>
</svg>
You are using a path element, why don't you just give the path a curve? See here for how to make curves using path elements: http://www.w3.org/TR/SVG/paths.html#PathDataCurveCommands