Home > Back-end >  Create a function that generates circular borders with n separate parts and places an event listener
Create a function that generates circular borders with n separate parts and places an event listener

Time:08-12

I need to create a series of circles that meet the following pattern: Circle Style

But I need to generate a function to create a circle divided into n parts, not just 2 that follows the same design pattern as the image. I was able to create 4 circles with that pattern, for that I used the following code:

.circle,
.circle1,
.circle2,
.circle3 {
  position: relative;
  padding: 0;
  margin: 1em auto;
  width: 310px;
  height: 310px;
  border-radius: 50%;
  list-style: none;
  overflow: hidden;
  display: grid;
  gap: 1rem;
  justify-content: center;
  align-items: center;
  transition: 1s ease-in-out;
}
.circle {
  grid-template-columns: 1fr;
}
.circle1 {
  grid-template-columns: 1fr 1fr;
}
.circle2 {
  grid-template-columns: 1fr 1fr; /* splitting the circle into 2, equally sized columns/semi-circles */
  grid-template-areas: 'up1 up2' 'down down';
  justify-content: center;
  align-items: center;
  transition: 1s ease-in-out;
}
.circle3 {
  grid-template-columns: 1fr 1fr; /* splitting the circle into 2, equally sized columns/semi-circles */
  grid-template-rows: 1fr 1fr;
  justify-content: center;
  align-items: center;
  transition: 1s ease-in-out;
}
li.inner-circle-one {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -145px 0px 0px -145px;
  width: 290px;
  height: 290px;
  border-radius: 50%;
  display: grid;
  grid-template-columns: 1fr;
  background-color: white;
  z-index: 99;
}
li.inner-circle {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -145px 0px 0px -145px;
  width: 290px;
  height: 290px;
  border-radius: 50%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background-color: white;
  z-index: 99;
}
li.slide,
li.slide1,
li.slide2,
li.slide3,
li.slide4,
li.slide5,
li.slide6,
li.slide7,
li.slide8,
li.slide9 {
  overflow: hidden;
  width: 100%;
  height: 100%;
  position: relative;
}

.text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 5rem;
}
.slide,
.slide1,
.slide2,
.slide3,
.slide4,
.slide5,
.slide6,
.slide7,
.slide8,
.slide9 {
  cursor: pointer;
  background: gray;
  transition: 1s ease-in-out;
}
.slide:hover,
.slide1:hover,
.slide2:hover,
.slide3:hover,
.slide4:hover,
.slide5:hover,
.slide6:hover,
.slide7:hover,
.slide8:hover,
.slide9:hover {
  transform: scale(1.1);
}
.slide1:hover {
  transform: translate(-10px);
}
.slide2:hover {
  transform: translate(10px);
}
.slide.purple,
.slide1.purple,
.slide2.purple,
.slide3.purple,
.slide4.purple,
.slide5.purple,
.slide6.purple,
.slide7.purple,
.slide8.purple,
.slide9.purple {
  background-color: purple;
}
.slide3 {
  grid-area: up1;
}
.slide4 {
  grid-area: up2;
}
.slide5 {
  grid-area: down;
}
.inner-text {
  position: absolute;
  z-index: 100;
  text-align: center;
  left: 140px;
  color: grey;
  font-weight: bold;
  font-size: 1.3rem;
}
<ul >
      <li ></li>
      <li >
        <div ></div>
      </li>
      <li ><span id="number">0</span>/1</li>
    </ul>
    <ul >
      <li ></li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li ><span id="number1">0</span>/2</li>
    </ul>
    <ul >
      <li ></li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li ><span id="number2">0</span>/3</li>
    </ul>
    <ul >
      <li ></li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li >
        <div ></div>
      </li>
      <li ><span id="number2">0</span>/4</li>
    </ul>

But I want to generate a circle with any number of parts that follow the same layout with a javascript function, with for example:

function generateCircleBorders(n) {
 //Put your code here
}

Is that possible?

CodePudding user response:

You can avoid a lot of math calculations by making use of CSS rotate and clip path.

You do need a little Javascript, to create the clip path we need the tan of an angle (360 degrees minus the gap required) / number of segments.

This method creates as many segments as are required (set the Javascript const num to the number required), rotates them about the center of the circle, clips them and adds an event listener to each.

Note that this method requires an acute angle, so the number of segments has to be 4 or above. If you need help adding the special code for 1-3 let me know.

const num = 3; //set this to the number required
const container = document.querySelector('.container');
container.style.setProperty('--num', num);
container.style.setProperty('--tan', Math.tan(((360 - num * 10) / num) * Math.PI / 180)); //10 is degrees of each gap
for (let i = 0; i < num; i  ) {
  const segment = document.createElement('div');
  segment.style.setProperty('--n', i);
  segment.id = 'Segment'   (i   1);
  container.append(segment);
  segment.addEventListener('click', function() {
    alert(segment.id);
  });
}
container.classList.add('num'   num);
.container {
  --d: 50vmin;
  /* the diameter of the circle */
  --bW: 10%;
  /* the width of the border */
  --r: calc(var(--d) / 2);
  width: var(--d);
  height: var(--d);
  border-radius: 50%;
  position: relative;
  overflow: hidden;
}

.container::after {
  content: '';
  background: white;
  width: calc(100% - var(--bW));
  height: calc(100% - var(--bW));
  position: absolute;
  z-index: 1;
  border-radius: 50%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.container div {
  clip-path: polygon(0 0, 0 var(--r), calc(var(--tan) * var(--r)) 0);
  background: black;
  width: 100%;
  height: 100%;
  position: absolute;
  transform: translateX(var(--r)) rotate(calc((360deg / var(--num)) * var(--n)));
  transform-origin: left center;
}

.container.num1 div {
  transform: translateX(0);
  clip-path: none;
}

.container.num2 div {
  clip-path: polygon(3% 0, 0 var(--r), 3% var(--d), var(--d) var(--d), var(--d) 0);
}

.container.num3 div {
  clip-path: polygon(35% 0, 0 var(--r), 35% var(--d), var(--d) var(--d), var(--d) 0);
}
<div >
</div>

CodePudding user response:

Using a canvas we can easily draw arcs. The trick is to see if mouse is hover a section, but simple geometry should help (distance and angle).

const size = 200;
const n = 7;
const width = 40;


var radius = size / 2 - width / 2

var canvas = document.querySelector("canvas")
canvas.width = size;
canvas.height = size;

var ctx = canvas.getContext("2d");

ctx.clearRect(0, 0, size, size);

var arc = 360 / n;
var rad = Math.PI / 180;


function draw_circle(color) {
  for (var i = 0; i < n; i  ) {
    draw_arc(i, color)
  }
}

function draw_arc(i, color) {
  ctx.beginPath();
  ctx.lineWidth = width;
  ctx.strokeStyle = color;
  ctx.arc(size * 0.5, size * 0.5, radius, arc * i * rad, arc * (i   0.95) * rad, false);
  ctx.stroke();
  ctx.closePath();
}


draw_circle("black");
canvas.addEventListener('mousemove', function(ev) {
  var cx = ev.offsetX
  var cy = ev.offsetY

  var x = size / 2 - cx;
  var y = size / 2 - cy;

  var distance = Math.sqrt(x * x   y * y);

  var alpha = (Math.atan2(y, x) / rad   180) % 360

  var arc = Math.floor(alpha / 360 * n)

  draw_circle("black");
  if (Math.abs(distance - radius) < width / 2) {
    draw_arc(arc, "red");
  }

})
<canvas></canvas>

  • Related