Drag the end points of the arrow. The sliders adjust the arrow parameters.
xxxxxxxxxx
/**
* Author: Oliver Steele <https://code.osteele.com>
* Source: https://www.openprocessing.org/sketch/1045212
*
* Draw an arrow between two points.
* Developed for use in https://www.openprocessing.org/sketch/1045156
*
* Also see Trimmed Arrow https://www.openprocessing.org/sketch/1045123
*/
// arrow parameters
let start, end
let lineWidth = 5
let arrowWidth = 15
let arrowLength = 10
let isDashed = true
function setup() {
createCanvas(windowWidth, windowHeight / 2)
controls()
noLoop()
start = createVector(width / 2, 100)
end = createVector(width / 2 + 100, 250)
}
function draw() {
background(100)
translate(0, 0)
// draw the endpoints
noFill()
stroke('lightgreen')
circle(start.x, start.y, 16)
stroke('pink')
circle(end.x, end.y, 16)
// draw the arrow
let dash = isDashed ? [7, 3] : null
noStroke()
fill(200)
arrow(start.x, start.y, end.x, end.y, {arrowLength, arrowWidth, lineWidth, dash})
}
function mouseDragged() {
// if the click is on the canvas, move the closest endpoint
if (mouseY < height) {
let m = createVector(mouseX, mouseY)
if (start.dist(m) < end.dist(m)) {
start = m
} else {
end = m
}
}
// This handles redrawing when the sliders change too
redraw()
}
function arrow(x0, y0, x1, y1, options) {
let defaultOptions = {arrowLength: 10, arrowWidth: 5, lineWidth: 5}
let {arrowLength, arrowWidth, lineWidth, dash} = {defaultOptions, options || {}}
let ll = dist(x0, y0, x1, y1) // line length
let al = min(arrowLength, ll)
let sl = ll - al // stem length
let hw = lineWidth / 2 // line half width
push()
translate(x0, y0)
rotate(atan2(y1 - y0, x1 - x0));
if (dash) {
let [pag, gap] = Array.isArray(dash) ? dash : [dash, dash];
let dl = pag + gap
while (dl < sl) {
rect(0, -hw, pag, 2 * hw)
translate(dl, 0)
ll -= dl
sl -= dl
}
}
let pts = [
[0, hw],
[sl, hw],
[sl, hw + arrowWidth / 2],
[ll, 0],
]
beginShape()
pts.forEach(([x, y]) => vertex(x, y))
pts.reverse().forEach(([x, y]) => vertex(x, -y))
endShape()
pop()
}
function controls() {
const sliderValueHandler = fn => ({ target }) => fn(Number(target.value))
let y = height + 20
createDiv("Line Width").position(10, y)
createSlider(1, y, lineWidth)
.position(100, height + 20)
.style("width", "250px")
.mouseMoved(sliderValueHandler(value => lineWidth = value))
y += 30
createDiv("Arrow Width").position(10, y)
createSlider(1, 20, arrowWidth)
.position(100, y)
.style("width", "250px")
.mouseMoved(sliderValueHandler(value => arrowWidth = value))
y += 30
createDiv("Arrow Length").position(10, y)
createSlider(1, 30, arrowLength)
.position(100, y)
.style("width", "250px")
.mouseMoved(sliderValueHandler(value => arrowLength = value))
y += 30
let dashCheckBox = createCheckbox("Dash", isDashed)
.position(10, y)
.changed(() => { isDashed = dashCheckBox.checked(); redraw() })
}