我正在制作一个个人资料图片裁剪编辑器,它允许在一个区域内拖动、缩放和旋转图像。
通过捕获区域的mousedown和mousemove事件,并计算光标在区域内的起始和停止x/y坐标来拖动图像,以获取光标移动的距离。然后将该值添加到或从图像的当前内联样式transform translate(x,y)值中(取决于方向)。
问题在于当图像旋转时,其translate(x y)值不再相对于区域的x/y坐标对应。
我找到了一些关于如何使用旋转角度的弧度和cos和sin计算旋转正方形或矩形的四个角的x/y坐标的示例。但由于几何不是我的强项,我不知道这些计算如何适用于图像的translate(x, y)值。
这是一个演示当前图像裁剪器的代码片段: https://codepen.io/ClubAce/pen/maNJNZ 无论图像如何旋转,都应该沿着区域的x/y轴拖动图像。
我真的希望有人能帮助我找出如何修改脚本以产生期望的拖动行为。
谢谢。
通过捕获区域的mousedown和mousemove事件,并计算光标在区域内的起始和停止x/y坐标来拖动图像,以获取光标移动的距离。然后将该值添加到或从图像的当前内联样式transform translate(x,y)值中(取决于方向)。
var dragArea = document.getElementById('drag-area');
var photoImg = document.getElementById('photo');
var cropCircle = document.getElementById('crop-circle');
var cloneContainer = document.getElementById('clone-container');
var resetAll = document.getElementById('reset-all');
var scaleSlider = document.getElementById('scale-slider');
var scaleInput = document.getElementById('scale-input');
var scaleReset = document.getElementById('scale-reset');
var rotateSlider = document.getElementById('rotate-slider');
var rotateInput = document.getElementById('rotate-input');
var rotateReset = document.getElementById('rotate-reset');
var area = {}, photo = {
translate: {
x: 0, y: 0
},
transformOrigin: {
x: 0, y: 0
}
};
photoImg.src = photoSrc();
photoImg.style.top = cropCircle.offsetTop+'px';
photoImg.style.left = cropCircle.offsetLeft+'px';
photoImg.style.transform = 'scale(1) rotate(0deg) translate(0px, 0px)';
photoImg.style.transformOrigin = '0px 0px';
photoImg.onload = function() {
if (this.naturalWidth < this.naturalHeight) {
this.width = cropCircle.clientWidth;
} else if (this.naturalWidth > this.naturalHeight) {
this.height = cropCircle.clientHeight;
} else {
this.height = cropCircle.clientHeight;
this.width = cropCircle.clientWidth;
}
}
dragArea.onmouseenter = function() {
this.onmousedown = function(e) {
var transform = photoImg.style.transform;
var photoStyle = window.getComputedStyle(photoImg);
var photoMatrix = new DOMMatrix(photoStyle.transform);
var transformOrigin = photoImg.style.transformOrigin.replace(/px/g, '').split(' ');
photo = {
translate: {},
x: photoMatrix.m41,
y: photoMatrix.m42,
scale: Number(/scale\((-?\d+(?:\.\d*)?)\)/.exec(transform)[1]),
rotate: Number(/rotate\((-?\d+(?:\.\d*)?)deg\)/.exec(transform)[1]),
transformOrigin: {
x: Number(transformOrigin[0]),
y: Number(transformOrigin[1])
}
}
area = {
start: {
x: e.offsetX + (e.target == cropCircle ? cropCircle.offsetLeft : 0),
y: e.offsetY + (e.target == cropCircle ? cropCircle.offsetTop : 0)
},
distance: {
x: 0,
y: 0
}
};
this.onmousemove = function(e) {
area.end = {
x: e.offsetX + (e.target == cropCircle ? cropCircle.offsetLeft : 0),
y: e.offsetY + (e.target == cropCircle ? cropCircle.offsetTop : 0)
};
if (area.end.x > area.start.x) {
area.distance.x = {
type: 'positive', // right
total: area.end.x - area.start.x
}
} else {
area.distance.x = {
type: 'negative', // left
total: area.start.x - area.end.x
}
}
if (area.end.y > area.start.y) {
area.distance.y = {
type: 'positive', // down
total: area.end.y - area.start.y
}
} else {
area.distance.y = {
type: 'negative', // up
total: area.start.y - area.end.y
}
}
if (area.distance.x.type == 'positive') {
photo.translate.x = photo.x + area.distance.x.total;
} else {
photo.translate.x = photo.x - area.distance.x.total;
}
if (area.distance.y.type == 'positive') {
photo.translate.y = photo.y + area.distance.y.total;
} else {
photo.translate.y = photo.y - area.distance.y.total;
}
photoTransform({x: photo.translate.x, y: photo.translate.y});
}
}
}
dragArea.onmouseleave = function() {
this.onmousemove = function(e) {
e.preventDefault();
}
}
dragArea.onmouseup = function() {
this.onmousemove = function(e) {
e.preventDefault();
}
}
resetAll.onclick = function() {
scaleSlider.value = scaleReset.value;
scaleInput.value = scaleReset.value;
rotateSlider.value = rotateReset.value;
rotateInput.value = rotateReset.value;
photo = {
translate: {
x: 0, y: 0
},
transformOrigin: {
x: 0, y: 0
}
};
photoTransform({scale: 1, rotate: '0', x: '0', y: '0'});
}
scaleSlider.oninput = function() {
var value = this.value;
scaleInput.value = value;
photoTransform({scale: value});
}
scaleInput.oninput = function() {
var value = this.value;
this.value = value.length ? value : scaleReset.value;
scaleSlider.value = this.value;
photoTransform({scale: this.value});
}
scaleInput.onkeydown = function(e) {
if (e.keyCode == 13) this.blur();
}
scaleInput.onblur = function() {
var value = this.value;
this.value = value.length ? value : scaleReset.value;
scaleSlider.value = this.value;
photoTransform({scale: this.value});
}
scaleReset.onclick = function() {
scaleSlider.value = this.value;
scaleInput.value = this.value;
photoTransform({scale: this.value});
}
rotateSlider.oninput = function() {
var value = this.value;
rotateInput.value = value;
photoTransform({rotate: value});
}
rotateInput.oninput = function() {
var value = this.value;
this.value = value.length ? value : rotateReset.value;
rotateSlider.value = this.value;
photoTransform({rotate: this.value});
}
rotateInput.onkeydown = function(e) {
if (e.keyCode == 13) this.blur();
}
rotateInput.onblur = function() {
var value = this.value;
this.value = value.length ? value : rotateReset.value;
rotateSlider.value = this.value;
photoTransform({rotate: this.value});
}
rotateReset.onclick = function() {
rotateSlider.value = this.value;
rotateInput.value = this.value;
photoTransform({rotate: this.value});
}
function photoTransform(property) {
property = property || {};
var transform = photoImg.style.transform;
var axisX = property.axisX || photo.transformOrigin.x || (cropCircle.getBoundingClientRect().width / 2);
var axisY = property.axisY || photo.transformOrigin.y || (cropCircle.getBoundingClientRect().height / 2);
var scale = property.scale || photo.scale || Number(/scale\((-?\d+(?:\.\d*)?)\)/.exec(transform)[1]);
var rotate = property.rotate || photo.rotate || Number(/rotate\((-?\d+(?:\.\d*)?)deg\)/.exec(transform)[1]);
var translate = /translate\((-?\d+(?:\.\d*)?)px, (-?\d+(?:\.\d*)?)px\)/.exec(transform);
var translateX = (property.x || photo.translate.x || Number(translate[1])) / scale;
var translateY = (property.y || photo.translate.y || Number(translate[2])) / scale;
photoImg.style.transformOrigin = axisX+'px '+axisY+'px';
photoImg.style.transform = 'scale('+scale+') rotate('+rotate+'deg) translate('+translateX+'px, '+translateY+'px)';
photo.transformOrigin = {
x: axisX,
y: axisY
}
photo.scale = scale;
photo.rotate = rotate;
}
function photoSrc() {
return 'data:image/jpeg;base64,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AENybkNib29sAAAAAABDbnRDYm9vbAAAAAAATGJsc2Jvb2wAAAAAAE5ndHZib29sAAAAAABFbWxEYm9vbAAAAAAASW50cmJvb2wAAAAAAEJja2dPYmpjAAAAAQAAAAAAAFJHQkMAAAADAAAAAFJkICBkb3ViQG/gAAAAAAAAAAAAR3JuIGRvdWJAb+AAAAAAAAAAAABCbCAgZG91YkBv4AAAAAAAAAAAAEJyZFRVbnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAAAAAAQY3JvcFdoZW5QcmludGluZ2Jvb2wAAAAADmNyb3BSZWN0Qm90dG9tbG9uZwAAAAAAAAAMY3JvcFJlY3RMZWZ0bG9uZwAAAAAAAAANY3JvcFJlY3RSaWdodGxvbmcAAAAAAAAAC2Nyb3BSZWN0VG9wbG9uZwAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAHjhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAADhCSU0EAgAAAAAAAgAAOEJJTQQwAAAAAAABAQA4QklNBC0AAAAAAAIAADhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAA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NzIyLWNhNDkzZjBjMzE5MyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2MjUyN2FhMS1jMjhmLTQ3ZjEtYWRiMi00MWZlYThhY2JkMGQiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0iRUFBQTAyMEJDQ0NGNDZGNzdCQ0NCNUJEQjVFRkRFREEiIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9IiIgeG1wOkNyZWF0ZURhdGU9IjIwMTktMDEtMThUMTc6NTY6MzMrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE5LTAxLTE4VDE3OjU4OjE2KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE5LTAxLTE4VDE3OjU4OjE2KzAxOjAwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MjQ1YjRhOGYtMmYzNC00NzVjLWEzYTMtMGJjMmI2ZjAwYWEzIiBzdEV2dDp3aGVuPSIyMDE5LTAxLTE4VDE3OjU4OjE2KzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NjI1MjdhYTEtYzI4Zi00N2YxLWFkYjItNDFmZWE4YWNiZDBkIiBzdEV2dDp3aGVuPSIyMDE5LTAxLTE4VDE3OjU4OjE2KzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/uAA5BZG9iZQBkgAAAAAH/2wCEACAhITMkM1EwMFFCLy8vQiccHBwcJyIXFxcXFyIRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBIjMzNCY0IhgYIhQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAMgAyAMBIgACEQEDEQH/3QAEAA3/xAEbAAADAQEBAQEBAQEBAAAAAAABAAIDBAUGBwgJCgsBAQEBAQEBAQEBAQEBAAAAAAABAgMEBQYHCAkKCxAAAgIBAwIDBAcGAwMGAgE1AQACEQMhEjEEQVEiE2FxMoGRsUKhBdHBFPBSI3IzYuGC8UM0kqKyFdJTJHPCYwaDk+Lyo0RUZCU1RRYmdDZVZbOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYRAAICAAUBBgYBAwEDBQMGLwABEQIhAzFBElFhcYGRIhMy8KGxBMHR4fFCUiNichSSM4JDJKKyNFNEY3PC0oOTo1Ti8gUVJQYWJjVkRVU2dGWzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdob/2gAMAwEAAhEDEQA/AIVVfpHyxVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUD//QhVV+kfLFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQP/9GFVX6R8sVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVA//0oVVfpHyxVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUD//ThVV+kfLFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQP/9SFVX6R8sVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVA//1YVVfpHyxVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUD//WhVV+kfLFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQP/9eFVX6R8sVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVA//0IVVfpHyxVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUD//RhVV+kfLFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQP/9KFVX6R8sVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVAVVUBVVQFVVA//04V8JX6R8s91XwlQPdV8JUD3VfCVA91XwlQPdV8JUD3VfCVA91XwlQPdV8JUD3VfCVA91XwlQPdV8JUD3VfCVA//2Q==';
}
body {
background-color: #eff1f3;
}
#profile-picture {
width: 370px;
height: 330px;
margin: auto;
}
#profile-picture * {
user-select: none;
}
#drag-area {
width: 100%;
height: 100%;
cursor: move;
cursor: grab;
display: block;
overflow: hidden;
position: relative;
background-color: #000;
background-repeat: repeat;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJElEQVQoU2M8e/asMQMaMDY2PosuxjgUFKI7GsTH5m7GIaAQAA4fIQ1WOLcWAAAAAElFTkSuQmCC');
}
#drag-area:active {
cursor: grabbing;
}
#clone-container {
width: 0px;
height: 0px;
display: block;
overflow: hidden;
position: absolute;
}
#photo, #photo-clone {
display: block;
min-width: 230px;
min-height: 230px;
position: absolute;
pointer-events: none;
}
img[src=''] {
visibility: hidden;
}
#crop-circle {
width: 230px;
height: 230px;
margin: 50px auto;
overflow: hidden;
position: relative;
border-radius: 50%;
box-shadow: 0 0 0 2px #fff, 0 0 0 100vw rgba(0,0,0,0.5);
}
#circle-thirds {
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
pointer-events: none;
border-radius: 100%;
}
#circle-thirds * {
z-index: 1;
position: absolute;
background-color: rgba(226,226,226,0.5);
}
#circle-thirds .top-horizontal {
width: 100%;
height: 1px;
top: 33.33333%;
}
#circle-thirds .bottom-horizontal {
width: 100%;
height: 1px;
top: 66.66666%;
}
#circle-thirds .left-vertical {
height: 100%;
width: 1px;
left: 33.33333%;
}
#circle-thirds .right-vertical {
height: 100%;
width: 1px;
left: 66.66666%;
}
.photo-options {
width: 100%;
display: block;
position: relative;
padding-top: 15px;
}
.option-buttons {
width: 100%;
display: flex;
position: relative;
padding-bottom: 10px;
justify-content: space-between;
}
.option-buttons button {
width: 100%;
}
.option-buttons button + button {
margin-left: 10px;
}
.photo-options fieldset {
margin: 0px;
}
.photo-options fieldset + fieldset {
margin-top: 10px;
}
.option-slider {
display: flex;
position: relative;
}
.option-slider input[type=range] {
width: 50%;
flex-shrink: 0;
}
.option-slider input[type=number] {
width: 20%;
margin: 0 10px;
}
.option-slider button {
width: 30%;
}
<div id="profile-picture">
<div id="drag-area">
<div id="clone-container"></div>
<img id="photo" src="">
<div id="crop-circle">
<div id="circle-thirds">
<span class="top-horizontal"></span>
<span class="bottom-horizontal"></span>
<span class="left-vertical"></span>
<span class="right-vertical"></span>
</div>
</div>
</div>
<div class="photo-options">
<div class="option-buttons">
<button id="reset-all">Reset everything</button>
</div>
<fieldset>
<legend>Scale</legend>
<div class="option-slider">
<input type="range" id="scale-slider" min="1" max="3" step="0.01" value="1">
<input type="number" id="scale-input" min="1" max="3" step="0.01" value="1">
<button id="scale-reset" value="1">Reset</button>
</div>
</fieldset>
<fieldset>
<legend>Rotate</legend>
<div class="option-slider">
<input type="range" id="rotate-slider" min="-180" max="180" step="1" value="0">
<input type="number" id="rotate-input" min="-180" max="180" step="1" value="0">
<button id="rotate-reset" value="0">Reset</button>
</div>
</fieldset>
</div>
</div>
我找到了一些关于如何使用旋转角度的弧度和cos和sin计算旋转正方形或矩形的四个角的x/y坐标的示例。但由于几何不是我的强项,我不知道这些计算如何适用于图像的translate(x, y)值。
这是一个演示当前图像裁剪器的代码片段: https://codepen.io/ClubAce/pen/maNJNZ 无论图像如何旋转,都应该沿着区域的x/y轴拖动图像。
我真的希望有人能帮助我找出如何修改脚本以产生期望的拖动行为。
谢谢。