Reputation: 1
In JSXGraph I graph a plate (polygon) with 4 forces (arrows) acting on it. I intend to use the code for a variable number of forces (that's why it is more general than necessary for just 4 forces).
Force components can be shown and hidden. When a force arrow (not passing through the pivot point) is dragged, the "drag" event triggers an animation:
1st: showing the force and its arm, waiting for 2s 2nd: rotate the polygon in the direction of the force component (either clockwise or anti-clockwise).
Problem 1: The animation is slow and rough. I tried to use "suspendUpdate" and "unsuspendUpdate", but it made things even worse. Probably, I did not use it at the right place.
Problem 2: (probably related) I did not find a good way to clone the polygon for the animation. Or would it be best to store its coordinates? But if so, how would I reset the polygon (plus force arrow) to its original position after the rotation/animation?
My complete code is here: https://jsfiddle.net/bujowi/j1etgLsp/3/
You find the function called for the animation from line 244 onwards:
function animateRotation(x1, y1, x2, y2, sign)
Any comments and suggestions for improvements are welcome.
Upvotes: 0
Views: 192
Reputation: 2338
In the jsfiddle the animation appears to be rough since the the drag event is fired multiple times. Therefore, the animation runs in parallel multiple times. In the code below this is prevented by the flag is_animated
. If true
no new animation can be started.
A minor, more JSXGraph-ish issue is that the transformation is added to the JSXGraph elements in every step of the animation in setInterval
. This may produce strange effects. It is much more clean to bind the transformation once to an element, but make the transformation dynamic, e.g. dependent on an angle variable:
var angle = 0.03;
let tRot = b1.create('transform', [function() { return sign * angle; }, pivot], { type: 'rotate' });
Additionally, this would make it possible to rotate the polygon back to the zero angle at the end of the animation. So, in setInterval
only the angle variable is increased and the board is updated:
let idInterval = setInterval(function() {
angle += 0.03;
b1.update();
// ...
}, refreshTime);
Here is the complete new animation code (without rotating back at the end):
function animateRotation(x1, y1, x2, y2, sign) {
if (this.is_animated) {
return;
}
this.is_animated = true;
// Force arrow and arm (distance from pivot)
let Rot1 = b1.create('point', [x1, y1], { visible: false })
let Rot2 = b1.create('point', [x2, y2], { visible: false })
let rotArrow = b1.create('arrow', [Rot1, Rot2], { strokeColor: '#000', strokeWidth: 3, visible: true })
// Polygon
let PolyCopy = []
for (i = 0; i < poly_coord.length; i++) {
PolyCopy.push(b1.create('point', [poly_coord[i][0], poly_coord[i][1]], at))
}
let polyCopy = b1.create('polygon', PolyCopy, { strokeColor: myBlue, fillColor: myBlue })
// Hide all other force arrows
showAllElements(false)
// Show line of action and distance from pivot for 1s
let lineOfAction = b1.create('line', [[x1, y1], [x2, y2]], { strokeColor: '#000', strokeWidth: 2, dash: 1 })
let perpLine = b1.create('perpendicular', [lineOfAction, Pivot], { withLabel: false, visible: false })
let isecP = b1.create('intersection', [perpLine, lineOfAction, 0], { withLabel: false, visible: false })
let dist = b1.create('segment', [Pivot, isecP], { strokeColor: '#000', strokeWidth: 4 })
var that = this; // make "this" available in the interval function
// This is the animation: rotating the polygon for how many 'frames', refreshTime in ms
setTimeout(function() {
b1.removeObject(lineOfAction)
b1.removeObject(perpLine)
b1.removeObject(isecP)
b1.removeObject(dist)
var angle = 0.03;
let tRot = b1.create('transform', [function() { return sign * angle; }, pivot], { type: 'rotate' });
tRot.bindTo(PolyCopy);
tRot.bindTo([Rot1, Rot2]);
let frames = 0;
const refreshTime = 50;
let idInterval = setInterval(function() {
angle += 0.03;
b1.update();
if (frames++ > 20) {
that.is_animated = false;
b1.removeObject(polyCopy);
b1.removeObject(rotArrow);
showAllElements(true);
clearInterval(idInterval);
}
}, refreshTime)
}, 1000); // time for showing the line of action and distance
}
See it live at https://jsfiddle.net/fbdzx0ht/3/
Best wishes, Alfred
Upvotes: 0