Skip to content

Commit

Permalink
Merge pull request #294 from caohongz/feat--add-fixedScaleCenter-mode…
Browse files Browse the repository at this point in the history
…-in-rect

Feature:  add fixed scale center mode in rect
  • Loading branch information
hughfenghen authored Oct 11, 2024
2 parents bb60f31 + b534d2c commit cc92647
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/long-monkeys-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@webav/av-canvas': patch
'@webav/av-cliper': patch
---

Feature: add fixedScaleCenter mode in rect
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ exports[`rotate sprite > rotate sprite 2`] = `2.819842099193151`;
exports[`scale sprite > drag rb(bottom right) ctrl 1`] = `
O {
"fixedAspectRatio": false,
"fixedScaleCenter": false,
"master": null,
"on": [Function],
}
Expand Down
60 changes: 60 additions & 0 deletions packages/av-canvas/src/sprites/__tests__/sprite-op.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,66 @@ describe('scale sprite', () => {
expect(Math.round(vs.rect.y)).toBe(100);
clear();
});

test('drag left ctrl with fixedScaleCenter', async () => {
const vs = new MockVisibleSprite();
await sprMng.addSprite(vs);
sprMng.activeSprite = vs;
vs.rect.w = 100;
vs.rect.h = 100;
vs.rect.fixedScaleCenter = true;

// 激活 sprite
const clear = draggabelSprite(cvsEl, sprMng, document.body);
cvsEl.dispatchEvent(crtMSEvt4Offset('mousedown', 0, 0));
expect(sprMng.activeSprite).toBe(vs);

window.dispatchEvent(new MouseEvent('mouseup'));
// 命中 left ctrl
cvsEl.dispatchEvent(crtMSEvt4Offset('mousedown', 0, 50));
window.dispatchEvent(
new MouseEvent('mousemove', {
clientX: 10,
clientY: 0,
}),
);
// 拖拽 left ctrl 缩放 rect 的宽度和高度
expect(vs.rect.x).toBe(10);
expect(vs.rect.w).toBe(80);
expect(vs.rect.h).toBe(100);

clear();
});

test('drag bottom ctrl with fixedScaleCenter', async () => {
const vs = new MockVisibleSprite();
await sprMng.addSprite(vs);
sprMng.activeSprite = vs;
vs.rect.w = 100;
vs.rect.h = 100;
vs.rect.fixedScaleCenter = true;

// 激活 sprite
const clear = draggabelSprite(cvsEl, sprMng, document.body);
cvsEl.dispatchEvent(crtMSEvt4Offset('mousedown', 0, 0));
expect(sprMng.activeSprite).toBe(vs);

window.dispatchEvent(new MouseEvent('mouseup'));
// 命中 bottom ctrl
cvsEl.dispatchEvent(crtMSEvt4Offset('mousedown', 50, 100));
window.dispatchEvent(
new MouseEvent('mousemove', {
clientX: 0,
clientY: -10,
}),
);
// 拖拽 bottom ctrl 缩放 rect 的宽度和高度
expect(vs.rect.y).toBe(10);
expect(vs.rect.w).toBe(100);
expect(vs.rect.h).toBe(80);

clear();
});
});

describe('rotate sprite', () => {
Expand Down
35 changes: 22 additions & 13 deletions packages/av-canvas/src/sprites/sprite-op.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ function scaleRect({
const minSize = 10;
let newW = w;
let newH = h;

// 中心点缩放时,宽高增量是原来的两倍
let newIncW = startRect.fixedScaleCenter ? incW * 2 : incW;
let newIncH = startRect.fixedScaleCenter ? incH * 2 : incH;
// 最小长度缩放限定
let newIncS = incS;
// 起始对角线长度
Expand All @@ -190,40 +192,47 @@ function scaleRect({
// 非等比例缩放时,变化的增量范围 由原宽高跟 minSize 的差值决定
// 非等比例缩放时,根据ctrlKey的不同,固定宽高中的一个,另一个根据增量计算,并考虑最小值限定
case 'l':
newW = Math.max(w + incW, minSize);
newW = Math.max(w + newIncW, minSize);
newIncS = Math.min(incS, w - minSize);
break;
case 'r':
newW = Math.max(w + incW, minSize);
newW = Math.max(w + newIncW, minSize);
newIncS = Math.max(incS, minSize - w);
break;
case 'b':
newH = Math.max(h + incH, minSize);
newH = Math.max(h + newIncH, minSize);
newIncS = Math.min(incS, h - minSize);
break;
case 't':
newH = Math.max(h + incH, minSize);
newH = Math.max(h + newIncH, minSize);
newIncS = Math.max(incS, minSize - h);
break;
// 等比例缩放时,变化(对角线长度)的增量范围由原对角线长度跟 minSize 对角线的差值决定
// 等比例缩放时,某一边达到最小值时保持宽高比例不变
case 'lt':
case 'lb':
newW = Math.max(w + incW, minSize);
newH = newW === minSize ? (h / w) * newW : h + incH;
newW = Math.max(w + newIncW, minSize);
newH = newW === minSize ? (h / w) * newW : h + newIncH;
newIncS = Math.min(incS, startS - minS);
break;
case 'rt':
case 'rb':
newW = Math.max(w + incW, minSize);
newH = newW === minSize ? (h / w) * newW : h + incH;
newW = Math.max(w + newIncW, minSize);
newH = newW === minSize ? (h / w) * newW : h + newIncH;
newIncS = Math.max(incS, minS - startS);
break;
}
const newCenterX = (newIncS / 2) * Math.cos(rotateAngle) + x + w / 2;
const newCenterY = (newIncS / 2) * Math.sin(rotateAngle) + y + h / 2;
const newX = newCenterX - newW / 2;
const newY = newCenterY - newH / 2;
let newX = x;
let newY = y;
if (startRect.fixedScaleCenter) {
newX = x + w / 2 - newW / 2;
newY = y + h / 2 - newH / 2;
} else {
const newCenterX = (newIncS / 2) * Math.cos(rotateAngle) + x + w / 2;
const newCenterY = (newIncS / 2) * Math.sin(rotateAngle) + y + h / 2;
newX = newCenterX - newW / 2;
newY = newCenterY - newH / 2;
}

updateRectWithSafeMargin(sprRect, cvsEl, {
x: newX,
Expand Down
8 changes: 8 additions & 0 deletions packages/av-cliper/src/sprite/rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ export class Rect implements IRectBaseProps {
*/
fixedAspectRatio = false;

/**
* 是否固定中心点进行缩放
* 值为 true 时,{@link Rect.ctrls} 将固定中心点不变进行缩放
* 值为 false 时,{@link Rect.ctrls} 将固定对角点不变进行缩放
*/
fixedScaleCenter = false;

/**
* 根据坐标、宽高计算出来的矩形控制点
*
Expand Down Expand Up @@ -223,6 +230,7 @@ export class Rect implements IRectBaseProps {
const rect = new Rect(x, y, w, h, master);
rect.angle = this.angle;
rect.fixedAspectRatio = this.fixedAspectRatio;
rect.fixedScaleCenter = this.fixedScaleCenter;
return rect;
}

Expand Down

0 comments on commit cc92647

Please sign in to comment.