Created
March 14, 2022 03:23
-
-
Save zuramai/ca79b6e5177ab365f66810b81af6f152 to your computer and use it in GitHub Desktop.
Unit Circle Canvas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UnitCircle { | |
constructor(canvas) { | |
this.canvas = canvas | |
this.ctx = this.canvas.getContext('2d') | |
this.circleSize = this.canvas.width * 2/5 | |
this.position = [0.23, -0.5] // equivalent to [x, y] | |
this.mousePosition = [0, 0] | |
this.isMouseDown = false | |
this.halfWidth = this.canvas.width/2 | |
this.halfHeight = this.canvas.height/2 | |
this.angle = this.getAngle(this.position) | |
this.cursorStatus = "default" | |
this.cursorRadius = 10 | |
this.cursorPoint = [] | |
this.init() | |
} | |
init() { | |
this.computeCursorPoint() | |
this.updatePosition() | |
this.draw() | |
this.canvas.addEventListener('mousemove', this.mouseEvent.bind(this)) | |
this.canvas.addEventListener('mousedown', this.mouseEvent.bind(this)) | |
this.canvas.addEventListener('mouseup', this.mouseEvent.bind(this)) | |
} | |
draw() { | |
// Clear the canvas | |
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) | |
this.drawCircle() | |
this.drawLines() | |
this.drawTriangles() | |
this.drawCursor() | |
this.drawText() | |
} | |
drawText() { | |
let fontSize = 12 | |
// Draw X Y position indicator | |
this.ctx.fillStyle = "white" | |
this.ctx.strokeStyle = "black" | |
this.ctx.lineWidth = 1 | |
this.ctx.textAlign = "center" | |
this.ctx.font = `${fontSize}px Arial` | |
this.ctx.fillText(`X = ${Math.round(this.position[0] *100)/100}`, | |
this.cursorPoint[0] + (this.halfWidth - this.cursorPoint[0]) / 2, | |
this.halfHeight-fontSize) | |
this.ctx.strokeText(`Y = ${Math.round(this.position[1] *100)/100}`, | |
this.cursorPoint[0] + fontSize, | |
this.halfHeight + (this.cursorPoint[1] - this.halfHeight) / 2) | |
this.ctx.fillText(`Y = ${Math.round(this.position[1] *100)/100}`, | |
this.cursorPoint[0] + fontSize, | |
this.halfHeight + (this.cursorPoint[1] - this.halfHeight) / 2) | |
} | |
drawCircle() { | |
let center = [this.canvas.width/2, this.canvas.height/2] | |
this.ctx.lineWidth = 2 | |
this.ctx.strokeStyle = "white" | |
this.ctx.beginPath() | |
this.ctx.arc(center[0], center[1], this.circleSize, 0, Math.PI*2) | |
this.ctx.stroke() | |
this.ctx.closePath() | |
this.ctx.beginPath() | |
this.ctx.strokeStyle = "rgba(120,120,120,.5)" | |
this.ctx.moveTo(center[0] - this.circleSize, center[1]) | |
this.ctx.lineTo(center[0] + this.circleSize, center[1]) | |
this.ctx.moveTo(center[0], center[1] - this.circleSize) | |
this.ctx.lineTo(center[0], center[1] + this.circleSize) | |
this.ctx.stroke() | |
this.ctx.closePath() | |
} | |
drawLines() { | |
this.ctx.beginPath() | |
this.ctx.lineWidth = 2 | |
this.ctx.strokeStyle = "white" | |
// Horizontal Line | |
this.ctx.moveTo(this.halfWidth, this.halfHeight) | |
this.ctx.lineTo(this.cursorPoint[0], this.halfHeight) | |
// Vertical Line | |
this.ctx.moveTo(this.cursorPoint[0], this.halfHeight) | |
this.ctx.lineTo(this.cursorPoint[0], this.cursorPoint[1]) | |
this.ctx.stroke() | |
this.ctx.closePath() | |
} | |
drawTriangles() { | |
let triangleSize = 7 | |
let absoluteOne = (n) => n < 0 ? -1 : 1 | |
let horizontalVerticalCorner = this.cursorPoint[0] + triangleSize * -absoluteOne(this.position[0]) | |
let verticalHorizontalCorner = this.cursorPoint[1] + triangleSize * -absoluteOne(this.position[1]) | |
this.ctx.fillStyle = "white" | |
this.ctx.beginPath() | |
this.ctx.moveTo(horizontalVerticalCorner, this.halfHeight - triangleSize) // top corner | |
this.ctx.lineTo(this.cursorPoint[0], this.halfHeight) // center corner | |
this.ctx.lineTo(horizontalVerticalCorner, this.halfHeight + triangleSize) // bottom corner | |
this.ctx.lineTo(horizontalVerticalCorner, this.halfHeight - triangleSize) // top corner | |
this.ctx.moveTo(this.cursorPoint[0] - triangleSize, verticalHorizontalCorner) // left corner | |
this.ctx.lineTo(this.cursorPoint[0], this.cursorPoint[1]) // center corner | |
this.ctx.lineTo(this.cursorPoint[0] + triangleSize, verticalHorizontalCorner) // bottom corner | |
this.ctx.lineTo(this.cursorPoint[0] - triangleSize, verticalHorizontalCorner) // right corner | |
this.ctx.fill() | |
this.ctx.closePath() | |
} | |
drawCursor() { | |
this.computeCursorPoint() | |
this.ctx.lineWidth = 2 | |
this.ctx.beginPath() | |
this.ctx.fillStyle = "rgba(77, 119, 255,.5)" | |
this.ctx.strokeStyle = "white" | |
this.ctx.arc(this.cursorPoint[0], this.cursorPoint[1], this.cursorRadius, 0, Math.PI*2) | |
this.ctx.fill() | |
this.ctx.stroke() | |
this.ctx.closePath() | |
} | |
computeCursorPoint() { | |
this.cursorPoint = [ | |
this.circleSize * Math.cos(this.angle) + this.halfWidth, | |
this.circleSize * Math.sin(this.angle) + this.halfHeight | |
] | |
} | |
getAngle(position) { | |
let dx = position[0] - this.halfWidth; | |
let dy = position[1] - this.halfHeight; | |
let rad = Math.atan2(dy, dx); | |
return rad | |
} | |
isMouseOnCursor() { | |
this.computeCursorPoint() | |
let dx = Math.abs(this.mousePosition[0] - this.cursorPoint[0]) | |
let dy = Math.abs(this.mousePosition[1] - this.cursorPoint[1]) | |
return dx * dx + dy * dy < this.cursorRadius * this.cursorRadius | |
} | |
mouseEvent(e) { | |
// Map mouse events function | |
let typeFunc = { | |
"mousemove": this.moveCircle.bind(this), | |
"mousedown": this.activateCircle.bind(this), | |
"mouseup": this.releaseCircle.bind(this) | |
} | |
// Save the mouse location | |
let rect = this.canvas.getBoundingClientRect() | |
this.mousePosition = [e.clientX - rect.x, e.clientY - rect.y] | |
// Execute the function | |
typeFunc[e.type](e) | |
this.draw() | |
} | |
updatePosition() { | |
this.angle = this.getAngle(this.mousePosition) | |
this.computeCursorPoint() | |
console.log(this.cursorPoint) | |
let positionX = (this.cursorPoint[0] - this.halfWidth) / this.circleSize * 1 | |
let positionY = (this.cursorPoint[1] - this.halfHeight) / this.circleSize * 1 | |
this.position = [ | |
positionX > 1 || positionX < -1 ? Math.round(position[0]) : positionX, | |
positionY > 1 || positionY < -1 ? Math.round(position[1]) : positionY | |
] | |
} | |
moveCircle() { | |
if(!this.isMouseDown) return | |
if(!this.isMouseOnCursor() && this.cursorStatus !== "holding") return | |
this.canvas.style.cursor = "pointer" | |
this.updatePosition() | |
} | |
activateCircle() { | |
this.isMouseDown = true | |
if(this.isMouseOnCursor()) this.cursorStatus = "holding" | |
} | |
releaseCircle() { | |
this.isMouseDown = false | |
this.cursorStatus = "default" | |
this.canvas.style.cursor = "default" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment