Изменение размера повернутого элемента с помощью javascript (interactive.js)
Я потратил много дней, пытаясь сделать изменяемый размер элемента, который вращается с помощью interactive.js.
Это код, который у меня есть в данный момент, я попытаюсь объяснить концепцию.
У нас есть элемент селектора по двум причинам, потому что контейнер можно масштабировать с помощью css-преобразования (например, масштабирования), и нам нужно, чтобы селектор был снаружи, и потому что у нас есть многоселемент, а селектор растет, если у меня есть два прямоугольника, но в этом случае это не главная проблема, и мы вычислили масштабированную пропорцию без проблем и прочего.
Когда селектор изменяет размер, он принимает прямоугольник и делает то же самое с шириной, высотой, слева, сверху и вращением.
Javascript:
// TAP - CLICK EVENT (just for positioning the selector)
interact('#rectangle').on('tap', event => {
console.log('Tap Box!');
event.stopPropagation();
const $rectangleCloned = $('#rectangle').clone();
const previousTransform = $rectangleCloned.css('transform');
$rectangleCloned.css('transform', 'none');
$rectangleCloned.css('opacity', '0');
$rectangleCloned.css('display', 'block');
$('#container').append($rectangleCloned);
const values = $rectangleCloned[0].getBoundingClientRect();
// This is just a trick for fast implementation:
$('#selector').css('top', values.y);
$('#selector').css('left', values.x);
$('#selector').css('width', values.width);
$('#selector').css('height', values.height);
$('#selector').css('transform', previousTransform);
$rectangleCloned.remove();
return values;
});
interact('.pointer9').draggable({
max: 1,
onmove: event => {
const angleDeg =
Math.atan2(
centerRotate.posY - event.pageY,
centerRotate.posX - event.pageX
) *
180 /
Math.PI;
console.log(this.rotate);
const prevAngle = this.rotate - angleInitial;
const angle = parseInt(angleDeg) + prevAngle;
this.$rectangle.css({
transform: 'rotate(' + angle + 'deg)'
});
this.$selector.css({
transform: 'rotate(' + angle + 'deg)'
});
},
onstart: event => {
const data = event.interactable.getRect(event.target.parentNode);
this.centerRotate = {
posX: data.left + data.width / 2,
posY: data.top + data.height / 2
};
this.angleInitial =
Math.atan2(
centerRotate.posY - event.pageY,
centerRotate.posX - event.pageX
) *
180 /
Math.PI;
this.$rectangle = $('#rectangle');
this.$selector = $('#selector');
this.rotate = $rectangle.attr('angle') || 0;
},
onend: event => {
const $box = $('#selector');
const matrix = $box.css('transform');
const values = matrix
.split('(')[1]
.split(')')[0]
.split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
$rectangle.attr('angle', angle);
}
});
interact('#selector')
.resizable({
// resize from all edges and corners
edges: {
left: true,
right: true,
bottom: true,
top: true
},
// keep the edges inside the parent
restrictEdges: {
outer: 'parent',
endOnly: true,
},
// minimum size
restrictSize: {
min: {
width: 100,
height: 50
},
},
inertia: true,
})
.on('resizemove', function(event) {
var target = event.target,
x = parseFloat($(target).offset().left) || 0,
y = parseFloat($(target).offset().top) || 0;
// update the element 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.left = x + 'px';
target.style.top = y + 'px';
$('#rectangle')[0].style.left = target.style.left;
$('#rectangle')[0].style.top = target.style.top;
$('#rectangle')[0].style.width = target.style.width;
$('#rectangle')[0].style.height = target.style.height;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
});
CSS:
#container {
width: 500px;
height: 400px;
top: 0;
left: 0;
position: absolute;
background-color: #CCC;
}
#rectangle {
top: 50px;
left: 50px;
width: 120px;
height: 60px;
background-color: red;
position: absolute;
}
#selector {
display: inline-block;
position: absolute;
pointer-events: none;
z-index: 9999;
top: -1000px;
/*Not showing at start*/
}
#selector .pointers {
display: inline-block;
position: absolute;
z-index: 2;
width: 10px;
height: 10px;
pointer-events: all;
}
#selector .pointers .point {
width: 10px;
height: 10px;
background-color: #fff;
border: 2px solid rgba(0, 0, 0, 0.9);
border-radius: 50%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
#selector .pointers.pointer1 {
top: -5px;
left: -5px;
}
#selector .pointers.pointer2 {
bottom: -5px;
left: -5px;
}
#selector .pointers.pointer3 {
top: -5px;
right: -5px;
}
#selector .pointers.pointer4 {
bottom: -5px;
right: -5px;
}
#selector .pointers.pointer-north {
top: -5px;
left: calc(50% - 5px);
}
#selector .pointers.pointer-south {
bottom: -5px;
left: calc(50% - 5px);
}
#selector .pointers.pointer-east {
right: -5px;
top: calc(50% - 5px);
}
#selector .pointers.pointer-west {
left: -5px;
top: calc(50% - 5px);
}
#selector .pointer-rotate {
border: 2px solid rgba(0, 0, 0, 0.9);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 50%;
cursor: rotate;
}
#selector .pointer9 {
bottom: -70px;
left: calc(50% - 11px);
display: inline-block;
width: 20px;
height: 20px;
background-color: #fff;
pointer-events: all;
position: absolute;
}
#selector .rotate-line {
border-left: 1px dashed #5f5f5f;
height: 40px;
position: absolute;
top: -40px;
left: calc(50% - 1px);
width: 1px;
}
HTML:
<div id="container">
<div id="rectangle">
</div>
<div id="selector">
<div class="pointers pointer1">
<div class="point"></div>
</div>
<div class="pointers pointer2">
<div class="point">
</div>
</div>
<div class="pointers pointer3">
<div class="point">
</div>
</div>
<div class="pointers pointer4">
<div class="point">
</div>
</div>
<div class="pointers pointer-north">
<div class="point">
</div>
</div>
<div class="pointers pointer-east">
<div class="point">
</div>
</div>
<div class="pointers pointer-south">
<div class="point">
</div>
</div>
<div class="pointers pointer-west">
<div class="point">
</div>
</div>
<span class="topline lines-resize" />
<span class="rightline lines-resize" />
<span class="botline lines-resize" />
<span class="leftline lines-resize" />
<div class="pointer-rotate pointer9" />
<div class="rotate-line" />
</div>
</div>
Скрипт для тестирования:
https://jsfiddle.net/ub70028c/46/
Я читал о других людях, пытающихся сделать то же самое без результатов...
Спасибо!
Ответы
Ответ 1
Я проверил ваш код и аналогичную библиотеку для изменения resizable
и rotatable
и я выясню вашу проблему.
Во-первых, проверка аналогичной библиотеки:
Посмотрите эту скрипту, которую я создал jquery.freetrans.js.
Если вы проверите на <div class="shape">
, вы можете увидеть
transform: matrix(1, 0, 0, 1, 0, 0);
Если вы повернете его, transform
изменится, как показано ниже:
transform: matrix(0.997373, -0.0724379, 0.0724379, 0.997373, 0, 0);
В аналогичном случае ваш код использует transform
которое сначала не transform
и после поворота оно выглядит следующим образом:
transform: rotate(-2.49576deg);
Если вы можете использовать matrix
вместо rotate
в transform
, ваш код будет работать правильно. Если вы не можете его изменить, вы можете использовать подобную библиотеку, например jquery.freetrans.js
которые работают правильно, jquery.freetrans.js
и jquery.freetrans.js
размер.
Ответ 2
https://github.com/taye/interact.js/issues/569
https://github.com/taye/interact.js/issues/499
https://github.com/taye/interact.js/issues/394
Боюсь, вы выбрали библиотеку, автор которой четко заявил о своем намерении
Там нет встроенного способа. Как я упоминал в #137
я не очень заинтересован в обработке масштабированных или вращающихся элементов
Поэтому вопрос, который вы должны задать себе:
Должен ли я найти обходное решение для работы этой библиотеки или, возможно, выбрать другую библиотеку?
Обновление-1: 28-апр-2018
Если вы хотите сделать это в холсте вместо обычных элементов, то я нашел fabric.js хорошим вариантом
Ответ 3
мы очень близки к завершению работы после пяти дней... нам нужно оптимизировать все математические вычисления... но да, это то, что я искал:
Извините, но у нас нет готового кода... Я опубликую все с комментариями для других людей.
Комментарии: Для математика эта задача не очень сложна, потому что все углы прямоугольные (90º). Я попытаюсь сделать PR для Interact.js, даже для других библиотек, чтобы реализовать эту функцию по умолчанию. Надеюсь, эта работа поможет другим разработчикам;)