我想在paperjs中拖动并调整矩形大小,我还想旋转矩形并调整其大小,同时保持其相对尺寸。
理想情况下,我想通过拖动其中一个角(锚点)来鼠标移动。什么数学或特征有助于在paperjs中做到这一点?
我已经尝试过使用缩放和修改角落,但它并没有像我想要的那样工作。有人能指出我的解决方案吗?
提前致谢。
答案 0 :(得分:1)
这是一个简单的解决方案,可以帮助您入门。它不能处理旋转,因为我不确定你如何设想UI工作,但是通过修改边界框来调整矩形的大小,你应该可以毫无问题地旋转它。
我决定构建自己的用户界面并继续进行,让您的示例更加复杂,尽可能多地解决您的问题,而无需更多信息。这是新草图:
用户界面是
Path
的每个分段点所在的位置。
代码的要点:
使用矩形的边界进行缩放。就纸张而言,Path.Rectangle
不是矩形。连接四个分段点的是四条曲线(恰好是直线)。当您需要使用矩形来获取其中心,左上角等时,您需要Rectangle
。使用矩形的边界(Path.Rectangle.bounds
)缩放可见矩形。该代码用一个额外的浅水矩形图示了边界,使其可见(旋转时最容易看到)。
onMouseDown()
设置onMouseDrag()
的状态,并设置每个州所需的数据,例如,为调整大小保存比例基础。
onMouseDrag()
实现移动,调整大小和旋转。
tool.onMouseDrag = function(e) {
if (rect.data.state === 'moving') {
rect.position = rect.position + e.point - e.lastPoint;
adjustRect(rect);
} else if (rect.data.state === 'resizing') {
// scale by distance from down point
var bounds = rect.data.bounds;
var scale = e.point.subtract(bounds.center).length /
rect.data.scaleBase.length;
var tlVec = bounds.topLeft.subtract(bounds.center).multiply(scale);
var brVec = bounds.bottomRight.subtract(bounds.center).multiply(scale);
var newBounds = new Rectangle(tlVec + bounds.center, brVec + bounds.center);
rect.bounds = newBounds;
adjustRect(rect);
} else if (rect.data.state === 'rotating') {
// rotate by difference of angles, relative to center, of
// the last two points.
var center = rect.bounds.center;
var baseVec = center - e.lastPoint;
var nowVec = center - e.point;
var angle = nowVec.angle - baseVec.angle;
rect.rotate(angle);
adjustRect(rect);
}
}
移动非常简单 - 只需计算事件中当前和最后一个点之间的差异,然后将矩形的位置改变那么多。
调整大小并不明显。策略是根据mousedown点和矩形中心之间的原始距离(scaleBase.length
)调整x和y边界。请注意,虽然paper-full.js允许使用运算符(" +"," - "," *"," /&#34 ;)使用点数,我使用原始的subtract()
和multiply()
方法几次 - 我发现用这种方式链接计算是很自然的。
旋转使用非常好的纸张概念,即点也定义了矢量,矢量具有角度。它只是注意到事件lastPoint
和point
之间相对于矩形中心的角度差异,并按该差异旋转矩形。
moveCircles()
和adjustRect()
只是用于更新角圆和浅绿色矩形的簿记功能。
答案 1 :(得分:0)
考虑以下问题。我刚刚根据大量示例完成了弄清楚这一点的过程。
我的目标:
Paper.js 代码
var hitOptions = {
segments: true,
stroke: true,
fill: true,
tolerance: 5
};
function drawHex(w, c, n){
var h = new Path.RegularPolygon(new Point(100, 100), 6, w / 2);
h.selectedColor = 'transparent';
c = c != undefined ? c : "#e9e9ff";
n = n != undefined ? n : "Hexayurt";
h.name = n;
h.fillColor = c;
h.data.highlight = new Group({
children: [makeBounds(h), makeCorners(h), makeTitle(h)],
strokeColor: '#a2a2ff',
visible: false
});
return h;
}
function makeCorners(o, s){
s = s != undefined ? s : 5;
var g = new Group();
var corners = [
o.bounds.topLeft,
o.bounds.topRight,
o.bounds.bottomLeft,
o.bounds.bottomRight
];
corners.forEach(function(corner, i) {
var h = new Path.Rectangle({
center: corner,
size: s
});
g.addChild(h);
});
return g;
}
function makeBounds(o){
return new Path.Rectangle({
rectangle: o.bounds
});
}
function makeTitle(o, n, c){
c = c != undefined ? c : 'black';
var t = new PointText({
fillColor: c,
content: n != undefined ? n : o.name,
strokeWidth: 0
});
t.bounds.center = o.bounds.center;
return t;
}
function selectItem(o){
console.log("Select Item", o.name);
o.selected = true;
o.data.highlight.visible = true;
o.data.highlight.bringToFront();
}
function clearSelected(){
project.selectedItems.forEach(function(o, i){
console.log("Unselect Item", o.name);
o.data.highlight.visible = false;
});
project.activeLayer.selected = false;
}
function moveBoxes(o){
var boxes = o.data.highlight.children[1].children;
boxes[0].position = o.bounds.topLeft;
boxes[1].position = o.bounds.topRight;
boxes[2].position = o.bounds.bottomLeft;
boxes[3].position = o.bounds.bottomRight;
}
function moveTitle(o){
var t = o.data.highlight.children[2];
t.bounds.center = o.bounds.center;
}
function adjustBounds(o){
if(o.data.state == "moving"){
o.data.highlight.position = o.position;
} else {
o.data.highlight.children[0].bounds = o.bounds;
moveBoxes(o);
}
}
var hex1 = drawHex(200);
console.log(hex1.data, hex1.data.highlight);
var segment, path;
var movePath = false;
var tool = new Tool();
tool.minDistance = 10;
tool.onMouseDown = function(event) {
segment = path = null;
var hitResult = project.hitTest(event.point, hitOptions);
if (!hitResult){
clearSelected();
return;
}
if(hitResult && hitResult.type == "fill"){
path = hitResult.item;
}
if (hitResult && hitResult.type == "segment") {
path = project.selectedItems[0];
segment = hitResult.segment;
if(event.modifiers.control){
path.data.state = "rotating";
} else {
path.data.state = "resizing";
path.data.bounds = path.bounds.clone();
path.data.scaleBase = event.point - path.bounds.center;
}
console.log(path.data);
}
movePath = hitResult.type == 'fill';
if (movePath){
project.activeLayer.addChild(hitResult.item);
path.data.state = "moving";
selectItem(path);
console.log("Init Event", path.data.state);
}
};
tool.onMouseDrag = function(event) {
console.log(path, segment, path.data.state);
if (segment && path.data.state == "resizing") {
var bounds = path.data.bounds;
var scale = event.point.subtract(bounds.center).length / path.data.scaleBase.length;
var tlVec = bounds.topLeft.subtract(bounds.center).multiply(scale);
var brVec = bounds.bottomRight.subtract(bounds.center).multiply(scale);
var newBounds = new Rectangle(tlVec + bounds.center, brVec + bounds.center);
path.bounds = newBounds;
adjustBounds(path);
} else if(segment && path.data.state == "rotating") {
var center = path.bounds.center;
var baseVec = center - event.lastPoint;
var nowVec = center - event.point;
var angle = nowVec.angle - baseVec.angle;
if(angle < 0){
path.rotate(-45);
} else {
path.rotate(45);
}
adjustBounds(path);
} else if (path && path.data.state == "moving") {
path.position += event.delta;
adjustBounds(path);
}
};
这利用 .data
将边界框、手柄和标题的引用存储为一个组。这样,他们总是在那里,他们可以visible
对或错。这样可以根据需要轻松显示和隐藏它们。
drawHex( width , color, name )
#e9e9ff
互动
这是我第一次通过它,我可能会清理很多代码。例如,我可以专门将事件绑定到句柄,而不是查看更多全局事件。