# Keep the position when not clicking

**URL:** <https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652>\
**Category:** Project Guidance\
**Created:** [May 8, 2020, 11:17pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652 "2020-05-08T23:17:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![matildespinheiro](https://avatars.discourse-cdn.com/v4/letter/m/b19c9b/32.png) [@matildespinheiro](https://discourse.processing.org/u/matildespinheiro)\
**Post date:** [May 8, 2020, 11:17pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/1 "2020-05-08T23:17:06Z")

</div>

I’m doing a project that we need to rotate an circular image relativity to the mouse.

The circle only moves when we click and drag the hand (mouse). When we are not dragging the mouse the image doesn’t move, which is good. However, if we stop clicking and start dragging on a different position it does the same as if we were clicking and dragging it.

This is a part of the code we have:

draw():  
pushMatrix();  
translate(width/2, height/2);  
float rotAngle = atan2(dragY - height/2, dragX - width/2);  
rotate(rotAngle);  
image(abc, 0, 0, ABC\_SIZE, ABC\_SIZE);  
popMatrix();  
mouseDragged():  
dragX = mouseX;  
dragY = mouseY;

images:

 ![Screenshot 2020-05-09 at 00.17.52](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f5cde239f660e179a18e300ee46b0273ebd68293.png)

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [May 9, 2020, 6:08am UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/2 "2020-05-09T06:08:49Z")

</div>

Maybe show your entire code please and then we can test

The atan2 line uses dragY.  
When this still has its old value, that’s bad.

Maybe update it in function mousePressed when dragging starts

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 9, 2020, 11:45am UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/3 "2020-05-09T11:45:47Z")

</div>

Hello,

> [@matildespinheiro](#):
>
> draw():

I changed category to Processing.py. Is that what you are using?

Get to know the resources available to you.  
There is a tab on top of page for Processing.py also.

> **Resources \< Click here to expand !**
>
> I encourage you to review the resources available here:
> 
> - The Processing website has references, examples, tutorials, etc.  
> [https://processing.org/](https://processing.org/)
> - Those available with the Processing PDE (IDE).  
> An exploration of the tabs will reveal what is available; there are libraries and examples there.
> - The Coding Train  
> [https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1\_aw](https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1_aw)  
> [https://thecodingtrain.com/](https://thecodingtrain.com/)
> - Happy Coding  
> [Processing Tutorials - Happy Coding](https://happycoding.io/tutorials/processing/)
> - The Processing Foundation  
> [https://processingfoundation.org/](https://processingfoundation.org/)  
> Check out the tabs.  
> In the education tab, there is a reference to the Coding Train.

`:)`

Please format your code as a courtesy to others:  
[https://discourse.processing.org/faq#format-your-code](https://discourse.processing.org/faq#format-your-code)

`:)`

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 9, 2020, 12:22pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/4 "2020-05-09T12:22:59Z")

</div>

Hello,

Your code worked in Processing as is with some modification.

I removed mouseDragged() from draw and used it as follows:

```auto
int dragX;
int dragY;

void setup()
  {
  size(400, 400);
  }

void draw()
  {
 //Your code
 // I also added circles and did not use image 
  }
  
// Updates only if inside circle (you set limits); this can be adapted for more control.
void mouseDragged()
  {
  //Equation to a circle; limiting mouse update to within circle.
  if (((mouseX-width/2)*(mouseX-width/2)+ (mouseY-width/2)*(mouseY-width/2)) < 110*110)
    {
    dragX = mouseX;
    dragY = mouseY;
    }  
  }

```

Take a look at the simple example I provided and try to understand it; this can be adapted for your use.

Some references for Processing:  
[https://processing.org/examples/button.html](https://processing.org/examples/button.html)  
[https://processing.org/examples/mousefunctions.html](https://processing.org/examples/mousefunctions.html)

![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/21363825c3dde52aea6a202008cd5b7f4f4b577f.png)

`:)`

---

<div class="post-metadata">

**Author:** ![matildespinheiro](https://avatars.discourse-cdn.com/v4/letter/m/b19c9b/32.png) [@matildespinheiro](https://discourse.processing.org/u/matildespinheiro)\
**Post date:** [May 9, 2020, 6:16pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/5 "2020-05-09T18:16:12Z")

</div>

import java.util.Arrays;  
import java.util.Collections;  
import java.util.Random;

// Screen resolution vars;  
float PPI, PPCM;  
float SCALE\_FACTOR;

// Finger parameters  
PImage fingerOcclusion;  
int FINGER\_SIZE;  
int FINGER\_OFFSET;

// Arm/watch parameters  
PImage arm;  
int ARM\_LENGTH;  
int ARM\_HEIGHT;

// Abc parameters  
PImage abc;  
int ABC\_SIZE;

// Check parameters  
PImage check;  
int CHECK\_SIZE;

// Study properties  
String[] phrases; // contains all the phrases that can be tested  
int NUM\_REPEATS = 2; // the total number of phrases to be tested  
int currTrialNum = 0; // the current trial number (indexes into phrases array above)  
String currentPhrase = “”; // the current target phrase  
String currentTyped = “”; // what the user has typed so far  
char currentLetter = ‘a’;

// Performance variables  
float startTime = 0; // time starts when the user clicks for the first time  
float finishTime = 0; // records the time of when the final trial ends  
float lastTime = 0; // the timestamp of when the last trial was completed  
float lettersEnteredTotal = 0; // a running total of the number of letters the user has entered (need this for final WPM computation)  
float lettersExpectedTotal = 0; // a running total of the number of letters expected (correct phrases)  
float errorsTotal = 0; // a running total of the number of errors (when hitting next)

int dragX = width/2; // the position of the mouse when dragged  
int dragY = height/2;

int lastX, lastY;

//Setup window and vars - runs once  
void setup()  
{  
//size(900, 900);  
fullScreen();  
textFont(createFont(“Arial”, 24)); // set the font to arial 24  
noCursor(); // hides the cursor to emulate a watch environment

// Load images  
arm = loadImage(“arm\_watch.png”);  
fingerOcclusion = loadImage(“finger.png”);  
abc = loadImage(“abc.png”);  
check = loadImage(“check.png”);

// Load phrases  
phrases = loadStrings(“phrases.txt”); // load the phrase set into memory  
Collections.shuffle(Arrays.asList(phrases), new Random()); // randomize the order of the phrases with no seed

// Scale targets and imagens to match screen resolution  
SCALE\_FACTOR = 1.0 / displayDensity(); // scale factor for high-density displays  
String[] ppi\_string = loadStrings(“ppi.txt”); // the text from the file is loaded into an array.  
PPI = float(ppi\_string[1]); // set PPI, we assume the ppi value is in the second line of the .txt  
PPCM = PPI / 2.54 \* SCALE\_FACTOR; // do not change this!

FINGER\_SIZE = (int)(11 \* PPCM);  
FINGER\_OFFSET = (int)(0.8 \* PPCM);  
ARM\_LENGTH = (int)(19 \* PPCM);  
ARM\_HEIGHT = (int)(11.2 \* PPCM);  
ABC\_SIZE = (int) (3.5 \* PPCM);  
CHECK\_SIZE = (int) (1.5 \* PPCM);  
}

void draw()  
{  
// Check if we have reached the end of the study  
if (finishTime != 0) return;

background(255); // clear background

// Draw arm and watch background  
imageMode(CENTER);  
image(arm, width/2, height/2, ARM\_LENGTH, ARM\_HEIGHT);

// Check if we just started the application  
if (startTime == 0 && !mousePressed)  
{  
fill(0);  
textAlign(CENTER);  
text(“Tap to start time!”, width/2, height/2);  
}  
else if (startTime == 0 && mousePressed) nextTrial(); // show next sentence

// Check if we are in the middle of a trial  
else if (startTime != 0)  
{  
textAlign(LEFT);  
fill(100);  
text("Phrase " + (currTrialNum + 1) + " of " + NUM\_REPEATS, width/2 - 4.0_PPCM, height/2 - 8.1_PPCM); // write the trial count  
text("Target: " + currentPhrase, width/2 - 4.0_PPCM, height/2 - 7.1_PPCM); // draw the target string  
fill(0);  
text("Entered: " + currentTyped + “|”, width/2 - 4.0_PPCM, height/2 - 6.1_PPCM); // draw what the user has entered thus far

```
// Draw very basic ACCEPT button - do not change this!
textAlign(CENTER);
noStroke();
fill(0, 250, 0);
rect(width/2 - 2*PPCM, height/2 - 5.1*PPCM, 4.0*PPCM, 2.0*PPCM);
fill(0);
text("ACCEPT >", width/2, height/2 - 4.1*PPCM);

// Draw screen areas    
// THIS IS THE ONLY INTERACTIVE AREA (4cm x 4cm); do not change size
noStroke();
noFill();
rect(width/2 - 2.0*PPCM, height/2 - 1.0*PPCM, 4.0*PPCM, 3.0*PPCM);

// Draw the letters in a circle
//imageMode(CENTER);
//image(abc, width/2, height/2, ABC_SIZE, ABC_SIZE);

// Rotate the letters
pushMatrix();
translate(width/2, height/2);
float rotAngle = atan2(dragY - height/2, dragX - width/2);
rotate(rotAngle);
image(abc, 0, 0, ABC_SIZE, ABC_SIZE);
lastX = dragX;
lastY = dragY;
popMatrix();  

// Draw the area where you put the letter wanted
stroke(0, 255, 0);
strokeWeight(2);
noFill();
rect(width/2 - 0.25*PPCM, height/2 - 1.8*PPCM, 0.5*PPCM, 0.5*PPCM);

// Draw the check
imageMode(CENTER);
image(check, width/2, height/2, CHECK_SIZE, CHECK_SIZE);

int points = 26;
float pointAngle = 360/points;
float radius = (3.5/2)*PPCM;
for(float angle = 0; angle < 360; angle = angle+pointAngle)
{
   float x = cos(radians(angle))*radius;
   float y = sin(radians(angle))*radius;
   
   line(x+width/2, y+height/2, width/2, height/2);
}
circle(width/2, height/2, 3.5*PPCM);

```

}

// Draw the user finger to illustrate the issues with occlusion (the fat finger problem)  
imageMode(CORNER);  
image(fingerOcclusion, mouseX - FINGER\_OFFSET, mouseY - FINGER\_OFFSET, FINGER\_SIZE, FINGER\_SIZE);  
}

// Check if mouse click was within certain bounds  
boolean didMouseClick(float x, float y, float w, float h)  
{  
return (mouseX \> x && mouseX \< x + w && mouseY \> y && mouseY \< y + h);  
}

void mouseDragged()  
{  
if(didMouseClick(width/2 - 2.0_PPCM, height/2 - 1.0_PPCM, 4.0_PPCM, 3.0_PPCM)) // Test click on ‘keyboard’ area - do not change this condition!  
{  
dragX = mouseX;  
dragY = mouseY;  
}  
else System.out.println(“debug: CLICK NOT ACCEPTED”);  
}

void mousePressed()  
{  
if (didMouseClick(width/2 - 2_PPCM, height/2 - 5.1_PPCM, 4.0_PPCM, 2.0_PPCM)) nextTrial(); // Test click on ‘accept’ button - do not change this!  
else if(didMouseClick(width/2 - 2.0_PPCM, height/2 - 1.0_PPCM, 4.0_PPCM, 3.0_PPCM)) // Test click on ‘keyboard’ area - do not change this condition!  
{  
// YOUR KEYBOARD IMPLEMENTATION NEEDS TO BE IN HERE! (inside the condition)

```
//DELETE Test click on left arrow
//if (didMouseClick(width/2 - ARROW_SIZE, height/2, ARROW_SIZE, ARROW_SIZE))
//{
// currentLetter--;
// if (currentLetter < '_') currentLetter = 'z'; // wrap around to z
//}
// Test click on right arrow
//else if (didMouseClick(width/2, height/2, ARROW_SIZE, ARROW_SIZE))
//{
// currentLetter++;
// if (currentLetter > 'z') currentLetter = '_'; // wrap back to space (aka underscore)
//}
// Test click on keyboard area (to confirm selection)
//else
//{
// if (currentLetter == '_') currentTyped+=" "; // if underscore, consider that a space bar
// else if (currentLetter == '`' && currentTyped.length() > 0) // if `, treat that as a delete command
// currentTyped = currentTyped.substring(0, currentTyped.length() - 1);
// else if (currentLetter != '`') currentTyped += currentLetter; // if not any of the above cases, add the current letter to the typed string
//}

```

}  
else System.out.println(“debug: CLICK NOT ACCEPTED”);  
}

void nextTrial()  
{  
if (currTrialNum \>= NUM\_REPEATS) return; // check to see if experiment is done

// Check if we’re in the middle of the tests  
else if (startTime != 0 && finishTime == 0)  
{  
System.out.println("==================");  
System.out.println("Phrase " + (currTrialNum+1) + " of " + NUM\_REPEATS);  
System.out.println("Target phrase: " + currentPhrase);  
System.out.println("Phrase length: " + currentPhrase.length());  
System.out.println("User typed: " + currentTyped);  
System.out.println("User typed length: " + currentTyped.length());  
System.out.println("Number of errors: " + computeLevenshteinDistance(currentTyped.trim(), currentPhrase.trim()));  
System.out.println(“Time taken on this trial: " + (millis() - lastTime));  
System.out.println(“Time taken since beginning: " + (millis() - startTime));  
System.out.println(”==================”);  
lettersExpectedTotal += currentPhrase.trim().length();  
lettersEnteredTotal += currentTyped.trim().length();  
errorsTotal += computeLevenshteinDistance(currentTyped.trim(), currentPhrase.trim());  
}

// Check to see if experiment just finished  
if (currTrialNum == NUM\_REPEATS - 1)  
{  
finishTime = millis();  
System.out.println("==================");  
System.out.println(“Trials complete!”); //output  
System.out.println("Total time taken: " + (finishTime - startTime));  
System.out.println("Total letters entered: " + lettersEnteredTotal);  
System.out.println("Total letters expected: " + lettersExpectedTotal);  
System.out.println("Total errors entered: " + errorsTotal);

```
float wpm = (lettersEnteredTotal / 5.0f) / ((finishTime - startTime) / 60000f); // FYI - 60K is number of milliseconds in minute
float freebieErrors = lettersExpectedTotal * .05; // no penalty if errors are under 5% of chars
float penalty = max(errorsTotal - freebieErrors, 0) * .5f;

System.out.println("Raw WPM: " + wpm);
System.out.println("Freebie errors: " + freebieErrors);
System.out.println("Penalty: " + penalty);
System.out.println("WPM w/ penalty: " + (wpm - penalty)); // yes, minus, because higher WPM is better
System.out.println("==================");

printResults(wpm, freebieErrors, penalty);

currTrialNum++; // increment by one so this mesage only appears once when all trials are done
return;

```

}

else if (startTime == 0) // first trial starting now  
{  
System.out.println(“Trials beginning! Starting timer…”);  
startTime = millis(); // start the timer!  
}  
else currTrialNum++; // increment trial number

lastTime = millis(); // record the time of when this trial ended  
currentTyped = “”; // clear what is currently typed preparing for next trial  
currentPhrase = phrases[currTrialNum]; // load the next phrase!  
}

// Print results at the end of the study  
void printResults(float wpm, float freebieErrors, float penalty)  
{  
background(0); // clears screen

textFont(createFont(“Arial”, 16)); // sets the font to Arial size 16  
fill(255); //set text fill color to white  
text(day() + “/” + month() + “/” + year() + " " + hour() + “:” + minute() + “:” + second(), 100, 20); // display time on screen

text(“Finished!”, width / 2, height / 2);  
text("Raw WPM: " + wpm, width / 2, height / 2 + 20);  
text("Freebie errors: " + freebieErrors, width / 2, height / 2 + 40);  
text("Penalty: " + penalty, width / 2, height / 2 + 60);  
text("WPM with penalty: " + (wpm - penalty), width / 2, height / 2 + 80);

saveFrame(“results-######.png”); // saves screenshot in current folder  
}

// This computes the error between two strings (i.e., original phrase and user input)  
int computeLevenshteinDistance(String phrase1, String phrase2)  
{  
int[][] distance = new int[phrase1.length() + 1][phrase2.length() + 1];

for (int i = 0; i \<= phrase1.length(); i++) distance[i][0] = i;  
for (int j = 1; j \<= phrase2.length(); j++) distance[0][j] = j;

for (int i = 1; i \<= phrase1.length(); i++)  
for (int j = 1; j \<= phrase2.length(); j++)  
distance[i][j] = min(min(distance[i - 1][j] + 1, distance[i][j - 1] + 1), distance[i - 1][j - 1] + ((phrase1.charAt(i - 1) == phrase2.charAt(j - 1)) ? 0 : 1));

return distance[phrase1.length()][phrase2.length()];  
}

---

<div class="post-metadata">

**Author:** ![matildespinheiro](https://avatars.discourse-cdn.com/v4/letter/m/b19c9b/32.png) [@matildespinheiro](https://discourse.processing.org/u/matildespinheiro)\
**Post date:** [May 9, 2020, 6:17pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/6 "2020-05-09T18:17:52Z")

</div>

below is the entire code

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 9, 2020, 6:37pm UTC](https://discourse.processing.org/t/keep-the-position-when-not-clicking/20652/7 "2020-05-09T18:37:58Z")

</div>

Please format your code as a courtesy to this community:  
[https://discourse.processing.org/faq#format-your-code](https://discourse.processing.org/faq#format-your-code)

Try to cut and paste your code into Processing and you will understand why.
