【问题标题】:How to convert screen coordinates to coordinates on a z transformed element?如何将屏幕坐标转换为 z 变换元素上的坐标?
【发布时间】:2015-10-07 14:22:37
【问题描述】:

我有一个 z 变换元素,它有一个标记作为子元素,我需要将该标记放在鼠标单击位置。

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

这是我当前的代码:

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>

【问题讨论】:

    标签: javascript 3d css-transforms coordinate-transformation


    【解决方案1】:

    这里最困难的部分似乎是将点击的屏幕空间坐标转换为转换后的坐标。一种方法是使用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()。它似乎使事情变得更容易。非常感谢!
    • 很高兴我能帮上忙!这对我来说也是一次学习经历。
    • 但是现在我尝试旋转元素,它开始计算坐标错误。你能想出一些适用于旋转元素的东西吗?我对rotateX 和rotateY 感兴趣。
    • @GiedriusT 不幸的是,我怀疑这会扩大问题的范围(我最初使用转换矩阵的想法现在可能不会过大)。考虑为此提出一个新问题?
    • 好的,我会就此提出一个新问题。
    猜你喜欢
    • 2018-06-28
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多