Here is what I have so far
https://jsfiddle.net/0p7zf13x/5/
Here is what I would like to obtain
Text around circle, and tangent to its center
The code is on jsfiddle, but here is a little piece of it.
var count = $("#rollo ul li").length;
var cx = 300;
var cy = 300;
var r = 300;
$("#rollo ul li").each(function(index) {
var theta = 2 * Math.PI * (index / count);
var left = cx + r * Math.sin(theta);
var top = cy - r * Math.cos(theta);
console.log(index, left, top);
$(this).css({ left: left, top: top });
$(this).css({"transform":"rotate("+Math.cos(theta)*-90+"deg)"});
});
I started from this code page
placing divs in a circle
Question : How to make texts around circle and left side of first letter, tangent to that same circle ? All texts evenly distributed.
Thanks
Just use the angle you're generating from:
$(this).css({"transform":"rotate("+(theta-Math.PI/2)+"rad)"});
fiddle
Related
After looking through similar questions posted to the forum and not finding something that helped me solve my own problem, I'm posting it.
I'm using SVG.js to generate SVG shapes in a web document. I'd like one of those shapes to ”follow” the mouse/cursor.
By that I mean: The shape has a fixed position/anchor point (at its original center) and it can only move a limited distance (let's say 50px) away from this fixed point.
I want the shape to move in the direction of the cursor, whenever the cursor moves, but never further than a defined distance away from its orignal position. I'm attaching a short animation to illustrate my description:
If the cursor were to disappear, the shape would snap back to its original center.
I know my way around Javascript, HTML and CSS. This type of element-manipulation is new to me and the math is giving my quite the headache, any help would be great.
It looks like I need the shape to basically rotate around its original center, with an angle relative to the cursor? I'm really unsure how to solve this. I have tried using a method to calculate the angle described in this post. My shape moves, but not as intended:
// init
var draw = SVG().addTo('body')
// draw
window.shape = draw.circle(25, 25).stroke({
color: '#000',
width: 2.5
}).fill("#fff");
shape.attr("id", "circle1");
shape.move(50, 50)
// move
var circle = $("#circle1");
var dist = 10;
$(document).mousemove(function(e) {
// angle
var circleCenter = [circle.offset().left + circle.width() / 2, circle.offset().top + circle.height() / 2];
var angle = Math.atan2(e.clientX - circleCenter[0], -(e.clientY - circleCenter[1])) * (180 / Math.PI);
var x = Math.sin(angle) * dist;
var y = (Math.cos(angle) * dist) * -1;
shape.animate().dmove(x, y);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.0.16/svg.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Note: It does not matter to me whether the solution depends on jQuery or not (ideally it doesn't).
After more fiddling around with some solutions to calculating angles and distances, I found the answer.
I'm using a fixed reference point to calculate the angle of the direct line between the center of the shape and the cursor. Then I move the shape relative to this reference point and by a given amount:
// Init canvas
var draw = SVG().addTo('body')
// Draw reference/anchor
var shape_marker_center = draw.circle(3,3).fill("#f00").move(150, 150);;
var grafikCenter = [shape_marker_center.attr("cx"), shape_marker_center.attr("cy")]
// Draw shapes
var shape = draw.circle(25, 25).stroke({color: '#000', width: 2.5 }).fill("none");
shape.attr("id", "circle1").attr({cx: grafikCenter[0], cy:grafikCenter[1]})
var shape2 = draw.circle(50, 50).stroke({color: '#000', width: 2.5 }).fill("none");
shape2.attr("id", "circle2").attr({cx: grafikCenter[0], cy:grafikCenter[1]})
var shape3 = draw.circle(75, 75).stroke({color: '#000', width: 2.5 }).fill("none");
shape3.attr("id", "circle3").attr({cx: grafikCenter[0], cy:grafikCenter[1]})
$(document).mousemove(function(e) {
var pointA = [shape_marker_center.attr("cx"), shape_marker_center.attr("cy")];
var pointB = [e.clientX, e.clientY];
var angle = Math.atan2(pointB[1] - pointA[1], pointB[0] - pointA[0]) * 180 / Math.PI ;
//
var distance_x_1 = Math.cos(angle*Math.PI/180) * 16;
var distance_y_1 = Math.sin(angle*Math.PI/180) * 16;
var distance_x_2 = Math.cos(angle*Math.PI/180) * 8;
var distance_y_2 = Math.sin(angle*Math.PI/180) * 8;
//
shape.center((grafikCenter[0] + distance_x_1), (grafikCenter[1] + distance_y_1));
shape2.center((grafikCenter[0] + (distance_x_2) ), (grafikCenter[1] + (distance_y_2)));
})
svg {
width: 100vw;
height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.0.16/svg.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Need help understanding this code, which is used to make an image move in an elliptical shape. What I don't understand, is the formula for e, px and py variable. What exactly is the e variable defined the complex way it is? I know it uses some mathematical formulas but i don't know which ones.
var b = 125;
var h = 115;
var rx = 7;
var ry = 4;
var e = 0;
function update() {
setInterval(function() {
e = (e + Math.PI / 360) % (Math.PI * 2);
rotate(e);
}, 10);
var lyd = new Audio("Vedlegg/skoytelyd.mp3");
lyd.play();
}
function rotate(e) {
var px = b + rx * Math.cos(e)*b/2;
var py = h + ry * Math.sin(e)*h/2;
document.getElementById("punkt").style.left = px + "px";
document.getElementById("punkt").style.top = py + "px";
}
</script>
<style>
div {
position: fixed;
}
#sentrum {
background: black;
left: 100px;
top: 50px;
}
#skoyteloper {
position: absolute;
top: 190px;
left: 450px;
width: 60px;
height: 60px;
}
</style>
</head>
<body>
<div id="sentrum"></div>
<img src="Vedlegg/bane.jpg" id="imgBane"></img>
</div>
<div id="punkt">
<img src="Vedlegg/skoyteloper.png" id="skoyteloper"></img>
</div>
TILBAKE
</body>
Sinus and cosinus:
Think of a triangle with one 90° angle. 1 line is horizontal, another line is at the right side and is vertical, the third line goes from bottom-left to top-right.
The angle on the left we call e (yes,it is the e in your function)
sinus of e is defined as the vertical line on the right divided by the diagonal line; cosinus e = horizontal line (which is touching the angle e) / diagonal.
--
Now draw a circle with middle at angle e and radius = the length of the diagonal.
If you raise the angle e you will see the vertical line get bigger and the horizontal line get smaller (keep the length of the diagonal constant), until you reach 90°. Then of course you can go beyond 90°, then the vertical line can be on the left. Further than 180° the vertical line will point down (negative coordinate), ...
So that's one of the uses of sin and cos: if you set an angle they give you an y-value and a x-value, showing you 1 point on a circle. It's always a number between -1 and +1. example: sin(0) = 0 (no vertical component), cos(0) = 1
This code here below gives you a circle around center (0,0) and radius 100. Feed this function a bunch of values for e and you get as many points on a circle
function rotate(e) {
var px = 100 * Math.cos(e);
var py = 100 * Math.sin(e);
}
Now, if instead of 100 * cos(e) you put 200 * cos(e), then it's not a circle anymore. Every x coordinate will be twice as far (compared to the circle). A different rx and ry will result in an ellipse.
your variables b & h are for pushing the center of the ellipse to somewhere inside the image/div/canvas/... rather than in a corner (then you clip most of the ellipse).
Does this help?
In easelJS, what is the best way to rotate an object around another? What I'm trying to accomplish is a method to rotate the crosshair around the circle pictured below, just like a planet orbits the sun:
I've been able to rotate objects around their own center point, but am having a difficult time devising a way to rotate one object around the center point of a second object. Any ideas?
Might make sense to wrap content in a Container. Translate the coordinates so the center point is where you want it, and then rotate the container.
To build on what Lanny is suggesting, there may be cases where you don't want to rotate the entire container. An alternative would be to use trigonometric functions and an incrementing angle to calculate the x/y position of the crosshair. You can find the x/y by using an angle (converted to radians) and Math.cos(angleInRadians) for x and Math.sin(angleInRadians) for y, the multiply by the radius of the orbit.
See this working example for reference.
Here's a complete snippet.
var stage = new createjs.Stage("stage");
var angle = 0;
var circle = new createjs.Shape();
circle.graphics.beginFill("#FF0000").drawEllipse(-25, -25, 50, 50).endFill();
circle.x = 100;
circle.y = 100;
var crosshair = new createjs.Shape();
crosshair.graphics.setStrokeStyle(2).beginStroke("#FF0000").moveTo(5, 0).lineTo(5, 10).moveTo(0, 5).lineTo(10, 5).endStroke();
stage.addChild(circle);
stage.addChild(crosshair);
createjs.Ticker.addEventListener("tick", function(){
angle++;
if(angle > 360)
angle = 1;
var rads = angle * Math.PI / 180;
var x = 100 * Math.cos(rads);
var y = 100 * Math.sin(rads);
crosshair.x = x + 100;
crosshair.y = y + 100;
stage.update();
});
Put another point respect to origin point with the same direction
var one_meter = 1 / map_resolution;
// get one meter distance from pointed points
var extra_x = one_meter * Math.cos(temp_rotation);
var extra_y = one_meter * Math.sin(-temp_rotation);
var new_x = mapXY.x + extra_x;
var new_y = mapXY.y + extra_y;
var home_point = new createjs.Shape().set({ x: new_x, y: new_y });
home_point.graphics.beginFill("Blue").drawCircle(0, 0, 10);
stage.addChild(home_point);
stage.update();
I have a JavaScript function which allows me to generate DOM elements and plot them on a circle with (good enough) even distribution around the circle. The code is as follows (I'm using jQuery):
function createFields(numberOfItems, className, radius) {
var container = $('#container');
for(var i = 0; i < +numberOfItems; i++) {
$('<div/>', {
'class': 'field ' + className,
'text': i + 1
}).appendTo(container);
}
var fields = $('.' + className),
container = $('#container'),
width = container.width(),
height = container.height(),
angle = 0,
step = (2*Math.PI) / fields.length;
fields.each(function() {
var x = Math.round(width/2 + radius * Math.cos(angle) - $(this).width()/2);
var y = Math.round(height/2 + radius * Math.sin(angle) - $(this).height()/2);
if(window.console) {
console.log($(this).text(), x, y);
}
$(this).css({
left: x + 'px',
top: y + 'px'
});
angle += step;
});
}
createFields(5, 'outer', 200);
createFields(4, 'inner', 120);
Fiddle: http://jsfiddle.net/z79gj8a7/
You'll notice that the generated elements begin at 90 degrees to the vertical. I'd like to plot them so that they begin at 0 degrees. Essentially, if you imagine this as a clock, I want to plot all of the items 3hrs earlier. I've tried modifying the angle in the script to -90 and also subtracting 90 from the angle += step line but it's not having the desired effect.
Could anyone who's better at maths than I suggest a way to get the elements to be plotted -90 degrees from where they are now? (I'm aware I could just rotate the #container but that seems like a hack as I'd have to rotate the elements to compensate to keep their content in the correct orientation).
Many thanks.
The script is working in radians not degrees :) here's what you want (I think) http://jsfiddle.net/z79gj8a7/1/
You need to shift the angle by pi/2
var x = Math.round(width/2 + radius * Math.cos(angle - (Math.PI/2)) - $(this).width()/2);
var y = Math.round(height/2 + radius * Math.sin(angle - (Math.PI/2)) - $(this).height()/2);
Or even better (having read the script properly) don't change the calculation of x and y but change the angle to start at -pi/2: http://jsfiddle.net/z79gj8a7/2/
angle = -Math.PI/2,
jsFiddle demo
function createFields(numberOfItems, className, radius) {
var container = $('#container'),
centerX = container.width()/2,
centerY = container.height()/2,
angle = 0;
for(var i = 0; i < +numberOfItems; i++) {
$('<div/>', {
'class': 'field ' + className,
'text': i + 1
}).appendTo(container);
}
var fields = $('.' + className),
tot = fields.length;
fields.each(function(i, e) {
var w2 = $(e).outerWidth(true)/2,
h2 = $(e).outerHeight(true)/2,
angle = 360/tot*i,
x = Math.round(centerX+radius * Math.sin(angle*Math.PI/180)),
y = Math.round(centerY+radius * -Math.cos(angle*Math.PI/180));
$(e).css({left:x-w2, top:y-h2}).text( i+1 );
});
}
createFields(5, 'outer', 200);
createFields(4, 'inner', 120);
Suppose my div has left:200px and top:400px, after I apply a rotate transform of suppose 90 deg the above top and left positions no more point to the old positions. Now how can we calculate the new top and left for the transformed div which are equivalent to the left and top positions of the non-transformed div after rotation.
Edited answer
Besides the starting position of the corner point (top-left in your example), and the rotation angle, we also need to know the position of the reference point of the rotation. This is the point around which we rotate the div (CSS calls it transform-origin). If you don't specify it, then normally, the centre of mass of the element is used.
I don't know of any JavaScript method that simply calculates it for you, but I can show you its Math, and a simple JS implementation.
Math
P: original position of the corner point, with (Px, Py) coordinates
O: reference point of the rotation, with (Ox, Oy) coordinates
Calculate the original position of P, relative to O.
x = Px - Ox
y = Py - Oy
Calculate the rotated position of P, relative to O.
x' = x * cos(angle) - y * sin(angle)
y' = x * sin(angle) + y * cos(angle)
Convert this position back to the original coordinate system.
Px' = x' + Ox
Py' = y' + Oy
If you're not aware of the formulas in step #2, you can find an explanation here.
JavaScript implementation
function rotatedPosition(pLeft, pTop, oLeft, oTop, angle){
// 1
var x = pLeft - oLeft;
var y = pTop - oTop;
// 2
var xRot = x * Math.cos(angle) - y * Math.sin(angle);
var yRot = x * Math.sin(angle) + y * Math.cos(angle);
// 3
var pLeftRot = xRot + oLeft;
var pTopRot = yRot + oTop
return {left: pLeftRot, top: pTopRot};
}
rotatedPosition requires you to define the original position of the point and the reference point, plus the angle.
In case you need a method which takes only a single argument, the div element itself, and computes the rest for you, then you can do something like:
function divTopLeftRotatedPosition(div){
var pLeft = // ...
var pTop = // ...
var width = // ...
var height = // ...
var angle = // ...
return rotatedPosition(pLeft, pTop, pLeft + width / 2, pTop + height / 2, angle);
}