Basically, i want to simulate spring behavior on painted image. I want to make it run through a few iterations scaling it up and down (like it is fixed on a spring).
All of the examples i found on the net lead to this class - FloatSpring.java
It should provide the needed calculations to move point A to point B applying spring-like effect which depends on various FloatSpring class settings. The problem is that i didn't find a single clear example how to use it properly.
I made this small example to test FloatSpring
on:
public static void main ( String[] args )
{
// Some image to bounce
final ImageIcon icon =
new ImageIcon ( WebProgressOverlayExample.class.getResource ( "icons/ava1.jpg" ) );
// Component to paint image on
JComponent spring = new JComponent ()
{
// Zoom value (1f = 100% = normal size)
float zoom = 1f;
{
// Basic spring settings
final FloatSpring fs = new FloatSpring ( 100 );
fs.setPosition ( zoom );
// Animation delay
final int delay = 1000 / 24;
// Animator
new Timer ( delay, new ActionListener ()
{
private float elapsed = 0f;
public void actionPerformed ( ActionEvent e )
{
// Increasing elapsed time and updating spring
elapsed += delay;
fs.update ( 3f, elapsed );
// Updating zoom value and component
zoom = fs.getPosition ();
repaint ();
}
} ).start ();
}
protected void paintComponent ( Graphics g )
{
super.paintComponent ( g );
// Scaled image
int width = Math.round ( icon.getIconWidth () * zoom );
int height = Math.round ( icon.getIconHeight () * zoom );
g.drawImage ( icon.getImage (), getWidth () / 2 - width / 2,
getHeight () / 2 - height / 2, this );
}
public Dimension getPreferredSize ()
{
return new Dimension ( 500, 500 );
}
};
JFrame frame = new JFrame ();
frame.add ( spring );
frame.pack ();
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
In this example zoom
property should bounce from 1f to 3f within the timer cycle and finally lead the displayed on component image to 3X zoom. Something like simple animated transition.
FloatSpring class should be fine - i just don't understand how to use it properly. To be exact - what should i specify as the springK
and dampingK
values and also the time
property purpose is unclear...
I would really appreciate any help there.
Here's a working sscce using FloatSpring
.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
/**
* @see http://stackoverflow.com/a/11233735/230513
*/
public class Test {
private static Spring spring = new Spring();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(spring);
frame.add(new JButton(new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent e) {
spring.start();
}
}), BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
spring.start();
}
});
}
private static class Spring extends JComponent {
private static final int SIZE = 500;
private static final int DELAY = 1000 / 20; // ~20Hz
private final Icon icon = UIManager.getIcon("OptionPane.informationIcon");
private final FloatSpring fs = new FloatSpring(42);
private final int target = 0;
private final float delta = 1f / SIZE;
private float elapsed = 0f;
private Timer timer = new Timer(DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if ((int) fs.getPosition() < (target + 1)) {
timer.stop();
return;
}
elapsed += delta;
fs.update(target, elapsed);
repaint();
}
});
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - icon.getIconWidth()) / 2;
int y = (int) fs.getPosition();
icon.paintIcon(this, g, x, y);
int xc = x + icon.getIconWidth() / 2;
g.drawLine(xc, 0, xc, y);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE / 2, SIZE);
}
public void start() {
timer.stop();
elapsed = 0;
fs.setPosition(SIZE - icon.getIconHeight());
fs.setVelocity(0);
timer.start();
}
}
}