当CSS元素从原始位置转换出来时,transform-origin
不随其移动;使所有后续的变换和旋转仍然来自它的原始transform-origin
(例如下面的例子)。
我知道有一种解决方法......那就是继续将所有新变换添加到前一个变换的右边。像这样:transform: translateY ( -5rem ) rotate( 45deg ) translateY( -10rem ) rotate( 15deg )...
等。这似乎总是根据需要从当前元素的中心开始新的变换。
问题
使用此技术基于用户输入转换元素时,您将不断向DOM添加转换。占用大量内存并导致其他不需要的滑动效果(可能)。
这是一个动画,显示每次变换后transform-origin
如何不移动到元素的中心:
'use strict';
function firstRotation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'First, the V is rotated around it\'s central axis.\
The <b>transform-origin</b> is centered.';
v.classList.add( 'first-rotation' );
status.classList.add( 'update' );
}, 1000 );
}
function firstTranslation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'Next, the element is translated forward in it\'s \
current orientation. The <b>transform-origin</b> stays\
behind where it was.';
v.classList.remove( 'first-rotation' );
v.classList.add( 'first-translation' );
}, 6000 );
}
function info() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'This next animation is where it\'s evident that\
the <b>transform-origin</b> is no longer centered, but\
back where it was at the beginning of these transforms';
}, 11000 );
}
function lastRotation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'This last rotation is far wider than desired because the\
transform origin is back where it started.'
v.classList.remove( 'first-translation' );
v.classList.add( 'last-rotation' );
}, 16000 );
}
function end() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.classList.remove( 'update' );
}, 21000 );
}
function start() {
firstRotation();
firstTranslation();
info();
lastRotation();
end();
}
start();
/* / / / / / / / / / / / / / ANIMATION DEFINITIONS / / / / / / / / / / / / / */
.first-rotation, .first-translation, .update, .last-rotation {
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
}
.first-rotation {
animation-name: first-rotation;
}
.first-translation {
animation-name: first-translation;
}
.update {
animation-name: update;
animation-iteration-count: infinite;
}
.last-rotation {
animation-name: last-rotation;
}
/*/ / / / / / / / / / / / / / ANIMATION KEYFRAMES / / / / / / / / / / / / / /*/
@keyframes first-rotation {
100% {
transform: rotate( 315deg );
}
}
@keyframes first-translation {
0% {
transform: rotate( 315deg );
}
100% {
transform: rotate( 315deg ) translate( 0, -5rem );
}
}
@keyframes update {
0% {
background-color: mediumslateblue;
}
}
@keyframes last-rotation {
0% {
transform: rotate( 315deg ) translate( 0, -5rem );
}
100% {
transform: rotate( 400deg ) translate( 0, -5rem );
}
}
<head>
<style>
@import url( "https://fonts.googleapis.com/css?family=Nunito" );
html {
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-family: "Nunito", sans-serif;
}
html,
body {
margin: 0;
padding: 0;
}
.v {
display: block;
font-size: 2rem;
transform: rotate( 180deg );
}
p {
width: 100%;
padding: 0.5rem;
position: absolute;
bottom: 0;
left: 0;
}
</style>
</head>
<body>
<div id="v-wrp" class="v-wrp">
<b class="v">V</b>
</div>
<p id="status" class="status"></p>
</body>
问题
我需要在CSS或JS中找到一种方法来重置transform-origin
的位置或将其移回到变换元素的中心。向右添加更多变换是一种在实时交互式环境中不适合我的技术。可以在这里看到一个尝试:Transforms are added...endlessly。
如何计算转换元素的位置并将transform-origin
移回其中心?或者如何获取多个转换值并将它们压缩为一个值,使其中的元素保持不变放置吗
答案 0 :(得分:0)
您还可以使用group_id <- c(rep(1, 22), rep(2, 27), rep(3, 51), rep(4, 26), rep(5, 8), rep(6, 17), rep(7, 26), rep(8, 17), rep(9, 14))
element_id <- c(seq.int(1, 22), seq.int(1, 27), seq.int(1, 51), seq.int(1, 26), seq.int(1, 8), seq.int(1, 17), seq.int(1, 26), seq.int(1, 17), seq.int(1, 14))
segment_id <- c(rep(1, 22), rep(1, 13), rep(2, (24-13)), rep(3, (27-24)), rep(1, 16), rep(2, (30-16)), rep(3, (51-30)), rep(1, 14), rep(2, (26-14)), rep(1, 8), rep(1, 6), rep(2, (11-6)), rep(3, (17-11)), rep(1, 9), rep(2, (20-9)), rep(3, (26-20)), rep(1, 17), rep(1,14))
solution_df <- data.frame(group_id, element_id, segment_id)
和top
翻译left
。您可以在#v-wrp
属性中创建动画。在transform-origin
元素中尝试一下。我希望它现在能够正常运作。
答案 1 :(得分:0)
您的问题是结构性问题。保持您的参考点(变换原点)不变,并按层分离您的旋转和平移变换(从原点平移的包含元素和根据需要旋转的内部包含元素)。
从结构上分离这些转换元素将从一开始就防止诸如此类的“跨源”问题。
答案 2 :(得分:0)
如果有人还在寻找这样的东西。
@jmcgrory 是对的,有单独的层真的很方便。但对于某些情况,以下将起作用。
如果您可以使用 svg,那么 transform-box 可能会有所帮助。
但是如果你使用任何其他元素而不是它会很困难,因为引用框(可以认为是元素的初始位置)在应用变换后不会改变,并且变换原点将根据其引用框进行处理。 transform-origin 需要与 translate 一起移动,transform:rotate 会变得更复杂,因为您必须计算元素移动的 x 和 y 长度,并基于此需要替换 transform(如果用于任何一个轴)到 x 和 y 并相应地更新变换原点,这种方法非常棘手,但效果很好,并且完全取决于元素运动的数学计算(您不需要编写太多的 css,但必须做一些计算)。
我已经复制了问题的片段并使其按预期工作。请检查以下代码以供参考。
'use strict';
function firstRotation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'First, the V is rotated around it\'s central axis.\
The <b>transform-origin</b> is centered.';
v.classList.add( 'first-rotation' );
status.classList.add( 'update' );
}, 1000 );
}
function firstTranslation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'Next, the element is translated forward in it\'s \
current orientation. The <b>transform-origin</b> stays\
behind where it was.';
v.classList.remove( 'first-rotation' );
v.classList.add( 'first-translation' );
}, 6000 );
}
function info() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'This next animation is where it\'s evident that\
the <b>transform-origin</b> is no longer centered, but\
back where it was at the beginning of these transforms';
}, 11000 );
}
function lastRotation() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.innerHTML = 'This last rotation is working correctly with calculated transform-origin.'
v.classList.remove( 'first-translation' );
v.classList.add( 'last-rotation' );
}, 16000 );
}
function end() {
var v = document.getElementById( 'v-wrp' ),
status = document.getElementById( 'status' )
setTimeout( function() {
status.classList.remove( 'update' );
}, 21000 );
}
function start() {
firstRotation();
firstTranslation();
info();
lastRotation();
end();
}
start();
/* / / / / / / / / / / / / / ANIMATION DEFINITIONS / / / / / / / / / / / / / */
.first-rotation, .first-translation, .update, .last-rotation {
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-fill-mode: forwards;
}
.first-rotation {
animation-name: first-rotation;
}
.first-translation {
animation-name: first-translation;
}
.update {
animation-name: update;
animation-iteration-count: infinite;
}
.last-rotation {
animation-name: last-rotation;
}
/*/ / / / / / / / / / / / / / ANIMATION KEYFRAMES / / / / / / / / / / / / / /*/
@keyframes first-rotation {
100% {
transform: rotate( 315deg );
}
}
@keyframes first-translation {
0% {
transform: rotate( 315deg );
}
100% {
transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px);
transform: rotate( 315deg ) translate( -3.536rem, -3.536rem );
}
}
@keyframes update {
0% {
background-color: mediumslateblue;
}
}
@keyframes last-rotation {
0% {
transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px);
transform: rotate( 315deg ) translate( -3.536rem, -3.536rem );
}
100% {
transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px);
transform: rotate( 400deg ) translate( -3.536rem, -3.536rem );
}
}
<head>
<style>
@import url( "https://fonts.googleapis.com/css?family=Nunito" );
html {
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-family: "Nunito", sans-serif;
}
html,
body {
margin: 0;
padding: 0;
}
.v {
display: block;
font-size: 2rem;
transform: rotate( 180deg );
}
p {
width: 100%;
padding: 0.5rem;
position: absolute;
bottom: 0;
left: 0;
}
</style>
</head>
<body>
<div id="v-wrp" class="v-wrp">
<b class="v">V</b>
</div>
<p id="status" class="status"></p>
</body>
答案 3 :(得分:0)
您将能够使用 JavaScript 的 DOMMatrix 或您自己的值来跟踪平移和旋转值。
这是一个非常基本的示例,例如您的小行星游戏: https://jsfiddle.net/omjktrsh/
矩阵为您提供了操作它的函数,而无需学习所有数学知识。 2D 变体有六个属性,它们是 3x3 矩阵的一部分:
a c e
b d f
0 0 1
哪里:
您可以使用 rotateSelf(deg)
使矩阵对其当前值执行旋转,或使用 rotate(deg)
使矩阵返回具有添加旋转的新矩阵(保留具有相同值的原始矩阵).
您可以使用 translateSelf(x, y)
相对于其当前旋转来移动它。如果你想移动它而不是相对于它的当前旋转,你可以像这样直接操作 e
和 f
值:
matrix.e += x; // x axis translation amount
matrix.f += y; // y axis translation amount
您可以轻松地应用任意数量的旋转,而无需在 CSS 中堆叠它们,然后使用 toString()
以 CSS 形式输出矩阵:
const matrix = new DOMMatrix();
const el = document.getElementById("transform-me");
// manipulate matrix as much as you want
...
matrix.translateSelf(...);
...
matrix.rotateSelf(...);
...
// apply matrix to elements css -> matrix(a, b, c, d, e, f)
el.style.transform = matrix.toString();
缺点是 DOMMatrix 的浏览器支持较少:https://caniuse.com/dommatrix
如果您想支持不支持 DOMMatrix 的浏览器,您仍然可以在这些浏览器中使用自己的数学和 transform: matrix(a, b, c, d, e, f)
语法:https://caniuse.com/transforms2d
如果您想了解二维变换矩阵背后的数学原理,Wikipedia 上有示例。请注意,某些资源使用了上面那个矩阵的翻转矩阵:
a b 0
c d 0
e f 1