Angular CDK 拖放缩放 CSS-属性 “transform: scale(0.5)” 无法按预期工作

Angular CDK drag-drop with zoom by CSS-property “transform: scale(0.5)” doesn’t work as expected

Angular CDK 拖放缩放 CSS-属性 “transform: scale(0.5)” 没有按预期工作。

如果外部-DIV按CSS-属性“transform: scale(0.5)”缩放,拖动不会'与鼠标指针正确对齐。一旦比例不等于 1,就会发生这种情况。

举个例子:https://stackblitz.com/edit/angular-2q1mte

我知道这个 post 因此

“@Input('cdkDragConstrainPosition') constrainPosition: (point: Point, dragRef: DragRef) => Point”.

但是如何编写自定义逻辑以使用指针正确映射拖动?或者是否有任何其他解决方案来提供缩放功能但保持拖动与鼠标指针正确对齐?

感谢任何帮助

我也遇到了这个问题

这里的解决方案:初始化一个比例变量并将其用于 dragConstrainPoint

  // change position of object while zooming ! (cdk fix)
    dragConstrainPoint = (point, dragRef) => {
      let zoomMoveXDifference = 0; 
      let zoomMoveYDifference = 0; 
      if (this._scale !- 1) {
       zoomMoveXDifference = (1 - this._scale) * dragRef.getFreeDragPosition().x;
       zoomMoveYDifference = (1 - this._scale) * dragRef.getFreeDragPosition().y;
      }
      return {
        x: point.x + zoomMoveXDifference ,
        y: point.y + zoomMoveYDifference
      };

我在使用 CDK material 和 Angular 11.

通过拖放缩放整个场景时遇到了同样的问题

dragConstrainPoint 解决方案不适用于我的上下文。 这个想法实际上是为了避免变换比例或缩放,它会弄乱鼠标和对象的位置,使多人拖放成为噩梦。

我的解决方案在具有不同场景比例的多人游戏中运行良好

解决方法: 我在包装器 div 上使用了 CSS 变量 --scale,动态比例计算

<div class="game-wrapper" style="{{'--scale:'+ gameScale}}">

在Angular中场景比例是这样计算的:

...
  private _unsubscriber$: Subject<any> = new Subject();
  public screenWidth$: BehaviorSubject<number> = new BehaviorSubject(null);
  public screenHeight$: BehaviorSubject<number> = new BehaviorSubject(null);
  public gameScale: number = 1;

public constructor(
    @Inject(DOCUMENT) private document: any
  ) { }
...


ngOnInit(): void {
   
    //Manage screen width
    this._setScreenResolution(window.innerWidth, window.innerHeight);
    fromEvent(window, 'resize')
      .pipe(
        debounceTime(1000),
        takeUntil(this._unsubscriber$)
      ).subscribe((evt: any) => {
      this._setScreenResolution(evt.target.innerWidth, evt.target.innerHeight);
    });
  }

  ngOnDestroy() {
    this._unsubscriber$.next();
    this._unsubscriber$.complete();
  }

  private _setScreenResolution(width: number, height: number): void {

    this.screenWidth$.next(width);
    this.screenHeight$.next(height);

    let scaleX = windowWidth / this.sceneWidth;
    let scaleY = windowHeight / this.sceneHeight;
    let scale = scaleX;

    if(scaleX > scaleY) {
      scale = scaleY;
    }
    //console.log("getGameScale", scale.toFixed(3));
    scale = parseFloat(scale.toFixed(3));
    this.gameScale = scale;
    
  }

在 HTML 模板和 CSS 中,每次涉及像素时,我们都会添加 calc()。

这里有一些 CSS 的例子,这些计算

width: calc(18px * var(--scale));
padding: calc(1px * var(-scale)) calc(6px * var(-scale));
background-size: calc(30px * var(-scale)) calc(30px * var(-scale)), cover;
margin: calc(20px * var(-scale)) calc(30px * var(-scale));
bottom: calc(300px * var(--scale));
border-radius: calc(4px * var(--scale));
font-size: calc(21px * var(--scale));
left: calc(10px * var(--scale));
top: calc(4px * var(--scale));
box-shadow: 0 0 0 calc(4px * var(--scale)) rgba(0,0,0,0.1) inset;
border: calc(2px * var(--scale)) solid #6898f3;
height: calc(32px * var(--scale));
min-height: calc(26px * var(--scale));
line-height: calc(42px * var(--scale));

为了本地CDK拖拽移动和拖拽结束值能够很好的发送给其他多人游戏, 你需要按 dividing by the scale:

来缩放它们
  dragMoved(event: CdkDragMove) {

      let {offsetLeft, offsetTop} = event.source.element.nativeElement;
      let {x, y} = event.distance;

      x = x / this.gameScale;
      y = y / this.gameScale;
      offsetLeft = offsetLeft / this.gameScale;
      offsetTop = offsetTop / this.gameScale;

      //Remove scene offset from calcul (ex. for aside left menu)
      let xpos = ((offsetLeft + x) - this.offset.x);
      let ypos = ((offsetTop + y) - this.offset.y);
      let position: any = {x: xpos, y: ypos};
    
      //The position is then sent to a multiplayer management relay message...
    
  }

//same for drag end + do not forget to reset the transform 3D at the end of the function
dragEnded(event: CdkDragEnd) {
...

    //The position at drag end is set on the object and for all other players

    //Reset translate3D
    //event.source._dragRef.setFreeDragPosition({x: 0, y: 0});
    event.source._dragRef.reset();

}

瞧!

我设法让它在 Angular 12 中工作而不使用 calc() 但保持 transorm: scale(x):

模板:

<div cdkDrag (cdkDragStarted)="startDragging($event)" [cdkDragFreeDragPosition]="dragPosition" [cdkDragConstrainPosition]="dragConstrainPoint">

组件:

_dragPosition: { x: number, y: number } = {x: 0, y: 0};

get dragPosition(): { x: number, y: number } {
  return this._dragPosition;
}


dragConstrainPoint = (point: any, dragRef: DragRef) => {
  let zoomMoveXDifference = 0;
  let zoomMoveYDifference = 0;
  if (this.scale != 1) {
    zoomMoveXDifference = (1 - this.scale) * dragRef.getFreeDragPosition().x;
    zoomMoveYDifference = (1 - this.scale) * dragRef.getFreeDragPosition().y;
  }

  return {
    x: point.x + zoomMoveXDifference as number,
    y: point.y + zoomMoveYDifference as number
  };
};

startDragging(event: CdkDragStart) {
  const position = {
    x: this.dragPosition.x * this.scale,
    y: this.dragPosition.y * this.scale
  };
  event.source._dragRef.setFreeDragPosition(position);
  (event.source._dragRef as any)._activeTransform = this.dragPosition;
  (event.source._dragRef as any)._applyRootElementTransform(this.dragPosition.x, this.dragPosition.y);
}