Code Monkey home page Code Monkey logo

element-resize-detector's Introduction

element-resize-detector

Optimized cross-browser resize listener for elements. Up to 37x faster than related approaches (read section 5 of the article).

npm install element-resize-detector

Usage

Include the script in the browser:

<script src="node_modules/element-resize-detector/dist/element-resize-detector.min.js"></script>

This will create a global function elementResizeDetectorMaker, which is the maker function that makes an element resize detector instance.

You can also require it like so:

var elementResizeDetectorMaker = require("element-resize-detector");

Create instance

// With default options (will use the object-based approach).
var erd = elementResizeDetectorMaker();

// With the ultra fast scroll-based approach.
// This is the recommended strategy.
var erdUltraFast = elementResizeDetectorMaker({
  strategy: "scroll" //<- For ultra performance.
});

There is also an callOnAdd option, which determines if listeners should be called when they are getting added. Default is true. If true, the listener is guaranteed to be called when it has been added. If false, the listener will not be guarenteed to be called when it has been added (does not prevent it from being called).

API

listenTo(element, listener) or listenTo(options, element, listener)

Listens to the element for resize events and calls the listener function with the element as argument on resize events. Options passed to the function will override the instance options.

Example usage:

erd.listenTo(document.getElementById("test"), function(element) {
  var width = element.offsetWidth;
  var height = element.offsetHeight;
  console.log("Size: " + width + "x" + height);
});

removeListener(element, listener)

Removes the listener from the element.

removeAllListeners(element)

Removes all listeners from the element, but does not completely remove the detector. Use this function if you may add listeners later and don't want the detector to have to initialize again.

uninstall(element)

Completely removes the detector and all listeners.

initDocument(document)

If you need to listen to elements inside another document (such as an iframe), you need to init that document with this function. Otherwise the library won't be able to detect when elements are attached to the document. So for an iframe, simpy invoke erd.initDocument(iframe.contentDocument); when the iframe is mounted on the DOM for the first time. The document from which the element resize detector instance is created will be initialized automatically. Notice that a new document is created when an iframe loads its content. So for iframes, be sure you invoke this function for each onLoad iframe event.

Caveats

  1. If the element has position: static it will be changed to position: relative. Any unintentional top/right/bottom/left/z-index styles will therefore be applied and absolute positioned children will be positioned relative to the element.
  2. A hidden element will be injected as a direct child to the element.

Credits

Big thanks to Evry sponsoring this project.

This library is using the two approaches (scroll and object) as first described at http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/.

The scroll based approach implementation was based on Marc J's implementation https://github.com/marcj/css-element-queries/blob/master/src/ResizeSensor.js.

Please note that both approaches have been heavily reworked for better performance and robustness.

Changelog

1.2.4

  • Harden onExpandScroll and onShrinkScroll handlers. See #132

1.2.3

  • Fix problems with object approach in FF. Revert #122.

1.2.2

  • Fixes scroll strategy to account for elements within shadow root. See #127.
  • Fix potential contenteditable bugs with object approach. See #122.

1.2.1

A release that includes 1.1.15 and 1.1.16 with 1.2.0.

1.2.0

  • Add new method initDocument(document) which is needed when listening to detached elements in other documents, such as iframes.
  • Add a new optional option that adds important! to most style properties, to avoid CSS overriding. Disabled by default.
  • Fix an issue with the object approach in IE8. See #95.
  • Fix uninstall issue with object approach. See #102.
  • Fixed errornous optimization that prevented scrollbar repositioning for really fast x -> y -> x resizes.

1.1.16

  • Fix bug that could happen during uninstall when waiting for unrendered objects. See #117.

1.1.15

  • ADA compliance fix for object approach. See #105.

1.1.14

  • Explicit use of window.getComputedStyle everywhere.

1.1.13

  • Only notify listeners when actual size change happened (in the rare case when multiple scroll events happens for the same resize). See #86.

1.1.12

  • Fixed an issue with embedded WebView's on Android and iOS (when getComputedStyle.width = null). See #74.
  • Fixed an issue with unrendered iframe in FireFox. See #68.

1.1.11

  • Cleaned up the development build tools.
  • Updated dev dependencies.
  • Fixed an issue when uninstalling an element, and then calling listenTo in the middle of an old resize event. See #61.

1.1.10

  • Fixed so that injected scroll elements are flex: none. See #64.
  • Fixed so that injected object element is not focusable. See #67.

1.1.9

  • Fixed uninstall issue when callOnAdd being true. Also now removing onAnimationStart listener when uninstalling. See #49.

1.1.8

  • Fixed a compatability issue with options.idHandler.get.

1.1.7

  • Fixed some rare issues with uninstalling elements while preparing/resizing.

1.1.6

  • Fixed an issue with the resize detector changing the dimensions of the target element in some browsers (e.g., IE and FireFox).

1.1.5

  • Fixed an issue with having parent elements dir=RTL.

1.1.4

  • Added extra safety styles to injected elements to make them more resilient to global CSS affecting them.

1.1.3

  • Now uninstall supports being called with elements that haven't been initialized. uninstall simply ignores non-erd elements.
  • uninstall now also supports a collection of elements.

1.1.2

  • Fixed so that uninstall may be called directly after a listenTo call.
  • Fixed a typo in the readme.
  • Fixed an invalid test.

1.1.1

  • Using window.getComputedStyle instead of relying on the method being available in the global scope. This enables this library to be used in simulated browser environments such as jsdom.

1.1.0

  • Supporting inline elements
  • Event-based solution for detecting attached/rendered events so that detached/unrendered elements can be listened to without polling
  • Now all changes that affects the offset size of an element are properly detected (such as padding and font-size).
  • Scroll is stabilized, and is the preferred strategy to use. The object strategy will be deprecated (and is currently only used for some legacy browsers such as IE9 and Opera 12).

element-resize-detector's People

Contributors

0x0d01 avatar abhsk avatar amir-hadzic avatar antontrollback avatar eliseumds avatar imcuttle avatar m59peacemaker avatar mariuszrak avatar martindoyleuk avatar mbonaci avatar mupchrch avatar nodeenthu avatar prasannavl avatar sanpochew avatar tregusti avatar valf avatar whoaa512 avatar wnr avatar wuct avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

element-resize-detector's Issues

detector <object> focusable under Firefox?

The user orbolanos commented at backalleycoder and stated that:

It looks like the created object is focusable under Firefox.
Adding the following code under addResizeListener fixes the issue.
obj.setAttribute('tabindex', '-1');

As far as I understood you are using backalleycoder's approach. Are you aware of this potential issue?

Calling uninstall too soon after calling listenTo results in an error

Calling uninstall too soon after calling listenTo results in an error:

element-resize-detector.js:969 Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.

This seems to happen because the work in listenTo has not completed yet and there doesn't seem to be any way of knowing when it's safe to call uninstall.

Failing test code:

window.onload = function() {
    var elementResizeDetector = elementResizeDetectorMaker({
        strategy: 'scroll'
    });

    elementResizeDetector.listenTo(document.querySelector('body'), console.log.bind(console));
    elementResizeDetector.uninstall(document.querySelector('body'));
}

IE8 object

Object seem do be broken on IE8 (and down?). Perhaps use the resize event instead of object fix since those legacy browsers support it.

Usage example?

Hi, I work on Chrome, and my next task is to create a native resize observer. It'll be similar to element-resize-detector.
I am currently writing a spec, and am looking for usage examples. Do you have any examples of where resize detector was needed?

PS: The scrolling trick you've used is neat. I've thought about how I'd write a polyfill, and did not come up with anything as clever.

IE11 failing

Probably doesn't like the async batch updating.

Bower support

Could you please add a bower.json to support installing with bower?

Resize detection is very flaky in RTL in Chrome and IE11

Try this in Chrome, it should add "lt" and "gte" classes to the elements for breakpoints 400 and 800.

It works some of the time, but often it does not. If you set dir="ltr" it works flawlessly.

<!DOCTYPE html>
<html dir="rtl">

<head>
    <style>
        body {
            box-sizing: border-box;
            height: 100%;
        }

        .maincontainer {
            width: 70%;
            height: 100%;
            float: left;
        }

        .sidebar {
            width: 30%;
            height: 100%;
            float: left;
        }

        .box.gte800 {
            background-color: grey;
        }

        .box.lt800.gte400 {
            background-color: lightgoldenrodyellow;
        }

        .box.lt400 {
            background-color: lightblue;
        }
    </style>
</head>

