Musical keyboard component written in React.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

60 rivejä
2.2 KiB

  1. type ReverseGetKeyFromPoint = (
  2. baseElement: HTMLElement,
  3. accidentalKeyLengthRatio: number,
  4. ) => (clientX: number, clientY?: number) => { key: number; velocity: number } | null
  5. const reverseGetKeyFromPoint: ReverseGetKeyFromPoint = (baseElement, accidentalKeyLengthRatio) => {
  6. const { top, left, width, height } = baseElement.getBoundingClientRect()
  7. return (clientX, clientY = top) => {
  8. const realTop = clientY - top
  9. const realLeft = clientX - left
  10. // convert the clientX to units in which keys are displayed (percentage)
  11. const leftInKeyUnits = (realLeft / width) * 100
  12. const maybeAccidental = realTop <= height * accidentalKeyLengthRatio!
  13. const keysArray = Array.from(baseElement.children) as HTMLElement[]
  14. const keys = keysArray.filter((c) => 'key' in c.dataset)
  15. const currentOctave = keys.filter((k) => {
  16. const octaveLeftBounds = Number(k.dataset.octaveLeftBounds)
  17. const octaveRightBounds = Number(k.dataset.octaveRightBounds)
  18. return octaveLeftBounds <= leftInKeyUnits && leftInKeyUnits < octaveRightBounds
  19. })
  20. const key: HTMLElement | undefined = currentOctave.reduce<HTMLElement | undefined>((selectedKey, octaveKey) => {
  21. if (maybeAccidental) {
  22. if (selectedKey !== undefined) {
  23. return selectedKey
  24. }
  25. const keyLeftBounds = Number(octaveKey.dataset.leftBounds)
  26. const keyRightBounds = Number(octaveKey.dataset.rightBounds)
  27. if (keyLeftBounds <= leftInKeyUnits && leftInKeyUnits < keyRightBounds) {
  28. return octaveKey
  29. }
  30. return selectedKey
  31. }
  32. if (selectedKey !== undefined) {
  33. return selectedKey
  34. }
  35. if (
  36. 'leftFullBounds' in octaveKey.dataset &&
  37. 'rightFullBounds' in octaveKey.dataset &&
  38. Number(octaveKey.dataset.leftFullBounds) <= leftInKeyUnits &&
  39. leftInKeyUnits < Number(octaveKey.dataset.rightFullBounds)
  40. ) {
  41. return octaveKey
  42. }
  43. return selectedKey
  44. }, undefined)
  45. if (key! === undefined) {
  46. return null
  47. }
  48. const { height: keyHeight } = key.getBoundingClientRect()
  49. return {
  50. velocity: realTop / keyHeight,
  51. key: Number(key.dataset.key),
  52. }
  53. }
  54. }
  55. export default reverseGetKeyFromPoint