Skip to content

Commit ae76e5c

Browse files
authored
Merge pull request #11 from SkalskiP/image_loading
Image loading queuing
2 parents 83da9e9 + 2923398 commit ae76e5c

File tree

6 files changed

+112
-70
lines changed

6 files changed

+112
-70
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export class ImageLoadManager {
2+
3+
private static queue: (() => Promise<any>)[] = [];
4+
private static isRunning: boolean = false;
5+
6+
public static add(fx: Promise<any>) {
7+
ImageLoadManager.queue.push(async () => await fx);
8+
}
9+
10+
public static run() {
11+
setTimeout(() => ImageLoadManager.runQueue(), 10);
12+
}
13+
14+
public static async runQueue() {
15+
if (!ImageLoadManager.isRunning) {
16+
ImageLoadManager.isRunning = true;
17+
await ImageLoadManager.runTasks();
18+
ImageLoadManager.isRunning = false;
19+
}
20+
}
21+
22+
private static async runTasks() {
23+
while (ImageLoadManager.queue.length > 0) {
24+
const fx = ImageLoadManager.queue.shift();
25+
await fx();
26+
}
27+
}
28+
}

src/utils/FileUtil.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {ImageData} from "../store/editor/types";
21
import uuidv1 from 'uuid/v1';
2+
import {ImageData} from "../store/editor/types";
33

