Link to home
Start Free TrialLog in
Avatar of Rodric MacOliver
Rodric MacOliverFlag for New Zealand

asked on

Lines between circles 2 - Derived question

Hi folks I'm in need to add a few funcionalities in the code below and I'd be very grateful to anyone who could do it. The first thing I need is that when a circle from the second tier that appears is clicked I need for the clicked circle move to the position of the original circle, I also need for the other circles generated by the first circle to hide before the new ones from behind the newly clicked circle to appear.

Well any help would be much appreciated.

Here is the code:

<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>Rodrigo</title>
<style type="text/css">
#circle-container {
  position: relative;
  margin: 0 auto;
  width: 500px;
  height: 500px;
  border: 0px solid green;
}
.circle-wrapper {
  position: absolute;  
  width: 500px;
  height: 500px;
  top: 0;
  left: 0;
}
.circle-wrapper:nth-of-type(1) {
  z-index: 1000
}
.circle {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 40px;
  background: red;
  left: 230px;
  top: 230px;
}
.blue {
  background: blue;
}
.green {
  background: green;
}
.yellow {
  background: yellow;
}
.orange {
  background: orange;
}
.pink {
  background: pink;
}
.purple {
  background: purple;
}
</style>
</head>
<body>
<div id="circle-container">
  <div class="circle-wrapper">
      <div class="circle animate blue"></div>
      <div class="circle animate green"></div>
      <div class="circle animate yellow"></div>
      <div class="circle animate orange"></div>
      <div class="circle animate pink"></div>
      <div class="circle animate purple"></div>
      <div id="circle" class="circle"></div>
  </div>
  <svg id="lines" height="500" width="500"></svg>  
</div>

<script src="jquery.js"></script>

<script>
 var clicked = false;
  var distanceToMove = 100;
  var clickedCircles = [];
  var total_circles = $('#circle-container .circle.animate').length;
  var angle = (Math.PI * 2 / total_circles);
  $('#circle').click(function() {
    if (clicked) return;
    clicked = true;
  var circlePos = $('#circle').position();
  var circlePosTop = circlePos.top + ($('#circle').outerWidth() / 2);
  var circlePosLeft = circlePos.left + ($('#circle').outerHeight() / 2);
    $('#circle-container .circle.animate').each(function(indx, item) {
      var top = distanceToMove * Math.cos(angle*(indx-1));
      var left = distanceToMove * Math.sin(angle *(indx-1));
      $(this).animate({left: "+=" + left, top: "+=" + top}, 1000, function(){;
      var newLine = document.createElementNS('http://www.w3.org/2000/svg','line');
      newLine.setAttribute('x1',circlePosLeft);
      newLine.setAttribute('y1',circlePosTop);
      newLine.setAttribute('x2',Math.floor(circlePosLeft + left));
      newLine.setAttribute('y2',Math.floor(circlePosTop + top));
      newLine.setAttribute('style','stroke:rgb(255,0,0);stroke-width:1');
      $('#lines').append(newLine);
    });
    });
  });
   $('#circle-container .circle.animate').click(function() {
    var thisIndex = $(this).index();
    var thisPos = $(this).position();
    var thisPosTop = thisPos.top + ($(this).outerWidth() / 2);
    var thisPosLeft = thisPos.left + ($(this).outerHeight() / 2);
    if($.inArray(thisIndex, clickedCircles) == -1){
      var circlesClone = $('.circle-wrapper:first').clone();
      $('#circle-container').append('<div id="circle-container_' + thisIndex + '" class="circle-wrapper"></div>');
      $(circlesClone).find('div:last').removeAttr('id');
      $(circlesClone).find('svg').removeAttr('id');
      $(circlesClone).find('div').each(function(indx, item) {
        $(this).css({top: thisPos.top, left: thisPos.left});
        var top = distanceToMove * Math.cos(angle*(indx-1));
        var left = distanceToMove * Math.sin(angle *(indx-1));
        $(this).animate({left: "+=" + left, top: "+=" + top}, 1000, function(){
          var newLine = document.createElementNS('http://www.w3.org/2000/svg','line');
          newLine.setAttribute('x1',thisPosLeft);
          newLine.setAttribute('y1',thisPosTop);
          newLine.setAttribute('x2',Math.floor(thisPosLeft + left));
          newLine.setAttribute('y2',Math.floor(thisPosTop + top));
          newLine.setAttribute('style','stroke:rgb(255,0,0);stroke-width:1');
          newLine.setAttribute('class','group' + thisIndex);
          $('#lines').append(newLine);
        });
        $('#circle-container_' + thisIndex).append($(this));
      });
      clickedCircles.push(thisIndex);
    }else{
      var remove = clickedCircles.indexOf(thisIndex);console.log(remove);
      if (remove > -1) {
          clickedCircles.splice(remove, 1);
          }
      $('.group' + thisIndex).remove();
      $('#circle-container_' + thisIndex + ' div').each(function() {    
        $(this).animate({left: thisPos.left, top: thisPos.top}, 1000, function() {
            $('#circle-container_' + thisIndex).remove();
        });
      });     
    }
  });
