I have a free jQuery image gallery that I am trying to make some modifications to to make it suit my project.
The gallery is a spinning circle with images.
The radius of the circle is defined in this manner:
radius = Math.round( (250) / Math.tan( Math.PI / itemLength ) );
However what I need is to make a new radius based on viewportwidth (vw)
Can anyone help me approach this correctly?
Also I would be very appreciative if someone would help me understand what is happening in the above code.
Here is the context for that line of code:
w = $(window);
container = $( '#contentContainer' );
carousel = $( '#carouselContainer' );
item = $( '.carouselItem' );
itemLength = $( '.carouselItem' ).length;
fps = $('#fps');
rY = 360 / itemLength;
radius = Math.round( (250) / Math.tan( Math.PI / itemLength ) );
https://jsfiddle.net/mxp5svjx/
here is a picture as requested:
the main problem is when i resize the window then radius of the circle stays the same.
here is a working demo:
http://codepen.io/johnblazek/full/nceyw/
I could be wrong but I think
Math.tan( Math.PI / itemLength )
is calculating the angle of each segment, the higher the value of itemLength gets, the smaller the angle. All items need to fit in the circle. The tan function generates a value depending on the angle value.
Then 250 is divided by the former result.
I guess swapping 250 with vw results in too high a value.
If you know the viewwidth it looks good on already then you can try something like:
radius = Math.round( (250 * (vw/default_vw) ) / Math.tan( Math.PI / itemLength ) );
I Found out the Key is 250. 250 is 13.02% of 1920 assuming you have a 1920px width window which I do. So i fiqured out I need 13.02% of window width.
I have obtained that by doing this:
radius = Math.round10( (($(window).width()) * 0.1302) / Math.tan( Math.PI / itemLength ) );
Math.round10(); // rounds to the nearest decimal.
$(window).width(); // is the width of the window. In my case 1920px
0.1302 is 13.02% // when you multiply it with something.
Final result is that I get a radius based on 13.02vw
Related
I want to overlay historic aerial photographs onto a map, using the image rotation available in IIIF. The problem that I am facing is that using code such as in http://jsfiddle.net/jamesinealing/tr7obasm/ I need to manually calculate the NW and SE points, which alter based on the rotation, in advance of placing the image on the map.
What I am looking to do is to calculate the pixel dimensions of the new rotated image (the bounding box, if you like) and then use those to at least get something approximate for the lat lng coordinates, which I can then tweak.
My test code for the calculation is at http://jsfiddle.net/jamesinealing/ehp65gy1/ (based on https://stackoverflow.com/a/17453766)
var rotation=30;
var angle=rotation;
// var angle=((360-rotation) % 180);
var imgWidth=300;
var imgHeight=224;
w = Math.sin(angle * Math.PI/180) * imgHeight + Math.cos(angle * Math.PI/180) * imgWidth;
h = Math.sin(angle * Math.PI/180) * imgWidth + Math.cos(angle * Math.PI/180) * imgHeight;
The problem is that it only works up to a 90 degree angle, whilst the IIIF rotation is any value 0-359. I appreciate that any value 180 or above will yield the same results, so some sort of modulus is needed anyway, but can't get my head around why it isn't working over 90 degrees!
The dimensions of the new box only vary according to angle % 90, i.e. between 300*224 and 224*300 on an ellipse, so you could just use Math.abs with the adjusted angle and some if statements to work out which way round it should be.
Is there any way to restrict the panning movement of a camera in scene?
Tried altering the pan method in orbitControls but I'm not really satisfied with the result, I wish there was more convenient/proper way to do it..
if ( scope.object instanceof THREE.PerspectiveCamera ) {
// perspective
var position = scope.object.position;
var offset = position.clone().sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
// we actually don't use screenWidth, since perspective camera is fixed to screen height
var dist_l = ( 2 * deltaX * targetDistance / screenHeight );
var dist_u = ( 2 * deltaY * targetDistance / screenHeight );
/////// X,Y limit calculation //////
var limit = 100;
if( (position.x - dist_l) <= -limit ){
dist_l = -0.1;
}else if( (position.x - dist_l) >= limit){
dist_l = 0.1;
}
if( (position.z - dist_u) <= -limit ){
dist_u = -0.1;
}else if( (position.z - dist_u) >= (limit*2.5) ){
dist_u = 0.1;
}
/////// X,Y limit calculation //////
scope.panLeft( dist_l );
scope.panUp( dist_u );
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
// orthographic
scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth );
scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight );
}
I have encountered the same problem. The solution is not to touch the pan() function but to check the limits in the update() function. Locate the line 162:
// move target to panned location
scope.target.add( panOffset );
Do your limit calculations right after this line:
if (scope.target.x > 1000)
scope.target.setX(1000);
if (scope.target.x < 0)
scope.target.setX (0);
...
This will clamp the target x-position. It works quite smoothly.
I have the exact same problem and thanks to David's solution, which gives me a lot of inspiration. I've some add up to David's answer:
If we only set target X, when keep panning to that limit, I have some unwanted rotation effect. This is because OrbitControls is working with 2 things: the target and the camera. To solve that, we need to set both target and the camera.
scope.target.setX(0);
camera.position.setX(0);
In this way, we guarantee the camera is always on the top of the object, hence no unwanted rotation happens.
If we want to keep the current rotation angle, we need to do some math. For example in my case, I only enabled the polar rotation:
let polarAngle = scope.getPolarAngle();
scope.target.set(0, camera.position.y + camera.position.z * Math.tan(polarAngle), 0);
camera.position.setX(0);
The idea is to set both target and camera position, but don't try to change the rotation angle. If there is rotation, do some math to calculate the target position first.
I'm building an app in which I present some planes with textures. However, I would like to calculate the radius of the helix (which I use in my calculations to create a helix), dynamically based on the frustum width and the camera position.
The helix is positioned at the center of the screen x=0, y=0, z=0.
I would like this to take under consideration the screen orientation (landscape/ portrait).So far this is the code I have but it seems that I'm missing something because the planes at the left and the right are not inside the viewport.
App.prototype.calculateHelixRadius = function(){
// plane width = height = 512;
var friend = this.getFriend();
var vFOV = friend.camera.fov * Math.PI / 180;
var dist = utils.getAbsPointsDistance3D(friend.camera.position, friend.scene.position);
var aspect = friend.settings.container.clientWidth / friend.settings.container.clientHeight;
var frustumHeight = 2.0 * dist * Math.tan(0.5 * vFOV);
var frustumWidth = frustumHeight * aspect;
return utils.isLandscape() ? frustumHeight / 2 : frustumWidth / 2 ;
};
What am I doing wrong and why are the planes at the edges of the screen not inside?
Also for reference here is the code of getAbsPointsDistance3D
var utils = {
// other helpers...
getAbsPointsDistance3D: function(p1, p2) {
var xd = p2.x - p1.x;
var yd = p2.y - p1.y;
var zd = p2.z - p1.z;
return Math.sqrt(xd * xd + yd * yd + zd * zd);
}
};
update
I tried decreasing the dist parameter but the results are not consistent...
I wonder if the following explains your clipping.
You calculate your frustum characteristics, then calculate the helix radius using, say, the frustum width (width or height depending on the screen aspect...I may be getting some of the particulars wrong here because your question does not completely explain the details, but the general concepts still hold). The image below is a top view of the scenario which shows a circle representing the cylinder that encloses the helix. I believe you have calculated radius1. If so, note that there will be clipping of the cylinder (the shaded area), and thus the helix, in "front" of the cylinder centre.
Instead you need to calculate the cylinder/helix radius as shown in the second image, i.e. you need radius2. If the large angle at the image left is fov (again, vFOV? or hFOV?, etc., depending on whether your helix is going up-down or side-to-side, etc.), then its half angle is fov/2. This is the same angle shown in the centre of the cylinder. Thus, you need to decrease your helix radius as follows: radius2 = radius1 * cos(fov/2).
I have some code that tweens an object towards the camera and fits to half the screen
var vFOV = camera.fov * Math.PI / 180;
var ratio = 2 * Math.tan( vFOV / 2 );
var screen = ratio * (window.innerWidth * 0.6 / window.innerHeight * 0.6) ;
var size = getCompoundBoundingBox( object ).max.y;
var width = getCompoundBoundingBox( object ).max.x;
var dist = (size/screen) * (object.scale.x * 2);
//get final position in front of camera
var pLocal = new THREE.Vector3( 0, 0, -dist );
//apply the direction the camera is facing
var target = pLocal.applyMatrix4( camera.matrixWorld );
//tween the object towards the camera
var tweenMove = new TWEEN.Tween(object.position).to(target, 1500).easing(TWEEN.Easing.Cubic.InOut);
The next thing I need to do is able able to move it either to the left or up, for other UI on the screen and the responsive element.
i.e. to move it to the left 3rd, or top third. It also needs to still be square onto the camera.
I've tried changing the pLocal value to something like (1, 0, - dist) but this just rotates the object when it tweens up.
Any ideas how I can add that functionality?
Solved by adding a new look position to left of camera
In Three.js I'm using this formulas to calculate visible width & height
var vFOV = camera.fov * Math.PI / 180; // convert vertical fov to radians
var height = 2 * Math.tan( vFOV / 2 ) * dist; // visible height
var aspect = window.width / window.height;
var width = height * aspect; // visible width
And with that I calculate the camera zoom required for object to fit exactly into render area by WIDTH
var zoom = (ObjectHeight/aspect) / (2*Math.tan(vFOV/2)) + ObjectDepth;
How do I calculate the camera zoom required for object to fit exactly into render area by HEIGHT?
Thanks to GuyGood, I found the solution:
var zoom = (ObjectHeight/2) / Math.tan(vFOV/2) - ObjectDepth;
I am doing the following which is based on the boundingSphere radius:
geometry.computeBoundingSphere();
radius = geometry.boundingSphere.radius;
distanceFactor = Math.abs( aspect * radius / Math.sin( fov/2 );
This is based on this stuff right here and I hope i interpreted it the right way:
http://www.flipcode.com/forums/thread/4172
This distanceFactor is the factor you need to move the camera along its viewing direction to fit it correctly. At the moment i am not sure if it is by height or width but maybe it helps you figure it out. :)