Image's pivot and resize animation

Hi all!.

I have been trying to sort a problem related with an animation that resizes an image in relation to the position of another image. I have a graphic element, namely the “icon”, that is positioned close to the top of the screen, but it can be at any point of the x axis. The idea is that when the “icon” is clicked wih the mouse, an image is opened at close distance to the element. So if the the distance between the element to be clicked and the width of the OF Window is more than the width of the image, the later is drawn at the right of a graphic element, and if the distance between the element and the width of the image is less than the width of the image, it is drawn at the left of the “icon” in order to keep it within the margins of the screen. By using ofPushMatrix() I can positioned the card correctly in relation to the element, and when the card is drawing at the right the animation works good since the image grows from the top left corner, which is the corner closer to the “icon”. The problem arises when the card is at the left, since despite positioned the card correctly the animation always grown from the top-left and not from the top-right, which is the closer to the “icon”.

here is the code:

#include "element.h"
#include "ofMain.h"

element::element(){}

void element::setup(std::string imgString, std::string imgOverString, std::string imgCardString, int posX, int posY){

  image.load(imgString);
  imageOver.load(imgOverString);
  imageCard.load(imgCardString);

  pos.x = posX;
  pos.y = posY;

  touched = false;

  previousCycle = false;

  animVel = 4;
  
  // animDuration = 1000;
}

void element::update(){

  // std::cout << deltaTime << std::endl;

if (previousCycle && touched) {
  deltaTime += ofGetLastFrameTime() * animVel; 
  if (deltaTime > 1) deltaTime = 1;
  previousCycle = true;
 }

 if (!previousCycle && touched ) {
   deltaTime = 0;
   previousCycle = true;
 }

 if (previousCycle && !touched) {
   deltaTime = 1;
  previousCycle = false;
 }

 if (!previousCycle && !touched ) {
   deltaTime += (-1 * ofGetLastFrameTime()) * animVel; 
   if (deltaTime < 0) deltaTime = 0;
   previousCycle = false;
 }

  std::cout << deltaTime << std::endl;
  
  }

void element::draw(){

  //draw image or overImage if the mouse if ever the graphic element
  
  if( ofGetMouseX() >= pos.x && ofGetMouseX() <= pos.x + image.getWidth() &&
      ofGetMouseY() >= pos.y && ofGetMouseY() <= pos.y + image.getHeight()){
    
    imageOver.draw(pos.x, pos.y);

  } else {

    image.draw(pos.x, pos.y); 

  }

  //position card 
  //initializing the temporal pos of the card
  //check whether the card gets out of frame, if it does it reposition the card.
  
  tempPosX = 0;
  tempPosY = 0;

  if (pos.x + image.getWidth() + imageCard.getWidth() + 20 > ofGetWidth()) {

    tempPosX = pos.x - (imageCard.getWidth() + 20);
    tempPosY = pos.y;
      
  } else {

    tempPosX = pos.x + image.getWidth() + 20;
    tempPosY = pos.y;
  
  }
  
//declaring a variable for the animation out of 
//the function that interpolate the initial and final values

  float xSize = interpolateValue(0, 1, deltaTime);
  float ySize = interpolateValue(0, 1, deltaTime);

  
  if (touched == 1) { //if the element is clicked or touched it opens the card
      
    ofPushMatrix();
    ofTranslate(tempPosX, tempPosY);
    ofScale(xSize * 4, ySize * 4, 0);
    imageCard.draw(0, 0);
    ofPopMatrix();
      
   
  } else { //if the click is beyond the element image, the card closes. 

    ofPushMatrix();
    ofTranslate(tempPosX, tempPosY);
    ofScale(xSize * 4 , ySize * 4, 0);
    imageCard.draw(0, 0);
    ofPopMatrix();  
    
  }
}

void element::isTouched(int input, int state){

if (ofGetMouseX() >= pos.x && ofGetMouseX() <= pos.x + image.getWidth() &&
      ofGetMouseY() >= pos.y && ofGetMouseY() <= pos.y + image.getHeight()) {

  if (input == state) {
    touched = true;
  } else {
    touched = false;
  }

  } else {

  if (input == state) {

    if (touched == true) {
      touched = false;
    } else {
      touched = false;
    }
  }
  }

  std::cout << touched << std::endl;

}

float element::interpolateValue(float initialValue, float finalValue, float mod){
  
  return ((1-mod) * initialValue) + (0.25 * mod);

}

I have not be able to change the pivot of the image with ofPushMatrix() so I wondering whether there is a different method.

thanks

Hey @pemb , would ofImage::setAnchorPoint() be helpful?

Another thought is to use ofImage::draw(); it has some versions that take both a position and size (width and height). Using these 3 things, it’s possible to “grow” an image in any direction. To grow an image to the right, the width/height arguments can vary with a fixed position. To grow it to the left, the position can be recalculated from the width and height. ofTranslate() and ofScale() might also work OK too, but they may add an extra layer of complexity.

Something like this will grow an image from the top-right corner:

// in ofApp.h:
ofImage image;
float x, y, w, h = 0.f;

// in ofApp::update()
    if(h < ofGetHeight()){
        h += 1.f;
        w = h * ofGetWidth() / ofGetHeight();
        x = ofGetWidth() - w;
        y = 0.f;
    }

// in ofApp::draw()
image.draw(x, y, w, h);

Hi @TimChi;

I had just discovered the setAnchrpoint() when you sent me the answer. It works as intended.

thanks a lot

1 Like

Hey @pemb ofImage::setAnchorPercent() is a similar one if you haven’t found it already. It might work well with how you’re using ofScale(). Glad that it’s working OK!