<body ng-app="cq">
    <h1>Hello Plunker!</h1>

    <div class="maincontainer">
        <box>Box1 content (70% width)</box>
        <box>Box2 content (70% width)</box>
    </div>

    <div class="sidebar">
        <box>Box3 content (30% width)</box>
        <box>Box4 content (30% width)</box>
    </div>


    <script data-require="[email protected]" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>

    <script src="https://rawgit.com/wnr/element-resize-detector/master/dist/element-resize-detector.js"></script>
    <script data-require="[email protected]" data-semver="1.5.3" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>

    <script>



angular.module('cq', [])
    .service('ElementWidthDetector', function () {
        var erd = elementResizeDetectorMaker({
            strategy: "scroll" //<- For ultra performance.
        });
        this.listenTo = erd.listenTo;
        this.removeListener = erd.removeListener;
    })

    .directive('cqBreakpoints', ['ElementWidthDetector', function (ElementWidthDetector) {
        return {
            restrict: 'A',
            scope: {
                onResize: '&',
            },
            link: function (scope, element, attrs) {
                var breakpoints = attrs.cqBreakpoints.split(' ');
                var listener = function () {
                    calculateCssClasses(element, breakpoints);
                    scope.onResize({width: element[0].offsetWidth})
                }
                ElementWidthDetector.listenTo(element, listener);
                element.on('$destroy', function () {
                    ElementWidthDetector.removeListener(element, listener);
                })
            }
        };
    }])

    .component('box', {
        template: '<div class="box" ng-transclude cq-breakpoints="400 800" on-resize="$ctrl.resized(width)"></div>',
        transclude: true,
        controller: function () {
            this.resized = function(width) {
                console.log('Box resized to: ' + width);
            };
        }
    });


// Code goes here
function calculateCssClasses(el, breakpoints) {
    var classesToRemove = breakpoints.reduce(function (a, b) { return a + ' lt' + b + ' gte' + b; }, '');
    el.removeClass(classesToRemove);
    var w = el[0].offsetWidth;

    breakpoints.forEach(function (val) {
        var b = parseFloat(val);
        if (w < b) {
            el.addClass("lt" + val);
        } else {
            el.addClass("gte" + val);
        }
    });
}
    </script>
</body>

</html>

Hidden element resize detection

Hi. We encountered an interesting issue. Where an element was activated, but it was displayed none. This causes the resize detection to not trigger if the element is shown again it looks like. Going to try and recreate in a plunker

See elqteam/elq#56

uninstall throws - Cannot read property 'busy' of undefined

When calling the uninstall method on a erd the above error is thrown.

var resizeDetectorElements = $("#uid .container").toArray();
var resizeDetector = elementResizeDetectorMaker({
     strategy: "scroll" //<- For ultra performance.
});
resizeDetector.listenTo(resizeDetectorElements, function(element) {
    // code for resize
});

*** this line throws the error ***
resizeDetector.uninstall(resizeDetectorElements);

It does not work in iOS simulator (Cordova app), should it?

Testing this library in a Cordova HTML5 application running on iOS simulator. Is it supposed to work?

Basically I scroll up and down the application/HTML with the mouse, and have also tried changing CSS properties of the target element via the JavaScript console. It does not fire the resize listener at all.

State purity in tests

I suggest creating and appending a new element for each test.. is there some magic going on that takes care of that, or are all the tests using the same DOM/state ? I have limited experience with Jasmine/Karma (I use tape), so I might be missing something. If each test is reusing the same element, I'd be glad to submit a PR to improve this. I think the Jasmine way is to use beforeEach(), though I personally prefer to skip the magic and manually call functions I need per test. Tell me what you think and I'll see if I can help.

Doesn't work in jsfiddle

I might be doing something really stupid here, but I cannot get this to work at all in JSFiddle. I'm actually trying to reproduce another problem I'm having with our prod site so I can submit an issue for that, but I can't get this library to work at all on JSFiddle.

elq-target-id

Should not contain elq information. Also, should be able to configure which id to use if element already has one.

MS Edge support?

I thought MS Edge was supported after seeing this script referenced in the comments on http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/, but it appears to be having issues using either strategy. Minimal test cases:

http://s.codepen.io/RwwL/debug/qbNamO (uses default strategy, not working in Edge with provided buttons or on window resize)

http://s.codepen.io/RwwL/debug/GoqNKd (uses scroll strategy, works in Edge on window resize but not after using the font size/padding buttons)

Maybe there's been a regression? Apologies if the mistake is in my usage or assumptions, of course.

Also possibly helpful info: working in CodePen's /pen/editors view, it appeared at first that the script wasn't working with any browser, but after checking the issues I think that may just be another occurrence of #31.

'object' strategy may throw error asynchronously

If resize-detection using the 'object' strategy is triggered on an element that is then removed from the page, line 28 in src/detection-strategy/object.js might throw an error, and it seems this error is thrown from asynchronous code, which makes catching it somewhat difficult.

In our case, it made IE11 throw up a dialog asking the end-user to debug the application :(

If this error needs to be communicated to the consumer, it should be done using a promise rejection, or perhaps a callback.

https://github.com/wnr/element-resize-detector/blob/master/src/detection-strategy/object.js#L28

ie11_-_error_when_emptying_search_string_from_non-search_mode

npm package

Hi!

It seems that latest npm version is very old, could you please update npm packages?

Uncaught TypeError: Cannot read property 'container' of undefined

I have an error when quickly adding and removing an element from DOM:

Uncaught TypeError: Cannot read property 'container' of undefined

Happens in Chrome, can't reproduce it in IE 11 or Firefox.
We use React.

Stacktrace

getExpandElement
getExpandChildElement
updateChildSizes
performUpdateChildSizes
process
processBatch

I can se that the the error happens after the element is uninstalled.

Mixed content

In Chrome Canary (53 and 54) I now get this warning for each element that has a listener for resizes:

I am using v1.1.0 and are not sending in any options to elementResizeDetectorMaker.

Using the site in stable Chrome 51 gives no such error.

onShrink attempted on undefined object

During certain manual stress tests, I ended up with the following error.

main.9f41ae4โ€ฆ.js:16 Uncaught TypeError: Cannot read property 'onShrink' of undefined

Unfortunately, it was a production system I was testing, so I just narrowed it down to this library, and the location of the minimized code looks something like this:

O(w,"scroll",function(){c(e).onShrink&&c(e).onShrink()})}

which leads to this line on the scroll detection strategy file: https://github.com/wnr/element-resize-detector/blob/master/src/detection-strategy/scroll.js#L370

So, probably a scroll event executed even the element's state is invalid. I'm unsure on when exactly that happened, due to the nature of my tests. However, I'm certain enough to file this issue (I'm using the resizer at only one point in the whole application, and it properly disposes of its resources, so its not from the app directly, but just likely just sets it up for this bug).

Scroll detection element sometimes causing page-level scrollbars

Can happen when the ERD enabled element is positioned close to the page boundaries.

Fixed by wrapping .erd_scroll_detection_container with something like this:

<div style="overflow: hidden; position: absolute; top: 0; right: 0; bottom: 0; left: 0">
  ... 
</div>

Should probably be tested that it doesn't cause new issues.

perf.html

Seem to call callback 2 times for each element.

Display: none should perhaps not be handled as a detached element.

If an element is not detached, but has width "auto" (as in the case when display:block) it could be feasible to traverse the DOM chain to fetch the first parent element that has an explicit width. This could get messy with different layout options for elements (inline vs block) etc, but could perhaps be done quite easily.

[Needs verification] scroll strategy performs bad in FireFox and IE relative to other implementations

Hello!

I've tested your plugin and there is one Problem.
Actually the "scroll" strategy is just faster in case of loading performance.
The "object" strategy is much faster in runtime.

I've created a fiddle: https://jsfiddle.net/930mvaux/4/

The first element has the object strategy and the second has the scroll strategy.
If you will start resizing both elements, you will notice how mich faster the object strategy actually is.

Maybe you have some improvements.

Best regards,
Sora

Activate on "elements in the air"

Does not work with elements that are not yet in the DOM. Would be nice to be able to activate elements so that the resize listener kicks in when the element is added to the DOM.

changes directly after listenTo calls

If dimension changes are done directly after listenTo calls then it might be that those resize events are not fired (since adding the event listener is async). This can probably be fixed by manually checking the dimensions before and after attachment of listener.

Prevent forced layouts

Right now layouts are being forced by offsetWidth and getComputedStyle(element).
The offsetWidth can be removed (since callOnAdd option exists) and getComputedStyle(element) may be changed to element.style because only position is accessed (which does not need to be computed, or does it?).

This makes the .start() call 10 times faster in bootstrap-elq.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.