What is the best way to ensure that circles only touch each other by their edges?

Trying to align three circles touching each other has been a challenge for me. Although I have successfully managed to make two touch, the third one remains elusive. How can I ensure that all three circles are in contact with each other, especially when the radius of each circle is subject to change?

I had considered using absolute positioning, but I'm uncertain about how it would interact with dynamic radii.

If anyone has suggestions or guidance on achieving this, I would greatly appreciate it.

View CodeSandbox

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Static Template</title>
    <style>
      .circle-diagram {
        height: 100%;
        min-height: 190px;
      }
      .circle-diagram .solar-grid-wrapper {
        display: flex;
      }
      .circle-diagram .yellow-circle,
      .circle-diagram .yellow-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 130px;
        height: 130px;
        background-color: #feda02;
      }
      .circle-diagram .green-circle,
      .circle-diagram .green-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 91.05px;
        height: 91.05px;
        background-color: #25dc8a;
        left: 124px;
        top: 15px;
      }
      .circle-diagram .blue-circle,
      .circle-diagram .blue-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 119.8px;
        height: 119.8px;
        background: #3d7ff9;
        left: 108px;
        top: 106px;
      }
      .circle-diagram .symbol {
        height: 15px;
        margin-bottom: 8px;
      }
      .circle-diagram .value {
        z-index: 10;
        opacity: 1;
        font-weight: 550;
      }

      #randomButton {
        margin-top: 60px;
        border: 1px solid black;
        background: #3d7ff9;
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <div class="circle-diagram">
      <div class="solar-grid-wrapper">
        <div
          class="yellow-circle"
          id="circle1"
          style="width: 150px; height: 150px;"
        >
          <div class="value">Cool text 1</div>
        </div>
        <div
          class="blue-circle"
          id="circle2"
          style="width: 160px; height: 160px;"
        >
          <div class="value">Cool text 2</div>
        </div>
      </div>
      <div
        class="green-circle"
        id="circle3"
        style="width: 222px; height: 222px;"
      >
        <div class="value">Cool text 3</div>
      </div>
    </div>

    <button id="randomButton">Random Width</button>
  </body>
  <script>
    document.getElementById("randomButton").addEventListener(
      "click",
      function() {
        function random(min, max) {
          return Math.round(Math.random() * Math.abs(max - min) + min);
        }
        const randomNumber1 = random(150, 220);
        const randomNumber2 = random(150, 220);
        const randomNumber3 = random(150, 220);
        document.getElementById("circle1").style.width = `${randomNumber1}px`;
        document.getElementById("circle1").style.height = `${randomNumber1}px`;
        document.getElementById("circle2").style.width = `${randomNumber2}px`;
        document.getElementById("circle2").style.height = `${randomNumber2}px`;
        document.getElementById("circle3").style.width = `${randomNumber3}px`;
        document.getElementById("circle3").style.height = `${randomNumber3}px`;
      },
      false
    );
  </script>
</html>

Answer №1

document.getElementById("randomButton").addEventListener(
  "click",
  function() {
    function random(min, max) {
      return Math.round(Math.random() * Math.abs(max - min) + min);
    }
    const r1 = random(150, 220);
    const r2 = random(150, 220);
    const r3 = random(150, 220);
    var circle1 = document.getElementById("circle1"),
      circle2 = document.getElementById("circle2"),
      circle3 = document.getElementById("circle3");
   
    var h =(r1>r2)? Math.sqrt((r1/2+r3/2)*(r1/2+r3/2)-r1*r1/4):Math.sqrt((r2/2+r3/2)*(r2/2+r3/2)-r2*r2/4),
    h2 = (r1>r2)? (r1+r3)/2:(r2+r3)/2,
    alpha = (r1>r2)?r1/r2:r2/r1;
    
    circle3.style.left =`${alpha*(h-h2)}px`;
    circle3.style.top =`${(5/4)*alpha*(r1-r2)/2}px`;
    
    circle1.style.width = `${r1}px`;
    circle1.style.height = `${r1}px`;
    circle2.style.width = `${r2}px`;
    circle2.style.height = `${r2}px`;
    circle3.style.width = `${r3}px`;
    circle3.style.height = `${r3}px`;
  },
  false
);
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.circle-diagram {
  display: flex;
  align-items: center;
 
}

.circle-diagram .solar-grid-wrapper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: gray;
}

.circle-diagram .yellow-circle,
.circle-diagram .yellow-circle-shadow {
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  font-size: 12px;
  width: 130px;
  height: 130px;
  background-color: #feda02;
  position: relative;
}

.circle-diagram .green-circle,
.circle-diagram .green-circle-shadow {
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  font-size: 12px;
  background-color: #25dc8a;
  position: relative;
  top: 0;
}

.circle-diagram .blue-circle,
.circle-diagram .blue-circle-shadow {
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  font-size: 12px;
  width: 119.8px;
  height: 119.8px;
  background: #3d7ff9;
  position: relative;
}

.circle-diagram .symbol {
  height: 15px;
  margin-bottom: 8px;
}

.circle-diagram .value {
  z-index: 10;
  opacity: 1;
  font-weight: 550;
}

#randomButton {
  margin-top: 60px;
  border: 1px solid black;
  background: #3d7ff9;
  padding: 10px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Static Template</title>
</head>

<body>
  <div class="circle-diagram">
    <div class="solar-grid-wrapper">
      <div class="yellow-circle" id="circle1" style="width: 160px; height: 160px;">
        <div class="value">Cool text 1</div>
      </div>
      <div class="blue-circle" id="circle2" style="width: 150px; height: 150px;">
        <div class="value">Cool text 2</div>
      </div>
    </div>
    <div class="green-circle" id="circle3" style="width: 222px; height: 222px;top:7.5Px;left:-18px;">
      <div class="value">Cool text 3</div>
    </div>
  </div>

  <button id="randomButton">Random Width</button>
</body>

</html>

Answer №2

Uncertain if this is what you're looking for, but here's a customized example featuring circles touching each other:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Modified Sample</title>
    <style>
      .circle-diagram {
        height: 100%;
        min-height: 190px;
      }
      .circle-diagram .solar-grid-wrapper {
        display: flex;
      }
      .circle-diagram .yellow-circle,
      .circle-diagram .yellow-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 130px;
        height: 130px;
        background-color: #feda02;
      }
      .circle-diagram .green-circle,
      .circle-diagram .green-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 91.05px;
        height: 91.05px;
        background-color: #25dc8a;
        left: 124px;
        top: 15px;
      }
      .circle-diagram .blue-circle,
      .circle-diagram .blue-circle-shadow {
        border-radius: 50%;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        color: #fff;
        font-size: 12px;
        width: 119.8px;
        height: 119.8px;
        background: #3d7ff9;
        left: 108px;
        top: 106px;
      }
      .circle-diagram .symbol {
        height: 15px;
        margin-bottom: 8px;
      }
      .circle-diagram .value {
        z-index: 10;
        opacity: 1;
        font-weight: 550;
      }

      #randomButton {
        margin-top: 60px;
        border: 1px solid black;
        background: #3d7ff9;
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <div class="circle-diagram">
      <div class="solar-grid-wrapper">
        <div
          class="yellow-circle"
          id="circle1"
          style="width: 150px; height: 150px"
        >
          <div class="value">Awesome text 1</div>
        </div>
        <div
          class="blue-circle"
          id="circle2"
          style="width: 160px; height: 160px;margin-left: -10px"
        >
          <div class="value">Awesome text 2</div>
        </div>
      </div>
      <div
        class="green-circle"
        id="circle3"
        style="width: 222px; height: 222px;margin-top: -30px"
      >
        <div class="value">Awesome text 3</div>
      </div>       
    </div>

    <button id="randomButton">Random Width</button>
  </body>
  <script>
    document.getElementById("randomButton").addEventListener(
      "click",
      function() {
        function random(min, max) {
          return Math.round(Math.random() * Math.abs(max - min) + min);
        }
        const randomNumber1 = random(150, 220);
        const randomMargin2 = random(10, randomNumber1 / 4);
        const randomNumber2 = random(150, 220);
        const randomNumber3 = random(150, 220);
        const randomMargin3 = random(10, randomNumber2 / 4);
        document.getElementById("circle1").style.width = `${randomNumber1}px`;
        document.getElementById("circle1").style.height = `${randomNumber1}px`;
        document.getElementById("circle2").style.width = `${randomNumber2}px`;
        document.getElementById("circle2").style.height = `${randomNumber2}px`;
        document.getElementById("circle2").style.marginLeft = `-${randomMargin2 }px`;
        document.getElementById("circle3").style.width = `${randomNumber3}px`;
        document.getElementById("circle3").style.height = `${randomNumber3}px`;
        document.getElementById("circle3").style.marginTop = `-${randomMargin3 }px`;
      },
      false
    );
  </script>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a GWT-compatible solution for implementing the Google Visualization - Annotation Chart

I am currently using the newly launched Annotation Chart in GWT by integrating native JavaScript. I have managed to display the example chart successfully, but unfortunately, it lacks interactivity and behaves more like an image. Can anyone provide guidanc ...

Encountered a cross-domain error with node.js and jQuery: ERR_CONNECTION_REFUSED

Just beginning my journey with Node.js. I've set up a basic node/express application that serves a single webpage featuring a button. When clicked, this button triggers a jQuery ajax request to an Express route. The route callback then makes an http ...

Exploring secure routes in Node.js with test cases using Mocha and Chai?

The function verifies whether the route is accessible or not function checkSessionCookieValidity(req, res, next) { if (!isValid(req.session)) { return res.status(401).json({ isLoggedIn: false }); } return next ...

The issue with Array.prototype.join in Internet Explorer 8

In my current working scenario, I encountered an issue with the following code snippet. It performs well in the latest versions of Internet Explorer (IE), but the join function fails to work correctly in IE 8 Version. <!DOCTYPE html> <html xmlns= ...

Unable to access static library Java Script file path using NSBundle

I have integrated a static compiled library into my project, which includes a JavaScript resource. At a specific event in my app, I need to execute the JavaScript file from this library. However, I am facing an issue where the path to the JS file appears ...

The background image fails to display on the button

Why isn't the background image for my button appearing when set using a CSS rule? I have a button with the class "todo" and although other parts of the rule work, the image itself does not show up even after trying "background: url" and "background-im ...

Unable to alter the dimensions of the `symbol` element from an external SVG using CSS, although the other `symbol` within the same document is responsive to styling changes

Could someone help me find the bug in my code related to resizing SVG symbols with CSS? I am able to resize one <symbol> from an external SVG file, but not another <symbol> from the same file. In my CSS, I am trying to change the width and hei ...

Automate brush control and transmit pertinent data through coding

Extending on the query from yesterday's thread, I am working towards implementing multiple brushes. While my current brute force method is functional, I require additional functionality to programmatically manage each of these newly created brushes. ...

Adjusting the input in a Textfield within React using Material UI

const [formData, setFormData] = useState({}); useEffect(() => { fetch("/formdata") .then((res) => res.json()) .then((data) => setFormData(data)); }, []); console.log("Form Data", formData); //Sorting by order let attr; ...

Is there a method to directly download large files from the server without having to wait for the blob response?

I'm currently working on video file requests using axios. I have set the requests with responseType: blob to create a video player once the response is received with window.URL.createObjectUrl(). However, I also have a button that allows the user to d ...

Tips for toggling the visibility of a revolution slider based on current time using JavaScript

Currently, I am integrating the revolution slider into my WordPress website. My goal is to have the slider change according to the standard time of day. For instance, I want slider1 to display in the morning, slider2 at noon, slider3 in the evening, and sl ...

React - Issue with automatic resizing of divs

Currently, I am delving into the realm of ReactJS and have embarked on a small project to enhance my skills. My main goal is to create a resizable div element that can be adjusted by dragging it across the screen. Here is the snippet of code that I have be ...

Creating a Node.js application using Express requires careful consideration of file structure and communication methods

Struggling to pass login form credentials to existing JavaScript files for logic and info retrieval. Login page contains a form with POST method. main.js handles the login: main.js module.exports = { returnSessionToken: function(success, error) { ...

Mini-navigation bar scrolling

I am trying to create a menu where I want to hide elements if the length of either class a or class b is larger than the entire container. I want to achieve a similar effect to what Facebook has. How can I make this happen? I have thought about one approac ...

AJAX/PHP causing delays due to lag problems

I've been trying to implement an asynchronous call in my PHP script, but I keep running into the same issue: "Maximum call stack size exceeded." This is causing severe lag on my site and I suspect there might be a loop somewhere in my code that I just ...

Ways to handle errors when using navigator.clipboard.writeText

document.queryCommandSupported('copy') may not be available on all browsers. I experimented with the code below, which successfully copies the link on Firefox but fails on Opera. It displays an alert indicating that the code has been copied, yet ...

Utilizing window.matchMedia in Javascript to retain user selections during page transitions

I am encountering difficulties with the prefers-color-scheme feature and the logic I am attempting to implement. Specifically, I have a toggle on my website that allows users to override their preferred color scheme (black or light mode). However, I am fac ...

Tips for dynamically filling HTML content with Ajax calls

I'm currently in the process of creating a website for my semester project, and I need to dynamically populate HTML content from an AJAX response. The data I'm receiving is related to posts from a database, but I specifically need to display 5 jo ...

Having trouble reaching the elements stored in an array?

As a beginner in Angular and JavaScript, I may be making some obvious mistakes so please bear with me. I have written this code that allows the selection of 2 text files and then combines them into a single array. $scope.textArray = []; $scope.textUpload ...

Retrieve data from FileReader's onload event asynchronously in Javascript

Although this question has been asked numerous times before, I have reviewed the answers provided and still cannot get my code to work. I am working with Angular 2. I have input tags for file insertion. The file successfully reaches the component, but when ...