Zoom Button on JIT Rgraph - javascript

While using R graph(Javascript Infovis Toolkit) I found only mouse wheel can be used as zoom in and out. Can any one help me with how I may control the graph with two buttons instead of mouse wheel.

This is an example for the Force directed variant for graph named
You can change the .zooming value as provided in the example, in this one I set it to 15 and it zooms fairly slowly.
fd:
function zoom(delta)
{
if (fd)
{
var val = fd.controller.Navigation.zooming/1000;
var ans = 1 - (delta * val);
fd.canvas.scale(ans, ans);
}
}

Related

Optimize pendulum animation (javascript)

TL;DR: I wrote plotly-based javascript simulation of mathematical pendulum. It works very slow. I'm looking for ideas on how to optimize it. Currently trying "bare" d3.js and struggling from the problem of coordinate transformation between SVG's coordinates and my own logical coordinates.
I'm writing web-textbook on ordinary differential equations and want to include interactive simulation and visualization of mathematical pendulum. Visualization should contain pendulum itself, its potential energy graph and full energy contour plot. Then user can choose the initial condition by clicking on energy contour plot, then animation should begin showing how the point moves in the phase space.
I wrote an example of such simulation:
https://jsfiddle.net/ischurov/p1krqnt6/
It's plotly-based. I create three axes and put there necessary graphs. The point that represent current state of the system is also a graph in plotly (i.e. scatter plot with the only one point).
Animation works as follows: I get current coordinates of the point in the phase space, calculate the new position of this point after some time, then update my graph according to this new position. The corresponding code:
var div = document.getElementById('myDiv');
function updateState(phi, v) {
var update = {x: [[phi], [phi], [0, Math.sin(phi)]], y: [[v],
[PotentialEnergy(phi)], [0, -Math.cos(phi)]]};
Plotly.restyle(div, update, [phaseDotIndex, 3, 4]);
}
myPlot.on('plotly_click', function(data){
if(data.points[0].data.type == 'contour'){
updateState(data.points[0].x, data.points[0].y);
}
});
var animate = null;
$('.animate_button').click(function(){
var div = document.getElementById('myDiv');
if(animate === null) {
var phi = div.data[phaseDotIndex].x[0],
v = div.data[phaseDotIndex].y[0],
E = FullEnergy(phi, v);
animate = setInterval(function() {
var phi = div.data[phaseDotIndex].x[0],
v = div.data[phaseDotIndex].y[0],
step = 0.1, newphi, newv, update;
newphi = phi + v * step;
newv = v + step * Force(phi);
/* skip some tweaks here */
updateState(phi, v);
},
100)
}
else
{
clearInterval(animate);
animate = null;
}
}
This code works almost as expected, but really slow and not smooth — at least, under Firefox (If I decrease update interval it works even worse).
I'm looking for ways to optimize this.
I believe that performance problems are due to plotly's update process: in order to move one point it have to recalculate the whole picture and it is slow. So I'm looking for ways to do it in different way.
Are there any ideas?
I'm looked for some direct d3.js approach which can be faster. I see the following steps here:
Draw a graph of potential energy and contour plot of full energy.
Draw the pendulum itself.
Put small circles on the graphs of potential energy and contour plot.
Make 'onclick' event handler to allow user to choose the initial state.
Run animation loop by updating the position of the circles and the pendulum according to current state.
To proceed with step 1, I can use third-party d3.js libraries like conrec for contour plots and/or excellent maurizzzio's function plot or even plotly itself (but I'm not going to use plotly to update the graph). Step 2 seem to be doable, but I didn't try it yet. The most difficult for now are steps 3 and 4 as I don't understand how to transform SVG coordinates into my graph's coordinates (that are plotted with some library) and vice-versa.
Or maybe there are more simple ways to do it?
I'm the author of function plot which is built on top of d3, luckily d3 has methods to perform mappings in d3-scale so assuming that you have a canvas of width x height dimensions which should be mapped linearly to the rectangle [xMin, yMin] x [xMax, yMax] in 2D euclidean space you'd need to create two linear scales
var xScale = d3.scale.linear()
.domain([xMin, xMax])
.range([0, width])
var yScale = d3.scale.linear()
.domain([yMin, yMax])
.range([height, 0])
Note that in SVG the y axis is flipped and because of that the yScale range's flipped too, then any 2D euclidean point is transformed to SVG coordinates as follows
var xCanvas = xScale(point.x)
var yCanvas = yScale(point.y)
The inverse transformation is given by
var xLogical = xScale.invert(point.x)
var xLogical = yScale.invert(point.y)
A possible solution I wrote to your problem using the above is
var instance = functionPlot({
target: '#demo',
disableZoom: true,
data: [{
fn: 'sin(10*(-cos(x) + y^2/2-1))',
fnType: 'implicit'
}]
})
var xScale = instance.meta.xScale
var yScale = instance.meta.yScale
var canvas = instance.canvas
var circle = canvas.append('circle')
.attr("r", 5)
.style("fill", "purple")
var start = Date.now()
function animate() {
// move the point along the circle of radius 1
var t = (Date.now() - start) * 0.003
var xLogical = Math.cos(t)
var yLogical = Math.sin(t)
var xCanvas = xScale(xLogical)
var yCanvas = yScale(yLogical)
circle
.attr('cx', xCanvas)
.attr('cy', yCanvas)
requestAnimationFrame(animate)
}
animate()
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://maurizzzio.github.io/function-plot/js/function-plot.js"></script>
<div id="demo"></div>
Issue in function plot's GitHub
I realise that this isn't exactly what you want but it does demonstrate that your code can be compact and still do what you require.
The following is some code that demonstrates some maths to animate a pendulum, extracted from one of my javascript widgets but the math logic should still be usable in your own project.
Create an image object - pendulumSet, a nice round ball will do.
// variables set for the pendulum
var gravity = -0.0110808; // tuned to -0.110808 as it approximates a 1 second interval
var acceleration = 0.1; //0.1
var velocity = 0.18; //.18
var angle = 8; // 8 (.4 radians = 22.91 degrees)
Create a timer with an interval of 0.01 seconds
Put this in the timer:
acceleration = gravity * angle;
velocity += acceleration;
angle += velocity;
pendulumSet.rotation = angle +180; // rotation as per a widget engine
That's it...
You might have to use something like the following to achieve the rotation in native javascript:
pendulumSet.style.transform = "rotate(90deg)"; // change the 90deg
This code above will simulate a pendulum in a much more compact fashion. This is 1/100th of a second, graphic animation and mathematical calculation so it will take some cpu, that is unavoidable. Nevertheless, the code is compact and the impact is minimal. Depending upon the engine interpreting the code, the cpu usage will be approx. 20-25% of a 2.5ghz core2duo from 2009, easily handled by more modern, faster cpus. Running similar code in Firefox may be noticeably slower as Firefox, in my experience, seems to perform similar animations less efficiently. You just have to try it and see.
The code is taken from this example javascript widget:
A steampunk clock for the desktop
So you can see the exact same code in operation.

Mouse events with d3.js and HTML5 Canvas (not SVG)

I'm fairly new to the Canvas and am completely new to d3.js...
I'm trying to use d3.js and the Canvas to create an interactive data visualisation. I have a very basic version of it working, however I'm a bit stumped on how to accurately interact with each node (a circle).
There seems to be limited info online on how to do this, or am I missing something?
I'm currently just trying to change the mouse cursor on mouseover / mouseout with the following code:
canvas.on("mousemove", function() {
var m = d3.mouse(this);
selectNode( m[0], m[1] );
});
var nodeI, thisNX, thisNY, nHover;
for ( i; i < nodes.length; i++ ) {
nX = nodes[i].x,
nY = nodes[i].y,
nR = nodes[i].radius - 3,
nHover = nodes[i].hover || "";
if ( mX >= nX - nR && mX <= nX + nR && mY >= nY - nR && mY <= nY + nR && nHover === "" ) {
console.log( "mouse on!" );
nodeI = nodes[i].index;
thisNX = nX;
thisNY = nY;
$('html,body').css('cursor','pointer');
nodes[i].hover = true;
} else {
if ( nHover === true ) {
console.log( "mouse off!" );
nodes[nodeI].hover = "";
$('html,body').css('cursor','default');
}
}
And here's a working fiddle: http://jsfiddle.net/u90cmm36/
I'm pretty close to getting this working, although I can't get the mouseout working correctly.
Am I going about this the correct way? It seems a little long winded to me. Where's the built in mouseover / mouseout for d3.js for the Canvas?
Thanks for your help!!
Unfortunately, there is no built-in mouseover for canvas. There's some libraries that do it, like KineticJS, but I haven't used it much. D3, which I have used quite a bit, doesn't have built in mouseover for canvas, to my knowledge.
Usually, if I'm using d3 with canvas, I use a transparent SVG layer to control mouse interaction. This approach gives both the interactivity of SVGs and the finer graphic control of canvas, but can drag performance down if you have LOTS of interactive bits, since each different interaction requires a DOM element. You can also do things by tracking mouse position, which is what you're doing. There's a few problems with your approach, though.
Right now, you're looping through all of your nodes to check mouse position one at a time. Even if your mouse is in a node, the loop will continue and change the cursor back when it checks and sees that you aren't in the next node in the loop. You should change this to check and see if you're in ANY of the nodes, and then once you've determined if you're in a node or not, stop checking the rest of the nodes and change your cursor (if it needs to be changed.)
Your current method of checking mouseover also checks bounding squares instead of circles. This will check if the mouse is in a circle:
var distance = Math.sqrt(Math.pow(nX - mX, 2) + Math.pow(nX - mX, 2));
if(distance <= nR){ //mouseover };

How to obtain data from the scene simulation with physijs and threejs

I-m working on a demo, it's very similar a one example in this page (http://chandlerprall.github.io/Physijs/examples/body.html ). It's just a box falling down. But I want to calculate the time taken since the box starts falling until it gets to the ground so I can calculate the velocity. Is there a way to do that?? Please help.
Here's an algorithm:
Animate : function (cb) {
//the above is whatever your initial animation function is
THREE.Clock.startTime = (new Date()).getMilliseconds();
if (objects touch ground) {
var now = (new Date()).getMilliseconds();
THREE.Clock.duration = now - THREE.Clock.startTime;
}
}

Attempting to get two simultaneous joysticks working with touch events

I've been battling with this for two days. I'm using an HTML5/JS game engine called ImpactJS and someone made a very useful plugin to create joystick touch zones for mobile devices. The idea is that you specify a zone on the screen where the joystick is activated when that area is touched.
The code for the plugin I am using is here. I have modified it slightly to add "curPos" (x and y coordinates of the spot that the user is currently touching), otherwise all code is identical. I have been trying to solve this problem myself as well as contacting the original creator, but they seem to be unreachable at this time and I'm getting nowhere.
I'm sure I'm doing something very wrong here, but while I can get the touch zones to work perfectly on their own, every time I try to use both joysticks at the same time they partially overwrite each other.
I have specified two zones as follows when my game initializes:
this.joystick1 = new TouchJoystickZone(0, 0, ig.system.width / 2, ig.system.height);
this.joystick2 = new TouchJoystickZone(ig.system.width / 2, 0, ig.system.width / 2, ig.system.height);
this.joystick1 is responsible for player rotation. this.joystick2 is responsible for player acceleration. In my Player entity I have the following movement code for the two joysticks. Again, this works perfectly when I only have one finger on the screen/one joystick in use:
if( ig.ua.mobile ) {
// ROTATION
if (ig.game.joystick1.touchStart.x > 0 && ig.game.joystick1.touchStart.x < ig.system.width/2) {
if (Math.abs(ig.game.joystick1.delta.x) >= 50 || Math.abs(ig.game.joystick1.delta.y) >= 50) {
this.joystickAngle = ig.game.Controller.toDegrees(ig.game.Controller.joystickAngle());
if (this.angle > this.joystickAngle + 20) {
this.angle -= this.turnSpeed * ig.system.tick;
}
else if (this.angle < this.joystickAngle - 20) {
this.angle += this.turnSpeed * ig.system.tick;
}
else {
this.angle = this.joystickAngle;
}
}
}
// THRUST
if (ig.game.joystick2.touchStart.x > ig.system.width / 2) {
if (ig.game.joystick2.delta.y <= -50) {
this.accel.x = Math.cos(this.angle*Math.PI/180)*this.thrust;
this.accel.y = (Math.sin(this.angle*Math.PI/180)*this.thrust);
this.fuel -= 0.1;
}
else if (ig.game.joystick2.delta.y >= 50) {
this.accel.x = Math.cos(this.angle*Math.PI/180)*-this.thrust;
this.accel.y = (Math.sin(this.angle*Math.PI/180)*-this.thrust);
this.fuel -= 0.1;
}
}
else {
this.accel.x = 0;
this.accel.y = 0;
}
}
As soon as I place a second finger on the screen, however, the first joystick becomes overwritten. I can rotate and then move or move and then rotate and it works fine, but I need to do both at the same time.
I found out that touchStart.x and touchStart.y seems to be being set for both joysticks when I tap to use the other stick and not just the relevant joystick1 or joystick2, even though in the plugin code those coordinates are only meant to be affected if the touch for that joystick is within the specified zone. I believe this is partly what is contributing to the issue. At this stage I've spent hours trying to figure this out and am just as lost as when I started.
Can someone possibly point me in the right direction with using both of these joysticks at the same time?
The joystick script you are using is only looking for the first finger. The following is from lines 47-48
var x = ev.touches[0].pageX - pos.left,
y = ev.touches[0].pageY - pos.top;
The '0' determines which finger to track.
The script would have the be changed to be aware which finger is on which element and then only track that finger. You could do that by either determining which element was pressed first or by location.
JSFiddle Example: http://jsfiddle.net/7WR88/5/
http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
As mentioned by #Dcullen, there may be multiple touches in each event starting at the first touch.
It would be a simple solution to iterate through the ev.touches collection and see if each touch falls into a hotzone. If it falls under hot zone 1, treat it as a touch for joystick 1. If it falls under hotzone 2, treat it as a touch for joystick 2.
This would mean that it doesn't matter in which order the touches appear, because they will always map to the correct joystick if they are near to it.

How can I make Raphael.js elements "wiggle" on the canvas?

I'm working on a project that uses SVG with Raphael.js. One component is a group of circles, each of which "wiggles" around randomly - that is, slowly moves along the x and y axes a small amount, and in random directions. Think of it like putting a marble on your palm and shaking your palm around slowly.
Is anyone aware of a Raphael.js plugin or code example that already accomplishes something like this? I'm not terribly particular about the effect - it just needs to be subtle/smooth and continuous.
If I need to create something on my own, do you have any suggestions for how I might go about it? My initial idea is along these lines:
Draw a circle on the canvas.
Start a loop that:
Randomly finds x and y coordinates within some circular boundary anchored on the circle's center point.
Animates the circle from its current location to those coordinates over a random time interval, using in/out easing to smooth the effect.
My concern is that this might look too mechanical - i.e., I assume it will look more like the circle is tracing a star pattern, or having a a seizure, or something like that. Ideally it would curve smoothly through the random points that it generates, but that seems far more complex.
If you can recommend any other code (preferably JavaScript) that I could adapt, that would be great too - e.g., a jQuery plugin or the like. I found one named jquery-wiggle, but that seems to only work along one axis.
Thanks in advance for any advice!
Something like the following could do it:
var paper = Raphael('canvas', 300, 300);
var circle_count = 40;
var wbound = 10; // how far an element can wiggle.
var circleholder = paper.set();
function rdm(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
// add a wiggle method to elements
Raphael.el.wiggle = function() {
var newcx = this.attrs.origCx + rdm(-wbound, wbound);
var newcy = this.attrs.origCy + rdm(-wbound, wbound);
this.animate({cx: newcx, cy: newcy}, 500, '<');
}
// draw our circles
// hackish: setting circle.attrs.origCx
for (var i=0;i<circle_count;i++) {
var cx = rdm(0, 280);
var cy = rdm(0, 280);
var rad = rdm(0, 15);
var circle = paper.circle(cx, cy, rad);
circle.attrs.origCx = cx;
circle.attrs.origCy = cy;
circleholder.push(circle);
}
// loop over all circles and wiggle
function wiggleall() {
for (var i=0;i<circleholder.length;i++) {
circleholder[i].wiggle();
}
}
// call wiggleAll every second
setInterval(function() {wiggleall()}, 1000);
http://jsfiddle.net/UDWW6/1/
Changing the easing, and delays between certain things happening should at least help in making things look a little more natural. Hope that helps.
You can accomplish a similar effect by extending Raphael's default easing formulas:
Raphael.easing_formulas["wiggle"] = function(n) { return Math.random() * 5 };
[shape].animate({transform:"T1,1"}, 500, "wiggle", function(e) {
this.transform("T0,0");
});
Easing functions take a ratio of time elapsed to total time and manipulate it. The returned value is applied to the properties being animated.
This easing function ignores n and returns a random value. You can create any wiggle you like by playing with the return formula.
A callback function is necessary if you want the shape to end up back where it began, since applying a transformation that does not move the shape does not produce an animation. You'll probably have to alter the transformation values.
Hope this is useful!
There is a very good set of easing effects available in Raphael.
Here's a random set of circles that are "given" bounce easing.
Dynamically add animation to objects
The full range of easing effects can be found here. You can play around with them and reference the latest documentation at the same time.
Putting calls in a loop is not the thing to do, though. Use callbacks, which are readily available.

Categories