Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace font loader with a resize event in reflow and scroll view #308

Conversation

olivierkorner
Copy link
Contributor

This pull request is a Work In Progress

Related issue(s) and/or pull request(s)

#304
#300

Additional information

This is intended as a fix for the font loader that doesn't as expected when there's no support for a native font loading API. But it might be useful when for some reason the layout of the chapter displayed changes (element becomes visible, remote content loaded, etc.)

Inspiration came from FontLoader itself, which watches for a scroll event to detect a div containing some text has been resized, due to the font substitution.
The method is documented in following article:
http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/

Applied here, the idea is to detect when the size of the body element in a reflowable iframe has changed and when this happens, to trigger an update of the pagination by calling updatePagination.

Some optimization is probably possible, since updatePagination is called anyway when new settings are applied or when the viewport is resized.

Feeback welcome!

@olivierkorner
Copy link
Contributor Author

Tested on iOS, OS X, Chrome, Firefox and Edge.

function(Globals, $, _, EventEmitter, BookmarkData, CfiNavigationLogic,
CurrentPagesInfo, Helpers, PageOpenRequest,
ViewerSettings, FontLoader) {
ViewerSettings, ResizeSensor) {
/**
Copy link
Member

Choose a reason for hiding this comment

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

In this PR, the removal of FontLoader (native and polyfill) means that we can also remove the NPM dependency, right?
https://github.com/readium/readium-shared-js/blob/develop/package.cson#L126
"FontLoader": 'smnh/FontLoader'

Copy link
Member

Choose a reason for hiding this comment

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

Oh, and of course the class file itself can be removed: https://github.com/readium/readium-shared-js/blob/develop/js/views/font_loader.js

The bookmark is updated every time the pagination changes (in onPaginationChanged).
If there's no deferred page request, at the end of updatePagination,
openPage is called with the bookmark's CFI so whenever viewport is resized or
a font is changed or loaded and the pagination changes, the reader stays on the
same page.
In ReaderView, after a viewport resize, the reader doesn't try to jump to the
bookmark saved at the start of the resize, as it is now handled directly by the
ReflowableView.
@olivierkorner
Copy link
Contributor Author

@danielweck Indeed, I removed the FontLoader depencencies.

I mentioned in a call that I was concerned that any change of the size, triggered by a change of the font size or the font family, or by any other cause actually, could push the visible page out the screen. To prevent this, I think we need to proactively keep a bookmark to the last known position, updated every time the user goes to a previous or next page, to a bookmark or to a target of the table of contents.

I implemented this approach in the ReflowView (Add "last position" commit f933ee2). It is not very accurate and it tends to drift to the beginning of the chapter every time it is used, maybe because the bookmarkCurrentPage method uses getFirstVisibleCfi.
Maybe it could be refined by using the CFI of an element in the middle of the visible range.

Last point, I implemented the resize sensor in the ScrollView (see #312). I removed the method reachStableContentHeight, as the resize sensor does a better job at tracking the content height.

@olivierkorner olivierkorner changed the title Replace font loader with a resize event on body of iframe in reflow view Replace font loader with a resize event in reflow and scroll view Sep 7, 2016
@rkwright
Copy link
Member

rkwright commented Sep 7, 2016

@olivierkorner I think this is a good change to make anyway.

@danielweck
Copy link
Member

TODO: ResizeSensor throttle or debounce to avoid flooding the event listeners that (or example) re-layout the stack of iframes in the continuous scroll view.

@danielweck
Copy link
Member

TODO: check that Media Overlays playback pause/resume behaviour is not affected by different CFI bookmark logic.

@danielweck
Copy link
Member

TODO: check that the CFI current reading location does not drift when restoring following a change of font size, etc. Top-left corner (first visible CFI) cause drift, better to preserve the original CFI even it is now located in the "middle" of a page spread.

@danielweck
Copy link
Member

TODO: extract the "resize sensor" JS code as an NPM dependency:
https://github.com/readium/readium-shared-js/pull/308/files#diff-7dd565756df0e649fea57f65acf40369
The original source is at https://github.com/marcj/css-element-queries/blob/master/src/ResizeSensor.js

Let's also consider this optimized version (still uses scroll detection, as based on the above JS lib):
https://github.com/wnr/element-resize-detector

Just for reference, these alternatives are getting old now (unmaintained), compared to the above:
https://github.com/procurios/ResizeSensor
https://github.com/flowkey/resize-sensor

@olivierkorner
Copy link
Contributor Author

@danielweck Actually, the ResizeSensor class in the PR is slightly different from the one in marcj/css-element-queries. I had to fix it a flaw that would cause some function to be called repeatedly after a resize has occured.

@danielweck
Copy link
Member

danielweck commented Sep 8, 2016

Great, so let's fork https://github.com/marcj/css-element-queries/blob/master/src/ResizeSensor.js (at https://github.com/danielweck/css-element-queries to follow the current convention), and let's add this new NPM dependency to:
https://github.com/readium/readium-shared-js/blob/master/package.cson#L102
as

    "css-element-queries": 'danielweck/css-element-queries'

...and then let's configure the RequireJS config:
https://github.com/readium/readium-shared-js/blob/master/build-config/RequireJS_config_common.js#L28

        ResizeSensor:
            process._RJS_rootDir(1) + '/node_modules/css-element-queries/src/ResizeSensor.js',

...and of course change the RequireJS function signatures (dependency injection) from "./resize_sensor" to "ResizeSensor".

Whenever openPage() is called in ReflowView, the pageRequest is saved.
After content is resized (font has changed or viewport has been resized),
we go back to the saved pageRequest.
If the user goes to next or previous page, the saved pageRequest is ditched
and we save the current position in a new pageRequest.
@danielweck
Copy link
Member

Thanks @olivierkorner for extracting the NPM dependency. I logged a global issue here: readium/readium-js-viewer#565 (comment)

@danielweck
Copy link
Member

Resize Sensor diff in our fork: marcj/css-element-queries@master...olivierkorner:master

@olivierkorner olivierkorner merged commit 9f9c6ec into readium:develop Oct 4, 2016
@danielweck
Copy link
Member

danielweck commented Oct 16, 2016

ToDo: test "dynamic content sizes".
readium/architecture#11 (comment)

EDIT: done. Works just fine in reflow and scroll views.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants