- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Looking for a way to control and move a shape across a graph
I'm looking for a way to control and move a 'drawn' shape or series of shapes across plot (graph builder) using JSL script, for data visualisation purposes. Think of it as an animation using a series of frames and then scrolling through them to give the impression of movement.
By 'drawn' shape, I mean something like:
Rect ()
I was thinking of taking the following approach, but I'm not sure exactly how to execute this or if there's a better approach:
- Script / draw the shape(s) required and associate them with a variable (which could be a row value) - we'll call this a frame
- Construct multiples frames, with the shape(s) required in different positions, with each frame assigned to a distinct variable
E.g.
Frame 1 - Shape is in position (X+0,Y) and associated with variable (v = 1)
Frame 2 - Shape is in position (X+1,Y) and associated with variable (v = 2)
Frame 3 - Shape is in position (X+2,Y) and associated with variable (v = 3)
- Use local data filter to scroll which variable is selected and therefore the position of the drawn shape(s)
I'd hope that this, as described in my example, would give the impression of the shape moving in direction X+.
As aforementioned I am unsure that this would work, the graph builder report would need to be updated / refreshed somehow to remove the old drawing (overwritten) in place of the new one when the variable selected is being changed.
I'm eager to see if something like this is possible and how this could be coded.
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
x1 = y1 = x2 = y2 = 0;
keepRunning=1;
New Window( "Example", gb = Graph Box( Frame Size( 800, 800 ), Oval( x1, y1, x2, y2 ) ), <<onclose(keepRunning=0;1) );
Wait( 0.1 );
radius = 5;
x = 50;
y = 90;
velocity = 0;
accel = .2;
prevtime = Tick Seconds();
While( keepRunning,
curtime = Tick Seconds();
dt = curtime - prevtime;
prevtime = curtime;
velocity -= accel;
dy = velocity * dt;
y = Max( 1, y + dy );
//Show( y );
ysize = Min( radius, y );
xsize = radius ^ 2 / ysize;
x1 = x - xsize;
x2 = x + xsize;
y1 = y + ysize;
y2 = y - ysize;
gb[framebox( 1 )] << inval << reshow;
Wait( 0 );
// the bounce is hard to model. the velocity decreases rapidly, then reverses rapidly.
// the following isn't quite right...
If( y < radius,
velocity += 5 / y; // reverse harder as the ball squishes more.
);
velocity *= .99;
);
- Chapters
- descriptions off, selected
- captions settings, opens captions settings dialog
- captions off, selected
- default, selected
This is a modal window.
Beginning of dialog window. Escape will cancel and close the window.
End of dialog window.
This is a modal window. This modal can be closed by pressing the Escape key or activating the close button.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
Could you provide better example about what you try to visualize? JMP does for example have Mousetrap() which can draw things based on the cursor location in the framebox
Names Default To Here(1);
dt = open("$SAMPLE_DATA/Big Class.jmp");
gb = dt << Graph Builder(
Variables(X(:weight), Y(:height), Overlay(:sex)),
Elements(Points(X, Y, Legend(9)), Line Of Fit(X, Y, Legend(11)))
);
exx = 70;
exy = 70;
Report(gb)[FrameBox(1)] << Add Graphics Script(
Mousetrap(
exx = x;
exy = y;
);
Rect({exx - 10, exy - 10}, {exx, exy});
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
This is really neat.
I think I can find a use for this, I'm eager to a have a play around to see how it works.
I'm now keen on taking a more passive approach to my initial problem, I didn't realise you can control a shapes velocity, acceleration over time like in Craige's example.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
x1 = y1 = x2 = y2 = 0;
keepRunning=1;
New Window( "Example", gb = Graph Box( Frame Size( 800, 800 ), Oval( x1, y1, x2, y2 ) ), <<onclose(keepRunning=0;1) );
Wait( 0.1 );
radius = 5;
x = 50;
y = 90;
velocity = 0;
accel = .2;
prevtime = Tick Seconds();
While( keepRunning,
curtime = Tick Seconds();
dt = curtime - prevtime;
prevtime = curtime;
velocity -= accel;
dy = velocity * dt;
y = Max( 1, y + dy );
//Show( y );
ysize = Min( radius, y );
xsize = radius ^ 2 / ysize;
x1 = x - xsize;
x2 = x + xsize;
y1 = y + ysize;
y2 = y - ysize;
gb[framebox( 1 )] << inval << reshow;
Wait( 0 );
// the bounce is hard to model. the velocity decreases rapidly, then reverses rapidly.
// the following isn't quite right...
If( y < radius,
velocity += 5 / y; // reverse harder as the ball squishes more.
);
velocity *= .99;
);
- Chapters
- descriptions off, selected
- captions settings, opens captions settings dialog
- captions off, selected
- default, selected
This is a modal window.
Beginning of dialog window. Escape will cancel and close the window.
End of dialog window.
This is a modal window. This modal can be closed by pressing the Escape key or activating the close button.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
This looks really good, I think this is what I'm after - I really like how this can be time driven.
Would it be possible to get this to work for a more complex drawing, such as:
Fill Color( RGB Color( 255, 0, 0 ) );
Rect (50, 90, 60, 80, 1);
Fill Color( RGB Color( 204, 0, 0 ) );
Rect (51, 89, 59, 81, 1);
Fill Color( RGB Color( 255, 0, 0 ) );
Polygon ( {59, 89}, {60, 90}, {50, 90}, {51, 89});
Fill Color( RGB Color( 153, 0, 0 ) );
Polygon ( {60, 80}, {59, 81}, {51, 81}, {50, 80});
Rather than bouncing, when the bottom of the shape hits the X-axis, I want to be able to get it to stop and stay in place.
Also, after a given time has elapsed I'd like other shapes drawing to enter the screen and follow the same path, with each one settling on the X-axis.
I've had a play around with the script you sent, but not sure quite how to modify it in the right way - really clever!!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: Looking for a way to control and move a shape across a graph
Yes, you can do that. It sounds like your object has a rigid shape and you want it to stop instantly when some condition is met. Not gradually slow down or distort. And it sounds like you will have multiple objects that may be released over time. I'd use a data table with one row per object, with column names similar to these:
Xpos Ypos Xvel Yvel XdeltaVel TdeltaVel IsActive IsDrawing Color Size Shape
Then I'd write two functions: UpdateRow( row number, deltaTime ) and DrawRow( row number ). UpdateRow might look something like this (untested, approximately right...):
UpdateRow = function({rowNumber, deltaTime}
if( dtQ:isActive[rowNumber],
dtQ:Xpos[rowNumber] += dtQ:Xvel[rowNumber] * deltaTime;
dtQ:Ypos[rowNumber] += dtQ:Yvel[rowNumber] * deltaTime;
// you might want the velocity to change as well, possibly using the deltaVelocity,
// make sure the Xs and Ys stay together
// do a test to see if still active
if( dtQ:y[rowNumber] <= 0, // whatever condition makes it stop
dtQ:isActive[rowNumber] = 0;
dtQ:isDrawing[rowNumber] -= 1; // count down until vanishes
)
}
When you add a row to the table (dtQ
, above, I tend to use dt for a table not delta time!) make sure to set the row's value for isActive to 1, and if you want the non-active objects to eventually expire, set the isDrawing to 100 or 1000 to control how many cycles go by before it stops drawing.
The DrawRow function looks something like this:
DrawRow = function({RowNumber},
if( dtQ:isDrawing[RowNumber],
// your code goes here. Add the dtQ:Xpos[RowNumber] to your X coords
// and same for Ypos/Y.
// .... use the color/size/shape values from the row if you find them useful
)
);
Now the graphics script becomes a pair of loops over dtQ, the first to apply the updates, and the second to do the drawing. You don't have to keep them separated, but you might find it helpful later if you decide to handle collisions.
In this example, the data table in dtQ could also be displayed with graph builder by plotting the xpos, ypos, color, size, shape values. GraphBuilder will update automatically and you don't need the DrawRow function. I've never used it but I think there might be a custom shape drawing mechanism for the points.
If you are trying to make a video (rather than an interactive, real-time display), settle on 30 or 60 FPS and let the delta time be constant from frame to frame. Above, I picked numbers that made it work on my machine. But if I picked 1/30 and made a set of numbered images, they would make a very smooth video.