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

Batched the getBoundingClientRect and style changes and added an IntersectionObserver #957

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class PageInternal extends PureComponent {
onGetAnnotationsSuccess,
onGetTextError,
onGetTextSuccess,
useObserverAlignText,
onRenderAnnotationLayerError,
onRenderAnnotationLayerSuccess,
onRenderError,
Expand All @@ -96,6 +97,7 @@ export class PageInternal extends PureComponent {
onGetAnnotationsSuccess,
onGetTextError,
onGetTextSuccess,
useObserverAlignText,
onRenderAnnotationLayerError,
onRenderAnnotationLayerSuccess,
onRenderError,
Expand Down Expand Up @@ -397,6 +399,7 @@ PageInternal.propTypes = {
rotate: isRotate,
scale: PropTypes.number,
unregisterPage: PropTypes.func,
useObserverAlignText : PropTypes.bool,
width: PropTypes.number,
};

Expand Down
63 changes: 62 additions & 1 deletion src/Page/TextLayer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export class TextLayerInternal extends PureComponent {
textItems: null,
};

constructor(props) {
super(props)

this.refTextItems = React.createRef()
this.countLoadedItem = 0
}

componentDidMount() {
const { page } = this.props;

Expand Down Expand Up @@ -52,13 +59,56 @@ export class TextLayerInternal extends PureComponent {
});
};

observer = new IntersectionObserver((entries) => {
const { sideways } = this;

let width = 0;
for (const entry of entries) {
width = entry.boundingClientRect[sideways ? 'height' : 'width'];
if(width > 0){
this.refTextItems.current[entry.target.i].updatedWidth(width).alignTextItem()
}
}
this.observer.disconnect();
});

onLoadSuccess = () => {
const { onGetTextSuccess } = this.props;
const { onGetTextSuccess, useObserverAlignText} = this.props;
const { textItems } = this.state;

if(useObserverAlignText){
for(let i = 0; i < this.refTextItems.current.length; i++){
let entry = this.refTextItems.current[i]
if(entry.props.str.length > 0){
entry.item.i = i
this.observer.observe(entry.item)
}
}
}
if (onGetTextSuccess) onGetTextSuccess(textItems);
};

onLoadSuccessAlignTextItem = async() => {
if(this.countLoadedItem < this.refTextItems.current.length){
this.countLoadedItem++;
}
if(this.refTextItems.current.length === this.countLoadedItem){
let indexUpdate = [];
requestAnimationFrame(() => {
for(let i = 0; i < this.refTextItems.current.length; i++){
if(this.refTextItems.current[i].updateElementWidth()){
indexUpdate.push(i);
}
}
if(indexUpdate.length > 0){
for(let i = 0; i < indexUpdate.length; i++){
this.refTextItems.current[indexUpdate[i]].alignTextItem();
}
}
});
}
}

onLoadError = (error) => {
this.setState({ textItems: false });

Expand All @@ -84,19 +134,30 @@ export class TextLayerInternal extends PureComponent {
return rotate - page.rotate;
}

get sideways() {
const { rotate } = this;
return rotate % 180 !== 0;
}

renderTextItems() {
const { textItems } = this.state;

if (!textItems) {
this.refTextItems.current = []
return null;
}

let i = -1
this.countLoadedItem = 0
this.refTextItems.current = new Array(textItems.length)
return textItems.map((textItem, itemIndex) => (
<TextLayerItem
ref={(ref) => this.refTextItems.current[++i] = ref}
// eslint-disable-next-line react/no-array-index-key
key={itemIndex}
itemIndex={itemIndex}
{...textItem}
onLoadSuccessAlignTextItem={!this.props.useObserverAlignText ? this.onLoadSuccessAlignTextItem : function(){ return }}
/>
));
}
Expand Down
90 changes: 77 additions & 13 deletions src/Page/TextLayerItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { isPage, isRotate } from '../shared/propTypes';

export class TextLayerItemInternal extends PureComponent {
componentDidMount() {
this.alignTextItem();
this.initTextItem();
}

componentDidUpdate() {
this.alignTextItem();
this.initTextItem();
}

get unrotatedViewport() {
Expand Down Expand Up @@ -71,7 +71,70 @@ export class TextLayerItemInternal extends PureComponent {
});
}

alignTextItem() {
initTextItem = () => {
const element = this.item;

if (!element) {
this.props.onLoadSuccessAlignTextItem()
return;
}

if(!this.fontFamily && this.props.str.length > 0){
this.fontFamily = element.style.fontFamily
this.loadTextItem()
} else {
this.props.onLoadSuccessAlignTextItem()
}
}

loadTextItem = async() => {
const element = this.item;
const { fontName } = this.props;

let fontData = await this.getFontData(fontName)
const fallbackFontName = fontData ? fontData.fallbackName : 'sans-serif';

this.fontFamily = `${fontName}, ${fallbackFontName}`;
this.ascent = fontData ? fontData.ascent : 0;
if(this.fontFamily !== element.style.fontFamily){
element.style.fontFamily = this.fontFamily
}
this.props.onLoadSuccessAlignTextItem()
}

updateElementWidth = () => {
const element = this.item;
if(element){
let actualWidth = this.getElementWidth(element);

if(this.actualWidth !== actualWidth && actualWidth > 0){
this.actualWidth = actualWidth
return true
}
}
return false
}

updatedWidth = (width) => {
this.actualWidth = width
return this
}

alignTextItem = async() => {
const element = this.item;
const { scale, width } = this.props;

const targetWidth = width * scale;
let transform = `scaleX(${targetWidth / this.actualWidth})`;

if (this.ascent) {
transform += ` translateY(${(1 - this.ascent) * 100}%)`;
}
element.style.transform = transform;
element.style.WebkitTransform = transform;
}

/* alignTextItem() {
const element = this.item;

if (!element) {
Expand Down Expand Up @@ -101,15 +164,15 @@ export class TextLayerItemInternal extends PureComponent {
element.style.transform = transform;
element.style.WebkitTransform = transform;
});
}
}*/

getElementWidth = (element) => {
const { sideways } = this;
return element.getBoundingClientRect()[sideways ? 'height' : 'width'];
};

render() {
const { fontSize, top, left } = this;
const { fontName, fontSize, top, left } = this;
const { customTextRenderer, scale, str: text } = this.props;

return (
Expand All @@ -119,7 +182,7 @@ export class TextLayerItemInternal extends PureComponent {
}}
style={{
height: '1em',
fontFamily: 'sans-serif',
fontFamily: `${fontName}, sans-serif`,
fontSize: `${fontSize * scale}px`,
position: 'absolute',
top: `${top * scale}px`,
Expand All @@ -140,17 +203,18 @@ TextLayerItemInternal.propTypes = {
fontName: PropTypes.string.isRequired,
itemIndex: PropTypes.number.isRequired,
page: isPage.isRequired,
onLoadSuccessAlignTextItem: PropTypes.func.isRequired,
rotate: isRotate,
scale: PropTypes.number,
str: PropTypes.string.isRequired,
transform: PropTypes.arrayOf(PropTypes.number).isRequired,
width: PropTypes.number.isRequired,
};

export default function TextLayerItem(props) {
return (
<PageContext.Consumer>
{(context) => <TextLayerItemInternal {...context} {...props} />}
</PageContext.Consumer>
);
}
const TextLayerItem = React.forwardRef((props, ref) => (
<PageContext.Consumer>
{(context) => <TextLayerItemInternal ref={ref} {...context} {...props} />}
</PageContext.Consumer>
));

export default TextLayerItem