我正在尝试构建一个界面,该界面允许在某些元素上进行大小调整/拖动和旋转,并且要实现此目的,我正在使用interact.js javascript库。
我的交互功能正在工作:
interact('.resize-drag-ratio')
.draggable({
onmove: window.dragMoveListener
})
.resizable({
preserveAspectRatio: true,
edges: { left: true, right: true, bottom: true, top: true }
})
.on('resizemove', function (event) {
var target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0),
y = (parseFloat(target.getAttribute('data-y')) || 0);
var min_size = 35;
if(event.rect.width>min_size){
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.webkitTransform = target.style.transform =
'translate(' + x + 'px,' + y + 'px)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
});
并拖动以允许旋转
interact('.drag-rotate')
.draggable({
onstart: function (event) {
const element = event.target;
const rect = element.getBoundingClientRect();
// store the center as the element has css `transform-origin: center center`
element.dataset.centerX = rect.left + rect.width / 2;
element.dataset.centerY = rect.top + rect.height / 2;
console.log("element.dataset.centerX: "+element.dataset.centerX);
console.log("element.dataset.centerY: "+element.dataset.centerY);
// get the angle of the element when the drag starts
element.dataset.angle = getDragAngle(event);
},
onmove: function (event) {
var element = event.target;
var center = {
x: 300,
y: 300,
};
console.log("element.dataset.centerX: "+element.dataset.centerX);
console.log("element.dataset.centerY: "+element.dataset.centerY);
var angle = getDragAngle(event);
// update transform style on dragmove
element.style.transform = 'rotate(' + angle + 'rad' + ')';
},
onend: function (event) {
const element = event.target;
// save the angle on dragend
element.dataset.angle = getDragAngle(event);
},
})
这两个类使用jQuery进行切换,从而将拖动变成旋转,反之亦然。
我的问题是对象的位置和旋转角度没有保持原样,而且我不确定如何解决。
将元素拖动到某个位置并按下“旋转”按钮后,我开始旋转该元素,该元素向左移动:0px,向左移动0px,并且不停留在其拖动位置。
您可以在此处查看完整的工作代码: https://codepen.io/yaary-vidanpeled/pen/ZZwGmE
答案 0 :(得分:1)
之所以发生这种情况,是因为每次应用CSS时,都会覆盖以前的样式。
这里是一个示例,假设您有一个文本(#text
,其中color
为red
,现在您想使用JavaScript进行更改。
document.getElementById('text').style.color = 'green';
这里实际上发生了什么?分配给样式对象的color属性的所有内容都将被覆盖。
在编写时(在.resize-drag-ratio
的交互初始化中),发生了同样的事情:
target.style.transform = 'translate(' + x + 'px,' + y + 'px)';
并通过写入(在translate
的交互初始化中)再次覆盖.drag-rotate
element.style.transform = 'rotate(' + angle + 'rad' + ')';
请记住,rotate()
和translate()
都是css translate
属性的值。
您应该以某种方式保留所有这些旋转角度并转换值。 (看起来您已经有了data-attribtues
了,所以不会很难)
并按如下所示应用element.style.transform
的值:
target.style.transform = 'translate(' + x + 'px,' + y + 'px) rotate(' + angle + 'rad)';
注意:您的代码段两次声明了function dragMoveListener(event) {
。
工作段:
console.log('start');
//function isEven
function isEven(n) {
return n == parseFloat(n) ? !(n % 2) : void 0;
}
interact('.resize-drag-ratio')
.draggable({
onmove: window.dragMoveListener
})
.resizable({
preserveAspectRatio: true,
edges: {
left: true,
right: true,
bottom: true,
top: true
}
})
.on('resizemove', function(event) {
var target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0),
y = (parseFloat(target.getAttribute('data-y')) || 0);
rotation = (parseFloat(target.getAttribute('data-angle')) || 0)
var min_size = 35;
if (event.rect.width > min_size) {
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.webkitTransform = target.style.transform =
'translate(' + x + 'px,' + y + 'px) rotate(' + rotation + 'rad)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
});
interact('.resize-drag')
.draggable({
onmove: window.dragMoveListener
})
.resizable({
preserveAspectRatio: false,
edges: {
left: true,
right: true,
bottom: true,
top: true
}
})
.on('resizemove', function(event) {
var target = event.target,
x = (parseFloat(target.getAttribute('data-x')) || 0),
y = (parseFloat(target.getAttribute('data-y')) || 0),
rotation = (parseFloat(target.getAttribute('data-angle')) || 0)
//console.log("event.rect.width: "+event.rect.width);
//prevents resizing to units smaller then 35px
var min_size = 35;
if (event.rect.width > min_size) {
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
//$("#form_bubble_width").val(event.rect.width);
//$("#form_bubble_width").val(event.rect.height);
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
target.style.webkitTransform = target.style.transform =
'translate(' + x + 'px,' + y + 'px) rotate(' + rotation + 'rad)';
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
//target.textContent = event.rect.width + '×' + event.rect.height;
}
});
// target elements with the "draggable" class
interact('.draggable')
.draggable({
// enable inertial throwing
inertia: true,
// keep the element within the area of it's parent
restrict: {
restriction: "parent",
endOnly: true,
elementRect: {
top: 0,
left: 0,
bottom: 1,
right: 1
}
},
// enable autoScroll
autoScroll: true,
// call this function on every dragmove event
onmove: dragMoveListener,
// call this function on every dragend event
onend: function(event) {
// var textEl = event.target.querySelector('p');
console.log(event.target.id)
var distance = (Math.sqrt(Math.pow(event.pageX - event.x0, 2) +
Math.pow(event.pageY - event.y0, 2) | 0))
.toFixed(2) + 'px';
}
});
interact('.resize-drag , .resize-drag-ratio').on('tap', function(event) {
event.preventDefault();
var target = event.target
console.log("tap resize-drag class element");
var uuid = target.id;
//console.log("uuid: "+uuid);
console.log("click");
});
function dragMoveListener(event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy,
rotation = (parseFloat(target.getAttribute('data-angle')) || 0);
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px) rotate(' + rotation + 'rad)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
target.setAttribute('data-angle', rotation);
}
// this is used later in the resizing and gesture demos
window.dragMoveListener = dragMoveListener;
var mouseX = 0,
mouseY = 0
//function onMousemove(e)
function onMousemove(e) {
var m_posx = 0,
m_posy = 0,
e_posx = 0,
e_posy = 0,
obj = this;
//get mouse position on document crossbrowser
if (!e) {
e = window.event;
}
if (e.pageX || e.pageY) {
m_posx = e.pageX;
m_posy = e.pageY;
} else if (e.clientX || e.clientY) {
m_posx = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
m_posy = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
//get parent element position in document
if (obj.offsetParent) {
do {
e_posx += obj.offsetLeft;
e_posy += obj.offsetTop;
} while (obj = obj.offsetParent);
}
// mouse position minus elm position is mouseposition relative to element:
dbg.innerHTML = ' X Position: ' + (m_posx - e_posx) +
' Y Position: ' + (m_posy - e_posy);
mouseX = (m_posx - e_posx);
mouseY = (m_posy - e_posy);
}
var elem = document.getElementById('container');
//elem.addEventListener('mousemove', onMousemove, false);
var dbg = document.getElementById('dbg'); //just for debug div instead of console
$(document).ready(function() {
var is_rotate = true;
$("#btn_rotate").click(function() {
// console.log('ddd');
if (is_rotate) {
$(this).text('drag-resize');
$(".element").removeClass("drag-rotate");
$(".element").addClass("resize-drag-ratio");
is_rotate = false;
} else {
$(this).text('rotate');
$(".element").removeClass("resize-drag-ratio");
$(".element").addClass("drag-rotate");
is_rotate = true;
}
//console.log('click: '+is_rotate);
});
var saved_mouseX = 0;
var saved_mouseY = 0;
//interact("#container").on('tap', function (event) {
interact("#container").on('tap', function(event) {
event.preventDefault();
var target = event.target
if (target.id == "tp_image") {
console.log(target.id);
console.log(mouseX + "-" + mouseY);
saved_mouseX = mouseX;
saved_mouseY = mouseY;
//$('#modal_stickers').modal('show');
}
});
//interact('.drag-rotate')
interact('.drag-rotate')
.draggable({
onstart: function(event) {
const element = event.target;
const rect = element.getBoundingClientRect();
// store the center as the element has css `transform-origin: center center`
element.dataset.centerX = rect.left + rect.width / 2;
element.dataset.centerY = rect.top + rect.height / 2;
// console.log("element.dataset.centerX: " + element.dataset.centerX);
// console.log("element.dataset.centerY: " + element.dataset.centerY);
// get the angle of the element when the drag starts
element.dataset.angle = getDragAngle(event);
},
onmove: function(event) {
var element = event.target;
var center = {
x: 300,
y: 300,
};
// console.log("element.dataset.centerX: " + element.dataset.centerX);
// console.log("element.dataset.centerY: " + element.dataset.centerY);
var angle = getDragAngle(event);
var x = element.dataset.x;
var y = element.dataset.y;
// update transform style on dragmove
// this is where the bug was; at initial point, there was no x, or y position set on the dataset of the element. thus your style value would be undefined, so here we check the values of x and y first and set the style accordingly;
if (typeof x != 'undefined' && typeof y != 'undefined') {
element.style.transform = 'translate(' + x + 'px, ' + y + 'px) rotate(' + angle + 'rad' + ')';
} else {
element.style.transform = 'rotate(' + angle + 'rad' + ')';
}
},
onend: function(event) {
const element = event.target;
// save the angle on dragend
element.dataset.angle = getDragAngle(event);
},
})
//function getDragAngle(event)
function getDragAngle(event) {
var element = event.target;
var startAngle = parseFloat(element.dataset.angle) || 0;
var center = {
x: parseFloat(element.dataset.centerX) || 0,
y: parseFloat(element.dataset.centerY) || 0,
};
var angle = Math.atan2(center.y - event.clientY,
center.x - event.clientX);
return angle - startAngle;
}
});
#btn_rotate {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
background: #ccc;
padding: 30px;
}
.element {
width: 25%;
min-height: 6.5em;
margin: 10%;
background-color: #29e;
color: white;
/* added later */
touch-action: none;
box-sizing: border-box;
}
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.0.js"></script>
<script type="text/javascript" src="https://unpkg.com/interactjs@next/dist/interact.js"></script>
<div class="element drag-rotate">
<p> drag to rotate</p>
</div>
<div id="btn_rotate">rotate
</div>
在脚本部分上
检查行。有一条评论解释了if
块以及发生这种情况的原因。