Skip to content

Commit

Permalink
feat(math): rectangleIntersects
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Strauß committed Apr 17, 2018
1 parent 7d82ba3 commit 2444212
Show file tree
Hide file tree
Showing 17 changed files with 136 additions and 46 deletions.
2 changes: 1 addition & 1 deletion src/animation/rendering.js
@@ -1,7 +1,7 @@
goog.module('clulib.animation.rendering');

const EventTarget = goog.require('goog.events.EventTarget');
const Event = goog.require('goog.events.Event');
const EventTarget = goog.require('goog.events.EventTarget');

/**
* A render loop which runs on requestAnimationFrame.
Expand Down
12 changes: 6 additions & 6 deletions src/cm/cm.js
@@ -1,13 +1,13 @@
goog.module('clulib.cm');

const {removeHoles, asyncForEachRight} = goog.require('clulib.array');
const Completer = goog.require('clulib.async.Completer');
const {closest, matches} = goog.require('clulib.dom');

const {removeDuplicates} = goog.require('goog.array');
const GoogComponent = goog.require('goog.ui.Component');
const {assert} = goog.require('goog.asserts');
const {getParentElement, isElement} = goog.require('goog.dom');
const GoogComponent = goog.require('goog.ui.Component');

const {removeHoles, asyncForEachRight} = goog.require('clulib.array');
const Completer = goog.require('clulib.async.Completer');
const {closest, matches} = goog.require('clulib.dom');

/**
* Component metadata.
Expand Down Expand Up @@ -793,7 +793,7 @@ class NodeTree {
while (getParentElement(element) !== rootElement) {
const parent = getParentElement(element);
if (parent.hasAttribute(this.manager_.getTypeAttribute()) &&
parent.hasAttribute(this.manager_.getIdAttribute()))
parent.hasAttribute(this.manager_.getIdAttribute()))
highestComponentElement = parent;
element = parent;
}
Expand Down
22 changes: 3 additions & 19 deletions src/dom/dom.js
Expand Up @@ -3,6 +3,8 @@ goog.module('clulib.dom');
const {getAncestor, isElement, getViewportSize} = goog.require('goog.dom');
const Rect = goog.require('goog.math.Rect');

const {rectangleIntersects} = goog.require('clulib.math');

/**
* Returns true if the element would be selected by the specified
* selector string, false otherwise.
Expand Down Expand Up @@ -72,25 +74,7 @@ function isElementVisible (element, factor = null) {
*/
const elementRect = new Rect(boundingRect.left, boundingRect.top, boundingRect.width, boundingRect.height);

/**
* @type {goog.math.Rect}
*/
const intersectionRect = Rect.intersection(viewportRect, elementRect);

// If no intersection exists or the area is zero, return false
if (intersectionRect == null || intersectionRect.getSize().area() === 0)
return false;

// If no percentage calculation is needed, return true
if (factor == null)
return true;

const elementArea = elementRect.getSize().area();
const intersectionArea = intersectionRect.getSize().area();

const visibleFactor = intersectionArea / elementArea;

return visibleFactor >= factor;
return rectangleIntersects(viewportRect, elementRect, factor);
}

exports = {matches, closest, isElementVisible};
2 changes: 1 addition & 1 deletion src/l10n/resource_bundle.js
@@ -1,8 +1,8 @@
goog.module('clulib.l10n.ResourceBundle');

const {httpGetJson} = goog.require('clulib.net.http_request');
const {objectToMap} = goog.require('clulib.collections');
const {cacheAsyncValue} = goog.require('clulib.functions');
const {httpGetJson} = goog.require('clulib.net.http_request');

/**
* A resource bundle containing localized messages.
Expand Down
33 changes: 32 additions & 1 deletion src/math/math.js
@@ -1,5 +1,7 @@
goog.module('clulib.math');

const Rect = goog.require('goog.math.Rect');

/**
* Maps a value from one range to another range.
*
Expand All @@ -14,4 +16,33 @@ function mapRange (x, inMin, inMax, outMin, outMax) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}

exports = {mapRange};
/**
* Returns true if a rectangle intersects another rectangle.
*
* Takes a factor to specify how much of rectangleB needs to intersect rectangleA.
*
* @param {goog.math.Rect} rectangleA
* @param {goog.math.Rect} rectangleB
* @param {?number|null} factor The factor from 0 (not intersecting) to 1 (completely intersecting)
* @returns {boolean}
*/
function rectangleIntersects (rectangleA, rectangleB, factor = null) {
/**
* @type {goog.math.Rect}
*/
const intersectionRect = Rect.intersection(rectangleA, rectangleB);

// If no intersection exists or the area is zero, return false
if (intersectionRect == null || intersectionRect.getSize().area() === 0)
return false;

// If no percentage calculation is needed, return true
if (factor == null)
return true;

const visibleFactor = intersectionRect.getSize().area() / rectangleB.getSize().area();

return visibleFactor >= factor;
}

exports = {mapRange, rectangleIntersects};
5 changes: 3 additions & 2 deletions src/net/http_request.js
@@ -1,11 +1,12 @@
goog.module('clulib.net.http_request');

const Completer = goog.require('clulib.async.Completer');
const events = goog.require('goog.events');
const XhrIo = goog.require('goog.net.XhrIo');
const EventType = goog.require('goog.net.EventType');
const XhrIo = goog.require('goog.net.XhrIo');
const ResponseType = goog.require('goog.net.XhrIo.ResponseType');

const Completer = goog.require('clulib.async.Completer');

/**
* @typedef {{
* response: *,
Expand Down
6 changes: 3 additions & 3 deletions src/ui/toggle_button.js
@@ -1,10 +1,10 @@
goog.module('clulib.ui.ToggleButton');

const {Component} = goog.require('clulib.cm');

const {contains, enable} = goog.require('goog.dom.classlist');
const GoogEvent = goog.require('goog.events.Event');
const GoogEventType = goog.require('goog.events.EventType');
const {contains, enable} = goog.require('goog.dom.classlist');

const {Component} = goog.require('clulib.cm');

/**
* @enum {string}
Expand Down
5 changes: 3 additions & 2 deletions test/animation/rendering_spec.js
@@ -1,9 +1,10 @@
goog.module('test.clulib.animation.rendering');

const {listen} = goog.require('goog.events');

const {RenderLoop, RenderLoopEventType} = goog.require('clulib.animation.rendering');
const {waitFor} = goog.require('testing.async');

const {listen} = goog.require('goog.events');
const {waitFor} = goog.require('testing.async');

exports = function () {
describe('clulib.animation.rendering', () => {
Expand Down
3 changes: 2 additions & 1 deletion test/array/array_spec.js
@@ -1,8 +1,9 @@
goog.module('test.clulib.array');

const {removeHoles, asyncForEach, asyncForEachRight} = goog.require('clulib.array');
const {clone} = goog.require('goog.array');

const {removeHoles, asyncForEach, asyncForEachRight} = goog.require('clulib.array');

exports = function () {
describe('clulib.array', () => {
describe('removeHoles', () => {
Expand Down
3 changes: 2 additions & 1 deletion test/async/completer_spec.js
@@ -1,8 +1,9 @@
goog.module('test.clulib.async.Completer');

const Completer = goog.require('clulib.async.Completer');
const AssertionError = goog.require('goog.asserts.AssertionError');

const Completer = goog.require('clulib.async.Completer');

exports = function () {
describe('clulib.async.Completer', () => {
it('should resolve its promise', async () => {
Expand Down
6 changes: 3 additions & 3 deletions test/cm/cm_spec.js
@@ -1,10 +1,10 @@
goog.module('test.clulib.cm');

const {ComponentManager, Component} = goog.require('clulib.cm');

const {appendChild, removeNode, getFirstElementChild} = goog.require('goog.dom');
const {contains} = goog.require('goog.dom.classlist');
const {has} = goog.require('goog.dom.dataset');
const {appendChild, removeNode, getFirstElementChild} = goog.require('goog.dom');

const {ComponentManager, Component} = goog.require('clulib.cm');

exports = function () {
describe('clulib.cm.ComponentManager', () => {
Expand Down
4 changes: 2 additions & 2 deletions test/dom/dom_spec.js
@@ -1,9 +1,9 @@
goog.module('test.clulib.dom');

const {matches, closest, isElementVisible} = goog.require('clulib.dom');

const {appendChild, removeNode, getViewportSize} = goog.require('goog.dom');

const {matches, closest, isElementVisible} = goog.require('clulib.dom');

exports = function () {
describe('clulib.dom', () => {
describe('matches', () => {
Expand Down
1 change: 1 addition & 0 deletions test/l10n/resource_bundle_spec.js
@@ -1,6 +1,7 @@
goog.module('test.clulib.l10n.ResourceBundle');

const ResourceBundle = goog.require('clulib.l10n.ResourceBundle');

const env = goog.require('testing.environment');

const base = `${env.basePath}/test-assets/l10n`;
Expand Down
1 change: 1 addition & 0 deletions test/l10n/resource_manager_spec.js
@@ -1,6 +1,7 @@
goog.module('test.clulib.l10n.ResourceManager');

const ResourceManager = goog.require('clulib.l10n.ResourceManager');

const env = goog.require('testing.environment');

const base = `${env.basePath}/test-assets/l10n`;
Expand Down
68 changes: 67 additions & 1 deletion test/math/math_spec.js
@@ -1,6 +1,9 @@
goog.module('test.clulib.math');

const {mapRange} = goog.require('clulib.math');
const Rect = goog.require('goog.math.Rect');
const Size = goog.require('goog.math.Size');

const {mapRange, rectangleIntersects} = goog.require('clulib.math');

exports = function () {
describe('clulib.math', () => {
Expand All @@ -18,5 +21,68 @@ exports = function () {
expect(mapRange(-5, -10, 0, -100, 0)).toBe(-50);
});
});

describe('rectangleIntersects', () => {
/**
* @type {goog.math.Size}
*/
const size = new Size(1024, 768);

