2

I am having a problem with the following code snippet: https://codepen.io/Vreesie/pen/yLxmYrQ

This code snippet shows you the following pattern: enter image description here

These dots are placed in a circular pattern. However, in the SCSS file I have hard coded that the number of nodes will be 6:

.cluster {
  $count: 6;
  @include on-circle($item-count: $count, $circle-size: 300px, $item-size: 100px);
   
  .node {
    display: block;
    position: absolute;
    top:  50%; 
    left: 50%;
    width:  100px;
    height: 100px;
    border-radius: 50%;
    background-color: #1F1F1F;
    border: #137FE3 3px solid;
  }
}

What I actually want is to dynamically determine the number of nodes using a selector. So when I remove/add a node, the pattern will adjust to the number of nodes. I can't really find anything about storing the number of items in a variable. I tried stuff like this:

$count: 0;
@for $i from 1 through 10 {
  .node:has(.node:nth-child(#{$i})) {
    $count: $count + 1;
  }
}

Here my idea was to loop 10 times (max number of nodes). If the node really does exist then add the counter, but this always returned 10 and not 6 in my case. How can I get this to work in SCSS so that I only need to modify my HTML?

A. Vreeswijk
  • 822
  • 1
  • 19
  • 57

1 Answers1

1

Storing a dynamic variable in the way you describe doesn't work in CSS.

Instead, for an alternative solution, this answer describes how you can target children of an element that has a specific number of children. In essence:

div:first-child:nth-last-child(#{$item-count}),
div:first-child:nth-last-child(#{$item-count}) ~ div {
    /* ... */;
}

will target all divs that are direct children of elements containing exactly $item-count number of children.

This can be applied to your situation. You can then generate rules for every permutation of node count up to a maximum. Each rule will contain a slightly different angle specific to the number of nodes, allowing transforms to be created that are perfectly set for the number of nodes being shown:

.node {
    $maximum: 20;
    $circle-size: 300px;
    $item-size: 100px;
    
    display: block;
    position: absolute;
    top:  50%; 
    left: 50%;
    width:  $item-size;
    height: $item-size;
    border-radius: 50%;
    background-color: #1F1F1F;
    border: #137FE3 3px solid;
    margin: -($item-size / 2);
    
    @for $item-count from 1 through $maximum {
        $angle: (360 /  $item-count);
        $rot: 0;
        
        &:first-child:nth-last-child(#{$item-count}),
        &:first-child:nth-last-child(#{$item-count}) ~ div {
            @for $i from 1 through $item-count {
                &:nth-of-type(#{$i}) {
                    transform: 
                        rotate($rot * 1deg) 
                        translate($circle-size / 2) 
                        rotate($rot * -1deg);
                }
                $rot: $rot + $angle;
            }
        }
    }
}

Adding or removing nodes in HTML (up to a maximum of 20) will cause the rotations to be automatically recalculated so that the nodes remain in a circle.

Here is a codepen that implements this in SASS.

jla
  • 4,191
  • 3
  • 27
  • 44
  • Yes this worked, thanks! One extra question. How can I apply filters, so let's say I also have these divs: `
    ` and `
    `. I don't want these nodes to be included in the circle count or anything
    – A. Vreeswijk Apr 03 '23 at 07:10
  • @A.Vreeswijk if the container will always have one `.template` and one `.empty` node then you can simply change the angle from `360 / $item-count` to `360 / ($item-count - 2)`. If the container may not contain any nodes with `.template` or `.empty` or may contain many, then I'm not sure that's possible with CSS/SASS alone. You may need a JavaScript solution. – jla Apr 03 '23 at 07:31