I am trying to make an animation system for my three.js project. I have a json file for the information. I was able to make the animation play. But, at the moment they need to be somewhere, they move to that location, instead of slowly moving to that location over time. The json file tells the program where the specific object needs to be at a certain location. For example:
Json File:
{
"right": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, 1, 0],
"0.5": [1, 1, 0]
}
}
Json files tells you position, at what second, then the positions.
Code:
for (const [key, value] of Object.entries(json.position.right))
if(seconds === json.position.right[key]) {
obj.position.x = json.right.position[key][0];
obj.position.y = json.right.position[key][1];
obj.position.z = json.right.position[key][2];
}
}
In the code, I loop through the json file's right cube position (which tells when the position changes happen). If the seconds match, it moves to that position.
How would I be able to get the movement inbetween the keyframes for the object?
Here is the example: https://mixed-polyester-a.glitch.me/
Here is all the code: https://glitch.com/edit/#!/mixed-polyester-a
I used Blockbench to export models as .OBJ files, materials as .MTL files, and animations as .JSON files.
Sorry if it sounds confusing, didn't really know how to explain it. Any help would be highly appreciated.
Three.js has a method called MathUtils.lerp() that takes in a starting position, an ending position, and an interpolation value between [0, 1]. You could use this to tween your object's current position to its target destination on each frame, as demonstrated in the example below:
const container = document.getElementById("container");
const ball = document.getElementById("ball");
// Set current positions
let ballPosX = 0;
let ballPosY = 0;
// Set target positions
let ballTargetX = 0;
let ballTargetY = 0;
// Update target positions on click
function onClick(event) {
ballTargetX = event.layerX;
ballTargetY = event.layerY;
//console.log(event);
}
function update() {
// Interpolate current position towards targets
ballPosX = THREE.MathUtils.lerp(ballPosX, ballTargetX, 0.1);
ballPosY = THREE.MathUtils.lerp(ballPosY, ballTargetY, 0.1);
// Apply current position to our object
ball.style.left = ballPosX + "px";
ball.style.top = ballPosY + "px";
requestAnimationFrame(update);
}
container.addEventListener("click", onClick);
update();
#container {
width: 300px;
height: 300px;
background: #ddd;
}
#ball {
width: 10px;
height: 10px;
position: absolute;
top: 0;
left: 0;
background: #f90;
border-radius: 10px;
margin-top: -5px;
margin-left: -5px;
}
<div id="container">
<div id="ball"></div>
</div>
<script src="https://threejs.org/build/three.js"></script>
Update:
To create a linear timeline with keyframes, I've used gsap.to() with the keyframes parameter to feed all the positions to the timeline. See here and look up "keyframes" for more details. You can see it in action in the code demo below, you'll need to iterate through your JSON to feed that data to GSAP on your own, though. Good luck!
// Set position vector
const ballPos = {x: 0, y: 0};
const positions = {
"0.0": [0, 0],
"0.25": [0, 100],
"0.5": [100, 100],
"0.75": [100, 0],
"1.0": [0, 0],
}
const timeline = gsap.to(ballPos, {keyframes: [
{x: positions["0.0"][0], y: positions["0.0"][1], duration: 0.0},
{x: positions["0.25"][0], y: positions["0.25"][1], duration: 0.25},
{x: positions["0.5"][0], y: positions["0.5"][1], duration: 0.25},
{x: positions["0.75"][0], y: positions["0.75"][1], duration: 0.25},
{x: positions["1.0"][0], y: positions["1.0"][1], duration: 0.25},
]});
const container = document.getElementById("container");
const ball = document.getElementById("ball");
let timelineTime = 0;
function update() {
timelineTime += 0.001;
timelineTime %= 1;
timeline.seek(timelineTime);
// Apply current position to our object
ball.style.left = ballPos.x + "px";
ball.style.top = ballPos.y + "px";
requestAnimationFrame(update);
}
update();
#container {
width: 300px;
height: 300px;
background: #ddd;
}
#ball {
width: 10px;
height: 10px;
position: absolute;
top: 0;
left: 0;
background: #f90;
border-radius: 10px;
margin-top: -5px;
margin-left: -5px;
}
<div id="container">
<div id="ball"></div>
</div>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/gsap.min.js"></script>
Related
I'm new to Matter JS, so please bear with me. I have the following code I put together from demos and other sources to suit my needs:
function biscuits(width, height, items, gutter) {
const {
Engine,
Render,
Runner,
Composites,
MouseConstraint,
Mouse,
World,
Bodies,
} = Matter
const engine = Engine.create()
const world = engine.world
const render = Render.create({
element: document.getElementById('canvas'),
engine,
options: {
width,
height,
showAngleIndicator: true,
},
})
Render.run(render)
const runner = Runner.create()
Runner.run(runner, engine)
const columns = media({ bp: 'xs' }) ? 3 : 1
const stack = Composites.stack(
getRandom(gutter, gutter * 2),
gutter,
columns,
items.length,
0,
0,
(x, y, a, b, c, i) => {
const item = items[i]
if (!item) {
return null
}
const {
width: itemWidth,
height: itemHeight,
} = item.getBoundingClientRect()
const radiusAmount = media({ bp: 'sm' }) ? 100 : 70
const radius = item.classList.contains('is-biscuit-4')
? radiusAmount
: 0
const shape = item.classList.contains('is-biscuit-2')
? Bodies.circle(x, y, itemWidth / 2)
: Bodies.rectangle(x, y, itemWidth, itemHeight, {
chamfer: { radius },
})
return shape
}
)
World.add(world, stack)
function positionDomElements() {
Engine.update(engine, 20)
stack.bodies.forEach((block, index) => {
const item = items[index]
const xTrans = block.position.x - item.offsetWidth / 2 - gutter / 2
const yTrans = block.position.y - item.offsetHeight / 2 - gutter / 2
item.style.transform = `translate3d(${xTrans}px, ${yTrans}px, 0) rotate(${block.angle}rad)`
})
window.requestAnimationFrame(positionDomElements)
}
positionDomElements()
World.add(world, [
Bodies.rectangle(width / 2, 0, width, gutter, { isStatic: true }),
Bodies.rectangle(width / 2, height, width, gutter, { isStatic: true }),
Bodies.rectangle(width, height / 2, gutter, height, { isStatic: true }),
Bodies.rectangle(0, height / 2, gutter, height, { isStatic: true }),
])
const mouse = Mouse.create(render.canvas)
const mouseConstraint = MouseConstraint.create(engine, {
mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false,
},
},
})
World.add(world, mouseConstraint)
render.mouse = mouse
Render.lookAt(render, {
min: { x: 0, y: 0 },
max: { x: width, y: height },
})
}
I have a HTML list of links that mimics the movements of the items in Matter JS (the positionDomElements function). I'm doing this for SEO purposes and also to make the navigation accessible and clickable.
However, because my canvas sits on top of my HTML (with opacity zero) I need to be able to make the items clickable as well as draggable, so that I can perform some other actions, like navigating to the links (and other events).
I'm not sure how to do this. I've searched around but I'm not having any luck.
Is it possible to have each item draggable (as it already is) AND perform a click event of some kind?
Any help or steer in the right direction would be greatly appreciated.
It seems like your task here is to add physics to a set of DOM navigation list nodes. You may be under the impression that matter.js needs to be provided a canvas to function and that hiding the canvas or setting its opacity to 0 is necessary if you want to ignore it.
Actually, you can just run MJS headlessly using your own update loop without injecting an element into the engine. Effectively, anything related to Matter.Render or Matter.Runner will not be needed and you can use a call to Matter.Engine.update(engine); to step the engine forward one tick in the requestAnimationFrame loop. You can then position the DOM elements using values pulled from the MJS bodies. You're already doing both of these things, so it's mostly a matter of cutting out the canvas and rendering calls.
Here's a runnable example that you can reference and adapt to your use case.
Positioning is the hard part; it takes some fussing to ensure the MJS coordinates match your mouse and element coordinates. MJS treats x/y coordinates as center of the body, so I used body.vertices[0] for the top-left corner which matches the DOM better. I imagine a lot of these rendering decisions are applicaton-specific, so consider this a proof-of-concept.
const listEls = document.querySelectorAll("#mjs-wrapper li");
const engine = Matter.Engine.create();
const stack = Matter.Composites.stack(
// xx, yy, columns, rows, columnGap, rowGap, cb
0, 0, listEls.length, 1, 0, 0,
(xx, yy, i) => {
const {x, y, width, height} = listEls[i].getBoundingClientRect();
return Matter.Bodies.rectangle(x, y, width, height, {
isStatic: i === 0 || i + 1 === listEls.length
});
}
);
Matter.Composites.chain(stack, 0.5, 0, -0.5, 0, {
stiffness: 0.5,
length: 20
});
const mouseConstraint = Matter.MouseConstraint.create(
engine, {element: document.querySelector("#mjs-wrapper")}
);
Matter.Composite.add(engine.world, [stack, mouseConstraint]);
listEls.forEach(e => {
e.style.position = "absolute";
e.addEventListener("click", e =>
console.log(e.target.textContent)
);
});
(function update() {
requestAnimationFrame(update);
stack.bodies.forEach((block, i) => {
const li = listEls[i];
const {x, y} = block.vertices[0];
li.style.top = `${y}px`;
li.style.left = `${x}px`;
li.style.transform = `translate(-50%, -50%)
rotate(${block.angle}rad)
translate(50%, 50%)`;
});
Matter.Engine.update(engine);
})();
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
body {
min-width: 600px;
}
#mjs-wrapper {
/* position this element */
margin: 1em;
height: 100%;
}
#mjs-wrapper ul {
font-size: 14pt;
list-style: none;
user-select: none;
position: relative;
}
#mjs-wrapper li {
background: #fff;
border: 1px solid #555;
display: inline-block;
padding: 1em;
cursor: move;
}
#mjs-wrapper li:hover {
background: #f2f2f2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
<div id="mjs-wrapper">
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
<li>Quux</li>
<li>Garply</li>
<li>Corge</li>
</ul>
</div>
How can I get Text object font size after modifying object in fabric.js?
Below is my code.
var text = new fabric.Text(imgText, {
left: 10,
top: 5,
fontSize: 15,
fontFamily: 'Verdana',
fill: 'white'
});
text.scaleToWidth(canvas.width * 0.5);
text.setControlsVisibility(canvasConfig);
canvas.add(text);
canvas.renderAll();
var objects = canvas.getActiveObject();
var obj = objects;
if (!obj) {
return;
}
//console.log(obj.get('fontSize') *= obj.scaleX);
var angle = obj.get('angle');
var objWidth = obj.get('width') * obj.scaleX;
var objWidthPercent = objWidth / canvas.width * 100;
var objHeight = obj.get('height') * obj.scaleY;
var objHeightPercent = objHeight / canvas.height * 100;
var bound = obj.getBoundingRect();
var objLeft = obj.get('left') / canvas.width * 100;
var objTop = obj.get('top') / canvas.height * 100;
var newfontsize = obj.fontSize * obj.scaleX;
Above I set default FontSize to 15. then I modify object I can get proper Height, Width, Left, Top, but I am not able to get FontSize.
In backend i set image and text like below screenshot.
In frontend what i get like below screenshot.
Below style for image & text on frontend.
element.style {
left: 64.37%;
top: 14.54%;
width: 28.25%;
height: 14.37%;
font-size: 63.58px;
color: #E346FF;
font-family: Times New Roman;
position: absolute;
max-width: 100%;
z-index: 996;
max-height: 100%;
}
element.style {
left: 56.5%;
top: 0.81%;
width: 42.86%;
height: 42.86%;
max-width: 100%;
max-height: 100%;
position: absolute;
z-index: 995;
display: block;
background-image: url(http://10.16.16.101/LabelExtension/pub/media/labelimageuploader/images/image/o/r/orange_38.png);
background-position: center;
background-repeat: no-repeat;
background-size: contain;
}
When i add below code it working perfect but in backend object is getting blur.
this.canvas.setHeight(300);
this.canvas.setWidth(240);
this.canvas.backgroundColor = '#E8EEF1';
this.canvas.setDimensions({width: '480px', height: '600px'}, {cssOnly: true});
Here is the way to match Fabric.js font transforms to CSS transforms: https://jsfiddle.net/mmalex/evpky3tn/
The solution is to match transformations of texts, not trying to adjust font size.
Step 1 - Prepare scene, compose canvas, group text with rectangle, let user manipulate this group, rotate and scale it.
var canvas = new fabric.Canvas(document.getElementById('c'));
var rect = new fabric.Rect({
width: 50,
height: 50,
left: 90,
top: 120,
fill: 'rgba(255,0,0,0.25)'
});
var text = new fabric.Text("123", {
left: rect.left,
top: rect.top,
fontSize: 15,
fontFamily: 'Verdana',
fill: 'black'
});
text.scaleToWidth(rect.width);
canvas.add(text);
var group = new fabric.Group([rect, text], {
originX: 'center',
originY: 'center',
angle: 25,
scaleY: 1.7
});
canvas.add(group);
canvas.renderAll();
Step 2 - prepare DIV style for scaling
.scaled { // this style is applied to DIV element with text
...
font-size: 15px; // Fabric.js text is also 15px size
transform: scale(1, 1); // define initial transform
transition: all 0.25s linear; // let it animate
...
}
Step 3 - Evaluate Fabric.js transforms and apply CSS on DIV element,
for example:
element.style {
transform: rotate(25deg) scale(1.74774, 2.97116);
}
The solution (aka button handler) converts Fabric.js transform to CSS transform:
function matchCssTransform() {
let textScale = text.getTotalObjectScaling();
let pixelRatio = window.devicePixelRatio;
let styleStr = `rotate(${group.angle}deg) scale(${textScale.scaleX / pixelRatio}, ${textScale.scaleY / pixelRatio}) `;
document.getElementById("scaled").style.transform = styleStr;
}
getHeightOfLine(lineIndex) → {Number} : Computes height of character at given position and return fontSize of the character. Is it? tell me.
It's a method of text class. http://fabricjs.com/docs/fabric.Text.html#getHeightOfLine
This is the vanilla js solution.
I am not able to get FontSize.
You can achieve fontSize using the computedStyle like
let style = window.getComputedStyle(text, null).getPropertyValue('font-size');
let fontSize = parseFloat(style);
https://developer.mozilla.org/de/docs/Web/API/Window/getComputedStyle
In addition to this I recommend you to work with vw and vh
.text {
font-size: 10vw;
}
https://web-design-weekly.com/2014/11/18/viewport-units-vw-vh-vmin-vmax/
All together gives us https://jsfiddle.net/a8woL1eh/
The problem is Text object does not change its fontSize property when it is modified or transformed unless set fontSize property manually. It's the reason why you get blurred text because despite changed the transform size the main fontSize remaining same. So possible solution will be somehow changing fontSize property dynamically.
http://jsfiddle.net/therowf/xkhwagd8/41/
Here I have attached a jsfiddle example form your code. This code is very similar to your one.
Thanks and let me know if this is worked. (:
var canvas = new fabric.Canvas(document.getElementById('c'));
var imgText ="This is text";
var canvasConfig = true;
var text = new fabric.Text(imgText, {
left: 10,
top: 5,
fontSize: 50,
fontFamily: 'Verdana',
fill: 'black'
});
text.scaleToWidth(canvas.width * 0.5);
text.setControlsVisibility(canvasConfig);
canvas.add(text);
canvas.renderAll();
var objects = canvas.getActiveObject();
function moveHandler(evt){
//evt.target.fontSize = 10;
var fontSizeX = evt.target.scaleX;
var fontSizeY = evt.target.scaleY;
if(fontSizeX === fontSizeY){
evt.target.fontSize = fontSizeX*100;
console.log(evt.target.fontSize);
}
}
canvas.on('object:scaling', moveHandler);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.6.0/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>
I animate a div's position, then back to it's origin with a different ease:
var anim_a = new TimelineMax().to($(".mybox"), 3, {x: 400}).stop();
var anim_b = new TimelineMax().to($(".mybox"), 1, {x: 0, ease:Bounce.easeOut}).stop();
Problem is after both the animations ran once, they wont run anymore, why? and how can I repeat them on demand?
JSFIDDLE
var anim_a = function() {
var anm = new TimelineMax().to($(".mybox"), 1, {
x: 400
}).stop();
anm.play();
}
var anim_b = function() {
var anm = new TimelineMax().to($(".mybox"), 1, {
x: 0,
ease: Bounce.easeOut
}).stop();
anm.play();
}
$(".run-a").click(function(e) {
anim_a();
});
$(".run-b").click(function(e) {
anim_b();
});
.run-a,
.run-b {
background: green;
display: inline-block;
padding: 10px;
cursor: pointer;
}
.mybox {
width: 200px;
height: 200px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenMax.min.js"></script>
<div class="run-a">Go</div>
<div class="run-b">Go back</div>
<div class="mybox"></div>
i am not used to this TimeLineMax. Still i made a small change to the code and now its working as said. Please check and confirm whether this will fit for your context. I just made anim_a and anim_b as two functions with play operation included.
I'm creating my own CSS tilemap. The tilemap is 5x5, and will be 1000x1000px in size.
I would like to add it to a 500x500px canvas element so that only 1/2 the map is shown. I have a camera function that center the player to the canvas and move the tilemap relative to the player.
Goal: Put CSS Tilemap as a background in the HTML5 canvas (even though CSS tilemap is larger than canvas, there should be no overlap)
Given map array
var mapArray = [
[0, 0, 0, 0 ,0],
[0, 1, 0, 0 ,0],
[0, 0, 0, 0 ,0],
[0, 0, 0, 0 ,0],
[0, 0, 1, 1 ,0]
];
I draw my map as such:
function drawMap() {
for (var i = 0; i < mapArray.length; i++) {
for (var j = 0; j < mapArray[i].length; j++) {
if (parseInt(mapArray[i][j]) == 0) {
$('#mapContainer').append('<div class="grass"></div>');
}
if (parseInt(mapArray[i][j]) == 1) {
$('#mapContainer').append('<div class="dirt"></div>');
}
}
}
}
CSS: I've tried appending the element directly to the HTML, and used z-index: -1 to perhaps push the tilemap to the background, but that didn't work.
#mapContainer {
height: 1000px;
width: 1000px;
position: relative;
outline: 1px solid black;
z-index: -1;
}
.grass {
height: 200px;
width: 200px;
position: relative;
float: left;
background-color: green;
z-index: -1;
}
.dirt {
height: 200px;
width: 200px;
position: relative;
float: left;
background-color: tan;
z-index: -1;
}
How can I add the #mapContainer element to the canvas? I am using createJS, so I tried doing this:
function createWorld() {
world = new createjs.Container();
var htmlElement = document.createElement('div');
htmlElement.id = 'mapContainer';
var domElement = new createjs.DOMElement(htmlElement);
world.addChild(domElement);
stage.addChild(world);
}
Any thoughts?
It sounds like you are spawning a div to contain a background image for every tile, you want the browser to render that behind your canvas (with the canvas translucent)?
I've done the divs-for-tiles before and I recommend against it. However, you should be able to achieve what your asking.
the canvas has the style background: transparent; or <canvas-element>.style.background = 'transparent';.
the canvas should be on top of the texture divs. I would recommend just making sure the canvas element occurs after the texture elements in the DOM tree / HTML, But if thats not easy z-index styles can take care of that too. I've never used negative z-indices's but they should work.
I would recommend doing the tile set rendering within the canvas. I've scaffolded soemthing like that together a long time ago. Your welcome to reuse any code from this old project: http://thorsummoner.github.io/old-html-tabletop-test/ source: https://github.com/thorsummoner/old-html-tabletop-test/blob/master/index.html
Hello I was trying to find a solution for a small script that can rotate objects around 1 center but it seems a bit too tricky for me.
I've found almost perfect solution and tried to modify it to suit my needs but there's a problem.
I'm trying to make 3 objects with text to rotate with same speed, same orbit but different start positions as if they were apexes(vertices) of equilateral triangle.
Here's my fiddle so far:
( function ( $ ) {
jQuery.fn.orbit = function(s, options){
var settings = {
orbits: 1 // Number of times to go round the orbit e.g. 0.5 = half an orbit
,period: 3000 // Number of milliseconds to complete one orbit.
,maxfps: 25 // Maximum number of frames per second. Too small gives "flicker", too large uses lots of CPU power
,clockwise: false // Direction of rotation.
};
$.extend(settings, options); // Merge the supplied options with the default settings.
return(this.each(function(){
var p = $(this);
/* First obtain the respective positions */
var p_top = p.css('top' ),
p_left = p.css('left'),
s_top = s.css('top' ),
s_left = s.css('left');
/* Then get the positions of the centres of the objects */
var p_x = parseInt(p_top ) + p.height()/2,
p_y = parseInt(p_left) + p.width ()/2,
s_x = parseInt(s_top ) + s.height()/2,
s_y = parseInt(s_left) + s.width ()/2;
/* Find the Adjacent and Opposite sides of the right-angled triangle */
var a = s_x - p_x,
o = s_y - p_y;
/* Calculate the hypotenuse (radius) and the angle separating the objects */
var r = Math.sqrt(a*a + o*o);
var theta = Math.acos(a / r);
/* Calculate the number of iterations to call setTimeout(), the delay and the "delta" angle to add/subtract */
var niters = Math.ceil(Math.min(4 * r, settings.period, 0.001 * settings.period * settings.maxfps));
var delta = 2*Math.PI / niters;
var delay = settings.period / niters;
if (! settings.clockwise) {delta = -delta;}
niters *= settings.orbits;
/* create the "timeout_loop function to do the work */
var timeout_loop = function(s, r, theta, delta, iter, niters, delay, settings){
setTimeout(function(){
/* Calculate the new position for the orbiting element */
var w = theta + iter * delta;
var a = r * Math.cos(w);
var o = r * Math.sin(w);
var x = parseInt(s.css('left')) + (s.height()/2) - a;
var y = parseInt(s.css('top' )) + (s.width ()/2) - o;
/* Set the CSS properties "top" and "left" to move the object to its new position */
p.css({top: (y - p.height()/2),
left: (x - p.width ()/2)});
/* Call the timeout_loop function if we have not yet done all the iterations */
if (iter < (niters - 1)) timeout_loop(s, r, theta, delta, iter+1, niters, delay, settings);
}, delay);
};
/* Call the timeout_loop function */
timeout_loop(s, r, theta, delta, 0, niters, delay, settings);
}));
}
}) (jQuery);
$('#object1' ).orbit($('#center' ), {orbits: 2, period: 8000});
$('#object2' ).orbit($('#center' ), {orbits: 4, period: 4000});
$('#object3' ).orbit($('#center' ), {orbits: 8, period: 2000});
HTML:
<h1> Example</h1>
<div id='rotation'>
<div id='center' >C</div>
<div id='object1' >Text1</div>
<div id='object2' >Text2</div>
<div id='object3' >Text3</div>
</div>
CSS:
#rotation {position: relative; width: 600px; height: 600px; background-color: #898989}
#center {position: absolute; width: 20px; height: 20px;
top: 300px; left: 300px; background-color: #ffffff;
-moz-border-radius: 40px; border-radius: 40px;
text-align: center; line-height: 15px;
}
#object1 {position: absolute; width: 36px; height: 36px;
top: 300px; left: 200px; background-color: #ff8f23;
-moz-border-radius: 18px; border-radius: 18px;
text-align: center; line-height: 30px;
}
#object2 {position: absolute; width: 36px; height: 36px;
top: 300px; left: 200px; background-color: #ff8f23;
-moz-border-radius: 18px; border-radius: 18px;
text-align: center; line-height: 30px;
}
#object3 {position: absolute; width: 36px; height: 36px;
top: 300px; left: 200px; background-color: #ff8f23;
-moz-border-radius: 18px; border-radius: 18px;
text-align: center; line-height: 30px;
}
I used different speed and revolutions for each object because I can't figure out how to set different start positions without messing up. If I touch x,y coordinates of any object in CSS then the orbiting messes up. It seems that object positions calculations are connected. And if I change coordinates then the calculation also changes. But I can't figure out how to fix this.
If you change the starting position of each element and call the .orbit function on each of them passing the same arguments it should work.
Check this out: fiddle
This is a slightly modified version of your fiddle. (Changed the starting positions and the arguments when calling the .orbit function.
Correct me if I'm wrong or if I didn't answer your question.
Got it working as intended
Fiddle
Jquery code:
var txt = $('#text .txt'), txtLen = txt.size();
var deg2rad = function(a) { return a*Math.PI/180.0; }
var angle = 0, speed=0.1, delay = 0, r = 100;
(function rotate() {
for (var i=0; i<txtLen; i++) {
var a = angle - (i * 360 / txtLen);
$(txt[i]).css({top: r+(Math.sin(deg2rad(a))*r), left: r+(Math.cos(deg2rad(a))*r)});
}
angle = (angle - speed) % 360;
setTimeout(rotate, delay);
})();
var rotation = function (){
$("#image").rotate({
duration: 6000,
angle:360,
animateTo:0,
callback: rotation,
easing: function (x,t,b,c,d){
var d = 6000
return c*(t/d)+b;
}
});
}
rotation();
var txt2 = $('#text2 .txt2'), txt2Len = txt2.size();
var deg2rad = function(a) { return a*Math.PI/180.0; }
var angle = 13, speed=0.2, delay = 0, r = 100;
(function rotate() {
for (var i=0; i<txt2Len; i++) {
var a = angle - (i * 360 / txt2Len);
$(txt2[i]).css({top: r+(Math.sin(deg2rad(a))*r), left:
r+(Math.cos(deg2rad(a))*r)});
}
// increment our angle and use a modulo so we are always in the range [0..360] degrees
angle = (angle - speed) % 360;
// after a slight delay, call the exact same function again
setTimeout(rotate, delay);
})(); // invoke this boxed function to initiate the rotation
var rotation = function (){
$("#image").rotate({
duration: 6000,
angle:360,
animateTo:0,
callback: rotation,
easing: function (x,t,b,c,d){
var d = 6000
return c*(t/d)+b;
}
});
}
rotation();