A method to dynamically render circular sectors without using HTML5 canvas
P粉731861241
P粉731861241 2023-09-02 10:43:07
0
1
523
<p>I'm making a fortune wheel and I need to create a wheel or circle based on the number of sectors and fill it with the prize name. </p> <p>I have completed the code for a circle with a fixed number of sectors. Here is an example of a circle containing 6 sectors. </p> <p> <pre class="brush:css;toolbar:false;">.wheel_container { position: relative; --wheel-size: 360px; width: var(--wheel-size); height: var(--wheel-size); margin-bottom: 2.4em; } .wheel { display: flex; justify-content: center; position: relative; overflow: hidden; width: 100%; height: 100%; border-radius: 50%; background-color: aquamarine; --segment-deg: 60deg; } .wheel div { display: flex; justify-content: center; align-items: center; position: absolute; width: calc((2 * 3.141592653589793 * (var(--wheel-size) / 2)) / 6); height: 50%; clip-path: polygon(0 0, 50% 100%, 100% 0); transform-origin: bottom; writing-mode: vertical-rl; } .wheel div > span { font-weight: 500; font-size: 1rem; text-align: center; color: rgba(0, 0, 0, 0.7); } .wheel div:nth-child(1) { background-color: beige; transform: rotate(calc(-1 * var(--segment-deg) / 2)); } .wheel div:nth-child(2) { background-color: blueviolet; transform: rotate(calc(-3 * var(--segment-deg) / 2)); } .wheel div:nth-child(3) { background-color: crimson; transform: rotate(calc(-5 * var(--segment-deg) / 2)); } .wheel div:nth-child(4) { background-color: orange; transform: rotate(calc(-7 * var(--segment-deg) / 2)); } .wheel div:nth-child(5) { background-color:violet; transform: rotate(calc(-9 * var(--segment-deg) / 2)); } .wheel div:nth-child(6) { background-color: yellow; transform: rotate(calc(-11 * var(--segment-deg) / 2)); }</pre> <pre class="brush:html;toolbar:false;"><div class='wheel_container'> <div class='wheel'> <div><span>Apple</span></div> <div><span>Durian</span></div> <div><span>Banana</span></div> <div><span>Mango</span></div> <div><span>Strawberry</span></div> <div><span>Jackfruit</span></div> </div> </div></pre> </p> <p>I tried to determine the <code>width</code> property of the <code>.wheel div</code> by calculating the circumference of the wheel divided by the number of sectors. However, this doesn't work because the polygon in <code>clip-path</code> is not curved, while the <code><div></code> that contains it is still a box. </p> <p>I was able to achieve the effect I wanted of 6 sector circles by adding some pixels to the width of <code><div></code>. </p> <p> <pre class="brush:css;toolbar:false;">.wheel_container { position: relative; --wheel-size: 360px; width: var(--wheel-size); height: var(--wheel-size); margin-bottom: 2.4em; } .wheel { display: flex; justify-content: center; position: relative; overflow: hidden; width: 100%; height: 100%; border-radius: 50%; background-color: aquamarine; --segment-deg: 60deg; } .wheel div { display: flex; justify-content: center; align-items: center; position: absolute; /* Modification */ width: calc((2 * 3.141592653589793 * ((var(--wheel-size) 37px) / 2)) / 6); height: 50%; clip-path: polygon(0 0, 50% 100%, 100% 0); transform-origin: bottom; writing-mode: vertical-rl; } .wheel div>span { font-weight: 500; font-size: 1rem; text-align: center; color: rgba(0, 0, 0, 0.7); } .wheel div:nth-child(1) { background-color: beige; transform: rotate(calc(-1 * var(--segment-deg) / 2)); } .wheel div:nth-child(2) { background-color: blueviolet; transform: rotate(calc(-3 * var(--segment-deg) / 2)); } .wheel div:nth-child(3) { background-color: crimson; transform: rotate(calc(-5 * var(--segment-deg) / 2)); } .wheel div:nth-child(4) { background-color: orange; transform: rotate(calc(-7 * var(--segment-deg) / 2)); } .wheel div:nth-child(5) { background-color:violet; transform: rotate(calc(-9 * var(--segment-deg) / 2)); } .wheel div:nth-child(6) { background-color: yellow; transform: rotate(calc(-11 * var(--segment-deg) / 2)); }</pre> <pre class="brush:html;toolbar:false;"><div class='wheel_container'> <div class='wheel'> <div><span>Apple</span></div> <div><span>Durian</span></div> <div><span>Banana</span></div> <div><span>Mango</span></div> <div><span>Strawberry</span></div> <div><span>Jackfruit</span></div> </div> </div></pre> </p> <p>However, the code that works for 6 sectors will not work for 8 sectors and so on...</p> <p>I think the solution might be in the SVG padding rules using <code>clip-path</code>. However, my knowledge of SVG only goes so far and I need some help. Other solutions are also welcome. </p>
P粉731861241
P粉731861241

reply all(1)
P粉460377540

The problem you are having is that the width and height of the .wheel div are calculated incorrectly. If the height is the radius of the circle: --radius: calc(var(--wheel-size) / 2 );, then the width is width: calc( 2 * var(--radius ) / 1.732);, where 1.732 is Math.sqrt(3). This works for a wheel with 6 parts, where the triangle (for the clipping path) is an equilateral triangle.

