Skip to content

Commit 40620b5

Browse files
author
Christian Natis
committed
Fix scroll bar positions in clones
1 parent de9693a commit 40620b5

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ Set to true to append the current time as a query string to URL requests to enab
155155

156156
A data URL for a placeholder image that will be used when fetching an image fails. Defaults to undefined and will throw an error on failed images
157157

158+
#### scrollFix
159+
160+
Set to true to have the resulting image take into account scroll positioning, this will be done by making the scroll container position relative, and then positioning the children absolutely based on the scroll position of the container and the height of the preceding children. Because this works with absolute and relative positioning there is a chance that it may not work as intended for you and is a experimental feature for now. Defaults to false
161+
158162
## Browsers
159163

160164
It's tested on latest Chrome and Firefox (49 and 45 respectively at the time

src/dom-to-image.js

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
// Default is to fail on error, no placeholder
1212
imagePlaceholder: undefined,
1313
// Default cache bust is false, it will use the cache
14-
cacheBust: false
14+
cacheBust: false,
15+
// Default scroll fix is false, it will not try to fix scrollbars
16+
scrollFix: false
1517
};
1618

1719
var domtoimage = {
@@ -147,6 +149,12 @@
147149
} else {
148150
domtoimage.impl.options.cacheBust = options.cacheBust;
149151
}
152+
153+
if(typeof(options.scrollFix) === 'undefined') {
154+
domtoimage.impl.options.scrollFix = defaultOptions.scrollFix;
155+
} else {
156+
domtoimage.impl.options.scrollFix = options.scrollFix;
157+
}
150158
}
151159

152160
function draw(domNode, options) {
@@ -244,6 +252,81 @@
244252
});
245253
}
246254
}
255+
256+
if(domtoimage.impl.options.scrollFix &&
257+
(original.scrollTop || original.scrollLeft)) {
258+
// Setup container for absolute positioning of children
259+
clone.style.position = 'relative';
260+
clone.style.overflow = 'hidden';
261+
clone.style.width = original.offsetWidth + 'px';
262+
clone.style.height = original.offsetHeight + 'px';
263+
var scrollTopRemaining = original.scrollTop > 0 ? original.scrollTop : null;
264+
var scrollLeftRemaining = original.scrollLeft > 0 ? original.scrollLeft : null;
265+
var originalOffsetTop = original.offsetTop;
266+
var originalOffsetLeft = original.offsetLeft;
267+
268+
var childTop, childTop2, childLeft, childLeft2, isStackingLeft, isStackingTop;
269+
// Loop through children and set position based on original
270+
// childs position and original contains scroll position
271+
for(var i = 0; i < clone.children.length; i++) {
272+
// Make sure this element is stylable
273+
if(typeof(clone.children[i]) === 'undefined' ||
274+
clone.children[i] === null ||
275+
typeof(clone.children[i].style) === 'undefined') {
276+
277+
continue;
278+
}
279+
280+
// Set child to absolute positioning relative to parent (container)
281+
clone.children[i].style.position = 'absolute';
282+
if(typeof(original.children[i - 1]) !== 'undefined') {
283+
childTop = original.children[i - 1].offsetTop;
284+
childTop2 = original.children[i].offsetTop;
285+
286+
childLeft = original.children[i - 1].offsetLeft;
287+
childLeft2 = original.children[i].offsetLeft;
288+
289+
// isStackingLeft is true when elements are being displayed inline
290+
isStackingLeft = childLeft !== childLeft2;
291+
// isStackingLeft is true when elements are being displayed block
292+
isStackingTop = childTop !== childTop2;
293+
294+
if(scrollTopRemaining && isStackingTop) {
295+
// Subtract the previous child's height from the scroll top
296+
// so that our current child will display underneath it
297+
scrollTopRemaining -= original.children[i - 1].offsetHeight;
298+
}
299+
if(scrollLeftRemaining && isStackingLeft) {
300+
// Subtract the previous child's width from the scroll left
301+
// so that our current child will display beside it
302+
scrollLeftRemaining -= original.children[i - 1].offsetWidth;
303+
}
304+
}
305+
306+
307+
if(scrollTopRemaining) {
308+
clone.children[i].style.top = -scrollTopRemaining + 'px';
309+
}
310+
else {
311+
// We don't have a scroll top, but we still need to set
312+
// the top positioning so that our absolute elements don't
313+
// appear overlapping vertically
314+
childTop2 = original.children[i].offsetTop;
315+
clone.children[i].style.top = (childTop2 - originalOffsetTop) + 'px';
316+
}
317+
318+
if(scrollLeftRemaining) {
319+
clone.children[i].style.left = -scrollLeftRemaining + 'px';
320+
}
321+
else {
322+
// We don't have a scroll left, but we still need to set
323+
// the left positioning so that our absolute elements don't
324+
// appear overlapping horizontally
325+
childLeft2 = original.children[i].offsetLeft;
326+
clone.children[i].style.left = (childLeft2 - originalOffsetLeft) + 'px';
327+
}
328+
}
329+
}
247330
}
248331

249332
function clonePseudoElements() {

0 commit comments

Comments
 (0)