mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-19 06:00:56 -05:00
Fix errors in DomElement.getOffset() by using native #getBoundingClientRect() in DomElement.getBounds() and relying on that. Closes #29
This commit is contained in:
parent
e1d90c921c
commit
d84f0d34cf
3 changed files with 69 additions and 97 deletions
|
@ -14,96 +14,67 @@
|
|||
* All rights reserved.
|
||||
*/
|
||||
|
||||
var DomElement = new function() {
|
||||
function cumulateOffset(el, name, parent, test) {
|
||||
var left = name + 'Left',
|
||||
top = name + 'Top',
|
||||
x = 0,
|
||||
y = 0,
|
||||
style;
|
||||
// If we're asked to calculate positioned offset, stop at any parent
|
||||
// element that has relative or absolute position.
|
||||
while (el && el.style && (!test || !test.test(
|
||||
style = DomElement.getComputedStyle(el, 'position')))) {
|
||||
x += el[left] || 0;
|
||||
y += el[top] || 0;
|
||||
el = el[parent];
|
||||
var DomElement = {
|
||||
getBounds: function(el, viewport) {
|
||||
var rect = el.getBoundingClientRect(),
|
||||
doc = el.ownerDocument,
|
||||
body = doc.body,
|
||||
docEl = doc.documentElement,
|
||||
x = rect.left - (docEl.clientLeft || body.clientLeft || 0),
|
||||
y = rect.top - (docEl.clientTop || body.clientTop || 0);
|
||||
if (!viewport) {
|
||||
var win = DomElement.getViewport(doc);
|
||||
x += win.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
||||
y += win.pageYOffset || docEl.scrollTop || body.scrollTop;
|
||||
}
|
||||
return {
|
||||
offset: Point.create(x, y),
|
||||
element: el,
|
||||
style: style
|
||||
};
|
||||
return new Rectangle(x, y, rect.width, rect.height);
|
||||
},
|
||||
|
||||
getOffset: function(el, viewport) {
|
||||
return this.getBounds(el, viewport).getPoint();
|
||||
},
|
||||
|
||||
getSize: function(el) {
|
||||
return this.getBounds(el, true).getSize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if element is invisibile (display: none, ...)
|
||||
*/
|
||||
isInvisible: function(el) {
|
||||
return this.getSize(el).equals([0, 0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if element is visibile in current viewport
|
||||
*/
|
||||
isVisible: function(el) {
|
||||
// See if the viewport bounds intersect with the windows rectangle
|
||||
// which always starts at 0, 0
|
||||
return !this.isInvisible(el) && this.getViewportBounds(el).intersects(
|
||||
this.getBounds(el, false, true));
|
||||
},
|
||||
|
||||
getViewport: function(doc) {
|
||||
return doc.defaultView || doc.parentWindow;
|
||||
},
|
||||
|
||||
getViewportBounds: function(el) {
|
||||
var doc = el.ownerDocument,
|
||||
view = this.getViewport(doc),
|
||||
body = doc.getElementsByTagName(
|
||||
doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0];
|
||||
return Rectangle.create(0, 0,
|
||||
view.innerWidth || body.clientWidth,
|
||||
view.innerHeight || body.clientHeight
|
||||
);
|
||||
},
|
||||
|
||||
getComputedStyle: function(el, name) {
|
||||
if (el.currentStyle)
|
||||
return el.currentStyle[Base.camelize(name)];
|
||||
var style = this.getViewport(el.ownerDocument)
|
||||
.getComputedStyle(el, null);
|
||||
return style ? style.getPropertyValue(Base.hyphenate(name)) : null;
|
||||
}
|
||||
|
||||
function getScrollOffset(el, test) {
|
||||
return cumulateOffset(el, 'scroll', 'parentNode', test).offset;
|
||||
}
|
||||
|
||||
return {
|
||||
getOffset: function(el, positioned, viewport) {
|
||||
var res = cumulateOffset(el, 'offset', 'offsetParent',
|
||||
positioned ? /^(relative|absolute|fixed)$/ : /^fixed$/);
|
||||
// We need to handle fixed positioned elements seperately if we're
|
||||
// asked to calculate offsets within the page (= not within
|
||||
// viewport), by adding their scroll offset to the result.
|
||||
if (res.style == 'fixed' && !viewport)
|
||||
return res.offset.add(getScrollOffset(res.element));
|
||||
// Otherwise remove scrolling from the calculated offset if we asked
|
||||
// for viewport coordinates
|
||||
return viewport
|
||||
? res.offset.subtract(getScrollOffset(el, /^fixed$/))
|
||||
: res.offset;
|
||||
},
|
||||
|
||||
getSize: function(el) {
|
||||
return Size.create(el.offsetWidth, el.offsetHeight);
|
||||
},
|
||||
|
||||
getBounds: function(el, positioned, viewport) {
|
||||
return new Rectangle(this.getOffset(el, positioned, viewport),
|
||||
this.getSize(el));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if element is invisibile (display: none, ...)
|
||||
*/
|
||||
isInvisible: function(el) {
|
||||
return this.getSize(el).equals([0, 0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if element is visibile in current viewport
|
||||
*/
|
||||
isVisible: function(el) {
|
||||
// See if the viewport bounds intersect with the windows rectangle
|
||||
// which always starts at 0, 0
|
||||
return !this.isInvisible(el)
|
||||
&& new Rectangle([0, 0], this.getViewportSize(el))
|
||||
.intersects(this.getBounds(el, false, true));
|
||||
},
|
||||
|
||||
getViewport: function(doc) {
|
||||
return doc.defaultView || doc.parentWindow;
|
||||
},
|
||||
|
||||
getViewportSize: function(el) {
|
||||
var doc = el.ownerDocument,
|
||||
view = this.getViewport(doc),
|
||||
body = doc.getElementsByTagName(
|
||||
doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0];
|
||||
return Size.create(
|
||||
view.innerWidth || body.clientWidth,
|
||||
view.innerHeight || body.clientHeight
|
||||
);
|
||||
},
|
||||
|
||||
getComputedStyle: function(el, name) {
|
||||
if (el.currentStyle)
|
||||
return el.currentStyle[Base.camelize(name)];
|
||||
var style = this.getViewport(el.ownerDocument)
|
||||
.getComputedStyle(el, null);
|
||||
return style ? style.getPropertyValue(Base.hyphenate(name)) : null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -60,8 +60,8 @@ var DomEvent = {
|
|||
|
||||
getOffset: function(event, target) {
|
||||
// Remove target offsets from page coordinates
|
||||
return DomEvent.getPoint(event).subtract(
|
||||
DomElement.getOffset(target || DomEvent.getTarget(event), true));
|
||||
return DomEvent.getPoint(event).subtract(DomElement.getOffset(
|
||||
target || DomEvent.getTarget(event)));
|
||||
},
|
||||
|
||||
preventDefault: function(event) {
|
||||
|
|
|
@ -42,9 +42,10 @@ var View = this.View = Base.extend(/** @lends View# */{
|
|||
if (PaperScript.hasAttribute(canvas, 'resize')) {
|
||||
// Subtract canvas' viewport offset from the total size, to
|
||||
// stretch it in
|
||||
var offset = DomElement.getOffset(canvas, false, true),
|
||||
var offset = DomElement.getOffset(canvas, true),
|
||||
that = this;
|
||||
size = DomElement.getViewportSize(canvas).subtract(offset);
|
||||
size = DomElement.getViewportBounds(canvas)
|
||||
.getSize().subtract(offset);
|
||||
canvas.width = size.width;
|
||||
canvas.height = size.height;
|
||||
DomEvent.add(window, {
|
||||
|
@ -52,11 +53,11 @@ var View = this.View = Base.extend(/** @lends View# */{
|
|||
// Only update canvas offset if it's not invisible, as
|
||||
// otherwise the offset would be wrong.
|
||||
if (!DomElement.isInvisible(canvas))
|
||||
offset = DomElement.getOffset(canvas, false, true);
|
||||
offset = DomElement.getOffset(canvas, true);
|
||||
// Set the size now, which internally calls onResize
|
||||
// and redraws the view
|
||||
that.setViewSize(DomElement.getViewportSize(canvas)
|
||||
.subtract(offset));
|
||||
that.setViewSize(DomElement.getViewportBounds(canvas)
|
||||
.getSize().subtract(offset));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue