Rotation support (#1099)

* rotate rectanble with fixed angle

* rotate dashed rectangle with fixed angle

* fix rotate handler rect

* fix canvas size with rotation

* angle in element base

* fix bug in calculating canvas size

* trial only for rectangle

* hitTest for rectangle rotation

* properly resize rotated rectangle

* fix canvas size calculation

* giving up... workaround for now

* **experimental** handler to rotate rectangle

* remove rotation on copy for debugging

* update snapshots

* better rotation handler with atan2

* rotate when drawImage

* add rotation handler

* hitTest for any shapes

* fix hitTest for curved lines

* rotate text element

* rotation locking

* hint messaage for rotating

* show proper handlers on mobile (a workaround, there should be a better way)

* refactor hitTest

* support exporting png

* support exporting svg

* fix rotating curved line

* refactor drawElementFromCanvas with getElementAbsoluteCoords

* fix export png and svg

* adjust resize positions for lines (N, E, S, W)

* do not make handlers big on mobile

* Update src/locales/en.json

Alright!

Co-Authored-By: Lipis <lipiridis@gmail.com>

* do not show rotation/resizing hints on mobile

* proper calculation for N and W positions

* simplify calculation

* use "rotation" as property name for clarification (may increase bundle size)

* update snapshots excluding rotation handle

* refactor with adjustPositionWithRotation

* refactor with adjustXYWithRotation

* forgot to rename rotation

* rename internal function

* initialize element angle on restore

* rotate wysiwyg editor

* fix shift-rotate around 270deg

* improve rotation locking

* refactor adjustXYWithRotation

* avoid rotation degree becomes >=360

* refactor with generateHandler

Co-authored-by: Lipis <lipiridis@gmail.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Daishi Kato 2020-04-02 17:40:26 +09:00 committed by GitHub
parent 3e3ce18755
commit 65be7973be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 664 additions and 108 deletions

View file

@ -263,30 +263,24 @@ function drawElementFromCanvas(
context: CanvasRenderingContext2D,
sceneState: SceneState,
) {
const element = elementWithCanvas.element;
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = ((x1 + x2) / 2 + sceneState.scrollX) * window.devicePixelRatio;
const cy = ((y1 + y2) / 2 + sceneState.scrollY) * window.devicePixelRatio;
context.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
context.translate(
-CANVAS_PADDING / elementWithCanvas.canvasZoom,
-CANVAS_PADDING / elementWithCanvas.canvasZoom,
);
context.translate(cx, cy);
context.rotate(element.angle);
context.drawImage(
elementWithCanvas.canvas!,
Math.floor(
-elementWithCanvas.canvasOffsetX +
(Math.floor(elementWithCanvas.element.x) + sceneState.scrollX) *
window.devicePixelRatio,
),
Math.floor(
-elementWithCanvas.canvasOffsetY +
(Math.floor(elementWithCanvas.element.y) + sceneState.scrollY) *
window.devicePixelRatio,
),
(-(x2 - x1) / 2) * window.devicePixelRatio -
CANVAS_PADDING / elementWithCanvas.canvasZoom,
(-(y2 - y1) / 2) * window.devicePixelRatio -
CANVAS_PADDING / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.width / elementWithCanvas.canvasZoom,
elementWithCanvas.canvas!.height / elementWithCanvas.canvasZoom,
);
context.translate(
CANVAS_PADDING / elementWithCanvas.canvasZoom,
CANVAS_PADDING / elementWithCanvas.canvasZoom,
);
context.rotate(-element.angle);
context.translate(-cx, -cy);
context.scale(window.devicePixelRatio, window.devicePixelRatio);
}
@ -325,11 +319,18 @@ export function renderElement(
if (renderOptimizations) {
drawElementFromCanvas(elementWithCanvas, rc, context, sceneState);
} else {
const offsetX = Math.floor(element.x + sceneState.scrollX);
const offsetY = Math.floor(element.y + sceneState.scrollY);
context.translate(offsetX, offsetY);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x1 + x2) / 2 + sceneState.scrollX;
const cy = (y1 + y2) / 2 + sceneState.scrollY;
const shiftX = (x2 - x1) / 2 - (element.x - x1);
const shiftY = (y2 - y1) / 2 - (element.y - y1);
context.translate(cx, cy);
context.rotate(element.angle);
context.translate(-shiftX, -shiftY);
drawElementOnCanvas(element, rc, context);
context.translate(-offsetX, -offsetY);
context.translate(shiftX, shiftY);
context.rotate(-element.angle);
context.translate(-cx, -cy);
}
break;
}
@ -347,6 +348,10 @@ export function renderElementToSvg(
offsetX?: number,
offsetY?: number,
) {
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x2 - x1) / 2 - (element.x - x1);
const cy = (y2 - y1) / 2 - (element.y - y1);
const degree = (180 * element.angle) / Math.PI;
const generator = rsvg.generator;
switch (element.type) {
case "selection": {
@ -366,7 +371,9 @@ export function renderElementToSvg(
}
node.setAttribute(
"transform",
`translate(${offsetX || 0} ${offsetY || 0})`,
`translate(${offsetX || 0} ${
offsetY || 0
}) rotate(${degree} ${cx} ${cy})`,
);
svgRoot.appendChild(node);
break;
@ -384,7 +391,9 @@ export function renderElementToSvg(
}
node.setAttribute(
"transform",
`translate(${offsetX || 0} ${offsetY || 0})`,
`translate(${offsetX || 0} ${
offsetY || 0
}) rotate(${degree} ${cx} ${cy})`,
);
group.appendChild(node);
});
@ -401,7 +410,9 @@ export function renderElementToSvg(
}
node.setAttribute(
"transform",
`translate(${offsetX || 0} ${offsetY || 0})`,
`translate(${offsetX || 0} ${
offsetY || 0
}) rotate(${degree} ${cx} ${cy})`,
);
const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
const lineHeight = element.height / lines.length;