Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: improve boundingBox method at ElementHandle #1357

Closed
schelkun opened this issue Nov 10, 2017 · 5 comments
Closed

Feature: improve boundingBox method at ElementHandle #1357

schelkun opened this issue Nov 10, 2017 · 5 comments
Labels

Comments

@schelkun
Copy link
Contributor

Current version of boundingBox is terribly coded as I think 😄 :
https://github.com/GoogleChrome/puppeteer/blob/master/lib/ElementHandle.js#L123

Look at DevTools method:
https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getBoxModel

DevTools method returns BoxModel:
https://chromedevtools.github.io/devtools-protocol/tot/DOM/#type-BoxModel

BoxModel contains:

  • content
  • padding
  • border
  • margin
  • width
  • height
  1. Why we are calculating width and height? It's already calculated and returned by DevTools, but we have:
const width = Math.max(quad[0], quad[2], quad[4], quad[6]) - x;
const height = Math.max(quad[1], quad[3], quad[5], quad[7]) - y;
  1. Puppeteer use only border position:
const quad = result.model.border;

What If I want to get content position? Or padding position or margin position? 😢

My advice is smth like that:

async boundingBox() {
  const result = await this._client.send('DOM.getBoxModel', {
    objectId: this._remoteObject.objectId
  }).catch(error => void debugError(error));

  if (!result)
    return null;

  const borderQuad = result.model.border;

  return {
    border: {
      x: Math.min(borderQuad[0], borderQuad[2], borderQuad[4], borderQuad[6]),
      y: Math.min(borderQuad[1], borderQuad[3], borderQuad[5], borderQuad[7]),
      width: Math.max(borderQuad[0], borderQuad[2], borderQuad[4], borderQuad[6]) - x,
      height: Math.max(borderQuad[1], borderQuad[3], borderQuad[5], borderQuad[7]) - y
    },
    // same for padding and margin
    width: result.model.width,
    height: result.model.height
  };
}
@JoelEinbinder
Copy link
Collaborator

Boxes can be rotated.

@schelkun
Copy link
Contributor Author

@JoelEinbinder and what? Why we can't access full returned object from DevTools in puppeteer?

@schelkun
Copy link
Contributor Author

@JoelEinbinder @aslushnikov what about content size? I can't get it with puppeteer.

@JoelEinbinder
Copy link
Collaborator

Right now bounding box is designed to match (getBoundingClientRect)[https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect].

I am curious as to what your use case is for getting the content size.

@JoelEinbinder JoelEinbinder reopened this Nov 13, 2017
@schelkun
Copy link
Contributor Author

@JoelEinbinder look at this method for example:

  async boundingBoxNew() {
    const {model} = await this._client.send('DOM.getBoxModel', {
      objectId: this._remoteObject.objectId
    });
    if (!model)
      throw new Error('Node is detached from document');

    const calculatePos = function(quad)  {
      const x = Math.min(quad[0], quad[2], quad[4], quad[6]);
      const y = Math.min(quad[1], quad[3], quad[5], quad[7]);
      return {
        x: x,
        y: y,
        width: Math.max(quad[0], quad[2], quad[4], quad[6]) - x,
        height: Math.max(quad[1], quad[3], quad[5], quad[7]) - y
      };
    };

    return {
      border: calculatePos(model.border),
      content: calculatePos(model.content),
      margin: calculatePos(model.margin),
      padding: calculatePos(model.padding),
      width: model.width,
      height: model.height
    };
  }

And this sample website and script:

const puppeteer = require('puppeteer');

(async() => {
    const browser = await puppeteer.launch({
        headless: false,
        timeout: 10000
    });

    const page = await browser.newPage();

    await page.setViewport({
        width: 1280,
        height: 800
    });

    await page.goto('https://schelkun.github.io/padding-link/index.html');

    const element = await page.$('.text');
    const oldBoundingBox = await element.boundingBox();

    console.log(oldBoundingBox);

    const newBoundingBox = await element.boundingBoxNew();

    console.log(newBoundingBox);
})();

As a result I can get real content position:

{ border: { x: 128, y: 36, width: 200, height: 58 },
  content: { x: 128, y: 56, width: 200, height: 18 },
  margin: { x: 128, y: 20, width: 1024, height: 90 },
  padding: { x: 128, y: 36, width: 200, height: 58 },
  width: 200,
  height: 58 }

Content position is very usefull for text select with mouse for example.

aslushnikov pushed a commit that referenced this issue Mar 29, 2018
This patch introduces ElementHandle.boxModel to get element's
box model.

Fixes #1357
aslushnikov added a commit to aslushnikov/puppeteer that referenced this issue Mar 29, 2018
This patch:
- re-makes test for EH.boxModel to make it more readable
- slightly changes wording in the `docs/api.md`.

References puppeteer#1357.
aslushnikov added a commit that referenced this issue Mar 30, 2018
…2287)

This patch:
- re-makes test for EH.boxModel to make it more readable
- slightly changes wording in the `docs/api.md`.

References #1357.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants