I'm working on an orbit simulation I have the planet orbiting, but if you look at the inner 3 planets then shift from the orbit's dashed line. On the bottom of the orbit the planet is below the line. At the top of the orbit the planet is either on or above the dashed line.
You can see a working example here.
I think this has to do with the border width not being taken into account but everything I've tried to correct the issue hasn't worked. I'm currently using outerWidth() and outerHeight() but that doesn't seem to be doing the trick.
This is the relevant bit of code:
var width = parseFloat($(this).parent().outerWidth()) / 2;
var height = parseFloat($(this).parent().outerHeight()) / 2;
var point = getPoint(width, height, angle * (Math.PI / 180));
$(this).css('left', point[0] + ($(this).parent().outerWidth() / 2) + 'px');
$(this).css('top', point[1] + ($(this).parent().outerHeight() / 2) + 'px');
The getPoint function is:
function getPoint(width, height, angle)
{
var x = parseFloat(width) * Math.cos(angle);
var y = parseFloat(height) * Math.sin(angle);
return [x, y];
}
You're right - it's the border size. I checked the CSS and it seemed fine, but the smaller planets were visibly off center.
To fix it, all I did was change these lines:
'margin-top' : '-' + ($(this).outerHeight() / 2) + 'px',
'margin-left' : '-' + ($(this).outerWidth() / 2) + 'px'
To this (added two before dividing):
'margin-top' : '-' + (($(this).outerHeight() + 2) / 2) + 'px',
'margin-left' : '-' + (($(this).outerWidth() + 2) / 2) + 'px'
You can see a working example at the updated fiddle here.
UPDATE - seems this isn't totally fixing the problem - as the planets round to the RHS of the orbit, they start to travel to the outer edge. On the up side though, you know that the fix is in those two lines... you just need to compensate for the position in the right amount, which I believe may end up being dynamic or something based on planet position.
Related
I have a slider which consists of iframes that are 1366px x 768px which I scale to fit on window resize. However, when 1366 is divided I can randomly get decimals on the actual width of the element which causes what I call as 'pixel breaking'.
Notice the while line on the second image. This is actually the second slide which is my problem. Example; 1366px becomes 1045.234234px so they don't line up properly.
I know I can also add a width by removing the decimals as parseInt(scaleAmount * 1366) but I don't think that can always be accurate with different resolutions.
Anything I can try to resolve or minimise this?
var $el = $(element);
var elHeight = 768;
var elWidth = 1366;
var $wrapper = $(parent);
function doResize(event, ui) {
var scale, origin;
scale = Math.min(
ui.size.width / elWidth,
ui.size.height / elHeight
);
$el.css({
'transform': "scale(" + scale + ")",
'-webkit-transform': "scale(" + scale + ")"
});
}
Since you're converting to a string, you can just trim off the decimal part of the number using scale.toFixed(0).
OK I think I've resolved it. I convert the transform scale to pixel value. Round up the pixel. And finally, convert the rounded pixel back to a transform scale. So the scaled pixel will always be an even number so therefore the pixels would not break anymore.
scale = Math.min(
ui.size.width / elWidth,
ui.size.height / elHeight
);
var scaleInPixels = scale * elWidth;
var evenPixel = 2 * Math.round(scaleInPixels / 2);
var finalScale = evenPixel / elWidth;
I've read all accepted answers on this topic and repeated exactly the logic used in them but my results seem to be skewed and 'random'.
I have correctly collected the X,Y and degrees from the center object as shown here:
console.log('deg' + degrees + ' - ' + 'x' + parseInt(x) + ', y' + parseInt(y));
Note: The X,Y grid spans much further out of the viewport that is shown. Technically the grid is unlimited in size. We are in our own specific X,Y coordinate in this grid space.
Now I want to calculate an X,Y coordinate that is 1000 pixels away from the click position. Here is an example of what I'm trying to achieve:
The logic I found elsewhere should be as simple as such:
x = 1000 * Math.cos(degrees);
y = 1000 * Math.sin(degrees);
console.log('deg' + degrees + ' - ' + 'x' + parseInt(x) + ', y' + parseInt(y));
The result is as such:
The issue: Clearly in the image above, the X,Y coordinates are way off to what I should be expecting. They are much too low and change too often to random numbers.
The grid for this layout is as shown below:
Note: The X axis goes positive to the left. Is this the underlying issue or is it my original logic that is wrong?
Thank you for considering my question
I've tried the suggested code. Here are my results.
Result from #MBo's now old answer:
new_x = 1000 * Math.cos(degrees * Math.PI / 180);
new_y = 1000 * Math.sin(degrees * Math.PI / 180);
The results look a lot cleaner and less 'random' however the end X,Y go in the incorrect direction and distance
and change too often
Trigonometric functions work with radians rather than degrees, so calculate arguments like this:
Math.cos(degrees * Math.PI / 180);
Math.sin(degrees * Math.PI / 180);
To make rotation around some point, add these values to its coordinates
x = center_object_x + Math.cos(degrees * Math.PI / 180);
y = center_object_y + Math.sin(degrees * Math.PI / 180);
I have an svg country map and I'm trying to achieve the effect when you click on a district and then see an animated scaling relative to selected district, i.e. scaling with transform-origin point in the center of a clicked district. And I would prefer not to use any libraries.
First of all, why here, when we have svg viewBox attribute setted, polygons drawn with getBoundingClientRect() points don't match their actual elements svg, map, e.target?
If we add some coefficients like here, then what viewBoxMapCoefX1 and viewBoxMapCoefX1 we need so the mapPolygon drawn with getBoundingClientRect() points matches actual map element?
When I try to scale map by adding:
// ANIMATION HERE
map.style.transformOrigin = transformOriginX + "px " + transformOriginY + "px";
map.style.transform = "scale(" + scale + ")";
it looks like transformOrigin value is wrong. If I try to change viewBox value by adding:
// ANIMATION HERE
svg.viewBox.baseVal.x = bounding.left;
svg.viewBox.baseVal.y = bounding.top;
svg.viewBox.baseVal.width = bounding.width;
svg.viewBox.baseVal.height = bounding.height;
then how can I make scaling animation with CSS (no SMIL)?
Any help or advice on this is greatly appreciated.
1) You should be using .getBBox() instead of BoundingClientRect to get the coordinates, as this will be based on the SVG itself and not the screen.
3) You are applying the transforms to the group tag, whereas it makes sense for these to be applied to the SVG element itself instead. You may have tried this already, but the transform origin value will all be based on the co-ordinates you're getting previously? So long as the animation works as intended, there is no issue with the animation front from what I can see.
// ANIMATION HERE
var svg = document.querySelector("svg");
svg.style.transformOrigin = '50% 50%';
svg.style.transform = 'scale(4)';
Thanks to #OwenAyres's answer 1 part of question has been solved.
Instead of scaling map straight relative to the selected district center we can find district's center in % insted of px and then move district's center to map's center and then make scale:
// ANIMATION HERE
var transformOriginXPercent = (50 - transformOriginX * 100 / mapBounding.width) * scale;
var transformOriginYPercent = (50 - transformOriginY * 100 / mapBounding.height) * scale;
var scaleText = "scale(" + scale + ")";
var translateText = "translate(" + transformOriginXPercent + "%," + transformOriginYPercent + "%)";
map.style.transformOrigin = "50% 50%";
map.style.transform = translateText + " " + scaleText;
and get expected result.
But there is still a question what coefficients for transformOriginX and transformOriginY are correct to get the result in the following form:
map.style.transformOrigin = (transformOriginX) + "px " + (transformOriginY) + "px";
map.style.transform = "scale(" + scale + ")";
I have this function set up
if (window.innerWidth && window.innerHeight) {
var winW = window.innerWidth;
}
var xM = winW/180;
var axis = 0;
$(window).bind('mousemove',function(e){
var xCoord = Math.floor(e.pageX/xM);
axis = 0.6 * Math.sin(xCoord);
var pageCoords = "( " + e.pageX + ", " + e.pageY + ", " + xCoord + " )";
$("span#showme").text(pageCoords);
});
setInterval(function() {
$("#welcome-background").fadeTo(0, 0.4 + axis);
}, 100);
(for additional reference and working visual- http://jsfiddle.net/ySjqh/2/ )
The code works in theory to divide the page evenly into segments from 0-180, then calculates which segment the mouse appears in. Then uses the Math.sin() function to derive how much opacity to apply, based on a padded starting point of 0.4 opacity (jQuery style), and should use the mouse position to determine how much of the remaining 0.6 to apply based on its distance from center, where mouse at center-page should yield full opacity.
What I don't get is why the script behaves this way, rolling through an entire sine wave when I've limited the input to the Math.sin(x) function to 1 < x < 180. If you replace xCoord with axis in the place where I build the jQuery text for #showme, you'll see that it throws negative numbers- which shouldn't be happening! ... so I don't get what the problem/behavior results from!!! Frustrating!!!
Just use:
xCoord = (xCoord * Math.PI) / 180; // Convert value to Radians
and it works..
Sample
http://jsfiddle.net/ySjqh/4/
axis = 0.6 * (1 - Math.abs(e.pageX - winW/2)/(winW/2));
Using the X distance from the center instead of sin.
My trigonometry is more than weak, and therefore I do not know how to draw a line segment shorter than full lines start point and end point.
http://jsfiddle.net/psycketom/TUyJb/
What I have tried, is, subtract from start point a fraction of target point, but it results in a wrong line.
/*
* this is an excerpt from fiddle, that shows
* the actual calculation functions I have implemented
*/
var target = {
x : width / 2 + 60,
y : 20
};
var start = {
x : width / 2,
y : height
};
var current = {
x : 0,
y : 0
};
var growth = 0.5;
current.x = start.x - (target.x * growth);
current.y = start.y - (target.y * growth);
My bet is that I have to use sin / cos or something else from the trigonometry branch to get it right. But, since my trigonometry is not even rusty, but weak in general, I'm stuck.
How do I draw a proper line to target?
If I understand you correctly, then this should give you what you're looking for:
current.x = start.x + (target.x - start.x) * growth;
current.y = start.y + (target.y - start.y) * growth;
The equation is a linear interpolate, its the same as linear easing. You take the delta of the start and end (min and max), multiply it by a percent (the normal) of how far along delta you are and then you add it back to the start value. Incredibly essential algorithm :)