Skip to content

Commit

Permalink
screenshot: get node's position relative to its document
Browse files Browse the repository at this point in the history
Before this change, it's relative to the viewport. So it will get
the wrong position if the page scrolls.

Fixes chromedp#844.
  • Loading branch information
ZekeLu committed Jun 15, 2021
1 parent 268e11c commit 3ee916d
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 17 deletions.
5 changes: 5 additions & 0 deletions js.go
Expand Up @@ -45,6 +45,11 @@ var (
//go:embed js/visible.js
visibleJS string

// getClientRectJS is a javascript snippet that returns the information about the
// size of the specified node and its position relative to its owner document.
//go:embed js/getClientRect.js
getClientRectJS string

// waitForPredicatePageFunction is a javascript snippet that runs the polling in the
// browser. It's copied from puppeteer. See
// https://github.com/puppeteer/puppeteer/blob/669f04a7a6e96cc8353a8cb152898edbc25e7c15/src/common/DOMWorld.ts#L870-L944
Expand Down
10 changes: 10 additions & 0 deletions js/getClientRect.js
@@ -0,0 +1,10 @@
function getClientRect() {
const e = this.getBoundingClientRect(),
t = this.ownerDocument.documentElement.getBoundingClientRect();
return {
x: e.left - t.left,
y: e.top - t.top,
width: e.width,
height: e.height,
};
}
25 changes: 8 additions & 17 deletions query.go
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"math"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -1079,28 +1078,20 @@ func Screenshot(sel interface{}, picbuf *[]byte, opts ...QueryOption) QueryActio
}

// get box model
box, err := dom.GetBoxModel().WithNodeID(nodes[0].NodeID).Do(ctx)
if err != nil {
var clip page.Viewport
if err := callFunctionOnNode(ctx, nodes[0], getClientRectJS, &clip); err != nil {
return err
}
if len(box.Margin) != 8 {
return ErrInvalidBoxModel
}

// The next comment is copied from the original code.
// This seems to be necessary? Seems to do the right thing regardless of DPI.
clip.Scale = 1

// take screenshot of the box
buf, err := page.CaptureScreenshot().
WithFormat(page.CaptureScreenshotFormatPng).
WithClip(&page.Viewport{
// Round the dimensions, as otherwise we might
// lose one pixel in either dimension.
X: math.Round(box.Margin[0]),
Y: math.Round(box.Margin[1]),
Width: math.Round(box.Margin[4] - box.Margin[0]),
Height: math.Round(box.Margin[5] - box.Margin[1]),
// This seems to be necessary? Seems to do the
// right thing regardless of DPI.
Scale: 1.0,
}).Do(ctx)
WithClip(&clip).
Do(ctx)
if err != nil {
return err
}
Expand Down

0 comments on commit 3ee916d

Please sign in to comment.