xxxxxxxxxx
183
/*
This sketch has some slight tweaks to tsfadali's "Projection definition":
https://editor.p5js.org/tsfadali/sketches/NQNZFYaQo
Changes:
It's possible I didn't record all my changes below, since I wasn't super
careful about that. But I think it's all here.
* New color defined (myDarkGray): lines 32, 41
* Changed axis color: line 61
(myDarkGray is now used throughout, not black)
* Changed color of points: line 67
* Added a border to the caption box: lines 128-129
* Updated text color and stroke weight: lines 133-134
* Fixed 'grabbing' cursor: see line 67, and take 'grabbing' out of
mouseDragged(). See "Notes" below for an explanation.
* changed label styling: see lines 107-113
Notes:
The 'grabbing' cursor wasn't working before because it's
only called once when the mouse moves and the cursor is pressed. The
cursor should change to 'grabbing' whenever it's positioned over one of
the points and the mouse is pressed (it should appear
whether or not the mouse is being moved). So, my solution uses
mouseIsPressed, which is a Boolean that's true as long as the mouse is
pressed (not only when it's first pressed).
*/
let xOrigin;
let yOrigin;
let xScale; //px per unit
let yScale; //px per unit
let graphWindow;
//vectors (p5.Vector objects)
let v, w, z, P_vw, vPerp, wPerp, vOffset, wOffset;
let labelOffset;
let t = -0.4; // time variable for animation
const STEP = 0.02
let isAnimating = true
//colors (putting these here for convenience)
let myMagenta, myGreen, myOrange, myDarkGray;
function setup() {
createCanvas(400, 400);
//colors
myMagenta = color(255, 93, 115);
myGreen = color(22, 219, 147);
myOrange = color(252, 152, 0);
myDarkGray = color(73, 73, 73);
//Create graph window
xOrigin = width / 2;
yOrigin = height / 2;
xScale = 10; //px per unit
yScale = 10; //px per unit
graphWindow = createGraphWindow(xOrigin, yOrigin, xScale, yScale);
//vectors
v = createVector(5, 12);
w = createVector(18, 4)
z = createVector(0, 0)
}
function draw() {
background(245);
//Axes
strokeWeight(2);
stroke(myDarkGray);
graphWindow.axis('horizontal');
graphWindow.axis('vertical');
//Points
strokeWeight(12);
stroke(myDarkGray);
graphWindow.point(v.x, v.y);
graphWindow.point(w.x, w.y);
if (isClose(w, mouseX, mouseY) || isClose(v, mouseX, mouseY)) {
if (mouseIsPressed) {
cursor('grabbing')
}
else{
cursor('grab')
}
} else {
cursor(ARROW)
}
//Labels
strokeWeight(1);
stroke(myMagenta);
fill(myMagenta);
text('v', graphWindow.X(v.x), graphWindow.Y(v.y) - 10)
stroke(myGreen);
fill(myGreen);
text('w', graphWindow.X(w.x), graphWindow.Y(w.y) - 10)
//Arrows
strokeWeight(3);
stroke(myGreen)
graphWindow.arrow(w)
stroke(myMagenta);
graphWindow.arrow(v);
P_vw = p5.Vector.mult(w, v.dot(w)/w.dot(w))
let dropped = p5.Vector.lerp(v, P_vw, t)
dropped.sub(v)
strokeWeight(1)
if (t >= 0)
graphWindow.arrow(dropped, v, 0, 0)
if (t < 1) {
if (isAnimating)
t = min(t + STEP, 1)
} else {
// do right angle indicator
let diff = p5.Vector.sub(v, P_vw)
if (diff.mag() >= 1) {
diff.normalize()
let v_op = p5.Vector.mult(P_vw, -1)
v_op.normalize()
graphWindow.arrow(v_op, p5.Vector.add(P_vw, diff), 0, 0)
graphWindow.arrow(diff, p5.Vector.add(P_vw, v_op), 0, 0)
}
strokeWeight(3)
if (P_vw.mag() > 0.5) {
graphWindow.arrow(P_vw)
} else {
graphWindow.arrow(z, P_vw, 0, 0)
}
strokeWeight(1)
t = 1
isAnimating = false
}
//Caption
strokeWeight(2);
stroke(myDarkGray);
fill(255)
rect(10, 350, 320, 40)
strokeWeight(1);
fill(myDarkGray);
textSize(18)
text('Drag the points to update the vectors', 20, 375)
}
function mouseReleased() {
isAnimating = true
}
function mouseDragged() {
t = -0.4
if (isClose(v, mouseX, mouseY)) {
v.x = graphWindow.x(mouseX)
v.y = graphWindow.y(mouseY)
}
else if (isClose(w, mouseX, mouseY)) {
w.x = graphWindow.x(mouseX)
w.y = graphWindow.y(mouseY)
}
}
function isClose(v, x, y, epsilon) {
if (!epsilon)
epsilon = 10
let vX = graphWindow.X(v.x)
let vY = graphWindow.Y(v.y)
return dist(vX, vY, x, y) < epsilon
}