In your example, the width is equal to the radius. This is not enough because the div exceeds the circle and you calculated the clipping path based on the size of the div.

To understand what's going on, remove border-radius: 50%; and add a semi-transparent unclipped portion to the wheel (clip-path: none;)

console.log(Math.sqrt(3))
*{margin:0;padding:0}


.wheel_container {
  position: relative;
  
  --wheel-size: 360px;
  width: var(--wheel-size);
  height: var(--wheel-size);
  
  margin-bottom: 2.4em;
}

.wheel {
  display: flex;
  justify-content: center;
  
  position: relative;
  overflow: hidden;
  
  width: var(--wheel-size);
  height: var(--wheel-size);
  
  border-radius: 50%;
  background-color: aquamarine;
  --segment-deg: 60deg;
}

.wheel div {
  display: flex;
  justify-content: center;
  align-items: center;
  
  position: absolute;
  
  
  --radius: calc(var(--wheel-size) / 2 );
  height: var(--radius);
  
  width: calc( 2 * var(--radius ) / 1.732);
  clip-path: polygon(0 0, 50% 100%, 100% 0);
  
  transform-origin: bottom;
  writing-mode: vertical-rl;
}

.wheel div > span {
  font-weight: 500;
  font-size: 1rem;
  text-align: center;
  color: rgba(0, 0, 0, 0.7);
}

.wheel div:nth-child(1) {
  background-color: beige;
  transform: rotate(calc(-1 * var(--segment-deg) / 2));
}

.wheel div:nth-child(2) {
  background-color: blueviolet;
  transform: rotate(calc(-3 * var(--segment-deg) / 2));
}

.wheel div:nth-child(3) {
  background-color: crimson;
  transform: rotate(calc(-5 * var(--segment-deg) / 2));
}

.wheel div:nth-child(4) {
  background-color: orange;
  transform: rotate(calc(-7 * var(--segment-deg) / 2));
}

.wheel div:nth-child(5) {
  background-color: violet;
  transform: rotate(calc(-9 * var(--segment-deg) / 2));
}

.wheel div:nth-child(6) {
  background-color: yellow;
  transform: rotate(calc(-11 * var(--segment-deg) / 2));
}


..wheel div {transform:none!important}
<div class='wheel_container'>
  <div class='wheel'>
    <div><span>Apple</span></div>
    <div><span>Durian</span></div>
    <div><span>Banana</span></div>
    <div><span>Mango</span></div>
    <div><span>Strawberry</span></div>
    <div><span>Jackfruit</span></div>
  </div>
</div>

In order to do an 8-segment wheel, you will need a --segment-deg:45 and a different .wheel div width. I'm using width: calc( 2 * var(--radius ) / 2.414);, where 2.414 is the tangent of (180 - 45) / 2.

let a = 67.5;
const rad = Math.PI / 180;

console.log((Math.tan( a * rad)))
*{margin:0;padding:0}


.wheel_container {
  position: relative;
  
  --wheel-size: 360px;
  width: var(--wheel-size);
  height: var(--wheel-size);
  
  margin-bottom: 2.4em;
}

.wheel {
  display: flex;
  justify-content: center;
  
  position: relative;
  overflow: hidden;
  
  width: var(--wheel-size);
  height: var(--wheel-size);
  
  border-radius: 50%;
  background-color: aquamarine;
  --segment-deg: 45deg;
}

.wheel div {
  display: flex;
  justify-content: center;
  align-items: center;
  
  position: absolute;
  
  
  --radius: calc(var(--wheel-size) / 2 );
  height: var(--radius);
  
  width: calc( 2 * var(--radius ) / 2.414);
  clip-path: polygon(0 0, 50% 100%, 100% 0);
  
  transform-origin: bottom;
  writing-mode: vertical-rl;
}

.wheel div > span {
  font-weight: 500;
  font-size: 1rem;
  text-align: center;
  color: rgba(0, 0, 0, 0.7);
}

.wheel div:nth-child(1) {
  background-color: beige;
  transform: rotate(calc(-1 * var(--segment-deg) / 2));
}

.wheel div:nth-child(2) {
  background-color: blueviolet;
  transform: rotate(calc(-3 * var(--segment-deg) / 2));
}

.wheel div:nth-child(3) {
  background-color: crimson;
  transform: rotate(calc(-5 * var(--segment-deg) / 2));
}

.wheel div:nth-child(4) {
  background-color: orange;
  transform: rotate(calc(-7 * var(--segment-deg) / 2));
}

.wheel div:nth-child(5) {
  background-color: violet;
  transform: rotate(calc(-9 * var(--segment-deg) / 2));
}

.wheel div:nth-child(6) {
  background-color: yellow;
  transform: rotate(calc(-11 * var(--segment-deg) / 2));
}


.wheel div:nth-child(7) {
  background-color: red;
  transform: rotate(calc(-13 * var(--segment-deg) / 2));
}

.wheel div:nth-child(8) {
  background-color: blue;
  transform: rotate(calc(-15 * var(--segment-deg) / 2));
}
<div class='wheel_container'>
  <div class='wheel'>
    <div><span>Apple</span></div>
    <div><span>Durian</span></div>
    <div><span>Banana</span></div>
    <div><span>Mango</span></div>
    <div><span>Strawberry</span></div>
    <div><span>Jackfruit</span></div>
    
    <div><span>red</span></div>
    <div><span>blue</
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!