Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add free-drawing page #7266

Merged
merged 19 commits into from
Jan 9, 2025
Merged
Prev Previous commit
Next Next commit
Add canvas coordinates tooltip (#7270)
* Add canvas coordinates tooltip

* Don't recalculate tooltip size on every mouse move
  • Loading branch information
dem4ron authored Jan 9, 2025
commit 77be0e842806ee000f014b598b6186dde3d3fad3
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react'
import { Exercise } from '../Exercise'
import { rToA } from './utils'
import { aToR, rToA } from './utils'
import * as Shapes from './shapes'
import type { ExecutionContext } from '@/interpreter/executor'

Expand Down Expand Up @@ -69,6 +68,7 @@ export default class DrawExercise extends Exercise {

Object.assign(this.view.style, {
display: 'none',
position: 'relative',
})

const grid = document.createElement('div')
Expand All @@ -77,7 +77,66 @@ export default class DrawExercise extends Exercise {

this.canvas = document.createElement('div')
this.canvas.classList.add('canvas')
this.canvas.style.position = 'relative'
this.view.appendChild(this.canvas)

this.tooltip = document.createElement('div')
this.tooltip.classList.add('tooltip')
Object.assign(this.tooltip.style, {
whiteSpace: 'nowrap',
position: 'absolute',
background: '#333',
color: '#fff',
padding: '4px',
borderRadius: '4px',
fontSize: '12px',
pointerEvents: 'none',
display: 'none',
})
this.view.appendChild(this.tooltip)

this.canvas.addEventListener('mousemove', this.showTooltip.bind(this))
this.canvas.addEventListener('mouseleave', this.hideTooltip.bind(this))
}

showTooltip(event: MouseEvent) {
const rect = this.canvas.getBoundingClientRect()
const canvasWidth = rect.width
const canvasHeight = rect.height

const absX = event.clientX - rect.left
const absY = event.clientY - rect.top

const relX = Math.round(aToR(absX, canvasWidth))
const relY = Math.round(aToR(absY, canvasHeight))

let tooltipX = absX + 10
let tooltipY = absY + 10

// providing these as constant values saves us from recalculating them every time
// update these values if the tooltip style changes
// measure max tooltip width/height with the fn below
// console.log(this.tooltip.getBoundingClientRect().width, this.tooltip.getBoundingClientRect().height)
const maxTooltipWidth = 75
const maxTooltipHeight = 32
// handle tooltip overflow-x
if (tooltipX + maxTooltipWidth + 5 > canvasWidth) {
tooltipX = absX - maxTooltipWidth - 10
}

// handle tooltip overflow-y
if (tooltipY + maxTooltipHeight + 5 > canvasHeight) {
tooltipY = absY - maxTooltipHeight - 10
}

this.tooltip.textContent = `X: ${relX}, Y: ${relY}`
this.tooltip.style.left = `${tooltipX}px`
this.tooltip.style.top = `${tooltipY}px`
this.tooltip.style.display = 'block'
}

hideTooltip() {
this.tooltip.style.display = 'none'
}

public getState() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,120 +2,17 @@
* Relative constant number the absolute number maps to
*/
export const RELATIVE_SIZE = 100

/**
*
* Convert relative x or y value to absolute value
*/
export function rToA(n: number) {
return (n / RELATIVE_SIZE) * 100
}

/**
*
* Convert absolute x or y value to absolute value
*/
export function aToR(n: number) {
console.group('HERE')
//return Math.round(n / (CANVAS_SIZE / RELATIVE_SIZE));
}
/**
*
*/
export function relativeToAbsolute(x: number, y: number) {
return { x: rToA(x), y: rToA(y) }
}
/**
*
*/
export function absoluteToRelative(x: number, y: number) {
return { x: aToR(x), y: aToR(y) }
}

// export function showMouseCoord(p: p5) {
// const mouseX = p.mouseX;
// const mouseY = p.mouseY;

// let textX = mouseX + 10;
// let textY = mouseY + 10;

// const textWidth = p.textWidth(`(${mouseX}, ${mouseY})`);
// const textHeight = 16;

// // in case of overflow
// if (textX + textWidth > p.width) {
// textX = mouseX - textWidth - 10;
// }

// if (textY + textHeight > p.height) {
// textY = mouseY - textHeight - 10;
// }

// if (textX < 0) {
// textX = 10;
// }

// if (textY < 0) {
// textY = 10;
// }

// const { x, y } = absoluteToRelative(mouseX, mouseY);
// p.text(`(${x}, ${y})`, textX, textY);

// p.stroke(0, 0, 0, 50);
// // xline
// p.line(mouseX, 0, mouseX, p.height);
// // yline
// p.line(0, mouseY, p.width, mouseY);
// }

// export function isMouseOverTheCanvas(p: p5) {
// return p.mouseX >= 0 && p.mouseX <= p.width && p.mouseY >= 0 && p.mouseY <= p.height;
// }

/**
* Converts the code string to a array of dictionary of function names and their arguments
*/
function parseCode(code: string): Array<{ [key: string]: number[] }> {
const result: Array<{ [key: string]: number[] }> = []

const lines = code.trim().split('\n')

const regex = /(\w+)\(([\d\s,]+)\)/

for (const line of lines) {
const match = line.match(regex)
if (match) {
const functionName = match[1]
const args = match[2].split(',').map((arg) => parseFloat(arg.trim()))
const obj: { [key: string]: number[] } = {}
obj[functionName] = args
result.push(obj)
}
}

return result
}

/**
* Calls p5 function with arguments
*/
// export function drawThings(code: string, p: p5) {
// const parsedCode = parseCode(code);
// parsedCode.forEach((line) => {
// const functionName = Object.keys(line)[0];
// const args = line[functionName];
// const digestedArgs = mapRelativeArgsToAbsoluteArgs(functionName, args);
// // @ts-ignore
// p[functionName](...digestedArgs);
// });
// }

function mapRelativeArgsToAbsoluteArgs(functionName: string, args: number[]) {
switch (functionName) {
case 'rect':
return args.map(rToA)
default:
return args
}
export function aToR(n: number, canvasSize: number) {
return (n / canvasSize) * RELATIVE_SIZE
}
Loading