components
components copied to clipboard
CDK Drag boundary is not working for SVG element
I am working on one project which having functionality to draw shape and drag it in it's container but when I used cdkBoundary for rect element and drag it then transform property updated base on top most parent's coordinate.
Can you post an example of your code? It's hard to tell what could be wrong based on the description.
Please find below sample code of my project Or you can get it from stackbliz
.boundary{ width: 200px; height: 200px; border: 1px solid red; }
.bluebox { height: 40px; width: 40px; background-color: blue; }
svg{ border: 1px solid green; width: 100%; }
rect, circle{ fill: darkgray; }
"dependencies": { "@angular/animations": "11.0.0", "@angular/cdk": "~11.0.0", "@angular/common": "~11.0.0", "@angular/compiler": "~11.0.0", "@angular/core": "~11.0.0", "@angular/forms": "~11.0.0", "@angular/platform-browser": "~11.0.0", "@angular/platform-browser-dynamic": "~11.0.0", "@angular/router": "~11.0.0", "core-js": "2.6.9", "rxjs": "~6.5.5", "zone.js": "0.10.3" },
Thank you for your reply,
Now I am getting 'Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://jmg1-sandbox.ideas.aha.io') does not match the recipient window's origin' error.
On Mon, Mar 1, 2021 at 10:23 PM Kristiyan Kostadinov < [email protected]> wrote:
Can you post an example of your code? It's hard to tell what could be wrong based on the description.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/angular/components/issues/22051#issuecomment-788103069, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGNHP3OAGKX2WW376IN7TEDTBPBCLANCNFSM4YJTKOLQ .
-- Regards,
- Jignesh Gothadiya Software Developer
@NiyazNz
This bug is due to your changes in https://github.com/angular/components/pull/19863
where you are returning an SVGPoint
object whose x/y coordinates are no longer relative to other items on the page (which needs to respected for boundary elements and I'm assuming this would mess up sorting as well, but haven't actually checked).
I experimented with a solution that doesn't modify the pointer position value and instead calculates a ratio to multiply the default transform translate value by
let transformRatioX = 1.0;
let transformRatioY = 1.0;
if (typeof SVGElement !== 'undefined' && this._rootElement instanceof SVGElement) {
const svgElement = this._ownerSVGElement;
const svgViewBoxRect = svgElement.viewBox.baseVal;
if (svgElement.clientWidth !== 0 && svgElement.clientHeight !== 0) {
const preserveAspectRatio = svgElement.preserveAspectRatio;
const aspectRatio = svgViewBoxRect.width / svgViewBoxRect.height;
let widthRatio = svgViewBoxRect.width / svgElement.clientWidth;
let heightRatio = svgViewBoxRect.height / svgElement.clientHeight;
if (preserveAspectRatio.baseVal.align !== preserveAspectRatio.baseVal.SVG_PRESERVEASPECTRATIO_NONE) {
if (preserveAspectRatio.baseVal.meetOrSlice == preserveAspectRatio.baseVal.SVG_MEETORSLICE_MEET) {
// meet (scale-down)
if (widthRatio > heightRatio) {
transformRatioX = widthRatio;
const height = svgElement.clientWidth / aspectRatio;
transformRatioY = svgViewBoxRect.height / height;
} else if (heightRatio > widthRatio) {
transformRatioY = heightRatio;
const width = svgElement.clientHeight * aspectRatio;
transformRatioX = svgViewBoxRect.width / width;
}
} else {
// slice (scale-up)
if (widthRatio > heightRatio) {
transformRatioY = heightRatio;
const width = svgElement.clientHeight * aspectRatio;
transformRatioX = svgViewBoxRect.width / width;
} else if (heightRatio > widthRatio) {
transformRatioX = widthRatio;
const height = svgElement.clientWidth / aspectRatio;
transformRatioY = svgViewBoxRect.height / height;
}
}
} else {
if (svgViewBoxRect.width !== 0) {
transformRatioX = widthRatio;
}
if (svgViewBoxRect.height !== 0) {
transformRatioY = heightRatio;
}
}
}
}
const activeTransform = this._activeTransform;
activeTransform.x =
(constrainedPointerPosition.x - this._pickupPositionOnPage.x) * transformRatioX + this._passiveTransform.x;
activeTransform.y =
(constrainedPointerPosition.y - this._pickupPositionOnPage.y) * transformRatioY + this._passiveTransform.y;
this._applyRootElementTransform(activeTransform.x, activeTransform.y);
This is totally unoptimized (perhaps the transform ratio could be cached) and possibly only working in Chrome (noticed clientHeight
/clientWidth
of an SVG can return 0 in Firefox) and assumes the SVG does not include padding, and probably issues with more edge cases, not the ideal place to put this code, etc...so really just a proof-of-concept.
This code was inserted here: https://github.com/angular/components/blob/ad248652e7da31398176fe11878b59805e440b5a/src/cdk/drag-drop/drag-ref.ts#L688-L704
along with reverting the change from your PR that modifies the returned pointer position.
Better repro case from #22593: https://stackblitz.com/edit/angular-wmvtan-co9kyn?file=package.json
Same #22592 issue in Angular11. Is there any workaround?
you could add a div outside the svg and set boundary to that, and after view init or whenever the svg size changes:
const svgRectangle = this.svg.nativeElement.getBoundingClientRect();
const boundary = this.boundary.nativeElement;
boundary.style.position = 'absolute';
boundary.style.visibility = 'hidden';
boundary.style.top = '0px';
boundary.style.left = '0px';
boundary.style.width = `${svgRectangle.width}px`;
boundary.style.height = `${svgRectangle.height}px`;