Skip to content

Commit

Permalink
Merge pull request #2017 from microsoft/u/juliaroldi/image-bugs-part-2
Browse files Browse the repository at this point in the history
Refactor rotate handle calculation
  • Loading branch information
juliaroldi authored Aug 10, 2023
2 parents a1a7b81 + 349d30a commit 69005d6
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,14 @@ export default class ImageEdit implements EditorPlugin {
const viewport = this.editor?.getVisibleViewport();
const isSmall = isASmallImage(targetWidth, targetHeight);
if (rotateHandle && rotateCenter && viewport) {
updateRotateHandleState(viewport, rotateCenter, rotateHandle, isSmall);
updateRotateHandleState(
viewport,
angleRad,
wrapper,
rotateCenter,
rotateHandle,
isSmall
);
}

updateSideHandlesVisibility(resizeHandles, isSmall);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export const Rotator: DragAndDropHandler<DragAndDropContext, RotateInfo> = {
*/
export function updateRotateHandleState(
editorRect: Rect,
angleRad: number,
wrapper: HTMLElement,
rotateCenter: HTMLElement,
rotateHandle: HTMLElement,
isSmallImage: boolean
Expand All @@ -62,21 +64,35 @@ export function updateRotateHandleState(
rotateCenter.style.display = '';
rotateHandle.style.display = '';
const rotateHandleRect = rotateHandle.getBoundingClientRect();
const wrapperRect = wrapper.getBoundingClientRect();

if (rotateHandleRect) {
const top = rotateHandleRect.top - editorRect.top;
const left = rotateHandleRect.left - editorRect.left;
const right = rotateHandleRect.right - editorRect.right;
const bottom = rotateHandleRect.bottom - editorRect.bottom;
if (rotateHandleRect && wrapperRect) {
let adjustedDistance = Number.MAX_SAFE_INTEGER;
if (top <= 0) {
const angle = angleRad * DEG_PER_RAD;

if (angle < 45 && angle > -45 && wrapperRect.top - editorRect.top < ROTATE_GAP) {
const top = rotateHandleRect.top - editorRect.top;
adjustedDistance = top;
} else if (left <= 0) {
} else if (
angle <= -80 &&
angle >= -100 &&
wrapperRect.left - editorRect.left < ROTATE_GAP
) {
const left = rotateHandleRect.left - editorRect.left;
adjustedDistance = left;
} else if (right >= 0) {
adjustedDistance = right;
} else if (bottom >= 0) {
adjustedDistance = bottom;
} else if (
angle >= 80 &&
angle <= 100 &&
editorRect.right - wrapperRect.right < ROTATE_GAP
) {
const right = rotateHandleRect.right - editorRect.right;
adjustedDistance = Math.min(editorRect.right - wrapperRect.right, right);
} else if (
(angle <= -160 || angle >= 160) &&
editorRect.bottom - wrapperRect.bottom < ROTATE_GAP
) {
const bottom = rotateHandleRect.bottom - editorRect.bottom;
adjustedDistance = Math.min(editorRect.bottom - wrapperRect.bottom, bottom);
}

const rotateGap = Math.max(Math.min(ROTATE_GAP, adjustedDistance), 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('ImageEdit | rotate and flip', () => {
});

function runRotateTest(angle: number, editInfo?: ImageEditInfo) {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_ROTATION';
const content = `<img id="${IMG_ID}" src='test'/>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
Expand All @@ -46,7 +46,7 @@ describe('ImageEdit | rotate and flip', () => {
flippedVertical?: boolean,
editInfo?: ImageEditInfo
) {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_FLIP';
const content = `<img id="${IMG_ID}" src='test'/>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
Expand Down Expand Up @@ -212,15 +212,15 @@ describe('ImageEdit | rotate and flip', () => {
});

it('start image editing', () => {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_EDITING';
const content = `<img id="${IMG_ID}" src='test'/>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
editor.focus();
editor.select(image);
plugin.setEditingImage(image, ImageEditOperation.Resize);
expect(editor.getContent()).toBe(
'<span style="vertical-align: bottom; font-size: 24px;"><img id="IMAGE_ID" src="test"></span>'
'<span style="vertical-align: bottom; font-size: 24px;"><img id="IMAGE_ID_EDITING" src="test"></span>'
);
});
});
Expand Down Expand Up @@ -271,7 +271,7 @@ describe('ImageEdit | plugin events | quitting', () => {
};

it('image selection quit editing', () => {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_QUIT';
const SPAN_ID = 'SPAN_ID';
const content = `<img id="${IMG_ID}" src='test'/><span id="${SPAN_ID}" ></span>`;
editor.setContent(content);
Expand All @@ -286,7 +286,7 @@ describe('ImageEdit | plugin events | quitting', () => {
});

it('mousedown quit editing', () => {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_MOUSE';
const SPAN_ID = 'SPAN_ID';
const content = `<img id="${IMG_ID}" src='test'/><span id="${SPAN_ID}" ></span>`;
editor.setContent(content);
Expand Down Expand Up @@ -314,7 +314,7 @@ describe('ImageEdit | plugin events | quitting', () => {

describe('ImageEdit | wrapper', () => {
let editor: IEditor;
const TEST_ID = 'imageEditTest';
const TEST_ID = 'imageEditTestWrapper';
let plugin: ImageEdit;

beforeEach(() => {
Expand All @@ -331,7 +331,7 @@ describe('ImageEdit | wrapper', () => {
});

it('image selection, remove max-width', () => {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_SELECTION';
const content = `<img id="${IMG_ID}" src='test'/>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
Expand All @@ -345,7 +345,7 @@ describe('ImageEdit | wrapper', () => {
});

it('image selection, cloned image should use style width/height attributes', () => {
const IMG_ID = 'IMAGE_ID';
const IMG_ID = 'IMAGE_ID_SELECTION_2';
const content = `<img id="${IMG_ID}" style="width: 300px; height: 300px" src='test'/>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
Expand Down
93 changes: 80 additions & 13 deletions packages/roosterjs-editor-plugins/test/imageEdit/rotatorTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe('Rotate: rotate only', () => {

describe('updateRotateHandlePosition', () => {
let editor: IEditor;
const TEST_ID = 'imageEditTest';
const TEST_ID = 'imageEditTest_rotateHandlePosition';
let plugin: ImageEdit;
let editorGetVisibleViewport: any;
beforeEach(() => {
Expand All @@ -119,28 +119,35 @@ describe('updateRotateHandlePosition', () => {
rotatePosition: DOMRect,
rotateCenterTop: string,
rotateCenterHeight: string,
rotateHandleTop: string
rotateHandleTop: string,
wrapperPosition: DOMRect,
angle: number
) {
const IMG_ID = 'IMAGE_ID';
const content = `<img id="${IMG_ID}" src='test'/>`;
const IMG_ID = 'IMAGE_ID_ROTATION';
const WRAPPER_ID = 'WRAPPER_ID_ROTATION';
const content = `<span id="${WRAPPER_ID}"><img id="${IMG_ID}" src='test'/></span>`;
editor.setContent(content);
const image = document.getElementById(IMG_ID) as HTMLImageElement;
plugin.setEditingImage(image, ImageEditOperation.Rotate);
const rotate = getRotateHTML(options)[0];
const rotateHTML = createElement(rotate, document);
image.parentElement!.appendChild(rotateHTML!);
const imageParent = image.parentElement;
imageParent!.appendChild(rotateHTML!);
const wrapper = document.getElementById(WRAPPER_ID) as HTMLElement;
const rotateCenter = document.getElementsByClassName('r_rotateC')[0] as HTMLElement;
const rotateHandle = document.getElementsByClassName('r_rotateH')[0] as HTMLElement;
spyOn(rotateHandle, 'getBoundingClientRect').and.returnValues(rotatePosition);
spyOn(wrapper, 'getBoundingClientRect').and.returnValues(wrapperPosition);
const viewport: Rect = {
top: 1,
bottom: 200,
left: 1,
right: 200,
};
editorGetVisibleViewport.and.returnValue(viewport);
const angleRad = angle / DEG_PER_RAD;

updateRotateHandleState(viewport, rotateCenter, rotateHandle, false);
updateRotateHandleState(viewport, angleRad, wrapper, rotateCenter, rotateHandle, false);

expect(rotateCenter.style.top).toBe(rotateCenterTop);
expect(rotateCenter.style.height).toBe(rotateCenterHeight);
Expand All @@ -162,7 +169,19 @@ describe('updateRotateHandlePosition', () => {
},
'-6px',
'0px',
'0px'
'0px',
{
top: 2,
bottom: 3,
left: 2,
right: 5,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
0
);
});

Expand All @@ -181,7 +200,19 @@ describe('updateRotateHandlePosition', () => {
},
'-21px',
'15px',
'-32px'
'-32px',
{
top: 0,
bottom: 20,
left: 3,
right: 5,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
50
);
});

Expand All @@ -190,17 +221,29 @@ describe('updateRotateHandlePosition', () => {
{
top: 2,
bottom: 3,
left: 0,
left: 2,
right: 5,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
'-6px',
'-7px',
'1px',
'0px',
'0px'
{
top: 2,
bottom: 3,
left: 2,
right: 5,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
-90
);
});

Expand All @@ -219,7 +262,19 @@ describe('updateRotateHandlePosition', () => {
},
'-6px',
'0px',
'0px'
'0px',
{
top: 0,
bottom: 190,
left: 3,
right: 190,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
180
);
});

Expand All @@ -238,7 +293,19 @@ describe('updateRotateHandlePosition', () => {
},
'-6px',
'0px',
'0px'
'0px',
{
top: 0,
bottom: 190,
left: 3,
right: 190,
height: 2,
width: 2,
x: 1,
y: 3,
toJSON: () => {},
},
90
);
});
});
Expand Down

0 comments on commit 69005d6

Please sign in to comment.