Skip to content

Commit

Permalink
Add canvas coordinates tooltip (#7270)
Browse files Browse the repository at this point in the history
* Add canvas coordinates tooltip

* Don't recalculate tooltip size on every mouse move
  • Loading branch information
dem4ron authored Jan 9, 2025
1 parent 72a48d6 commit 77be0e8
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 107 deletions.
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
}

0 comments on commit 77be0e8

Please sign in to comment.