DEV Community

HarmonyOS
HarmonyOS

Posted on

Convert the absolute coordinates in the click event to relative coordinates

Read the original article:Convert the absolute coordinates in the click event to relative coordinates

Problem Description

After obtaining the absolute coordinates of the click location through the child component's click event, how can these coordinates be converted to their relative coordinates with respect to the parent component?

Background Knowledge

componentUtils.getRectangleById: Retrieves the component instance object based on the component ID, and returns the obtained coordinates and size to the developer through the component instance object. The coordinates of the component refer to the coordinates of the top-left vertex of the component.

The onAreaChange callback is triggered when the component's area changes. It returns the width and height of the target element after the change, as well as the coordinates of the target element relative to the parent element and the top-left corner of the page.

Solution

Solution 1: The localOffset obtained using componentUtils.getRectangleById represents the coordinates of the child component within the parent component. The x, y coordinates obtained from the onTouch event represent the touch point's coordinates within the child component. By adding these two together, you can obtain the touch point's coordinates within the parent component.
The complete code is as follows:

@Entry
@Component
struct Index {
  @State startXIn: number = 0;
  @State startYIn: number = 0;

  build() {
    Column() {
      Column() {
        Image($r('app.media.background'))
          .id('123456')
          .width(150)
          .height(200)
          .onTouch((event) => {
            let modePosition = this.getUIContext().getComponentUtils().getRectangleById('123456')
            // Component position relative to its parent
            let imageX = this.getUIContext().px2vp(modePosition.localOffset.x)
            let imageY = this.getUIContext().px2vp(modePosition.localOffset.y)
            console.info('localOffset is', `${imageX} `, `${imageY}`)
            // Touch offset within the child component
            let startX = event.touches[0].x
            let startY = event.touches[0].y
            console.info(`touches are`, `${startX}`, `${startY}`)
            // Convert coordinates to be relative to the parent component
            this.startXIn = startX + imageX;
            this.startYIn = startY + imageY;
          })
      }
      .width(200)
      .height(250)
      .backgroundColor('#61CFBE')
      .justifyContent(FlexAlign.Center)

      Text(`X coordinate relative to parent: ${this.startXIn}`)
      Text(`Y coordinate relative to parent: ${this.startYIn}`)
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Solution 2: Using onAreaChange, you can obtain the coordinates offsetX and offsetY of the child component relative to the parent component. The x and y values in ClickEvent represent the coordinates of the click within the child component. By adding these two sets of coordinates, you can obtain the coordinates of the touch point within the parent component.
The complete code is as follows:

@Entry
@Component
struct Index2 {
  @State startXIn: number = 0;
  @State startYIn: number = 0;
  @State offsetX: number = 0
  @State offsetY: number = 0

  build() {
    Column() {
      Column() {
        Image($r('app.media.background'))
          .width(150)
          .height(200)
          .onAreaChange((oldValue: Area, newValue: Area) => {
            this.offsetX = Number(newValue.position.x)
            this.offsetY = Number(newValue.position.y)
          })
          .onClick((event?: ClickEvent) => {
            if (event) {
              let startX = event.x
              let startY = event.y
              console.info(`touches are`, `${startX}`, `${startY}`)
              this.startXIn = startX + this.offsetX;
              this.startYIn = startY + this.offsetY;
            }
          })
      }
      .width(200)
      .height(250)
      .backgroundColor('#61CFBE')
      .justifyContent(FlexAlign.Center)

      Text(`X coordinate relative to parent: ${this.startXIn}`)
      Text(`Y coordinate relative to parent: ${this.startYIn}`)
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

The implementation ideas for both are the same; they only differ in the methods used. Both involve adding the coordinates of the click position within the child component to the coordinates of the child component within the parent component, thereby obtaining the coordinates of the click position relative to the parent component.

Code Running Effect Diagram

kb1.gif

Related Documents or Links

https://developer.huawei.com/consumer/en/doc/harmonyos-references/arkts-apis-uicontext-componentutils#getrectanglebyid

https://developer.huawei.com/consumer/en/doc/harmonyos-references/ts-universal-component-area-change-event#onareachange

Written by Recep Sadullah Yegin

Top comments (0)