From 3ee916d51592d3e06e3ad5104081537d272659b7 Mon Sep 17 00:00:00 2001 From: Zeke Lu Date: Tue, 15 Jun 2021 16:49:08 +0800 Subject: [PATCH] screenshot: get node's position relative to its document Before this change, it's relative to the viewport. So it will get the wrong position if the page scrolls. Fixes #844. --- js.go | 5 +++++ js/getClientRect.js | 10 ++++++++++ query.go | 25 ++++++++----------------- 3 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 js/getClientRect.js diff --git a/js.go b/js.go index a2ca228b..191e8351 100644 --- a/js.go +++ b/js.go @@ -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 diff --git a/js/getClientRect.js b/js/getClientRect.js new file mode 100644 index 00000000..ecce1e76 --- /dev/null +++ b/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, + }; +} diff --git a/query.go b/query.go index 7e0900ed..2eb22fa5 100644 --- a/query.go +++ b/query.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "math" "strconv" "strings" "sync" @@ -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 }