mirror of https://github.com/mkrhere/pw2
1 changed files with 321 additions and 0 deletions
@ -0,0 +1,321 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
|
<title>Cursor Position in Transformed Element</title> |
||||
|
<style> |
||||
|
body { |
||||
|
font-family: Arial, sans-serif; |
||||
|
margin: 0; |
||||
|
padding: 20px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
.container { |
||||
|
margin: 50px; |
||||
|
position: relative; |
||||
|
width: 600px; |
||||
|
height: 400px; |
||||
|
border: 1px solid #ccc; |
||||
|
background-color: #fff; |
||||
|
} |
||||
|
|
||||
|
#transformed-element { |
||||
|
position: absolute; |
||||
|
width: 200px; |
||||
|
height: 150px; |
||||
|
background-color: rgba(100, 150, 250, 0.5); |
||||
|
border: 2px solid #4080ff; |
||||
|
top: 125px; |
||||
|
left: 200px; |
||||
|
transform-origin: center center; |
||||
|
transform: rotate(30deg) scale(1.2, 0.9); |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
font-weight: bold; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
#position-indicator { |
||||
|
position: absolute; |
||||
|
top: 10px; |
||||
|
left: 10px; |
||||
|
background-color: rgba(255, 255, 255, 0.8); |
||||
|
padding: 5px 10px; |
||||
|
border-radius: 5px; |
||||
|
font-family: monospace; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
#cursor-dot { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 6px; |
||||
|
height: 6px; |
||||
|
background-color: red; |
||||
|
border-radius: 50%; |
||||
|
margin-left: -3px; |
||||
|
margin-top: -3px; |
||||
|
pointer-events: none; |
||||
|
} |
||||
|
|
||||
|
#controls { |
||||
|
margin-bottom: 20px; |
||||
|
display: flex; |
||||
|
gap: 20px; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.control-group { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 5px; |
||||
|
} |
||||
|
|
||||
|
label { |
||||
|
font-size: 12px; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.status { |
||||
|
margin-top: 15px; |
||||
|
font-size: 14px; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
#inside-status { |
||||
|
margin-left: 20px; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h1>Cursor Position in Transformed Element</h1> |
||||
|
|
||||
|
<div id="controls"> |
||||
|
<div class="control-group"> |
||||
|
<label for="rotation">Rotation (degrees)</label> |
||||
|
<input |
||||
|
type="range" |
||||
|
id="rotation" |
||||
|
min="-180" |
||||
|
max="180" |
||||
|
value="30" |
||||
|
step="5" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="control-group"> |
||||
|
<label for="scale-x">Scale X</label> |
||||
|
<input |
||||
|
type="range" |
||||
|
id="scale-x" |
||||
|
min="0.5" |
||||
|
max="2" |
||||
|
value="1.2" |
||||
|
step="0.1" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="control-group"> |
||||
|
<label for="scale-y">Scale Y</label> |
||||
|
<input |
||||
|
type="range" |
||||
|
id="scale-y" |
||||
|
min="0.5" |
||||
|
max="2" |
||||
|
value="0.9" |
||||
|
step="0.1" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="control-group"> |
||||
|
<label for="translate-x">Translate X</label> |
||||
|
<input |
||||
|
type="range" |
||||
|
id="translate-x" |
||||
|
min="-100" |
||||
|
max="100" |
||||
|
value="0" |
||||
|
step="0.1" |
||||
|
/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="control-group"> |
||||
|
<label for="translate-y">Translate Y</label> |
||||
|
<input |
||||
|
type="range" |
||||
|
id="translate-y" |
||||
|
min="-100" |
||||
|
max="100" |
||||
|
value="0" |
||||
|
step="0.1" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="status"> |
||||
|
Element coordinates: <span id="coords"></span> |
||||
|
<span id="inside-status">Outside element</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="container"> |
||||
|
<div id="position-indicator">Position: (0, 0)</div> |
||||
|
<div id="transformed-element"> |
||||
|
Transformed Element |
||||
|
<div id="cursor-dot"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<script> |
||||
|
/** |
||||
|
* Calculate cursor position relative to a transformed DOM element's original coordinate system |
||||
|
* |
||||
|
* @param {MouseEvent} event - The mouse event containing cursor position |
||||
|
* @param {HTMLElement} element - The transformed DOM element |
||||
|
* @returns {Object} - The x,y coordinates relative to the element's internal coordinate system |
||||
|
*/ |
||||
|
function getCursorPositionRelativeToElement(event, element) { |
||||
|
// Get the mouse coordinates in client space |
||||
|
const clientX = event.clientX; |
||||
|
const clientY = event.clientY; |
||||
|
|
||||
|
// Get the element's current bounding box (includes transformation effects) |
||||
|
const boundingRect = element.getBoundingClientRect(); |
||||
|
|
||||
|
// If no transform is applied, do simple calculation |
||||
|
const computedStyle = window.getComputedStyle(element); |
||||
|
const transformValue = |
||||
|
computedStyle.transform || |
||||
|
computedStyle.webkitTransform || |
||||
|
computedStyle.mozTransform; |
||||
|
|
||||
|
if (transformValue === "none" || !transformValue) { |
||||
|
return { |
||||
|
x: clientX - boundingRect.left, |
||||
|
y: clientY - boundingRect.top, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
// Create a matrix from the transform string |
||||
|
const matrix = new DOMMatrix(transformValue); |
||||
|
|
||||
|
// Get the element's dimensions |
||||
|
const width = element.offsetWidth; |
||||
|
const height = element.offsetHeight; |
||||
|
|
||||
|
// Calculate the center of the transformed element |
||||
|
const centerX = boundingRect.left + boundingRect.width / 2; |
||||
|
const centerY = boundingRect.top + boundingRect.height / 2; |
||||
|
|
||||
|
// Calculate mouse position relative to the element's transformed center |
||||
|
const relativeToCenter = { |
||||
|
x: clientX - centerX, |
||||
|
y: clientY - centerY, |
||||
|
}; |
||||
|
|
||||
|
// Create the inverse of the transformation matrix |
||||
|
const inverseMatrix = matrix.inverse(); |
||||
|
|
||||
|
// Remove the translation components from the inverse matrix |
||||
|
inverseMatrix.e = 0; |
||||
|
inverseMatrix.f = 0; |
||||
|
|
||||
|
// Apply the inverse transformation (rotation and scaling only) |
||||
|
const transformedPoint = { |
||||
|
x: |
||||
|
relativeToCenter.x * inverseMatrix.a + |
||||
|
relativeToCenter.y * inverseMatrix.c, |
||||
|
y: |
||||
|
relativeToCenter.x * inverseMatrix.b + |
||||
|
relativeToCenter.y * inverseMatrix.d, |
||||
|
}; |
||||
|
|
||||
|
// Convert from center-relative to top-left-relative coordinates |
||||
|
return { |
||||
|
x: transformedPoint.x + width / 2, |
||||
|
y: transformedPoint.y + height / 2, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
// DOM elements |
||||
|
const element = document.getElementById("transformed-element"); |
||||
|
const indicator = document.getElementById("position-indicator"); |
||||
|
const cursorDot = document.getElementById("cursor-dot"); |
||||
|
const coordsDisplay = document.getElementById("coords"); |
||||
|
const insideStatus = document.getElementById("inside-status"); |
||||
|
|
||||
|
// Control elements |
||||
|
const rotationControl = document.getElementById("rotation"); |
||||
|
const scaleXControl = document.getElementById("scale-x"); |
||||
|
const scaleYControl = document.getElementById("scale-y"); |
||||
|
const translateXControl = document.getElementById("translate-x"); |
||||
|
const translateYControl = document.getElementById("translate-y"); |
||||
|
|
||||
|
// Update transform based on controls |
||||
|
function updateTransform() { |
||||
|
const rotation = rotationControl.value; |
||||
|
const scaleX = scaleXControl.value; |
||||
|
const scaleY = scaleYControl.value; |
||||
|
const translateX = translateXControl.value; |
||||
|
const translateY = translateYControl.value; |
||||
|
|
||||
|
element.style.transform = `rotate(${rotation}deg) scale(${scaleX}, ${scaleY}) translate(${translateX}px, ${translateY}px)`; |
||||
|
} |
||||
|
|
||||
|
// Listen to control changes |
||||
|
rotationControl.addEventListener("input", updateTransform); |
||||
|
scaleXControl.addEventListener("input", updateTransform); |
||||
|
scaleYControl.addEventListener("input", updateTransform); |
||||
|
translateXControl.addEventListener("input", updateTransform); |
||||
|
translateYControl.addEventListener("input", updateTransform); |
||||
|
|
||||
|
// Track mouse movement |
||||
|
document.addEventListener("mousemove", event => { |
||||
|
// Show cursor dot |
||||
|
// cursorDot.style.left = `${event.clientX}px`; |
||||
|
// cursorDot.style.top = `${event.clientY}px`; |
||||
|
|
||||
|
// Get relative position |
||||
|
const relativePos = getCursorPositionRelativeToElement(event, element); |
||||
|
|
||||
|
// Round values for display |
||||
|
const x = Math.round(relativePos.x); |
||||
|
const y = Math.round(relativePos.y); |
||||
|
|
||||
|
// Update position indicator |
||||
|
indicator.textContent = `Position: (${x}, ${y})`; |
||||
|
coordsDisplay.textContent = `(${x}, ${y})`; |
||||
|
|
||||
|
// Check if cursor is within original element dimensions |
||||
|
const isInside = |
||||
|
relativePos.x >= 0 && |
||||
|
relativePos.x <= element.offsetWidth && |
||||
|
relativePos.y >= 0 && |
||||
|
relativePos.y <= element.offsetHeight; |
||||
|
|
||||
|
// Update status indicators |
||||
|
if (isInside) { |
||||
|
insideStatus.textContent = "Inside element"; |
||||
|
insideStatus.style.color = "green"; |
||||
|
coordsDisplay.style.color = "green"; |
||||
|
|
||||
|
cursorDot.style.transform = `translate(${relativePos.x}px, ${relativePos.y}px)`; |
||||
|
cursorDot.style.opacity = "1"; |
||||
|
} else { |
||||
|
insideStatus.textContent = "Outside element"; |
||||
|
insideStatus.style.color = "red"; |
||||
|
coordsDisplay.style.color = "red"; |
||||
|
|
||||
|
cursorDot.style.transform = `translate(0px, 0px)`; |
||||
|
cursorDot.style.opacity = "0"; |
||||
|
} |
||||
|
}); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
Loading…
Reference in new issue