Smooth Zoom on Mouse click. Easing? And Stop Zooming.

Hello,

I've got this project set up and it almost works! What I'm having trouble with is two things; the first is I would like when the mouse is clicked for the zoom to smoothly grow into it's final state instead of snapping like it does now. The second issue I'm having trouble with is I would like the image to move back to it's original scale when the left mouse is clicked for the second time. Currently it just keep zooming in and you have to right mouse click to reset. Any suggestions? Thanks, you all have been a great help over the past few months.

import hype.*;
import hype.extended.layout.HGridLayout;
import hype.extended.behavior.HAttractor;

HDrawablePool pool;
HAttractor    ha;
HAttractor.HAttractionForce hf;



PImage img;

float zoom = 1;
float x,y;



void setup() {
    size(1364,640);
    H.init(this).background(#263746);
    smooth();


    img = loadImage("ring.png");


    ha = new HAttractor()
        .repelMode()
        .addForce(320, 320, 200)
        .debugMode(false);
    hf = ha.getForce(0);

    pool = new HDrawablePool(1248);
    pool.autoAddToStage()
        .add(new HEllipse(4))
        .layout(new HGridLayout().startX(21).startY(21).spacing(26,26).cols(52))
        .onCreate(
             new HCallback() {
                public void run(Object obj) {
                    HDrawable d = (HDrawable) obj;
                    d.stroke(#dddddc).fill(#263746).anchorAt(H.CENTER);

                    ha.addTarget(d, 8, 1f);

                }
            }
        )
        .requestAll()
    ;
}



void draw() {
    hf.loc(mouseX, mouseY);
    H.drawStage();


        pushMatrix();
        translate(682 + x*zoom, 320 + y*zoom);
        scale(zoom);
        imageMode(CENTER);
        image(img, 10, 10, 400, 400);
        popMatrix();

}

void mousePressed() {


  if (mouseButton == LEFT) {
    x += (width/2 - mouseX)/zoom;
    y += (height/2 - mouseY)/zoom;
    zoom *= 3;
  } else {
    zoom = 1;
    x = 0;
    y = 0;
  }

}
Tagged:

Answers

  • I would modify your function in the following manner:

    final float DEFAULT_ZOOM = 1.0;
    
    //Your setup()....
    //Your draw()....    
    
    void mousePressed() { 
      if (mouseButton == LEFT) {
        zoom=map(mouseX,0,width,0.5,3.0); // Mapping zoom scaling factor to mouseX position along the sketch width.
      }
    
      //Reset scaling to an original value
      if (mouseButton == RIGHT) {
        zoom=DEFAULT_ZOOM;
      }
    }
    

    I hope it helps,

    Kf

  • @kfrajer Thanks for the help but what I'm trying to avoid is using the right mouse button. Is there any way to click once with the left and it zooms in then click the left mouse button again and it goes back to the original size?

    Thanks

  • @Brendan_Wilson If you are trying to switch between two modes when the mouse is clicked, perhaps do that with mouseClicked. Then only execute your mousePressed code if the mouse is in the correct mode.

  • I bet it would. I'll have to look up how to do that hahah.

  • edited October 2016

    Hey @jeremydouglass

    This is what I got so far from your advice. It almost works, as in every other left click it will stay zoom in and then the second left click brings it back. BUT most of the time it zooms in then snaps back right away. See anything I might change to fix this?

    Thanks a lot for your help.

    void mousePressed() {
    
          if (mouseButton == LEFT) {
            x += (width/2 - mouseX)/zoom;
            y += (height/2 - mouseY)/zoom;
            zoom *= 4;
          } 
    
        }
    
        void mouseClicked() {
    
          if (mouseButton == RIGHT) {
    
          } else {
            zoom = 1;
            x = 0;
            y = 0;
          }
    
        }
    
  • edited October 2016 Answer ✓

    @Brendan_Wilson -- I think you are facing a few challenges here. You want a timed event. You want smoothly changing zoom values while the event is happening. You want it to stop on its own. You want it to be reversible (zoom-in-out). And there are actually several different ways of solving each of these problems!

    One approach is to save a start time (start a timer) anytime you click, and then use lerp() to compute the zoom value based on that time. Click -- clock starts -- code computes more and more zoom until the clock gets too far away, then it maxes out and stops itself.

    lerp(zoomFrom, zoomTo, elapsedTime/zoomDuration);
    

    For zooming back out -- you could store a flag and turn it on and off, but if you only have a fixed zoom in and zoom out, the simpler thing is just to swap your "from" and "to" zoom variables. Click -- "zoom from 1 to 5" -- Click -- "zoom from 5 to 1" -- Click -- "zoom from 1 to 5". Zoom works the same in both directions, and there is only 1 kind of click.

    float tmp = zoomFrom;
    zoomFrom = zoomTo;
    zoomTo = tmp;
    

    Here is a simple example sketch to illustrate this kind of approach:

    /**
     * A Timed Click-to-Zoom
     * 2016-10-03
     **/
    
    float zoomFrom;
    float zoomTo;
    int   zoomDuration;
    int   zoomStart;
    
    void setup(){
      size(200,200);
      zoomTo   = 1.0;
      zoomFrom = 5.0;
      zoomDuration = 1000;
      zoomStart = -zoomDuration;
    }
    
    void draw(){
      background(0);
      scale(zoomState());
      rect(10,10,20,20);
    }
    
    float zoomState(){
      float elapsed = millis() - zoomStart; // check timer
      if(elapsed < zoomDuration){ // don't zoom past 100% duration
        return lerp(zoomFrom, zoomTo, elapsed/zoomDuration); // zoom based on elapsed time
      }
      else{
        return zoomTo;
      }
    }
    
    void mouseClicked() {
      if (mouseButton == LEFT) {
        if(zoomState() == zoomTo){ // act only if we are not already mid-zoom
          float tmp = zoomFrom; zoomFrom = zoomTo; zoomTo = tmp; // swap values
          zoomStart = millis(); // start timer
        }
      }
    }
    
  • @jeremydouglass Damn dude! works great. Thanks again for your help!

Sign In or Register to comment.