components/ProfileEdit/ProfileEditForm/ProfileEditFormAvatar/ProfileEditFormAvatar.jsx

/**
 * Попап редактирования профиля
 * @module ProfileEdit
 * @author Ihor Bielchenko
 * @requires react
 * @requires react#Component
 * @requires redux#bindActionCreators
 * @requires react-redux
 * @requires actions/StateConfigAction.js
 * @requires actions/StateUserAction.js
 * @requires img/loader.gif
 */

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as StateUserAction from '../../../../actions/StateUserAction.js';
import * as StateConfigAction from '../../../../actions/StateConfigAction.js';
import Loader from '../../../../img/loader.gif';

/**
 * Компонент таблицы конкретной группы на странице учителя
 * @extends Component
 */
class ProfileEditFormAvatar extends Component {

	/**
	 * Загрузка аватара в браузере 
	 * @fires onChange
	 * @param {Object} e
	 */
	upload(e) {
		let self = this;

		/** Лоадер загрузки аватара
		 */
		self.props.StateConfigAction.avatarLoader(self.props.config);
		let file = e.target.files[0];

		/** Загрузка 90x90
		 */
		self.readFiles(file, 90, 90, (canvas) => {
			let ava90x90 = canvas.toDataURL('image/png');
			self.props.user.avatar_90x90 = ava90x90;
			self.props.StateUserAction.update(self.props.user, () => {

				/** Загрузка 150x150
				 */
				self.readFiles(file, 150, 150, (canvas) => {
					let avatar_150x150 = canvas.toDataURL('image/png');
					self.props.user.avatar_150x150 = avatar_150x150;
					self.props.StateUserAction.update(self.props.user, () => {

						/** Загрузка 62x62
						 */
						self.readFiles(file, 62, 62, (canvas) => {
							let avatar_62x62 = canvas.toDataURL('image/png');
							self.props.user.avatar_62x62 = avatar_62x62;
							self.props.StateUserAction.update(self.props.user, () => {

								/** Загрузка 32x32
								 */
								self.readFiles(file, 32, 32, (canvas) => {
									let avatar_32x32 = canvas.toDataURL('image/png');
									self.props.user.avatar_32x32 = avatar_32x32;
									self.props.StateUserAction.update(self.props.user, () => {

										/** Убрать лоадер загрузки аватара
										 */
										self.props.StateConfigAction.avatarLoader(self.props.config);
									});
								});
							});
						});
					});
				});
			});
		});
	}

	/**
	 * Добавление картинок файлридером через канвас
	 * @param {Number} w Ширина
	 * @param {Number} h Высота
	 * @param {Object} file Загружаемый файл
	 */
	readFiles(file, w, h, callback = () => {}) {
		let self = this;
		let reader = new FileReader();
		let canvas = document.getElementById('canvas__container');
		let ctx = canvas.getContext('2d');

		reader.onload = (e) => {
			let img = new Image();

			img.onload = () => {
				/** Размер превью, рисуемой канвасом
				 */
				canvas.width = w;
				canvas.height = h;
				self.drawImageProp(ctx, img, 0, 0, w, h, 0.5, 0.5);

				callback(canvas);
			}
			img.src = e.target.result;
		}
		reader.readAsDataURL(file);
	}

	/**
	 * Центрирование изображения
	 * @param {Object} ctx
	 * @param {Object} img
	 * @param {Int} x
	 * @param {Int} y
	 * @param {Int} w
	 * @param {Int} h
	 * @param {Int} offsetX
	 * @param {Int} offsetY
	 */
	drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
		if (arguments.length === 2) {
			x = y = 0;
			w = ctx.canvas.width;
			h = ctx.canvas.height;
		}

		offsetX = typeof offsetX === 'number' ? offsetX : 0.5;
		offsetY = typeof offsetY === 'number' ? offsetY : 0.5;

		if (offsetX < 0) offsetX = 0;
		if (offsetY < 0) offsetY = 0;
		if (offsetX > 1) offsetX = 1;
		if (offsetY > 1) offsetY = 1;

		var iw = img.width,
			ih = img.height,
			r = Math.min(w / iw, h / ih),
			nw = iw * r,
			nh = ih * r,
			cx, cy, cw, ch, ar = 1;

		if (nw < w) ar = w / nw
		if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh;

		nw *= ar;
		nh *= ar;

		cw = iw / (nw / w);
		ch = ih / (nh / h);

		cx = (iw - cw) * offsetX;
		cy = (ih - ch) * offsetY;

		if (cx < 0) cx = 0;
		if (cy < 0) cy = 0;
		if (cw > iw) cw = iw;
		if (ch > ih) ch = ih;

		ctx.drawImage(img, cx, cy, cw, ch,  x, y, w, h);
	}

	/**
	 * Render component
	 * @return {Object} jsx object
	 */
	render() {
		return <div className="photo-block">
					<div className="photo">
						{this.props.config.show_avatar_loader === 0 ?
							<img src={this.props.user.avatar_90x90} alt="avatar" /> :
							<div style={{backgroundImage: 'url('+ Loader +')'}} 
								className="avatar-loader__img"></div>}
					</div>

					<canvas id="canvas__container"
							className="canvas__container"></canvas>

					<label htmlFor="avatar-input"
						className="avatar-input__label">{this.props.lang.upload_photo_title}</label>
					<input type="file"
							name="files[]"
							accept="image/*"
							id="avatar-input"
							multiple="multiple"
							className="system__input"
							onChange={this.upload.bind(this)} />
				</div>
	}
}

/**
 * Init redux states
 *
 * @param {Object} state
 * @return {Object}
 */
function mapStateToProps(state) {
	return {
		lang: state.lang,
		user: state.user,
		config: state.config
	}
}

/**
 * Init redux actions
 * @param {Function} dispatch
 * @return {Object}
 */
function mapDispatchToProps(dispatch) {
	return {
		StateUserAction: bindActionCreators(StateUserAction, dispatch),
		StateConfigAction: bindActionCreators(StateConfigAction, dispatch),
	}
}

export default connect(mapStateToProps, mapDispatchToProps)(ProfileEditFormAvatar);