/**
* @type {goog.math.Rect}
*/
const rectA = new Rect(0, 0, size.width, size.height);

it('should detect fully intersecting rectangles', () => {
/**
* @type {goog.math.Rect}
*/
const fullyVisible = new Rect(
size.width / 4,
size.height / 4,
size.width / 2,
size.height / 2
);

expect(rectangleIntersects(rectA, fullyVisible)).toBe(true);
expect(rectangleIntersects(rectA, fullyVisible, 1)).toBe(true);
});

it('should detect partially intersecting rectangles', () => {
const quarterVisible = new Rect(
size.width / 2,
size.height / 2,
size.width,
size.height
);

expect(rectangleIntersects(rectA, quarterVisible)).toBe(true);
expect(rectangleIntersects(rectA, quarterVisible, .23)).toBe(true);
expect(rectangleIntersects(rectA, quarterVisible, .25)).toBe(true);
expect(rectangleIntersects(rectA, quarterVisible, .26)).toBe(false);
});

it('should not detect non intersecting rectangles', () => {
const notVisible = new Rect(
0,
size.height * 2,
size.width,
size.height
);

expect(rectangleIntersects(rectA, notVisible)).toBe(false);
});

it('should not detect non intersecting rectangles on edge', () => {
const notVisibleOnEdge = new Rect(
0,
size.height,
size.width,
size.height
);

expect(rectangleIntersects(rectA, notVisibleOnEdge)).toBe(false);
});
});
});
};
6 changes: 4 additions & 2 deletions test/net/http_request_spec.js
@@ -1,9 +1,11 @@
goog.module('test.clulib.net.http_request');

const env = goog.require('testing.environment');
const http = goog.require('clulib.net.http_request');
const ErrorType = goog.require('goog.net.EventType');

const http = goog.require('clulib.net.http_request');

const env = goog.require('testing.environment');

const jsonFile = `${env.basePath}/test-assets/json/dummy.json`;
const jsonString = 'Hello, world!';

Expand Down
3 changes: 2 additions & 1 deletion test/validation/validation_spec.js
Expand Up @@ -2,9 +2,10 @@ goog.module('test.clulib.validation');

const ResponseType = goog.require('goog.net.XhrIo.ResponseType');

const http = goog.require('clulib.net.http_request');
const validation = goog.require('clulib.validation');

const {basePath} = goog.require('testing.environment');
const http = goog.require('clulib.net.http_request');

/**
* @returns {Promise<Blob>}
Expand Down

0 comments on commit 2444212

Please sign in to comment.