</script>



</body></html>

Open in new window

Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

I need for the clicked circle move to the position of the original circle
Which is the original - the red circle that appears on page load or the circle that appears when you click one of the circles on the circumference of the first red circle?

The code currently expands out to 16 circles - I am getting the impression that you want to keep a circle in the centre and always expand from that.

Is it correct that you want the following
a) First circle (red) appears on page load
b) Click this - 6 circles appear around the first
c) Click one of the 6 and it moves to the centre (red) circle before showing its children

Is that correct?
Avatar of Rodric MacOliver

ASKER

julianH, yes it seems that what you mentioned is what I want.

The first is the one that is the first to be clicked, and than its children come out from behind it,
When one click on on of its children the others must close (behind the parent from which they appeared) and the parent should disappear;
Then the children that was clicked should move to the center where its parent was and just disappeared and make its own children appear from behind like his parent had before him.

Does that make sense?

Thanks
What is the process for navigating back?

Will one of the child circles be a back link?
julianH, I hadn't thought about that... Maybe instead of the first circle to disappear it should go to the bottom of the screen faded, this way it could always be brought back by clicking on it...

The more important feature is to be abble to go from father to son, and than from son to grandson and so forth...
Some questions

How many levels must this go down to
How are you loading the levels - are these preloaded or are they generated
julianH, they must be loaded with ajax and they are retrieved from a database in a query. I want to have a circlefor each record that the query will return. So the first circle (that is referent to a single query) qill return for example 4 records, so it should show 4 circles coming from him. When you click on the "son" another query is called in ajax and return the number of records and so on...
Theoretically it should be scalable.
Cheers
Ok - that makes sense - was not clear from your code.

This should be relatively straight forward - the only missing piece is what to do with the clicked circle's parent.

Otherwise it is
on click
    get children (AJAX)
    parent retrieves non-clicked siblings - animates them behind itself and removes lines
    animate clicked circle to center
    animate children out - as we have at the moment - and draw lines

Is that in line with what you are wanting.
julianH, yep, it seem to be what I need...
:)
The parent can disappear, I'll figura a way go back without it...
Cheers
Here is a rough samples sans lines - you can put those back in
<!doctype html>
<html>
<head>
<title>Test</title>
<style type="text/css">
#circle-container {
  position: relative;
  width: 500px;
  height: 500px;
  margin: 0 auto;
  border: 1px solid green;
}
.circle {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 40px;
  background: red;
  left: 230px;
  top: 230px;
  z-index: 1;
}
#circle {
  z-index: 2000;
}
.blue {
  background: blue;
}
.green {
  background: green;
}
.yellow {
  background: yellow;
}
.orange {
  background: orange;
}
.pink {
  background: pink;
}
.purple {
  background: purple;
}
</style>
</head>
<body>
<div id="circle-container">
  <div class="circle child blue" data-id="1"></div>
  <div class="circle child green" data-id="2"></div>
  <div class="circle child yellow" data-id="3"></div>
  <div class="circle child orange" data-id="4"></div>
  <div class="circle child pink" data-id="5"></div>
  <div class="circle child purple" data-id="6"></div>
  <div id="circle" class="circle"></div>
</div>
<script src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">
var distanceToMove = 100;

function hideCircles(selected)
{
  $('#circle-container div.circle').each(function(indx, item) {
    if (indx != selected) { 
    $(item).fadeOut(1000, function() {$(this).remove();});
    }
  });
}

function expandCircles()
{
  if ($('#circle').hasClass('expanded')) return;
  $('#circle').addClass('expanded');
  var total_circles = $('#circle-container .circle.child').length;
  var angle = (Math.PI * 2 / total_circles)
  $('#circle-container div.child').each(function(indx, item) {
    var top = distanceToMove * Math.cos(angle*(indx-1));
    var left = distanceToMove * Math.sin(angle *(indx-1)); 
    $(this).animate({left: "+=" + left, top: "+=" + top}, 1000);
  });
}
$(function() {

  $('#circle-container').on('click','#circle', function() {
    expandCircles();
  });
  
  $('#circle-container').on('click','.child', function() {
    var current = $(this);
    var index = $(this).index();
    $.ajax({
      url: 'getsubmenu.php',
      data: {id: $(this).data('id')},
      type: 'POST',
      dataType: 'JSON',
      success: function(response) {
        hideCircles(index);
        current.removeClass('child').attr('id','circle').animate({left: '230px', top: '230px'}, 1000, function() {
          for(i=0; i<response.length;i++) {
            $('#circle-container').append(
              $('<div/>').addClass('circle child type' + i).data('id', response[i])
            );
          }
          expandCircles()
        });
      }
    });
  });
});
</script>
</body>
</html>

Open in new window

Working sample here http://www.marcorpsa.com/ee/t717.html
Slight update to the code above - the above code goes screwy if you click on another circle while it is loading a new menu
Change the hideCircles function to
function hideCircles(selected)
{
  // ADD THE addClass function call
  $('#circle-container div.circle').addClass('closing').each(function(indx, item) {
    if (indx != selected) { 
      $(item).fadeOut(1000, function() {$(this).remove();});
    }
  });
}

Open in new window

And the onclick to
  $('#circle-container').on('click','.child', function() {
    // ADD THIS LINE
    if ($(this).hasClass('closing') || $(this).attr('id') == 'circle') return;
    var current = $(this);
    var index = $(this).index();
    ...

Open in new window

Another slight change - to make the move to center of the selected circle not rely on hard coded co-ordinates
  $('#circle-container').on('click','.child', function() {
	if ($(this).hasClass('closing') || $(this).attr('id') == 'circle') return;
    var current = $(this);
    var index = $(this).index();
    $.ajax({
      url: 'getsubmenu.php',
      data: {id: $(this).data('id')},
      type: 'POST',
      dataType: 'JSON',
      success: function(response) {
        hideCircles(index);

        // ADD THESE TWO LINES AND CHANGE THE ANIMATE LINE
        var left = $('#circle').css('left');
        var top = $('#circle').css('top');
        current.removeClass('child').attr('id','circle').animate({left: left, top: top}, 1000, function() {

          for(i=0; i<response.length;i++) {
            $('#circle-container').append(
              $('<div/>').addClass('circle child type' + i).data('id', response[i])
            );
          }
          expandCircles()
        });
      }
    });
  });

Open in new window

julianH, its not working doing the modifications mentioned above...

The code would be something like this:

<!doctype html>
<html>
<head>
<title>Test</title>
<style type="text/css">
#circle-container {
  position: relative;
  width: 500px;
  height: 500px;
  margin: 0 auto;
  border: 1px solid green;
}
.circle {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 40px;
  background: red;
  left: 230px;
  top: 230px;
  z-index: 1;
}
#circle {
  z-index: 2000;
}
.blue {
  background: blue;
}
.green {
  background: green;
}
.yellow {
  background: yellow;
}
.orange {
  background: orange;
}
.pink {
  background: pink;
}
.purple {
  background: purple;
}
</style>
</head>
<body>
<div id="circle-container">
  <div class="circle child blue" data-id="1"></div>
  <div class="circle child green" data-id="2"></div>
  <div class="circle child yellow" data-id="3"></div>
  <div class="circle child orange" data-id="4"></div>
  <div class="circle child pink" data-id="5"></div>
  <div class="circle child purple" data-id="6"></div>
  <div id="circle" class="circle"></div>
</div>
<script src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">
var distanceToMove = 100;

function hideCircles(selected)
{
  // ADD THE addClass function call
  $('#circle-container div.circle').addClass('closing').each(function(indx, item) {
    if (indx != selected) { 
      $(item).fadeOut(1000, function() {$(this).remove();});
    }
  });
}
                                          

function expandCircles()
{
  if ($('#circle').hasClass('expanded')) return;
  $('#circle').addClass('expanded');
  var total_circles = $('#circle-container .circle.child').length;
  var angle = (Math.PI * 2 / total_circles)
  $('#circle-container div.child').each(function(indx, item) {
    var top = distanceToMove * Math.cos(angle*(indx-1));
    var left = distanceToMove * Math.sin(angle *(indx-1)); 
    $(this).animate({left: "+=" + left, top: "+=" + top}, 1000);
  });
}
$(function() {

  $('#circle-container').on('click','#circle', function() {
    expandCircles();
  });

    
  $('#circle-container').on('click','.child', function() {
    if ($(this).hasClass('closing') || $(this).attr('id') == 'circle') return;
    var current = $(this);
    var index = $(this).index();
    $.ajax({
      url: 'getsubmenu.php',
      data: {id: $(this).data('id')},
      type: 'POST',
      dataType: 'JSON',
      success: function(response) {
        hideCircles(index);
        current.removeClass('child').attr('id','circle').animate({left: '230px', top: '230px'}, 1000, function() {
          for(i=0; i<response.length;i++) {
            $('#circle-container').append(
              $('<div/>').addClass('circle child type' + i).data('id', response[i])
            );
          }
          expandCircles()
        });
      }
    });
  });
});
</script>
</body>
</html>

Open in new window



Doing all that you mentioned above, but it doesn't work...
Cheers
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yep julianH, I think this will work fine. If I need any more help with it I'll post it here. Thanks a lot.
Cheers
You are welcome - thanks for the points