web-component-designer icon indicating copy to clipboard operation
web-component-designer copied to clipboard

Draw Resize Overlay around transformed objects

Open jogibear9988 opened this issue 2 years ago • 2 comments

Check how we could draw the resize/selection overlay around a rotated object (or otherwise transformed)

  • [x] try to draw the lines without 1px x 1px helper div... use matrix transform. Consider transform origin in tx and ty. Remove helper element's 1px/1px cornerDiv if successful.
  • [x] Consider scale factor > done with 9e44aeb8a29320713af3075482de64e2b7e0e999
  • [ ] Redraw while scolling canvas
  • [x] overlay doesn't fit perfectly in all rotation angles > Fixed with 3dc7c24ec688e655212a2798cdfffca4dd5b1e79
  • [x] When an object is dragged into another, the overlay is drawn in the wrong place
  • [x] Restore mouse extension over after placement > 2227ac9517054441939d0bd30888e3cd5db7bb6f

jogibear9988 avatar Mar 10 '22 18:03 jogibear9988

How does the helperElement / cornerDiv variant work?

image

A clone of the actual element for which the vertices are to be determined is also passed to the method. The visibility is set to hidden for this element. At the same time the current transform is saved and reset. Then the clone is added to the DOM (helperElement) located in designerCanvas.

image

The Transform Origin of the cloned element without transformation is saved. Then the cloned element is destroyed.

image

Calculate corner points of the untransformed element and store them in an object array

  const cornerPoints: IPoint[] = [     {       x: originalRect.x + cloneBoundingRect.x - untransformedCornerPointsOffset,       y: originalRect.y + cloneBoundingRect.y - untransformedCornerPointsOffset     },     {       x: originalRect.x + cloneBoundingRect.x + cloneBoundingRect.width + untransformedCornerPointsOffset,       y: originalRect.y + cloneBoundingRect.y - untransformedCornerPointsOffset     },     {       x: originalRect.x + cloneBoundingRect.x - untransformedCornerPointsOffset,       y: originalRect.y + cloneBoundingRect.y + cloneBoundingRect.height + untransformedCornerPointsOffset     },     {       x: originalRect.x + cloneBoundingRect.x + cloneBoundingRect.width + untransformedCornerPointsOffset,       y: originalRect.y + cloneBoundingRect.y + cloneBoundingRect.height + untransformedCornerPointsOffset     }   ]

Is the original rect needed at all? The element is located in the DesignerCanvas. X and y apparently always return 0 anyway.

Remove helperElements‘s children image

  let cornerPointsTranformOrigins = new Array(4);

Calculate transform origin of the corner points so that they are congruent with the transform origin of the element.

    const transformOrigin = (parseInt(transformOriginBackup.split(' ')[0]) + untransformedCornerPointsOffset).toString() + ' ' + (parseInt(transformOriginBackup.split(' ')[1]) + untransformedCornerPointsOffset).toString(); cornerPointsTranformOrigins[0] = (parseInt(transformOrigin.split(' ')[0])).toString() + ' ' + (parseInt(transformOrigin.split(' ')[1])).toString();   cornerPointsTranformOrigins[1] = (cornerPoints[0].x - cornerPoints[1].x + parseInt(transformOrigin.split(' ')[0])).toString() + ' ' + (parseInt(transformOrigin.split(' ')[1])).toString();   cornerPointsTranformOrigins[2] = (parseInt(transformOrigin.split(' ')[0])).toString() + ' ' + (cornerPoints[0].y - cornerPoints[2].y + parseInt(transformOrigin.split(' ')[1])).toString();   cornerPointsTranformOrigins[3] = (cornerPoints[0].x - cornerPoints[1].x + parseInt(transformOrigin.split(' ')[0])).toString() + ' ' + (cornerPoints[0].y - cornerPoints[2].y + parseInt(transformOrigin.split(' ')[1])).toString(); image

Create 1px/1px corner divs

image

    const cornerDivs: HTMLDivElement[] = [];   let element: HTMLDivElement;   for (let i = 0; i < cornerPointsTranformOrigins.length; i++) {     element = document.createElement('div');     element.style.visibility = 'hidden';     element.style.position = 'absolute';     element.style.width = "1px";     element.style.height = "1px";     element.style.top = cornerPoints[i].y.toString() + 'px';     element.style.left = cornerPoints[i].x.toString() + 'px';     element.style.transformOrigin = cornerPointsTranformOrigins[i].split(' ')[0] + 'px' + ' ' + cornerPointsTranformOrigins[i].split(' ')[1] + 'px';     cornerDivs.push(helperElement.appendChild(element)); }