44
export class FileUtil {
55
public static mapFileDataToImageData(fileData: File): ImageData {
@@ -12,15 +12,21 @@ export class FileUtil {
1212
}
1313
}
1414

15-
public static loadImage(fileData: File, onSuccess: (image:HTMLImageElement) => any, onFailure: () => any) {
16-
const reader = new FileReader();
17-
reader.readAsDataURL(fileData);
18-
reader.onloadend = function(evt: any) {
15+
public static loadImage(fileData: File, onSuccess: (image:HTMLImageElement) => any, onFailure: () => any): Promise<void> {
16+
return new Promise((resolve, reject) => {
17+
const url = URL.createObjectURL(fileData);
1918
const image = new Image();
20-
image.src = evt.target.result;
21-
image.onload = () => onSuccess(image);
22-
image.onerror = () => onFailure();
23-
}
19+
image.src = url;
20+
image.onload = () => {
21+
onSuccess(image);
22+
resolve();
23+
};
24+
image.onerror = () => {
25+
onFailure();
26+
reject();
27+
};
28+
})
29+
2430
}
2531

2632
public static loadLabelsList(fileData: File, onSuccess: (labels:string[]) => any, onFailure: () => any) {

src/views/EditorView/Editor/Editor.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {BaseRenderEngine} from "../../../logic/render/BaseRenderEngine";
2222
import {CustomCursorStyle} from "../../../data/CustomCursorStyle";
2323
import classNames from "classnames";
2424
import {PolygonRenderEngine} from "../../../logic/render/PolygonRenderEngine";
25+
import {ImageLoadManager} from "../../../logic/imageRepository/ImageLoadManager";
2526

2627
interface IProps {
2728
size: ISize;
@@ -61,11 +62,14 @@ class Editor extends React.Component<IProps, IState> {
6162
this.canvas.addEventListener("mousedown", this.mouseDownEventBus);
6263

6364
const {imageData, size ,activeLabelType} = this.props;
64-
this.loadImage(imageData);
65+
66+
ImageLoadManager.add(this.loadImage(imageData));
67+
6568
this.resizeCanvas(size);
6669
this.primaryRenderingEngine = new PrimaryEditorRenderEngine(this.canvas, this.imageRectOnCanvas);
6770
this.mountSupportRenderingEngine(activeLabelType);
68-
this.fullCanvasRender()
71+
this.fullCanvasRender();
72+
ImageLoadManager.run();
6973
}
7074

7175
public componentWillUnmount(): void {
@@ -76,14 +80,15 @@ class Editor extends React.Component<IProps, IState> {
7680

7781
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>, snapshot?: any): void {
7882
if (prevProps.imageData.id !== this.props.imageData.id) {
79-
this.loadImage(this.props.imageData);
83+
ImageLoadManager.add(this.loadImage(this.props.imageData));
8084
}
8185
if (prevProps.activeLabelType !== this.props.activeLabelType) {
8286
this.swapSupportRenderingEngine(this.props.activeLabelType)
8387
}
8488
this.resizeCanvas(this.props.size);
8589
this.calculateImageRect(this.state.image);
8690
this.fullCanvasRender();
91+
ImageLoadManager.run();
8792
}
8893

8994
// =================================================================================================================
@@ -115,7 +120,7 @@ class Editor extends React.Component<IProps, IState> {
115120
// LOAD IMAGE
116121
// =================================================================================================================
117122

118-
private loadImage = (imageData: ImageData) => {
123+
private loadImage = async (imageData: ImageData): Promise<any> => {
119124
if (imageData.loadStatus) {
120125
this.setState({image: ImageRepository.getById(imageData.id)})
121126
}

src/views/EditorView/EditorContainer/EditorContainer.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import React, {useState} from 'react';
2-
import './EditorContainer.scss';
3-
import {SideNavigationBar} from "../SideNavigationBar/SideNavigationBar";
2+
import {connect} from "react-redux";
43
import {Direction} from "../../../data/Direction";
5-
import {VerticalEditorButton} from "../VerticalEditorButton/VerticalEditorButton";
6-
import Editor from "../Editor/Editor";
7-
import BottomNavigationBar from "../BottomNavigationBar/BottomNavigationBar";
84
import {ISize} from "../../../interfaces/ISize";
9-
import {AppState} from "../../../store";
10-
import {connect} from "react-redux";
115
import {Settings} from "../../../settings/Settings";
6+
import {AppState} from "../../../store";
127
import {ImageData} from "../../../store/editor/types";
138
import ImagesList from "../SideNavigationBar/ImagesList/ImagesList";
149
import LabelsToolkit from "../SideNavigationBar/LabelsToolkit/LabelsToolkit";
10+
import {SideNavigationBar} from "../SideNavigationBar/SideNavigationBar";
11+
import {VerticalEditorButton} from "../VerticalEditorButton/VerticalEditorButton";
12+
import './EditorContainer.scss';
13+
import Editor from "../Editor/Editor";
14+
import BottomNavigationBar from "../BottomNavigationBar/BottomNavigationBar";
1515

1616
interface IProps {
1717
windowSize: ISize;

src/views/EditorView/SideNavigationBar/ImagePreview/ImagePreview.tsx

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1+
import classNames from "classnames";
12
import React from 'react';
2-
import './ImagePreview.scss';
3-
import {ImageData} from "../../../../store/editor/types";
3+
import {connect} from "react-redux";
44
import {ClipLoader} from "react-spinners";
5-
import {Settings} from "../../../../settings/Settings";
5+
import {ImageLoadManager} from "../../../../logic/imageRepository/ImageLoadManager";
6+
import {IRect} from "../../../../interfaces/IRect";
7+
import {ISize} from "../../../../interfaces/ISize";
68
import {ImageRepository} from "../../../../logic/imageRepository/ImageRepository";
7-
import {updateImageDataById} from "../../../../store/editor/actionCreators";
9+
import {Settings} from "../../../../settings/Settings";
810
import {AppState} from "../../../../store";
9-
import {connect} from "react-redux";
11+
import {updateImageDataById} from "../../../../store/editor/actionCreators";
12+
import {ImageData} from "../../../../store/editor/types";
1013
import {FileUtil} from "../../../../utils/FileUtil";
11-
import classNames from "classnames";
12-
import {ISize} from "../../../../interfaces/ISize";
1314
import {RectUtil} from "../../../../utils/RectUtil";
14-
import {IRect} from "../../../../interfaces/IRect";
15+
import './ImagePreview.scss';
1516

1617
interface IProps {
1718
imageData: ImageData;
@@ -40,22 +41,24 @@ class ImagePreview extends React.Component<IProps, IState> {
4041
}
4142

4243
public componentDidMount(): void {
43-
this.loadImage(this.props.imageData, this.props.isScrolling);
44+
ImageLoadManager.add(this.loadImage(this.props.imageData, this.props.isScrolling));
45+
ImageLoadManager.run();
4446
}
4547

4648
public componentWillUpdate(nextProps: Readonly<IProps>, nextState: Readonly<IState>, nextContext: any): void {
4749
if (this.props.imageData.id !== nextProps.imageData.id) {
4850
if (nextProps.imageData.loadStatus) {
49-
this.loadImage(nextProps.imageData, nextProps.isScrolling);
51+
ImageLoadManager.add(this.loadImage(nextProps.imageData, nextProps.isScrolling));
5052
}
5153
else {
5254
this.setState({image: null});
5355
}
5456
}
5557

5658
if (this.props.isScrolling && !nextProps.isScrolling) {
57-
this.loadImage(nextProps.imageData, false);
59+
ImageLoadManager.add(this.loadImage(nextProps.imageData, false));
5860
}
61+
ImageLoadManager.run();
5962
}
6063

6164
shouldComponentUpdate(nextProps: Readonly<IProps>, nextState: Readonly<IState>, nextContext: any): boolean {
@@ -67,7 +70,7 @@ class ImagePreview extends React.Component<IProps, IState> {
6770
)
6871
}
6972

70-
private loadImage = (imageData: ImageData, isScrolling: boolean) => {
73+
private loadImage = async (imageData:ImageData, isScrolling:boolean) => {
7174
if (imageData.loadStatus) {
7275
const image = ImageRepository.getById(imageData.id);
7376
if (this.state.image !== image) {
@@ -77,7 +80,7 @@ class ImagePreview extends React.Component<IProps, IState> {
7780
else if (!isScrolling || !this.isLoading) {
7881
this.isLoading = true;
7982
const saveLoadedImagePartial = (image: HTMLImageElement) => this.saveLoadedImage(image, imageData);
80-
FileUtil.loadImage(imageData.fileData, saveLoadedImagePartial, this.handleLoadImageError);
83+
await FileUtil.loadImage(imageData.fileData, saveLoadedImagePartial, this.handleLoadImageError);
8184
}
8285
};
8386

@@ -144,38 +147,38 @@ class ImagePreview extends React.Component<IProps, IState> {
144147
onClick={onClick ? onClick : undefined}
145148
>
146149
{(!!this.state.image) ?
147-
[
148-
<div
149-
className="Foreground"
150-
key={"Foreground"}
151-
style={this.getStyle()}
152-
>
153-
<img
154-
className="Image"
155-
draggable={false}
156-
src={this.state.image.src}
157-
alt={this.state.image.alt}
158-
style={{...this.getStyle(), left: 0, top: 0}}
150+
[
151+
<div
152+
className="Foreground"
153+
key={"Foreground"}
154+
style={this.getStyle()}
155+
>
156+
<img
157+
className="Image"
158+
draggable={false}
159+
src={this.state.image.src}
160+
alt={this.state.image.alt}
161+
style={{...this.getStyle(), left: 0, top: 0}}
162+
/>
163+
{isChecked && <img
164+
className="CheckBox"
165+
draggable={false}
166+
src={"ico/checkbox-checked-color.png"}
167+
alt={"checkbox"}
168+
/>}
169+
</div>,
170+
<div
171+
className="Background"
172+
key={"Background"}
173+
style={this.getStyle()}
159174
/>
160-
{isChecked && <img
161-
className="CheckBox"
162-
draggable={false}
163-
src={"ico/checkbox-checked-color.png"}
164-
alt={"checkbox"}
165-
/>}
166-
</div>,
167-
<div
168-
className="Background"
169-
key={"Background"}
170-
style={this.getStyle()}
171-
/>
172-
] :
173-
<ClipLoader
174-
sizeUnit={"px"}
175-
size={30}
176-
color={Settings.SECONDARY_COLOR}
177-
loading={true}
178-
/>}
175+
] :
176+
<ClipLoader
177+
sizeUnit={"px"}
178+
size={30}
179+
color={Settings.SECONDARY_COLOR}
180+
loading={true}
181+
/>}
179182
</div>)
180183
}
181184
}

src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import React from 'react';
2+
import {connect} from "react-redux";
3+
import {LabelType} from "../../../../data/LabelType";
24
import {ISize} from "../../../../interfaces/ISize";
3-
import './ImagesList.scss';
4-
import {VirtualList} from "../../../Common/VirtualList/VirtualList";
5-
import {ImageData} from "../../../../store/editor/types";
65
import {AppState} from "../../../../store";
7-
import {connect} from "react-redux";
8-
import ImagePreview from "../ImagePreview/ImagePreview";
96
import {updateActiveImageIndex, updateActiveLabelId} from "../../../../store/editor/actionCreators";
10-
import {LabelType} from "../../../../data/LabelType";
7+
import {ImageData} from "../../../../store/editor/types";
8+
import {VirtualList} from "../../../Common/VirtualList/VirtualList";
9+
import ImagePreview from "../ImagePreview/ImagePreview";
10+
import './ImagesList.scss';
1111

1212
interface IProps {
1313
activeImageIndex: number;

0 commit comments

Comments
 (0)