Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@print-one/grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.21.16",
"version": "0.21.17",
"author": "Print.one",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
Expand Down
30 changes: 28 additions & 2 deletions src/canvas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import Frame from './model/Frame';
import { CanvasEvents, ToWorldOption } from './types';
import CanvasView, { FitViewportOptions } from './view/CanvasView';
import FrameView from './view/FrameView';
import { rotateCoordinate } from '../utils/Rotator';

export type CanvasEvent = `${CanvasEvents}`;

Expand Down Expand Up @@ -488,9 +489,26 @@ export default class CanvasModule extends Module<CanvasConfig> {
const zoom = this.getZoomDecimal();
const zoomOffset = 1 / zoom;

let y = (e.clientY + addTop - yOffset) * zoomOffset;
let x = (e.clientX + addLeft - xOffset) * zoomOffset;

const rotated = rotateCoordinate(
{
l: x,
t: y,
},
{
l: 0,
t: 0,
w: frame?.model?.width ?? 0,
h: frame?.model?.height ?? 0,
r: -this.getRotationAngle(),
}
);

return {
y: (e.clientY + addTop - yOffset) * zoomOffset,
x: (e.clientX + addLeft - xOffset) * zoomOffset,
y: rotated.t,
x: rotated.l,
};
}

Expand Down Expand Up @@ -596,6 +614,14 @@ export default class CanvasModule extends Module<CanvasConfig> {
return parseFloat(this.canvas.get('zoom'));
}

getRotationAngle() {
return this.canvas.get('rotationAngle');
}

setRotationAngle(value: number) {
this.canvas.set('rotationAngle', value);
}