**Apply saved transform to the corner divs and calc their x and y values **

  let transformedCornerPoints: IPoint3D[] = []; for (let i = 0; i < cornerDivs.length; i++) {     //let transformedCornerDiv: HTMLElement;     let transformedCornerPoint: IPoint3D = { x: null, y: null, z: null };     //transformedCornerDiv = applyMatrixToElement((<HTMLElement>this.extendedItem.element).style.transform, cornerDivs[i]);     cornerDivs[i].style.transform = transformBackup;     //transformedCornerDiv =  applyMatrixToElement((<HTMLElement>this.extendedItem.element).style.transform, cornerDivs[i]);     transformedCornerPoint.x = designerCanvas.getNormalizedElementCoordinates(cornerDivs[i]).x;     transformedCornerPoint.y = designerCanvas.getNormalizedElementCoordinates(cornerDivs[i]).y;     transformedCornerPoint.z = 0;     transformedCornerPoints.push(transformedCornerPoint);   } return transformedCornerPoints;

7evenk avatar Oct 19 '22 21:10 7evenk

This is the new method without cornerDiv!

image

  • Hide clone
  • Reset transfrom
  • Append clone to DOM (designerCanvas helperElement)
  • Destroy clone

image

Calculate the corner points of the untransformed clone

`  const appendedCloneWithoutTranformCornerDOMPoints: DOMPoint[] = [];   appendedCloneWithoutTranformCornerDOMPoints[topleft] = DOMPoint.fromPoint(     {       x: appendedCloneWithoutTranformRect.x - untransformedCornerPointsOffset,       y: appendedCloneWithoutTranformRect.y - untransformedCornerPointsOffset     }   )

...

helperElement.replaceChildren(); `

Calculate the transform origin related to the canvas

image

  const transformOriginRelatedToCanvas: DOMPointReadOnly = DOMPointReadOnly.fromPoint(     {       x: appendedCloneWithoutTranformRect.x + parseInt(getComputedStyle(<HTMLElement>originalElement).transformOrigin.split(' ')[0]),       y: appendedCloneWithoutTranformRect.y + parseInt(getComputedStyle(<HTMLElement>originalElement).transformOrigin.split(' ')[1]),       z: 0,       w: 0     }   )

Calcluate the vectors (𝑻𝑶𝑷𝟎) ⃗, (𝑻𝑶𝑷𝟏) ⃗, (𝑻𝑶𝑷𝟐) ⃗, (𝑻𝑶𝑷𝟑) ⃗

  let top0 = new DOMPoint(-(transformOriginRelatedToCanvas.x - appendedCloneWithoutTranformCornerDOMPoints[topleft].x), -(transformOriginRelatedToCanvas.y - appendedCloneWithoutTranformCornerDOMPoints[topleft].y));   let top1 = new DOMPoint(-(transformOriginRelatedToCanvas.x - appendedCloneWithoutTranformCornerDOMPoints[topright].x), -(transformOriginRelatedToCanvas.y - appendedCloneWithoutTranformCornerDOMPoints[topright].y));   let top2 = new DOMPoint(-(transformOriginRelatedToCanvas.x - appendedCloneWithoutTranformCornerDOMPoints[bottomleft].x), -(transformOriginRelatedToCanvas.y - appendedCloneWithoutTranformCornerDOMPoints[bottomleft].y));   let top3 = new DOMPoint(-(transformOriginRelatedToCanvas.x - appendedCloneWithoutTranformCornerDOMPoints[bottomright].x), -(transformOriginRelatedToCanvas.y - appendedCloneWithoutTranformCornerDOMPoints[bottomright].y));

Apply original element‘s transformation matrix to each point

  let top0Transformed = top0.matrixTransform(originalElementMatrix);   let top1Transformed = top1.matrixTransform(originalElementMatrix);   let top2Transformed = top2.matrixTransform(originalElementMatrix);   let top3Transformed = top3.matrixTransform(originalElementMatrix);

Calcluate the vectors (𝑪𝑶𝑷𝟎′) ⃗, (𝑪𝑶𝑷𝟏′) ⃗, (𝑪𝑶𝑷𝟐′) ⃗, (𝑪𝑶𝑷𝟑′) ⃗

image

  let transformedCornerPoints: DOMPoint[] = [];   transformedCornerPoints[0] = new DOMPoint(transformOriginRelatedToCanvas.x + top0Transformed.x, transformOriginRelatedToCanvas.y + top0Transformed.y);   transformedCornerPoints[1] = new DOMPoint(transformOriginRelatedToCanvas.x + top1Transformed.x, transformOriginRelatedToCanvas.y + top1Transformed.y);   transformedCornerPoints[2] = new DOMPoint(transformOriginRelatedToCanvas.x + top2Transformed.x, transformOriginRelatedToCanvas.y + top2Transformed.y);   transformedCornerPoints[3] = new DOMPoint(transformOriginRelatedToCanvas.x + top3Transformed.x, transformOriginRelatedToCanvas.y + top3Transformed.y);

image

7evenk avatar Oct 19 '22 21:10 7evenk

Get original element’s transform origin relative to canvas and add available vectors to get the transformed corner points

getDesignerCanvasNormalizedTransformedOrigin()

image

  1. Apply resulting transformation (multiplied self by all ancestors) to appendedClone.
  2. Calc transform origin position related to designer canvas
  3. Calc the element’s transform origin corner point vectors of the untransformed appendedClone
  4. Apply the resulting transformation to all corner point vectors
  5. Add these transformed vectors to original element’s transform origin that is related to the designer canvas

7evenk avatar Nov 14 '22 16:11 7evenk

https://user-images.githubusercontent.com/5232626/201771139-3e0747e5-bd11-4ded-9e05-266a0360bf4b.mp4

7evenk avatar Nov 14 '22 21:11 7evenk