Расчет getBoundingClientRect в процентах

Я уже вычисляю левую и верхнюю позиции, используя getBoundingClientRect() дочернего элемента по отношению к родительскому в px и переходя от одного компонента к другому, и могу размещать дочерние элементы в ожидаемых позициях, однако я хочу, чтобы дочерние элементы реагировали на родительский элемент, для этого мне нужны верхняя и левая позиции в % Я уже пытался изменить значения и единицу измерения с px на % с консоли и смог получить желаемую отзывчивость, однако попытка вычислить в процентах в коде не работает должным образом, это не помещает дочерний элемент в правильное положение, хотя достигается отзывчивость.

  minX: viewRect.left - movableClientRect.left + movable.position.x,
  maxX: viewRect.right - movableClientRect.right + movable.position.x,
  minY: viewRect.top - movableClientRect.top + movable.position.y,
  maxY: viewRect.bottom - movableClientRect.bottom + movable.position.y

 this.dataService.setData(this.zonePosition = 
 {
  x : (viewRect.left - movableClientRect.left)/viewRect.left ,
  y: (viewRect.top - movableClientRect.top)/viewRect.top
  }

В более раннем коде я делал только viewRect.left - movableClientRect.left, поэтому значения были в пикселях, и теперь я попытался разделить на viewRect.left, а затем * 100, чтобы преобразовать его в %, но процентное значение не помещает дочерний элемент элементы правильно.

Обновление с директивами для расчета позиции

movable.directive В этом я вычисляю позиции x и y дочернего элемента.

interface Position {
  x: number;
  y: number;
}

@Directive({
 selector: '[appMovable]'
})
export class MovableDirective extends DraggableDirective {
@HostBinding('style.transform') get transform(): SafeStyle {
   return this.sanitizer.bypassSecurityTrustStyle(
  `translateX(${this.position.x}%) translateY(${this.position.y}%)`
  );
 }

 @HostBinding('class.movable') movable = true;

 position: Position = {x: 0, y: 0};
 zonePosition = {x:0, y:0, id:""}

 private startPosition: Position;

 @Input('appMovableReset') reset = false;

 constructor(private sanitizer: DomSanitizer, public element: ElementRef, 
  private dataService: DataService) {
  super(element);
  }

 @HostListener('dragStart', ['$event'])
  onDragStart(event: PointerEvent) {
   this.startPosition = {
     x: event.clientX - this.position.x,
     y: event.clientY - this.position.y
   }
 }

 @HostListener('dragMove', ['$event'])
  onDragMove(event: PointerEvent) {
   this.position.x = event.clientX - this.startPosition.x;
   this.position.y = event.clientY - this.startPosition.y;
  }

  @HostListener('dragEnd', ['$event'])
   onDragEnd(event: PointerEvent) {
    if (this.reset) {
     this.position = {x: 0, y: 0};
    }
   }
   }

Директива, в которой я вычисляю левый и верхний элементы дочернего элемента и присваиваю его dataService

  Directive({
   selector: '[appMovableArea]'
  })
  export class MovableAreaDirective implements AfterContentInit {
  @ContentChildren(MovableDirective) movables: QueryList<MovableDirective>;

  private boundaries: Boundaries;
  private subscriptions: Subscription[] = [];

  zonePosition = {x:0, y:0, id:""}

  constructor(private element: ElementRef, private dataService: DataService) 
  {}

  ngAfterContentInit(): void {
   this.movables.changes.subscribe(() => {
   this.subscriptions.forEach(s => s.unsubscribe());

   this.movables.forEach(movable => {
   this.subscriptions.push(movable.dragStart.subscribe(() => 
       this.measureBoundaries(movable)));
   this.subscriptions.push(movable.dragMove.subscribe(() => 
   this.maintainBoundaries(movable)));
   });
   });

   this.movables.notifyOnChanges();
    }

   private measureBoundaries(movable: MovableDirective) {
    const viewRect: ClientRect = 
       this.element.nativeElement.getBoundingClientRect();
    const movableClientRect: ClientRect = 
       movable.element.nativeElement.getBoundingClientRect();

    this.dataService.setData(this.zonePosition= {x : (viewRect.left - 
      movableClientRect.left)/viewRect.left , y: (viewRect.top - 
      movableClientRect.top)/viewRect.top, id: "" })

    this.boundaries = {
      minX: viewRect.left - movableClientRect.left + movable.position.x,
      maxX: viewRect.right - movableClientRect.right + movable.position.x,
      minY: viewRect.top - movableClientRect.top + movable.position.y,
      maxY: viewRect.bottom - movableClientRect.bottom + movable.position.y
    };
   }

    private maintainBoundaries(movable: MovableDirective) {
     movable.position.x = Math.max(this.boundaries.minX, 
      movable.position.x);
    movable.position.x = Math.min(this.boundaries.maxX, movable.position.x);
    movable.position.y = Math.max(this.boundaries.minY, movable.position.y);
    movable.position.y = Math.min(this.boundaries.maxY, movable.position.y);
   }
   }

person Enthu    schedule 14.08.2019    source источник
comment
Если требуется дополнительная информация, пожалуйста, дайте мне знать   -  person Enthu    schedule 14.08.2019


Ответы (1)


Если у вас уже есть позиция в пикселях относительно элемента-контейнера, то все, что вам нужно, это разделить это значение в пикселях на размер контейнера в пикселях и умножить на 100:

perc_x = px_x / px_width * 100;
perc_y = px_y / px_height * 100;

elem = document.querySelector('.content');
container = document.querySelector('.container');
const mouse = {
  x: null,
  y: null,
  down: false
};
let will_draw = false;

elem.onmousedown = e => {
  mouse.down = true;
};
onmouseup = e => {
  mouse.down = false;
};
document.onmousemove = e => {
  if(!mouse.down) { return; }

  const container_rect = container.getBoundingClientRect();
  // relative to container, in px
  mouse.x = e.clientX - container_rect.left;
  mouse.y = e.clientY - container_rect.top;
  if(!will_draw) {
    requestAnimationFrame(draw);
    will_draw = true;
  }
}

function draw() {
  will_draw = false;
  const { width, height} = container.getBoundingClientRect();
  const perc_x = mouse.x / width * 100;
  const perc_y = mouse.y / height * 100;
  // -5 to center (elem has its width set to 10%)
  elem.style.setProperty('left', (perc_x - 5) + '%');
  // -5 to center (elem has its height set to 10%)
  elem.style.setProperty('top', (perc_y - 5) + '%');
}
.container {
  width: 80vw;
  height: 80vh;
  border: 1px solid;
  position: relative;
}
.content {
  width: 10%;
  height: 10%;
  position: absolute;
  top: 45%;
  left: 45%;
  background: green;
}
<div class="container">
  <div class="content">
  </div>
</div>

person Kaiido    schedule 15.08.2019
comment
Я также обновил свой пост с расчетом, который я применил, но я не понимаю, относится ли верхняя и левая часть элемента, который я получаю, к его родителю или к области просмотра, моя цель - получить отношение к его родителю, пожалуйста, предложите - person Enthu; 15.08.2019
comment
@Enthu, просто посмотри на мой фрагмент? Я делаю все это. Чтобы получить позицию относительно контейнера, вы просто делаете mouseEvent.clientX - container.getBoundingClientRect().left - person Kaiido; 15.08.2019
comment
@Enthu, мы устанавливаем верхние левые координаты нашего элемента через CSS. - 5 должен сделать так, чтобы наша мышь указывала на центр нашего элемента. Так как наш элемент имеет ширину 10×10%, чтобы сделать его центр равным, скажем, 50% 50%, нам нужно установить его верхнюю и левую части на 45%. Вот что делает эта строка. - person Kaiido; 16.08.2019