/**
* Set canvas position coordinates
* @param {Number} x Horizontal position
Expand Down
1 change: 1 addition & 0 deletions src/canvas/model/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default class Canvas extends ModuleModel<CanvasModule> {
frames: [],
rulers: false,
zoom: 100,
rotationAngle: 0,
x: 0,
y: 0,
// Scripts to apply on all frames
Expand Down
50 changes: 45 additions & 5 deletions src/canvas/view/CanvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Frame from '../model/Frame';
import { GetBoxRectOptions, ToWorldOption } from '../types';
import FrameView from './FrameView';
import FramesView from './FramesView';
import { rotateCoordinate } from '../../utils/Rotator';

export interface MarginPaddingOffsets {
marginTop?: number;
Expand All @@ -36,6 +37,8 @@ export type ElementPosOpts = {
avoidFrameZoom?: boolean;
noScroll?: boolean;
nativeBoundingRect?: boolean;
avoidRotate?: boolean;
overrideRect?: ElementRect;
};

export interface FitViewportOptions {
Expand Down Expand Up @@ -252,8 +255,9 @@ export default class CanvasView extends ModuleView<Canvas> {
if (framesArea) {
const { x, y } = model.attributes;
const zoomDc = module.getZoomDecimal();
const rotation = module.getRotationAngle();

framesArea.style.transform = `scale(${zoomDc}) translate(${x * mpl}px, ${y * mpl}px)`;
framesArea.style.transform = `scale(${zoomDc}) translate(${x * mpl}px, ${y * mpl}px) rotate(${rotation}deg)`;
}

if (cvStyle) {
Expand Down Expand Up @@ -455,7 +459,26 @@ export default class CanvasView extends ModuleView<Canvas> {
const frame = this.frame?.el;
const winEl = el?.ownerDocument.defaultView;
const frEl = winEl ? (winEl.frameElement as HTMLElement) : frame;
this.frmOff = this.offset(frEl || frame, { nativeBoundingRect: true });
const zoom = this.module.getZoomDecimal();
//Native offset has been transformed by the zoom and rotation
const nativeOffset = this.offset(frEl || frame, { nativeBoundingRect: true });
//Original offset of the element has not been transformed
const originalOffset = this.offset(frEl || frame, { nativeBoundingRect: false });

//We want to get the offset without the rotation
const middle = {
x: nativeOffset.left + nativeOffset.width / 2,
y: nativeOffset.top + nativeOffset.height / 2,
};

let width = originalOffset.width * zoom;
let height = originalOffset.height * zoom;
this.frmOff = {
width: width,
height: height,
top: middle.y - height / 2,
left: middle.x - width / 2,
};
}
return this.frmOff;
}
Expand All @@ -482,12 +505,29 @@ export default class CanvasView extends ModuleView<Canvas> {
const frameOffset = this.getFrameOffset(el);
const canvasEl = this.el;
const canvasOffset = this.getCanvasOffset();
const elRect = this.offset(el, opts);
const elRect = opts.overrideRect ?? this.offset(el, opts);
const frameTop = opts.avoidFrameOffset ? 0 : frameOffset.top;
const frameLeft = opts.avoidFrameOffset ? 0 : frameOffset.left;

const elTop = opts.avoidFrameZoom ? elRect.top : elRect.top * zoom;
const elLeft = opts.avoidFrameZoom ? elRect.left : elRect.left * zoom;
const rotated = rotateCoordinate(
{
l: elRect.left + elRect.width / 2,
t: elRect.top + elRect.height / 2,
},
{
l: 0,
t: 0,
w: this.frame?.model?.width ?? 0,
h: this.frame?.model?.height ?? 0,
r: opts.avoidRotate ? 0 : this.module.getRotationAngle(),
}
);

rotated.l -= elRect.width / 2;
rotated.t -= elRect.height / 2;

const elTop = opts.avoidFrameZoom ? rotated.t : rotated.t * zoom;
const elLeft = opts.avoidFrameZoom ? rotated.l : rotated.l * zoom;

const top = opts.avoidFrameOffset ? elTop : elTop + frameTop - canvasOffset.top + canvasEl.scrollTop;
const left = opts.avoidFrameOffset ? elLeft : elLeft + frameLeft - canvasOffset.left + canvasEl.scrollLeft;
Expand Down
31 changes: 26 additions & 5 deletions src/commands/view/ComponentDrag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ export default {
},

getElementPos(el: HTMLElement) {
return this.editor.Canvas.getElementPos(el, { noScroll: 1 });
return this.editor.Canvas.getElementPos(el, {
noScroll: 1,
avoidRotate: 1,
avoidFrameOffset: 1,
avoidFrameZoom: 1,
});
},

getElementGuides(el: HTMLElement) {
Expand Down Expand Up @@ -428,14 +433,30 @@ export default {
const statEdge2Raw = isY ? rect.left + rect.width : rect.top + rect.height;
const posFirst = isY ? item.y : item.x;
const posSecond = isEdge1 ? statEdge2 : origEdge2;
const pos2 = `${posFirst}px`;
const size = isEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2;
const sizeRaw = isEdge1 ? origEdge1Raw - statEdge2Raw : statEdge1Raw - origEdge2Raw;

const position = this.editor.Canvas.getElementPos(origin, {
noScroll: 1,
overrideRect: {
top: isY ? posFirst : posSecond,
left: isY ? posSecond : posFirst,
width: isY ? size : 0,
height: isY ? 0 : size,
},
});

const rotationAngle = this.canvas.getRotationAngle();
const zoom = this.canvas.getZoomDecimal();

guideInfoStyle.display = '';
guideInfoStyle[isY ? 'top' : 'left'] = pos2;
guideInfoStyle[isY ? 'left' : 'top'] = `${posSecond}px`;
guideInfoStyle[isY ? 'width' : 'height'] = `${size}px`;
guideInfoStyle.top = `${position.top}px`;
guideInfoStyle.left = `${position.left}px`;
guideInfoStyle.rotate = `${rotationAngle}deg`;
guideInfoStyle[isY ? 'width' : 'height'] = `${size * zoom}px`;
elGuideInfoCnt.innerHTML = `${Math.round(sizeRaw)}px`;
elGuideInfoCnt.style.rotate = `${-rotationAngle}deg`;
elGuideInfoCnt.style.transformOrigin = isY ? '50% 100%' : '100% 50%';
this.em.trigger(`${evName}:active`, {
...this.getEventOpts(),
guide: item,
Expand Down
1 change: 1 addition & 0 deletions src/commands/view/Resize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default {
prefix: editor.getConfig().stylePrefix,
posFetcher: canvasView.getElementPos.bind(canvasView),
mousePosFetcher: canvas.getMouseRelativePos.bind(canvas),
rotationAngle: canvas.getRotationAngle(),
...(opt.options || {}),
};
let { canvasResizer } = this;
Expand Down
1 change: 1 addition & 0 deletions src/commands/view/Rotate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default {
prefix: editor.getConfig().stylePrefix,
posFetcher: canvasView.getElementPos.bind(canvasView),
mousePosFetcher: (ev: MouseEvent) => canvas.getMouseRelativeCanvas(ev, {}),
rotationAngle: canvas.getRotationAngle(),
...(opt.options || {}),
};
let { canvasRotator } = this;
Expand Down
2 changes: 2 additions & 0 deletions src/commands/view/SelectComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ export default {
style.width = pos.width + unit;
style.height = pos.height + unit;
style.rotate = window.getComputedStyle(el).getPropertyValue('rotate');
style.transform = `rotate(${this.canvas.getRotationAngle()}deg)`;

this._trgToolUp('local', {
component,
Expand Down Expand Up @@ -794,6 +795,7 @@ export default {
style.width = pos.width + unit;
style.height = pos.height + unit;
style.rotate = window.getComputedStyle(el).getPropertyValue('rotate');
style.transform = `rotate(${this.canvas.getRotationAngle()}deg)`;

this.updateToolbarPos({ top: targetToElem.top, left: targetToElem.left });
this._trgToolUp('global', {
Expand Down
Loading
Loading