Skip to content

Commit

Permalink
Merge pull request #11 from SkalskiP/image_loading
Browse files Browse the repository at this point in the history
Image loading queuing
  • Loading branch information
SkalskiP authored Aug 7, 2019
2 parents 83da9e9 + 2923398 commit ae76e5c
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 70 deletions.
28 changes: 28 additions & 0 deletions src/logic/imageRepository/ImageLoadManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export class ImageLoadManager {

private static queue: (() => Promise<any>)[] = [];
private static isRunning: boolean = false;

public static add(fx: Promise<any>) {
ImageLoadManager.queue.push(async () => await fx);
}

public static run() {
setTimeout(() => ImageLoadManager.runQueue(), 10);
}

public static async runQueue() {
if (!ImageLoadManager.isRunning) {
ImageLoadManager.isRunning = true;
await ImageLoadManager.runTasks();
ImageLoadManager.isRunning = false;
}
}

private static async runTasks() {
while (ImageLoadManager.queue.length > 0) {
const fx = ImageLoadManager.queue.shift();
await fx();
}
}
}
24 changes: 15 additions & 9 deletions src/utils/FileUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ImageData} from "../store/editor/types";
import uuidv1 from 'uuid/v1';
import {ImageData} from "../store/editor/types";

export class FileUtil {
public static mapFileDataToImageData(fileData: File): ImageData {
Expand All @@ -12,15 +12,21 @@ export class FileUtil {
}
}

public static loadImage(fileData: File, onSuccess: (image:HTMLImageElement) => any, onFailure: () => any) {
const reader = new FileReader();
reader.readAsDataURL(fileData);
reader.onloadend = function(evt: any) {
public static loadImage(fileData: File, onSuccess: (image:HTMLImageElement) => any, onFailure: () => any): Promise<void> {
return new Promise((resolve, reject) => {
const url = URL.createObjectURL(fileData);
const image = new Image();
image.src = evt.target.result;
image.onload = () => onSuccess(image);
image.onerror = () => onFailure();
}
image.src = url;
image.onload = () => {
onSuccess(image);
resolve();
};
image.onerror = () => {
onFailure();
reject();
};
})

}

public static loadLabelsList(fileData: File, onSuccess: (labels:string[]) => any, onFailure: () => any) {
Expand Down
13 changes: 9 additions & 4 deletions src/views/EditorView/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {BaseRenderEngine} from "../../../logic/render/BaseRenderEngine";
import {CustomCursorStyle} from "../../../data/CustomCursorStyle";
import classNames from "classnames";
import {PolygonRenderEngine} from "../../../logic/render/PolygonRenderEngine";
import {ImageLoadManager} from "../../../logic/imageRepository/ImageLoadManager";

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

const {imageData, size ,activeLabelType} = this.props;
this.loadImage(imageData);

ImageLoadManager.add(this.loadImage(imageData));

this.resizeCanvas(size);
this.primaryRenderingEngine = new PrimaryEditorRenderEngine(this.canvas, this.imageRectOnCanvas);
this.mountSupportRenderingEngine(activeLabelType);
this.fullCanvasRender()
this.fullCanvasRender();
ImageLoadManager.run();
}

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

public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>, snapshot?: any): void {
if (prevProps.imageData.id !== this.props.imageData.id) {
this.loadImage(this.props.imageData);
ImageLoadManager.add(this.loadImage(this.props.imageData));
}
if (prevProps.activeLabelType !== this.props.activeLabelType) {
this.swapSupportRenderingEngine(this.props.activeLabelType)
}
this.resizeCanvas(this.props.size);
this.calculateImageRect(this.state.image);
this.fullCanvasRender();
ImageLoadManager.run();
}

// =================================================================================================================
Expand Down Expand Up @@ -115,7 +120,7 @@ class Editor extends React.Component<IProps, IState> {
// LOAD IMAGE
// =================================================================================================================

private loadImage = (imageData: ImageData) => {
private loadImage = async (imageData: ImageData): Promise<any> => {
if (imageData.loadStatus) {
this.setState({image: ImageRepository.getById(imageData.id)})
}
Expand Down
14 changes: 7 additions & 7 deletions src/views/EditorView/EditorContainer/EditorContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React, {useState} from 'react';
import './EditorContainer.scss';
import {SideNavigationBar} from "../SideNavigationBar/SideNavigationBar";
import {connect} from "react-redux";
import {Direction} from "../../../data/Direction";
import {VerticalEditorButton} from "../VerticalEditorButton/VerticalEditorButton";
import Editor from "../Editor/Editor";
import BottomNavigationBar from "../BottomNavigationBar/BottomNavigationBar";
import {ISize} from "../../../interfaces/ISize";
import {AppState} from "../../../store";
import {connect} from "react-redux";
import {Settings} from "../../../settings/Settings";
import {AppState} from "../../../store";
import {ImageData} from "../../../store/editor/types";
import ImagesList from "../SideNavigationBar/ImagesList/ImagesList";
import LabelsToolkit from "../SideNavigationBar/LabelsToolkit/LabelsToolkit";
import {SideNavigationBar} from "../SideNavigationBar/SideNavigationBar";
import {VerticalEditorButton} from "../VerticalEditorButton/VerticalEditorButton";
import './EditorContainer.scss';
import Editor from "../Editor/Editor";
import BottomNavigationBar from "../BottomNavigationBar/BottomNavigationBar";

interface IProps {
windowSize: ISize;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import classNames from "classnames";
import React from 'react';
import './ImagePreview.scss';
import {ImageData} from "../../../../store/editor/types";
import {connect} from "react-redux";
import {ClipLoader} from "react-spinners";
import {Settings} from "../../../../settings/Settings";
import {ImageLoadManager} from "../../../../logic/imageRepository/ImageLoadManager";
import {IRect} from "../../../../interfaces/IRect";
import {ISize} from "../../../../interfaces/ISize";
import {ImageRepository} from "../../../../logic/imageRepository/ImageRepository";
import {updateImageDataById} from "../../../../store/editor/actionCreators";
import {Settings} from "../../../../settings/Settings";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import {updateImageDataById} from "../../../../store/editor/actionCreators";
import {ImageData} from "../../../../store/editor/types";
import {FileUtil} from "../../../../utils/FileUtil";
import classNames from "classnames";
import {ISize} from "../../../../interfaces/ISize";
import {RectUtil} from "../../../../utils/RectUtil";
import {IRect} from "../../../../interfaces/IRect";
import './ImagePreview.scss';

interface IProps {
imageData: ImageData;
Expand Down Expand Up @@ -40,22 +41,24 @@ class ImagePreview extends React.Component<IProps, IState> {
}

public componentDidMount(): void {
this.loadImage(this.props.imageData, this.props.isScrolling);
ImageLoadManager.add(this.loadImage(this.props.imageData, this.props.isScrolling));
ImageLoadManager.run();
}

public componentWillUpdate(nextProps: Readonly<IProps>, nextState: Readonly<IState>, nextContext: any): void {
if (this.props.imageData.id !== nextProps.imageData.id) {
if (nextProps.imageData.loadStatus) {
this.loadImage(nextProps.imageData, nextProps.isScrolling);
ImageLoadManager.add(this.loadImage(nextProps.imageData, nextProps.isScrolling));
}
else {
this.setState({image: null});
}
}

if (this.props.isScrolling && !nextProps.isScrolling) {
this.loadImage(nextProps.imageData, false);
ImageLoadManager.add(this.loadImage(nextProps.imageData, false));
}
ImageLoadManager.run();
}

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

private loadImage = (imageData: ImageData, isScrolling: boolean) => {
private loadImage = async (imageData:ImageData, isScrolling:boolean) => {
if (imageData.loadStatus) {
const image = ImageRepository.getById(imageData.id);
if (this.state.image !== image) {
Expand All @@ -77,7 +80,7 @@ class ImagePreview extends React.Component<IProps, IState> {
else if (!isScrolling || !this.isLoading) {
this.isLoading = true;
const saveLoadedImagePartial = (image: HTMLImageElement) => this.saveLoadedImage(image, imageData);
FileUtil.loadImage(imageData.fileData, saveLoadedImagePartial, this.handleLoadImageError);
await FileUtil.loadImage(imageData.fileData, saveLoadedImagePartial, this.handleLoadImageError);
}
};

Expand Down Expand Up @@ -144,38 +147,38 @@ class ImagePreview extends React.Component<IProps, IState> {
onClick={onClick ? onClick : undefined}
>
{(!!this.state.image) ?
[
<div
className="Foreground"
key={"Foreground"}
style={this.getStyle()}
>
<img
className="Image"
draggable={false}
src={this.state.image.src}
alt={this.state.image.alt}
style={{...this.getStyle(), left: 0, top: 0}}
[
<div
className="Foreground"
key={"Foreground"}
style={this.getStyle()}
>
<img
className="Image"
draggable={false}
src={this.state.image.src}
alt={this.state.image.alt}
style={{...this.getStyle(), left: 0, top: 0}}
/>
{isChecked && <img
className="CheckBox"
draggable={false}
src={"ico/checkbox-checked-color.png"}
alt={"checkbox"}
/>}
</div>,
<div
className="Background"
key={"Background"}
style={this.getStyle()}
/>
{isChecked && <img
className="CheckBox"
draggable={false}
src={"ico/checkbox-checked-color.png"}
alt={"checkbox"}
/>}
</div>,
<div
className="Background"
key={"Background"}
style={this.getStyle()}
/>
] :
<ClipLoader
sizeUnit={"px"}
size={30}
color={Settings.SECONDARY_COLOR}
loading={true}
/>}
] :
<ClipLoader
sizeUnit={"px"}
size={30}
color={Settings.SECONDARY_COLOR}
loading={true}
/>}
</div>)
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import {connect} from "react-redux";
import {LabelType} from "../../../../data/LabelType";
import {ISize} from "../../../../interfaces/ISize";
import './ImagesList.scss';
import {VirtualList} from "../../../Common/VirtualList/VirtualList";
import {ImageData} from "../../../../store/editor/types";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import ImagePreview from "../ImagePreview/ImagePreview";
import {updateActiveImageIndex, updateActiveLabelId} from "../../../../store/editor/actionCreators";
import {LabelType} from "../../../../data/LabelType";
import {ImageData} from "../../../../store/editor/types";
import {VirtualList} from "../../../Common/VirtualList/VirtualList";
import ImagePreview from "../ImagePreview/ImagePreview";
import './ImagesList.scss';

interface IProps {
activeImageIndex: number;
Expand Down

0 comments on commit ae76e5c

Please sign in to comment.