diff options
-rw-r--r-- | src/client/util/Transform.ts | 73 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 2 |
4 files changed, 64 insertions, 21 deletions
diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index e9170ec36..dca37c960 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -2,65 +2,105 @@ export class Transform { private _translateX: number = 0; private _translateY: number = 0; private _scale: number = 1; + private _rotate: number = 0; static Identity(): Transform { return new Transform(0, 0, 1); } - get TranslateX(): number { return this._translateX; } - get TranslateY(): number { return this._translateY; } - get Scale(): number { return this._scale; } + get TranslateX(): number { + return this._translateX; + } + get TranslateY(): number { + return this._translateY; + } + get Scale(): number { + return this._scale; + } + get Rotate(): number { + return this._rotate; + } + get RotateDeg(): number { + return (this._rotate * 180) / Math.PI; + } - constructor(x: number, y: number, scale: number) { + /** + * Represents a transformation/scale matrix (can contain a rotation value, but it is not used when transforming points) + * @param x + * @param y + * @param scale + * @param rotation NOTE: this is passed along but is NOT used by any of the transformation functionsStores + */ + constructor(x: number, y: number, scale: number, rotationRadians?: number) { this._translateX = x; this._translateY = y; this._scale = scale; + this._rotate = rotationRadians ?? 0; } + /** + * Rotate in radians + * @param rot + * @returns the modified transformation + */ + rotate = (rot: number): this => { + this._rotate += rot; + return this; + }; + /** + * Rotation in degrees + * @param rot + * @returns the modified transformation + */ + rotateDeg = (rot: number): this => { + this._rotate += (rot * Math.PI) / 180; + return this; + }; + translate = (x: number, y: number): this => { this._translateX += x; this._translateY += y; return this; - } + }; scale = (scale: number): this => { this._scale *= scale; this._translateX *= scale; this._translateY *= scale; return this; - } + }; scaleAbout = (scale: number, x: number, y: number): this => { this._translateX += x * this._scale - x * this._scale * scale; this._translateY += y * this._scale - y * this._scale * scale; this._scale *= scale; return this; - } + }; transform = (transform: Transform): this => { this._translateX = transform._translateX + transform._scale * this._translateX; this._translateY = transform._translateY + transform._scale * this._translateY; this._scale *= transform._scale; return this; - } + }; preTranslate = (x: number, y: number): this => { this._translateX += this._scale * x; this._translateY += this._scale * y; return this; - } + }; preScale = (scale: number): this => { this._scale *= scale; return this; - } + }; preTransform = (transform: Transform): this => { this._translateX += transform._translateX * this._scale; this._translateY += transform._translateY * this._scale; this._scale *= transform._scale; return this; - } + }; translated = (x: number, y: number): Transform => this.copy().translate(x, y); @@ -82,18 +122,17 @@ export class Transform { y *= this._scale; y += this._translateY; return [x, y]; - } + }; transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale]; - transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } { + transformBounds(x: number, y: number, width: number, height: number): { x: number; y: number; width: number; height: number } { [x, y] = this.transformPoint(x, y); [width, height] = this.transformDirection(width, height); return { x, y, width, height }; } - inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale); - - copy = () => new Transform(this._translateX, this._translateY, this._scale); + inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale, -this._rotate); -}
\ No newline at end of file + copy = () => new Transform(this._translateX, this._translateY, this._scale, this._rotate); +} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6663c5ee8..dc5839bdd 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -69,7 +69,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2}; const {x,y} = Utils.rotPt(e.clientX - center.x, e.clientY - center.y, - -NumCast(SelectionManager.Docs().lastElement()?.rotation)/180*Math.PI); + -NumCast(SelectionManager.Views().lastElement()?.screenToLocalTransform().RotateDeg)); (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && // (this.Bounds.x > center.x+x + this._resizeBorderWidth / 2 || this.Bounds.r < center.x+x - this._resizeBorderWidth / 2 || @@ -698,7 +698,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const bounds = this.ClippedBounds; const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView; const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? - const rotation = SelectionManager.Views().length == 1 ? seldocview.docViewPath.reduce((rot, view) => rot + NumCast(view.rootDoc._rotation), 0) : 0; + const rotation = SelectionManager.Views().length == 1 ? seldocview.screenToLocalTransform().RotateDeg : 0; // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 5fbe5d0e3..ab124eede 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -226,7 +226,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF this.props.Document.x = this.props.w_X() + x; this.props.Document.y = this.props.w_Y() + y; }; - screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(-this.props.w_X(), -this.props.w_Y()); + screenToLocalTransform = () => + this.props + .ScreenToLocalTransform() + .translate(-this.props.w_X(), -this.props.w_Y()) + .rotateDeg(this.props.w_Rotation?.() || 0); returnThis = () => this; /// this indicates whether the doc view is activated because of its relationshop to a group diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 459b3036d..6ebf84738 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -938,7 +938,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp className="videoBox-ui" style={{ transformOrigin: 'top left', - transform: `rotate(${NumCast(this.rootDoc.rotation)}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`, + transform: `rotate(${this.props.ScreenToLocalTransform().RotateDeg}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`, left: xPos, top: yMid, height: uiHeight, |