Skip to content
This repository was archived by the owner on Jul 30, 2018. It is now read-only.

Intersection Meta #664

Closed
wants to merge 16 commits into from
Closed

Conversation

pottedmeat
Copy link
Contributor

@pottedmeat pottedmeat commented Sep 7, 2017

Type: feature

The following has been addressed in the PR:

  • There is a related issue
  • All code matches the style guide
  • Unit or Functional tests are included in the PR

Description:

Allows for observing intersections with a root node, root margin, and intersection thresholds (passed as a second argument to get and has). Returns an object with isIntersecting and intersectionRatio.

Contains code to optionally change which intersection cause an invalidation (Within, Outside, Never, and Custom) by calling invalidateIf.

Resolves #644

@dylans dylans added this to the 2017.09 milestone Sep 7, 2017
@pottedmeat pottedmeat changed the title POC: Intersection Meta Intersection Meta Sep 8, 2017
Copy link
Member

@agubler agubler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs updating to the latest Evented meta implementation and then can give another review.

options: IntersectionGetOptions;
root: string;
rootMargin: string | undefined;
thresholds: number[]; // thresholds the observe should be attached with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can you add this as jsdoc and not an inline comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I didn't because it's a private interface.

export interface IntersectionGetOptions {
root?: string;
rootMargin?: string;
threshold?: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need threshold and thresholds? If we need a convenience of passing a single threshold, can we not just type it number | number[]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to go with thresholds and make it always number[]

private _details: IntersectionDetail[] = [];

private _getDetails(options: IntersectionGetOptions): IntersectionDetail {
let {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these all lets? Does root need a default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If thresholds is always an array, the let doesn't matter and I can allow root to be undefined in the details object.

const {
_details: details
} = this;
if (typeof threshold === 'number' && !thresholds.length) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wouldn't need this thresholds, is typed as number | number[].

Could just do:

thresholds = Array.isArray(thresholds) ? thresholds : [ thresholds ];

root === detail.root &&
rootMargin === detail.rootMargin &&
thresholds.length === detail.thresholds.length &&
thresholds.every(function(i) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I reading this wrong? is this using the threshold as an index?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this seems wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have added a test for this to ensure the same set of options doesn't create additional observers.

// Look to see if a detail record has already been created for these options
let cached: IntersectionDetail | undefined = undefined;
for (const detail of details) {
if (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can simplify this if condition some what....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of formatting or?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is pretty complicated, i'd either break these logical conditions up so each one is done individually, like:

if (options !== detail.options) {
    continue;
}

Or perhaps even better, use a different mechanism for the options caching (like a map, using the serialised options as the key)? It would look something like this:

	private _details: Map<string, IntersectionDetail> = new Map();

	private _getDetails(options: IntersectionGetOptions): IntersectionDetail {
		const cacheKey = JSON.stringify(options);
		let cached = this._details.get(cacheKey);

		if (!cached) {
			const entries = new WeakMap<Element, IntersectionObserverEntry>();
			cached = { ...options, entries };
			this._details.set(cacheKey, cached);
		}
		return cached;
	}

details.intersectionObserver = observer;
this.own({
destroy() {
observer.disconnect();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shows as uncovered in the test coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not sure why it's not getting called.

const {
intersectionRatio,
isIntersecting
} = <(IntersectionObserverEntry & { isIntersecting: boolean })> entry;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to cast like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until TypeScript is updated to include this property.

intersectionObserver?: IntersectionObserver; // attached observer
options: IntersectionGetOptions;
root: string;
rootMargin: string | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rootMargin?: string; over rootMargin: string | undefined?

@agubler agubler mentioned this pull request Sep 22, 2017
3 tasks
@pottedmeat
Copy link
Contributor Author

Closed in lieu of Ant's PR

@pottedmeat pottedmeat closed this Sep 22, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants