user736893
user736893

Reputation:

Dynamically build a 3d cylinder of elements with jquery

UPDATE: I've cleaned this up a lot (I think), but it also seems to be worse. Here is a fiddle with some added features like using arrow keys to rotate the object. This makes it easier to see the problems.

https://jsfiddle.net/scottbeeson/ue4c7ocj/


original question

I'm trying to create a 3D vertical carousel dynamically using JQuery, based on the tutorial and demo here. I'm trying to start out as basic and dynamic as possible, but it's not coming together (literally).

Here is what I have:

function RotaMenu ( e ) {
	this.element = e;
	this.rotation = 0;
	this.panelCount = this.element.children().length;
	this.panelSize = $(this.element).outerHeight();
	this.theta = 360 / this.panelCount;
	this.radius = Math.round( ( this.panelSize / 2) / Math.tan( Math.PI / this.panelCount ) );
	console.log("Created new menu: panelCount=" + this.panelCount + ", panelSize=" + this.panelSize + ", theta=" + this.theta + ", radius=" + this.radius);
}

RotaMenu.prototype.update = function() {
	this.theta = 360 / this.panelCount;
	this.radius = Math.round( ( this.panelSize / 2) / Math.tan( Math.PI / this.panelCount ) );
	for ( i = 0; i < this.panelCount; i++ ) {
		panel = $(this.element).children()[i];
		angle = this.theta * i;
		$(panel).css('transform','rotateX(' + angle + 'deg) rotateY(0deg) translateZ(' + this.radius + 'px)');
	}
};


$(function() {
	var mainmenu = new RotaMenu($('#mainmenu'));
	mainmenu.update();
});
.rmenu {
  margin-top: 100px;
}
.rmenu div {
  border: 1px solid gray;
  width: 100px;
  height: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mainmenu" class="rmenu">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>

Here is what it looks like with 6 children. What am I doing wrong?

enter image description here

Upvotes: 1

Views: 496

Answers (1)

roberto tom&#225;s
roberto tom&#225;s

Reputation: 4687

updated

So now I see on my computer why the version you had before needed the adjustment to radius that I had added earlier. This is because you were correctly calculating based on the height, and of course your goal was vertical. There's only two minor changes to effect this difference: rotateX instead of Y and use the correct radius calculation that you had before. Reflecting those changes I have edited the answer. I believe this will be what you are looking for.

solution

I think your main issue is that you are missing some css that makes it easier to get the basic structure up so you can debug it. You also need the outer container so you can add a camera point for the perspective so the transform looks pretty, otherwise it will look flat.

here's my sample: https://jsfiddle.net/8ymm7xu6/2/

important CSS:

.rmenu {
  position: absolute;
  transform-style: preserve-3d;
  margin-top: 100px;
}
.rmenu div {
  border: 1px solid gray;
  width: 100px;
  height: 20px;
  margin: 0;
  position: absolute;
}
.container {
  position: relative;
  perspective: 1000px;
  display: flex;
  align-items: center;
  justify-content: center;
}

and the html change

<section class="container">
  <div id="mainmenu" class="rmenu">
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>  
</section>

there were also changes to the jquery:

function RotaMenu ( e ) {
    this.element = e;
    this.rotation = 0;
    this.panelCount = this.element.children().length;
    this.panelSize = $(this.element).children().first().outerHeight();
    this.theta = 360 / this.panelCount;
    this.radius = Math.round( ( this.panelSize / 2) / Math.tan( Math.PI / this.panelCount ) )
    console.log("Created new menu: panelCount=" + this.panelCount + ", panelSize=" + this.panelSize + ", theta=" + this.theta + ", radius=" + this.radius);
}

RotaMenu.prototype.update = function() {
    for ( i = 0; i < this.panelCount; i++ ) {
        panel = $(this.element).children()[i];
        angle = Math.round(this.theta * i);
        $(panel).css('transform','rotateX(' + angle + 'deg) translateZ(' + this.radius + 'px)');
    }
};


$(function() {
    var mainmenu = new RotaMenu($('#mainmenu'));
    mainmenu.update();
});
  • panelSize needed to go off the panels, not the panels container
  • radius needed to increase by panelCount
  • no off-axis rotation (At least not yet!)

Upvotes: 1

Related Questions