Currently I have this sample which creates four points , then connects it.
Basically what I want is to drag the whole connection of the lines(area) when you click on a line but when you selects the circle it should be extended(already implemented)
for(var i=0;i<connectors.length;i++){
var c=connectors[i];
var s=anchors[c.start];
var e=anchors[c.end];
ctx.beginPath();
ctx.moveTo(s.x,s.y);
ctx.lineTo(e.x,e.y);
ctx.stroke();
}
// draw circles
for(var i=0;i<anchors.length;i++){
ctx.beginPath();
ctx.arc(anchors[i].x,anchors[i].y,radius,0,Math.PI*2);
ctx.fill();
ctx.fillText(anchors[i].label,anchors[i].x-5,anchors[i].y-15);
}`
You got 2 important steps you have to tackle for this problem:
1 - Detect if the mouse is on a line when holding down LMB.
2 - Move all dots connected to the line in question when moving mouse.
Detect if a point is on a line
Theory: Mathematically you can detect if a point is on a (enclosed) line if the distance between said point to the 2 ends of the line is EQUAL to the distance between the 2 ends of the line.
More information: here
I wrote a little function to check this:
function mouseOnLine(mousePos) {
for (var i = 0 ; i < connectors.length; i++){
var pA = anchors[connectors[i].start];
var pB = anchors[connectors[i].end];
var first = distanceBetween(pA,mousePos) + distanceBetween(pB,mousePos);
var second = distanceBetween(pA,pB);
if (Math.abs(first - second) < 0.3) //Threshold of 0.3
return connectors[i];
}
return null;
}
Important to note: I don't check if it's equal to 0, but rather if the difference is smaller than 0.3, so the mouse doesn't have to be exactly on the line, as that would be quite hard to achieve.
Distance between is a simple pythagoras calculation:
var distanceBetween = function (point1, point2) {
var distX = Math.abs( point1.x - point2.x);
var distY = Math.abs(point1.y - point2.y);
return Math.sqrt((distX * distX) + (distY * distY));
}
Move all points connected to this one
Theory: As soon as we detected that the mousebutton is held down on top of a line, we have to find the first point of that form. We know that each polygon contains 4 points, so we can just loop over the next 4 points.
We can find the first point of the polygon (assuming they're always in order), with a little calculation:
var startPoints = Math.floor(fullDrag.start / 4) * 4;
//Example: We clicked on the line starting with point 3. this will return:
//Math.floor(3 / 4) * 4 ==> Math.floor(0.75) * 4 ==> 0 * 4 ==> 0
Now just loop and move it all:
var startPoints = Math.floor(fullDrag.start / 4) * 4;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
for (var i = 0; i < 4; i++) {
anchors[startPoints+i].x +=(mouseX-startX);
anchors[startPoints+i].y +=(mouseY-startY);
}
startX=mouseX;
startY=mouseY;
Other people reading this: The code shown above are only snippets from the entire solution. You can find a working fiddle right here
Related
I'm trying to draw a noisy line (using perlin noise) between two specific points.
for example A(100, 200) and B(400,600).
The line could be a points series.
Drawing random noisy line is so clear but I dont know how can I calculate distance specific points.
working of P5.js.
I don't have any code written yet to upload.
Please can anyone help me?
I tried to add sufficient comments that you would be able to learn how such a thing is done. There are a number of things that you should make yourself aware of if you aren't already, and it's hard to say which if these you're missing:
for loops
drawing lines using beginShape()/vertex()/endShape()
Trigonometry (in this case sin/cos/atan2) which make it possible to find angles and determine 2d offsets in X and Y components at a given angle
p5.Vector() and its dist() function.
// The level of detail in the line in number of pixels between each point.
const pixelsPerSegment = 10;
const noiseScale = 120;
const noiseFrequency = 0.01;
const noiseSpeed = 0.1;
let start;
let end;
function setup() {
createCanvas(400, 400);
noFill();
start = createVector(10, 10);
end = createVector(380, 380);
}
function draw() {
background(255);
let lineLength = start.dist(end);
// Determine the number of segments, and make sure there is at least one.
let segments = max(1, round(lineLength / pixelsPerSegment));
// Determine the number of points, which is the number of segments + 1
let points = 1 + segments;
// We need to know the angle of the line so that we can determine the x
// and y position for each point along the line, and when we offset based
// on noise we do so perpendicular to the line.
let angle = atan2(end.y - start.y, end.x - start.x);
let xInterval = pixelsPerSegment * cos(angle);
let yInterval = pixelsPerSegment * sin(angle);
beginShape();
// Always start with the start point
vertex(start.x, start.y);
// for each point that is neither the start nor end point
for (let i = 1; i < points - 1; i++) {
// determine the x and y positions along the straight line
let x = start.x + xInterval * i;
let y = start.y + yInterval * i;
// calculate the offset distance using noice
let offset =
// The bigger this number is the greater the range of offsets will be
noiseScale *
(noise(
// The bigger the value of noiseFrequency, the more erretically
// the offset will change from point to point.
i * pixelsPerSegment * noiseFrequency,
// The bigger the value of noiseSpeed, the more quickly the curve
// fluxuations will change over time.
(millis() / 1000) * noiseSpeed
) - 0.5);
// Translate offset into x and y components based on angle - 90°
// (or in this case, PI / 2 radians, which is equivalent)
let xOffset = offset * cos(angle - PI / 2);
let yOffset = offset * sin(angle - PI / 2);
vertex(x + xOffset, y + yOffset);
}
vertex(end.x, end.y);
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
This code makes jaggy lines, but they could be smoothed using curveVertex(). Also, making the line pass through the start and end points exactly is a little tricky because the very next point may be offset by a large amount. You could fix this by making noiseScale very depending on how far from an endpoint the current point is. This could be done by multiplying noiseScale by sin(i / points.length * PI) for example.
I'm currently working on a maze generating algorithm called recursive division. The algorithm is quite simple to understand: Step 1: if the height of your chamber is smaller than the width, divide your grid/chamber with a vertical line. If the height is greater than the width, then divide your chamber with a horizontal line. Step 2: Repeat step 1 with the sub-chambers that were created by the lines. You want to repeat these steps until you get a maze (until the width or height equals 1 unit).
The problem that I have with this algorithm is that JavaScript prints out a RangeError, meaning that I called the function that creates the maze too many times (I'm trying to implement this algorithm with a recursive function). Is there any way to avoid/prevent this from happening? Or am I missing something important in my code that makes the algorithm not work properly?
I have tried to implement a trampoline function, but since I'm a beginner I just don't understand it well enough to implement my self. I have also restarted my entire project ruffly 3 times with some hope that I will come up with a different approach to this problem, but I get the same error every time.
My code here:
//leftCord = the left most x coordinate of my chamber/grid, upCord = the upmost y coordinate of my
grid etc.
//(0, 0) IS POSITIONED IN THE LEFT TOP NODE OF MY GRID
function createMaze(leftCord, rightCord, upCord, downCord) {
var height = Math.abs(downCord - upCord);
var width = Math.abs(rightCord - leftCord);
if (height < 2 || width < 2) {
//The maze is completed!
return;
} else {
if (height < width) {
//cut the chamber/grid vertically
//Getting a random number that's EVEN and drawing the function x = 'random number' on the grid
var x = randomNum(leftCord / 2, rightCord / 2) * 2;
var lineX = [];
for (i = upCord; i < downCord; i++) {
lineX.push(grid[i][x]);
}
//Making a random door/passage and making sure it's ODD
var randomDoor = randomNum(0, lineX.length / 2) * 2 + 1;
lineX.splice(randomDoor, 1);
//Drawing the line
for (i = 0; i < lineX.length; i++) {
lineX[i].className = "wall";
}
//Making the same thing again, but with the left and right sub-chambers that were created by the line
createMaze(leftCord, x, upCord, downCord);
createMaze(x, rightCord, upCord, downCord);
} else {
//cut the chamber/grid horizontally
//Getting a random number that's EVEN and drawing the function y = 'random number' on the grid
var y = randomNum(0, downCord / 2) * 2;
var lineY = [];
for (i = leftCord; i < rightCord; i++) {
lineY.push(grid[y][i]);
}
//Making a random door/passage and making sure it's ODD
var randomDoor = randomNum(0, lineY.length / 2) * 2 + 1;
lineY.splice(randomDoor, 1);
//Drawing the line
for(i = 0; i < lineY.length; i++){
lineY[i].className = "wall";
}
//Making the same thing again, but with the upper and lower-chambers that were created by the line
createMaze(leftCord, rightCord, upCord, y);
createMaze(leftCord, rightCord, y, downCord);
}
}
}
This is happening because you never initialize i with var- it is sent into the global scope and is overwritten each function call.
I have a polar graph (see image) with 120 different points. I want to make it so if the user clicks or hovers on one of the points, the coordinate of that point is displayed. I have an array called pointCoordinates that stores each canvas coordinate of each points like this:
[[x1, y1], [x2, y2] ... [x120, y120]]
This is how I am capturing mouse coordinates (which I might later change to click):
document.onmousemove = function(e) {
var x = e.clientX;
var y = e.clientY;
}
I was originally planning to use a formula to check if the mouse is in a certain region (using the distance formula) or simplifying it all into a circle. Either way, this will require me to have 120 different if statements to check for this. I feel like this is inefficient and probably slow. Are there other methods for doing this?
Edit:
To provide more information, these points will NOT be draggable. I am planning to display something like a tooltip near the point that was clicked where the polar coordinates of the point will be shown.
Edit 2:
After using the code posted below and drawing a rectangle in the "clickable" spot on the map, I get this image. I do not want the click detection to be perfect, but this is pretty far off after pi/3. Any ideas how to fix this? I used this code to generate the black spots:
for(var x = 0; x < WIDTH*2/3; x++){
for(var y = 0; y < HEIGHT; y++){
var mp = realToPolar(x, y);//converts canvas x and y into polar
if(checkRadialDistance(mp[0], mp[1])){ //returns true if in bounds
ctx.fillRect(x, y, 1, 1);
}
}
}
Playing around with the constants still generates the same pattern, just of different thicknesses. checkRadialDistance is just the renamed checkr function that inside calls checkrt.
JSBIN Keep in mind, width of screen has to be greater than height for this to work properly.
The image generated by mt-rt. I later made a minor edit, so that whole circle is covered when theta = 0.
EDIT: My (accepted) answer was bad. This corrects it:
This assumes r to be 1 to 5. Convert mouse cartesian mx,my to polar mr,mt. First check if mr is close to 1 of the 5 radii. Function checkr does that. If it is close, then check if mt is close to 1 of the 24 thetas. Function checkt does that. A complication is that the atan2 function is not continuous at pi radians which is where points are at, so make the discontinuity at -pi/24 radians where there are no points.
A "close" value is pi/24 since the arc distance between two adjacent points at r=1 will be pi/12.
var del = 1*Math.PI/24*.7; // for example
function xy2rt(xy) { // to polar cordinates
var rt = [];
rt.push(Math.sqrt(xy[0]*xy[0]+xy[1]*xy[1])); // r
var zatan = Math.atan2(xy[1], xy[0]);
// make the discontinuity at -pi/24
if (zatan < -Math.PI/24) zatan += 2*Math.PI;
rt.push(zatan); // theta
return rt;
}
function checkr() { // check radial distance
for (var pr=1; pr<=5; pr+=1) { // 5 radii
if (Math.abs(mr-pr) < del) { checkt(pr); break; }
}
}
function checkt(pr) { // check theta
var pt;
for (var ipt=0; ipt<24; ipt+=1) { // 24 thetas
pt = ipt / 24 * 2 * Math.PI;
if (Math.abs(mt-pt) < del/pr) {
// is close -- do whatever
break;
}
}
}
My problem was when checking the arc distance, I was using mr and pr whereas only pr should be used. The OP found my error by processing every pixel on the canvas and found there was a problem. I also processed every pixel and this image shows the routines to be correct now. The black is where the routines determine that the pixel is close to one of the 120 points.
EDIT: Faster processing
There are a lot of Math.* functions being executed. Although I haven't timed anything, I think this has to be much faster.
1) The x,y coordintates of the 120 points are stored in arrays.
2) Instead of getting polar mr, mt, pr, and pt, use vector processing.
Here is the derivation of arcd, the arc distance using vectors.
sint = sin(theta) = (M cross P)/mr/pr (cross product Mouse X Point)
cost = cos(theta) = (M dot P)/mr/pr (dot product Mouse . Point)
sint will be used to get arc distance, but sint goes to zero at theta=+-pi as well as theta=0, so:
mdotp will be used to determine if theta is near zero and not +-pi
arcd = pr*theta
arcd = pr*sin(theta) (good approximation for small theta)
arcd = pr*abs(M cross P)/mr/mp (from above)
if ardd < del, check if mdotp > 0.
Here are the load-xy-arrays and the new checkr and checkt routines.
apx=[], apy=[]; // the saved x,y of the 120 points
function loadapxapy() { // load arrays of px, py
var itheta, theta
for (var pr=1; pr<=5; pr+=1) { // 2-dimension arrays
apx[pr] = []; apy[pr] = []; // 5 arrays, 1 for each pr
for (itheta=0; itheta<24; itheta+=1) { // 24 x's and y's
theta = Math.PI*itheta/12;
apx[pr][itheta] = pr*Math.cos(theta);
apy[pr][itheta] = pr*Math.sin(theta);
}
}
}
function checkr() { // check radial distance
var mr = Math.sqrt(mx*mx+my*my); // mouse r
for (var pr=1; pr<=5; pr+=1) { // check 1 to 5
if (Math.abs(mr-pr) < del) { // mouser - pointr
checkt(mr, pr); // if close, check thetas
}
}
}
function checkt(mr, pr) { // check thetas
var px, py, sint, mdotp, arcd;
for (var itheta=0; itheta<24; itheta+=1) { // check 24
px = apx[pr][itheta]; // get saved x
py = apy[pr][itheta]; // and y
// This arcd is derived from vector processing
// At least this doesn't use the accursed "atan"!
sint = Math.abs(mx*py-my*px)/mr/pr; // sine
arcd = pr*sint; // arc distance
if (arcd<del) { // arc distance check
mdotp = (mx*px+my*py); // final check
if (mdotp > 0) { // to see if theta is near zero and not +-pi
setpixelxy([mx, my]); // or whatever..
}
}
}
}
I have made a board with 156X64 divs 3 pixel each with border radius, so it looks like a board out of LED. I have string representing 0 or 1 of each 7X5 matrix of letters.
var lgeoa="00100001000001000001100011000101110";//7X5 matrix letter A
var lgeob="10000111000010001010100011000101110";//7X5 matrix letter B
and so on...
Drawing letter means change corresponding div background color. It is working fine, but after that I wanted to animate them the problem started. I clear line and draw in every 10 milliseconds, but its very very laggy. So please how can this code be optimized to work without lags?
P.S. Surprisingly it's working better in IE11 rather than in chrome.
Here is a fiddle
There's a lot of optimization that can be done here. I'll point out a couple.
Starting with the animate function, the first thing I notice is that you're running a bit of code every 10ms. Why don't we check out what's being run?
function animate() {
var string = "აბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰ ტესტ ტესტ აი ემ ე თეიბლ ტექსტი იწერება აქ"; //string to animate
position = 150; //initial position of string
window.setInterval(function () {
clearLine(0);
drawOnBoard(string, position, 0);
position = position - 1;
}, 10);
}
Clearline is the first function.
function clearLine(n){
for(var i=n*symbolHeight*lineWidth+n*lineWidth;i<(n+1)*symbolHeight*lineWidth+n*lineWidth;i++)
leds[i].style.backgroundColor="black";
}
That's a bit of a mess in the for loop. My understanding is that non-compiled code will run all of that math for every single iteration. So let's move it out of the for loop.
function clearLine(n) {
var initial = n * symbolHeight * lineWidth + n * lineWidth;
var length = (n + 1) * symbolHeight * lineWidth + n * lineWidth;
for (var i = initial; i < length; i++)
leds[i].style.backgroundColor = "black";
}
Ah but there's still more to be done. I see that both equations have a lot of shared math.
function clearLine(n) {
var whateverThisIs = symbolHeight * lineWidth + n * lineWidth;
var initial = n * whateverThisIs;
var length = (n + 1) * whateverThisIs;
for (var i = initial; i < length; i++)
leds[i].style.backgroundColor = "black";
}
I saw that you're moving on so I'll stop working on this for now. There's still plenty more to optimize.
Here's a fiddle of the updated version.
I'm building a turn based HTML game based on a 2D square grid. Each grid square could take a variable number of movement points to cross (IE: 1 MP for roads, 1.5 MP for grasslands, 2 MP for forests, etc). When the user clicks on a unit I want to determine all possible movable spaces with said unit's allotted movement points so that I can highlight them and make them clickable.
Is there a free library available to do this? I've seen a few pathing algorithms but nothing about determining movable area. How do other game developers handle this problem? I'm open to both vanilla JS and JQuery solutions.
Well, I decided to try and attack this myself. I've never been great at these sorts of algorithms so I'm sure there's a more efficient way to handle it than what I've done. However, for my purposes it runs quickly enough and is very simple and easy to understand.
In case it's helpful to anyone else looking to do the same, I've included the code below. This is an updated version of my original answer, which I modified to also store the path taken so that you can show the units moving through the correct spaces. This answer uses JQuery in the lower examples, but only in a few places; you can easily enough replace them with vanilla JS. And the first block of code, containing the actual path/area finding functionality, is pure JS.
<script>
var possibleMovementAreaArray = new Array(); // This array will hold our allowable movement tiles. Your other functions can access this after running possibleMovementArea().
function possibleMovementArea(unitIndex) {
// I'm storing each unit in my game in an array. So I pass in the index of the unit I want to determine the movement area for.
var x = unitList[unitIndex][10]; // x coordinate on the playgrid
var y = unitList[unitIndex][11]; // y coordinate on the playgrid
var mp = unitList[unitIndex][15]; // number of movement points
possibleMovementAreaArray.length = 0; // Clear our array so previous runs don't interfere.
findPossibleMovement(x, y, mp);
}
function findPossibleMovement(x, y, mp, prevStepX, prevStepY) {
// This is a recursive function; something I'm not normally too good at.
for (var d=1; d<=4; d++) {
// We run through each of the four cardinal directions. Bump this to 8 and add 4 more cases to include corners.
if (d == 1) {
// Check Up
var newX = x;
var newY = y - 1;
} else if (d == 2) {
// Check Down
var newX = x;
var newY = y + 1;
} else if (d == 3) {
// Check Left
var newX = x - 1;
var newY = y;
} else if (d == 4) {
// Check Right
var newX = x + 1;
var newY = y;
}
// Check to see if this square is occupied by another unit. Two units cannot occupy the same space.
spaceOccupied = false;
for (var j=1; j<=numUnits; j++) {
if (unitList[j][10] == newX && unitList[j][11] == newY)
spaceOccupied = true;
}
if (!spaceOccupied) {
// Modify this for loop as needed for your usage. I have a 2D array called mainMap that holds the ID of a type of terrain for each tile.
// I then have an array called terList that holds all the details for each type of terrain, such as movement points needed to get past.
// This for loop is just looking up the ID of the terrain for use later. Sort of like a "SELECT * FROM terrainInfo WHERE ID=terrainOfCurrentTile".
for (var j=1; j<=numTerrains; j++) {
if (newX > 0 && newX <= mapWidth && newY > 0 && newY <= mapHeight && terList[j][1] == mainMap[newX][newY])
break; // After finding the index of terList break out of the loop so j represents the correct index.
}
if (j <= numTerrains) { // Run if an actual terrain is found. No terrain is found if the search runs off the sides of the map.
var newMp = mp - terList[j][7]; // Decrement the movement points for this particular path.
if (newMp >= 0) { // Only continue if there were enough movement points to move to this square.
// Check to see if this square is already logged. For both efficiency and simplicity we only want each square logged once.
var newIndex = possibleMovementAreaArray.length
var alreadyLogged = false
if (possibleMovementAreaArray.length > 0) {
for (var j=0; j<possibleMovementAreaArray.length; j++) {
if (possibleMovementAreaArray[j][1] == newX && possibleMovementAreaArray[j][2] == newY) {
alreadyLogged = true;
var alreadyLoggedIndex = j;
}
}
}
if (!alreadyLogged) {
// This adds a row to the array and records the x and y coordinates of this tile as movable
possibleMovementAreaArray[newIndex] = new Array(6);
possibleMovementAreaArray[newIndex][1] = newX;
possibleMovementAreaArray[newIndex][2] = newY;
possibleMovementAreaArray[newIndex][3] = prevStepX; // This tracks the x coords of the steps taken so far to get here.
possibleMovementAreaArray[newIndex][4] = prevStepY; // This tracks the y coords of the steps taken so far to get here.
possibleMovementAreaArray[newIndex][5] = newMp; // Records remaining MP after the previous steps have been taken.
}
if (alreadyLogged && newMp > possibleMovementAreaArray[alreadyLoggedIndex][5]) {
// If this tile was already logged, but there was less MP remaining on that attempt, then this one is more efficient. Update the old path with this one.
possibleMovementAreaArray[alreadyLoggedIndex][3] = prevStepX;
possibleMovementAreaArray[alreadyLoggedIndex][4] = prevStepY;
possibleMovementAreaArray[alreadyLoggedIndex][5] = newMp;
}
if (newMp > 0) {
// Now update the list of previous steps to include this tile. This list will be passed along to the next call of this function, thus building a path.
if (prevStepX == '') {
var newPrevStepX = [newX];
var newPrevStepY = [newY];
} else {
// This code is required to make a full copy of the array holding the existing list of steps. If you use a simple equals then you just create a reference and
// subsequent calls are all updating the same array which creates a chaotic mess. This way we store a separate array for each possible path.
var newPrevStepX = prevStepX.slice();
newPrevStepX.push(newX);
var newPrevStepY = prevStepY.slice();
newPrevStepY.push(newY);
}
// If there are still movement points remaining, check and see where we could move next.
findPossibleMovement(newX, newY, newMp, newPrevStepX, newPrevStepY);
}
}
}
}
}
}
</script>
After running the above, you can then loop through the array to find all usable tiles. Here is how I did it:
<script>
// Shows the movement area based on the currently selected unit.
function showMovement() {
var newHTML = "";
curAction = "move";
possibleMovementArea(curUnit); // See above code
for (x=0; x<possibleMovementAreaArray.length; x++) {
// Loop over the array and do something with each tile. In this case I'm creating an overlay that I'll fade in and out.
var tileLeft = (possibleMovementAreaArray[x][1] - 1) * mapTileSize; // Figure out where to absolutely position this tile.
var tileTop = (possibleMovementAreaArray[x][2] - 1) * mapTileSize; // Figure out where to absolutely position this tile.
newHTML = newHTML + "<img id='path_" + possibleMovementAreaArray[x][1] + "_" + possibleMovementAreaArray[x][2] + "' onClick='mapClk(" + possibleMovementAreaArray[x][1] + ", " + possibleMovementAreaArray[x][2] + ", 0);' src='imgs/path.png' class='mapTile' style='left:" + tileLeft + "px; top:" + tileTop + "px;'>";
}
$("#movementDiv").html(newHTML); // Add all those images into a preexisting div.
$("#movementDiv").css("opacity", "0.5"); // Fade the div to 50%
$("#movementDiv").show(); // Make the div visible.
startFading(); // Run a routine to fade the div in and out.
}
</script>
Since we determined the path, we can easily show movement as well by looping through the stored information:
<script>
for (j=0; j<possibleMovementAreaArray[areaIndex][3].length; j++) {
// This loop moves the unit img to each tile on its way to its destination. The final destination tile is not included.
var animSpeed = 150; // Time in ms that it takes to move each square.
var animEase = "linear"; // We want movement to remain a constant speed through each square in this case.
var targetLeft = (possibleMovementAreaArray[areaIndex][3][j]-1) * mapTileSize; // This looks at each step in the path array and multiplies it by tile size to determine the new horizonal position.
var targetTop = (possibleMovementAreaArray[areaIndex][4][j]-1) * mapTileSize; // This looks at each step in the path array and multiplies it by tile size to determine the new vertical position.
$("#char_"+curUnit).animate({"left":targetLeft, "top":targetTop}, animSpeed, animEase); // Do the animation. Subsequent animations get queued.
}
// Now we need to move to that last tile.
newLeft = (x-1) * mapTileSize;
newTop = (y-1) * mapTileSize;
$("#char_"+curUnit).animate({"left":newLeft, "top":newTop}, 400, "easeOutCubic"); // Slow unit at the end of journey for aesthetic purposes.
$("#char_"+curUnit).addClass("unitMoved", 250); // Turns the image grayscale so it can easily be seen that it has already moved.
</script>
Hopefully this is helpful to others.