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

Rodric MacOliverResearcherAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
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?
0
Rodric MacOliverResearcherAuthor Commented:
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
0
Julian HansenCommented:
What is the process for navigating back?

Will one of the child circles be a back link?
0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

Rodric MacOliverResearcherAuthor Commented:
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...
0
Julian HansenCommented:
Some questions

How many levels must this go down to
How are you loading the levels - are these preloaded or are they generated
0
Rodric MacOliverResearcherAuthor Commented:
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
0
Julian HansenCommented:
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.
0
Rodric MacOliverResearcherAuthor Commented:
julianH, yep, it seem to be what I need...
:)
The parent can disappear, I'll figura a way go back without it...
Cheers
0
Julian HansenCommented:
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
0
Julian HansenCommented:
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

0
Julian HansenCommented:
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

0
Rodric MacOliverResearcherAuthor Commented:
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
0
Julian HansenCommented:
Did you have a look at the online sample - that has all the working code in it. Recommend you do a view source on that and see what is different.

http://www.marcorpsa.com/ee/t717.html

I suspect the problem is that in my code I call a php script getsubmenu.php that just returns a JSON array of numbers
<?php
$return = array(
	1,2,3,4,5,6);
die(json_encode($return));
?>

Open in new window

This represents the AJAX call to get the next menu. I don't know how your menu data works so you will have to modify this to your specific situation.
However, check the link above first and see if that functionality is what you were looking for - after that we can look at how to apply it specifically to your situation.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Rodric MacOliverResearcherAuthor Commented:
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
0
Julian HansenCommented:
You are welcome - thanks for the points
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
jQuery

From novice to tech pro — start learning today.