divinelemon
divinelemon

Reputation: 2097

Make Canvas (rectangle) wrap around a rectangle with border-radius

I have an image with border radius that I am trying to make a canvas line wrap around it. I want to use canvas because I need to be able to set the value of how far the rectangle wraps around it, so for example, if I set it to 1 the rectangle would barely be their, and if I set it too 100 it would be completely around the rectangle with border radius. Here's an example of what I need with a circle:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function newLine(){
  let value = (Math.floor(Math.random() * 100) + 1) * 0.06283185307179587;
  ctx.clearRect(0, 0, c.width, c.height);
  ctx.lineWidth = 10;
  ctx.strokeStyle = '#00FF00';
  
  ctx.beginPath();
  ctx.arc(100, 75, 55, 0, value);
  ctx.stroke();
}

setInterval(()=>{
newLine()
}, 100)
img{
  width: 100px;
  border-radius: 50px;
  position: absolute;
  left: 58px;
  top: 33px;
 }
<img src="https://media-exp1.licdn.com/dms/image/C4E0BAQHikN6EXPd23Q/company-logo_200_200/0/1595359131127?e=2159024400&v=beta&t=S5MNjBDjiH433VCWzjPeiopNDhxGwmfcMk4Zf1P_m_s"></img>
<canvas id="myCanvas"></canvas>

However, if I make the border radius a little smaller, it doesn't wrap around it. Is there a way to do this?

Heres a code snippet showing what I need:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function newLine(){
  let value = (Math.floor(Math.random() * 100) + 1) * 0.06283185307179587;
  ctx.clearRect(0, 0, c.width, c.height);
  ctx.lineWidth = 10;
  ctx.strokeStyle = '#00FF00';
  
  ctx.beginPath();
  ctx.arc(100, 75, 55, 0, value);
  ctx.stroke();
}

setInterval(()=>{
newLine()
}, 100)
img{
  width: 100px;
  border-radius: 30px;
  position: absolute;
  left: 58px;
  top: 33px;
 }
<img src="https://media-exp1.licdn.com/dms/image/C4E0BAQHikN6EXPd23Q/company-logo_200_200/0/1595359131127?e=2159024400&v=beta&t=S5MNjBDjiH433VCWzjPeiopNDhxGwmfcMk4Zf1P_m_s"></img>
<canvas id="myCanvas"></canvas>

Is this possible? Thanks

Upvotes: 3

Views: 255

Answers (1)

Wendelin
Wendelin

Reputation: 2401

I think this is a nice solution, very flexible and basically no JS overhead.

const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");

let value = 0

function newLine(){
  value += Math.PI/60
  value %= Math.PI*2
  
  ctx.clearRect(0, 0, c.width, c.height);
  ctx.lineWidth = 10;
  ctx.fillStyle = '#00FF00';
  
  ctx.beginPath();
  // move to center
  ctx.moveTo(c.width/2, c.height/2)
  // line to right
  ctx.lineTo(c.width, c.height/2)
  // make a big semicircle
  ctx.arc(c.width/2, c.height/2, c.width, 0, value);
  ctx.fill();
}

setInterval(()=>{
newLine()
}, 100)
:root {
/** ===== Try changing these variables ===== **/
  --thing-radius: 35px;
  --thing-border: 5px;
  --thing-size: 100px;
  
  
  --thing-double-border: calc(2 * var(--thing-border));
}

.thing {
  width: calc(var(--thing-size) + var(--thing-double-border));
  height: calc(var(--thing-size) + var(--thing-double-border));
  display: grid;
  grid-template-areas: "center";
  grid-template-columns: 100%;
}

.thing > * {
  box-sizing: border-box;
  grid-area: center;
  width: 100%;
}

.thing > img {
  border-radius: var(--thing-radius);
  border: var(--thing-border) solid transparent;
  z-index: 1;
}
 
.thing > canvas {
  border-radius: var(--thing-radius);
}
<div class="thing">
  <!-- note that you don't need to change the canvas size -->
  <canvas id="myCanvas" width="100" height="100"></canvas>
  <img src="https://media-exp1.licdn.com/dms/image/C4E0BAQHikN6EXPd23Q/company-logo_200_200/0/1595359131127?e=2159024400&v=beta&t=S5MNjBDjiH433VCWzjPeiopNDhxGwmfcMk4Zf1P_m_s"/>
</div>

This solution works by rendering a big pie that is then cropped by css behind the image.

Upvotes: 3

Related Questions