如何将屏幕坐标转换为 Z 转换元素上的坐标?

3

我有一个 Z-transformed 元素,其中包含一个标记作为子元素,我需要将该标记放置在鼠标单击位置。

我需要知道如何将屏幕坐标转换为 Z-transformed 元素上的坐标。

这是我当前的代码:

function getPosition(screenCoords)
{
    // This function should return x and y coordinates on z-transformed element and I have no idea how to achieve that.
    
    return {x: 2500, y: 1500};
}

var $viewport = $(".viewport");
var $marker = $(".marker");
    
$viewport.on("click", function(e){
        
    e.preventDefault();
        
    var newMarkerPosition = getPosition({x: e.pageX, y: e.pageY});
        
    $marker.css({
        left: newMarkerPosition.x + "px", 
        top: newMarkerPosition.y + "px"
    });
        
});
html, body {
    
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    
}

.viewport {
    
    width: 100%;
    height: 100%;
    overflow: hidden;
    
    perspective: 1000px;
    perspective-origin: 50% 50%;
}

.z-transformed-element {
    
    width: 5000px;
    height: 3000px;
    transform-origin: 2500px 1500px;
    background-color: gray;
    position: relative;
    
    transform: translateX(-2500px) translateY(-1500px) translateZ(-10000px);
    
}

.marker {
    
    left: 0;
    top: 0;
    
    width: 200px;
    height: 200px;
    margin-left: -100px;
    margin-top: -100px;
    background-color: red;
    border-radius: 100px;
    position: absolute;
    
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="viewport">
    <div class="z-transformed-element">
        <div class="marker"></div>
    </div>
</div>

1个回答

3
这里最困难的部分似乎是将点击的屏幕坐标转换为变换后的坐标。你可以使用getBoundingClientRect()函数(返回对象应用所有变换后的尺寸/位置)来计算元素显示尺寸和“实际”尺寸之间的比率,从而完成此操作。
一旦得到比率,只需将其与点击坐标相乘(并将其偏移以相对于元素的显示中心坐标),即可获得变换后的点击坐标。
我已经修改了您的代码,以展示如何使用此方法将CSS变换的元素移动到鼠标点击位置:

function getPosition(screenCoords)
{
    var $transformedEl = $(".z-transformed-element");
    
    // Calculating "actual" center of element
    var elementCenter = {
        x: $transformedEl.innerWidth() / 2,
        y: $transformedEl.innerHeight() / 2
    }
    
    // Determining ratio of displayed dimensions to "actual" dimensions
    var boundingRect = $transformedEl[0].getBoundingClientRect();
    var dimRatio = $transformedEl.innerWidth() / boundingRect.width;
    
    // Determining offset click coordinates (relative to displayed center of element)
    var clickOffset = {
        x: screenCoords.x - $transformedEl.offset().left - boundingRect.width / 2,
        y: screenCoords.y - $transformedEl.offset().top - boundingRect.height / 2
    }
    
    // Calculating coordinates of click, relative to element's "actual" center and ratio of displayed to "actual" dimensions
    var finalCoords = {
     x: elementCenter.x + clickOffset.x * dimRatio,
     y: elementCenter.y + clickOffset.y * dimRatio
    }
    
    return finalCoords;
}

var $viewport = $(".viewport");
var $marker = $(".marker");
    
$viewport.on("click", function(e){
        
    e.preventDefault();
    
    console.log(e.pageX, e.pageY);
    
    var newMarkerPosition = getPosition({x: e.pageX, y: e.pageY});
        
    $marker.css({
        left: newMarkerPosition.x + "px", 
        top: newMarkerPosition.y + "px"
    });
        
});
html, body {
    
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    
}

.viewport {
    
    width: 100%;
    height: 100%;
    overflow: hidden;
    
    perspective: 1000px;
    perspective-origin: 50% 50%;
}

.z-transformed-element {
    
    width: 5000px;
    height: 3000px;
    transform-origin: 2500px 1500px;
    background-color: gray;
    position: relative;
    
    transform: translateX(-2500px) translateY(-1500px) translateZ(-10000px);
    
}

.marker {
    
    left: 0;
    top: 0;
    
    width: 200px;
    height: 200px;
    margin-left: -100px;
    margin-top: -100px;
    background-color: red;
    border-radius: 100px;
    position: absolute;
    
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="viewport">
    <div class="z-transformed-element">
        <div class="marker"></div>
    </div>
</div>

我承认对于我来说,找到最简单的方法很难 - 我几乎走了通过转换矩阵来转换坐标的路线!唉。

希望这能帮到你!如果你有任何问题,请告诉我。


太棒了!之前不知道getBoundingClientRect()这个方法。看起来它能让事情变得更简单。非常感谢! - GiedriusT
很高兴能帮上忙!对我来说,这也是一个学习的经历。 - Serlite
但是现在我尝试旋转元素,它开始计算坐标错误。你能想出适用于旋转元素的解决方案吗?我对rotateX和rotateY很感兴趣。 - GiedriusT
@GiedriusT 很遗憾,我怀疑这样会使问题的范围变得更广(我最初考虑使用转换矩阵可能现在并不过分)。考虑提出一个新问题来解决这个? - Serlite
好的,我会就这个问题提出一个新的问题。 - GiedriusT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接